From 826cdd860bdd73bda283af4810e4d08ba9812390 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Thu, 20 Feb 2025 15:46:24 -0800 Subject: [PATCH 01/83] Add binary vector subtype --- .../include/bsoncxx/v_noabi/bsoncxx/enums/binary_sub_type.hpp | 1 + src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/types.hpp | 1 + 2 files changed, 2 insertions(+) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/enums/binary_sub_type.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/enums/binary_sub_type.hpp index 5ab13f1001..374e379e62 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/enums/binary_sub_type.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/enums/binary_sub_type.hpp @@ -26,6 +26,7 @@ BSONCXX_ENUM(md5, 0x05) BSONCXX_ENUM(encrypted, 0x06) BSONCXX_ENUM(column, 0x07) BSONCXX_ENUM(sensitive, 0x08) +BSONCXX_ENUM(vector, 0x09) BSONCXX_ENUM(user, 0x80) // clang-format on diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/types.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/types.hpp index b5aeb37d68..d7e64664b0 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/types.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/types.hpp @@ -79,6 +79,7 @@ enum class binary_sub_type : std::uint8_t { k_encrypted = 0x06, ///< Encrypted BSON value. k_column = 0x07, ///< Compressed BSON column. k_sensitive = 0x08, ///< Sensitive. + k_vector = 0x09, ///< BSON Binary Vector specification. k_user = 0x80, ///< User defined. }; From 5101593ea36814bc4b885658ea2bffee8acf6ec2 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Wed, 19 Mar 2025 20:58:16 -0700 Subject: [PATCH 02/83] Add an example that demonstrates most vector view API features --- examples/bsoncxx/bson_binary_vector.cpp | 142 ++++++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 examples/bsoncxx/bson_binary_vector.cpp diff --git a/examples/bsoncxx/bson_binary_vector.cpp b/examples/bsoncxx/bson_binary_vector.cpp new file mode 100644 index 0000000000..e652aa097a --- /dev/null +++ b/examples/bsoncxx/bson_binary_vector.cpp @@ -0,0 +1,142 @@ +// Copyright 2009-present MongoDB, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +int EXAMPLES_CDECL main() { + using bsoncxx::builder::basic::kvp; + using bsoncxx::builder::basic::make_document; + using bsoncxx::builder::basic::sub_binary; + + bsoncxx::document::value doc = make_document( + kvp("binary", + [&](sub_binary sbin) { + uint32_t len = 1000; + uint8_t* vec = sbin.allocate(bsoncxx::binary_sub_type::k_binary, len); + memset(vec, 0x55, len); + }), + kvp("vector_int8", + [&](sub_binary sbin) { + auto view = sbin.allocate(bsoncxx::vector::formats::f_int8{}, 1000); + uint8_t i = 0; + std::generate(view.begin(), view.end(), [&] { return (int8_t)++i; }); + }), + kvp("vector_float32", + [&](sub_binary sbin) { + auto view = sbin.allocate(bsoncxx::vector::formats::f_float32{}, 1000); + view[0] = 0.f; + view[1] = 1e-38f; + for (size_t i = 2; i < view.size(); i++) { + view[i] = view[i - 1] + view[i - 2]; + } + for (auto i = view.begin(); i != view.end(); i++) { + if (!(*i * 0.f < *i)) { + *i = float(std::sin(double(i - view.begin()) * 1e-3)); + } + } + std::fill(view.end() - 10, view.end() - 7, std::numeric_limits::infinity()); + view[0] += 1.f; + view[1] *= 1e38f; + view[1] /= 2.f; + view[1] -= 1.f + view[0]; + }), + kvp("vector_packed_bit", [&](sub_binary sbin) { + auto view = sbin.allocate(bsoncxx::vector::formats::f_packed_bit{}, 61); + std::fill(view.begin(), view.end(), true); + view[5] = !view[5]; + view[6] = view[1]; + view[7] = view[5]; + view[8] = 0; + view[60] = false; + std::fill(view.end() - 20, view.end() - 4, false); + std::fill(view.end() - 8, view.end() - 5, true); + for (auto i = view.byte_begin(); i != view.byte_end(); i++) { + *i ^= 0xFF; + } + std::copy(view.byte_begin(), view.byte_begin() + 2, view.byte_begin() + 2); + std::copy(view.begin() + 5, view.begin() + 9, view.begin() + 56); + })); + + std::cout << bsoncxx::to_json(doc) << std::endl; + + { + bsoncxx::vector::view v(doc["vector_int8"].get_binary()); + std::cout << "int8: " << v.size() << std::endl; + for (auto i = v.begin(); i != v.end(); i++) { + std::cout << int(*i) << " "; + } + std::cout << std::endl; + } + + { + bsoncxx::vector::view v(doc["vector_int8"].get_binary()); + std::cout << "int8 bytes: " << v.byte_size() << std::hex << std::endl; + for (auto i = v.byte_begin(); i != v.byte_end(); i++) { + std::cout << int(*i) << " "; + } + std::cout << std::dec << std::endl; + } + + { + bsoncxx::vector::view v(doc["vector_float32"].get_binary()); + std::cout << "float32: " << v.size() << std::endl; + for (auto i = v.begin(); i != v.end(); i++) { + std::cout << *i << " "; + } + std::cout << std::endl; + } + + { + bsoncxx::vector::view v(doc["vector_float32"].get_binary()); + std::cout << "float32 bytes: " << v.byte_size() << std::hex << std::endl; + for (auto i = v.byte_begin(); i != v.byte_end(); i++) { + std::cout << int(*i) << " "; + } + std::cout << std::dec << std::endl; + } + + { + bsoncxx::vector::view v(doc["vector_packed_bit"].get_binary()); + std::cout << "packed_bit: " << v.size() << std::endl; + for (auto i = v.begin(); i != v.end(); i++) { + std::cout << *i << " "; + } + std::cout << std::endl; + } + + { + bsoncxx::vector::view v(doc["vector_packed_bit"].get_binary()); + std::cout << "packed_bit bytes: " << v.byte_size() << std::hex << std::endl; + for (auto i = v.byte_begin(); i != v.byte_end(); i++) { + std::cout << int(*i) << " "; + } + std::cout << std::dec << std::endl; + } + + return 0; +} From 5bddf8ca789f9e13351a94a46c62a44040de37ee Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Wed, 19 Mar 2025 21:00:03 -0700 Subject: [PATCH 03/83] Bump required libmongoc version to pre-release 2.0.0 --- CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 88c466f985..cdb42939ca 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,12 +49,12 @@ else() endif() # Also update etc/purls.txt. -set(LIBBSON_REQUIRED_VERSION 1.30.0) +set(LIBBSON_REQUIRED_VERSION 1.31.0) set(LIBBSON_REQUIRED_ABI_VERSION 1.0) # Also update etc/purls.txt. -set(LIBMONGOC_REQUIRED_VERSION 1.30.0) -set(LIBMONGOC_DOWNLOAD_VERSION 1.30.1) +set(LIBMONGOC_REQUIRED_VERSION 1.31.0) +set(LIBMONGOC_DOWNLOAD_VERSION 0b3bb26c586c8a341710b853183abe5946693931) set(LIBMONGOC_REQUIRED_ABI_VERSION 1.0) set(NEED_DOWNLOAD_C_DRIVER false) From fa061e8525c2f56cc0373b6fc15231d41ae87f9f Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Wed, 19 Mar 2025 21:04:25 -0700 Subject: [PATCH 04/83] Additional binary builder tests, including sub_binary --- src/bsoncxx/test/bson_builder.cpp | 64 +++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/src/bsoncxx/test/bson_builder.cpp b/src/bsoncxx/test/bson_builder.cpp index c882ee11b7..84de2c45ff 100644 --- a/src/bsoncxx/test/bson_builder.cpp +++ b/src/bsoncxx/test/bson_builder.cpp @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -886,6 +887,69 @@ TEST_CASE("basic document builder works", "[bsoncxx::builder::basic]") { viewable_eq_viewable(stream, basic); } + SECTION("b_binary works") { + { + using namespace builder::stream; + stream << "foo" + << types::b_binary{binary_sub_type::k_binary, 8, reinterpret_cast("deadbeef")}; + } + { + using namespace builder::basic; + basic.append( + kvp("hello", "world"), + kvp("foo", + types::b_binary{binary_sub_type::k_binary, 8, reinterpret_cast("deadbeef")})); + } + viewable_eq_viewable(stream, basic); + } + SECTION("sub_binary builder works") { + { + using namespace builder::stream; + stream << "foo" + << types::b_binary{binary_sub_type::k_binary, 8, reinterpret_cast("deadbeef")}; + } + { + using namespace builder::basic; + basic.append(kvp("hello", "world"), kvp("foo", [](sub_binary sb) { + memcpy(sb.allocate(binary_sub_type::k_binary, 8), "deadbeef", 8); + })); + } + viewable_eq_viewable(stream, basic); + } + SECTION("sub_binary can allocate and fill a larger memory region") { + using namespace builder::basic; + uint32_t const size = 32 * 1024 * 1024; + basic.append( + kvp("foo", [](sub_binary sb) { memset(sb.allocate(binary_sub_type::k_binary, size), 0x55, size); })); + REQUIRE(basic.view().length() > size); + } + SECTION("sub_binary builder can allocate with length zero") { + { + using namespace builder::stream; + stream << "foo" << types::b_binary{binary_sub_type::k_binary, 0, reinterpret_cast("")}; + } + { + using namespace builder::basic; + basic.append( + kvp("hello", "world"), kvp("foo", [](sub_binary sb) { sb.allocate(binary_sub_type::k_binary, 0); })); + } + viewable_eq_viewable(stream, basic); + } + SECTION("sub_binary throws on double allocation") { + using namespace builder::basic; + REQUIRE_THROWS_AS( + basic.append( + kvp("foo", + [](sub_binary sb) { + sb.allocate(binary_sub_type::k_binary, 0); + sb.allocate(binary_sub_type::k_binary, 0); + })), + bsoncxx::exception); + } + SECTION("sub_binary throws on missing allocation") { + using namespace builder::basic; + REQUIRE_THROWS_AS(basic.append(kvp("foo", [](sub_binary) {})), bsoncxx::exception); + } } TEST_CASE("basic document builder move semantics work", "[bsoncxx::builder::basic::document]") { From b2dd2f8bedd489de204b63e4823b764c84a9b2f9 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Wed, 19 Mar 2025 21:04:46 -0700 Subject: [PATCH 05/83] vector API tests --- src/bsoncxx/test/CMakeLists.txt | 2 + src/bsoncxx/test/vector.cpp | 521 ++++++++++++++++++++++++++++++++ 2 files changed, 523 insertions(+) create mode 100644 src/bsoncxx/test/vector.cpp diff --git a/src/bsoncxx/test/CMakeLists.txt b/src/bsoncxx/test/CMakeLists.txt index b2ddd04ffa..2a53864813 100644 --- a/src/bsoncxx/test/CMakeLists.txt +++ b/src/bsoncxx/test/CMakeLists.txt @@ -40,6 +40,7 @@ add_executable(test_bson exception_guard.cpp json.cpp oid.cpp + vector.cpp optional.test.cpp view_or_value.cpp make_unique.test.cpp @@ -158,6 +159,7 @@ set_dist_list(src_bsoncxx_test_DIST exception_guard.hh json.cpp oid.cpp + vector.cpp optional.test.cpp test_macro_guards.cpp.in to_string.hh diff --git a/src/bsoncxx/test/vector.cpp b/src/bsoncxx/test/vector.cpp new file mode 100644 index 0000000000..b04c15f170 --- /dev/null +++ b/src/bsoncxx/test/vector.cpp @@ -0,0 +1,521 @@ +// Copyright 2009-present MongoDB, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#define ALL_VECTOR_FORMATS vector::formats::f_float32, vector::formats::f_int8, vector::formats::f_packed_bit + +namespace { + +using namespace bsoncxx; + +template +struct format_specific; + +template <> +struct format_specific { + using value_type = float; + static constexpr std::array bytes_empty() { + return {0x27, 0x00}; + } + static constexpr std::array bytes_unit() { + return {0x27, 0x00, 0x00, 0x00, 0x80, 0x3f}; + } + static constexpr value_type element_unit() { + return 1.f; + } +}; + +template <> +struct format_specific { + using value_type = int8_t; + static constexpr std::array bytes_empty() { + return {0x03, 0x00}; + } + static constexpr std::array bytes_unit() { + return {0x03, 0x00, 0x01}; + } + static constexpr value_type element_unit() { + return 1; + } +}; + +template <> +struct format_specific { + using value_type = bool; + static constexpr std::array bytes_empty() { + return {0x10, 0x00}; + } + static constexpr std::array bytes_unit() { + return {0x10, 0x07, 0x80}; + } + static constexpr value_type element_unit() { + return true; + } +}; + +template +void binary_eq_bytes(types::b_binary const& binary, Sequence const& bytes) { + REQUIRE(binary.size == bytes.size()); + REQUIRE(std::memcmp(binary.bytes, bytes.data(), bytes.size()) == 0); +} + +template +void iterator_operations( + Iterator const& begin, + Iterator const& end, + std::ptrdiff_t expected_size, + Element element_unit) { + REQUIRE(end - begin == expected_size); + + for (std::ptrdiff_t outer_index = 0; outer_index < 50; outer_index++) { + Iterator outer_front = begin + outer_index; + Iterator outer_back = end - outer_index; + + REQUIRE(outer_front - begin == outer_index); + REQUIRE(begin - outer_front == -outer_index); + + REQUIRE(end - outer_back == outer_index); + REQUIRE(outer_back - end == -outer_index); + + for (std::ptrdiff_t inner_index = 0; inner_index < 20; inner_index++) { + Iterator inner_front = outer_front + inner_index; + Iterator inner_back = outer_back - inner_index; + + REQUIRE(inner_front - outer_front == inner_index); + REQUIRE(outer_front - inner_front == -inner_index); + + REQUIRE(outer_back - inner_back == inner_index); + REQUIRE(inner_back - outer_back == -inner_index); + } + } + + Iterator iter_copy = begin; + REQUIRE(iter_copy == begin); + REQUIRE(iter_copy >= begin); + REQUIRE(iter_copy <= begin); + REQUIRE_FALSE(iter_copy != begin); + REQUIRE_FALSE(iter_copy < begin); + + REQUIRE(++iter_copy - begin == 1); + REQUIRE(iter_copy > begin); + REQUIRE(iter_copy >= begin); + REQUIRE(iter_copy != begin); + REQUIRE_FALSE(iter_copy == begin); + REQUIRE_FALSE(iter_copy <= begin); + REQUIRE_FALSE(iter_copy < begin); + + REQUIRE(--iter_copy - begin == 0); + REQUIRE(iter_copy == begin); + + REQUIRE(iter_copy++ - begin == 0); + REQUIRE(iter_copy-- - begin == 1); + REQUIRE(iter_copy == begin); + + std::generate(begin, end, [&] { return element_unit; }); + std::for_each(begin, end, [&](auto const& value) { REQUIRE(value == element_unit); }); + + std::copy(begin, begin + (expected_size / 2), begin + (expected_size / 2)); + std::for_each(begin, end, [&](auto const& value) { REQUIRE(value == element_unit); }); + + std::for_each(begin, end, [&](auto&& value) { value = element_unit; }); + std::for_each(begin, end, [&](auto const& value) { REQUIRE(value == element_unit); }); + + std::fill(begin, end, element_unit); + std::for_each(begin, end, [&](auto const& value) { REQUIRE(value == element_unit); }); + + std::sort(begin, end); + std::for_each(begin, end, [&](auto const& value) { REQUIRE(value == element_unit); }); + + std::for_each(begin, end, [&](auto&& value) { value -= element_unit; }); + std::for_each(begin, end, [&](auto&& value) { value *= element_unit; }); + std::for_each(begin, end, [&](auto&& value) { value /= element_unit; }); + std::for_each(begin, end, [&](auto const& value) { REQUIRE(value != element_unit); }); + std::for_each(begin, end, [&](auto const& value) { REQUIRE(value < element_unit); }); + std::for_each(begin, end, [&](auto const& value) { REQUIRE(value <= element_unit); }); + std::for_each(begin, end, [&](auto const& value) { REQUIRE_FALSE(value == element_unit); }); + std::for_each(begin, end, [&](auto const& value) { REQUIRE_FALSE(value > element_unit); }); + std::for_each(begin, end, [&](auto const& value) { REQUIRE_FALSE(value >= element_unit); }); + + std::for_each(begin, end, [&](auto&& value) { value += element_unit; }); + std::for_each(begin, end, [&](auto&& value) { value *= element_unit; }); + std::for_each(begin, end, [&](auto&& value) { value /= element_unit; }); + std::for_each(begin, end, [&](auto const& value) { REQUIRE(value == element_unit); }); +} + +TEMPLATE_TEST_CASE("all vector view formats", "[bsoncxx::vector::view]", ALL_VECTOR_FORMATS) { + using test_format_specific = format_specific; + using value_type = typename test_format_specific::value_type; + + SECTION("accept a valid vector with no elements") { + auto bytes = test_format_specific::bytes_empty(); + types::b_binary const binary{binary_sub_type::k_vector, bytes.size(), bytes.data()}; + vector::view view{binary}; + REQUIRE(view.empty()); + REQUIRE(view.size() == 0); + REQUIRE(view.byte_size() == 0); + CHECK_THROWS_AS(view.at(0), std::out_of_range); + CHECK_THROWS_AS(view.byte_at(0), std::out_of_range); + } + + SECTION("decode a valid vector with a single element") { + auto bytes = test_format_specific::bytes_unit(); + auto element = test_format_specific::element_unit(); + types::b_binary const binary{binary_sub_type::k_vector, bytes.size(), bytes.data()}; + vector::view view{binary}; + REQUIRE_FALSE(view.empty()); + REQUIRE(view.size() == 1u); + REQUIRE(view.byte_size() == bytes.size() - 2u); + REQUIRE(view.at(0) == element); + REQUIRE(view[0] == element); + REQUIRE(view.byte_at(0) == bytes[2]); + REQUIRE(view.byte_at(bytes.size() - 3u) == bytes[bytes.size() - 1u]); + CHECK_THROWS_AS(view.at(1), std::out_of_range); + CHECK_THROWS_AS(view.byte_at(bytes.size() - 2u), std::out_of_range); + } + + SECTION("reject binary data of the wrong sub_type") { + auto bytes = test_format_specific::bytes_empty(); + auto invalid_type = GENERATE( + binary_sub_type::k_binary, binary_sub_type::k_encrypted, binary_sub_type::k_uuid, binary_sub_type::k_user); + types::b_binary const binary{invalid_type, bytes.size(), bytes.data()}; + REQUIRE_THROWS_WITH( + vector::view(binary), Catch::Matchers::ContainsSubstring("invalid BSON vector")); + } + + SECTION("reject binary data that's too short to include a header") { + auto bytes = test_format_specific::bytes_empty(); + auto bytes_to_remove = GENERATE(1u, 2u); + REQUIRE(bytes.size() >= bytes_to_remove); + types::b_binary const binary{binary_sub_type::k_vector, uint32_t(bytes.size() - bytes_to_remove), bytes.data()}; + REQUIRE_THROWS_WITH( + vector::view(binary), Catch::Matchers::ContainsSubstring("invalid BSON vector")); + } + + SECTION("reject empty vectors with any modified header bits") { + for (unsigned bit_index = 0; bit_index < 16; bit_index++) { + auto bytes = test_format_specific::bytes_empty(); + bytes[bit_index >> 3u] ^= 1u << (bit_index & 7u); + types::b_binary const binary{binary_sub_type::k_vector, bytes.size(), bytes.data()}; + REQUIRE_THROWS_WITH( + vector::view(binary), Catch::Matchers::ContainsSubstring("invalid BSON vector")); + } + } + + SECTION("encode a single element as expected") { + using namespace builder::basic; + auto expected_bytes = test_format_specific::bytes_unit(); + auto element = test_format_specific::element_unit(); + bsoncxx::document::value doc = + make_document(kvp("vector", [&](sub_binary sbin) { sbin.allocate(TestType{}, 1u)[0u] = element; })); + types::b_binary const& binary = doc.view()["vector"].get_binary(); + REQUIRE(binary.sub_type == binary_sub_type::k_vector); + binary_eq_bytes(binary, expected_bytes); + vector::view validate_encoded{binary}; + } + + SECTION("support algorithms and operators on element iterators") { + using namespace builder::basic; + bsoncxx::document::value doc = make_document(kvp("vector", [&](sub_binary sbin) { + // Avoid multiples of 8, to cover nonzero packed_bit 'padding'. + auto view = sbin.allocate(TestType{}, 8007u); + iterator_operations( + view.begin(), view.end(), std::ptrdiff_t(view.size()), test_format_specific::element_unit()); + })); + types::b_binary const& binary = doc.view()["vector"].get_binary(); + vector::view validate_encoded{binary}; + REQUIRE(binary.size > 1000u); + } + + SECTION("support algorithms and operators on byte iterators") { + using namespace builder::basic; + bsoncxx::document::value doc = make_document(kvp("vector", [&](sub_binary sbin) { + // Choose a multiple of 8, to avoid the effects of masking unused bits. + auto view = sbin.allocate(TestType{}, 8000u); + iterator_operations(view.byte_begin(), view.byte_end(), std::ptrdiff_t(view.byte_size()), uint8_t(1)); + })); + types::b_binary const& binary = doc.view()["vector"].get_binary(); + vector::view validate_encoded{binary}; + REQUIRE(binary.size > 1000u); + } + + SECTION("support assignment between referenced elements") { + using namespace builder::basic; + bsoncxx::document::value doc = make_document(kvp("vector", [&](sub_binary sbin) { + auto view = sbin.allocate(TestType{}, 2u); + view[0] = test_format_specific::element_unit(); + view[1] = value_type{0}; + REQUIRE(view.at(0) != view.at(1)); + REQUIRE_FALSE(view.at(0) == view.at(1)); + view[1] = view[0]; + REQUIRE(view.at(0) == view.at(1)); + REQUIRE_FALSE(view.at(0) != view.at(1)); + })); + types::b_binary const& binary = doc.view()["vector"].get_binary(); + vector::view validate_encoded{binary}; + } + + SECTION("support assignment between referenced bytes") { + using namespace builder::basic; + bsoncxx::document::value doc = make_document(kvp("vector", [&](sub_binary sbin) { + auto view = sbin.allocate(TestType{}, 16u); + std::fill(view.begin(), view.end(), test_format_specific::element_unit()); + *(view.end() - 2) = value_type{0}; + REQUIRE(view.byte_at(view.byte_size() - 2) != view.byte_at(view.byte_size() - 1)); + REQUIRE_FALSE(view.byte_at(view.byte_size() - 2) == view.byte_at(view.byte_size() - 1)); + view.byte_at(view.byte_size() - 2) = view.byte_at(view.byte_size() - 1); + REQUIRE(view.byte_at(view.byte_size() - 2) == view.byte_at(view.byte_size() - 1)); + REQUIRE_FALSE(view.byte_at(view.byte_size() - 2) != view.byte_at(view.byte_size() - 1)); + })); + types::b_binary const& binary = doc.view()["vector"].get_binary(); + vector::view validate_encoded{binary}; + } + + SECTION("fail to allocate unrepresentably large vectors") { + using namespace builder::basic; + // This checks that we can detect overlarge sizes and throw an exception. + // Detailed checks for the size limit are delegated to Libbson (via libbson_length_for_append) + REQUIRE_THROWS_WITH( + make_document(kvp("vector", [&](sub_binary sbin) { sbin.allocate(TestType{}, SIZE_MAX); })), + Catch::Matchers::ContainsSubstring("BSON vector too large")); + } + + SECTION("support front and back element references") { + using namespace builder::basic; + bsoncxx::document::value doc = make_document(kvp("vector", [&](sub_binary sbin) { + auto view = sbin.allocate(TestType{}, 2u); + std::fill(view.begin(), view.end(), test_format_specific::element_unit()); + *(view.end() - 1) = value_type{0}; + REQUIRE(view.back() == value_type{0}); + REQUIRE(view.back() == view[view.size() - 1u]); + REQUIRE(view.front() != view.back()); + REQUIRE_FALSE(view.front() == view.back()); + view.front() = view.back(); + REQUIRE(view[0] == value_type{0}); + REQUIRE(view.front() == view.back()); + REQUIRE_FALSE(view.front() != view.back()); + REQUIRE(view[view.size() - 1u] == value_type{0}); + view.back() = test_format_specific::element_unit(); + REQUIRE(view[0] == value_type{0}); + REQUIRE(view[view.size() - 1u] != value_type{0}); + REQUIRE(view.front() != view.back()); + REQUIRE_FALSE(view.front() == view.back()); + })); + types::b_binary const& binary = doc.view()["vector"].get_binary(); + vector::view validate_encoded{binary}; + } + + SECTION("support front and back byte references") { + using namespace builder::basic; + bsoncxx::document::value doc = make_document(kvp("vector", [&](sub_binary sbin) { + auto view = sbin.allocate(TestType{}, 16u); + std::fill(view.begin(), view.end(), value_type{0}); + REQUIRE(view.front() == view.back()); + REQUIRE_FALSE(view.front() != view.back()); + REQUIRE(view.byte_front() == view.byte_back()); + REQUIRE_FALSE(view.byte_front() != view.byte_back()); + view.back() = test_format_specific::element_unit(); + REQUIRE(view.byte_front() != view.byte_back()); + REQUIRE_FALSE(view.byte_front() == view.byte_back()); + view.byte_front() = UINT8_C(0); + view.byte_back() = UINT8_C(0); + REQUIRE(view.byte_front() == view.byte_back()); + REQUIRE_FALSE(view.byte_front() != view.byte_back()); + })); + types::b_binary const& binary = doc.view()["vector"].get_binary(); + vector::view validate_encoded{binary}; + } +} + +TEST_CASE("vector view float32", "[bsoncxx::vector::view]") { + SECTION("rejects binary data with an incorrect length") { + static uint8_t const bytes[] = {0x27, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00}; + auto invalid_length = GENERATE(0u, 1u, 3u, 4u, 5u, 7u, 8u, 9u); + types::b_binary const binary{binary_sub_type::k_vector, uint32_t(invalid_length), bytes}; + REQUIRE_THROWS_WITH( + vector::view(binary), + Catch::Matchers::ContainsSubstring("invalid BSON vector")); + } + + SECTION("rejects binary data from other vector formats") { + auto bytes = GENERATE( + format_specific::bytes_empty(), + format_specific::bytes_empty()); + types::b_binary const binary{binary_sub_type::k_vector, bytes.size(), bytes.data()}; + REQUIRE_THROWS_WITH( + vector::view(binary), + Catch::Matchers::ContainsSubstring("invalid BSON vector")); + } + + SECTION("accepts and correctly decodes elements with infinite value") { + static uint8_t const bytes[] = { + 0x27, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x7F}; + types::b_binary const binary{binary_sub_type::k_vector, sizeof bytes, bytes}; + vector::view view{binary}; + REQUIRE(view.size() == 3u); + REQUIRE(view[0] < 0.f); + REQUIRE(view[0] * 0.f != 0.f); + REQUIRE(view[1] == 0.f); + REQUIRE(view[2] > 0.f); + REQUIRE(view[2] * 0.f != 0.f); + } +} + +TEST_CASE("vector view int8_t", "[bsoncxx::vector::view]") { + SECTION("rejects binary data from other vector formats") { + auto bytes = GENERATE( + format_specific::bytes_empty(), + format_specific::bytes_empty()); + types::b_binary const binary{binary_sub_type::k_vector, bytes.size(), bytes.data()}; + REQUIRE_THROWS_WITH( + vector::view(binary), + Catch::Matchers::ContainsSubstring("invalid BSON vector")); + } +} + +TEST_CASE("vector view packed_bit", "[bsoncxx::vector::view]") { + SECTION("rejects empty vectors with nonzero padding") { + for (unsigned byte_value = 1u; byte_value <= UINT8_MAX; byte_value++) { + auto bytes = format_specific::bytes_empty(); + bytes[1] = uint8_t(byte_value); + types::b_binary const binary{binary_sub_type::k_vector, bytes.size(), bytes.data()}; + REQUIRE_THROWS_WITH( + vector::view(binary), + Catch::Matchers::ContainsSubstring("invalid BSON vector")); + } + } + + SECTION("rejects nonempty vectors with bits set in header padding byte") { + for (unsigned byte_value = 8u; byte_value <= UINT8_MAX; byte_value++) { + uint8_t const bytes[] = {0x10, uint8_t(byte_value), 0x00}; + types::b_binary const binary{binary_sub_type::k_vector, sizeof bytes, bytes}; + REQUIRE_THROWS_WITH( + vector::view(binary), + Catch::Matchers::ContainsSubstring("invalid BSON vector")); + } + } + + SECTION("rejects nonempty vectors with nonzero values in unused trailing bits") { + for (unsigned byte_value = 1u; byte_value <= 7u; byte_value++) { + uint8_t bytes[] = {0x10, uint8_t(byte_value), 0xff}; + types::b_binary const binary{binary_sub_type::k_vector, sizeof bytes, bytes}; + REQUIRE_THROWS_WITH( + vector::view(binary), + Catch::Matchers::ContainsSubstring("invalid BSON vector")); + // Succeeds when unused bits are then zeroed + bytes[2] = 0; + vector::view view{binary}; + REQUIRE(view.size() == 8u - byte_value); + } + } + + SECTION("masks writes to unused portions of the last byte") { + using namespace builder::basic; + bsoncxx::document::value doc = make_document(kvp("vector", [&](sub_binary sbin) { + auto view = sbin.allocate(vector::formats::f_packed_bit{}, 9u); + std::fill(view.begin(), view.end(), true); + REQUIRE(view.byte_size() == 2u); + REQUIRE(view.byte_at(0) == 0xff); + REQUIRE(view.byte_at(1) == 0x80); + view.byte_at(1) = 0x7f; + REQUIRE(view.at(7) == true); + REQUIRE(view.at(8) == false); + REQUIRE(view.byte_at(1) == 0x00); + view.byte_at(1) = 0xff; + view.byte_at(0) = 0xaa; + REQUIRE(view.at(0) == true); + REQUIRE(view.at(1) == false); + REQUIRE(view.at(2) == true); + REQUIRE(view.at(3) == false); + REQUIRE(view.at(4) == true); + REQUIRE(view.at(5) == false); + REQUIRE(view.at(6) == true); + REQUIRE(view.at(7) == false); + REQUIRE(view.at(8) == true); + REQUIRE(view.byte_at(0) == 0xaa); + REQUIRE(view.byte_at(1) == 0x80); + })); + types::b_binary const& binary = doc.view()["vector"].get_binary(); + REQUIRE(binary.sub_type == binary_sub_type::k_vector); + std::array expected_bytes{0x10, 7, 0xaa, 0x80}; + binary_eq_bytes(binary, expected_bytes); + } + + SECTION("validates nonempty vectors with any padding value") { + for (unsigned byte_value = 0; byte_value <= 7; byte_value++) { + uint8_t const bytes[] = {0x10, uint8_t(byte_value), 0x00}; + types::b_binary const binary{binary_sub_type::k_vector, sizeof bytes, bytes}; + vector::view view{binary}; + REQUIRE(view.size() == 8 - byte_value); + } + } + + SECTION("rejects binary data from other vector formats") { + auto bytes = GENERATE( + format_specific::bytes_empty(), + format_specific::bytes_empty()); + types::b_binary const binary{binary_sub_type::k_vector, bytes.size(), bytes.data()}; + REQUIRE_THROWS_WITH( + vector::view(binary), + Catch::Matchers::ContainsSubstring("invalid BSON vector")); + } + + SECTION("writes and successfully re-validates vectors of any length") { + for (std::size_t element_count = 0; element_count < 1000; element_count++) { + using namespace builder::basic; + bsoncxx::document::value doc = make_document(kvp("vector", [&](sub_binary sbin) { + auto view = sbin.allocate(vector::formats::f_packed_bit{}, element_count); + REQUIRE(view.size() == element_count); + REQUIRE(view.byte_size() == (element_count + 7u) / 8); + std::fill(view.byte_begin(), view.byte_end(), UINT8_C(0xFF)); + REQUIRE(view.empty() == (element_count == 0)); + if (!view.empty()) { + std::for_each(view.byte_begin(), view.byte_end() - 1, [&](std::uint8_t value) { + REQUIRE(value == UINT8_C(0xFF)); + }); + std::size_t padding = view.byte_size() * std::size_t(8) - view.size(); + REQUIRE(view.byte_back() == std::uint8_t(0xFF << padding)); + } + })); + types::b_binary const& binary = doc.view()["vector"].get_binary(); + REQUIRE(binary.sub_type == binary_sub_type::k_vector); + vector::view view{binary}; + REQUIRE(view.size() == element_count); + REQUIRE(view.byte_size() == (element_count + 7u) / 8); + REQUIRE(view.empty() == (element_count == 0u)); + if (!view.empty()) { + std::for_each(view.byte_begin(), view.byte_end() - 1, [&](std::uint8_t value) { + REQUIRE(value == UINT8_C(0xFF)); + }); + std::size_t padding = view.byte_size() * std::size_t(8) - view.size(); + REQUIRE(padding == binary.bytes[1]); + REQUIRE(view.byte_back() == std::uint8_t(0xFF << padding)); + } + } + } +} + +} // namespace From 2a478bbe4fe8e6a5cc6bf3eb451acead88dd2ce3 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Wed, 19 Mar 2025 21:05:47 -0700 Subject: [PATCH 06/83] New error codes for use in bsoncxx::vector --- .../bsoncxx/v_noabi/bsoncxx/exception/error_code.hpp | 6 ++++++ .../lib/bsoncxx/v_noabi/bsoncxx/exception/error_code.cpp | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/exception/error_code.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/exception/error_code.hpp index 925adc4305..80b5feae01 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/exception/error_code.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/exception/error_code.hpp @@ -143,6 +143,12 @@ enum class error_code : std::int32_t { k_cannot_append_minkey, /// @} + /// A BSON Binary Vector failed to parse in the requested format. + k_invalid_vector, + + /// A BSON Binary Vector would be too large to represent. + k_vector_too_large, + // Add new constant string message to error_code.cpp as well! }; diff --git a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/exception/error_code.cpp b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/exception/error_code.cpp index 35f497cb3b..df77ec2174 100644 --- a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/exception/error_code.cpp +++ b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/exception/error_code.cpp @@ -81,6 +81,10 @@ class error_category_impl final : public std::error_category { return {"unable to append " #name}; #include #undef BSONCXX_ENUM + case error_code::k_invalid_vector: + return "invalid BSON vector"; + case error_code::k_vector_too_large: + return "BSON vector too large"; default: return "unknown bsoncxx error code"; } From 8ed6fb9abc9c08542a5cfb25263679b240090817 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Wed, 19 Mar 2025 21:07:35 -0700 Subject: [PATCH 07/83] document the bsoncxx::vector namespaces --- src/bsoncxx/include/bsoncxx/docs/top.hpp | 10 ++++++++++ src/bsoncxx/include/bsoncxx/docs/v_noabi.hpp | 20 ++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/src/bsoncxx/include/bsoncxx/docs/top.hpp b/src/bsoncxx/include/bsoncxx/docs/top.hpp index 3d4530d9fe..3bd37a02ce 100644 --- a/src/bsoncxx/include/bsoncxx/docs/top.hpp +++ b/src/bsoncxx/include/bsoncxx/docs/top.hpp @@ -88,3 +88,13 @@ /// @namespace bsoncxx::types::bson_value /// Declares entities representing any BSON value type. /// + +/// +/// @namespace bsoncxx::vector +/// Declarations related to BSON Binary Vector (@ref bsoncxx::v_noabi::binary_sub_type::k_vector) items. +/// + +/// +/// @namespace bsoncxx::vector::formats +/// Each type here is a supported format for bsoncxx::vector +/// \ No newline at end of file diff --git a/src/bsoncxx/include/bsoncxx/docs/v_noabi.hpp b/src/bsoncxx/include/bsoncxx/docs/v_noabi.hpp index a9275ae284..a118abe953 100644 --- a/src/bsoncxx/include/bsoncxx/docs/v_noabi.hpp +++ b/src/bsoncxx/include/bsoncxx/docs/v_noabi.hpp @@ -148,3 +148,23 @@ /// @namespace bsoncxx::v_noabi::types::bson_value /// Declares entities representing any BSON value type. /// + +/// +/// @namespace bsoncxx::v_noabi::vector +/// Declarations related to BSON Binary Vector (@ref bsoncxx::v_noabi::binary_sub_type::k_vector) items. +/// + +/// +/// @namespace bsoncxx::v_noabi::vector::iterators +/// Special-purpose iterator types for bsoncxx::vector +/// + +/// +/// @namespace bsoncxx::v_noabi::vector::elements +/// Special-purpose element reference types for bsoncxx::vector +/// + +/// +/// @namespace bsoncxx::v_noabi::vector::formats +/// Each type here is a supported format for bsoncxx::vector +/// \ No newline at end of file From b316f501210cd1d92b29a2db683da816a8e15cdb Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Wed, 19 Mar 2025 21:10:16 -0700 Subject: [PATCH 08/83] Add forwarding headers for vector and sub_binary --- src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/fwd.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/fwd.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/fwd.hpp index 03e9a53f6a..37226857a0 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/fwd.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/fwd.hpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -45,6 +46,8 @@ #include #include #include +#include +#include #include /// From 5360c231ace9ffe4cd053041692e2715be69b6ca Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Wed, 19 Mar 2025 21:11:21 -0700 Subject: [PATCH 09/83] initial implementation for bsoncxx::vector --- .../v_noabi/bsoncxx/vector/elements.hpp | 287 +++++++++++++++++ .../v_noabi/bsoncxx/vector/formats-fwd.hpp | 53 +++ .../v_noabi/bsoncxx/vector/formats.hpp | 48 +++ .../bsoncxx/v_noabi/bsoncxx/vector/impl.hpp | 170 ++++++++++ .../v_noabi/bsoncxx/vector/iterators.hpp | 304 ++++++++++++++++++ .../v_noabi/bsoncxx/vector/view-fwd.hpp | 43 +++ .../bsoncxx/v_noabi/bsoncxx/vector/view.hpp | 281 ++++++++++++++++ src/bsoncxx/lib/CMakeLists.txt | 1 + .../lib/bsoncxx/v_noabi/bsoncxx/vector.cpp | 120 +++++++ 9 files changed, 1307 insertions(+) create mode 100644 src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/elements.hpp create mode 100644 src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/formats-fwd.hpp create mode 100644 src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/formats.hpp create mode 100644 src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/impl.hpp create mode 100644 src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/iterators.hpp create mode 100644 src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/view-fwd.hpp create mode 100644 src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/view.hpp create mode 100644 src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/vector.cpp diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/elements.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/elements.hpp new file mode 100644 index 0000000000..c33a8b2546 --- /dev/null +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/elements.hpp @@ -0,0 +1,287 @@ +// Copyright 2009-present MongoDB, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include + +#include + +namespace bsoncxx { +namespace v_noabi { +namespace vector { + +namespace iterators { + +template +class packed_bit_element; + +template +class packed_bit_byte; + +} // namespace iterators + +namespace elements { + +/// @brief A 32-bit float value in packed little-endian format +class float32 { + public: + /// @brief Construct a packed little-endian value from a float input in the local byte order. + /// @param value Floating point value to convert + float32(float value) noexcept { +#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) + std::memcpy(bytes, &value, sizeof value); +#elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) + std::uint32_t u32; + std::memcpy(&u32, &value, sizeof value); + u32 = bswap32(u32); + std::memcpy(bytes, &u32, sizeof value); +#else +#error No implementation for storing 32-bit little endian unaligned float +#endif + } + + /// Convert a packed little-endian floating point value back to the local byte order. + operator float() const noexcept { + float value; +#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) + std::memcpy(&value, bytes, sizeof value); +#elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) + std::uint32_t u32; + std::memcpy(&u32, bytes, sizeof value); + u32 = bswap32(u32); + std::memcpy(&value, &u32, sizeof value); +#else +#error No implementation for loading 32-bit little endian unaligned float +#endif + return value; + } + + /// Operator +=, emulating normal float behavior + float32& operator+=(float const& other) noexcept { + return *this = *this + other; + } + + /// Operator -=, emulating normal float behavior + float32& operator-=(float const& other) noexcept { + return *this = *this - other; + } + + /// Operator *=, emulating normal float behavior + float32& operator*=(float const& other) noexcept { + return *this = *this * other; + } + + /// Operator /=, emulating normal float behavior + float32& operator/=(float const& other) noexcept { + return *this = *this / other; + } + + private: + static std::uint32_t bswap32(std::uint32_t value) { +#ifndef _WIN32 + return __builtin_bswap32(value); +#else + return _byteswap_ulong(value); +#endif + } + + std::uint8_t bytes[4]; +}; + +/// @brief Reference to a single element in a packed_bit vector. +/// @tparam Iterator Underlying byte iterator type, optionally const. +template +class packed_bit_element { + public: + /// Value type chosen to represent a single-bit element + using value_type = bool; + + /// Obtain the referenced element's current value + constexpr operator value_type() const { + return ((*byte & mask) == UINT8_C(0)) ? value_type(0) : value_type(1); + } + + /// Set the value of the element referenced + packed_bit_element const& operator=(value_type const& v) const { + if (v == 0) { + *byte &= ~mask; + } else { + *byte |= mask; + } + return *this; + } + + /// Copy the referenced value from another reference of the same type + packed_bit_element const& operator=(packed_bit_element const& v) const noexcept { + return *this = value_type(v); + } + + /// Operator +=, emulating number reference behavior + packed_bit_element const& operator+=(value_type const& other) const noexcept { + return *this = *this + other; + } + + /// Operator -=, emulating number reference behavior + packed_bit_element const& operator-=(value_type const& other) const noexcept { + return *this = *this - other; + } + + /// Operator *=, emulating number reference behavior + packed_bit_element const& operator*=(value_type const& other) const noexcept { + return *this = *this * other; + } + + /// Operator /=, emulating number reference behavior + packed_bit_element const& operator/=(value_type const& other) const noexcept { + return *this = *this / other; + } + + /// Operator %=, emulating number reference behavior + packed_bit_element const& operator%=(value_type const& other) const noexcept { + return *this = *this % other; + } + + /// Operator ^=, emulating number reference behavior + packed_bit_element const& operator^=(value_type const& other) const noexcept { + return *this = *this ^ other; + } + + /// Operator &=, emulating number reference behavior + packed_bit_element const& operator&=(value_type const& other) const noexcept { + return *this = *this & other; + } + + /// Operator |=, emulating number reference behavior + packed_bit_element const& operator|=(value_type const& other) const noexcept { + return *this = *this | other; + } + + constexpr packed_bit_element(packed_bit_element const& other) : byte(other.byte), mask(other.mask) {} + + private: + friend class iterators::packed_bit_element; + + constexpr packed_bit_element(Iterator byte_iter, uint8_t bit_index) noexcept + : byte(byte_iter), mask(uint8_t(0x80u >> bit_index)) {} + + Iterator byte; + std::uint8_t mask; +}; + +/// packed_bit_element is Swappable even when it's not an lvalue reference +template +void swap(packed_bit_element a, packed_bit_element b) noexcept { + bool a_value = a; + bool b_value = b; + a = b_value; + b = a_value; +} + +/// @brief Reference to a byte or partial byte within a vector of packed_bit elements. +/// Allows access to each byte as a uint8_t, while masking off writes to reserved bits. +/// @tparam Iterator Underlying byte iterator type, optionally const. +template +class packed_bit_byte { + public: + /// @brief Read the entire byte, as a std::uint8_t. + constexpr operator std::uint8_t() const noexcept { + return *byte; + } + + /// @brief Overwrite the usable portion of the byte, and set reserved bits to zero. + /// @param v Byte to write. Reserved bits are ignored. + /// @return *this + packed_bit_byte const& operator=(std::uint8_t const& v) const noexcept { + *byte = v & mask; + return *this; + } + + /// Copy the referenced value from another reference of the same type + packed_bit_byte const& operator=(packed_bit_byte const& v) const noexcept { + return *this = std::uint8_t(v); + } + + /// Operator +=, emulating number reference behavior + packed_bit_byte const& operator+=(std::uint8_t const& other) const noexcept { + return *this = *this + other; + } + + /// Operator -=, emulating number reference behavior + packed_bit_byte const& operator-=(std::uint8_t const& other) const noexcept { + return *this = *this - other; + } + + /// Operator *=, emulating number reference behavior + packed_bit_byte const& operator*=(std::uint8_t const& other) const noexcept { + return *this = *this * other; + } + + /// Operator /=, emulating number reference behavior + packed_bit_byte const& operator/=(std::uint8_t const& other) const noexcept { + return *this = *this / other; + } + + /// Operator %=, emulating number reference behavior + packed_bit_byte const& operator%=(std::uint8_t const& other) const noexcept { + return *this = *this % other; + } + + /// Operator ^=, emulating number reference behavior + packed_bit_byte const& operator^=(std::uint8_t const& other) const noexcept { + return *this = *this ^ other; + } + + /// Operator &=, emulating number reference behavior + packed_bit_byte const& operator&=(std::uint8_t const& other) const noexcept { + return *this = *this & other; + } + + /// Operator |=, emulating number reference behavior + packed_bit_byte const& operator|=(std::uint8_t const& other) const noexcept { + return *this = *this | other; + } + + constexpr packed_bit_byte(packed_bit_byte const& other) : byte(other.byte), mask(other.mask) {} + + private: + friend class iterators::packed_bit_byte; + + constexpr packed_bit_byte(Iterator byte_iter, uint8_t byte_mask) noexcept : byte(byte_iter), mask(byte_mask) {} + + Iterator byte; + std::uint8_t mask; +}; + +/// packed_bit_byte is Swappable even when it's not an lvalue reference +template +void swap(packed_bit_byte a, packed_bit_byte b) noexcept { + std::uint8_t a_value = a; + std::uint8_t b_value = b; + a = b_value; + b = a_value; +} + +} // namespace elements +} // namespace vector +} // namespace v_noabi +} // namespace bsoncxx + +#include + +/// +/// @file +/// Special purpose element reference types for BSON Binary Vector access +/// diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/formats-fwd.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/formats-fwd.hpp new file mode 100644 index 0000000000..18498f9f9c --- /dev/null +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/formats-fwd.hpp @@ -0,0 +1,53 @@ +// Copyright 2009-present MongoDB, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include + +namespace bsoncxx { +namespace v_noabi { +namespace vector { +namespace formats { + +struct f_float32; +struct f_int8; +struct f_packed_bit; + +} // namespace formats +} // namespace vector +} // namespace v_noabi +} // namespace bsoncxx + +namespace bsoncxx { +namespace vector { +namespace formats { + +using ::bsoncxx::v_noabi::vector::formats::f_float32; +using ::bsoncxx::v_noabi::vector::formats::f_int8; +using ::bsoncxx::v_noabi::vector::formats::f_packed_bit; + +} // namespace formats +} // namespace vector +} // namespace bsoncxx + +#include + +/// +/// @file +/// Declares vector formats: +/// @ref bsoncxx::vector::formats::f_float32 +/// @ref bsoncxx::vector::formats::f_int8 +/// @ref bsoncxx::vector::formats::f_packed_bit +/// diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/formats.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/formats.hpp new file mode 100644 index 0000000000..99e8a8855c --- /dev/null +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/formats.hpp @@ -0,0 +1,48 @@ +// Copyright 2009-present MongoDB, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include + +#include + +namespace bsoncxx { +namespace v_noabi { +namespace vector { +namespace formats { + +/// @brief Vector format for 32-bit floating point elements, packed least significant byte first. +struct f_float32 {}; + +/// @brief Vector format for signed 8-bit integer elements. +struct f_int8 {}; + +/// @brief Vector format for single bit elements, packed most significant bit first. +struct f_packed_bit {}; + +} // namespace formats +} // namespace vector +} // namespace v_noabi +} // namespace bsoncxx + +#include + +/// +/// @file +/// Declares vector formats: +/// @ref bsoncxx::v_noabi::vector::formats::f_float32 +/// @ref bsoncxx::v_noabi::vector::formats::f_int8 +/// @ref bsoncxx::v_noabi::vector::formats::f_packed_bit +/// diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/impl.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/impl.hpp new file mode 100644 index 0000000000..163652c5e5 --- /dev/null +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/impl.hpp @@ -0,0 +1,170 @@ +// Copyright 2009-present MongoDB, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include +#include +#include + +#include + +namespace bsoncxx { +namespace v_noabi { +namespace vector { +namespace impl { + +/// @brief Implementation detail. A copy of the validated BSON Binary Vector header, included in each view. +struct header { + std::uint8_t bytes[2]; +}; + +/// @brief Implementation detail. Common data for each view type. +/// @tparam Format One of the @ref bsoncxx::v_noabi::vector::formats types. +template +struct view_data { + using byte_type = typename std::conditional::value, std::uint8_t const, std::uint8_t>::type; + using byte_count_type = std::uint32_t; + + byte_type* bytes; + byte_count_type size; + header header_copy; +}; + +/// @brief Implementation detail. Default format traits. +struct format_traits_base { + using element_count_type = std::size_t; + + using byte_difference_type = std::ptrdiff_t; + using element_difference_type = std::ptrdiff_t; + + using byte_reference = std::uint8_t&; + using const_byte_reference = std::uint8_t const&; + + using byte_iterator = std::uint8_t*; + using const_byte_iterator = std::uint8_t const*; +}; + +/// @brief Implementation detail. Format traits, specialized by format. +/// @tparam Format One of the @ref bsoncxx::v_noabi::vector::formats types. +template +struct format_traits; + +/// @brief Implementation detail. Format traits for bsoncxx::v_noabi::vector::formats::f_int8. +template <> +struct format_traits : format_traits_base { + using value_type = std::int8_t; + + using reference = std::int8_t&; + using const_reference = std::int8_t const&; + using iterator = std::int8_t*; + using const_iterator = std::int8_t const*; + + static BSONCXX_ABI_EXPORT_CDECL(uint32_t) length_for_append(std::size_t element_count); + static BSONCXX_ABI_EXPORT_CDECL(header) + write_frame(uint8_t* binary_data, uint32_t binary_data_length, std::size_t element_count); + static BSONCXX_ABI_EXPORT_CDECL(view_data) const_validate(types::b_binary const& binary); + + static constexpr std::size_t element_count(uint32_t binary_data_length, header) noexcept { + return binary_data_length - sizeof(header::bytes); + } + + static byte_iterator make_byte_iterator(iterator element, iterator) noexcept { + return byte_iterator(static_cast(element)); + } + + static const_byte_iterator make_byte_iterator(const_iterator element, const_iterator) noexcept { + return const_byte_iterator(static_cast(element)); + } +}; + +/// @brief Implementation detail. Format traits for bsoncxx::v_noabi::vector::formats::f_float32. +template <> +struct format_traits : format_traits_base { + using value_type = float; + + using reference = elements::float32&; + using const_reference = elements::float32 const&; + using iterator = elements::float32*; + using const_iterator = elements::float32 const*; + + static BSONCXX_ABI_EXPORT_CDECL(uint32_t) length_for_append(std::size_t element_count); + static BSONCXX_ABI_EXPORT_CDECL(header) + write_frame(uint8_t* binary_data, uint32_t binary_data_length, std::size_t element_count); + static BSONCXX_ABI_EXPORT_CDECL(view_data) const_validate(types::b_binary const& binary); + + static constexpr std::size_t element_count(uint32_t binary_data_length, header) noexcept { + return (binary_data_length - sizeof(header::bytes)) / sizeof(float); + } + + static byte_iterator make_byte_iterator(iterator element, iterator) noexcept { + return byte_iterator(static_cast(element)); + } + + static const_byte_iterator make_byte_iterator(const_iterator element, const_iterator) noexcept { + return const_byte_iterator(static_cast(element)); + } +}; + +/// @brief Implementation detail. Format traits for bsoncxx::v_noabi::vector::formats::f_packed_bit. +template <> +struct format_traits : format_traits_base { + using value_type = bool; + + using iterator = iterators::packed_bit_element; + using const_iterator = iterators::packed_bit_element; + using reference = iterator::reference; + using const_reference = const_iterator::reference; + + using byte_iterator = iterators::packed_bit_byte; + using const_byte_iterator = iterators::packed_bit_byte; + using byte_reference = byte_iterator::reference; + using const_byte_reference = const_byte_iterator::reference; + + using byte_difference_type = byte_iterator::difference_type; + using element_difference_type = iterator::difference_type; + + static BSONCXX_ABI_EXPORT_CDECL(uint32_t) length_for_append(std::size_t element_count); + static BSONCXX_ABI_EXPORT_CDECL(header) + write_frame(uint8_t* binary_data, uint32_t binary_data_length, std::size_t element_count); + static BSONCXX_ABI_EXPORT_CDECL(view_data) const_validate( + types::b_binary const& binary); + + static constexpr std::size_t element_count(uint32_t binary_data_length, header hdr) noexcept { + return std::size_t(binary_data_length - sizeof(hdr.bytes)) * std::size_t(8u) - std::size_t(hdr.bytes[1] & 7u); + } + + static byte_iterator make_byte_iterator(iterator element, iterator element_end) noexcept { + return {element, element_end}; + } + + static constexpr const_byte_iterator make_byte_iterator( + const_iterator element, + const_iterator element_end) noexcept { + return {element, element_end}; + } +}; + +} // namespace impl +} // namespace vector +} // namespace v_noabi +} // namespace bsoncxx + +#include + +/// +/// @file +/// For internal use only! +/// diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/iterators.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/iterators.hpp new file mode 100644 index 0000000000..31025f28a6 --- /dev/null +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/iterators.hpp @@ -0,0 +1,304 @@ +// Copyright 2009-present MongoDB, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include + +#include + +namespace bsoncxx { +namespace v_noabi { +namespace vector { + +template +class view; + +namespace impl { + +template +struct format_traits; + +} // namespace impl + +namespace iterators { + +template +class packed_bit_byte; + +/// @brief Iterator for elements within a packed_bit vector +/// @tparam Iterator Underlying byte iterator type +template +class packed_bit_element { + public: + /// Values pointed to by this iterator are single bits represented by bool. + using value_type = bool; + + /// References to individual bits are each bsoncxx::v_noabi::elements::packed_bit_element. + using reference = elements::packed_bit_element const; + + /// Element pointers aren't really a useful concept here, but this is defined for compatibility with standard + /// random-access iterators. + using pointer = elements::packed_bit_element const*; + + /// This is a standard random-access iterator. + using iterator_category = std::random_access_iterator_tag; + + /// A signed bit count + using difference_type = std::ptrdiff_t; + + /// @brief Dereference this bit iterator into a bit reference. + /// @return An individual bit reference, as a bsoncxx::v_noabi::elements::packed_bit_element. + constexpr reference operator*() const noexcept { + return {byte, bit}; + } + + /// Compare two bit iterators + constexpr bool operator==(packed_bit_element const& other) const noexcept { + return byte == other.byte && bit == other.bit; + } + + /// Compare two bit iterators + constexpr bool operator!=(packed_bit_element const& other) const noexcept { + return byte != other.byte || bit != other.bit; + } + + /// Compare two bit iterators + constexpr bool operator<(packed_bit_element const& other) const noexcept { + return byte < other.byte || (byte == other.byte && bit < other.bit); + } + + /// Compare two bit iterators + constexpr bool operator<=(packed_bit_element const& other) const noexcept { + return byte < other.byte || (byte == other.byte && bit <= other.bit); + } + + /// Compare two bit iterators + constexpr bool operator>(packed_bit_element const& other) const noexcept { + return byte > other.byte || (byte == other.byte && bit > other.bit); + } + + /// Compare two bit iterators + constexpr bool operator>=(packed_bit_element const& other) const noexcept { + return byte > other.byte || (byte == other.byte && bit >= other.bit); + } + + /// @brief Calculate a signed addition of this iterator with a ptrdiff_t, moving it forward or backward the + /// indicated number of bits. + /// If the iterator goes out of range, behavior is undefined. + constexpr packed_bit_element operator+(difference_type const& other) const noexcept { + return { + byte + ((other >> 3) + ((difference_type(bit) + (other & 7)) >> 3)), + std::uint8_t((bit + unsigned(other)) & 7u)}; + } + + /// @brief Calculate a signed subtraction of a ptrdiff_t from this iterator, moving it backward or forward the + /// indicated number of bits. + /// If the iterator goes out of range, behavior is undefined. + constexpr packed_bit_element operator-(difference_type const& other) const noexcept { + return *this + (-other); + } + + /// @brief Calculate the difference in position between two bit iterators + /// If the two iterators do not point into the same vector, behavior is undefined. + constexpr difference_type operator-(packed_bit_element const& other) const noexcept { + return {(byte - other.byte) * 8 + (difference_type(bit) - difference_type(other.bit))}; + } + + /// Advance this iterator forward by the indicated number of bits + packed_bit_element& operator+=(difference_type const& other) noexcept { + return *this = *this + other; + } + + /// Move this iterator backward by the indicated number of bits + packed_bit_element& operator-=(difference_type const& other) noexcept { + return *this = *this - other; + } + + /// Pre-increment + packed_bit_element& operator++() noexcept { + return *this += difference_type(1); + } + + /// Pre-decrement + packed_bit_element& operator--() noexcept { + return *this -= difference_type(1); + } + + /// Post-increment + packed_bit_element operator++(int) noexcept { + packed_bit_element prev = *this; + ++*this; + return prev; + } + + /// Post-decrement + packed_bit_element operator--(int) noexcept { + packed_bit_element prev = *this; + --*this; + return prev; + } + + private: + friend class packed_bit_byte; + friend class view; + friend class view; + + constexpr packed_bit_element(Iterator byte_iter, uint8_t bit_index = 0) noexcept + : byte(byte_iter), bit(bit_index) {} + + Iterator byte; + uint8_t bit; +}; + +/// @brief Iterator for bytes within a packed_bit vector +/// @tparam Iterator Underlying byte iterator type +template +class packed_bit_byte { + public: + /// Values pointed to by this iterator are unsigned bytes. + using value_type = std::uint8_t; + + /// References to individual bytes are each bsoncxx::v_noabi::elements::packed_bit_byte, to protect the validity of + /// bytes with reserved portions. + using reference = elements::packed_bit_byte const; + + /// Element pointers aren't really a useful concept here, but this is defined for compatibility with standard + /// random-access iterators. + using pointer = elements::packed_bit_byte const*; + + /// This is a standard random-access iterator. + using iterator_category = std::random_access_iterator_tag; + + /// A signed byte count + using difference_type = std::ptrdiff_t; + + /// @brief Dereference the byte iterator + /// @return A bsoncxx::v_noabi::elements::packed_bit_byte that can be used like a byte reference. + constexpr reference operator*() const noexcept { + return {byte, (byte + 1) == byte_end ? last_byte_mask : value_type(0xFFu)}; + } + + /// Compare two byte iterators + constexpr bool operator==(packed_bit_byte const& other) const noexcept { + return byte == other.byte; + } + + /// Compare two byte iterators + constexpr bool operator!=(packed_bit_byte const& other) const noexcept { + return byte != other.byte; + } + + /// Compare two byte iterators + constexpr bool operator<(packed_bit_byte const& other) const noexcept { + return byte < other.byte; + } + + /// Compare two byte iterators + constexpr bool operator<=(packed_bit_byte const& other) const noexcept { + return byte <= other.byte; + } + + /// Compare two byte iterators + constexpr bool operator>(packed_bit_byte const& other) const noexcept { + return byte > other.byte; + } + + /// Compare two byte iterators + constexpr bool operator>=(packed_bit_byte const& other) const noexcept { + return byte >= other.byte; + } + + /// @brief Calculate a signed addition of this iterator with a ptrdiff_t, moving it forward or backward the + /// indicated number of bytes. + /// If the iterator goes out of range, behavior is undefined. + constexpr packed_bit_byte operator+(difference_type const& other) const noexcept { + return {byte + other, byte_end, last_byte_mask}; + } + + /// @brief Calculate a signed subtraction of a ptrdiff_t from this iterator, moving it backward or forward the + /// indicated number of bytes. + /// If the iterator goes out of range, behavior is undefined. + constexpr packed_bit_byte operator-(difference_type const& other) const noexcept { + return *this + (-other); + } + + /// @brief Calculate the difference in position between two byte iterators + /// If the two iterators do not point into the same vector, behavior is undefined. + constexpr difference_type operator-(packed_bit_byte const& other) const noexcept { + return {byte - other.byte}; + } + + /// Advance this iterator forward by the indicated number of bytes + packed_bit_byte& operator+=(difference_type const& other) noexcept { + return *this = *this + other; + } + + /// Move this iterator backward by the indicated number of bytes + packed_bit_byte& operator-=(difference_type const& other) noexcept { + return *this = *this - other; + } + + /// Pre-increment + packed_bit_byte& operator++() noexcept { + return *this += difference_type(1); + } + + /// Pre-decrement + packed_bit_byte& operator--() noexcept { + return *this -= difference_type(1); + } + + /// Post-increment + packed_bit_byte operator++(int) noexcept { + packed_bit_byte prev = *this; + ++*this; + return prev; + } + + /// Post-decrement + packed_bit_byte operator--(int) noexcept { + packed_bit_byte prev = *this; + --*this; + return prev; + } + + private: + friend struct impl::format_traits; + friend struct impl::format_traits; + + constexpr packed_bit_byte(packed_bit_element element, packed_bit_element element_end) + : byte(element.byte), + byte_end((element_end + 7u).byte), + last_byte_mask(value_type(0xFFu << (-element_end.bit & 7u))) {} + + constexpr packed_bit_byte(Iterator byte, Iterator byte_end, value_type last_byte_mask) + : byte(byte), byte_end(byte_end), last_byte_mask(last_byte_mask) {} + + Iterator byte; + Iterator byte_end; + value_type last_byte_mask; +}; + +} // namespace iterators +} // namespace vector +} // namespace v_noabi +} // namespace bsoncxx + +#include + +/// +/// @file +/// Special purpose iterator types for BSON Binary Vector access +/// diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/view-fwd.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/view-fwd.hpp new file mode 100644 index 0000000000..f9692864cc --- /dev/null +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/view-fwd.hpp @@ -0,0 +1,43 @@ +// Copyright 2009-present MongoDB, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include + +namespace bsoncxx { +namespace v_noabi { +namespace vector { + +template +class view; + +} // namespace vector +} // namespace v_noabi +} // namespace bsoncxx + +namespace bsoncxx { +namespace vector { + +using ::bsoncxx::v_noabi::vector::view; + +} // namespace vector +} // namespace bsoncxx + +#include + +/// +/// @file +/// Declares @ref bsoncxx::vector::view. +/// diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/view.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/view.hpp new file mode 100644 index 0000000000..a3ed76fc76 --- /dev/null +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/view.hpp @@ -0,0 +1,281 @@ +// Copyright 2009-present MongoDB, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include + +#include + +#include +#include + +#include + +namespace bsoncxx { +namespace v_noabi { + +namespace builder { +namespace basic { +class sub_binary; +} // namespace basic +} // namespace builder + +namespace vector { + +/// @brief Accessor for the contents of a valid BSON Binary Vector +/// @tparam Format One of the @ref bsoncxx::v_noabi::vector::formats types, optionally with a const qualifier. +/// +/// This accessor operates on data formatted for the bsoncxx::v_noabi::binary_sub_type::k_vector BSON binary +/// subtype. A mutable view may be constructed only using bsoncxx::v_noabi::builder::basic::sub_binary. A const +/// view may be constructed by validating a bsoncxx::v_noabi::types::b_binary. +/// +/// The specific iterator and element types vary for each supported format. When possible, +/// iterators are raw pointers. +/// +/// bsoncxx::v_noabi::vector::formats::f_float32 uses a custom element type to support packed storage with a fixed byte +/// order. +/// +/// bsoncxx::v_noabi::vector::formats::f_packed_bit uses a custom element and iterator type for single bits that unpacks +/// them as bool. It also has custom element and iterator types for byte access, which serve to mask writes to reserved +/// bits. +/// +template +class view { + using format_traits = typename impl::format_traits::type>; + + public: + using format = Format; + + using const_value_type = typename format_traits::value_type const; + using value_type = typename std::conditional< + std::is_const::value, + typename format_traits::value_type const, + typename format_traits::value_type>::type; + + using const_reference = typename format_traits::const_reference; + using reference = typename std::conditional< + std::is_const::value, + typename format_traits::const_reference, + typename format_traits::reference>::type; + + using const_iterator = typename format_traits::const_iterator; + using iterator = typename std::conditional< + std::is_const::value, + typename format_traits::const_iterator, + typename format_traits::iterator>::type; + + using byte_type = typename impl::view_data::byte_type; + using byte_count_type = typename impl::view_data::byte_count_type; + using element_count_type = typename format_traits::element_count_type; + using byte_difference_type = typename format_traits::byte_difference_type; + using element_difference_type = typename format_traits::element_difference_type; + + using const_byte_reference = typename format_traits::const_byte_reference; + using byte_reference = typename std::conditional< + std::is_const::value, + typename format_traits::const_byte_reference, + typename format_traits::byte_reference>::type; + + using const_byte_iterator = typename format_traits::const_byte_iterator; + using byte_iterator = typename std::conditional< + std::is_const::value, + typename format_traits::const_byte_iterator, + typename format_traits::byte_iterator>::type; + + /// @brief Construct a const Vector view by validating a bsoncxx::v_noabi::types::b_binary reference. + /// @param binary Non-owning reference to BSON binary data + /// @throws If the data can't be validated, throws bsoncxx::v_noabi::exception with + /// bsoncxx::v_noabi::error_code::k_invalid_vector, if the vector + /// + /// The Binary data is validated as a Vector of the templated Format. On success, a view is created which + /// references the same data as the bsoncxx::v_noabi::types::b_binary pointer. + view(types::b_binary const& binary) : impl_data(format_traits::const_validate(binary)) {} + + /// @brief Count the bytes of element data + /// @return Size of the vector data, not including any headers + constexpr byte_count_type byte_size() const noexcept { + return impl_data.size - sizeof(impl::header::bytes); + } + + /// @brief Count the number of elements + /// @return Number of elements + constexpr element_count_type size() const noexcept { + return format_traits::element_count(impl_data.size, impl_data.header_copy); + } + + /// @brief Obtain an iterator pointing to the beginning of the vector + /// @return A per-element random access iterator, pointing at the first element if one exists + constexpr iterator begin() const noexcept { + return iterator(impl_data.bytes + sizeof(impl::header::bytes)); + } + + /// @brief Obtain an iterator pointing just past the end of the vector + /// @return A per-element random access iterator, pointing just past the end of the vector + constexpr iterator end() const noexcept { + return begin() + element_difference_type(size()); + } + + /// @brief Obtain a reference to the first element + /// @return An element reference + /// Undefined behavior if the vector is empty. + reference front() noexcept { + return *begin(); + } + + /// @brief Obtain a const reference to the first element + /// @return An element reference + /// Undefined behavior if the vector is empty. + constexpr const_reference front() const noexcept { + return *begin(); + } + + /// @brief Obtain a reference to the last element + /// @return An element reference + /// Undefined behavior if the vector is empty. + reference back() noexcept { + return *(begin() + element_difference_type(size() - 1u)); + } + + /// @brief Obtain a const reference to the last element + /// @return An element reference + /// Undefined behavior if the vector is empty. + constexpr const_reference back() const noexcept { + return *(begin() + element_difference_type(size() - 1u)); + } + + /// @brief Obtain a byte iterator pointing to the beginning of the vector + /// @return A per-byte random access iterator, pointing at the first byte if one exists + constexpr byte_iterator byte_begin() const noexcept { + return format_traits::make_byte_iterator(begin(), end()); + } + + /// @brief Obtain a byte iterator pointing just past the end of the vector + /// @return A per-byte random access iterator, pointing just past the end of the vector + constexpr byte_iterator byte_end() const noexcept { + return byte_begin() + byte_difference_type(byte_size()); + } + + /// @brief Obtain a reference to the first byte + /// @return A byte reference + /// Undefined behavior if the vector is empty. + byte_reference byte_front() noexcept { + return *byte_begin(); + } + + /// @brief Obtain a const reference to the first byte + /// @return A byte reference + /// Undefined behavior if the vector is empty. + constexpr const_byte_reference byte_front() const noexcept { + return *byte_begin(); + } + + /// @brief Obtain a reference to the last byte + /// @return A byte reference + /// Undefined behavior if the vector is empty. + byte_reference byte_back() noexcept { + return *(byte_begin() + byte_difference_type(byte_size() - 1u)); + } + + /// @brief Obtain a const reference to the last byte + /// @return A byte reference + /// Undefined behavior if the vector is empty. + constexpr const_byte_reference byte_back() const noexcept { + return *(byte_begin() + byte_difference_type(byte_size() - 1u)); + } + + /// @brief Obtain a reference to a numbered byte, with bounds checking + /// @param index Index in the range 0 to byte_size()-1 inclusive. + /// @return A byte reference + /// @throws std::out_of_range, if the index is outside the allowed range. + byte_reference byte_at(byte_count_type index) { + if (index >= byte_size()) { + throw std::out_of_range{"bsoncxx::vector::view::byte_at()"}; + } + return *(byte_begin() + byte_difference_type(index)); + } + + /// @brief Obtain a const reference to a numbered byte, with bounds checking + /// @param index Index in the range 0 to byte_size()-1 inclusive. + /// @return A byte reference + /// @throws std::out_of_range, if the index is outside the allowed range. + const_byte_reference byte_at(byte_count_type index) const { + if (index >= byte_size()) { + throw std::out_of_range{"bsoncxx::vector::view::byte_at()"}; + } + return *(byte_begin() + byte_difference_type(index)); + } + + /// @brief Obtain a reference to a numbered element, with bounds checking + /// @param index Index in the range 0 to size()-1 inclusive. + /// @return An element reference + /// @throws std::out_of_range, if the index is outside the allowed range. + reference at(element_count_type index) { + if (index >= size()) { + throw std::out_of_range{"bsoncxx::vector::view::at()"}; + } + return *(begin() + element_difference_type(index)); + } + + /// @brief Obtain a const reference to a numbered element, with bounds checking + /// @param index Index in the range 0 to size()-1 inclusive. + /// @return An element reference + /// @throws std::out_of_range, if the index is outside the allowed range. + const_reference at(element_count_type index) const { + if (index >= size()) { + throw std::out_of_range{"bsoncxx::vector::view::at()"}; + } + return *(begin() + element_difference_type(index)); + } + + /// @brief Obtain a reference to a numbered element, without bounds checking + /// @param index Index in the range 0 to size()-1 inclusive. + /// @return An element reference + /// Undefined behavior if the index is out of bounds. + reference operator[](element_count_type index) noexcept { + return *(begin() + element_difference_type(index)); + } + + /// @brief Obtain a const reference to a numbered element, without bounds checking + /// @param index Index in the range 0 to size()-1 inclusive. + /// @return An element reference + /// Undefined behavior if the index is out of bounds. + constexpr const_reference operator[](element_count_type index) const noexcept { + return *(begin() + element_difference_type(index)); + } + + /// @brief Test whether the vector is empty + /// @return True if the vector has a size() of zero. + constexpr bool empty() const noexcept { + return size() == 0u; + } + + private: + friend class bsoncxx::v_noabi::builder::basic::sub_binary; + + view(impl::view_data data) noexcept : impl_data(data) {} + + impl::view_data impl_data; +}; + +} // namespace vector +} // namespace v_noabi +} // namespace bsoncxx + +#include + +/// +/// @file +/// Declares @ref bsoncxx::v_noabi::vector::view. +/// diff --git a/src/bsoncxx/lib/CMakeLists.txt b/src/bsoncxx/lib/CMakeLists.txt index 282ed5b9d9..2a900c9a10 100644 --- a/src/bsoncxx/lib/CMakeLists.txt +++ b/src/bsoncxx/lib/CMakeLists.txt @@ -37,6 +37,7 @@ set(bsoncxx_sources_v_noabi bsoncxx/v_noabi/bsoncxx/types/bson_value/value.cpp bsoncxx/v_noabi/bsoncxx/types/bson_value/view.cpp bsoncxx/v_noabi/bsoncxx/validate.cpp + bsoncxx/v_noabi/bsoncxx/vector.cpp ) set(bsoncxx_sources_v1 diff --git a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/vector.cpp b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/vector.cpp new file mode 100644 index 0000000000..7b9fb72063 --- /dev/null +++ b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/vector.cpp @@ -0,0 +1,120 @@ +// Copyright 2009-present MongoDB, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include +#include +#include + +#include + +namespace bsoncxx { +namespace v_noabi { +namespace vector { +namespace impl { + +enum element_type : std::uint8_t { + signed_integer = 0, + unsigned_integer = 1, + floating_point = 2, +}; + +enum element_size : std::uint8_t { + bits_1 = 0, + bits_8 = 3, + bits_32 = 7, +}; + +static header make_header(element_type element_type, element_size element_size, std::uint8_t padding) { + return header{{(std::uint8_t)((std::uint8_t)element_type << 4 | (std::uint8_t)element_size), padding}}; +} + +static header copy_header(std::uint8_t const* bytes) { + header result; + memcpy(&result.bytes, bytes, sizeof result.bytes); + return result; +} + +template +static std::uint32_t libbson_length_for_append(std::size_t element_count, Impl func) { + std::uint32_t result = func(element_count); + if (result < sizeof(header::bytes)) { + throw bsoncxx::v_noabi::exception{error_code::k_vector_too_large}; + } + return result; +} + +std::uint32_t format_traits::length_for_append(std::size_t element_count) { + return libbson_length_for_append(element_count, bson_vector_int8_binary_data_length); +} + +std::uint32_t format_traits::length_for_append(std::size_t element_count) { + return libbson_length_for_append(element_count, bson_vector_float32_binary_data_length); +} + +std::uint32_t format_traits::length_for_append(std::size_t element_count) { + return libbson_length_for_append(element_count, bson_vector_packed_bit_binary_data_length); +} + +header format_traits::write_frame(std::uint8_t* binary_data, std::uint32_t, std::size_t) { + header hdr = make_header(element_type::signed_integer, element_size::bits_8, 0); + memcpy(binary_data, &hdr, sizeof hdr); + return hdr; +} + +header format_traits::write_frame(std::uint8_t* binary_data, std::uint32_t, std::size_t) { + header hdr = make_header(element_type::floating_point, element_size::bits_32, 0); + memcpy(binary_data, &hdr, sizeof hdr); + return hdr; +} + +header format_traits::write_frame( + std::uint8_t* binary_data, + std::uint32_t binary_data_length, + std::size_t element_count) { + header hdr = make_header( + element_type::unsigned_integer, element_size::bits_1, std::uint8_t(std::size_t(7u) & -element_count)); + binary_data[binary_data_length - 1] = UINT8_C(0); + memcpy(binary_data, &hdr, sizeof hdr); + return hdr; +} + +template +static view_data libbson_const_validate(bsoncxx::v_noabi::types::b_binary const& binary, Impl func) { + if (binary.sub_type != binary_sub_type::k_vector || !func(NULL, binary.bytes, binary.size)) { + throw bsoncxx::v_noabi::exception{error_code::k_invalid_vector}; + } + return {binary.bytes, binary.size, copy_header(binary.bytes)}; +} + +view_data format_traits::const_validate( + bsoncxx::v_noabi::types::b_binary const& binary) { + return libbson_const_validate(binary, bson_vector_int8_const_view_init); +} + +view_data format_traits::const_validate( + bsoncxx::v_noabi::types::b_binary const& binary) { + return libbson_const_validate(binary, bson_vector_float32_const_view_init); +} + +view_data format_traits::const_validate( + bsoncxx::v_noabi::types::b_binary const& binary) { + return libbson_const_validate(binary, bson_vector_packed_bit_const_view_init); +} + +} // namespace impl +} // namespace vector +} // namespace v_noabi +} // namespace bsoncxx From f573b11f6e84790cb92ad92b7b68bc9e0d6e9133 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Wed, 19 Mar 2025 21:12:28 -0700 Subject: [PATCH 10/83] sub_binary builder and integration with core --- .../v_noabi/bsoncxx/builder/basic/impl.hpp | 16 +++- .../bsoncxx/builder/basic/sub_binary-fwd.hpp | 42 +++++++++ .../bsoncxx/builder/basic/sub_binary.hpp | 86 +++++++++++++++++++ .../bsoncxx/v_noabi/bsoncxx/builder/core.hpp | 25 ++++++ .../bsoncxx/v_noabi/bsoncxx/builder/core.cpp | 24 ++++++ 5 files changed, 190 insertions(+), 3 deletions(-) create mode 100644 src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/sub_binary-fwd.hpp create mode 100644 src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/sub_binary.hpp diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/impl.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/impl.hpp index 578a41ae7e..cc7c14efed 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/impl.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/impl.hpp @@ -15,6 +15,7 @@ #pragma once #include +#include #include #include @@ -40,10 +41,19 @@ detail::requires_t> generic_append(core core->close_array(); } +template +detail::requires_t> generic_append(core* core, T&& func) { + detail::invoke(std::forward(func), sub_binary(core)); + core->close_binary(); +} + template -detail::requires_not_t, detail::is_invocable> generic_append( - core* core, - T&& t) { +detail::requires_not_t< + void, + detail::is_invocable, + detail::is_invocable, + detail::is_invocable> +generic_append(core* core, T&& t) { core->append(std::forward(t)); } diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/sub_binary-fwd.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/sub_binary-fwd.hpp new file mode 100644 index 0000000000..984fddaeeb --- /dev/null +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/sub_binary-fwd.hpp @@ -0,0 +1,42 @@ +// Copyright 2009-present MongoDB, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +namespace bsoncxx { +namespace v_noabi { +namespace builder { +namespace basic { + +class sub_binary; + +} // namespace basic +} // namespace builder +} // namespace v_noabi +} // namespace bsoncxx + +namespace bsoncxx { +namespace builder { +namespace basic { + +using ::bsoncxx::v_noabi::builder::basic::sub_binary; + +} // namespace basic +} // namespace builder +} // namespace bsoncxx + +/// +/// @file +/// Declares @ref bsoncxx::builder::basic::sub_binary, for constructing BSON Binary values in-place. +/// diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/sub_binary.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/sub_binary.hpp new file mode 100644 index 0000000000..b3c4ff141a --- /dev/null +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/sub_binary.hpp @@ -0,0 +1,86 @@ +// Copyright 2009-present MongoDB, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include + +#include +#include +#include +#include +#include + +#include + +namespace bsoncxx { +namespace v_noabi { +namespace builder { +namespace basic { + +/// +/// Represents a BSON Binary element being constructed during an append operation. +/// +class sub_binary { + public: + /// + /// Default constructor + /// + sub_binary(core* core) : _core(core) {} + + /// @brief Allocate space for an un-initialized BSON Binary element of any subtype. + /// @param sub_type BSON binary subtype code, identifying the format of the data within. + /// @param length Number of bytes to allocate + /// @return Pointer to uninitialized memory within the bson_t, valid only during this sub_binary builder's lifetime. + /// The caller must overwrite every byte if the resulting BSON document is to be used. + /// @throws bsoncxx::v_noabi::exception if this sub_binary has already allocated. + /// bsoncxx::v_noabi::exception if the binary fails to append due to the BSON size limit. + uint8_t* allocate(binary_sub_type sub_type, uint32_t length) { + return _core->append(sub_type, length); + } + + /// @brief Allocate and format space for a BSON Binary Vector with uninitialized elements. + /// @param fmt Instance of a format type from @ref bsoncxx::v_noabi::vector::formats + /// @param element_count Number of elements to allocate space for. + /// @return A vector::view, valid during the lifetime of this sub_binary builder. Every element must be overwritten + /// before that element is read or the resulting document is used. + /// @throws bsoncxx::v_noabi::exception if this sub_binary has already allocated. + /// bsoncxx::v_noabi::exception if the binary fails to append due to the BSON size limit. + /// bsoncxx::v_noabi::exception if a vector of the requested size would be too large to represent. + template ::value_type> + vector::view allocate(Format, std::size_t element_count) { + using format_traits = typename vector::impl::format_traits; + uint32_t binary_data_length = format_traits::length_for_append(element_count); + uint8_t* binary_data = allocate(binary_sub_type::k_vector, binary_data_length); + return { + {binary_data, + binary_data_length, + format_traits::write_frame(binary_data, binary_data_length, element_count)}}; + } + + private: + core* _core; +}; + +} // namespace basic +} // namespace builder +} // namespace v_noabi +} // namespace bsoncxx + +#include + +/// +/// @file +/// Declares @ref bsoncxx::v_noabi::builder::basic::sub_binary, for constructing BSON Binary values in-place. +/// diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/core.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/core.hpp index 2c04a739fc..d0eb406dee 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/core.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/core.hpp @@ -237,6 +237,20 @@ class core { /// BSONCXX_ABI_EXPORT_CDECL(core&) append(types::b_binary const& value); + /// + /// Appends a BSON binary datum by allocating space that the caller must fill with content. + /// + /// @return + /// A pointer to the allocated binary data block. The caller must write to every + /// byte or discard the builder. + /// + /// @throws + /// bsoncxx::v_noabi::exception if the current BSON datum is a document that is waiting for a + /// key to be appended to start a new key/value pair. + /// bsoncxx::v_noabi::exception if the binary fails to append. + /// + BSONCXX_ABI_EXPORT_CDECL(uint8_t*) append(binary_sub_type sub_type, uint32_t length); + /// /// Appends a BSON undefined. /// @@ -693,6 +707,17 @@ class core { /// BSONCXX_ABI_EXPORT_CDECL(void) clear(); + /// + /// Closes the current sub-binary within this BSON datum. + /// + /// @return + /// A reference to the object on which this member function is being called. This facilitates + /// method chaining. + /// + /// @throws bsoncxx::v_noabi::exception if the binary contents were never allocated. + /// + BSONCXX_ABI_EXPORT_CDECL(core&) close_binary(); + private: std::unique_ptr _impl; }; diff --git a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/builder/core.cpp b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/builder/core.cpp index 1b06149488..16b7e4bd8f 100644 --- a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/builder/core.cpp +++ b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/builder/core.cpp @@ -351,6 +351,23 @@ core& core::append(types::b_binary const& value) { return *this; } +uint8_t* core::append(binary_sub_type sub_type, uint32_t length) { + stdx::string_view key = _impl->next_key(); + uint8_t* allocated_bytes; + + if (!bson_append_binary_uninit( + _impl->back(), + key.data(), + static_cast(key.length()), + static_cast(sub_type), + &allocated_bytes, + length)) { + throw bsoncxx::v_noabi::exception{error_code::k_cannot_append_binary}; + } + + return allocated_bytes; +} + core& core::append(types::b_undefined const&) { stdx::string_view key = _impl->next_key(); @@ -685,6 +702,13 @@ core& core::close_array() { return *this; } +core& core::close_binary() { + if (!_impl->is_viewable()) { + throw bsoncxx::v_noabi::exception{error_code::k_unmatched_key_in_builder}; + } + return *this; +} + bsoncxx::v_noabi::document::view core::view_document() const { if (!_impl->is_viewable()) { throw bsoncxx::v_noabi::exception{error_code::k_unmatched_key_in_builder}; From 2b5c35a21340d55afc74bf3acd2add543684082b Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Thu, 20 Mar 2025 11:20:21 -0700 Subject: [PATCH 11/83] remove obsolete workaround for CDRIVER-5732 --- examples/api/bsoncxx/examples/bson_errors/big_string.hh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/api/bsoncxx/examples/bson_errors/big_string.hh b/examples/api/bsoncxx/examples/bson_errors/big_string.hh index d8d14af18e..35d0eecd66 100644 --- a/examples/api/bsoncxx/examples/bson_errors/big_string.hh +++ b/examples/api/bsoncxx/examples/bson_errors/big_string.hh @@ -27,8 +27,7 @@ namespace examples { // Used to trigger builder append failure. struct big_string { // BSON_SIZE_MAX == 0x7FFFFFFF - // Leave some room for CDRIVER-5732. - std::size_t length{static_cast(std::numeric_limits::max() - 32u)}; + std::size_t length{static_cast(std::numeric_limits::max())}; // Allocate an UNINITIALIZED blob of data that will not be accessed due to length checks. // Leaving memory unitialized (rather than zero-init) should hopefully avoid slow and expensive From 16b8e1f252da2b9ba58f16c8af83f7e6b6a2a1f8 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Thu, 20 Mar 2025 11:49:52 -0700 Subject: [PATCH 12/83] avoid int32 overflow prior to bson_append_utf8 invocation --- .../lib/bsoncxx/v_noabi/bsoncxx/builder/core.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/builder/core.cpp b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/builder/core.cpp index 16b7e4bd8f..c00231dfcc 100644 --- a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/builder/core.cpp +++ b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/builder/core.cpp @@ -298,13 +298,14 @@ core& core::append(types::b_double const& value) { core& core::append(types::b_string const& value) { stdx::string_view key = _impl->next_key(); - - if (!bson_append_utf8( - _impl->back(), - key.data(), - static_cast(key.length()), - value.value.data(), - static_cast(value.value.length()))) { + std::size_t value_length = value.value.length(); + + if (value_length > std::size_t{INT32_MAX} || !bson_append_utf8( + _impl->back(), + key.data(), + static_cast(key.length()), + value.value.data(), + static_cast(value_length))) { throw bsoncxx::v_noabi::exception{error_code::k_cannot_append_string}; } From 5c6d77e7646373d7780a3b93f5e8bacee5195396 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Thu, 20 Mar 2025 13:25:01 -0700 Subject: [PATCH 13/83] Temporary MONGOC_VERSION_MINIMUM bump for pre-2.0.0 --- .../config_generator/components/funcs/install_c_driver.py | 3 ++- .evergreen/generated_configs/functions.yml | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.evergreen/config_generator/components/funcs/install_c_driver.py b/.evergreen/config_generator/components/funcs/install_c_driver.py index 29e886d159..fd8649de78 100644 --- a/.evergreen/config_generator/components/funcs/install_c_driver.py +++ b/.evergreen/config_generator/components/funcs/install_c_driver.py @@ -14,7 +14,8 @@ # Only LIBMONGOC_DOWNLOAD_VERSION needs to be updated when pinning to an unreleased commit. # If pinning to an unreleased commit, create a "Blocked" JIRA ticket with # a "depends on" link to the appropriate C Driver version release ticket. -MONGOC_VERSION_MINIMUM = '1.30.1' +# TODO: Temporary for pre-2.0.0 Libmongoc. Update when 2.0.0 is released. +MONGOC_VERSION_MINIMUM = '0b3bb26c586c8a341710b853183abe5946693931' class InstallCDriver(Function): diff --git a/.evergreen/generated_configs/functions.yml b/.evergreen/generated_configs/functions.yml index c3448b6d91..985af36b92 100644 --- a/.evergreen/generated_configs/functions.yml +++ b/.evergreen/generated_configs/functions.yml @@ -398,7 +398,7 @@ functions: type: setup params: updates: - - { key: mongoc_version_minimum, value: 1.30.1 } + - { key: mongoc_version_minimum, value: 0b3bb26c586c8a341710b853183abe5946693931 } - command: subprocess.exec type: setup params: From 37fe267b9cf93aaab3d07b49367b743aef0913f2 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Thu, 20 Mar 2025 13:41:30 -0700 Subject: [PATCH 14/83] Fixes for conversion warnings --- .../bsoncxx/v_noabi/bsoncxx/vector/elements.hpp | 10 +++++----- .../include/bsoncxx/v_noabi/bsoncxx/vector/view.hpp | 2 +- src/bsoncxx/test/vector.cpp | 9 ++++++++- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/elements.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/elements.hpp index c33a8b2546..e9f79b989b 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/elements.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/elements.hpp @@ -117,7 +117,7 @@ class packed_bit_element { /// Set the value of the element referenced packed_bit_element const& operator=(value_type const& v) const { if (v == 0) { - *byte &= ~mask; + *byte &= std::uint8_t(~mask); } else { *byte |= mask; } @@ -141,7 +141,7 @@ class packed_bit_element { /// Operator *=, emulating number reference behavior packed_bit_element const& operator*=(value_type const& other) const noexcept { - return *this = *this * other; + return *this = *this && other; // Avoid int-in-bool-context warning } /// Operator /=, emulating number reference behavior @@ -216,17 +216,17 @@ class packed_bit_byte { /// Operator +=, emulating number reference behavior packed_bit_byte const& operator+=(std::uint8_t const& other) const noexcept { - return *this = *this + other; + return *this = std::uint8_t(*this + other); } /// Operator -=, emulating number reference behavior packed_bit_byte const& operator-=(std::uint8_t const& other) const noexcept { - return *this = *this - other; + return *this = std::uint8_t(*this - other); } /// Operator *=, emulating number reference behavior packed_bit_byte const& operator*=(std::uint8_t const& other) const noexcept { - return *this = *this * other; + return *this = std::uint8_t(*this * other); } /// Operator /=, emulating number reference behavior diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/view.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/view.hpp index a3ed76fc76..e29ca6548b 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/view.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/view.hpp @@ -106,7 +106,7 @@ class view { /// @brief Count the bytes of element data /// @return Size of the vector data, not including any headers constexpr byte_count_type byte_size() const noexcept { - return impl_data.size - sizeof(impl::header::bytes); + return impl_data.size - byte_count_type(sizeof(impl::header::bytes)); } /// @brief Count the number of elements diff --git a/src/bsoncxx/test/vector.cpp b/src/bsoncxx/test/vector.cpp index b04c15f170..8fafbbd117 100644 --- a/src/bsoncxx/test/vector.cpp +++ b/src/bsoncxx/test/vector.cpp @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include + #include #include @@ -150,6 +152,9 @@ void iterator_operations( std::sort(begin, end); std::for_each(begin, end, [&](auto const& value) { REQUIRE(value == element_unit); }); + BSONCXX_PRIVATE_WARNINGS_PUSH(); + BSONCXX_PRIVATE_WARNINGS_DISABLE(GCC("-Wconversion")); + std::for_each(begin, end, [&](auto&& value) { value -= element_unit; }); std::for_each(begin, end, [&](auto&& value) { value *= element_unit; }); std::for_each(begin, end, [&](auto&& value) { value /= element_unit; }); @@ -164,6 +169,8 @@ void iterator_operations( std::for_each(begin, end, [&](auto&& value) { value *= element_unit; }); std::for_each(begin, end, [&](auto&& value) { value /= element_unit; }); std::for_each(begin, end, [&](auto const& value) { REQUIRE(value == element_unit); }); + + BSONCXX_PRIVATE_WARNINGS_POP(); } TEMPLATE_TEST_CASE("all vector view formats", "[bsoncxx::vector::view]", ALL_VECTOR_FORMATS) { @@ -218,7 +225,7 @@ TEMPLATE_TEST_CASE("all vector view formats", "[bsoncxx::vector::view]", ALL_VEC SECTION("reject empty vectors with any modified header bits") { for (unsigned bit_index = 0; bit_index < 16; bit_index++) { auto bytes = test_format_specific::bytes_empty(); - bytes[bit_index >> 3u] ^= 1u << (bit_index & 7u); + bytes[bit_index >> 3u] ^= std::uint8_t(1u << (bit_index & 7u)); types::b_binary const binary{binary_sub_type::k_vector, bytes.size(), bytes.data()}; REQUIRE_THROWS_WITH( vector::view(binary), Catch::Matchers::ContainsSubstring("invalid BSON vector")); From d577c15379cd2cca307d06cf2e0358395f996fed Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Thu, 20 Mar 2025 14:36:47 -0700 Subject: [PATCH 15/83] Add missing includes --- .../include/bsoncxx/v_noabi/bsoncxx/vector/iterators.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/iterators.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/iterators.hpp index 31025f28a6..57f3424c57 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/iterators.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/iterators.hpp @@ -14,7 +14,10 @@ #pragma once +#include + #include +#include #include From d93b1d7e669bc22b999030a3bd96a8b35c264ec5 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Thu, 20 Mar 2025 14:57:46 -0700 Subject: [PATCH 16/83] Fix endian detection for win32 --- .../bsoncxx/v_noabi/bsoncxx/vector/elements.hpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/elements.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/elements.hpp index e9f79b989b..8616723739 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/elements.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/elements.hpp @@ -14,6 +14,10 @@ #pragma once +#ifndef _WIN32 +#include // Endian detection +#endif + #include #include @@ -41,9 +45,11 @@ class float32 { /// @brief Construct a packed little-endian value from a float input in the local byte order. /// @param value Floating point value to convert float32(float value) noexcept { -#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) +#if (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) || \ + defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && (__BYTE_ORDER == __LITTLE_ENDIAN) std::memcpy(bytes, &value, sizeof value); -#elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) +#elif (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) || \ + defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && (__BYTE_ORDER == __BIG_ENDIAN) std::uint32_t u32; std::memcpy(&u32, &value, sizeof value); u32 = bswap32(u32); @@ -56,9 +62,11 @@ class float32 { /// Convert a packed little-endian floating point value back to the local byte order. operator float() const noexcept { float value; -#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) +#if (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) || \ + defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && (__BYTE_ORDER == __LITTLE_ENDIAN) std::memcpy(&value, bytes, sizeof value); -#elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) +#elif (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) || \ + defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && (__BYTE_ORDER == __BIG_ENDIAN) std::uint32_t u32; std::memcpy(&u32, bytes, sizeof value); u32 = bswap32(u32); From d29c352ed48fb9de4146ef583a5319db86269ebe Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Thu, 20 Mar 2025 15:12:38 -0700 Subject: [PATCH 17/83] fixup! Fix endian detection for win32 --- .../v_noabi/bsoncxx/vector/elements.hpp | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/elements.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/elements.hpp index 8616723739..d69c64364d 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/elements.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/elements.hpp @@ -45,14 +45,15 @@ class float32 { /// @brief Construct a packed little-endian value from a float input in the local byte order. /// @param value Floating point value to convert float32(float value) noexcept { -#if (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) || \ +#if defined(_WIN32) || \ + (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) || \ defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && (__BYTE_ORDER == __LITTLE_ENDIAN) std::memcpy(bytes, &value, sizeof value); #elif (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) || \ defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && (__BYTE_ORDER == __BIG_ENDIAN) std::uint32_t u32; std::memcpy(&u32, &value, sizeof value); - u32 = bswap32(u32); + u32 = __builtin_bswap32(u32); std::memcpy(bytes, &u32, sizeof value); #else #error No implementation for storing 32-bit little endian unaligned float @@ -62,14 +63,15 @@ class float32 { /// Convert a packed little-endian floating point value back to the local byte order. operator float() const noexcept { float value; -#if (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) || \ +#if defined(_WIN32) || \ + (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) || \ defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && (__BYTE_ORDER == __LITTLE_ENDIAN) std::memcpy(&value, bytes, sizeof value); #elif (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) || \ defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && (__BYTE_ORDER == __BIG_ENDIAN) std::uint32_t u32; std::memcpy(&u32, bytes, sizeof value); - u32 = bswap32(u32); + u32 = __builtin_bswap32(u32); std::memcpy(&value, &u32, sizeof value); #else #error No implementation for loading 32-bit little endian unaligned float @@ -98,14 +100,6 @@ class float32 { } private: - static std::uint32_t bswap32(std::uint32_t value) { -#ifndef _WIN32 - return __builtin_bswap32(value); -#else - return _byteswap_ulong(value); -#endif - } - std::uint8_t bytes[4]; }; From 5019c3d29089d2f5f361e75301ff40e6f7fd39be Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Thu, 20 Mar 2025 15:42:26 -0700 Subject: [PATCH 18/83] Replace problematic operator overloads and tests --- .../v_noabi/bsoncxx/vector/elements.hpp | 41 ++++++------------- src/bsoncxx/test/vector.cpp | 17 +++----- 2 files changed, 18 insertions(+), 40 deletions(-) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/elements.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/elements.hpp index d69c64364d..3e9c16ce66 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/elements.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/elements.hpp @@ -131,42 +131,17 @@ class packed_bit_element { return *this = value_type(v); } - /// Operator +=, emulating number reference behavior - packed_bit_element const& operator+=(value_type const& other) const noexcept { - return *this = *this + other; - } - - /// Operator -=, emulating number reference behavior - packed_bit_element const& operator-=(value_type const& other) const noexcept { - return *this = *this - other; - } - - /// Operator *=, emulating number reference behavior - packed_bit_element const& operator*=(value_type const& other) const noexcept { - return *this = *this && other; // Avoid int-in-bool-context warning - } - - /// Operator /=, emulating number reference behavior - packed_bit_element const& operator/=(value_type const& other) const noexcept { - return *this = *this / other; - } - - /// Operator %=, emulating number reference behavior - packed_bit_element const& operator%=(value_type const& other) const noexcept { - return *this = *this % other; - } - - /// Operator ^=, emulating number reference behavior + /// Operator ^=, emulating bool reference behavior packed_bit_element const& operator^=(value_type const& other) const noexcept { return *this = *this ^ other; } - /// Operator &=, emulating number reference behavior + /// Operator &=, emulating bool reference behavior packed_bit_element const& operator&=(value_type const& other) const noexcept { return *this = *this & other; } - /// Operator |=, emulating number reference behavior + /// Operator |=, emulating bool reference behavior packed_bit_element const& operator|=(value_type const& other) const noexcept { return *this = *this | other; } @@ -256,6 +231,16 @@ class packed_bit_byte { return *this = *this | other; } + /// Operator <<=, emulating number reference behavior + packed_bit_byte const& operator<<=(unsigned other) const noexcept { + return *this = *this << other; + } + + /// Operator >>=, emulating number reference behavior + packed_bit_byte const& operator>>=(unsigned other) const noexcept { + return *this = *this >> other; + } + constexpr packed_bit_byte(packed_bit_byte const& other) : byte(other.byte), mask(other.mask) {} private: diff --git a/src/bsoncxx/test/vector.cpp b/src/bsoncxx/test/vector.cpp index 8fafbbd117..c7a25207e4 100644 --- a/src/bsoncxx/test/vector.cpp +++ b/src/bsoncxx/test/vector.cpp @@ -152,25 +152,18 @@ void iterator_operations( std::sort(begin, end); std::for_each(begin, end, [&](auto const& value) { REQUIRE(value == element_unit); }); - BSONCXX_PRIVATE_WARNINGS_PUSH(); - BSONCXX_PRIVATE_WARNINGS_DISABLE(GCC("-Wconversion")); + *(end - 1) = Element{0}; + std::sort(begin, end); + REQUIRE(*begin == Element{0}); + std::for_each(begin + 1, end, [&](auto const& value) { REQUIRE(value == element_unit); }); - std::for_each(begin, end, [&](auto&& value) { value -= element_unit; }); - std::for_each(begin, end, [&](auto&& value) { value *= element_unit; }); - std::for_each(begin, end, [&](auto&& value) { value /= element_unit; }); + std::for_each(begin, end, [&](auto&& value) { value = Element{0}; }); std::for_each(begin, end, [&](auto const& value) { REQUIRE(value != element_unit); }); std::for_each(begin, end, [&](auto const& value) { REQUIRE(value < element_unit); }); std::for_each(begin, end, [&](auto const& value) { REQUIRE(value <= element_unit); }); std::for_each(begin, end, [&](auto const& value) { REQUIRE_FALSE(value == element_unit); }); std::for_each(begin, end, [&](auto const& value) { REQUIRE_FALSE(value > element_unit); }); std::for_each(begin, end, [&](auto const& value) { REQUIRE_FALSE(value >= element_unit); }); - - std::for_each(begin, end, [&](auto&& value) { value += element_unit; }); - std::for_each(begin, end, [&](auto&& value) { value *= element_unit; }); - std::for_each(begin, end, [&](auto&& value) { value /= element_unit; }); - std::for_each(begin, end, [&](auto const& value) { REQUIRE(value == element_unit); }); - - BSONCXX_PRIVATE_WARNINGS_POP(); } TEMPLATE_TEST_CASE("all vector view formats", "[bsoncxx::vector::view]", ALL_VECTOR_FORMATS) { From 8bddeb6a6ff685d129ac30643404a65e149e3406 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Thu, 20 Mar 2025 16:07:28 -0700 Subject: [PATCH 19/83] lambda missing capture mode --- src/bsoncxx/test/bson_builder.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bsoncxx/test/bson_builder.cpp b/src/bsoncxx/test/bson_builder.cpp index 84de2c45ff..1cac657feb 100644 --- a/src/bsoncxx/test/bson_builder.cpp +++ b/src/bsoncxx/test/bson_builder.cpp @@ -920,7 +920,7 @@ TEST_CASE("basic document builder works", "[bsoncxx::builder::basic]") { using namespace builder::basic; uint32_t const size = 32 * 1024 * 1024; basic.append( - kvp("foo", [](sub_binary sb) { memset(sb.allocate(binary_sub_type::k_binary, size), 0x55, size); })); + kvp("foo", [&](sub_binary sb) { memset(sb.allocate(binary_sub_type::k_binary, size), 0x55, size); })); REQUIRE(basic.view().length() > size); } SECTION("sub_binary builder can allocate with length zero") { From 479a5accf1f179111b3170e8b44b3cbeafc994e5 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Thu, 20 Mar 2025 16:44:51 -0700 Subject: [PATCH 20/83] Add missing include --- src/bsoncxx/test/vector.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bsoncxx/test/vector.cpp b/src/bsoncxx/test/vector.cpp index c7a25207e4..6b76f0426e 100644 --- a/src/bsoncxx/test/vector.cpp +++ b/src/bsoncxx/test/vector.cpp @@ -14,6 +14,7 @@ #include +#include #include #include From 37ddd51b107370a52f56626b8434dec0e6755da0 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Thu, 20 Mar 2025 21:32:43 -0700 Subject: [PATCH 21/83] cstdint consistency fixes --- .../bsoncxx/v_noabi/bsoncxx/vector/impl.hpp | 20 ++++++++++--------- .../v_noabi/bsoncxx/vector/iterators.hpp | 5 +++-- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/impl.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/impl.hpp index 163652c5e5..bba96c04de 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/impl.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/impl.hpp @@ -14,6 +14,8 @@ #pragma once +#include + #include #include #include @@ -72,12 +74,12 @@ struct format_traits : format_traits_base { using iterator = std::int8_t*; using const_iterator = std::int8_t const*; - static BSONCXX_ABI_EXPORT_CDECL(uint32_t) length_for_append(std::size_t element_count); + static BSONCXX_ABI_EXPORT_CDECL(std::uint32_t) length_for_append(std::size_t element_count); static BSONCXX_ABI_EXPORT_CDECL(header) - write_frame(uint8_t* binary_data, uint32_t binary_data_length, std::size_t element_count); + write_frame(std::uint8_t* binary_data, std::uint32_t binary_data_length, std::size_t element_count); static BSONCXX_ABI_EXPORT_CDECL(view_data) const_validate(types::b_binary const& binary); - static constexpr std::size_t element_count(uint32_t binary_data_length, header) noexcept { + static constexpr std::size_t element_count(std::uint32_t binary_data_length, header) noexcept { return binary_data_length - sizeof(header::bytes); } @@ -100,12 +102,12 @@ struct format_traits : format_traits_base { using iterator = elements::float32*; using const_iterator = elements::float32 const*; - static BSONCXX_ABI_EXPORT_CDECL(uint32_t) length_for_append(std::size_t element_count); + static BSONCXX_ABI_EXPORT_CDECL(std::uint32_t) length_for_append(std::size_t element_count); static BSONCXX_ABI_EXPORT_CDECL(header) - write_frame(uint8_t* binary_data, uint32_t binary_data_length, std::size_t element_count); + write_frame(std::uint8_t* binary_data, std::uint32_t binary_data_length, std::size_t element_count); static BSONCXX_ABI_EXPORT_CDECL(view_data) const_validate(types::b_binary const& binary); - static constexpr std::size_t element_count(uint32_t binary_data_length, header) noexcept { + static constexpr std::size_t element_count(std::uint32_t binary_data_length, header) noexcept { return (binary_data_length - sizeof(header::bytes)) / sizeof(float); } @@ -136,13 +138,13 @@ struct format_traits : format_traits_base { using byte_difference_type = byte_iterator::difference_type; using element_difference_type = iterator::difference_type; - static BSONCXX_ABI_EXPORT_CDECL(uint32_t) length_for_append(std::size_t element_count); + static BSONCXX_ABI_EXPORT_CDECL(std::uint32_t) length_for_append(std::size_t element_count); static BSONCXX_ABI_EXPORT_CDECL(header) - write_frame(uint8_t* binary_data, uint32_t binary_data_length, std::size_t element_count); + write_frame(std::uint8_t* binary_data, std::uint32_t binary_data_length, std::size_t element_count); static BSONCXX_ABI_EXPORT_CDECL(view_data) const_validate( types::b_binary const& binary); - static constexpr std::size_t element_count(uint32_t binary_data_length, header hdr) noexcept { + static constexpr std::size_t element_count(std::uint32_t binary_data_length, header hdr) noexcept { return std::size_t(binary_data_length - sizeof(hdr.bytes)) * std::size_t(8u) - std::size_t(hdr.bytes[1] & 7u); } diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/iterators.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/iterators.hpp index 57f3424c57..55d212ca36 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/iterators.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/iterators.hpp @@ -15,6 +15,7 @@ #pragma once #include +#include #include #include @@ -158,11 +159,11 @@ class packed_bit_element { friend class view; friend class view; - constexpr packed_bit_element(Iterator byte_iter, uint8_t bit_index = 0) noexcept + constexpr packed_bit_element(Iterator byte_iter, std::uint8_t bit_index = 0) noexcept : byte(byte_iter), bit(bit_index) {} Iterator byte; - uint8_t bit; + std::uint8_t bit; }; /// @brief Iterator for bytes within a packed_bit vector From d2b21301cacb6ce43a7ba61477d11e4f116fb50b Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Thu, 20 Mar 2025 21:49:13 -0700 Subject: [PATCH 22/83] More header and name qualification fixes --- .../bsoncxx/v_noabi/bsoncxx/builder/basic/sub_binary.hpp | 8 +++++--- .../include/bsoncxx/v_noabi/bsoncxx/vector/iterators.hpp | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/sub_binary.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/sub_binary.hpp index b3c4ff141a..d8ff10e46a 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/sub_binary.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/sub_binary.hpp @@ -14,6 +14,8 @@ #pragma once +#include + #include #include @@ -46,7 +48,7 @@ class sub_binary { /// The caller must overwrite every byte if the resulting BSON document is to be used. /// @throws bsoncxx::v_noabi::exception if this sub_binary has already allocated. /// bsoncxx::v_noabi::exception if the binary fails to append due to the BSON size limit. - uint8_t* allocate(binary_sub_type sub_type, uint32_t length) { + std::uint8_t* allocate(binary_sub_type sub_type, std::uint32_t length) { return _core->append(sub_type, length); } @@ -61,8 +63,8 @@ class sub_binary { template ::value_type> vector::view allocate(Format, std::size_t element_count) { using format_traits = typename vector::impl::format_traits; - uint32_t binary_data_length = format_traits::length_for_append(element_count); - uint8_t* binary_data = allocate(binary_sub_type::k_vector, binary_data_length); + std::uint32_t binary_data_length = format_traits::length_for_append(element_count); + std::uint8_t* binary_data = allocate(binary_sub_type::k_vector, binary_data_length); return { {binary_data, binary_data_length, diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/iterators.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/iterators.hpp index 55d212ca36..965f0c800e 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/iterators.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/iterators.hpp @@ -14,8 +14,8 @@ #pragma once -#include #include +#include #include #include From 983da6b490f8eedabfb589edb6326cca27fa8fa4 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Fri, 21 Mar 2025 11:46:03 -0700 Subject: [PATCH 23/83] Revert "avoid int32 overflow prior to bson_append_utf8 invocation" This reverts commit 16b8e1f252da2b9ba58f16c8af83f7e6b6a2a1f8. --- .../lib/bsoncxx/v_noabi/bsoncxx/builder/core.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/builder/core.cpp b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/builder/core.cpp index c00231dfcc..16b7e4bd8f 100644 --- a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/builder/core.cpp +++ b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/builder/core.cpp @@ -298,14 +298,13 @@ core& core::append(types::b_double const& value) { core& core::append(types::b_string const& value) { stdx::string_view key = _impl->next_key(); - std::size_t value_length = value.value.length(); - - if (value_length > std::size_t{INT32_MAX} || !bson_append_utf8( - _impl->back(), - key.data(), - static_cast(key.length()), - value.value.data(), - static_cast(value_length))) { + + if (!bson_append_utf8( + _impl->back(), + key.data(), + static_cast(key.length()), + value.value.data(), + static_cast(value.value.length()))) { throw bsoncxx::v_noabi::exception{error_code::k_cannot_append_string}; } From d1f59dd89f7dbe9c8e3e4ee7a25f20f6536f71b3 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Fri, 21 Mar 2025 11:46:21 -0700 Subject: [PATCH 24/83] Revert "remove obsolete workaround for CDRIVER-5732" This reverts commit 2b5c35a21340d55afc74bf3acd2add543684082b. --- examples/api/bsoncxx/examples/bson_errors/big_string.hh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/api/bsoncxx/examples/bson_errors/big_string.hh b/examples/api/bsoncxx/examples/bson_errors/big_string.hh index 35d0eecd66..d8d14af18e 100644 --- a/examples/api/bsoncxx/examples/bson_errors/big_string.hh +++ b/examples/api/bsoncxx/examples/bson_errors/big_string.hh @@ -27,7 +27,8 @@ namespace examples { // Used to trigger builder append failure. struct big_string { // BSON_SIZE_MAX == 0x7FFFFFFF - std::size_t length{static_cast(std::numeric_limits::max())}; + // Leave some room for CDRIVER-5732. + std::size_t length{static_cast(std::numeric_limits::max() - 32u)}; // Allocate an UNINITIALIZED blob of data that will not be accessed due to length checks. // Leaving memory unitialized (rather than zero-init) should hopefully avoid slow and expensive From 03af662eaa39532f8cb68bc9f7774368aafe845f Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Fri, 21 Mar 2025 11:53:06 -0700 Subject: [PATCH 25/83] clang-format --- src/bsoncxx/include/bsoncxx/docs/top.hpp | 2 +- src/bsoncxx/include/bsoncxx/docs/v_noabi.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bsoncxx/include/bsoncxx/docs/top.hpp b/src/bsoncxx/include/bsoncxx/docs/top.hpp index 3bd37a02ce..b1a068d249 100644 --- a/src/bsoncxx/include/bsoncxx/docs/top.hpp +++ b/src/bsoncxx/include/bsoncxx/docs/top.hpp @@ -97,4 +97,4 @@ /// /// @namespace bsoncxx::vector::formats /// Each type here is a supported format for bsoncxx::vector -/// \ No newline at end of file +/// diff --git a/src/bsoncxx/include/bsoncxx/docs/v_noabi.hpp b/src/bsoncxx/include/bsoncxx/docs/v_noabi.hpp index a118abe953..0aeba43d9a 100644 --- a/src/bsoncxx/include/bsoncxx/docs/v_noabi.hpp +++ b/src/bsoncxx/include/bsoncxx/docs/v_noabi.hpp @@ -167,4 +167,4 @@ /// /// @namespace bsoncxx::v_noabi::vector::formats /// Each type here is a supported format for bsoncxx::vector -/// \ No newline at end of file +/// From 0c26bc82595975cda68943525612b3c3a4ba270f Mon Sep 17 00:00:00 2001 From: mdbmes Date: Fri, 21 Mar 2025 20:29:06 -0700 Subject: [PATCH 26/83] Update src/bsoncxx/include/bsoncxx/docs/v_noabi.hpp Co-authored-by: Ezra Chung <88335979+eramongodb@users.noreply.github.com> --- src/bsoncxx/include/bsoncxx/docs/v_noabi.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bsoncxx/include/bsoncxx/docs/v_noabi.hpp b/src/bsoncxx/include/bsoncxx/docs/v_noabi.hpp index 0aeba43d9a..67496220e7 100644 --- a/src/bsoncxx/include/bsoncxx/docs/v_noabi.hpp +++ b/src/bsoncxx/include/bsoncxx/docs/v_noabi.hpp @@ -151,7 +151,7 @@ /// /// @namespace bsoncxx::v_noabi::vector -/// Declarations related to BSON Binary Vector (@ref bsoncxx::v_noabi::binary_sub_type::k_vector) items. +/// @copydoc bsoncxx::vector /// /// From 6bb33764a4a2a22582745306fba9a609e0a0f5ac Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Fri, 21 Mar 2025 20:21:07 -0700 Subject: [PATCH 27/83] Revert change to required libbson/libmongoc versions --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cdb42939ca..d4880da905 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,11 +49,11 @@ else() endif() # Also update etc/purls.txt. -set(LIBBSON_REQUIRED_VERSION 1.31.0) +set(LIBBSON_REQUIRED_VERSION 1.30.0) set(LIBBSON_REQUIRED_ABI_VERSION 1.0) # Also update etc/purls.txt. -set(LIBMONGOC_REQUIRED_VERSION 1.31.0) +set(LIBMONGOC_REQUIRED_VERSION 1.30.0) set(LIBMONGOC_DOWNLOAD_VERSION 0b3bb26c586c8a341710b853183abe5946693931) set(LIBMONGOC_REQUIRED_ABI_VERSION 1.0) From 411a643f9023ee4236306967fbc50718c732f53c Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Fri, 21 Mar 2025 20:23:59 -0700 Subject: [PATCH 28/83] Remove ALL_VECTOR_FORMATS --- src/bsoncxx/test/vector.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/bsoncxx/test/vector.cpp b/src/bsoncxx/test/vector.cpp index 6b76f0426e..ecd824e271 100644 --- a/src/bsoncxx/test/vector.cpp +++ b/src/bsoncxx/test/vector.cpp @@ -29,8 +29,6 @@ #include #include -#define ALL_VECTOR_FORMATS vector::formats::f_float32, vector::formats::f_int8, vector::formats::f_packed_bit - namespace { using namespace bsoncxx; @@ -167,7 +165,12 @@ void iterator_operations( std::for_each(begin, end, [&](auto const& value) { REQUIRE_FALSE(value >= element_unit); }); } -TEMPLATE_TEST_CASE("all vector view formats", "[bsoncxx::vector::view]", ALL_VECTOR_FORMATS) { +TEMPLATE_TEST_CASE( + "all vector view formats", + "[bsoncxx::vector::view]", + vector::formats::f_float32, + vector::formats::f_int8, + vector::formats::f_packed_bit) { using test_format_specific = format_specific; using value_type = typename test_format_specific::value_type; From 1a3bf3ce943bb391fbf780f7079a00d4d201a598 Mon Sep 17 00:00:00 2001 From: mdbmes Date: Mon, 24 Mar 2025 07:47:55 -0700 Subject: [PATCH 29/83] Update src/bsoncxx/include/bsoncxx/docs/v_noabi.hpp Co-authored-by: Ezra Chung <88335979+eramongodb@users.noreply.github.com> --- src/bsoncxx/include/bsoncxx/docs/v_noabi.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bsoncxx/include/bsoncxx/docs/v_noabi.hpp b/src/bsoncxx/include/bsoncxx/docs/v_noabi.hpp index 67496220e7..a21f7203f6 100644 --- a/src/bsoncxx/include/bsoncxx/docs/v_noabi.hpp +++ b/src/bsoncxx/include/bsoncxx/docs/v_noabi.hpp @@ -166,5 +166,5 @@ /// /// @namespace bsoncxx::v_noabi::vector::formats -/// Each type here is a supported format for bsoncxx::vector +/// @copydoc bsoncxx::vector::formats /// From d45eca7eaeeb38ced5aba938a201cef27cf6e3dd Mon Sep 17 00:00:00 2001 From: mdbmes Date: Mon, 24 Mar 2025 07:48:26 -0700 Subject: [PATCH 30/83] Update src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/formats.hpp Co-authored-by: Ezra Chung <88335979+eramongodb@users.noreply.github.com> --- .../include/bsoncxx/v_noabi/bsoncxx/vector/formats.hpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/formats.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/formats.hpp index 99e8a8855c..073d867bc5 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/formats.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/formats.hpp @@ -41,8 +41,5 @@ struct f_packed_bit {}; /// /// @file -/// Declares vector formats: -/// @ref bsoncxx::v_noabi::vector::formats::f_float32 -/// @ref bsoncxx::v_noabi::vector::formats::f_int8 -/// @ref bsoncxx::v_noabi::vector::formats::f_packed_bit +/// Declares entities in @ref bsoncxx::v_noabi::vector::formats. /// From 9be7d04987ae6989791527069e6a66abf6f0468b Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Mon, 24 Mar 2025 08:13:39 -0700 Subject: [PATCH 31/83] Replace most REQUIREs with CHECKs --- src/bsoncxx/test/vector.cpp | 259 ++++++++++++++++++------------------ 1 file changed, 129 insertions(+), 130 deletions(-) diff --git a/src/bsoncxx/test/vector.cpp b/src/bsoncxx/test/vector.cpp index ecd824e271..3140355388 100644 --- a/src/bsoncxx/test/vector.cpp +++ b/src/bsoncxx/test/vector.cpp @@ -81,7 +81,7 @@ struct format_specific { template void binary_eq_bytes(types::b_binary const& binary, Sequence const& bytes) { REQUIRE(binary.size == bytes.size()); - REQUIRE(std::memcmp(binary.bytes, bytes.data(), bytes.size()) == 0); + CHECK(std::memcmp(binary.bytes, bytes.data(), bytes.size()) == 0); } template @@ -90,79 +90,79 @@ void iterator_operations( Iterator const& end, std::ptrdiff_t expected_size, Element element_unit) { - REQUIRE(end - begin == expected_size); + CHECK(end - begin == expected_size); for (std::ptrdiff_t outer_index = 0; outer_index < 50; outer_index++) { Iterator outer_front = begin + outer_index; Iterator outer_back = end - outer_index; - REQUIRE(outer_front - begin == outer_index); - REQUIRE(begin - outer_front == -outer_index); + CHECK(outer_front - begin == outer_index); + CHECK(begin - outer_front == -outer_index); - REQUIRE(end - outer_back == outer_index); - REQUIRE(outer_back - end == -outer_index); + CHECK(end - outer_back == outer_index); + CHECK(outer_back - end == -outer_index); for (std::ptrdiff_t inner_index = 0; inner_index < 20; inner_index++) { Iterator inner_front = outer_front + inner_index; Iterator inner_back = outer_back - inner_index; - REQUIRE(inner_front - outer_front == inner_index); - REQUIRE(outer_front - inner_front == -inner_index); + CHECK(inner_front - outer_front == inner_index); + CHECK(outer_front - inner_front == -inner_index); - REQUIRE(outer_back - inner_back == inner_index); - REQUIRE(inner_back - outer_back == -inner_index); + CHECK(outer_back - inner_back == inner_index); + CHECK(inner_back - outer_back == -inner_index); } } Iterator iter_copy = begin; - REQUIRE(iter_copy == begin); - REQUIRE(iter_copy >= begin); - REQUIRE(iter_copy <= begin); - REQUIRE_FALSE(iter_copy != begin); - REQUIRE_FALSE(iter_copy < begin); - - REQUIRE(++iter_copy - begin == 1); - REQUIRE(iter_copy > begin); - REQUIRE(iter_copy >= begin); - REQUIRE(iter_copy != begin); - REQUIRE_FALSE(iter_copy == begin); - REQUIRE_FALSE(iter_copy <= begin); - REQUIRE_FALSE(iter_copy < begin); - - REQUIRE(--iter_copy - begin == 0); - REQUIRE(iter_copy == begin); - - REQUIRE(iter_copy++ - begin == 0); - REQUIRE(iter_copy-- - begin == 1); - REQUIRE(iter_copy == begin); + CHECK(iter_copy == begin); + CHECK(iter_copy >= begin); + CHECK(iter_copy <= begin); + CHECK_FALSE(iter_copy != begin); + CHECK_FALSE(iter_copy < begin); + + CHECK(++iter_copy - begin == 1); + CHECK(iter_copy > begin); + CHECK(iter_copy >= begin); + CHECK(iter_copy != begin); + CHECK_FALSE(iter_copy == begin); + CHECK_FALSE(iter_copy <= begin); + CHECK_FALSE(iter_copy < begin); + + CHECK(--iter_copy - begin == 0); + CHECK(iter_copy == begin); + + CHECK(iter_copy++ - begin == 0); + CHECK(iter_copy-- - begin == 1); + CHECK(iter_copy == begin); std::generate(begin, end, [&] { return element_unit; }); - std::for_each(begin, end, [&](auto const& value) { REQUIRE(value == element_unit); }); + std::for_each(begin, end, [&](auto const& value) { CHECK(value == element_unit); }); std::copy(begin, begin + (expected_size / 2), begin + (expected_size / 2)); - std::for_each(begin, end, [&](auto const& value) { REQUIRE(value == element_unit); }); + std::for_each(begin, end, [&](auto const& value) { CHECK(value == element_unit); }); std::for_each(begin, end, [&](auto&& value) { value = element_unit; }); - std::for_each(begin, end, [&](auto const& value) { REQUIRE(value == element_unit); }); + std::for_each(begin, end, [&](auto const& value) { CHECK(value == element_unit); }); std::fill(begin, end, element_unit); - std::for_each(begin, end, [&](auto const& value) { REQUIRE(value == element_unit); }); + std::for_each(begin, end, [&](auto const& value) { CHECK(value == element_unit); }); std::sort(begin, end); - std::for_each(begin, end, [&](auto const& value) { REQUIRE(value == element_unit); }); + std::for_each(begin, end, [&](auto const& value) { CHECK(value == element_unit); }); *(end - 1) = Element{0}; std::sort(begin, end); - REQUIRE(*begin == Element{0}); - std::for_each(begin + 1, end, [&](auto const& value) { REQUIRE(value == element_unit); }); + CHECK(*begin == Element{0}); + std::for_each(begin + 1, end, [&](auto const& value) { CHECK(value == element_unit); }); std::for_each(begin, end, [&](auto&& value) { value = Element{0}; }); - std::for_each(begin, end, [&](auto const& value) { REQUIRE(value != element_unit); }); - std::for_each(begin, end, [&](auto const& value) { REQUIRE(value < element_unit); }); - std::for_each(begin, end, [&](auto const& value) { REQUIRE(value <= element_unit); }); - std::for_each(begin, end, [&](auto const& value) { REQUIRE_FALSE(value == element_unit); }); - std::for_each(begin, end, [&](auto const& value) { REQUIRE_FALSE(value > element_unit); }); - std::for_each(begin, end, [&](auto const& value) { REQUIRE_FALSE(value >= element_unit); }); + std::for_each(begin, end, [&](auto const& value) { CHECK(value != element_unit); }); + std::for_each(begin, end, [&](auto const& value) { CHECK(value < element_unit); }); + std::for_each(begin, end, [&](auto const& value) { CHECK(value <= element_unit); }); + std::for_each(begin, end, [&](auto const& value) { CHECK_FALSE(value == element_unit); }); + std::for_each(begin, end, [&](auto const& value) { CHECK_FALSE(value > element_unit); }); + std::for_each(begin, end, [&](auto const& value) { CHECK_FALSE(value >= element_unit); }); } TEMPLATE_TEST_CASE( @@ -178,9 +178,9 @@ TEMPLATE_TEST_CASE( auto bytes = test_format_specific::bytes_empty(); types::b_binary const binary{binary_sub_type::k_vector, bytes.size(), bytes.data()}; vector::view view{binary}; - REQUIRE(view.empty()); - REQUIRE(view.size() == 0); - REQUIRE(view.byte_size() == 0); + CHECK(view.empty()); + CHECK(view.size() == 0); + CHECK(view.byte_size() == 0); CHECK_THROWS_AS(view.at(0), std::out_of_range); CHECK_THROWS_AS(view.byte_at(0), std::out_of_range); } @@ -190,13 +190,13 @@ TEMPLATE_TEST_CASE( auto element = test_format_specific::element_unit(); types::b_binary const binary{binary_sub_type::k_vector, bytes.size(), bytes.data()}; vector::view view{binary}; - REQUIRE_FALSE(view.empty()); - REQUIRE(view.size() == 1u); - REQUIRE(view.byte_size() == bytes.size() - 2u); - REQUIRE(view.at(0) == element); - REQUIRE(view[0] == element); - REQUIRE(view.byte_at(0) == bytes[2]); - REQUIRE(view.byte_at(bytes.size() - 3u) == bytes[bytes.size() - 1u]); + CHECK_FALSE(view.empty()); + CHECK(view.size() == 1u); + CHECK(view.byte_size() == bytes.size() - 2u); + CHECK(view.at(0) == element); + CHECK(view[0] == element); + CHECK(view.byte_at(0) == bytes[2]); + CHECK(view.byte_at(bytes.size() - 3u) == bytes[bytes.size() - 1u]); CHECK_THROWS_AS(view.at(1), std::out_of_range); CHECK_THROWS_AS(view.byte_at(bytes.size() - 2u), std::out_of_range); } @@ -206,7 +206,7 @@ TEMPLATE_TEST_CASE( auto invalid_type = GENERATE( binary_sub_type::k_binary, binary_sub_type::k_encrypted, binary_sub_type::k_uuid, binary_sub_type::k_user); types::b_binary const binary{invalid_type, bytes.size(), bytes.data()}; - REQUIRE_THROWS_WITH( + CHECK_THROWS_WITH( vector::view(binary), Catch::Matchers::ContainsSubstring("invalid BSON vector")); } @@ -215,7 +215,7 @@ TEMPLATE_TEST_CASE( auto bytes_to_remove = GENERATE(1u, 2u); REQUIRE(bytes.size() >= bytes_to_remove); types::b_binary const binary{binary_sub_type::k_vector, uint32_t(bytes.size() - bytes_to_remove), bytes.data()}; - REQUIRE_THROWS_WITH( + CHECK_THROWS_WITH( vector::view(binary), Catch::Matchers::ContainsSubstring("invalid BSON vector")); } @@ -224,7 +224,7 @@ TEMPLATE_TEST_CASE( auto bytes = test_format_specific::bytes_empty(); bytes[bit_index >> 3u] ^= std::uint8_t(1u << (bit_index & 7u)); types::b_binary const binary{binary_sub_type::k_vector, bytes.size(), bytes.data()}; - REQUIRE_THROWS_WITH( + CHECK_THROWS_WITH( vector::view(binary), Catch::Matchers::ContainsSubstring("invalid BSON vector")); } } @@ -236,7 +236,7 @@ TEMPLATE_TEST_CASE( bsoncxx::document::value doc = make_document(kvp("vector", [&](sub_binary sbin) { sbin.allocate(TestType{}, 1u)[0u] = element; })); types::b_binary const& binary = doc.view()["vector"].get_binary(); - REQUIRE(binary.sub_type == binary_sub_type::k_vector); + CHECK(binary.sub_type == binary_sub_type::k_vector); binary_eq_bytes(binary, expected_bytes); vector::view validate_encoded{binary}; } @@ -251,7 +251,7 @@ TEMPLATE_TEST_CASE( })); types::b_binary const& binary = doc.view()["vector"].get_binary(); vector::view validate_encoded{binary}; - REQUIRE(binary.size > 1000u); + CHECK(binary.size > 1000u); } SECTION("support algorithms and operators on byte iterators") { @@ -263,7 +263,7 @@ TEMPLATE_TEST_CASE( })); types::b_binary const& binary = doc.view()["vector"].get_binary(); vector::view validate_encoded{binary}; - REQUIRE(binary.size > 1000u); + CHECK(binary.size > 1000u); } SECTION("support assignment between referenced elements") { @@ -272,11 +272,11 @@ TEMPLATE_TEST_CASE( auto view = sbin.allocate(TestType{}, 2u); view[0] = test_format_specific::element_unit(); view[1] = value_type{0}; - REQUIRE(view.at(0) != view.at(1)); - REQUIRE_FALSE(view.at(0) == view.at(1)); + CHECK(view.at(0) != view.at(1)); + CHECK_FALSE(view.at(0) == view.at(1)); view[1] = view[0]; - REQUIRE(view.at(0) == view.at(1)); - REQUIRE_FALSE(view.at(0) != view.at(1)); + CHECK(view.at(0) == view.at(1)); + CHECK_FALSE(view.at(0) != view.at(1)); })); types::b_binary const& binary = doc.view()["vector"].get_binary(); vector::view validate_encoded{binary}; @@ -288,11 +288,11 @@ TEMPLATE_TEST_CASE( auto view = sbin.allocate(TestType{}, 16u); std::fill(view.begin(), view.end(), test_format_specific::element_unit()); *(view.end() - 2) = value_type{0}; - REQUIRE(view.byte_at(view.byte_size() - 2) != view.byte_at(view.byte_size() - 1)); - REQUIRE_FALSE(view.byte_at(view.byte_size() - 2) == view.byte_at(view.byte_size() - 1)); + CHECK(view.byte_at(view.byte_size() - 2) != view.byte_at(view.byte_size() - 1)); + CHECK_FALSE(view.byte_at(view.byte_size() - 2) == view.byte_at(view.byte_size() - 1)); view.byte_at(view.byte_size() - 2) = view.byte_at(view.byte_size() - 1); - REQUIRE(view.byte_at(view.byte_size() - 2) == view.byte_at(view.byte_size() - 1)); - REQUIRE_FALSE(view.byte_at(view.byte_size() - 2) != view.byte_at(view.byte_size() - 1)); + CHECK(view.byte_at(view.byte_size() - 2) == view.byte_at(view.byte_size() - 1)); + CHECK_FALSE(view.byte_at(view.byte_size() - 2) != view.byte_at(view.byte_size() - 1)); })); types::b_binary const& binary = doc.view()["vector"].get_binary(); vector::view validate_encoded{binary}; @@ -302,7 +302,7 @@ TEMPLATE_TEST_CASE( using namespace builder::basic; // This checks that we can detect overlarge sizes and throw an exception. // Detailed checks for the size limit are delegated to Libbson (via libbson_length_for_append) - REQUIRE_THROWS_WITH( + CHECK_THROWS_WITH( make_document(kvp("vector", [&](sub_binary sbin) { sbin.allocate(TestType{}, SIZE_MAX); })), Catch::Matchers::ContainsSubstring("BSON vector too large")); } @@ -313,20 +313,20 @@ TEMPLATE_TEST_CASE( auto view = sbin.allocate(TestType{}, 2u); std::fill(view.begin(), view.end(), test_format_specific::element_unit()); *(view.end() - 1) = value_type{0}; - REQUIRE(view.back() == value_type{0}); - REQUIRE(view.back() == view[view.size() - 1u]); - REQUIRE(view.front() != view.back()); - REQUIRE_FALSE(view.front() == view.back()); + CHECK(view.back() == value_type{0}); + CHECK(view.back() == view[view.size() - 1u]); + CHECK(view.front() != view.back()); + CHECK_FALSE(view.front() == view.back()); view.front() = view.back(); - REQUIRE(view[0] == value_type{0}); - REQUIRE(view.front() == view.back()); - REQUIRE_FALSE(view.front() != view.back()); - REQUIRE(view[view.size() - 1u] == value_type{0}); + CHECK(view[0] == value_type{0}); + CHECK(view.front() == view.back()); + CHECK_FALSE(view.front() != view.back()); + CHECK(view[view.size() - 1u] == value_type{0}); view.back() = test_format_specific::element_unit(); - REQUIRE(view[0] == value_type{0}); - REQUIRE(view[view.size() - 1u] != value_type{0}); - REQUIRE(view.front() != view.back()); - REQUIRE_FALSE(view.front() == view.back()); + CHECK(view[0] == value_type{0}); + CHECK(view[view.size() - 1u] != value_type{0}); + CHECK(view.front() != view.back()); + CHECK_FALSE(view.front() == view.back()); })); types::b_binary const& binary = doc.view()["vector"].get_binary(); vector::view validate_encoded{binary}; @@ -337,17 +337,17 @@ TEMPLATE_TEST_CASE( bsoncxx::document::value doc = make_document(kvp("vector", [&](sub_binary sbin) { auto view = sbin.allocate(TestType{}, 16u); std::fill(view.begin(), view.end(), value_type{0}); - REQUIRE(view.front() == view.back()); - REQUIRE_FALSE(view.front() != view.back()); - REQUIRE(view.byte_front() == view.byte_back()); - REQUIRE_FALSE(view.byte_front() != view.byte_back()); + CHECK(view.front() == view.back()); + CHECK_FALSE(view.front() != view.back()); + CHECK(view.byte_front() == view.byte_back()); + CHECK_FALSE(view.byte_front() != view.byte_back()); view.back() = test_format_specific::element_unit(); - REQUIRE(view.byte_front() != view.byte_back()); - REQUIRE_FALSE(view.byte_front() == view.byte_back()); + CHECK(view.byte_front() != view.byte_back()); + CHECK_FALSE(view.byte_front() == view.byte_back()); view.byte_front() = UINT8_C(0); view.byte_back() = UINT8_C(0); - REQUIRE(view.byte_front() == view.byte_back()); - REQUIRE_FALSE(view.byte_front() != view.byte_back()); + CHECK(view.byte_front() == view.byte_back()); + CHECK_FALSE(view.byte_front() != view.byte_back()); })); types::b_binary const& binary = doc.view()["vector"].get_binary(); vector::view validate_encoded{binary}; @@ -359,7 +359,7 @@ TEST_CASE("vector view float32", "[bsoncxx::vector::view]") { static uint8_t const bytes[] = {0x27, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00}; auto invalid_length = GENERATE(0u, 1u, 3u, 4u, 5u, 7u, 8u, 9u); types::b_binary const binary{binary_sub_type::k_vector, uint32_t(invalid_length), bytes}; - REQUIRE_THROWS_WITH( + CHECK_THROWS_WITH( vector::view(binary), Catch::Matchers::ContainsSubstring("invalid BSON vector")); } @@ -369,7 +369,7 @@ TEST_CASE("vector view float32", "[bsoncxx::vector::view]") { format_specific::bytes_empty(), format_specific::bytes_empty()); types::b_binary const binary{binary_sub_type::k_vector, bytes.size(), bytes.data()}; - REQUIRE_THROWS_WITH( + CHECK_THROWS_WITH( vector::view(binary), Catch::Matchers::ContainsSubstring("invalid BSON vector")); } @@ -380,11 +380,11 @@ TEST_CASE("vector view float32", "[bsoncxx::vector::view]") { types::b_binary const binary{binary_sub_type::k_vector, sizeof bytes, bytes}; vector::view view{binary}; REQUIRE(view.size() == 3u); - REQUIRE(view[0] < 0.f); - REQUIRE(view[0] * 0.f != 0.f); - REQUIRE(view[1] == 0.f); - REQUIRE(view[2] > 0.f); - REQUIRE(view[2] * 0.f != 0.f); + CHECK(view[0] < 0.f); + CHECK(view[0] * 0.f != 0.f); + CHECK(view[1] == 0.f); + CHECK(view[2] > 0.f); + CHECK(view[2] * 0.f != 0.f); } } @@ -394,7 +394,7 @@ TEST_CASE("vector view int8_t", "[bsoncxx::vector::view]") { format_specific::bytes_empty(), format_specific::bytes_empty()); types::b_binary const binary{binary_sub_type::k_vector, bytes.size(), bytes.data()}; - REQUIRE_THROWS_WITH( + CHECK_THROWS_WITH( vector::view(binary), Catch::Matchers::ContainsSubstring("invalid BSON vector")); } @@ -406,7 +406,7 @@ TEST_CASE("vector view packed_bit", "[bsoncxx::vector::view]") { auto bytes = format_specific::bytes_empty(); bytes[1] = uint8_t(byte_value); types::b_binary const binary{binary_sub_type::k_vector, bytes.size(), bytes.data()}; - REQUIRE_THROWS_WITH( + CHECK_THROWS_WITH( vector::view(binary), Catch::Matchers::ContainsSubstring("invalid BSON vector")); } @@ -416,7 +416,7 @@ TEST_CASE("vector view packed_bit", "[bsoncxx::vector::view]") { for (unsigned byte_value = 8u; byte_value <= UINT8_MAX; byte_value++) { uint8_t const bytes[] = {0x10, uint8_t(byte_value), 0x00}; types::b_binary const binary{binary_sub_type::k_vector, sizeof bytes, bytes}; - REQUIRE_THROWS_WITH( + CHECK_THROWS_WITH( vector::view(binary), Catch::Matchers::ContainsSubstring("invalid BSON vector")); } @@ -426,13 +426,13 @@ TEST_CASE("vector view packed_bit", "[bsoncxx::vector::view]") { for (unsigned byte_value = 1u; byte_value <= 7u; byte_value++) { uint8_t bytes[] = {0x10, uint8_t(byte_value), 0xff}; types::b_binary const binary{binary_sub_type::k_vector, sizeof bytes, bytes}; - REQUIRE_THROWS_WITH( + CHECK_THROWS_WITH( vector::view(binary), Catch::Matchers::ContainsSubstring("invalid BSON vector")); // Succeeds when unused bits are then zeroed bytes[2] = 0; vector::view view{binary}; - REQUIRE(view.size() == 8u - byte_value); + CHECK(view.size() == 8u - byte_value); } } @@ -441,29 +441,29 @@ TEST_CASE("vector view packed_bit", "[bsoncxx::vector::view]") { bsoncxx::document::value doc = make_document(kvp("vector", [&](sub_binary sbin) { auto view = sbin.allocate(vector::formats::f_packed_bit{}, 9u); std::fill(view.begin(), view.end(), true); - REQUIRE(view.byte_size() == 2u); - REQUIRE(view.byte_at(0) == 0xff); - REQUIRE(view.byte_at(1) == 0x80); + CHECK(view.byte_size() == 2u); + CHECK(view.byte_at(0) == 0xff); + CHECK(view.byte_at(1) == 0x80); view.byte_at(1) = 0x7f; - REQUIRE(view.at(7) == true); - REQUIRE(view.at(8) == false); - REQUIRE(view.byte_at(1) == 0x00); + CHECK(view.at(7) == true); + CHECK(view.at(8) == false); + CHECK(view.byte_at(1) == 0x00); view.byte_at(1) = 0xff; view.byte_at(0) = 0xaa; - REQUIRE(view.at(0) == true); - REQUIRE(view.at(1) == false); - REQUIRE(view.at(2) == true); - REQUIRE(view.at(3) == false); - REQUIRE(view.at(4) == true); - REQUIRE(view.at(5) == false); - REQUIRE(view.at(6) == true); - REQUIRE(view.at(7) == false); - REQUIRE(view.at(8) == true); - REQUIRE(view.byte_at(0) == 0xaa); - REQUIRE(view.byte_at(1) == 0x80); + CHECK(view.at(0) == true); + CHECK(view.at(1) == false); + CHECK(view.at(2) == true); + CHECK(view.at(3) == false); + CHECK(view.at(4) == true); + CHECK(view.at(5) == false); + CHECK(view.at(6) == true); + CHECK(view.at(7) == false); + CHECK(view.at(8) == true); + CHECK(view.byte_at(0) == 0xaa); + CHECK(view.byte_at(1) == 0x80); })); types::b_binary const& binary = doc.view()["vector"].get_binary(); - REQUIRE(binary.sub_type == binary_sub_type::k_vector); + CHECK(binary.sub_type == binary_sub_type::k_vector); std::array expected_bytes{0x10, 7, 0xaa, 0x80}; binary_eq_bytes(binary, expected_bytes); } @@ -473,7 +473,7 @@ TEST_CASE("vector view packed_bit", "[bsoncxx::vector::view]") { uint8_t const bytes[] = {0x10, uint8_t(byte_value), 0x00}; types::b_binary const binary{binary_sub_type::k_vector, sizeof bytes, bytes}; vector::view view{binary}; - REQUIRE(view.size() == 8 - byte_value); + CHECK(view.size() == 8 - byte_value); } } @@ -482,7 +482,7 @@ TEST_CASE("vector view packed_bit", "[bsoncxx::vector::view]") { format_specific::bytes_empty(), format_specific::bytes_empty()); types::b_binary const binary{binary_sub_type::k_vector, bytes.size(), bytes.data()}; - REQUIRE_THROWS_WITH( + CHECK_THROWS_WITH( vector::view(binary), Catch::Matchers::ContainsSubstring("invalid BSON vector")); } @@ -495,28 +495,27 @@ TEST_CASE("vector view packed_bit", "[bsoncxx::vector::view]") { REQUIRE(view.size() == element_count); REQUIRE(view.byte_size() == (element_count + 7u) / 8); std::fill(view.byte_begin(), view.byte_end(), UINT8_C(0xFF)); - REQUIRE(view.empty() == (element_count == 0)); + CHECK(view.empty() == (element_count == 0)); if (!view.empty()) { std::for_each(view.byte_begin(), view.byte_end() - 1, [&](std::uint8_t value) { - REQUIRE(value == UINT8_C(0xFF)); + CHECK(value == UINT8_C(0xFF)); }); std::size_t padding = view.byte_size() * std::size_t(8) - view.size(); - REQUIRE(view.byte_back() == std::uint8_t(0xFF << padding)); + CHECK(view.byte_back() == std::uint8_t(0xFF << padding)); } })); types::b_binary const& binary = doc.view()["vector"].get_binary(); - REQUIRE(binary.sub_type == binary_sub_type::k_vector); + CHECK(binary.sub_type == binary_sub_type::k_vector); vector::view view{binary}; REQUIRE(view.size() == element_count); REQUIRE(view.byte_size() == (element_count + 7u) / 8); - REQUIRE(view.empty() == (element_count == 0u)); + CHECK(view.empty() == (element_count == 0u)); if (!view.empty()) { - std::for_each(view.byte_begin(), view.byte_end() - 1, [&](std::uint8_t value) { - REQUIRE(value == UINT8_C(0xFF)); - }); + std::for_each( + view.byte_begin(), view.byte_end() - 1, [&](std::uint8_t value) { CHECK(value == UINT8_C(0xFF)); }); std::size_t padding = view.byte_size() * std::size_t(8) - view.size(); - REQUIRE(padding == binary.bytes[1]); - REQUIRE(view.byte_back() == std::uint8_t(0xFF << padding)); + CHECK(padding == binary.bytes[1]); + CHECK(view.byte_back() == std::uint8_t(0xFF << padding)); } } } From e184ea58db7ea9edef9814eaa7580b8379a72d6b Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Mon, 24 Mar 2025 08:20:55 -0700 Subject: [PATCH 32/83] Replace most REQUIRE with CHECK in bson_builder too --- src/bsoncxx/test/bson_builder.cpp | 138 +++++++++++++++--------------- 1 file changed, 69 insertions(+), 69 deletions(-) diff --git a/src/bsoncxx/test/bson_builder.cpp b/src/bsoncxx/test/bson_builder.cpp index 1cac657feb..494503b110 100644 --- a/src/bsoncxx/test/bson_builder.cpp +++ b/src/bsoncxx/test/bson_builder.cpp @@ -45,7 +45,7 @@ void bson_eq_stream(bson_t const* bson, bsoncxx::builder::stream::document const INFO("expected = " << to_json(expected)); INFO("builder = " << to_json(test)); REQUIRE(expected.length() == test.length()); - REQUIRE(std::memcmp(expected.data(), test.data(), expected.length()) == 0); + CHECK(std::memcmp(expected.data(), test.data(), expected.length()) == 0); } template @@ -56,7 +56,7 @@ void viewable_eq_viewable(T const& stream, U const& basic) { INFO("expected = " << to_json(expected)); INFO("basic = " << to_json(test)); REQUIRE(expected.length() == test.length()); - REQUIRE(std::memcmp(expected.data(), test.data(), expected.length()) == 0); + CHECK(std::memcmp(expected.data(), test.data(), expected.length()) == 0); } template @@ -66,7 +66,7 @@ void bson_eq_object(bson_t const* bson, T const actual) { INFO("expected = " << to_json(expected)); INFO("actual = " << to_json(actual)); REQUIRE(expected.length() == actual.length()); - REQUIRE(std::memcmp(expected.data(), actual.data(), expected.length()) == 0); + CHECK(std::memcmp(expected.data(), actual.data(), expected.length()) == 0); } TEST_CASE("builder appends string", "[bsoncxx::builder::stream]") { @@ -418,7 +418,7 @@ TEST_CASE("builder appends decimal128", "[bsoncxx::builder::stream]") { auto d = types::b_decimal128{"-1234E+999"}; auto v = types::bson_value::view{d}; - REQUIRE(v.get_decimal128() == d); + CHECK(v.get_decimal128() == d); b << "foo" << v; @@ -686,8 +686,8 @@ TEST_CASE("document core builder ownership", "[bsoncxx::builder::core]") { b.append(types::b_int32{1}); auto doc = b.view_document(); auto ele = doc["falafel"]; - REQUIRE(ele.type() == type::k_int32); - REQUIRE(ele.get_value() == types::b_int32{1}); + CHECK(ele.type() == type::k_int32); + CHECK(ele.get_value() == types::b_int32{1}); } SECTION("when passing a stdx::string_view, ownership handled by caller") { @@ -702,13 +702,13 @@ TEST_CASE("document core builder throws on insufficient stack", "[bsoncxx::build builder::core b(false); b.key_view("hi"); - REQUIRE_THROWS(b.close_document()); + CHECK_THROWS(b.close_document()); } TEST_CASE("array core builder throws on insufficient stack", "[bsoncxx::builder::core]") { builder::core b(true); - REQUIRE_THROWS(b.close_array()); + CHECK_THROWS(b.close_array()); } TEST_CASE("core builder open/close works", "[bsoncxx::builder::core]") { @@ -728,26 +728,26 @@ TEST_CASE("core builder open/close works", "[bsoncxx::builder::core]") { SECTION("opening a document and closing an array throws") { b.open_document(); - REQUIRE_THROWS(b.close_array()); + CHECK_THROWS(b.close_array()); } SECTION("opening an array and closing a document throws") { b.open_array(); - REQUIRE_THROWS(b.close_document()); + CHECK_THROWS(b.close_document()); } SECTION("opening an array and viewing throws") { b.open_array(); - REQUIRE_THROWS(b.view_document()); + CHECK_THROWS(b.view_document()); } SECTION("opening a document and viewing throws") { b.open_document(); - REQUIRE_THROWS(b.view_document()); + CHECK_THROWS(b.view_document()); } SECTION("viewing with with only the key and no value fails") { - REQUIRE_THROWS(b.view_document()); + CHECK_THROWS(b.view_document()); } SECTION("viewing with with a key and value suceeds") { @@ -761,72 +761,72 @@ TEST_CASE("core view/extract methods throw when called with wrong top-level type builder::core core_document(false); SECTION("view_array only throws when called on document") { - REQUIRE_NOTHROW(core_array.view_array()); - REQUIRE_THROWS(core_document.view_array()); + CHECK_NOTHROW(core_array.view_array()); + CHECK_THROWS(core_document.view_array()); } SECTION("extract_array only throws when called on document") { - REQUIRE_NOTHROW(core_array.extract_array()); - REQUIRE_THROWS(core_document.extract_array()); + CHECK_NOTHROW(core_array.extract_array()); + CHECK_THROWS(core_document.extract_array()); } SECTION("view_document only throws when called on array") { - REQUIRE_THROWS(core_array.view_document()); - REQUIRE_NOTHROW(core_document.view_document()); + CHECK_THROWS(core_array.view_document()); + CHECK_NOTHROW(core_document.view_document()); } SECTION("extract_document only throws when called on array") { - REQUIRE_THROWS(core_array.extract_document()); - REQUIRE_NOTHROW(core_document.extract_document()); + CHECK_THROWS(core_array.extract_document()); + CHECK_NOTHROW(core_document.extract_document()); } } TEST_CASE("core builder throws on consecutive keys", "[bsoncxx::builder::core]") { SECTION("appending key_view twice") { builder::core builder{false}; - REQUIRE_NOTHROW(builder.key_view("foo")); - REQUIRE_THROWS_AS(builder.key_view("bar"), bsoncxx::exception); + CHECK_NOTHROW(builder.key_view("foo")); + CHECK_THROWS_AS(builder.key_view("bar"), bsoncxx::exception); } SECTION("appending key_view then key_owned") { builder::core builder{false}; - REQUIRE_NOTHROW(builder.key_view("foo")); - REQUIRE_THROWS_AS(builder.key_owned("bar"), bsoncxx::exception); + CHECK_NOTHROW(builder.key_view("foo")); + CHECK_THROWS_AS(builder.key_owned("bar"), bsoncxx::exception); } SECTION("appending key_owned then key_view") { builder::core builder{false}; - REQUIRE_NOTHROW(builder.key_owned("foo")); - REQUIRE_THROWS_AS(builder.key_view("bar"), bsoncxx::exception); + CHECK_NOTHROW(builder.key_owned("foo")); + CHECK_THROWS_AS(builder.key_view("bar"), bsoncxx::exception); } SECTION("appending key_owned twice") { builder::core builder{false}; - REQUIRE_NOTHROW(builder.key_owned("foo")); - REQUIRE_THROWS_AS(builder.key_owned("bar"), bsoncxx::exception); + CHECK_NOTHROW(builder.key_owned("foo")); + CHECK_THROWS_AS(builder.key_owned("bar"), bsoncxx::exception); } } TEST_CASE("core method chaining to build document works", "[bsoncxx::builder::core]") { auto full_doc = builder::core{false}.key_owned("foo").append(1).key_owned("bar").append(true).extract_document(); - REQUIRE(full_doc.view()["foo"].type() == types::b_int32::type_id); - REQUIRE(full_doc.view()["foo"].get_int32() == 1); - REQUIRE(full_doc.view()["bar"].type() == types::b_bool::type_id); - REQUIRE(full_doc.view()["bar"].get_bool() == true); + CHECK(full_doc.view()["foo"].type() == types::b_int32::type_id); + CHECK(full_doc.view()["foo"].get_int32() == 1); + CHECK(full_doc.view()["bar"].type() == types::b_bool::type_id); + CHECK(full_doc.view()["bar"].get_bool() == true); } TEST_CASE("core method chaining to build array works", "[bsoncxx::builder::core]") { auto array = builder::core{true}.append("foo").append(1).append(true).extract_array(); auto array_view = array.view(); - REQUIRE(std::distance(array_view.begin(), array_view.end()) == 3); - REQUIRE(array_view[0].type() == type::k_string); - REQUIRE(string::to_string(array_view[0].get_string().value) == "foo"); - REQUIRE(array_view[1].type() == type::k_int32); - REQUIRE(array_view[1].get_int32().value == 1); - REQUIRE(array_view[2].type() == type::k_bool); - REQUIRE(array_view[2].get_bool().value == true); + CHECK(std::distance(array_view.begin(), array_view.end()) == 3); + CHECK(array_view[0].type() == type::k_string); + CHECK(string::to_string(array_view[0].get_string().value) == "foo"); + CHECK(array_view[1].type() == type::k_int32); + CHECK(array_view[1].get_int32().value == 1); + CHECK(array_view[2].type() == type::k_bool); + CHECK(array_view[2].get_bool().value == true); } TEST_CASE("basic document builder works", "[bsoncxx::builder::basic]") { @@ -921,7 +921,7 @@ TEST_CASE("basic document builder works", "[bsoncxx::builder::basic]") { uint32_t const size = 32 * 1024 * 1024; basic.append( kvp("foo", [&](sub_binary sb) { memset(sb.allocate(binary_sub_type::k_binary, size), 0x55, size); })); - REQUIRE(basic.view().length() > size); + CHECK(basic.view().length() > size); } SECTION("sub_binary builder can allocate with length zero") { { @@ -937,7 +937,7 @@ TEST_CASE("basic document builder works", "[bsoncxx::builder::basic]") { } SECTION("sub_binary throws on double allocation") { using namespace builder::basic; - REQUIRE_THROWS_AS( + CHECK_THROWS_AS( basic.append( kvp("foo", [](sub_binary sb) { @@ -948,7 +948,7 @@ TEST_CASE("basic document builder works", "[bsoncxx::builder::basic]") { } SECTION("sub_binary throws on missing allocation") { using namespace builder::basic; - REQUIRE_THROWS_AS(basic.append(kvp("foo", [](sub_binary) {})), bsoncxx::exception); + CHECK_THROWS_AS(basic.append(kvp("foo", [](sub_binary) {})), bsoncxx::exception); } } @@ -1248,31 +1248,31 @@ TEST_CASE("array::view works", "[bsoncxx::builder::array]") { stream << 100 << 99 << 98; - REQUIRE(stream.view()[0].get_int32() == 100); - REQUIRE(stream.view()[1].get_int32() == 99); - REQUIRE(stream.view()[2].get_int32() == 98); + CHECK(stream.view()[0].get_int32() == 100); + CHECK(stream.view()[1].get_int32() == 99); + CHECK(stream.view()[2].get_int32() == 98); } TEST_CASE("builder::basic::make_document works", "[bsoncxx::builder::basic::make_document]") { auto full_doc = builder::basic::make_document(builder::basic::kvp("foo", 1), builder::basic::kvp("bar", true)); - REQUIRE(full_doc.view()["foo"].type() == types::b_int32::type_id); - REQUIRE(full_doc.view()["foo"].get_int32() == 1); - REQUIRE(full_doc.view()["bar"].type() == types::b_bool::type_id); - REQUIRE(full_doc.view()["bar"].get_bool() == true); + CHECK(full_doc.view()["foo"].type() == types::b_int32::type_id); + CHECK(full_doc.view()["foo"].get_int32() == 1); + CHECK(full_doc.view()["bar"].type() == types::b_bool::type_id); + CHECK(full_doc.view()["bar"].get_bool() == true); } TEST_CASE("builder::basic::make_array works", "[bsoncxx::builder::basic::make_array]") { auto array = builder::basic::make_array("foo", 1, true); auto array_view = array.view(); - REQUIRE(std::distance(array_view.begin(), array_view.end()) == 3); - REQUIRE(array_view[0].type() == type::k_string); - REQUIRE(string::to_string(array_view[0].get_string().value) == "foo"); - REQUIRE(array_view[1].type() == type::k_int32); - REQUIRE(array_view[1].get_int32().value == 1); - REQUIRE(array_view[2].type() == type::k_bool); - REQUIRE(array_view[2].get_bool().value == true); + CHECK(std::distance(array_view.begin(), array_view.end()) == 3); + CHECK(array_view[0].type() == type::k_string); + CHECK(string::to_string(array_view[0].get_string().value) == "foo"); + CHECK(array_view[1].type() == type::k_int32); + CHECK(array_view[1].get_int32().value == 1); + CHECK(array_view[2].type() == type::k_bool); + CHECK(array_view[2].get_bool().value == true); } TEST_CASE("stream in a document::view works", "[bsoncxx::builder::stream]") { @@ -1281,9 +1281,9 @@ TEST_CASE("stream in a document::view works", "[bsoncxx::builder::stream]") { auto sub_doc = builder::stream::document{} << "b" << 1 << finalize; auto full_doc = builder::stream::document{} << "a" << sub_doc.view() << finalize; - REQUIRE(full_doc.view()["a"].type() == bsoncxx::types::b_document::type_id); - REQUIRE(full_doc.view()["a"]["b"].type() == bsoncxx::types::b_int32::type_id); - REQUIRE(full_doc.view()["a"]["b"].get_int32().value == 1); + CHECK(full_doc.view()["a"].type() == bsoncxx::types::b_document::type_id); + CHECK(full_doc.view()["a"]["b"].type() == bsoncxx::types::b_int32::type_id); + CHECK(full_doc.view()["a"]["b"].get_int32().value == 1); } TEST_CASE("stream in an array::view works", "[bsoncxx::builder::stream]") { @@ -1292,18 +1292,18 @@ TEST_CASE("stream in an array::view works", "[bsoncxx::builder::stream]") { auto sub_array = builder::stream::array{} << 1 << 2 << 3 << finalize; auto full_doc = builder::stream::document{} << "a" << sub_array.view() << finalize; - REQUIRE(full_doc.view()["a"].type() == bsoncxx::types::b_array::type_id); - REQUIRE(full_doc.view()["a"][1].type() == bsoncxx::types::b_int32::type_id); - REQUIRE(full_doc.view()["a"][1].get_int32().value == 2); + CHECK(full_doc.view()["a"].type() == bsoncxx::types::b_array::type_id); + CHECK(full_doc.view()["a"][1].type() == bsoncxx::types::b_int32::type_id); + CHECK(full_doc.view()["a"][1].get_int32().value == 2); } TEST_CASE("builder::stream::document throws on consecutive keys", "[bsoncxx::builder::core]") { builder::stream::document doc; - REQUIRE_NOTHROW( + CHECK_NOTHROW( doc << "foo" << "bar"); - REQUIRE_NOTHROW(doc << "far"); - REQUIRE_THROWS_AS(doc << "boo", bsoncxx::exception); + CHECK_NOTHROW(doc << "far"); + CHECK_THROWS_AS(doc << "boo", bsoncxx::exception); } TEST_CASE("list builder appends utf8", "[bsoncxx::builder::list]") { @@ -1617,7 +1617,7 @@ TEST_CASE("list builder appends decimal128", "[bsoncxx::builder::list]") { auto d = types::b_decimal128{"-1234E+999"}; auto v = types::bson_value::view{d}; - REQUIRE(v.get_decimal128() == d); + CHECK(v.get_decimal128() == d); builder::list b{"foo", v}; bson_eq_object(&expected, b.view().get_document().value); @@ -1772,10 +1772,10 @@ TEST_CASE("list builder with explicit type deduction", "[bsoncxx::builder::list] SECTION("document") { builder::list b; auto kvp_regex = Catch::Matchers::Matches("(.*)must be list of key-value pairs(.*)", Catch::CaseSensitive::No); - REQUIRE_THROWS_WITH((b = builder::document{"foo", 1, 2}), kvp_regex); + CHECK_THROWS_WITH((b = builder::document{"foo", 1, 2}), kvp_regex); auto type_regex = Catch::Matchers::Matches("(.*)must be string type(.*)int32(.*)", Catch::CaseSensitive::No); - REQUIRE_THROWS_WITH((b = builder::document{"foo", 1, 2, 4}), type_regex); + CHECK_THROWS_WITH((b = builder::document{"foo", 1, 2, 4}), type_regex); } } From a8c285c255711b801974d8dd6aa90b69e9c0b7ac Mon Sep 17 00:00:00 2001 From: mdbmes Date: Mon, 24 Mar 2025 08:35:32 -0700 Subject: [PATCH 33/83] Update src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/sub_binary.hpp Co-authored-by: Ezra Chung <88335979+eramongodb@users.noreply.github.com> --- .../bsoncxx/v_noabi/bsoncxx/builder/basic/sub_binary.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/sub_binary.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/sub_binary.hpp index d8ff10e46a..eed20643b2 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/sub_binary.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/sub_binary.hpp @@ -58,8 +58,8 @@ class sub_binary { /// @return A vector::view, valid during the lifetime of this sub_binary builder. Every element must be overwritten /// before that element is read or the resulting document is used. /// @throws bsoncxx::v_noabi::exception if this sub_binary has already allocated. - /// bsoncxx::v_noabi::exception if the binary fails to append due to the BSON size limit. - /// bsoncxx::v_noabi::exception if a vector of the requested size would be too large to represent. + /// @throws bsoncxx::v_noabi::exception if the binary fails to append due to the BSON size limit. + /// @throws bsoncxx::v_noabi::exception if a vector of the requested size would be too large to represent. template ::value_type> vector::view allocate(Format, std::size_t element_count) { using format_traits = typename vector::impl::format_traits; From 9d8e4c7bf50ac963a07de402963b6c19c606d060 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Mon, 24 Mar 2025 08:37:12 -0700 Subject: [PATCH 34/83] k_vector_out_of_range --- .../v_noabi/bsoncxx/exception/error_code.hpp | 3 +++ .../bsoncxx/v_noabi/bsoncxx/vector/view.hpp | 25 +++++++++++-------- .../v_noabi/bsoncxx/exception/error_code.cpp | 2 ++ src/bsoncxx/test/vector.cpp | 9 ++++--- 4 files changed, 25 insertions(+), 14 deletions(-) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/exception/error_code.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/exception/error_code.hpp index 80b5feae01..c8a96a4d09 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/exception/error_code.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/exception/error_code.hpp @@ -149,6 +149,9 @@ enum class error_code : std::int32_t { /// A BSON Binary Vector would be too large to represent. k_vector_too_large, + /// Attempted out-of-range access to a BSON Binary Vector element. + k_vector_out_of_range, + // Add new constant string message to error_code.cpp as well! }; diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/view.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/view.hpp index e29ca6548b..820b75dd51 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/view.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/view.hpp @@ -18,6 +18,8 @@ #include +#include +#include #include #include @@ -96,8 +98,7 @@ class view { /// @brief Construct a const Vector view by validating a bsoncxx::v_noabi::types::b_binary reference. /// @param binary Non-owning reference to BSON binary data - /// @throws If the data can't be validated, throws bsoncxx::v_noabi::exception with - /// bsoncxx::v_noabi::error_code::k_invalid_vector, if the vector + /// @throws bsoncxx::v_noabi::exception with bsoncxx::v_noabi::error_code::k_invalid_vector, if validation fails. /// /// The Binary data is validated as a Vector of the templated Format. On success, a view is created which /// references the same data as the bsoncxx::v_noabi::types::b_binary pointer. @@ -198,10 +199,11 @@ class view { /// @brief Obtain a reference to a numbered byte, with bounds checking /// @param index Index in the range 0 to byte_size()-1 inclusive. /// @return A byte reference - /// @throws std::out_of_range, if the index is outside the allowed range. + /// @throws bsoncxx::v_noabi::exception with bsoncxx::v_noabi::error_code::k_vector_out_of_range, if the index is + /// outside the allowed range. byte_reference byte_at(byte_count_type index) { if (index >= byte_size()) { - throw std::out_of_range{"bsoncxx::vector::view::byte_at()"}; + throw bsoncxx::v_noabi::exception{error_code::k_vector_out_of_range}; } return *(byte_begin() + byte_difference_type(index)); } @@ -209,10 +211,11 @@ class view { /// @brief Obtain a const reference to a numbered byte, with bounds checking /// @param index Index in the range 0 to byte_size()-1 inclusive. /// @return A byte reference - /// @throws std::out_of_range, if the index is outside the allowed range. + /// @throws bsoncxx::v_noabi::exception with bsoncxx::v_noabi::error_code::k_vector_out_of_range, if the index is + /// outside the allowed range. const_byte_reference byte_at(byte_count_type index) const { if (index >= byte_size()) { - throw std::out_of_range{"bsoncxx::vector::view::byte_at()"}; + throw bsoncxx::v_noabi::exception{error_code::k_vector_out_of_range}; } return *(byte_begin() + byte_difference_type(index)); } @@ -220,10 +223,11 @@ class view { /// @brief Obtain a reference to a numbered element, with bounds checking /// @param index Index in the range 0 to size()-1 inclusive. /// @return An element reference - /// @throws std::out_of_range, if the index is outside the allowed range. + /// @throws bsoncxx::v_noabi::exception with bsoncxx::v_noabi::error_code::k_vector_out_of_range, if the index is + /// outside the allowed range. reference at(element_count_type index) { if (index >= size()) { - throw std::out_of_range{"bsoncxx::vector::view::at()"}; + throw bsoncxx::v_noabi::exception{error_code::k_vector_out_of_range}; } return *(begin() + element_difference_type(index)); } @@ -231,10 +235,11 @@ class view { /// @brief Obtain a const reference to a numbered element, with bounds checking /// @param index Index in the range 0 to size()-1 inclusive. /// @return An element reference - /// @throws std::out_of_range, if the index is outside the allowed range. + /// @throws bsoncxx::v_noabi::exception with bsoncxx::v_noabi::error_code::k_vector_out_of_range, if the index is + /// outside the allowed range. const_reference at(element_count_type index) const { if (index >= size()) { - throw std::out_of_range{"bsoncxx::vector::view::at()"}; + throw bsoncxx::v_noabi::exception{error_code::k_vector_out_of_range}; } return *(begin() + element_difference_type(index)); } diff --git a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/exception/error_code.cpp b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/exception/error_code.cpp index df77ec2174..6d5c7f1596 100644 --- a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/exception/error_code.cpp +++ b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/exception/error_code.cpp @@ -85,6 +85,8 @@ class error_category_impl final : public std::error_category { return "invalid BSON vector"; case error_code::k_vector_too_large: return "BSON vector too large"; + case error_code::k_vector_out_of_range: + return "BSON vector access out of range"; default: return "unknown bsoncxx error code"; } diff --git a/src/bsoncxx/test/vector.cpp b/src/bsoncxx/test/vector.cpp index 3140355388..7a08e3d8bc 100644 --- a/src/bsoncxx/test/vector.cpp +++ b/src/bsoncxx/test/vector.cpp @@ -181,8 +181,8 @@ TEMPLATE_TEST_CASE( CHECK(view.empty()); CHECK(view.size() == 0); CHECK(view.byte_size() == 0); - CHECK_THROWS_AS(view.at(0), std::out_of_range); - CHECK_THROWS_AS(view.byte_at(0), std::out_of_range); + CHECK_THROWS_WITH(view.at(0), Catch::Matchers::ContainsSubstring("BSON vector access out of range")); + CHECK_THROWS_WITH(view.byte_at(0), Catch::Matchers::ContainsSubstring("BSON vector access out of range")); } SECTION("decode a valid vector with a single element") { @@ -197,8 +197,9 @@ TEMPLATE_TEST_CASE( CHECK(view[0] == element); CHECK(view.byte_at(0) == bytes[2]); CHECK(view.byte_at(bytes.size() - 3u) == bytes[bytes.size() - 1u]); - CHECK_THROWS_AS(view.at(1), std::out_of_range); - CHECK_THROWS_AS(view.byte_at(bytes.size() - 2u), std::out_of_range); + CHECK_THROWS_WITH(view.at(1), Catch::Matchers::ContainsSubstring("BSON vector access out of range")); + CHECK_THROWS_WITH( + view.byte_at(bytes.size() - 2u), Catch::Matchers::ContainsSubstring("BSON vector access out of range")); } SECTION("reject binary data of the wrong sub_type") { From 973f7b68b2a53ad232ed14227b03db655d6574e7 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Mon, 24 Mar 2025 09:02:38 -0700 Subject: [PATCH 35/83] doxygen suggestions --- src/bsoncxx/include/bsoncxx/docs/top.hpp | 14 ++++++++++++-- src/bsoncxx/include/bsoncxx/docs/v_noabi.hpp | 9 +++++++-- .../bsoncxx/builder/basic/sub_binary-fwd.hpp | 2 +- .../v_noabi/bsoncxx/builder/basic/sub_binary.hpp | 7 ++++--- .../bsoncxx/v_noabi/bsoncxx/vector/view.hpp | 8 +------- 5 files changed, 25 insertions(+), 15 deletions(-) diff --git a/src/bsoncxx/include/bsoncxx/docs/top.hpp b/src/bsoncxx/include/bsoncxx/docs/top.hpp index b1a068d249..7bd91cd35e 100644 --- a/src/bsoncxx/include/bsoncxx/docs/top.hpp +++ b/src/bsoncxx/include/bsoncxx/docs/top.hpp @@ -91,10 +91,20 @@ /// /// @namespace bsoncxx::vector -/// Declarations related to BSON Binary Vector (@ref bsoncxx::v_noabi::binary_sub_type::k_vector) items. +/// Declarations related to the BSON Binary Vector subtype. /// /// /// @namespace bsoncxx::vector::formats -/// Each type here is a supported format for bsoncxx::vector +/// Declares supported BSON Binary Vector formats. +/// + +/// +/// @namespace bsoncxx::vector::elements +/// Declares element accessor types for BSON Binary Vector. +/// + +/// +/// @namespace bsoncxx::vector::iterators +/// Declares iterator types for BSON Binary Vector. /// diff --git a/src/bsoncxx/include/bsoncxx/docs/v_noabi.hpp b/src/bsoncxx/include/bsoncxx/docs/v_noabi.hpp index a21f7203f6..f1ccaf1a9b 100644 --- a/src/bsoncxx/include/bsoncxx/docs/v_noabi.hpp +++ b/src/bsoncxx/include/bsoncxx/docs/v_noabi.hpp @@ -96,6 +96,11 @@ /// Provides headers declaring entities in @ref bsoncxx::v_noabi::types::bson_value. /// +/// +/// @dir bsoncxx/v_noabi/bsoncxx/vector +/// Provides headers declaring entities in @ref bsoncxx::v_noabi::vector. +/// + /// /// @namespace bsoncxx::v_noabi /// Declares entities whose ABI stability is NOT guaranteed. @@ -156,12 +161,12 @@ /// /// @namespace bsoncxx::v_noabi::vector::iterators -/// Special-purpose iterator types for bsoncxx::vector +/// @copydoc bsoncxx::vector::iterators /// /// /// @namespace bsoncxx::v_noabi::vector::elements -/// Special-purpose element reference types for bsoncxx::vector +/// @copydoc bsoncxx::vector::elements /// /// diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/sub_binary-fwd.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/sub_binary-fwd.hpp index 984fddaeeb..748a96b2ac 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/sub_binary-fwd.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/sub_binary-fwd.hpp @@ -38,5 +38,5 @@ using ::bsoncxx::v_noabi::builder::basic::sub_binary; /// /// @file -/// Declares @ref bsoncxx::builder::basic::sub_binary, for constructing BSON Binary values in-place. +/// Declares @ref bsoncxx::builder::basic::sub_binary /// diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/sub_binary.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/sub_binary.hpp index eed20643b2..bbff078666 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/sub_binary.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/sub_binary.hpp @@ -47,7 +47,7 @@ class sub_binary { /// @return Pointer to uninitialized memory within the bson_t, valid only during this sub_binary builder's lifetime. /// The caller must overwrite every byte if the resulting BSON document is to be used. /// @throws bsoncxx::v_noabi::exception if this sub_binary has already allocated. - /// bsoncxx::v_noabi::exception if the binary fails to append due to the BSON size limit. + /// @throws bsoncxx::v_noabi::exception if the binary fails to append due to the BSON size limit. std::uint8_t* allocate(binary_sub_type sub_type, std::uint32_t length) { return _core->append(sub_type, length); } @@ -61,7 +61,8 @@ class sub_binary { /// @throws bsoncxx::v_noabi::exception if the binary fails to append due to the BSON size limit. /// @throws bsoncxx::v_noabi::exception if a vector of the requested size would be too large to represent. template ::value_type> - vector::view allocate(Format, std::size_t element_count) { + vector::view allocate(Format fmt, std::size_t element_count) { + (void)fmt; using format_traits = typename vector::impl::format_traits; std::uint32_t binary_data_length = format_traits::length_for_append(element_count); std::uint8_t* binary_data = allocate(binary_sub_type::k_vector, binary_data_length); @@ -84,5 +85,5 @@ class sub_binary { /// /// @file -/// Declares @ref bsoncxx::v_noabi::builder::basic::sub_binary, for constructing BSON Binary values in-place. +/// Declares @ref bsoncxx::v_noabi::builder::basic::sub_binary /// diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/view.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/view.hpp index 820b75dd51..9ab2b7de7e 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/view.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/view.hpp @@ -17,6 +17,7 @@ #include #include +#include #include #include @@ -27,13 +28,6 @@ namespace bsoncxx { namespace v_noabi { - -namespace builder { -namespace basic { -class sub_binary; -} // namespace basic -} // namespace builder - namespace vector { /// @brief Accessor for the contents of a valid BSON Binary Vector From 7194f602923f8d68cba3946e835f3877c9592929 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Tue, 25 Mar 2025 14:32:30 -0700 Subject: [PATCH 36/83] Rename bsoncxx::v_noabi::vector::impl to detail --- .../bsoncxx/builder/basic/sub_binary.hpp | 6 +++--- .../bsoncxx/vector/{impl.hpp => detail.hpp} | 4 ++-- .../v_noabi/bsoncxx/vector/iterators.hpp | 8 ++++---- .../bsoncxx/v_noabi/bsoncxx/vector/view.hpp | 18 +++++++++--------- .../lib/bsoncxx/v_noabi/bsoncxx/vector.cpp | 6 +++--- 5 files changed, 21 insertions(+), 21 deletions(-) rename src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/{impl.hpp => detail.hpp} (99%) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/sub_binary.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/sub_binary.hpp index bbff078666..8ac64b064f 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/sub_binary.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/sub_binary.hpp @@ -20,8 +20,8 @@ #include #include +#include #include -#include #include #include @@ -60,10 +60,10 @@ class sub_binary { /// @throws bsoncxx::v_noabi::exception if this sub_binary has already allocated. /// @throws bsoncxx::v_noabi::exception if the binary fails to append due to the BSON size limit. /// @throws bsoncxx::v_noabi::exception if a vector of the requested size would be too large to represent. - template ::value_type> + template ::value_type> vector::view allocate(Format fmt, std::size_t element_count) { (void)fmt; - using format_traits = typename vector::impl::format_traits; + using format_traits = typename vector::detail::format_traits; std::uint32_t binary_data_length = format_traits::length_for_append(element_count); std::uint8_t* binary_data = allocate(binary_sub_type::k_vector, binary_data_length); return { diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/impl.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/detail.hpp similarity index 99% rename from src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/impl.hpp rename to src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/detail.hpp index bba96c04de..61a7fe8e92 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/impl.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/detail.hpp @@ -26,7 +26,7 @@ namespace bsoncxx { namespace v_noabi { namespace vector { -namespace impl { +namespace detail { /// @brief Implementation detail. A copy of the validated BSON Binary Vector header, included in each view. struct header { @@ -159,7 +159,7 @@ struct format_traits : format_traits_base { } }; -} // namespace impl +} // namespace detail } // namespace vector } // namespace v_noabi } // namespace bsoncxx diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/iterators.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/iterators.hpp index 965f0c800e..32933c6b30 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/iterators.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/iterators.hpp @@ -29,12 +29,12 @@ namespace vector { template class view; -namespace impl { +namespace detail { template struct format_traits; -} // namespace impl +} // namespace detail namespace iterators { @@ -279,8 +279,8 @@ class packed_bit_byte { } private: - friend struct impl::format_traits; - friend struct impl::format_traits; + friend struct detail::format_traits; + friend struct detail::format_traits; constexpr packed_bit_byte(packed_bit_element element, packed_bit_element element_end) : byte(element.byte), diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/view.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/view.hpp index 9ab2b7de7e..7f871c5cff 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/view.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/view.hpp @@ -16,13 +16,13 @@ #include -#include #include +#include #include #include +#include #include -#include #include @@ -49,7 +49,7 @@ namespace vector { /// template class view { - using format_traits = typename impl::format_traits::type>; + using format_traits = typename detail::format_traits::type>; public: using format = Format; @@ -72,8 +72,8 @@ class view { typename format_traits::const_iterator, typename format_traits::iterator>::type; - using byte_type = typename impl::view_data::byte_type; - using byte_count_type = typename impl::view_data::byte_count_type; + using byte_type = typename detail::view_data::byte_type; + using byte_count_type = typename detail::view_data::byte_count_type; using element_count_type = typename format_traits::element_count_type; using byte_difference_type = typename format_traits::byte_difference_type; using element_difference_type = typename format_traits::element_difference_type; @@ -101,7 +101,7 @@ class view { /// @brief Count the bytes of element data /// @return Size of the vector data, not including any headers constexpr byte_count_type byte_size() const noexcept { - return impl_data.size - byte_count_type(sizeof(impl::header::bytes)); + return impl_data.size - byte_count_type(sizeof(detail::header::bytes)); } /// @brief Count the number of elements @@ -113,7 +113,7 @@ class view { /// @brief Obtain an iterator pointing to the beginning of the vector /// @return A per-element random access iterator, pointing at the first element if one exists constexpr iterator begin() const noexcept { - return iterator(impl_data.bytes + sizeof(impl::header::bytes)); + return iterator(impl_data.bytes + sizeof(detail::header::bytes)); } /// @brief Obtain an iterator pointing just past the end of the vector @@ -263,9 +263,9 @@ class view { private: friend class bsoncxx::v_noabi::builder::basic::sub_binary; - view(impl::view_data data) noexcept : impl_data(data) {} + view(detail::view_data data) noexcept : impl_data(data) {} - impl::view_data impl_data; + detail::view_data impl_data; }; } // namespace vector diff --git a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/vector.cpp b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/vector.cpp index 7b9fb72063..40729ed8ba 100644 --- a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/vector.cpp +++ b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/vector.cpp @@ -16,14 +16,14 @@ #include #include -#include +#include #include namespace bsoncxx { namespace v_noabi { namespace vector { -namespace impl { +namespace detail { enum element_type : std::uint8_t { signed_integer = 0, @@ -114,7 +114,7 @@ view_data format_traits::con return libbson_const_validate(binary, bson_vector_packed_bit_const_view_init); } -} // namespace impl +} // namespace detail } // namespace vector } // namespace v_noabi } // namespace bsoncxx From d38f8aab91f55541b8909df7476a98d127e97a44 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Tue, 25 Mar 2025 15:33:24 -0700 Subject: [PATCH 37/83] Take the impl out of impl_data --- .../include/bsoncxx/v_noabi/bsoncxx/vector/view.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/view.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/view.hpp index 7f871c5cff..d2e773c9df 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/view.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/view.hpp @@ -96,24 +96,24 @@ class view { /// /// The Binary data is validated as a Vector of the templated Format. On success, a view is created which /// references the same data as the bsoncxx::v_noabi::types::b_binary pointer. - view(types::b_binary const& binary) : impl_data(format_traits::const_validate(binary)) {} + view(types::b_binary const& binary) : _data(format_traits::const_validate(binary)) {} /// @brief Count the bytes of element data /// @return Size of the vector data, not including any headers constexpr byte_count_type byte_size() const noexcept { - return impl_data.size - byte_count_type(sizeof(detail::header::bytes)); + return _data.size - byte_count_type(sizeof(detail::header::bytes)); } /// @brief Count the number of elements /// @return Number of elements constexpr element_count_type size() const noexcept { - return format_traits::element_count(impl_data.size, impl_data.header_copy); + return format_traits::element_count(_data.size, _data.header_copy); } /// @brief Obtain an iterator pointing to the beginning of the vector /// @return A per-element random access iterator, pointing at the first element if one exists constexpr iterator begin() const noexcept { - return iterator(impl_data.bytes + sizeof(detail::header::bytes)); + return iterator(_data.bytes + sizeof(detail::header::bytes)); } /// @brief Obtain an iterator pointing just past the end of the vector @@ -263,9 +263,9 @@ class view { private: friend class bsoncxx::v_noabi::builder::basic::sub_binary; - view(detail::view_data data) noexcept : impl_data(data) {} + view(detail::view_data data) noexcept : _data(data) {} - detail::view_data impl_data; + detail::view_data _data; }; } // namespace vector From fa51a1684c8126356db5c108c722a93ad119f672 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Tue, 25 Mar 2025 15:49:20 -0700 Subject: [PATCH 38/83] Refactor forward declarations --- .../v_noabi/bsoncxx/vector/detail-fwd.hpp | 37 ++++++++++++++ .../v_noabi/bsoncxx/vector/elements-fwd.hpp | 42 ++++++++++++++++ .../v_noabi/bsoncxx/vector/elements.hpp | 15 ++---- .../v_noabi/bsoncxx/vector/formats-fwd.hpp | 5 +- .../v_noabi/bsoncxx/vector/iterators-fwd.hpp | 49 +++++++++++++++++++ .../v_noabi/bsoncxx/vector/iterators.hpp | 20 ++------ 6 files changed, 137 insertions(+), 31 deletions(-) create mode 100644 src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/detail-fwd.hpp create mode 100644 src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/elements-fwd.hpp create mode 100644 src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/iterators-fwd.hpp diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/detail-fwd.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/detail-fwd.hpp new file mode 100644 index 0000000000..57cf94ca4b --- /dev/null +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/detail-fwd.hpp @@ -0,0 +1,37 @@ +// Copyright 2009-present MongoDB, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include + +namespace bsoncxx { +namespace v_noabi { +namespace vector { +namespace detail { + +template +struct format_traits; + +} // namespace detail +} // namespace vector +} // namespace v_noabi +} // namespace bsoncxx + +#include + +/// +/// @file +/// For internal use only! +/// diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/elements-fwd.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/elements-fwd.hpp new file mode 100644 index 0000000000..b7aef1b30f --- /dev/null +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/elements-fwd.hpp @@ -0,0 +1,42 @@ +// Copyright 2009-present MongoDB, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include + +namespace bsoncxx { +namespace v_noabi { +namespace vector { +namespace elements { + +class float32; + +template +class packed_bit_element; + +template +class packed_bit_byte; + +} // namespace elements +} // namespace vector +} // namespace v_noabi +} // namespace bsoncxx + +#include + +/// +/// @file +/// Forward declarations for @ref bsoncxx::v_noabi::vector::elements. +/// diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/elements.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/elements.hpp index 3e9c16ce66..a8bd6410e0 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/elements.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/elements.hpp @@ -21,22 +21,13 @@ #include #include +#include + #include namespace bsoncxx { namespace v_noabi { namespace vector { - -namespace iterators { - -template -class packed_bit_element; - -template -class packed_bit_byte; - -} // namespace iterators - namespace elements { /// @brief A 32-bit float value in packed little-endian format @@ -270,5 +261,5 @@ void swap(packed_bit_byte a, packed_bit_byte b) noexcept { /// /// @file -/// Special purpose element reference types for BSON Binary Vector access +/// Declares entities in @ref bsoncxx::v_noabi::vector::elements. /// diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/formats-fwd.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/formats-fwd.hpp index 18498f9f9c..f6018fccdb 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/formats-fwd.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/formats-fwd.hpp @@ -46,8 +46,5 @@ using ::bsoncxx::v_noabi::vector::formats::f_packed_bit; /// /// @file -/// Declares vector formats: -/// @ref bsoncxx::vector::formats::f_float32 -/// @ref bsoncxx::vector::formats::f_int8 -/// @ref bsoncxx::vector::formats::f_packed_bit +/// Declares entities in @ref bsoncxx::vector::formats. /// diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/iterators-fwd.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/iterators-fwd.hpp new file mode 100644 index 0000000000..5f0c7dfa04 --- /dev/null +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/iterators-fwd.hpp @@ -0,0 +1,49 @@ +// Copyright 2009-present MongoDB, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include + +#include +#include + +#include + +namespace bsoncxx { +namespace v_noabi { +namespace vector { +namespace iterators { + +template +class packed_bit_byte; + +template +class packed_bit_element; + +template +class packed_bit_byte; + +} // namespace iterators +} // namespace vector +} // namespace v_noabi +} // namespace bsoncxx + +#include + +/// +/// @file +/// Forward declarations for @ref bsoncxx::v_noabi::vector::iterators. +/// diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/iterators.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/iterators.hpp index 32933c6b30..9706c6c600 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/iterators.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/iterators.hpp @@ -17,6 +17,10 @@ #include #include +#include +#include +#include + #include #include @@ -25,22 +29,8 @@ namespace bsoncxx { namespace v_noabi { namespace vector { - -template -class view; - -namespace detail { - -template -struct format_traits; - -} // namespace detail - namespace iterators { -template -class packed_bit_byte; - /// @brief Iterator for elements within a packed_bit vector /// @tparam Iterator Underlying byte iterator type template @@ -304,5 +294,5 @@ class packed_bit_byte { /// /// @file -/// Special purpose iterator types for BSON Binary Vector access +/// Declares entities in @ref bsoncxx::v_noabi::vector::iterators. /// From d69d6e286703a9b33d180b90d05066928ed3274e Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Tue, 25 Mar 2025 16:16:12 -0700 Subject: [PATCH 39/83] Rename vector view to vector accessor --- examples/bsoncxx/bson_binary_vector.cpp | 92 +++--- .../bsoncxx/builder/basic/sub_binary.hpp | 8 +- .../vector/{view-fwd.hpp => accessor-fwd.hpp} | 6 +- .../bsoncxx/vector/{view.hpp => accessor.hpp} | 24 +- .../bsoncxx/v_noabi/bsoncxx/vector/detail.hpp | 17 +- .../v_noabi/bsoncxx/vector/iterators.hpp | 6 +- .../lib/bsoncxx/v_noabi/bsoncxx/vector.cpp | 8 +- src/bsoncxx/test/vector.cpp | 278 +++++++++--------- 8 files changed, 221 insertions(+), 218 deletions(-) rename src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/{view-fwd.hpp => accessor-fwd.hpp} (90%) rename src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/{view.hpp => accessor.hpp} (92%) diff --git a/examples/bsoncxx/bson_binary_vector.cpp b/examples/bsoncxx/bson_binary_vector.cpp index e652aa097a..83aaaba320 100644 --- a/examples/bsoncxx/bson_binary_vector.cpp +++ b/examples/bsoncxx/bson_binary_vector.cpp @@ -23,8 +23,8 @@ #include #include #include +#include #include -#include #include @@ -42,97 +42,99 @@ int EXAMPLES_CDECL main() { }), kvp("vector_int8", [&](sub_binary sbin) { - auto view = sbin.allocate(bsoncxx::vector::formats::f_int8{}, 1000); + auto vec = sbin.allocate(bsoncxx::vector::formats::f_int8{}, 1000); uint8_t i = 0; - std::generate(view.begin(), view.end(), [&] { return (int8_t)++i; }); + std::generate(vec.begin(), vec.end(), [&] { return (int8_t)++i; }); }), kvp("vector_float32", [&](sub_binary sbin) { - auto view = sbin.allocate(bsoncxx::vector::formats::f_float32{}, 1000); - view[0] = 0.f; - view[1] = 1e-38f; - for (size_t i = 2; i < view.size(); i++) { - view[i] = view[i - 1] + view[i - 2]; + auto vec = sbin.allocate(bsoncxx::vector::formats::f_float32{}, 1000); + vec[0] = 0.f; + vec[1] = 1e-38f; + for (size_t i = 2; i < vec.size(); i++) { + vec[i] = vec[i - 1] + vec[i - 2]; } - for (auto i = view.begin(); i != view.end(); i++) { + for (auto i = vec.begin(); i != vec.end(); i++) { if (!(*i * 0.f < *i)) { - *i = float(std::sin(double(i - view.begin()) * 1e-3)); + *i = float(std::sin(double(i - vec.begin()) * 1e-3)); } } - std::fill(view.end() - 10, view.end() - 7, std::numeric_limits::infinity()); - view[0] += 1.f; - view[1] *= 1e38f; - view[1] /= 2.f; - view[1] -= 1.f + view[0]; + std::fill(vec.end() - 10, vec.end() - 7, std::numeric_limits::infinity()); + vec[0] += 1.f; + vec[1] *= 1e38f; + vec[1] /= 2.f; + vec[1] -= 1.f + vec[0]; }), kvp("vector_packed_bit", [&](sub_binary sbin) { - auto view = sbin.allocate(bsoncxx::vector::formats::f_packed_bit{}, 61); - std::fill(view.begin(), view.end(), true); - view[5] = !view[5]; - view[6] = view[1]; - view[7] = view[5]; - view[8] = 0; - view[60] = false; - std::fill(view.end() - 20, view.end() - 4, false); - std::fill(view.end() - 8, view.end() - 5, true); - for (auto i = view.byte_begin(); i != view.byte_end(); i++) { + auto vec = sbin.allocate(bsoncxx::vector::formats::f_packed_bit{}, 61); + std::fill(vec.begin(), vec.end(), true); + vec[5] = !vec[5]; + vec[6] = vec[1]; + vec[7] = vec[5]; + vec[8] = 0; + vec[60] = false; + std::fill(vec.end() - 20, vec.end() - 4, false); + std::fill(vec.end() - 8, vec.end() - 5, true); + for (auto i = vec.byte_begin(); i != vec.byte_end(); i++) { *i ^= 0xFF; } - std::copy(view.byte_begin(), view.byte_begin() + 2, view.byte_begin() + 2); - std::copy(view.begin() + 5, view.begin() + 9, view.begin() + 56); + std::copy(vec.byte_begin(), vec.byte_begin() + 2, vec.byte_begin() + 2); + std::copy(vec.begin() + 5, vec.begin() + 9, vec.begin() + 56); })); std::cout << bsoncxx::to_json(doc) << std::endl; { - bsoncxx::vector::view v(doc["vector_int8"].get_binary()); - std::cout << "int8: " << v.size() << std::endl; - for (auto i = v.begin(); i != v.end(); i++) { + bsoncxx::vector::accessor vec(doc["vector_int8"].get_binary()); + std::cout << "int8: " << vec.size() << std::endl; + for (auto i = vec.begin(); i != vec.end(); i++) { std::cout << int(*i) << " "; } std::cout << std::endl; } { - bsoncxx::vector::view v(doc["vector_int8"].get_binary()); - std::cout << "int8 bytes: " << v.byte_size() << std::hex << std::endl; - for (auto i = v.byte_begin(); i != v.byte_end(); i++) { + bsoncxx::vector::accessor vec(doc["vector_int8"].get_binary()); + std::cout << "int8 bytes: " << vec.byte_size() << std::hex << std::endl; + for (auto i = vec.byte_begin(); i != vec.byte_end(); i++) { std::cout << int(*i) << " "; } std::cout << std::dec << std::endl; } { - bsoncxx::vector::view v(doc["vector_float32"].get_binary()); - std::cout << "float32: " << v.size() << std::endl; - for (auto i = v.begin(); i != v.end(); i++) { + bsoncxx::vector::accessor vec(doc["vector_float32"].get_binary()); + std::cout << "float32: " << vec.size() << std::endl; + for (auto i = vec.begin(); i != vec.end(); i++) { std::cout << *i << " "; } std::cout << std::endl; } { - bsoncxx::vector::view v(doc["vector_float32"].get_binary()); - std::cout << "float32 bytes: " << v.byte_size() << std::hex << std::endl; - for (auto i = v.byte_begin(); i != v.byte_end(); i++) { + bsoncxx::vector::accessor vec(doc["vector_float32"].get_binary()); + std::cout << "float32 bytes: " << vec.byte_size() << std::hex << std::endl; + for (auto i = vec.byte_begin(); i != vec.byte_end(); i++) { std::cout << int(*i) << " "; } std::cout << std::dec << std::endl; } { - bsoncxx::vector::view v(doc["vector_packed_bit"].get_binary()); - std::cout << "packed_bit: " << v.size() << std::endl; - for (auto i = v.begin(); i != v.end(); i++) { + bsoncxx::vector::accessor vec( + doc["vector_packed_bit"].get_binary()); + std::cout << "packed_bit: " << vec.size() << std::endl; + for (auto i = vec.begin(); i != vec.end(); i++) { std::cout << *i << " "; } std::cout << std::endl; } { - bsoncxx::vector::view v(doc["vector_packed_bit"].get_binary()); - std::cout << "packed_bit bytes: " << v.byte_size() << std::hex << std::endl; - for (auto i = v.byte_begin(); i != v.byte_end(); i++) { + bsoncxx::vector::accessor vec( + doc["vector_packed_bit"].get_binary()); + std::cout << "packed_bit bytes: " << vec.byte_size() << std::hex << std::endl; + for (auto i = vec.byte_begin(); i != vec.byte_end(); i++) { std::cout << int(*i) << " "; } std::cout << std::dec << std::endl; diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/sub_binary.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/sub_binary.hpp index 8ac64b064f..6863a63a31 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/sub_binary.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/sub_binary.hpp @@ -20,9 +20,9 @@ #include #include +#include #include #include -#include #include @@ -55,13 +55,13 @@ class sub_binary { /// @brief Allocate and format space for a BSON Binary Vector with uninitialized elements. /// @param fmt Instance of a format type from @ref bsoncxx::v_noabi::vector::formats /// @param element_count Number of elements to allocate space for. - /// @return A vector::view, valid during the lifetime of this sub_binary builder. Every element must be overwritten - /// before that element is read or the resulting document is used. + /// @return A writable vector::accessor, valid during the lifetime of this sub_binary builder. Every element must be + /// overwritten before that element is read or the resulting document is used. /// @throws bsoncxx::v_noabi::exception if this sub_binary has already allocated. /// @throws bsoncxx::v_noabi::exception if the binary fails to append due to the BSON size limit. /// @throws bsoncxx::v_noabi::exception if a vector of the requested size would be too large to represent. template ::value_type> - vector::view allocate(Format fmt, std::size_t element_count) { + vector::accessor allocate(Format fmt, std::size_t element_count) { (void)fmt; using format_traits = typename vector::detail::format_traits; std::uint32_t binary_data_length = format_traits::length_for_append(element_count); diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/view-fwd.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/accessor-fwd.hpp similarity index 90% rename from src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/view-fwd.hpp rename to src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/accessor-fwd.hpp index f9692864cc..9d8cd1363b 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/view-fwd.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/accessor-fwd.hpp @@ -21,7 +21,7 @@ namespace v_noabi { namespace vector { template -class view; +class accessor; } // namespace vector } // namespace v_noabi @@ -30,7 +30,7 @@ class view; namespace bsoncxx { namespace vector { -using ::bsoncxx::v_noabi::vector::view; +using ::bsoncxx::v_noabi::vector::accessor; } // namespace vector } // namespace bsoncxx @@ -39,5 +39,5 @@ using ::bsoncxx::v_noabi::vector::view; /// /// @file -/// Declares @ref bsoncxx::vector::view. +/// Declares @ref bsoncxx::vector::accessor. /// diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/view.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/accessor.hpp similarity index 92% rename from src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/view.hpp rename to src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/accessor.hpp index d2e773c9df..82bc1e1982 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/view.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/accessor.hpp @@ -17,7 +17,7 @@ #include #include -#include +#include #include #include @@ -34,8 +34,8 @@ namespace vector { /// @tparam Format One of the @ref bsoncxx::v_noabi::vector::formats types, optionally with a const qualifier. /// /// This accessor operates on data formatted for the bsoncxx::v_noabi::binary_sub_type::k_vector BSON binary -/// subtype. A mutable view may be constructed only using bsoncxx::v_noabi::builder::basic::sub_binary. A const -/// view may be constructed by validating a bsoncxx::v_noabi::types::b_binary. +/// subtype. A mutable accessor may be constructed only using bsoncxx::v_noabi::builder::basic::sub_binary. A const +/// accessor may be constructed by validating any bsoncxx::v_noabi::types::b_binary. /// /// The specific iterator and element types vary for each supported format. When possible, /// iterators are raw pointers. @@ -48,7 +48,7 @@ namespace vector { /// bits. /// template -class view { +class accessor { using format_traits = typename detail::format_traits::type>; public: @@ -72,8 +72,8 @@ class view { typename format_traits::const_iterator, typename format_traits::iterator>::type; - using byte_type = typename detail::view_data::byte_type; - using byte_count_type = typename detail::view_data::byte_count_type; + using byte_type = typename detail::accessor_data::byte_type; + using byte_count_type = typename detail::accessor_data::byte_count_type; using element_count_type = typename format_traits::element_count_type; using byte_difference_type = typename format_traits::byte_difference_type; using element_difference_type = typename format_traits::element_difference_type; @@ -90,13 +90,13 @@ class view { typename format_traits::const_byte_iterator, typename format_traits::byte_iterator>::type; - /// @brief Construct a const Vector view by validating a bsoncxx::v_noabi::types::b_binary reference. + /// @brief Construct a const Vector accessor by validating a bsoncxx::v_noabi::types::b_binary reference. /// @param binary Non-owning reference to BSON binary data /// @throws bsoncxx::v_noabi::exception with bsoncxx::v_noabi::error_code::k_invalid_vector, if validation fails. /// - /// The Binary data is validated as a Vector of the templated Format. On success, a view is created which + /// The Binary data is validated as a Vector of the templated Format. On success, an accessor is created which /// references the same data as the bsoncxx::v_noabi::types::b_binary pointer. - view(types::b_binary const& binary) : _data(format_traits::const_validate(binary)) {} + accessor(types::b_binary const& binary) : _data(format_traits::const_validate(binary)) {} /// @brief Count the bytes of element data /// @return Size of the vector data, not including any headers @@ -263,9 +263,9 @@ class view { private: friend class bsoncxx::v_noabi::builder::basic::sub_binary; - view(detail::view_data data) noexcept : _data(data) {} + accessor(detail::accessor_data data) noexcept : _data(data) {} - detail::view_data _data; + detail::accessor_data _data; }; } // namespace vector @@ -276,5 +276,5 @@ class view { /// /// @file -/// Declares @ref bsoncxx::v_noabi::vector::view. +/// Declares @ref bsoncxx::v_noabi::vector::accessor. /// diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/detail.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/detail.hpp index 61a7fe8e92..5281778a75 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/detail.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/detail.hpp @@ -28,15 +28,15 @@ namespace v_noabi { namespace vector { namespace detail { -/// @brief Implementation detail. A copy of the validated BSON Binary Vector header, included in each view. +/// @brief Implementation detail. A copy of the validated BSON Binary Vector header, included in each accessor. struct header { std::uint8_t bytes[2]; }; -/// @brief Implementation detail. Common data for each view type. -/// @tparam Format One of the @ref bsoncxx::v_noabi::vector::formats types. +/// @brief Implementation detail. Common data for each accessor type. +/// @tparam Format One of the @ref bsoncxx::v_noabi::vector::formats types, optionally const. template -struct view_data { +struct accessor_data { using byte_type = typename std::conditional::value, std::uint8_t const, std::uint8_t>::type; using byte_count_type = std::uint32_t; @@ -60,7 +60,7 @@ struct format_traits_base { }; /// @brief Implementation detail. Format traits, specialized by format. -/// @tparam Format One of the @ref bsoncxx::v_noabi::vector::formats types. +/// @tparam Format One of the @ref bsoncxx::v_noabi::vector::formats types, without qualifiers. template struct format_traits; @@ -77,7 +77,7 @@ struct format_traits : format_traits_base { static BSONCXX_ABI_EXPORT_CDECL(std::uint32_t) length_for_append(std::size_t element_count); static BSONCXX_ABI_EXPORT_CDECL(header) write_frame(std::uint8_t* binary_data, std::uint32_t binary_data_length, std::size_t element_count); - static BSONCXX_ABI_EXPORT_CDECL(view_data) const_validate(types::b_binary const& binary); + static BSONCXX_ABI_EXPORT_CDECL(accessor_data) const_validate(types::b_binary const& binary); static constexpr std::size_t element_count(std::uint32_t binary_data_length, header) noexcept { return binary_data_length - sizeof(header::bytes); @@ -105,7 +105,8 @@ struct format_traits : format_traits_base { static BSONCXX_ABI_EXPORT_CDECL(std::uint32_t) length_for_append(std::size_t element_count); static BSONCXX_ABI_EXPORT_CDECL(header) write_frame(std::uint8_t* binary_data, std::uint32_t binary_data_length, std::size_t element_count); - static BSONCXX_ABI_EXPORT_CDECL(view_data) const_validate(types::b_binary const& binary); + static BSONCXX_ABI_EXPORT_CDECL(accessor_data) const_validate( + types::b_binary const& binary); static constexpr std::size_t element_count(std::uint32_t binary_data_length, header) noexcept { return (binary_data_length - sizeof(header::bytes)) / sizeof(float); @@ -141,7 +142,7 @@ struct format_traits : format_traits_base { static BSONCXX_ABI_EXPORT_CDECL(std::uint32_t) length_for_append(std::size_t element_count); static BSONCXX_ABI_EXPORT_CDECL(header) write_frame(std::uint8_t* binary_data, std::uint32_t binary_data_length, std::size_t element_count); - static BSONCXX_ABI_EXPORT_CDECL(view_data) const_validate( + static BSONCXX_ABI_EXPORT_CDECL(accessor_data) const_validate( types::b_binary const& binary); static constexpr std::size_t element_count(std::uint32_t binary_data_length, header hdr) noexcept { diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/iterators.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/iterators.hpp index 9706c6c600..c25438818a 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/iterators.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/iterators.hpp @@ -17,9 +17,9 @@ #include #include +#include #include #include -#include #include #include @@ -146,8 +146,8 @@ class packed_bit_element { private: friend class packed_bit_byte; - friend class view; - friend class view; + friend class accessor; + friend class accessor; constexpr packed_bit_element(Iterator byte_iter, std::uint8_t bit_index = 0) noexcept : byte(byte_iter), bit(bit_index) {} diff --git a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/vector.cpp b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/vector.cpp index 40729ed8ba..ab8f2c19e4 100644 --- a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/vector.cpp +++ b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/vector.cpp @@ -92,24 +92,24 @@ header format_traits::write_frame( } template -static view_data libbson_const_validate(bsoncxx::v_noabi::types::b_binary const& binary, Impl func) { +static accessor_data libbson_const_validate(bsoncxx::v_noabi::types::b_binary const& binary, Impl func) { if (binary.sub_type != binary_sub_type::k_vector || !func(NULL, binary.bytes, binary.size)) { throw bsoncxx::v_noabi::exception{error_code::k_invalid_vector}; } return {binary.bytes, binary.size, copy_header(binary.bytes)}; } -view_data format_traits::const_validate( +accessor_data format_traits::const_validate( bsoncxx::v_noabi::types::b_binary const& binary) { return libbson_const_validate(binary, bson_vector_int8_const_view_init); } -view_data format_traits::const_validate( +accessor_data format_traits::const_validate( bsoncxx::v_noabi::types::b_binary const& binary) { return libbson_const_validate(binary, bson_vector_float32_const_view_init); } -view_data format_traits::const_validate( +accessor_data format_traits::const_validate( bsoncxx::v_noabi::types::b_binary const& binary) { return libbson_const_validate(binary, bson_vector_packed_bit_const_view_init); } diff --git a/src/bsoncxx/test/vector.cpp b/src/bsoncxx/test/vector.cpp index 7a08e3d8bc..93b5216a38 100644 --- a/src/bsoncxx/test/vector.cpp +++ b/src/bsoncxx/test/vector.cpp @@ -20,8 +20,8 @@ #include #include #include +#include #include -#include #include @@ -166,8 +166,8 @@ void iterator_operations( } TEMPLATE_TEST_CASE( - "all vector view formats", - "[bsoncxx::vector::view]", + "all vector accessor formats", + "[bsoncxx::vector::accessor]", vector::formats::f_float32, vector::formats::f_int8, vector::formats::f_packed_bit) { @@ -177,29 +177,29 @@ TEMPLATE_TEST_CASE( SECTION("accept a valid vector with no elements") { auto bytes = test_format_specific::bytes_empty(); types::b_binary const binary{binary_sub_type::k_vector, bytes.size(), bytes.data()}; - vector::view view{binary}; - CHECK(view.empty()); - CHECK(view.size() == 0); - CHECK(view.byte_size() == 0); - CHECK_THROWS_WITH(view.at(0), Catch::Matchers::ContainsSubstring("BSON vector access out of range")); - CHECK_THROWS_WITH(view.byte_at(0), Catch::Matchers::ContainsSubstring("BSON vector access out of range")); + vector::accessor vec{binary}; + CHECK(vec.empty()); + CHECK(vec.size() == 0); + CHECK(vec.byte_size() == 0); + CHECK_THROWS_WITH(vec.at(0), Catch::Matchers::ContainsSubstring("BSON vector access out of range")); + CHECK_THROWS_WITH(vec.byte_at(0), Catch::Matchers::ContainsSubstring("BSON vector access out of range")); } SECTION("decode a valid vector with a single element") { auto bytes = test_format_specific::bytes_unit(); auto element = test_format_specific::element_unit(); types::b_binary const binary{binary_sub_type::k_vector, bytes.size(), bytes.data()}; - vector::view view{binary}; - CHECK_FALSE(view.empty()); - CHECK(view.size() == 1u); - CHECK(view.byte_size() == bytes.size() - 2u); - CHECK(view.at(0) == element); - CHECK(view[0] == element); - CHECK(view.byte_at(0) == bytes[2]); - CHECK(view.byte_at(bytes.size() - 3u) == bytes[bytes.size() - 1u]); - CHECK_THROWS_WITH(view.at(1), Catch::Matchers::ContainsSubstring("BSON vector access out of range")); + vector::accessor vec{binary}; + CHECK_FALSE(vec.empty()); + CHECK(vec.size() == 1u); + CHECK(vec.byte_size() == bytes.size() - 2u); + CHECK(vec.at(0) == element); + CHECK(vec[0] == element); + CHECK(vec.byte_at(0) == bytes[2]); + CHECK(vec.byte_at(bytes.size() - 3u) == bytes[bytes.size() - 1u]); + CHECK_THROWS_WITH(vec.at(1), Catch::Matchers::ContainsSubstring("BSON vector access out of range")); CHECK_THROWS_WITH( - view.byte_at(bytes.size() - 2u), Catch::Matchers::ContainsSubstring("BSON vector access out of range")); + vec.byte_at(bytes.size() - 2u), Catch::Matchers::ContainsSubstring("BSON vector access out of range")); } SECTION("reject binary data of the wrong sub_type") { @@ -208,7 +208,7 @@ TEMPLATE_TEST_CASE( binary_sub_type::k_binary, binary_sub_type::k_encrypted, binary_sub_type::k_uuid, binary_sub_type::k_user); types::b_binary const binary{invalid_type, bytes.size(), bytes.data()}; CHECK_THROWS_WITH( - vector::view(binary), Catch::Matchers::ContainsSubstring("invalid BSON vector")); + vector::accessor(binary), Catch::Matchers::ContainsSubstring("invalid BSON vector")); } SECTION("reject binary data that's too short to include a header") { @@ -217,7 +217,7 @@ TEMPLATE_TEST_CASE( REQUIRE(bytes.size() >= bytes_to_remove); types::b_binary const binary{binary_sub_type::k_vector, uint32_t(bytes.size() - bytes_to_remove), bytes.data()}; CHECK_THROWS_WITH( - vector::view(binary), Catch::Matchers::ContainsSubstring("invalid BSON vector")); + vector::accessor(binary), Catch::Matchers::ContainsSubstring("invalid BSON vector")); } SECTION("reject empty vectors with any modified header bits") { @@ -226,7 +226,7 @@ TEMPLATE_TEST_CASE( bytes[bit_index >> 3u] ^= std::uint8_t(1u << (bit_index & 7u)); types::b_binary const binary{binary_sub_type::k_vector, bytes.size(), bytes.data()}; CHECK_THROWS_WITH( - vector::view(binary), Catch::Matchers::ContainsSubstring("invalid BSON vector")); + vector::accessor(binary), Catch::Matchers::ContainsSubstring("invalid BSON vector")); } } @@ -239,19 +239,19 @@ TEMPLATE_TEST_CASE( types::b_binary const& binary = doc.view()["vector"].get_binary(); CHECK(binary.sub_type == binary_sub_type::k_vector); binary_eq_bytes(binary, expected_bytes); - vector::view validate_encoded{binary}; + vector::accessor validate_encoded{binary}; } SECTION("support algorithms and operators on element iterators") { using namespace builder::basic; bsoncxx::document::value doc = make_document(kvp("vector", [&](sub_binary sbin) { // Avoid multiples of 8, to cover nonzero packed_bit 'padding'. - auto view = sbin.allocate(TestType{}, 8007u); + auto vec = sbin.allocate(TestType{}, 8007u); iterator_operations( - view.begin(), view.end(), std::ptrdiff_t(view.size()), test_format_specific::element_unit()); + vec.begin(), vec.end(), std::ptrdiff_t(vec.size()), test_format_specific::element_unit()); })); types::b_binary const& binary = doc.view()["vector"].get_binary(); - vector::view validate_encoded{binary}; + vector::accessor validate_encoded{binary}; CHECK(binary.size > 1000u); } @@ -259,44 +259,44 @@ TEMPLATE_TEST_CASE( using namespace builder::basic; bsoncxx::document::value doc = make_document(kvp("vector", [&](sub_binary sbin) { // Choose a multiple of 8, to avoid the effects of masking unused bits. - auto view = sbin.allocate(TestType{}, 8000u); - iterator_operations(view.byte_begin(), view.byte_end(), std::ptrdiff_t(view.byte_size()), uint8_t(1)); + auto vec = sbin.allocate(TestType{}, 8000u); + iterator_operations(vec.byte_begin(), vec.byte_end(), std::ptrdiff_t(vec.byte_size()), uint8_t(1)); })); types::b_binary const& binary = doc.view()["vector"].get_binary(); - vector::view validate_encoded{binary}; + vector::accessor validate_encoded{binary}; CHECK(binary.size > 1000u); } SECTION("support assignment between referenced elements") { using namespace builder::basic; bsoncxx::document::value doc = make_document(kvp("vector", [&](sub_binary sbin) { - auto view = sbin.allocate(TestType{}, 2u); - view[0] = test_format_specific::element_unit(); - view[1] = value_type{0}; - CHECK(view.at(0) != view.at(1)); - CHECK_FALSE(view.at(0) == view.at(1)); - view[1] = view[0]; - CHECK(view.at(0) == view.at(1)); - CHECK_FALSE(view.at(0) != view.at(1)); + auto vec = sbin.allocate(TestType{}, 2u); + vec[0] = test_format_specific::element_unit(); + vec[1] = value_type{0}; + CHECK(vec.at(0) != vec.at(1)); + CHECK_FALSE(vec.at(0) == vec.at(1)); + vec[1] = vec[0]; + CHECK(vec.at(0) == vec.at(1)); + CHECK_FALSE(vec.at(0) != vec.at(1)); })); types::b_binary const& binary = doc.view()["vector"].get_binary(); - vector::view validate_encoded{binary}; + vector::accessor validate_encoded{binary}; } SECTION("support assignment between referenced bytes") { using namespace builder::basic; bsoncxx::document::value doc = make_document(kvp("vector", [&](sub_binary sbin) { - auto view = sbin.allocate(TestType{}, 16u); - std::fill(view.begin(), view.end(), test_format_specific::element_unit()); - *(view.end() - 2) = value_type{0}; - CHECK(view.byte_at(view.byte_size() - 2) != view.byte_at(view.byte_size() - 1)); - CHECK_FALSE(view.byte_at(view.byte_size() - 2) == view.byte_at(view.byte_size() - 1)); - view.byte_at(view.byte_size() - 2) = view.byte_at(view.byte_size() - 1); - CHECK(view.byte_at(view.byte_size() - 2) == view.byte_at(view.byte_size() - 1)); - CHECK_FALSE(view.byte_at(view.byte_size() - 2) != view.byte_at(view.byte_size() - 1)); + auto vec = sbin.allocate(TestType{}, 16u); + std::fill(vec.begin(), vec.end(), test_format_specific::element_unit()); + *(vec.end() - 2) = value_type{0}; + CHECK(vec.byte_at(vec.byte_size() - 2) != vec.byte_at(vec.byte_size() - 1)); + CHECK_FALSE(vec.byte_at(vec.byte_size() - 2) == vec.byte_at(vec.byte_size() - 1)); + vec.byte_at(vec.byte_size() - 2) = vec.byte_at(vec.byte_size() - 1); + CHECK(vec.byte_at(vec.byte_size() - 2) == vec.byte_at(vec.byte_size() - 1)); + CHECK_FALSE(vec.byte_at(vec.byte_size() - 2) != vec.byte_at(vec.byte_size() - 1)); })); types::b_binary const& binary = doc.view()["vector"].get_binary(); - vector::view validate_encoded{binary}; + vector::accessor validate_encoded{binary}; } SECTION("fail to allocate unrepresentably large vectors") { @@ -311,57 +311,57 @@ TEMPLATE_TEST_CASE( SECTION("support front and back element references") { using namespace builder::basic; bsoncxx::document::value doc = make_document(kvp("vector", [&](sub_binary sbin) { - auto view = sbin.allocate(TestType{}, 2u); - std::fill(view.begin(), view.end(), test_format_specific::element_unit()); - *(view.end() - 1) = value_type{0}; - CHECK(view.back() == value_type{0}); - CHECK(view.back() == view[view.size() - 1u]); - CHECK(view.front() != view.back()); - CHECK_FALSE(view.front() == view.back()); - view.front() = view.back(); - CHECK(view[0] == value_type{0}); - CHECK(view.front() == view.back()); - CHECK_FALSE(view.front() != view.back()); - CHECK(view[view.size() - 1u] == value_type{0}); - view.back() = test_format_specific::element_unit(); - CHECK(view[0] == value_type{0}); - CHECK(view[view.size() - 1u] != value_type{0}); - CHECK(view.front() != view.back()); - CHECK_FALSE(view.front() == view.back()); + auto vec = sbin.allocate(TestType{}, 2u); + std::fill(vec.begin(), vec.end(), test_format_specific::element_unit()); + *(vec.end() - 1) = value_type{0}; + CHECK(vec.back() == value_type{0}); + CHECK(vec.back() == vec[vec.size() - 1u]); + CHECK(vec.front() != vec.back()); + CHECK_FALSE(vec.front() == vec.back()); + vec.front() = vec.back(); + CHECK(vec[0] == value_type{0}); + CHECK(vec.front() == vec.back()); + CHECK_FALSE(vec.front() != vec.back()); + CHECK(vec[vec.size() - 1u] == value_type{0}); + vec.back() = test_format_specific::element_unit(); + CHECK(vec[0] == value_type{0}); + CHECK(vec[vec.size() - 1u] != value_type{0}); + CHECK(vec.front() != vec.back()); + CHECK_FALSE(vec.front() == vec.back()); })); types::b_binary const& binary = doc.view()["vector"].get_binary(); - vector::view validate_encoded{binary}; + vector::accessor validate_encoded{binary}; } SECTION("support front and back byte references") { using namespace builder::basic; bsoncxx::document::value doc = make_document(kvp("vector", [&](sub_binary sbin) { - auto view = sbin.allocate(TestType{}, 16u); - std::fill(view.begin(), view.end(), value_type{0}); - CHECK(view.front() == view.back()); - CHECK_FALSE(view.front() != view.back()); - CHECK(view.byte_front() == view.byte_back()); - CHECK_FALSE(view.byte_front() != view.byte_back()); - view.back() = test_format_specific::element_unit(); - CHECK(view.byte_front() != view.byte_back()); - CHECK_FALSE(view.byte_front() == view.byte_back()); - view.byte_front() = UINT8_C(0); - view.byte_back() = UINT8_C(0); - CHECK(view.byte_front() == view.byte_back()); - CHECK_FALSE(view.byte_front() != view.byte_back()); + auto vec = sbin.allocate(TestType{}, 16u); + std::fill(vec.begin(), vec.end(), value_type{0}); + CHECK(vec.front() == vec.back()); + CHECK_FALSE(vec.front() != vec.back()); + CHECK(vec.byte_front() == vec.byte_back()); + CHECK_FALSE(vec.byte_front() != vec.byte_back()); + vec.back() = test_format_specific::element_unit(); + CHECK(vec.byte_front() != vec.byte_back()); + CHECK_FALSE(vec.byte_front() == vec.byte_back()); + vec.byte_front() = UINT8_C(0); + vec.byte_back() = UINT8_C(0); + CHECK(vec.byte_front() == vec.byte_back()); + CHECK_FALSE(vec.byte_front() != vec.byte_back()); })); types::b_binary const& binary = doc.view()["vector"].get_binary(); - vector::view validate_encoded{binary}; + vector::accessor validate_encoded{binary}; } } -TEST_CASE("vector view float32", "[bsoncxx::vector::view]") { +TEST_CASE("vector accessor float32", "[bsoncxx::vector::accessor]") { SECTION("rejects binary data with an incorrect length") { static uint8_t const bytes[] = {0x27, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00}; auto invalid_length = GENERATE(0u, 1u, 3u, 4u, 5u, 7u, 8u, 9u); types::b_binary const binary{binary_sub_type::k_vector, uint32_t(invalid_length), bytes}; CHECK_THROWS_WITH( - vector::view(binary), + vector::accessor(binary), Catch::Matchers::ContainsSubstring("invalid BSON vector")); } @@ -371,7 +371,7 @@ TEST_CASE("vector view float32", "[bsoncxx::vector::view]") { format_specific::bytes_empty()); types::b_binary const binary{binary_sub_type::k_vector, bytes.size(), bytes.data()}; CHECK_THROWS_WITH( - vector::view(binary), + vector::accessor(binary), Catch::Matchers::ContainsSubstring("invalid BSON vector")); } @@ -379,36 +379,36 @@ TEST_CASE("vector view float32", "[bsoncxx::vector::view]") { static uint8_t const bytes[] = { 0x27, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x7F}; types::b_binary const binary{binary_sub_type::k_vector, sizeof bytes, bytes}; - vector::view view{binary}; - REQUIRE(view.size() == 3u); - CHECK(view[0] < 0.f); - CHECK(view[0] * 0.f != 0.f); - CHECK(view[1] == 0.f); - CHECK(view[2] > 0.f); - CHECK(view[2] * 0.f != 0.f); + vector::accessor vec{binary}; + REQUIRE(vec.size() == 3u); + CHECK(vec[0] < 0.f); + CHECK(vec[0] * 0.f != 0.f); + CHECK(vec[1] == 0.f); + CHECK(vec[2] > 0.f); + CHECK(vec[2] * 0.f != 0.f); } } -TEST_CASE("vector view int8_t", "[bsoncxx::vector::view]") { +TEST_CASE("vector accessor int8_t", "[bsoncxx::vector::accessor]") { SECTION("rejects binary data from other vector formats") { auto bytes = GENERATE( format_specific::bytes_empty(), format_specific::bytes_empty()); types::b_binary const binary{binary_sub_type::k_vector, bytes.size(), bytes.data()}; CHECK_THROWS_WITH( - vector::view(binary), + vector::accessor(binary), Catch::Matchers::ContainsSubstring("invalid BSON vector")); } } -TEST_CASE("vector view packed_bit", "[bsoncxx::vector::view]") { +TEST_CASE("vector accessor packed_bit", "[bsoncxx::vector::accessor]") { SECTION("rejects empty vectors with nonzero padding") { for (unsigned byte_value = 1u; byte_value <= UINT8_MAX; byte_value++) { auto bytes = format_specific::bytes_empty(); bytes[1] = uint8_t(byte_value); types::b_binary const binary{binary_sub_type::k_vector, bytes.size(), bytes.data()}; CHECK_THROWS_WITH( - vector::view(binary), + vector::accessor(binary), Catch::Matchers::ContainsSubstring("invalid BSON vector")); } } @@ -418,7 +418,7 @@ TEST_CASE("vector view packed_bit", "[bsoncxx::vector::view]") { uint8_t const bytes[] = {0x10, uint8_t(byte_value), 0x00}; types::b_binary const binary{binary_sub_type::k_vector, sizeof bytes, bytes}; CHECK_THROWS_WITH( - vector::view(binary), + vector::accessor(binary), Catch::Matchers::ContainsSubstring("invalid BSON vector")); } } @@ -428,40 +428,40 @@ TEST_CASE("vector view packed_bit", "[bsoncxx::vector::view]") { uint8_t bytes[] = {0x10, uint8_t(byte_value), 0xff}; types::b_binary const binary{binary_sub_type::k_vector, sizeof bytes, bytes}; CHECK_THROWS_WITH( - vector::view(binary), + vector::accessor(binary), Catch::Matchers::ContainsSubstring("invalid BSON vector")); // Succeeds when unused bits are then zeroed bytes[2] = 0; - vector::view view{binary}; - CHECK(view.size() == 8u - byte_value); + vector::accessor vec{binary}; + CHECK(vec.size() == 8u - byte_value); } } SECTION("masks writes to unused portions of the last byte") { using namespace builder::basic; bsoncxx::document::value doc = make_document(kvp("vector", [&](sub_binary sbin) { - auto view = sbin.allocate(vector::formats::f_packed_bit{}, 9u); - std::fill(view.begin(), view.end(), true); - CHECK(view.byte_size() == 2u); - CHECK(view.byte_at(0) == 0xff); - CHECK(view.byte_at(1) == 0x80); - view.byte_at(1) = 0x7f; - CHECK(view.at(7) == true); - CHECK(view.at(8) == false); - CHECK(view.byte_at(1) == 0x00); - view.byte_at(1) = 0xff; - view.byte_at(0) = 0xaa; - CHECK(view.at(0) == true); - CHECK(view.at(1) == false); - CHECK(view.at(2) == true); - CHECK(view.at(3) == false); - CHECK(view.at(4) == true); - CHECK(view.at(5) == false); - CHECK(view.at(6) == true); - CHECK(view.at(7) == false); - CHECK(view.at(8) == true); - CHECK(view.byte_at(0) == 0xaa); - CHECK(view.byte_at(1) == 0x80); + auto vec = sbin.allocate(vector::formats::f_packed_bit{}, 9u); + std::fill(vec.begin(), vec.end(), true); + CHECK(vec.byte_size() == 2u); + CHECK(vec.byte_at(0) == 0xff); + CHECK(vec.byte_at(1) == 0x80); + vec.byte_at(1) = 0x7f; + CHECK(vec.at(7) == true); + CHECK(vec.at(8) == false); + CHECK(vec.byte_at(1) == 0x00); + vec.byte_at(1) = 0xff; + vec.byte_at(0) = 0xaa; + CHECK(vec.at(0) == true); + CHECK(vec.at(1) == false); + CHECK(vec.at(2) == true); + CHECK(vec.at(3) == false); + CHECK(vec.at(4) == true); + CHECK(vec.at(5) == false); + CHECK(vec.at(6) == true); + CHECK(vec.at(7) == false); + CHECK(vec.at(8) == true); + CHECK(vec.byte_at(0) == 0xaa); + CHECK(vec.byte_at(1) == 0x80); })); types::b_binary const& binary = doc.view()["vector"].get_binary(); CHECK(binary.sub_type == binary_sub_type::k_vector); @@ -473,8 +473,8 @@ TEST_CASE("vector view packed_bit", "[bsoncxx::vector::view]") { for (unsigned byte_value = 0; byte_value <= 7; byte_value++) { uint8_t const bytes[] = {0x10, uint8_t(byte_value), 0x00}; types::b_binary const binary{binary_sub_type::k_vector, sizeof bytes, bytes}; - vector::view view{binary}; - CHECK(view.size() == 8 - byte_value); + vector::accessor vec{binary}; + CHECK(vec.size() == 8 - byte_value); } } @@ -484,7 +484,7 @@ TEST_CASE("vector view packed_bit", "[bsoncxx::vector::view]") { format_specific::bytes_empty()); types::b_binary const binary{binary_sub_type::k_vector, bytes.size(), bytes.data()}; CHECK_THROWS_WITH( - vector::view(binary), + vector::accessor(binary), Catch::Matchers::ContainsSubstring("invalid BSON vector")); } @@ -492,31 +492,31 @@ TEST_CASE("vector view packed_bit", "[bsoncxx::vector::view]") { for (std::size_t element_count = 0; element_count < 1000; element_count++) { using namespace builder::basic; bsoncxx::document::value doc = make_document(kvp("vector", [&](sub_binary sbin) { - auto view = sbin.allocate(vector::formats::f_packed_bit{}, element_count); - REQUIRE(view.size() == element_count); - REQUIRE(view.byte_size() == (element_count + 7u) / 8); - std::fill(view.byte_begin(), view.byte_end(), UINT8_C(0xFF)); - CHECK(view.empty() == (element_count == 0)); - if (!view.empty()) { - std::for_each(view.byte_begin(), view.byte_end() - 1, [&](std::uint8_t value) { + auto vec = sbin.allocate(vector::formats::f_packed_bit{}, element_count); + REQUIRE(vec.size() == element_count); + REQUIRE(vec.byte_size() == (element_count + 7u) / 8); + std::fill(vec.byte_begin(), vec.byte_end(), UINT8_C(0xFF)); + CHECK(vec.empty() == (element_count == 0)); + if (!vec.empty()) { + std::for_each(vec.byte_begin(), vec.byte_end() - 1, [&](std::uint8_t value) { CHECK(value == UINT8_C(0xFF)); }); - std::size_t padding = view.byte_size() * std::size_t(8) - view.size(); - CHECK(view.byte_back() == std::uint8_t(0xFF << padding)); + std::size_t padding = vec.byte_size() * std::size_t(8) - vec.size(); + CHECK(vec.byte_back() == std::uint8_t(0xFF << padding)); } })); types::b_binary const& binary = doc.view()["vector"].get_binary(); CHECK(binary.sub_type == binary_sub_type::k_vector); - vector::view view{binary}; - REQUIRE(view.size() == element_count); - REQUIRE(view.byte_size() == (element_count + 7u) / 8); - CHECK(view.empty() == (element_count == 0u)); - if (!view.empty()) { + vector::accessor vec{binary}; + REQUIRE(vec.size() == element_count); + REQUIRE(vec.byte_size() == (element_count + 7u) / 8); + CHECK(vec.empty() == (element_count == 0u)); + if (!vec.empty()) { std::for_each( - view.byte_begin(), view.byte_end() - 1, [&](std::uint8_t value) { CHECK(value == UINT8_C(0xFF)); }); - std::size_t padding = view.byte_size() * std::size_t(8) - view.size(); + vec.byte_begin(), vec.byte_end() - 1, [&](std::uint8_t value) { CHECK(value == UINT8_C(0xFF)); }); + std::size_t padding = vec.byte_size() * std::size_t(8) - vec.size(); CHECK(padding == binary.bytes[1]); - CHECK(view.byte_back() == std::uint8_t(0xFF << padding)); + CHECK(vec.byte_back() == std::uint8_t(0xFF << padding)); } } } From 61bfb595d975edb7f5097c6f6415dac8a1db7e57 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Tue, 25 Mar 2025 18:07:19 -0700 Subject: [PATCH 40/83] Refactor exported symbols out of 'detail' namespace --- .../bsoncxx/builder/basic/sub_binary.hpp | 15 ++-- .../v_noabi/bsoncxx/vector/accessor.hpp | 6 +- .../v_noabi/bsoncxx/vector/detail-fwd.hpp | 3 + .../bsoncxx/v_noabi/bsoncxx/vector/detail.hpp | 56 ++++++-------- .../v_noabi/bsoncxx/vector/formats.hpp | 25 ++++++- .../lib/bsoncxx/v_noabi/bsoncxx/vector.cpp | 73 +++++++++---------- 6 files changed, 92 insertions(+), 86 deletions(-) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/sub_binary.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/sub_binary.hpp index 6863a63a31..790ea86556 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/sub_binary.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/sub_binary.hpp @@ -17,12 +17,12 @@ #include #include +#include +#include +#include #include #include -#include -#include -#include #include @@ -63,13 +63,10 @@ class sub_binary { template ::value_type> vector::accessor allocate(Format fmt, std::size_t element_count) { (void)fmt; - using format_traits = typename vector::detail::format_traits; - std::uint32_t binary_data_length = format_traits::length_for_append(element_count); + std::uint32_t binary_data_length = Format::length_for_append(element_count); std::uint8_t* binary_data = allocate(binary_sub_type::k_vector, binary_data_length); - return { - {binary_data, - binary_data_length, - format_traits::write_frame(binary_data, binary_data_length, element_count)}}; + Format::write_frame(binary_data, binary_data_length, element_count); + return {vector::detail::accessor_data(binary_data, binary_data_length)}; } private: diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/accessor.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/accessor.hpp index 82bc1e1982..50898b8c04 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/accessor.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/accessor.hpp @@ -96,12 +96,12 @@ class accessor { /// /// The Binary data is validated as a Vector of the templated Format. On success, an accessor is created which /// references the same data as the bsoncxx::v_noabi::types::b_binary pointer. - accessor(types::b_binary const& binary) : _data(format_traits::const_validate(binary)) {} + accessor(types::b_binary const& binary) : _data((format::validate(binary), binary)) {} /// @brief Count the bytes of element data /// @return Size of the vector data, not including any headers constexpr byte_count_type byte_size() const noexcept { - return _data.size - byte_count_type(sizeof(detail::header::bytes)); + return _data.size - byte_count_type(detail::header_size); } /// @brief Count the number of elements @@ -113,7 +113,7 @@ class accessor { /// @brief Obtain an iterator pointing to the beginning of the vector /// @return A per-element random access iterator, pointing at the first element if one exists constexpr iterator begin() const noexcept { - return iterator(_data.bytes + sizeof(detail::header::bytes)); + return iterator(_data.bytes + detail::header_size); } /// @brief Obtain an iterator pointing just past the end of the vector diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/detail-fwd.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/detail-fwd.hpp index 57cf94ca4b..299115c1d3 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/detail-fwd.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/detail-fwd.hpp @@ -24,6 +24,9 @@ namespace detail { template struct format_traits; +template +struct accessor_data; + } // namespace detail } // namespace vector } // namespace v_noabi diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/detail.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/detail.hpp index 5281778a75..e6c1cf7409 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/detail.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/detail.hpp @@ -14,7 +14,9 @@ #pragma once +#include #include +#include #include #include @@ -28,13 +30,14 @@ namespace v_noabi { namespace vector { namespace detail { -/// @brief Implementation detail. A copy of the validated BSON Binary Vector header, included in each accessor. -struct header { - std::uint8_t bytes[2]; -}; +// Implementation detail. Size of the BSON Binary Vector header, in bytes. +constexpr std::size_t header_size = 2; + +// Implementation detail. Type for local copies of the vector header. +typedef std::array header; -/// @brief Implementation detail. Common data for each accessor type. -/// @tparam Format One of the @ref bsoncxx::v_noabi::vector::formats types, optionally const. +// @brief Implementation detail. Common data for each accessor type. +// @tparam Format One of the @ref bsoncxx::v_noabi::vector::formats types, optionally const. template struct accessor_data { using byte_type = typename std::conditional::value, std::uint8_t const, std::uint8_t>::type; @@ -43,9 +46,15 @@ struct accessor_data { byte_type* bytes; byte_count_type size; header header_copy; + + accessor_data(types::b_binary const& binary) : accessor_data(binary.bytes, binary.size) {} + + accessor_data(byte_type* bytes, byte_count_type size) : bytes(bytes), size(size) { + std::memcpy(header_copy.data(), bytes, header_size); + } }; -/// @brief Implementation detail. Default format traits. +// @brief Implementation detail. Default format traits. struct format_traits_base { using element_count_type = std::size_t; @@ -59,12 +68,12 @@ struct format_traits_base { using const_byte_iterator = std::uint8_t const*; }; -/// @brief Implementation detail. Format traits, specialized by format. -/// @tparam Format One of the @ref bsoncxx::v_noabi::vector::formats types, without qualifiers. +// @brief Implementation detail. Format traits, specialized by format. +// @tparam Format One of the @ref bsoncxx::v_noabi::vector::formats types, without qualifiers. template struct format_traits; -/// @brief Implementation detail. Format traits for bsoncxx::v_noabi::vector::formats::f_int8. +// @brief Implementation detail. Format traits for bsoncxx::v_noabi::vector::formats::f_int8. template <> struct format_traits : format_traits_base { using value_type = std::int8_t; @@ -74,13 +83,8 @@ struct format_traits : format_traits_base { using iterator = std::int8_t*; using const_iterator = std::int8_t const*; - static BSONCXX_ABI_EXPORT_CDECL(std::uint32_t) length_for_append(std::size_t element_count); - static BSONCXX_ABI_EXPORT_CDECL(header) - write_frame(std::uint8_t* binary_data, std::uint32_t binary_data_length, std::size_t element_count); - static BSONCXX_ABI_EXPORT_CDECL(accessor_data) const_validate(types::b_binary const& binary); - static constexpr std::size_t element_count(std::uint32_t binary_data_length, header) noexcept { - return binary_data_length - sizeof(header::bytes); + return binary_data_length - header_size; } static byte_iterator make_byte_iterator(iterator element, iterator) noexcept { @@ -92,7 +96,7 @@ struct format_traits : format_traits_base { } }; -/// @brief Implementation detail. Format traits for bsoncxx::v_noabi::vector::formats::f_float32. +// @brief Implementation detail. Format traits for bsoncxx::v_noabi::vector::formats::f_float32. template <> struct format_traits : format_traits_base { using value_type = float; @@ -102,14 +106,8 @@ struct format_traits : format_traits_base { using iterator = elements::float32*; using const_iterator = elements::float32 const*; - static BSONCXX_ABI_EXPORT_CDECL(std::uint32_t) length_for_append(std::size_t element_count); - static BSONCXX_ABI_EXPORT_CDECL(header) - write_frame(std::uint8_t* binary_data, std::uint32_t binary_data_length, std::size_t element_count); - static BSONCXX_ABI_EXPORT_CDECL(accessor_data) const_validate( - types::b_binary const& binary); - static constexpr std::size_t element_count(std::uint32_t binary_data_length, header) noexcept { - return (binary_data_length - sizeof(header::bytes)) / sizeof(float); + return (binary_data_length - header_size) / sizeof(float); } static byte_iterator make_byte_iterator(iterator element, iterator) noexcept { @@ -121,7 +119,7 @@ struct format_traits : format_traits_base { } }; -/// @brief Implementation detail. Format traits for bsoncxx::v_noabi::vector::formats::f_packed_bit. +// @brief Implementation detail. Format traits for bsoncxx::v_noabi::vector::formats::f_packed_bit. template <> struct format_traits : format_traits_base { using value_type = bool; @@ -139,14 +137,8 @@ struct format_traits : format_traits_base { using byte_difference_type = byte_iterator::difference_type; using element_difference_type = iterator::difference_type; - static BSONCXX_ABI_EXPORT_CDECL(std::uint32_t) length_for_append(std::size_t element_count); - static BSONCXX_ABI_EXPORT_CDECL(header) - write_frame(std::uint8_t* binary_data, std::uint32_t binary_data_length, std::size_t element_count); - static BSONCXX_ABI_EXPORT_CDECL(accessor_data) const_validate( - types::b_binary const& binary); - static constexpr std::size_t element_count(std::uint32_t binary_data_length, header hdr) noexcept { - return std::size_t(binary_data_length - sizeof(hdr.bytes)) * std::size_t(8u) - std::size_t(hdr.bytes[1] & 7u); + return std::size_t(binary_data_length - header_size) * std::size_t(8u) - std::size_t(hdr[1] & 7u); } static byte_iterator make_byte_iterator(iterator element, iterator element_end) noexcept { diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/formats.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/formats.hpp index 073d867bc5..09315defca 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/formats.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/formats.hpp @@ -14,6 +14,10 @@ #pragma once +#include + +#include +#include #include #include @@ -24,13 +28,28 @@ namespace vector { namespace formats { /// @brief Vector format for 32-bit floating point elements, packed least significant byte first. -struct f_float32 {}; +struct f_float32 { + static BSONCXX_ABI_EXPORT_CDECL(std::uint32_t) length_for_append(std::size_t element_count); + static BSONCXX_ABI_EXPORT_CDECL(void) + write_frame(std::uint8_t* binary_data, std::uint32_t binary_data_length, std::size_t element_count); + static BSONCXX_ABI_EXPORT_CDECL(void) validate(types::b_binary const& binary); +}; /// @brief Vector format for signed 8-bit integer elements. -struct f_int8 {}; +struct f_int8 { + static BSONCXX_ABI_EXPORT_CDECL(std::uint32_t) length_for_append(std::size_t element_count); + static BSONCXX_ABI_EXPORT_CDECL(void) + write_frame(std::uint8_t* binary_data, std::uint32_t binary_data_length, std::size_t element_count); + static BSONCXX_ABI_EXPORT_CDECL(void) validate(types::b_binary const& binary); +}; /// @brief Vector format for single bit elements, packed most significant bit first. -struct f_packed_bit {}; +struct f_packed_bit { + static BSONCXX_ABI_EXPORT_CDECL(std::uint32_t) length_for_append(std::size_t element_count); + static BSONCXX_ABI_EXPORT_CDECL(void) + write_frame(std::uint8_t* binary_data, std::uint32_t binary_data_length, std::size_t element_count); + static BSONCXX_ABI_EXPORT_CDECL(void) validate(types::b_binary const& binary); +}; } // namespace formats } // namespace vector diff --git a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/vector.cpp b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/vector.cpp index ab8f2c19e4..b55c2c926d 100644 --- a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/vector.cpp +++ b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/vector.cpp @@ -38,83 +38,78 @@ enum element_size : std::uint8_t { }; static header make_header(element_type element_type, element_size element_size, std::uint8_t padding) { - return header{{(std::uint8_t)((std::uint8_t)element_type << 4 | (std::uint8_t)element_size), padding}}; + return {{(std::uint8_t)((std::uint8_t)element_type << 4 | (std::uint8_t)element_size), padding}}; } -static header copy_header(std::uint8_t const* bytes) { - header result; - memcpy(&result.bytes, bytes, sizeof result.bytes); - return result; +static void write_header(std::uint8_t* binary_data, header hdr) { + std::memcpy(binary_data, hdr.data(), header_size); } +} // namespace detail + +namespace formats { + template static std::uint32_t libbson_length_for_append(std::size_t element_count, Impl func) { std::uint32_t result = func(element_count); - if (result < sizeof(header::bytes)) { - throw bsoncxx::v_noabi::exception{error_code::k_vector_too_large}; + if (result < BSON_VECTOR_HEADER_LEN) { + throw exception{error_code::k_vector_too_large}; } return result; } -std::uint32_t format_traits::length_for_append(std::size_t element_count) { +std::uint32_t f_int8::length_for_append(std::size_t element_count) { return libbson_length_for_append(element_count, bson_vector_int8_binary_data_length); } -std::uint32_t format_traits::length_for_append(std::size_t element_count) { +std::uint32_t f_float32::length_for_append(std::size_t element_count) { return libbson_length_for_append(element_count, bson_vector_float32_binary_data_length); } -std::uint32_t format_traits::length_for_append(std::size_t element_count) { +std::uint32_t f_packed_bit::length_for_append(std::size_t element_count) { return libbson_length_for_append(element_count, bson_vector_packed_bit_binary_data_length); } -header format_traits::write_frame(std::uint8_t* binary_data, std::uint32_t, std::size_t) { - header hdr = make_header(element_type::signed_integer, element_size::bits_8, 0); - memcpy(binary_data, &hdr, sizeof hdr); - return hdr; +void f_int8::write_frame(std::uint8_t* binary_data, std::uint32_t, std::size_t) { + detail::write_header( + binary_data, detail::make_header(detail::element_type::signed_integer, detail::element_size::bits_8, 0)); } -header format_traits::write_frame(std::uint8_t* binary_data, std::uint32_t, std::size_t) { - header hdr = make_header(element_type::floating_point, element_size::bits_32, 0); - memcpy(binary_data, &hdr, sizeof hdr); - return hdr; +void f_float32::write_frame(std::uint8_t* binary_data, std::uint32_t, std::size_t) { + detail::write_header( + binary_data, detail::make_header(detail::element_type::floating_point, detail::element_size::bits_32, 0)); } -header format_traits::write_frame( - std::uint8_t* binary_data, - std::uint32_t binary_data_length, - std::size_t element_count) { - header hdr = make_header( - element_type::unsigned_integer, element_size::bits_1, std::uint8_t(std::size_t(7u) & -element_count)); +void f_packed_bit::write_frame(std::uint8_t* binary_data, std::uint32_t binary_data_length, std::size_t element_count) { binary_data[binary_data_length - 1] = UINT8_C(0); - memcpy(binary_data, &hdr, sizeof hdr); - return hdr; + detail::write_header( + binary_data, + detail::make_header( + detail::element_type::unsigned_integer, + detail::element_size::bits_1, + std::uint8_t(std::size_t(7u) & -element_count))); } -template -static accessor_data libbson_const_validate(bsoncxx::v_noabi::types::b_binary const& binary, Impl func) { +template +static void libbson_validate(types::b_binary const& binary, Impl func) { if (binary.sub_type != binary_sub_type::k_vector || !func(NULL, binary.bytes, binary.size)) { throw bsoncxx::v_noabi::exception{error_code::k_invalid_vector}; } - return {binary.bytes, binary.size, copy_header(binary.bytes)}; } -accessor_data format_traits::const_validate( - bsoncxx::v_noabi::types::b_binary const& binary) { - return libbson_const_validate(binary, bson_vector_int8_const_view_init); +void formats::f_int8::validate(types::b_binary const& binary) { + return libbson_validate(binary, bson_vector_int8_const_view_init); } -accessor_data format_traits::const_validate( - bsoncxx::v_noabi::types::b_binary const& binary) { - return libbson_const_validate(binary, bson_vector_float32_const_view_init); +void formats::f_float32::validate(types::b_binary const& binary) { + return libbson_validate(binary, bson_vector_float32_const_view_init); } -accessor_data format_traits::const_validate( - bsoncxx::v_noabi::types::b_binary const& binary) { - return libbson_const_validate(binary, bson_vector_packed_bit_const_view_init); +void formats::f_packed_bit::validate(types::b_binary const& binary) { + return libbson_validate(binary, bson_vector_packed_bit_const_view_init); } -} // namespace detail +} // namespace formats } // namespace vector } // namespace v_noabi } // namespace bsoncxx From c52a7f1ee6a559d5b6302709b59cd46444bcce01 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Tue, 25 Mar 2025 18:19:48 -0700 Subject: [PATCH 41/83] Fix doc comments for vector elements/iterators namespaces --- src/bsoncxx/include/bsoncxx/docs/top.hpp | 10 ---------- src/bsoncxx/include/bsoncxx/docs/v_noabi.hpp | 10 +++++----- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/src/bsoncxx/include/bsoncxx/docs/top.hpp b/src/bsoncxx/include/bsoncxx/docs/top.hpp index 7bd91cd35e..fa23e0d442 100644 --- a/src/bsoncxx/include/bsoncxx/docs/top.hpp +++ b/src/bsoncxx/include/bsoncxx/docs/top.hpp @@ -98,13 +98,3 @@ /// @namespace bsoncxx::vector::formats /// Declares supported BSON Binary Vector formats. /// - -/// -/// @namespace bsoncxx::vector::elements -/// Declares element accessor types for BSON Binary Vector. -/// - -/// -/// @namespace bsoncxx::vector::iterators -/// Declares iterator types for BSON Binary Vector. -/// diff --git a/src/bsoncxx/include/bsoncxx/docs/v_noabi.hpp b/src/bsoncxx/include/bsoncxx/docs/v_noabi.hpp index f1ccaf1a9b..0262be0c8d 100644 --- a/src/bsoncxx/include/bsoncxx/docs/v_noabi.hpp +++ b/src/bsoncxx/include/bsoncxx/docs/v_noabi.hpp @@ -160,16 +160,16 @@ /// /// -/// @namespace bsoncxx::v_noabi::vector::iterators -/// @copydoc bsoncxx::vector::iterators +/// @namespace bsoncxx::v_noabi::vector::formats +/// @copydoc bsoncxx::vector::formats /// /// /// @namespace bsoncxx::v_noabi::vector::elements -/// @copydoc bsoncxx::vector::elements +/// Declares element accessor types for BSON Binary Vector. /// /// -/// @namespace bsoncxx::v_noabi::vector::formats -/// @copydoc bsoncxx::vector::formats +/// @namespace bsoncxx::v_noabi::vector::iterators +/// Declares iterator types for BSON Binary Vector. /// From 9737bf0a38c9d36b35d98ce7e6c2ea18f81eb98d Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Tue, 25 Mar 2025 18:22:02 -0700 Subject: [PATCH 42/83] Can't rely on constexpr std::array operator[] --- src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/detail.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/detail.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/detail.hpp index e6c1cf7409..3a31ad0b37 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/detail.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/detail.hpp @@ -137,7 +137,7 @@ struct format_traits : format_traits_base { using byte_difference_type = byte_iterator::difference_type; using element_difference_type = iterator::difference_type; - static constexpr std::size_t element_count(std::uint32_t binary_data_length, header hdr) noexcept { + static std::size_t element_count(std::uint32_t binary_data_length, header hdr) noexcept { return std::size_t(binary_data_length - header_size) * std::size_t(8u) - std::size_t(hdr[1] & 7u); } From 53dc7086f928384dc94da4945f994cbaa370dafb Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Tue, 25 Mar 2025 19:08:03 -0700 Subject: [PATCH 43/83] Move internal parts of format exports to detail namespace --- .../lib/bsoncxx/v_noabi/bsoncxx/vector.cpp | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/vector.cpp b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/vector.cpp index b55c2c926d..fa1dae7110 100644 --- a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/vector.cpp +++ b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/vector.cpp @@ -41,14 +41,10 @@ static header make_header(element_type element_type, element_size element_size, return {{(std::uint8_t)((std::uint8_t)element_type << 4 | (std::uint8_t)element_size), padding}}; } -static void write_header(std::uint8_t* binary_data, header hdr) { +static void write_header(std::uint8_t* binary_data, header const& hdr) { std::memcpy(binary_data, hdr.data(), header_size); } -} // namespace detail - -namespace formats { - template static std::uint32_t libbson_length_for_append(std::size_t element_count, Impl func) { std::uint32_t result = func(element_count); @@ -58,16 +54,27 @@ static std::uint32_t libbson_length_for_append(std::size_t element_count, Impl f return result; } +template +static void libbson_validate(types::b_binary const& binary, Impl func) { + if (binary.sub_type != binary_sub_type::k_vector || !func(NULL, binary.bytes, binary.size)) { + throw exception{error_code::k_invalid_vector}; + } +} + +} // namespace detail + +namespace formats { + std::uint32_t f_int8::length_for_append(std::size_t element_count) { - return libbson_length_for_append(element_count, bson_vector_int8_binary_data_length); + return detail::libbson_length_for_append(element_count, bson_vector_int8_binary_data_length); } std::uint32_t f_float32::length_for_append(std::size_t element_count) { - return libbson_length_for_append(element_count, bson_vector_float32_binary_data_length); + return detail::libbson_length_for_append(element_count, bson_vector_float32_binary_data_length); } std::uint32_t f_packed_bit::length_for_append(std::size_t element_count) { - return libbson_length_for_append(element_count, bson_vector_packed_bit_binary_data_length); + return detail::libbson_length_for_append(element_count, bson_vector_packed_bit_binary_data_length); } void f_int8::write_frame(std::uint8_t* binary_data, std::uint32_t, std::size_t) { @@ -90,23 +97,16 @@ void f_packed_bit::write_frame(std::uint8_t* binary_data, std::uint32_t binary_d std::uint8_t(std::size_t(7u) & -element_count))); } -template -static void libbson_validate(types::b_binary const& binary, Impl func) { - if (binary.sub_type != binary_sub_type::k_vector || !func(NULL, binary.bytes, binary.size)) { - throw bsoncxx::v_noabi::exception{error_code::k_invalid_vector}; - } -} - void formats::f_int8::validate(types::b_binary const& binary) { - return libbson_validate(binary, bson_vector_int8_const_view_init); + return detail::libbson_validate(binary, bson_vector_int8_const_view_init); } void formats::f_float32::validate(types::b_binary const& binary) { - return libbson_validate(binary, bson_vector_float32_const_view_init); + return detail::libbson_validate(binary, bson_vector_float32_const_view_init); } void formats::f_packed_bit::validate(types::b_binary const& binary) { - return libbson_validate(binary, bson_vector_packed_bit_const_view_init); + return detail::libbson_validate(binary, bson_vector_packed_bit_const_view_init); } } // namespace formats From 6b9cd01e9cddf358ee8c8db230408edc3614124b Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Tue, 25 Mar 2025 19:10:54 -0700 Subject: [PATCH 44/83] Update vector fwd headers --- src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/fwd.hpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/fwd.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/fwd.hpp index 37226857a0..0cdf7fd084 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/fwd.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/fwd.hpp @@ -46,8 +46,11 @@ #include #include #include +#include +#include +#include #include -#include +#include #include /// From 8b61e632fa8f0b11078b4c15b3a9d858060ea860 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Tue, 25 Mar 2025 19:34:37 -0700 Subject: [PATCH 45/83] Remove extra includes --- .../bsoncxx/v_noabi/bsoncxx/vector/iterators-fwd.hpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/iterators-fwd.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/iterators-fwd.hpp index 5f0c7dfa04..928c32a33b 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/iterators-fwd.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/iterators-fwd.hpp @@ -14,12 +14,6 @@ #pragma once -#include -#include - -#include -#include - #include namespace bsoncxx { From 799c897af7949e2de821ee406310a29f6bfd4c65 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Tue, 25 Mar 2025 19:51:45 -0700 Subject: [PATCH 46/83] Add core::open_binary for symmetry --- .../bsoncxx/v_noabi/bsoncxx/builder/basic/impl.hpp | 1 + .../include/bsoncxx/v_noabi/bsoncxx/builder/core.hpp | 9 +++++++++ src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/builder/core.cpp | 5 +++++ 3 files changed, 15 insertions(+) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/impl.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/impl.hpp index cc7c14efed..bcc4457fe5 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/impl.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/impl.hpp @@ -43,6 +43,7 @@ detail::requires_t> generic_append(core template detail::requires_t> generic_append(core* core, T&& func) { + core->open_binary(); detail::invoke(std::forward(func), sub_binary(core)); core->close_binary(); } diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/core.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/core.hpp index d0eb406dee..fbb0a4f22c 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/core.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/core.hpp @@ -707,6 +707,15 @@ class core { /// BSONCXX_ABI_EXPORT_CDECL(void) clear(); + /// + /// Opens a sub-binary within this BSON datum. + /// + /// @return + /// A reference to the object on which this member function is being called. This facilitates + /// method chaining. + /// + BSONCXX_ABI_EXPORT_CDECL(core&) open_binary(); + /// /// Closes the current sub-binary within this BSON datum. /// diff --git a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/builder/core.cpp b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/builder/core.cpp index c00231dfcc..3ecacc30d8 100644 --- a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/builder/core.cpp +++ b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/builder/core.cpp @@ -638,6 +638,11 @@ core& core::open_array() { return *this; } +core& core::open_binary() { + // No effect currently. (Here for symmetry and possibly extensibility) + return *this; +} + core& core::concatenate(bsoncxx::v_noabi::document::view const& view) { if (_impl->is_array()) { bson_iter_t iter; From a581e0a227aed29fdd6f6367c7014975964df8e7 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Tue, 25 Mar 2025 21:04:53 -0700 Subject: [PATCH 47/83] Fix duplicate forward declaration --- .../include/bsoncxx/v_noabi/bsoncxx/vector/iterators-fwd.hpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/iterators-fwd.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/iterators-fwd.hpp index 928c32a33b..7647911523 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/iterators-fwd.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/iterators-fwd.hpp @@ -21,9 +21,6 @@ namespace v_noabi { namespace vector { namespace iterators { -template -class packed_bit_byte; - template class packed_bit_element; From da065890663eb67db32dfa71e2b7320c5e61dd90 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Tue, 25 Mar 2025 21:10:46 -0700 Subject: [PATCH 48/83] Add include for completeness --- src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/vector.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/vector.cpp b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/vector.cpp index fa1dae7110..7cab540f95 100644 --- a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/vector.cpp +++ b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/vector.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include From 3dfc9f146055d20fbdaab5bb1223949318aeb03a Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Tue, 25 Mar 2025 21:19:33 -0700 Subject: [PATCH 49/83] Fix typo in test name --- src/bsoncxx/test/vector.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bsoncxx/test/vector.cpp b/src/bsoncxx/test/vector.cpp index 93b5216a38..9e34248857 100644 --- a/src/bsoncxx/test/vector.cpp +++ b/src/bsoncxx/test/vector.cpp @@ -413,7 +413,7 @@ TEST_CASE("vector accessor packed_bit", "[bsoncxx::vector::accessor]") { } } - SECTION("rejects nonempty vectors with bits set in header padding byte") { + SECTION("rejects nonempty vectors with reserved bits set in header padding byte") { for (unsigned byte_value = 8u; byte_value <= UINT8_MAX; byte_value++) { uint8_t const bytes[] = {0x10, uint8_t(byte_value), 0x00}; types::b_binary const binary{binary_sub_type::k_vector, sizeof bytes, bytes}; From 9a670cfe0f189d33b67a8c8d948a80145e600d79 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Tue, 25 Mar 2025 21:53:17 -0700 Subject: [PATCH 50/83] Comment about accessor_data constructor assumptions --- src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/detail.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/detail.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/detail.hpp index 3a31ad0b37..175029ed5f 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/detail.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/detail.hpp @@ -47,8 +47,10 @@ struct accessor_data { byte_count_type size; header header_copy; + // Construct accessor_data around a b_binary that has already had its subtype and size validated. accessor_data(types::b_binary const& binary) : accessor_data(binary.bytes, binary.size) {} + // Construct accessor_data around binary data that has already been validated, and capture a header copy. accessor_data(byte_type* bytes, byte_count_type size) : bytes(bytes), size(size) { std::memcpy(header_copy.data(), bytes, header_size); } From 4ca943191a17d45f3186af6d5a00648fe142c86a Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Wed, 26 Mar 2025 13:58:39 -0700 Subject: [PATCH 51/83] Document types in vector::accessor --- .../v_noabi/bsoncxx/vector/accessor.hpp | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/accessor.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/accessor.hpp index 50898b8c04..6ee01e7b70 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/accessor.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/accessor.hpp @@ -52,39 +52,84 @@ class accessor { using format_traits = typename detail::format_traits::type>; public: + /// The type from bsoncxx::v_noabi::vector::formats representing this vector's layout and element type using format = Format; + /// Const qualified version of @ref value_type using const_value_type = typename format_traits::value_type const; + + /// A type suitable for holding element values. + /// + /// For example: std::int8_t, float, bool using value_type = typename std::conditional< std::is_const::value, typename format_traits::value_type const, typename format_traits::value_type>::type; + /// Type for referencing const-qualified vector elements in-place using const_reference = typename format_traits::const_reference; + + /// Type for referencing vector elements in-place + /// + /// For example: std::int8_t&, bsoncxx::v_noabi::vector::elements::float32&, bsoncxx::v_noabi::vector::elements::packed_bit_element using reference = typename std::conditional< std::is_const::value, typename format_traits::const_reference, typename format_traits::reference>::type; + /// Iterator for const-qualified vector elements using const_iterator = typename format_traits::const_iterator; + + /// Element iterator type + /// + /// For example: std::int8_t*, bsoncxx::v_noabi::vector::elements::float32*, bsoncxx::v_noabi::vector::iterators::packed_bit_element using iterator = typename std::conditional< std::is_const::value, typename format_traits::const_iterator, typename format_traits::iterator>::type; + /// Type for the underlying byte data + /// + /// For example: std::uint8_t, std::uint8_t const using byte_type = typename detail::accessor_data::byte_type; + + /// Type for byte counts + /// + /// For example: std::uint32_t, due to BSON size limits. using byte_count_type = typename detail::accessor_data::byte_count_type; + + /// Type for element counts + /// + /// For example: std::size_t using element_count_type = typename format_traits::element_count_type; + + /// Type for signed differences between byte iterators + /// + /// For example: std::ptrdiff_t using byte_difference_type = typename format_traits::byte_difference_type; + + /// Type for signed differences between element iterators + /// + /// For example: std::ptrdiff_t using element_difference_type = typename format_traits::element_difference_type; + /// Type for referencing const-qualified vector bytes in-place using const_byte_reference = typename format_traits::const_byte_reference; + + /// Type for referencing vector bytes in-place + /// + /// For example: std::uint8_t&, std::uint8_t const&, bsoncxx::v_noabi::vector::elements::packed_bit_byte using byte_reference = typename std::conditional< std::is_const::value, typename format_traits::const_byte_reference, typename format_traits::byte_reference>::type; + /// Iterator for const-qualified vector bytes using const_byte_iterator = typename format_traits::const_byte_iterator; + + /// Byte iterator type + /// + /// For example: std::uint8_t*, std::uint8_t const*, bsoncxx::v_noabi::vector::iterators::packed_bit_byte using byte_iterator = typename std::conditional< std::is_const::value, typename format_traits::const_byte_iterator, From 007192b99e607db15cf8c0f441e41b15c455b374 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Wed, 26 Mar 2025 14:16:15 -0700 Subject: [PATCH 52/83] Add cbegin/cend --- .../v_noabi/bsoncxx/vector/accessor.hpp | 30 +++++++++++++++++-- src/bsoncxx/test/vector.cpp | 17 +++++++++-- 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/accessor.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/accessor.hpp index 6ee01e7b70..7a38341dbb 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/accessor.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/accessor.hpp @@ -71,7 +71,8 @@ class accessor { /// Type for referencing vector elements in-place /// - /// For example: std::int8_t&, bsoncxx::v_noabi::vector::elements::float32&, bsoncxx::v_noabi::vector::elements::packed_bit_element + /// For example: std::int8_t&, bsoncxx::v_noabi::vector::elements::float32&, + /// bsoncxx::v_noabi::vector::elements::packed_bit_element using reference = typename std::conditional< std::is_const::value, typename format_traits::const_reference, @@ -82,7 +83,8 @@ class accessor { /// Element iterator type /// - /// For example: std::int8_t*, bsoncxx::v_noabi::vector::elements::float32*, bsoncxx::v_noabi::vector::iterators::packed_bit_element + /// For example: std::int8_t*, bsoncxx::v_noabi::vector::elements::float32*, + /// bsoncxx::v_noabi::vector::iterators::packed_bit_element using iterator = typename std::conditional< std::is_const::value, typename format_traits::const_iterator, @@ -167,6 +169,18 @@ class accessor { return begin() + element_difference_type(size()); } + /// @brief Obtain a const iterator pointing to the beginning of the vector + /// @return A per-element random access const iterator, pointing at the first element if one exists + constexpr const_iterator cbegin() const noexcept { + return const_iterator(_data.bytes + detail::header_size); + } + + /// @brief Obtain a const iterator pointing just past the end of the vector + /// @return A per-element random access const iterator, pointing just past the end of the vector + constexpr const_iterator cend() const noexcept { + return cbegin() + element_difference_type(size()); + } + /// @brief Obtain a reference to the first element /// @return An element reference /// Undefined behavior if the vector is empty. @@ -207,6 +221,18 @@ class accessor { return byte_begin() + byte_difference_type(byte_size()); } + /// @brief Obtain a const byte iterator pointing to the beginning of the vector + /// @return A per-byte random access const iterator, pointing at the first byte if one exists + constexpr const_byte_iterator byte_cbegin() const noexcept { + return format_traits::make_byte_iterator(cbegin(), cend()); + } + + /// @brief Obtain a const byte iterator pointing just past the end of the vector + /// @return A per-byte random access const iterator, pointing just past the end of the vector + constexpr const_byte_iterator byte_cend() const noexcept { + return byte_cbegin() + byte_difference_type(byte_size()); + } + /// @brief Obtain a reference to the first byte /// @return A byte reference /// Undefined behavior if the vector is empty. diff --git a/src/bsoncxx/test/vector.cpp b/src/bsoncxx/test/vector.cpp index 9e34248857..2b09bdab2d 100644 --- a/src/bsoncxx/test/vector.cpp +++ b/src/bsoncxx/test/vector.cpp @@ -247,8 +247,9 @@ TEMPLATE_TEST_CASE( bsoncxx::document::value doc = make_document(kvp("vector", [&](sub_binary sbin) { // Avoid multiples of 8, to cover nonzero packed_bit 'padding'. auto vec = sbin.allocate(TestType{}, 8007u); - iterator_operations( - vec.begin(), vec.end(), std::ptrdiff_t(vec.size()), test_format_specific::element_unit()); + auto const element_unit = test_format_specific::element_unit(); + iterator_operations(vec.begin(), vec.end(), std::ptrdiff_t(vec.size()), element_unit); + std::for_each(vec.cbegin(), vec.cend(), [&](auto const& value) { CHECK_FALSE(value == element_unit); }); })); types::b_binary const& binary = doc.view()["vector"].get_binary(); vector::accessor validate_encoded{binary}; @@ -260,7 +261,10 @@ TEMPLATE_TEST_CASE( bsoncxx::document::value doc = make_document(kvp("vector", [&](sub_binary sbin) { // Choose a multiple of 8, to avoid the effects of masking unused bits. auto vec = sbin.allocate(TestType{}, 8000u); - iterator_operations(vec.byte_begin(), vec.byte_end(), std::ptrdiff_t(vec.byte_size()), uint8_t(1)); + uint8_t const element_unit(1); + iterator_operations(vec.byte_begin(), vec.byte_end(), std::ptrdiff_t(vec.byte_size()), element_unit); + std::for_each( + vec.byte_cbegin(), vec.byte_cend(), [&](auto const& value) { CHECK_FALSE(value == element_unit); }); })); types::b_binary const& binary = doc.view()["vector"].get_binary(); vector::accessor validate_encoded{binary}; @@ -442,6 +446,8 @@ TEST_CASE("vector accessor packed_bit", "[bsoncxx::vector::accessor]") { bsoncxx::document::value doc = make_document(kvp("vector", [&](sub_binary sbin) { auto vec = sbin.allocate(vector::formats::f_packed_bit{}, 9u); std::fill(vec.begin(), vec.end(), true); + std::for_each(vec.begin(), vec.end(), [&](bool value) { CHECK(value == true); }); + std::for_each(vec.cbegin(), vec.cend(), [&](bool value) { CHECK(value == true); }); CHECK(vec.byte_size() == 2u); CHECK(vec.byte_at(0) == 0xff); CHECK(vec.byte_at(1) == 0x80); @@ -501,6 +507,9 @@ TEST_CASE("vector accessor packed_bit", "[bsoncxx::vector::accessor]") { std::for_each(vec.byte_begin(), vec.byte_end() - 1, [&](std::uint8_t value) { CHECK(value == UINT8_C(0xFF)); }); + std::for_each(vec.byte_cbegin(), vec.byte_cend() - 1, [&](std::uint8_t value) { + CHECK(value == UINT8_C(0xFF)); + }); std::size_t padding = vec.byte_size() * std::size_t(8) - vec.size(); CHECK(vec.byte_back() == std::uint8_t(0xFF << padding)); } @@ -514,6 +523,8 @@ TEST_CASE("vector accessor packed_bit", "[bsoncxx::vector::accessor]") { if (!vec.empty()) { std::for_each( vec.byte_begin(), vec.byte_end() - 1, [&](std::uint8_t value) { CHECK(value == UINT8_C(0xFF)); }); + std::for_each( + vec.byte_cbegin(), vec.byte_cend() - 1, [&](std::uint8_t value) { CHECK(value == UINT8_C(0xFF)); }); std::size_t padding = vec.byte_size() * std::size_t(8) - vec.size(); CHECK(padding == binary.bytes[1]); CHECK(vec.byte_back() == std::uint8_t(0xFF << padding)); From 352bb73a1b64f34ba411f3a614dde7ddff47759e Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Wed, 26 Mar 2025 14:25:09 -0700 Subject: [PATCH 53/83] Requested change to header order --- .../bsoncxx/v_noabi/bsoncxx/builder/basic/sub_binary.hpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/sub_binary.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/sub_binary.hpp index 790ea86556..5cd553a6db 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/sub_binary.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/sub_binary.hpp @@ -14,9 +14,12 @@ #pragma once +#include + +// + #include -#include #include #include #include From 165a5b7c60660af8e8f4608b947f1e9ff73b291c Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Wed, 26 Mar 2025 14:26:50 -0700 Subject: [PATCH 54/83] Replace open_binary with suggestion --- .../bsoncxx/v_noabi/bsoncxx/builder/basic/impl.hpp | 2 +- .../include/bsoncxx/v_noabi/bsoncxx/builder/core.hpp | 8 ++------ src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/builder/core.cpp | 5 ----- 3 files changed, 3 insertions(+), 12 deletions(-) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/impl.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/impl.hpp index bcc4457fe5..773b128033 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/impl.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/impl.hpp @@ -43,7 +43,7 @@ detail::requires_t> generic_append(core template detail::requires_t> generic_append(core* core, T&& func) { - core->open_binary(); + // Opened by the user invoking `sub_binary::allocate()` in `func`. detail::invoke(std::forward(func), sub_binary(core)); core->close_binary(); } diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/core.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/core.hpp index fbb0a4f22c..cda028f685 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/core.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/core.hpp @@ -708,13 +708,9 @@ class core { BSONCXX_ABI_EXPORT_CDECL(void) clear(); /// - /// Opens a sub-binary within this BSON datum. + /// A sub-binary must be opened by invoking @ref bsoncxx::v_noabi::builder::basic::sub_binary::allocate() /// - /// @return - /// A reference to the object on which this member function is being called. This facilitates - /// method chaining. - /// - BSONCXX_ABI_EXPORT_CDECL(core&) open_binary(); + core& open_binary() = delete; /// /// Closes the current sub-binary within this BSON datum. diff --git a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/builder/core.cpp b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/builder/core.cpp index 3ecacc30d8..c00231dfcc 100644 --- a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/builder/core.cpp +++ b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/builder/core.cpp @@ -638,11 +638,6 @@ core& core::open_array() { return *this; } -core& core::open_binary() { - // No effect currently. (Here for symmetry and possibly extensibility) - return *this; -} - core& core::concatenate(bsoncxx::v_noabi::document::view const& view) { if (_impl->is_array()) { bson_iter_t iter; From dccb2fdcf87297077cb19bcc29e37b855eae649c Mon Sep 17 00:00:00 2001 From: mdbmes Date: Wed, 26 Mar 2025 14:31:40 -0700 Subject: [PATCH 55/83] Update src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/sub_binary-fwd.hpp Co-authored-by: Ezra Chung <88335979+eramongodb@users.noreply.github.com> --- .../bsoncxx/v_noabi/bsoncxx/builder/basic/sub_binary-fwd.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/sub_binary-fwd.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/sub_binary-fwd.hpp index 748a96b2ac..6056685462 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/sub_binary-fwd.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/sub_binary-fwd.hpp @@ -38,5 +38,5 @@ using ::bsoncxx::v_noabi::builder::basic::sub_binary; /// /// @file -/// Declares @ref bsoncxx::builder::basic::sub_binary +/// Declares @ref bsoncxx::v_noabi::builder::basic::sub_binary /// From 868179acb1ca260ab2b209c896d80335b5fd2d45 Mon Sep 17 00:00:00 2001 From: mdbmes Date: Wed, 26 Mar 2025 14:38:20 -0700 Subject: [PATCH 56/83] Update src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/accessor-fwd.hpp Co-authored-by: Ezra Chung <88335979+eramongodb@users.noreply.github.com> --- .../include/bsoncxx/v_noabi/bsoncxx/vector/accessor-fwd.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/accessor-fwd.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/accessor-fwd.hpp index 9d8cd1363b..bd0972cf1f 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/accessor-fwd.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/accessor-fwd.hpp @@ -39,5 +39,5 @@ using ::bsoncxx::v_noabi::vector::accessor; /// /// @file -/// Declares @ref bsoncxx::vector::accessor. +/// Declares @ref bsoncxx::v_noabi::vector::accessor. /// From b8df720adb386ecb7d30342ed4fc919ea8b80c40 Mon Sep 17 00:00:00 2001 From: mdbmes Date: Wed, 26 Mar 2025 14:39:07 -0700 Subject: [PATCH 57/83] Update src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/vector.cpp Co-authored-by: Ezra Chung <88335979+eramongodb@users.noreply.github.com> --- src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/vector.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/vector.cpp b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/vector.cpp index 7cab540f95..70e7d1f578 100644 --- a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/vector.cpp +++ b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/vector.cpp @@ -39,7 +39,7 @@ enum element_size : std::uint8_t { }; static header make_header(element_type element_type, element_size element_size, std::uint8_t padding) { - return {{(std::uint8_t)((std::uint8_t)element_type << 4 | (std::uint8_t)element_size), padding}}; + return {{static_cast((element_type << 4) | element_size), padding}}; } static void write_header(std::uint8_t* binary_data, header const& hdr) { From 3422b2e2203c206e69c23aecf3b978273e01ba62 Mon Sep 17 00:00:00 2001 From: mdbmes Date: Wed, 26 Mar 2025 14:39:25 -0700 Subject: [PATCH 58/83] Update src/bsoncxx/test/vector.cpp Co-authored-by: Ezra Chung <88335979+eramongodb@users.noreply.github.com> --- src/bsoncxx/test/vector.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bsoncxx/test/vector.cpp b/src/bsoncxx/test/vector.cpp index 2b09bdab2d..8524ac6577 100644 --- a/src/bsoncxx/test/vector.cpp +++ b/src/bsoncxx/test/vector.cpp @@ -137,7 +137,8 @@ void iterator_operations( CHECK(iter_copy == begin); std::generate(begin, end, [&] { return element_unit; }); - std::for_each(begin, end, [&](auto const& value) { CHECK(value == element_unit); }); + std::for_each( + begin, end, [&](auto const& value) { CHECK_THAT(value, Catch::Matchers::WithinAbs(element_unit, 0.0)); }); std::copy(begin, begin + (expected_size / 2), begin + (expected_size / 2)); std::for_each(begin, end, [&](auto const& value) { CHECK(value == element_unit); }); From 2ef0bb20f34de95517686f0342d0d78f71eb814b Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Wed, 26 Mar 2025 14:30:43 -0700 Subject: [PATCH 59/83] More header order changes --- .../bsoncxx/v_noabi/bsoncxx/builder/basic/document.hpp | 5 ++++- .../include/bsoncxx/v_noabi/bsoncxx/vector/accessor.hpp | 5 ++++- .../include/bsoncxx/v_noabi/bsoncxx/vector/formats.hpp | 5 ++++- .../include/bsoncxx/v_noabi/bsoncxx/vector/iterators.hpp | 5 ++++- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/document.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/document.hpp index e5212419b0..e5dd3af672 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/document.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/document.hpp @@ -14,9 +14,12 @@ #pragma once -#include #include +// + +#include + #include #include #include diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/accessor.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/accessor.hpp index 7a38341dbb..63b00c3d90 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/accessor.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/accessor.hpp @@ -14,10 +14,13 @@ #pragma once +#include + +// + #include #include -#include #include #include diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/formats.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/formats.hpp index 09315defca..5a9bc315a2 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/formats.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/formats.hpp @@ -14,11 +14,14 @@ #pragma once +#include + +// + #include #include #include -#include #include diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/iterators.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/iterators.hpp index c25438818a..ced501205c 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/iterators.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/iterators.hpp @@ -14,12 +14,15 @@ #pragma once +#include + +// + #include #include #include #include -#include #include #include From 7ffdb172649580847fa1d02d10714d32d82981d5 Mon Sep 17 00:00:00 2001 From: mdbmes Date: Wed, 26 Mar 2025 15:02:36 -0700 Subject: [PATCH 60/83] Update src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/vector.cpp Co-authored-by: Ezra Chung <88335979+eramongodb@users.noreply.github.com> --- src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/vector.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/vector.cpp b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/vector.cpp index 70e7d1f578..dee0f98fbc 100644 --- a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/vector.cpp +++ b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/vector.cpp @@ -12,12 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include +#include + +// + #include #include #include -#include -#include #include From 66b2a02c307cdeb0519181f164c45e1ba765cdd1 Mon Sep 17 00:00:00 2001 From: mdbmes Date: Wed, 26 Mar 2025 15:04:10 -0700 Subject: [PATCH 61/83] Update src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/accessor.hpp Co-authored-by: Ezra Chung <88335979+eramongodb@users.noreply.github.com> --- .../include/bsoncxx/v_noabi/bsoncxx/vector/accessor.hpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/accessor.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/accessor.hpp index 63b00c3d90..20951032e8 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/accessor.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/accessor.hpp @@ -184,9 +184,8 @@ class accessor { return cbegin() + element_difference_type(size()); } - /// @brief Obtain a reference to the first element - /// @return An element reference - /// Undefined behavior if the vector is empty. + /// Obtain a reference to the first element. + /// @warning Undefined behavior if the vector is empty. reference front() noexcept { return *begin(); } From e809f9fae26f5626c082c38bc3b1df087d5da950 Mon Sep 17 00:00:00 2001 From: mdbmes Date: Wed, 26 Mar 2025 15:19:02 -0700 Subject: [PATCH 62/83] Update src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/accessor.hpp Co-authored-by: Ezra Chung <88335979+eramongodb@users.noreply.github.com> --- .../include/bsoncxx/v_noabi/bsoncxx/vector/accessor.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/accessor.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/accessor.hpp index 20951032e8..aa1cbe6ea4 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/accessor.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/accessor.hpp @@ -40,8 +40,7 @@ namespace vector { /// subtype. A mutable accessor may be constructed only using bsoncxx::v_noabi::builder::basic::sub_binary. A const /// accessor may be constructed by validating any bsoncxx::v_noabi::types::b_binary. /// -/// The specific iterator and element types vary for each supported format. When possible, -/// iterators are raw pointers. +/// The specific iterator and element types vary for each supported format. /// /// bsoncxx::v_noabi::vector::formats::f_float32 uses a custom element type to support packed storage with a fixed byte /// order. From b5671187f9934709d54eda158f8100751eec577a Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Wed, 26 Mar 2025 15:11:27 -0700 Subject: [PATCH 63/83] Revert "Update src/bsoncxx/test/vector.cpp" This reverts commit 3422b2e2203c206e69c23aecf3b978273e01ba62. --- src/bsoncxx/test/vector.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/bsoncxx/test/vector.cpp b/src/bsoncxx/test/vector.cpp index 8524ac6577..2b09bdab2d 100644 --- a/src/bsoncxx/test/vector.cpp +++ b/src/bsoncxx/test/vector.cpp @@ -137,8 +137,7 @@ void iterator_operations( CHECK(iter_copy == begin); std::generate(begin, end, [&] { return element_unit; }); - std::for_each( - begin, end, [&](auto const& value) { CHECK_THAT(value, Catch::Matchers::WithinAbs(element_unit, 0.0)); }); + std::for_each(begin, end, [&](auto const& value) { CHECK(value == element_unit); }); std::copy(begin, begin + (expected_size / 2), begin + (expected_size / 2)); std::for_each(begin, end, [&](auto const& value) { CHECK(value == element_unit); }); From d170e9e9fba15afb4e99b51ed98c7b6746f48ed0 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Wed, 26 Mar 2025 15:56:14 -0700 Subject: [PATCH 64/83] Shorten doc comments --- .../v_noabi/bsoncxx/vector/accessor.hpp | 90 +++++++------------ 1 file changed, 33 insertions(+), 57 deletions(-) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/accessor.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/accessor.hpp index aa1cbe6ea4..ced3bc36ee 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/accessor.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/accessor.hpp @@ -147,38 +147,32 @@ class accessor { /// references the same data as the bsoncxx::v_noabi::types::b_binary pointer. accessor(types::b_binary const& binary) : _data((format::validate(binary), binary)) {} - /// @brief Count the bytes of element data - /// @return Size of the vector data, not including any headers + /// Count the bytes of element data, not including any headers constexpr byte_count_type byte_size() const noexcept { return _data.size - byte_count_type(detail::header_size); } - /// @brief Count the number of elements - /// @return Number of elements + /// Count the number of elements constexpr element_count_type size() const noexcept { return format_traits::element_count(_data.size, _data.header_copy); } - /// @brief Obtain an iterator pointing to the beginning of the vector - /// @return A per-element random access iterator, pointing at the first element if one exists + /// Obtain a per-element iterator pointing to the beginning of the vector constexpr iterator begin() const noexcept { return iterator(_data.bytes + detail::header_size); } - /// @brief Obtain an iterator pointing just past the end of the vector - /// @return A per-element random access iterator, pointing just past the end of the vector + /// Obtain a per-element end iterator constexpr iterator end() const noexcept { return begin() + element_difference_type(size()); } - /// @brief Obtain a const iterator pointing to the beginning of the vector - /// @return A per-element random access const iterator, pointing at the first element if one exists + /// Obtain a const per-element iterator pointing to the beginning of the vector constexpr const_iterator cbegin() const noexcept { return const_iterator(_data.bytes + detail::header_size); } - /// @brief Obtain a const iterator pointing just past the end of the vector - /// @return A per-element random access const iterator, pointing just past the end of the vector + /// Obtain a const per-element end iterator constexpr const_iterator cend() const noexcept { return cbegin() + element_difference_type(size()); } @@ -189,82 +183,70 @@ class accessor { return *begin(); } - /// @brief Obtain a const reference to the first element - /// @return An element reference - /// Undefined behavior if the vector is empty. + /// Obtain a const reference to the first element + /// @warning Undefined behavior if the vector is empty. constexpr const_reference front() const noexcept { return *begin(); } - /// @brief Obtain a reference to the last element - /// @return An element reference - /// Undefined behavior if the vector is empty. + /// Obtain a reference to the last element + /// @warning Undefined behavior if the vector is empty. reference back() noexcept { return *(begin() + element_difference_type(size() - 1u)); } - /// @brief Obtain a const reference to the last element - /// @return An element reference - /// Undefined behavior if the vector is empty. + /// Obtain a const reference to the last element + /// @warning Undefined behavior if the vector is empty. constexpr const_reference back() const noexcept { return *(begin() + element_difference_type(size() - 1u)); } - /// @brief Obtain a byte iterator pointing to the beginning of the vector - /// @return A per-byte random access iterator, pointing at the first byte if one exists + /// Obtain a per-byte iterator pointing to the beginning of the vector constexpr byte_iterator byte_begin() const noexcept { return format_traits::make_byte_iterator(begin(), end()); } - /// @brief Obtain a byte iterator pointing just past the end of the vector - /// @return A per-byte random access iterator, pointing just past the end of the vector + /// Obtain a per-byte end iterator constexpr byte_iterator byte_end() const noexcept { return byte_begin() + byte_difference_type(byte_size()); } - /// @brief Obtain a const byte iterator pointing to the beginning of the vector - /// @return A per-byte random access const iterator, pointing at the first byte if one exists + /// Obtain a const per-byte iterator pointing to the beginning of the vector constexpr const_byte_iterator byte_cbegin() const noexcept { return format_traits::make_byte_iterator(cbegin(), cend()); } - /// @brief Obtain a const byte iterator pointing just past the end of the vector - /// @return A per-byte random access const iterator, pointing just past the end of the vector + /// Obtain a const per-byte end iterator constexpr const_byte_iterator byte_cend() const noexcept { return byte_cbegin() + byte_difference_type(byte_size()); } - /// @brief Obtain a reference to the first byte - /// @return A byte reference - /// Undefined behavior if the vector is empty. + /// Obtain a reference to the first byte + /// @warning Undefined behavior if the vector is empty. byte_reference byte_front() noexcept { return *byte_begin(); } - /// @brief Obtain a const reference to the first byte - /// @return A byte reference - /// Undefined behavior if the vector is empty. + /// Obtain a const reference to the first byte + /// @warning Undefined behavior if the vector is empty. constexpr const_byte_reference byte_front() const noexcept { return *byte_begin(); } - /// @brief Obtain a reference to the last byte - /// @return A byte reference - /// Undefined behavior if the vector is empty. + /// Obtain a reference to the last byte + /// @warning Undefined behavior if the vector is empty. byte_reference byte_back() noexcept { return *(byte_begin() + byte_difference_type(byte_size() - 1u)); } - /// @brief Obtain a const reference to the last byte - /// @return A byte reference - /// Undefined behavior if the vector is empty. + /// Obtain a const reference to the last byte + /// @warning Undefined behavior if the vector is empty. constexpr const_byte_reference byte_back() const noexcept { return *(byte_begin() + byte_difference_type(byte_size() - 1u)); } - /// @brief Obtain a reference to a numbered byte, with bounds checking + /// Obtain a reference to a numbered byte, with bounds checking /// @param index Index in the range 0 to byte_size()-1 inclusive. - /// @return A byte reference /// @throws bsoncxx::v_noabi::exception with bsoncxx::v_noabi::error_code::k_vector_out_of_range, if the index is /// outside the allowed range. byte_reference byte_at(byte_count_type index) { @@ -274,9 +256,8 @@ class accessor { return *(byte_begin() + byte_difference_type(index)); } - /// @brief Obtain a const reference to a numbered byte, with bounds checking + /// Obtain a const reference to a numbered byte, with bounds checking /// @param index Index in the range 0 to byte_size()-1 inclusive. - /// @return A byte reference /// @throws bsoncxx::v_noabi::exception with bsoncxx::v_noabi::error_code::k_vector_out_of_range, if the index is /// outside the allowed range. const_byte_reference byte_at(byte_count_type index) const { @@ -286,9 +267,8 @@ class accessor { return *(byte_begin() + byte_difference_type(index)); } - /// @brief Obtain a reference to a numbered element, with bounds checking + /// Obtain a reference to a numbered element, with bounds checking /// @param index Index in the range 0 to size()-1 inclusive. - /// @return An element reference /// @throws bsoncxx::v_noabi::exception with bsoncxx::v_noabi::error_code::k_vector_out_of_range, if the index is /// outside the allowed range. reference at(element_count_type index) { @@ -298,9 +278,8 @@ class accessor { return *(begin() + element_difference_type(index)); } - /// @brief Obtain a const reference to a numbered element, with bounds checking + /// Obtain a const reference to a numbered element, with bounds checking /// @param index Index in the range 0 to size()-1 inclusive. - /// @return An element reference /// @throws bsoncxx::v_noabi::exception with bsoncxx::v_noabi::error_code::k_vector_out_of_range, if the index is /// outside the allowed range. const_reference at(element_count_type index) const { @@ -310,24 +289,21 @@ class accessor { return *(begin() + element_difference_type(index)); } - /// @brief Obtain a reference to a numbered element, without bounds checking + /// Obtain a reference to a numbered element, without bounds checking /// @param index Index in the range 0 to size()-1 inclusive. - /// @return An element reference - /// Undefined behavior if the index is out of bounds. + /// @warning Undefined behavior if the index is out of bounds. reference operator[](element_count_type index) noexcept { return *(begin() + element_difference_type(index)); } - /// @brief Obtain a const reference to a numbered element, without bounds checking + /// Obtain a const reference to a numbered element, without bounds checking /// @param index Index in the range 0 to size()-1 inclusive. - /// @return An element reference - /// Undefined behavior if the index is out of bounds. + /// @warning Undefined behavior if the index is out of bounds. constexpr const_reference operator[](element_count_type index) const noexcept { return *(begin() + element_difference_type(index)); } - /// @brief Test whether the vector is empty - /// @return True if the vector has a size() of zero. + /// Test whether the vector is empty constexpr bool empty() const noexcept { return size() == 0u; } From 9218f9766da72e2c99b5d78417c1300279dedf03 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Wed, 26 Mar 2025 21:45:08 -0700 Subject: [PATCH 65/83] Disable gcc -Wfloat-equal warnings for comparisons in bsoncxx::vector test --- src/bsoncxx/test/vector.cpp | 40 +++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/bsoncxx/test/vector.cpp b/src/bsoncxx/test/vector.cpp index 2b09bdab2d..ee7d937c0a 100644 --- a/src/bsoncxx/test/vector.cpp +++ b/src/bsoncxx/test/vector.cpp @@ -136,6 +136,9 @@ void iterator_operations( CHECK(iter_copy-- - begin == 1); CHECK(iter_copy == begin); + BSONCXX_PRIVATE_WARNINGS_PUSH(); + BSONCXX_PRIVATE_WARNINGS_DISABLE(GNU("-Wfloat-equal")); + std::generate(begin, end, [&] { return element_unit; }); std::for_each(begin, end, [&](auto const& value) { CHECK(value == element_unit); }); @@ -163,6 +166,8 @@ void iterator_operations( std::for_each(begin, end, [&](auto const& value) { CHECK_FALSE(value == element_unit); }); std::for_each(begin, end, [&](auto const& value) { CHECK_FALSE(value > element_unit); }); std::for_each(begin, end, [&](auto const& value) { CHECK_FALSE(value >= element_unit); }); + + BSONCXX_PRIVATE_WARNINGS_POP(); } TEMPLATE_TEST_CASE( @@ -193,8 +198,15 @@ TEMPLATE_TEST_CASE( CHECK_FALSE(vec.empty()); CHECK(vec.size() == 1u); CHECK(vec.byte_size() == bytes.size() - 2u); + + BSONCXX_PRIVATE_WARNINGS_PUSH(); + BSONCXX_PRIVATE_WARNINGS_DISABLE(GNU("-Wfloat-equal")); + CHECK(vec.at(0) == element); CHECK(vec[0] == element); + + BSONCXX_PRIVATE_WARNINGS_POP(); + CHECK(vec.byte_at(0) == bytes[2]); CHECK(vec.byte_at(bytes.size() - 3u) == bytes[bytes.size() - 1u]); CHECK_THROWS_WITH(vec.at(1), Catch::Matchers::ContainsSubstring("BSON vector access out of range")); @@ -249,7 +261,11 @@ TEMPLATE_TEST_CASE( auto vec = sbin.allocate(TestType{}, 8007u); auto const element_unit = test_format_specific::element_unit(); iterator_operations(vec.begin(), vec.end(), std::ptrdiff_t(vec.size()), element_unit); + + BSONCXX_PRIVATE_WARNINGS_PUSH(); + BSONCXX_PRIVATE_WARNINGS_DISABLE(GNU("-Wfloat-equal")); std::for_each(vec.cbegin(), vec.cend(), [&](auto const& value) { CHECK_FALSE(value == element_unit); }); + BSONCXX_PRIVATE_WARNINGS_POP(); })); types::b_binary const& binary = doc.view()["vector"].get_binary(); vector::accessor validate_encoded{binary}; @@ -277,11 +293,17 @@ TEMPLATE_TEST_CASE( auto vec = sbin.allocate(TestType{}, 2u); vec[0] = test_format_specific::element_unit(); vec[1] = value_type{0}; + + BSONCXX_PRIVATE_WARNINGS_PUSH(); + BSONCXX_PRIVATE_WARNINGS_DISABLE(GNU("-Wfloat-equal")); + CHECK(vec.at(0) != vec.at(1)); CHECK_FALSE(vec.at(0) == vec.at(1)); vec[1] = vec[0]; CHECK(vec.at(0) == vec.at(1)); CHECK_FALSE(vec.at(0) != vec.at(1)); + + BSONCXX_PRIVATE_WARNINGS_POP(); })); types::b_binary const& binary = doc.view()["vector"].get_binary(); vector::accessor validate_encoded{binary}; @@ -318,6 +340,10 @@ TEMPLATE_TEST_CASE( auto vec = sbin.allocate(TestType{}, 2u); std::fill(vec.begin(), vec.end(), test_format_specific::element_unit()); *(vec.end() - 1) = value_type{0}; + + BSONCXX_PRIVATE_WARNINGS_PUSH(); + BSONCXX_PRIVATE_WARNINGS_DISABLE(GNU("-Wfloat-equal")); + CHECK(vec.back() == value_type{0}); CHECK(vec.back() == vec[vec.size() - 1u]); CHECK(vec.front() != vec.back()); @@ -332,6 +358,8 @@ TEMPLATE_TEST_CASE( CHECK(vec[vec.size() - 1u] != value_type{0}); CHECK(vec.front() != vec.back()); CHECK_FALSE(vec.front() == vec.back()); + + BSONCXX_PRIVATE_WARNINGS_POP(); })); types::b_binary const& binary = doc.view()["vector"].get_binary(); vector::accessor validate_encoded{binary}; @@ -342,6 +370,10 @@ TEMPLATE_TEST_CASE( bsoncxx::document::value doc = make_document(kvp("vector", [&](sub_binary sbin) { auto vec = sbin.allocate(TestType{}, 16u); std::fill(vec.begin(), vec.end(), value_type{0}); + + BSONCXX_PRIVATE_WARNINGS_PUSH(); + BSONCXX_PRIVATE_WARNINGS_DISABLE(GNU("-Wfloat-equal")); + CHECK(vec.front() == vec.back()); CHECK_FALSE(vec.front() != vec.back()); CHECK(vec.byte_front() == vec.byte_back()); @@ -353,6 +385,8 @@ TEMPLATE_TEST_CASE( vec.byte_back() = UINT8_C(0); CHECK(vec.byte_front() == vec.byte_back()); CHECK_FALSE(vec.byte_front() != vec.byte_back()); + + BSONCXX_PRIVATE_WARNINGS_POP(); })); types::b_binary const& binary = doc.view()["vector"].get_binary(); vector::accessor validate_encoded{binary}; @@ -385,11 +419,17 @@ TEST_CASE("vector accessor float32", "[bsoncxx::vector::accessor]") { types::b_binary const binary{binary_sub_type::k_vector, sizeof bytes, bytes}; vector::accessor vec{binary}; REQUIRE(vec.size() == 3u); + + BSONCXX_PRIVATE_WARNINGS_PUSH(); + BSONCXX_PRIVATE_WARNINGS_DISABLE(GNU("-Wfloat-equal")); + CHECK(vec[0] < 0.f); CHECK(vec[0] * 0.f != 0.f); CHECK(vec[1] == 0.f); CHECK(vec[2] > 0.f); CHECK(vec[2] * 0.f != 0.f); + + BSONCXX_PRIVATE_WARNINGS_POP(); } } From 42250eabbe8aa46a4d9c6e57c7953a9921ef2ccc Mon Sep 17 00:00:00 2001 From: mdbmes Date: Wed, 26 Mar 2025 21:47:11 -0700 Subject: [PATCH 66/83] Update src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/formats-fwd.hpp Co-authored-by: Ezra Chung <88335979+eramongodb@users.noreply.github.com> --- .../include/bsoncxx/v_noabi/bsoncxx/vector/formats-fwd.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/formats-fwd.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/formats-fwd.hpp index f6018fccdb..110a2a1c2a 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/formats-fwd.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/formats-fwd.hpp @@ -46,5 +46,5 @@ using ::bsoncxx::v_noabi::vector::formats::f_packed_bit; /// /// @file -/// Declares entities in @ref bsoncxx::vector::formats. +/// Declares entities in @ref bsoncxx::v_noabi::vector::formats. /// From 3f61ef48770aa4ea51c29248ee824121b1896e43 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Wed, 26 Mar 2025 21:54:07 -0700 Subject: [PATCH 67/83] Hide detail from accessor type declarations --- .../bsoncxx/v_noabi/bsoncxx/vector/accessor.hpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/accessor.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/accessor.hpp index ced3bc36ee..77373df218 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/accessor.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/accessor.hpp @@ -58,10 +58,12 @@ class accessor { using format = Format; /// Const qualified version of @ref value_type + /// @hideinitializer using const_value_type = typename format_traits::value_type const; /// A type suitable for holding element values. /// + /// @hideinitializer /// For example: std::int8_t, float, bool using value_type = typename std::conditional< std::is_const::value, @@ -69,10 +71,12 @@ class accessor { typename format_traits::value_type>::type; /// Type for referencing const-qualified vector elements in-place + /// @hideinitializer using const_reference = typename format_traits::const_reference; /// Type for referencing vector elements in-place /// + /// @hideinitializer /// For example: std::int8_t&, bsoncxx::v_noabi::vector::elements::float32&, /// bsoncxx::v_noabi::vector::elements::packed_bit_element using reference = typename std::conditional< @@ -81,10 +85,12 @@ class accessor { typename format_traits::reference>::type; /// Iterator for const-qualified vector elements + /// @hideinitializer using const_iterator = typename format_traits::const_iterator; /// Element iterator type /// + /// @hideinitializer /// For example: std::int8_t*, bsoncxx::v_noabi::vector::elements::float32*, /// bsoncxx::v_noabi::vector::iterators::packed_bit_element using iterator = typename std::conditional< @@ -94,34 +100,41 @@ class accessor { /// Type for the underlying byte data /// + /// @hideinitializer /// For example: std::uint8_t, std::uint8_t const using byte_type = typename detail::accessor_data::byte_type; /// Type for byte counts /// + /// @hideinitializer /// For example: std::uint32_t, due to BSON size limits. using byte_count_type = typename detail::accessor_data::byte_count_type; /// Type for element counts /// + /// @hideinitializer /// For example: std::size_t using element_count_type = typename format_traits::element_count_type; /// Type for signed differences between byte iterators /// + /// @hideinitializer /// For example: std::ptrdiff_t using byte_difference_type = typename format_traits::byte_difference_type; /// Type for signed differences between element iterators /// + /// @hideinitializer /// For example: std::ptrdiff_t using element_difference_type = typename format_traits::element_difference_type; /// Type for referencing const-qualified vector bytes in-place + /// @hideinitializer using const_byte_reference = typename format_traits::const_byte_reference; /// Type for referencing vector bytes in-place /// + /// @hideinitializer /// For example: std::uint8_t&, std::uint8_t const&, bsoncxx::v_noabi::vector::elements::packed_bit_byte using byte_reference = typename std::conditional< std::is_const::value, @@ -129,10 +142,12 @@ class accessor { typename format_traits::byte_reference>::type; /// Iterator for const-qualified vector bytes + /// @hideinitializer using const_byte_iterator = typename format_traits::const_byte_iterator; /// Byte iterator type /// + /// @hideinitializer /// For example: std::uint8_t*, std::uint8_t const*, bsoncxx::v_noabi::vector::iterators::packed_bit_byte using byte_iterator = typename std::conditional< std::is_const::value, From bd78a37b61953c79b23357f10f6ad55cbdab0798 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Wed, 26 Mar 2025 22:50:12 -0700 Subject: [PATCH 68/83] vector example: shorter output, more comments --- examples/bsoncxx/bson_binary_vector.cpp | 94 ++++++++++++++++++++----- 1 file changed, 76 insertions(+), 18 deletions(-) diff --git a/examples/bsoncxx/bson_binary_vector.cpp b/examples/bsoncxx/bson_binary_vector.cpp index 83aaaba320..9ac59743e6 100644 --- a/examples/bsoncxx/bson_binary_vector.cpp +++ b/examples/bsoncxx/bson_binary_vector.cpp @@ -16,7 +16,6 @@ #include #include #include -#include #include #include @@ -34,65 +33,120 @@ int EXAMPLES_CDECL main() { using bsoncxx::builder::basic::sub_binary; bsoncxx::document::value doc = make_document( + + // + // Added along with BSON Binary Vector support, the new sub_binary builder + // allows allocating any type of BSON Binary item in-place. A callback taking + // a sub_binary argument can calculate the required space before calling allocate() + // on the sub_binary to get a pointer to the new in-place allocation. + // + // Every byte of the allocated binary region must be written or the resulting BSON + // will have undefined contents. If allocate() isn't called exactly once, + // an exception will be thrown. + // kvp("binary", [&](sub_binary sbin) { - uint32_t len = 1000; + uint32_t len = 10; uint8_t* vec = sbin.allocate(bsoncxx::binary_sub_type::k_binary, len); memset(vec, 0x55, len); }), + + // + // The sub_binary also provides an allocate() method for BSON Binary Vector. + // Instead of a sub_type and byte length, this takes a vector format + // and an element count. + // + // This example uses the f_int8 vector format, which has int8_t elements. + // The allocate() call here returns a bsoncxx::vector::accessor instance + // that works like a random access container but does not own memory directly. + // kvp("vector_int8", [&](sub_binary sbin) { - auto vec = sbin.allocate(bsoncxx::vector::formats::f_int8{}, 1000); - uint8_t i = 0; - std::generate(vec.begin(), vec.end(), [&] { return (int8_t)++i; }); + auto vec = sbin.allocate(bsoncxx::vector::formats::f_int8{}, 10); + int8_t i = -5; + std::generate(vec.begin(), vec.end(), [&] { return ++i; }); }), + + // + // BSON Binary Vector supports formats that do not map directly to C++ + // built-in types. The f_float32 format is an unaligned little endian + // serialization of IEEE 754 32-bit binary floating point. On some platforms, + // this sort of data could be accessed using a raw float*, but for consistent + // portability we have a bsoncxx::v_noabi::vector::elements::float32 type which + // has the unaligned little-endian representation in memory but supports automatic + // conversion to and from 'float'. + // + // The vector accessor works like a container of floats. Elements can be assigned + // from float expressions or used as float expressions. Assignment operators + // operate by automatically convering to float and then back to elements::float32. + // kvp("vector_float32", [&](sub_binary sbin) { - auto vec = sbin.allocate(bsoncxx::vector::formats::f_float32{}, 1000); + auto vec = sbin.allocate(bsoncxx::vector::formats::f_float32{}, 10); + // Calculate a fibonacci sequence starting near the smallest representable value vec[0] = 0.f; vec[1] = 1e-38f; for (size_t i = 2; i < vec.size(); i++) { vec[i] = vec[i - 1] + vec[i - 2]; } - for (auto i = vec.begin(); i != vec.end(); i++) { - if (!(*i * 0.f < *i)) { - *i = float(std::sin(double(i - vec.begin()) * 1e-3)); - } - } - std::fill(vec.end() - 10, vec.end() - 7, std::numeric_limits::infinity()); + // Demonstrate assignment operators vec[0] += 1.f; vec[1] *= 1e38f; vec[1] /= 2.f; vec[1] -= 1.f + vec[0]; }), + + // + // packed_bit vectors support any number of single-bit elements, + // using an accessor that works like a random-access container of + // bool values. This works using a reference-proxy type + // bsoncxx::v_noabi::vector::elements::packed_bit_element and an iterator + // bsoncxx::v_noabi::vector::iterators::packed_bit_element. + // + // Every bsoncxx::vector:accessor can be accessed either in per-element + // or per-byte mode. Byte mode is particularly useful for applications that + // may want to use packed_bit vectors in the serialized format without + // accessing individual elements. + // kvp("vector_packed_bit", [&](sub_binary sbin) { auto vec = sbin.allocate(bsoncxx::vector::formats::f_packed_bit{}, 61); + // Start by setting all bits to 1 std::fill(vec.begin(), vec.end(), true); + // Flip a bit using a boolean expression vec[5] = !vec[5]; + // Assignment of a packed_bit_element reference copies the referenced bit value vec[6] = vec[1]; vec[7] = vec[5]; + // Bits can be assigned using boolean expressions, initialized with 0. vec[8] = 0; vec[60] = false; + // Demonstrate addressing bits backward from the end of the vector std::fill(vec.end() - 20, vec.end() - 4, false); std::fill(vec.end() - 8, vec.end() - 5, true); + // Flip all bits, operating an entire byte at a time. + // The last byte will have bits that do not correspond to any elements, and writes to these are ignored. for (auto i = vec.byte_begin(); i != vec.byte_end(); i++) { *i ^= 0xFF; } + // Demonstrate copying bit ranges and byte ranges using std::copy std::copy(vec.byte_begin(), vec.byte_begin() + 2, vec.byte_begin() + 2); std::copy(vec.begin() + 5, vec.begin() + 9, vec.begin() + 56); })); + // Demonstrate extended JSON serialization of the entire document std::cout << bsoncxx::to_json(doc) << std::endl; + // Iterate over elements in the int8 vector { bsoncxx::vector::accessor vec(doc["vector_int8"].get_binary()); std::cout << "int8: " << vec.size() << std::endl; - for (auto i = vec.begin(); i != vec.end(); i++) { - std::cout << int(*i) << " "; + for (auto&& i : vec) { + std::cout << int(i) << " "; } std::cout << std::endl; } + // Iterate over bytes in the int8 vector { bsoncxx::vector::accessor vec(doc["vector_int8"].get_binary()); std::cout << "int8 bytes: " << vec.byte_size() << std::hex << std::endl; @@ -102,15 +156,17 @@ int EXAMPLES_CDECL main() { std::cout << std::dec << std::endl; } + // Iterate over elements in the float32 vector { bsoncxx::vector::accessor vec(doc["vector_float32"].get_binary()); std::cout << "float32: " << vec.size() << std::endl; - for (auto i = vec.begin(); i != vec.end(); i++) { - std::cout << *i << " "; + for (auto&& i : vec) { + std::cout << i << " "; } std::cout << std::endl; } + // Iterate over bytes in the float32 vector { bsoncxx::vector::accessor vec(doc["vector_float32"].get_binary()); std::cout << "float32 bytes: " << vec.byte_size() << std::hex << std::endl; @@ -120,16 +176,18 @@ int EXAMPLES_CDECL main() { std::cout << std::dec << std::endl; } + // Iterate over elements in the packed_bit vector { bsoncxx::vector::accessor vec( doc["vector_packed_bit"].get_binary()); std::cout << "packed_bit: " << vec.size() << std::endl; - for (auto i = vec.begin(); i != vec.end(); i++) { - std::cout << *i << " "; + for (auto&& i : vec) { + std::cout << i << " "; } std::cout << std::endl; } + // Iterate over bytes in the packed_bit vector { bsoncxx::vector::accessor vec( doc["vector_packed_bit"].get_binary()); From ebf3ec1b19265d643c0b9355bef270e17a1b2212 Mon Sep 17 00:00:00 2001 From: mdbmes Date: Wed, 26 Mar 2025 22:52:20 -0700 Subject: [PATCH 69/83] Update src/bsoncxx/test/vector.cpp Co-authored-by: Ezra Chung <88335979+eramongodb@users.noreply.github.com> --- src/bsoncxx/test/vector.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bsoncxx/test/vector.cpp b/src/bsoncxx/test/vector.cpp index ee7d937c0a..76392d0001 100644 --- a/src/bsoncxx/test/vector.cpp +++ b/src/bsoncxx/test/vector.cpp @@ -186,7 +186,7 @@ TEMPLATE_TEST_CASE( CHECK(vec.empty()); CHECK(vec.size() == 0); CHECK(vec.byte_size() == 0); - CHECK_THROWS_WITH(vec.at(0), Catch::Matchers::ContainsSubstring("BSON vector access out of range")); + CHECK_THROWS_WITH_CODE(vec.at(0), bsoncxx::v_noabi::error_code::k_vector_out_of_range); CHECK_THROWS_WITH(vec.byte_at(0), Catch::Matchers::ContainsSubstring("BSON vector access out of range")); } From c147b8874e78abfa05718063f944efc4fa00ee14 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Wed, 26 Mar 2025 22:58:26 -0700 Subject: [PATCH 70/83] Prefer CHECK_THROWS_WITH_CODE --- src/bsoncxx/test/vector.cpp | 55 +++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 30 deletions(-) diff --git a/src/bsoncxx/test/vector.cpp b/src/bsoncxx/test/vector.cpp index 76392d0001..40172f1511 100644 --- a/src/bsoncxx/test/vector.cpp +++ b/src/bsoncxx/test/vector.cpp @@ -27,7 +27,6 @@ #include #include -#include namespace { @@ -187,7 +186,7 @@ TEMPLATE_TEST_CASE( CHECK(vec.size() == 0); CHECK(vec.byte_size() == 0); CHECK_THROWS_WITH_CODE(vec.at(0), bsoncxx::v_noabi::error_code::k_vector_out_of_range); - CHECK_THROWS_WITH(vec.byte_at(0), Catch::Matchers::ContainsSubstring("BSON vector access out of range")); + CHECK_THROWS_WITH_CODE(vec.byte_at(0), bsoncxx::v_noabi::error_code::k_vector_out_of_range); } SECTION("decode a valid vector with a single element") { @@ -209,9 +208,8 @@ TEMPLATE_TEST_CASE( CHECK(vec.byte_at(0) == bytes[2]); CHECK(vec.byte_at(bytes.size() - 3u) == bytes[bytes.size() - 1u]); - CHECK_THROWS_WITH(vec.at(1), Catch::Matchers::ContainsSubstring("BSON vector access out of range")); - CHECK_THROWS_WITH( - vec.byte_at(bytes.size() - 2u), Catch::Matchers::ContainsSubstring("BSON vector access out of range")); + CHECK_THROWS_WITH_CODE(vec.at(1), bsoncxx::v_noabi::error_code::k_vector_out_of_range); + CHECK_THROWS_WITH_CODE(vec.byte_at(bytes.size() - 2u), bsoncxx::v_noabi::error_code::k_vector_out_of_range); } SECTION("reject binary data of the wrong sub_type") { @@ -219,8 +217,8 @@ TEMPLATE_TEST_CASE( auto invalid_type = GENERATE( binary_sub_type::k_binary, binary_sub_type::k_encrypted, binary_sub_type::k_uuid, binary_sub_type::k_user); types::b_binary const binary{invalid_type, bytes.size(), bytes.data()}; - CHECK_THROWS_WITH( - vector::accessor(binary), Catch::Matchers::ContainsSubstring("invalid BSON vector")); + CHECK_THROWS_WITH_CODE( + vector::accessor(binary), bsoncxx::v_noabi::error_code::k_invalid_vector); } SECTION("reject binary data that's too short to include a header") { @@ -228,8 +226,8 @@ TEMPLATE_TEST_CASE( auto bytes_to_remove = GENERATE(1u, 2u); REQUIRE(bytes.size() >= bytes_to_remove); types::b_binary const binary{binary_sub_type::k_vector, uint32_t(bytes.size() - bytes_to_remove), bytes.data()}; - CHECK_THROWS_WITH( - vector::accessor(binary), Catch::Matchers::ContainsSubstring("invalid BSON vector")); + CHECK_THROWS_WITH_CODE( + vector::accessor(binary), bsoncxx::v_noabi::error_code::k_invalid_vector); } SECTION("reject empty vectors with any modified header bits") { @@ -237,8 +235,8 @@ TEMPLATE_TEST_CASE( auto bytes = test_format_specific::bytes_empty(); bytes[bit_index >> 3u] ^= std::uint8_t(1u << (bit_index & 7u)); types::b_binary const binary{binary_sub_type::k_vector, bytes.size(), bytes.data()}; - CHECK_THROWS_WITH( - vector::accessor(binary), Catch::Matchers::ContainsSubstring("invalid BSON vector")); + CHECK_THROWS_WITH_CODE( + vector::accessor(binary), bsoncxx::v_noabi::error_code::k_invalid_vector); } } @@ -329,9 +327,9 @@ TEMPLATE_TEST_CASE( using namespace builder::basic; // This checks that we can detect overlarge sizes and throw an exception. // Detailed checks for the size limit are delegated to Libbson (via libbson_length_for_append) - CHECK_THROWS_WITH( + CHECK_THROWS_WITH_CODE( make_document(kvp("vector", [&](sub_binary sbin) { sbin.allocate(TestType{}, SIZE_MAX); })), - Catch::Matchers::ContainsSubstring("BSON vector too large")); + bsoncxx::v_noabi::error_code::k_vector_too_large); } SECTION("support front and back element references") { @@ -398,9 +396,8 @@ TEST_CASE("vector accessor float32", "[bsoncxx::vector::accessor]") { static uint8_t const bytes[] = {0x27, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00}; auto invalid_length = GENERATE(0u, 1u, 3u, 4u, 5u, 7u, 8u, 9u); types::b_binary const binary{binary_sub_type::k_vector, uint32_t(invalid_length), bytes}; - CHECK_THROWS_WITH( - vector::accessor(binary), - Catch::Matchers::ContainsSubstring("invalid BSON vector")); + CHECK_THROWS_WITH_CODE( + vector::accessor(binary), bsoncxx::v_noabi::error_code::k_invalid_vector); } SECTION("rejects binary data from other vector formats") { @@ -408,9 +405,8 @@ TEST_CASE("vector accessor float32", "[bsoncxx::vector::accessor]") { format_specific::bytes_empty(), format_specific::bytes_empty()); types::b_binary const binary{binary_sub_type::k_vector, bytes.size(), bytes.data()}; - CHECK_THROWS_WITH( - vector::accessor(binary), - Catch::Matchers::ContainsSubstring("invalid BSON vector")); + CHECK_THROWS_WITH_CODE( + vector::accessor(binary), bsoncxx::v_noabi::error_code::k_invalid_vector); } SECTION("accepts and correctly decodes elements with infinite value") { @@ -439,9 +435,8 @@ TEST_CASE("vector accessor int8_t", "[bsoncxx::vector::accessor]") { format_specific::bytes_empty(), format_specific::bytes_empty()); types::b_binary const binary{binary_sub_type::k_vector, bytes.size(), bytes.data()}; - CHECK_THROWS_WITH( - vector::accessor(binary), - Catch::Matchers::ContainsSubstring("invalid BSON vector")); + CHECK_THROWS_WITH_CODE( + vector::accessor(binary), bsoncxx::v_noabi::error_code::k_invalid_vector); } } @@ -451,9 +446,9 @@ TEST_CASE("vector accessor packed_bit", "[bsoncxx::vector::accessor]") { auto bytes = format_specific::bytes_empty(); bytes[1] = uint8_t(byte_value); types::b_binary const binary{binary_sub_type::k_vector, bytes.size(), bytes.data()}; - CHECK_THROWS_WITH( + CHECK_THROWS_WITH_CODE( vector::accessor(binary), - Catch::Matchers::ContainsSubstring("invalid BSON vector")); + bsoncxx::v_noabi::error_code::k_invalid_vector); } } @@ -461,9 +456,9 @@ TEST_CASE("vector accessor packed_bit", "[bsoncxx::vector::accessor]") { for (unsigned byte_value = 8u; byte_value <= UINT8_MAX; byte_value++) { uint8_t const bytes[] = {0x10, uint8_t(byte_value), 0x00}; types::b_binary const binary{binary_sub_type::k_vector, sizeof bytes, bytes}; - CHECK_THROWS_WITH( + CHECK_THROWS_WITH_CODE( vector::accessor(binary), - Catch::Matchers::ContainsSubstring("invalid BSON vector")); + bsoncxx::v_noabi::error_code::k_invalid_vector); } } @@ -471,9 +466,9 @@ TEST_CASE("vector accessor packed_bit", "[bsoncxx::vector::accessor]") { for (unsigned byte_value = 1u; byte_value <= 7u; byte_value++) { uint8_t bytes[] = {0x10, uint8_t(byte_value), 0xff}; types::b_binary const binary{binary_sub_type::k_vector, sizeof bytes, bytes}; - CHECK_THROWS_WITH( + CHECK_THROWS_WITH_CODE( vector::accessor(binary), - Catch::Matchers::ContainsSubstring("invalid BSON vector")); + bsoncxx::v_noabi::error_code::k_invalid_vector); // Succeeds when unused bits are then zeroed bytes[2] = 0; vector::accessor vec{binary}; @@ -529,9 +524,9 @@ TEST_CASE("vector accessor packed_bit", "[bsoncxx::vector::accessor]") { format_specific::bytes_empty(), format_specific::bytes_empty()); types::b_binary const binary{binary_sub_type::k_vector, bytes.size(), bytes.data()}; - CHECK_THROWS_WITH( + CHECK_THROWS_WITH_CODE( vector::accessor(binary), - Catch::Matchers::ContainsSubstring("invalid BSON vector")); + bsoncxx::v_noabi::error_code::k_invalid_vector); } SECTION("writes and successfully re-validates vectors of any length") { From 506772457c2cb7c81104afc965f1f6499e2a6f43 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Wed, 26 Mar 2025 23:20:06 -0700 Subject: [PATCH 71/83] Clarify comment --- examples/bsoncxx/bson_binary_vector.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/bsoncxx/bson_binary_vector.cpp b/examples/bsoncxx/bson_binary_vector.cpp index 9ac59743e6..1d1de90d6c 100644 --- a/examples/bsoncxx/bson_binary_vector.cpp +++ b/examples/bsoncxx/bson_binary_vector.cpp @@ -117,7 +117,7 @@ int EXAMPLES_CDECL main() { // Assignment of a packed_bit_element reference copies the referenced bit value vec[6] = vec[1]; vec[7] = vec[5]; - // Bits can be assigned using boolean expressions, initialized with 0. + // Bits can be assigned from boolean expressions, and from zero. vec[8] = 0; vec[60] = false; // Demonstrate addressing bits backward from the end of the vector From 5b7c99166ec00665590d1dad65cc78d3ab6d6b55 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Wed, 26 Mar 2025 23:26:50 -0700 Subject: [PATCH 72/83] Unclutter the vector example some more --- examples/bsoncxx/bson_binary_vector.cpp | 29 ++++++++++++++----------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/examples/bsoncxx/bson_binary_vector.cpp b/examples/bsoncxx/bson_binary_vector.cpp index 1d1de90d6c..c0a85bfbd8 100644 --- a/examples/bsoncxx/bson_binary_vector.cpp +++ b/examples/bsoncxx/bson_binary_vector.cpp @@ -28,9 +28,14 @@ #include int EXAMPLES_CDECL main() { + using bsoncxx::binary_sub_type; using bsoncxx::builder::basic::kvp; using bsoncxx::builder::basic::make_document; using bsoncxx::builder::basic::sub_binary; + using bsoncxx::vector::accessor; + using bsoncxx::vector::formats::f_float32; + using bsoncxx::vector::formats::f_int8; + using bsoncxx::vector::formats::f_packed_bit; bsoncxx::document::value doc = make_document( @@ -47,8 +52,8 @@ int EXAMPLES_CDECL main() { kvp("binary", [&](sub_binary sbin) { uint32_t len = 10; - uint8_t* vec = sbin.allocate(bsoncxx::binary_sub_type::k_binary, len); - memset(vec, 0x55, len); + uint8_t* data = sbin.allocate(binary_sub_type::k_binary, len); + memset(data, 0x55, len); }), // @@ -62,7 +67,7 @@ int EXAMPLES_CDECL main() { // kvp("vector_int8", [&](sub_binary sbin) { - auto vec = sbin.allocate(bsoncxx::vector::formats::f_int8{}, 10); + auto vec = sbin.allocate(f_int8{}, 10); int8_t i = -5; std::generate(vec.begin(), vec.end(), [&] { return ++i; }); }), @@ -82,7 +87,7 @@ int EXAMPLES_CDECL main() { // kvp("vector_float32", [&](sub_binary sbin) { - auto vec = sbin.allocate(bsoncxx::vector::formats::f_float32{}, 10); + auto vec = sbin.allocate(f_float32{}, 10); // Calculate a fibonacci sequence starting near the smallest representable value vec[0] = 0.f; vec[1] = 1e-38f; @@ -109,7 +114,7 @@ int EXAMPLES_CDECL main() { // accessing individual elements. // kvp("vector_packed_bit", [&](sub_binary sbin) { - auto vec = sbin.allocate(bsoncxx::vector::formats::f_packed_bit{}, 61); + auto vec = sbin.allocate(f_packed_bit{}, 61); // Start by setting all bits to 1 std::fill(vec.begin(), vec.end(), true); // Flip a bit using a boolean expression @@ -138,7 +143,7 @@ int EXAMPLES_CDECL main() { // Iterate over elements in the int8 vector { - bsoncxx::vector::accessor vec(doc["vector_int8"].get_binary()); + accessor vec(doc["vector_int8"].get_binary()); std::cout << "int8: " << vec.size() << std::endl; for (auto&& i : vec) { std::cout << int(i) << " "; @@ -148,7 +153,7 @@ int EXAMPLES_CDECL main() { // Iterate over bytes in the int8 vector { - bsoncxx::vector::accessor vec(doc["vector_int8"].get_binary()); + accessor vec(doc["vector_int8"].get_binary()); std::cout << "int8 bytes: " << vec.byte_size() << std::hex << std::endl; for (auto i = vec.byte_begin(); i != vec.byte_end(); i++) { std::cout << int(*i) << " "; @@ -158,7 +163,7 @@ int EXAMPLES_CDECL main() { // Iterate over elements in the float32 vector { - bsoncxx::vector::accessor vec(doc["vector_float32"].get_binary()); + accessor vec(doc["vector_float32"].get_binary()); std::cout << "float32: " << vec.size() << std::endl; for (auto&& i : vec) { std::cout << i << " "; @@ -168,7 +173,7 @@ int EXAMPLES_CDECL main() { // Iterate over bytes in the float32 vector { - bsoncxx::vector::accessor vec(doc["vector_float32"].get_binary()); + accessor vec(doc["vector_float32"].get_binary()); std::cout << "float32 bytes: " << vec.byte_size() << std::hex << std::endl; for (auto i = vec.byte_begin(); i != vec.byte_end(); i++) { std::cout << int(*i) << " "; @@ -178,8 +183,7 @@ int EXAMPLES_CDECL main() { // Iterate over elements in the packed_bit vector { - bsoncxx::vector::accessor vec( - doc["vector_packed_bit"].get_binary()); + accessor vec(doc["vector_packed_bit"].get_binary()); std::cout << "packed_bit: " << vec.size() << std::endl; for (auto&& i : vec) { std::cout << i << " "; @@ -189,8 +193,7 @@ int EXAMPLES_CDECL main() { // Iterate over bytes in the packed_bit vector { - bsoncxx::vector::accessor vec( - doc["vector_packed_bit"].get_binary()); + accessor vec(doc["vector_packed_bit"].get_binary()); std::cout << "packed_bit bytes: " << vec.byte_size() << std::hex << std::endl; for (auto i = vec.byte_begin(); i != vec.byte_end(); i++) { std::cout << int(*i) << " "; From 87849b3dcba890c1f9038ba5ed94f4ca3379bc63 Mon Sep 17 00:00:00 2001 From: mdbmes Date: Thu, 27 Mar 2025 09:52:01 -0700 Subject: [PATCH 73/83] Update src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/types.hpp Co-authored-by: Ezra Chung <88335979+eramongodb@users.noreply.github.com> --- src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/types.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/types.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/types.hpp index d7e64664b0..4636ee1954 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/types.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/types.hpp @@ -79,7 +79,7 @@ enum class binary_sub_type : std::uint8_t { k_encrypted = 0x06, ///< Encrypted BSON value. k_column = 0x07, ///< Compressed BSON column. k_sensitive = 0x08, ///< Sensitive. - k_vector = 0x09, ///< BSON Binary Vector specification. + k_vector = 0x09, ///< BSON Binary Vector. k_user = 0x80, ///< User defined. }; From bb613969f937f26817319fb9b23f5a13e92ce234 Mon Sep 17 00:00:00 2001 From: mdbmes Date: Thu, 27 Mar 2025 10:00:19 -0700 Subject: [PATCH 74/83] Update src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/elements.hpp Co-authored-by: Ezra Chung <88335979+eramongodb@users.noreply.github.com> --- .../include/bsoncxx/v_noabi/bsoncxx/vector/elements.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/elements.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/elements.hpp index a8bd6410e0..e4799eaa56 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/elements.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/elements.hpp @@ -243,7 +243,9 @@ class packed_bit_byte { std::uint8_t mask; }; -/// packed_bit_byte is Swappable even when it's not an lvalue reference +/// Swap the referenced values for `a` and `b`. +/// +/// @note `packed_bit_byte` is a proxy reference and behaves like an lvalue reference. template void swap(packed_bit_byte a, packed_bit_byte b) noexcept { std::uint8_t a_value = a; From 3747aae6b87779f8c60ca513404448f6aa9cb3e3 Mon Sep 17 00:00:00 2001 From: mdbmes Date: Thu, 27 Mar 2025 10:02:12 -0700 Subject: [PATCH 75/83] Update src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/vector.cpp Co-authored-by: Ezra Chung <88335979+eramongodb@users.noreply.github.com> --- src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/vector.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/vector.cpp b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/vector.cpp index dee0f98fbc..442a519e28 100644 --- a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/vector.cpp +++ b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/vector.cpp @@ -29,6 +29,7 @@ namespace v_noabi { namespace vector { namespace detail { +// Equivalent to bson_vector_element_type_t. enum element_type : std::uint8_t { signed_integer = 0, unsigned_integer = 1, From 107b19263545afc811ae581f6bd61f337dabcccc Mon Sep 17 00:00:00 2001 From: mdbmes Date: Thu, 27 Mar 2025 10:02:47 -0700 Subject: [PATCH 76/83] Update src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/vector.cpp Co-authored-by: Ezra Chung <88335979+eramongodb@users.noreply.github.com> --- src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/vector.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/vector.cpp b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/vector.cpp index 442a519e28..8adc71e589 100644 --- a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/vector.cpp +++ b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/vector.cpp @@ -36,6 +36,7 @@ enum element_type : std::uint8_t { floating_point = 2, }; +// Equivalent to bson_vector_element_size_t. enum element_size : std::uint8_t { bits_1 = 0, bits_8 = 3, From f8ad45df66d88c80e4b867ea31d0a0ccce39f3a2 Mon Sep 17 00:00:00 2001 From: mdbmes Date: Thu, 27 Mar 2025 10:04:08 -0700 Subject: [PATCH 77/83] Update src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/detail.hpp Co-authored-by: Ezra Chung <88335979+eramongodb@users.noreply.github.com> --- src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/detail.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/detail.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/detail.hpp index 175029ed5f..7431d2c3b9 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/detail.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/detail.hpp @@ -14,6 +14,10 @@ #pragma once +#include + +// + #include #include #include From 73737dd02dfa808e0ce87fdec94531ad660ca4a3 Mon Sep 17 00:00:00 2001 From: mdbmes Date: Thu, 27 Mar 2025 10:05:20 -0700 Subject: [PATCH 78/83] Update src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/elements.hpp Co-authored-by: Ezra Chung <88335979+eramongodb@users.noreply.github.com> --- .../include/bsoncxx/v_noabi/bsoncxx/vector/elements.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/elements.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/elements.hpp index e4799eaa56..6b9662e78b 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/elements.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/elements.hpp @@ -14,6 +14,10 @@ #pragma once +#include + +// + #ifndef _WIN32 #include // Endian detection #endif From 14019ab53aadcca5bd3317b9a829f806fc19c24f Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Thu, 27 Mar 2025 10:35:46 -0700 Subject: [PATCH 79/83] Add accessor::as_const --- .../bsoncxx/v_noabi/bsoncxx/vector/accessor.hpp | 11 +++++++++-- .../include/bsoncxx/v_noabi/bsoncxx/vector/detail.hpp | 6 +++++- src/bsoncxx/test/vector.cpp | 9 +++++++++ 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/accessor.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/accessor.hpp index 77373df218..40bdd951be 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/accessor.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/accessor.hpp @@ -154,14 +154,20 @@ class accessor { typename format_traits::const_byte_iterator, typename format_traits::byte_iterator>::type; - /// @brief Construct a const Vector accessor by validating a bsoncxx::v_noabi::types::b_binary reference. + /// @brief Construct a const vector accessor by validating a bsoncxx::v_noabi::types::b_binary reference. /// @param binary Non-owning reference to BSON binary data /// @throws bsoncxx::v_noabi::exception with bsoncxx::v_noabi::error_code::k_invalid_vector, if validation fails. /// - /// The Binary data is validated as a Vector of the templated Format. On success, an accessor is created which + /// The Binary data is validated as a vector of the templated Format. On success, an accessor is created which /// references the same data as the bsoncxx::v_noabi::types::b_binary pointer. accessor(types::b_binary const& binary) : _data((format::validate(binary), binary)) {} + /// Obtain a const version of this vector accessor, without re-validating the vector data. + constexpr accessor as_const() const noexcept { + // Erase the template parameter from accessor_data to allow conversion from possibly-not-const to const. + return {{_data.bytes, _data.size, _data.header_copy}}; + } + /// Count the bytes of element data, not including any headers constexpr byte_count_type byte_size() const noexcept { return _data.size - byte_count_type(detail::header_size); @@ -325,6 +331,7 @@ class accessor { private: friend class bsoncxx::v_noabi::builder::basic::sub_binary; + friend class accessor::type>; accessor(detail::accessor_data data) noexcept : _data(data) {} diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/detail.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/detail.hpp index 7431d2c3b9..c2a8b1484a 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/detail.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/detail.hpp @@ -54,7 +54,11 @@ struct accessor_data { // Construct accessor_data around a b_binary that has already had its subtype and size validated. accessor_data(types::b_binary const& binary) : accessor_data(binary.bytes, binary.size) {} - // Construct accessor_data around binary data that has already been validated, and capture a header copy. + // Construct accessor_data with an existing header copy + accessor_data(byte_type* bytes, byte_count_type size, header header_copy) + : bytes(bytes), size(size), header_copy(header_copy) {} + + // Construct accessor_data around binary data that has already been validated, and capture a new header copy. accessor_data(byte_type* bytes, byte_count_type size) : bytes(bytes), size(size) { std::memcpy(header_copy.data(), bytes, header_size); } diff --git a/src/bsoncxx/test/vector.cpp b/src/bsoncxx/test/vector.cpp index 40172f1511..3dc87c7d3d 100644 --- a/src/bsoncxx/test/vector.cpp +++ b/src/bsoncxx/test/vector.cpp @@ -260,9 +260,13 @@ TEMPLATE_TEST_CASE( auto const element_unit = test_format_specific::element_unit(); iterator_operations(vec.begin(), vec.end(), std::ptrdiff_t(vec.size()), element_unit); + // Two ways of iterating as const BSONCXX_PRIVATE_WARNINGS_PUSH(); BSONCXX_PRIVATE_WARNINGS_DISABLE(GNU("-Wfloat-equal")); std::for_each(vec.cbegin(), vec.cend(), [&](auto const& value) { CHECK_FALSE(value == element_unit); }); + std::for_each(vec.as_const().begin(), vec.as_const().end(), [&](auto const& value) { + CHECK_FALSE(value == element_unit); + }); BSONCXX_PRIVATE_WARNINGS_POP(); })); types::b_binary const& binary = doc.view()["vector"].get_binary(); @@ -277,8 +281,13 @@ TEMPLATE_TEST_CASE( auto vec = sbin.allocate(TestType{}, 8000u); uint8_t const element_unit(1); iterator_operations(vec.byte_begin(), vec.byte_end(), std::ptrdiff_t(vec.byte_size()), element_unit); + + // Two ways of iterating as const std::for_each( vec.byte_cbegin(), vec.byte_cend(), [&](auto const& value) { CHECK_FALSE(value == element_unit); }); + std::for_each(vec.as_const().byte_begin(), vec.as_const().byte_end(), [&](auto const& value) { + CHECK_FALSE(value == element_unit); + }); })); types::b_binary const& binary = doc.view()["vector"].get_binary(); vector::accessor validate_encoded{binary}; From cfee0fb67eb8894b985f2b61bc4e799183a322cc Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Thu, 27 Mar 2025 18:20:47 -0700 Subject: [PATCH 80/83] Prefer {} initializers --- examples/bsoncxx/bson_binary_vector.cpp | 22 ++++++++--------- .../v_noabi/bsoncxx/builder/basic/impl.hpp | 6 ++--- .../bsoncxx/builder/basic/sub_binary.hpp | 2 +- .../v_noabi/bsoncxx/vector/accessor.hpp | 4 ++-- .../bsoncxx/v_noabi/bsoncxx/vector/detail.hpp | 8 +++---- .../v_noabi/bsoncxx/vector/elements.hpp | 8 +++---- .../v_noabi/bsoncxx/vector/iterators.hpp | 24 +++++++++---------- .../lib/bsoncxx/v_noabi/bsoncxx/vector.cpp | 2 +- src/bsoncxx/test/vector.cpp | 20 ++++++++-------- 9 files changed, 48 insertions(+), 48 deletions(-) diff --git a/examples/bsoncxx/bson_binary_vector.cpp b/examples/bsoncxx/bson_binary_vector.cpp index c0a85bfbd8..0a427cf9b9 100644 --- a/examples/bsoncxx/bson_binary_vector.cpp +++ b/examples/bsoncxx/bson_binary_vector.cpp @@ -108,7 +108,7 @@ int EXAMPLES_CDECL main() { // bsoncxx::v_noabi::vector::elements::packed_bit_element and an iterator // bsoncxx::v_noabi::vector::iterators::packed_bit_element. // - // Every bsoncxx::vector:accessor can be accessed either in per-element + // Every bsoncxx::vector::accessor can be accessed either in per-element // or per-byte mode. Byte mode is particularly useful for applications that // may want to use packed_bit vectors in the serialized format without // accessing individual elements. @@ -143,27 +143,27 @@ int EXAMPLES_CDECL main() { // Iterate over elements in the int8 vector { - accessor vec(doc["vector_int8"].get_binary()); + accessor vec{doc["vector_int8"].get_binary()}; std::cout << "int8: " << vec.size() << std::endl; for (auto&& i : vec) { - std::cout << int(i) << " "; + std::cout << int{i} << " "; } std::cout << std::endl; } // Iterate over bytes in the int8 vector { - accessor vec(doc["vector_int8"].get_binary()); + accessor vec{doc["vector_int8"].get_binary()}; std::cout << "int8 bytes: " << vec.byte_size() << std::hex << std::endl; for (auto i = vec.byte_begin(); i != vec.byte_end(); i++) { - std::cout << int(*i) << " "; + std::cout << int{*i} << " "; } std::cout << std::dec << std::endl; } // Iterate over elements in the float32 vector { - accessor vec(doc["vector_float32"].get_binary()); + accessor vec{doc["vector_float32"].get_binary()}; std::cout << "float32: " << vec.size() << std::endl; for (auto&& i : vec) { std::cout << i << " "; @@ -173,17 +173,17 @@ int EXAMPLES_CDECL main() { // Iterate over bytes in the float32 vector { - accessor vec(doc["vector_float32"].get_binary()); + accessor vec{doc["vector_float32"].get_binary()}; std::cout << "float32 bytes: " << vec.byte_size() << std::hex << std::endl; for (auto i = vec.byte_begin(); i != vec.byte_end(); i++) { - std::cout << int(*i) << " "; + std::cout << int{*i} << " "; } std::cout << std::dec << std::endl; } // Iterate over elements in the packed_bit vector { - accessor vec(doc["vector_packed_bit"].get_binary()); + accessor vec{doc["vector_packed_bit"].get_binary()}; std::cout << "packed_bit: " << vec.size() << std::endl; for (auto&& i : vec) { std::cout << i << " "; @@ -193,10 +193,10 @@ int EXAMPLES_CDECL main() { // Iterate over bytes in the packed_bit vector { - accessor vec(doc["vector_packed_bit"].get_binary()); + accessor vec{doc["vector_packed_bit"].get_binary()}; std::cout << "packed_bit bytes: " << vec.byte_size() << std::hex << std::endl; for (auto i = vec.byte_begin(); i != vec.byte_end(); i++) { - std::cout << int(*i) << " "; + std::cout << int{*i} << " "; } std::cout << std::dec << std::endl; } diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/impl.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/impl.hpp index 773b128033..a7c50ff812 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/impl.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/impl.hpp @@ -30,21 +30,21 @@ namespace impl { template detail::requires_t> generic_append(core* core, T&& func) { core->open_document(); - detail::invoke(std::forward(func), sub_document(core)); + detail::invoke(std::forward(func), sub_document{core}); core->close_document(); } template // placeholder 'void' for VS2015 compat detail::requires_t> generic_append(core* core, T&& func) { core->open_array(); - detail::invoke(std::forward(func), sub_array(core)); + detail::invoke(std::forward(func), sub_array{core}); core->close_array(); } template detail::requires_t> generic_append(core* core, T&& func) { // Opened by the user invoking `sub_binary::allocate()` in `func`. - detail::invoke(std::forward(func), sub_binary(core)); + detail::invoke(std::forward(func), sub_binary{core}); core->close_binary(); } diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/sub_binary.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/sub_binary.hpp index 5cd553a6db..f86162c29c 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/sub_binary.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/sub_binary.hpp @@ -42,7 +42,7 @@ class sub_binary { /// /// Default constructor /// - sub_binary(core* core) : _core(core) {} + sub_binary(core* core) : _core{core} {} /// @brief Allocate space for an un-initialized BSON Binary element of any subtype. /// @param sub_type BSON binary subtype code, identifying the format of the data within. diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/accessor.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/accessor.hpp index 40bdd951be..8bb3283403 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/accessor.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/accessor.hpp @@ -160,7 +160,7 @@ class accessor { /// /// The Binary data is validated as a vector of the templated Format. On success, an accessor is created which /// references the same data as the bsoncxx::v_noabi::types::b_binary pointer. - accessor(types::b_binary const& binary) : _data((format::validate(binary), binary)) {} + accessor(types::b_binary const& binary) : _data{(format::validate(binary), binary)} {} /// Obtain a const version of this vector accessor, without re-validating the vector data. constexpr accessor as_const() const noexcept { @@ -333,7 +333,7 @@ class accessor { friend class bsoncxx::v_noabi::builder::basic::sub_binary; friend class accessor::type>; - accessor(detail::accessor_data data) noexcept : _data(data) {} + accessor(detail::accessor_data data) noexcept : _data{data} {} detail::accessor_data _data; }; diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/detail.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/detail.hpp index c2a8b1484a..5da014a32d 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/detail.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/detail.hpp @@ -52,14 +52,14 @@ struct accessor_data { header header_copy; // Construct accessor_data around a b_binary that has already had its subtype and size validated. - accessor_data(types::b_binary const& binary) : accessor_data(binary.bytes, binary.size) {} + accessor_data(types::b_binary const& binary) : accessor_data{binary.bytes, binary.size} {} // Construct accessor_data with an existing header copy accessor_data(byte_type* bytes, byte_count_type size, header header_copy) - : bytes(bytes), size(size), header_copy(header_copy) {} + : bytes{bytes}, size{size}, header_copy{header_copy} {} // Construct accessor_data around binary data that has already been validated, and capture a new header copy. - accessor_data(byte_type* bytes, byte_count_type size) : bytes(bytes), size(size) { + accessor_data(byte_type* bytes, byte_count_type size) : bytes{bytes}, size{size} { std::memcpy(header_copy.data(), bytes, header_size); } }; @@ -148,7 +148,7 @@ struct format_traits : format_traits_base { using element_difference_type = iterator::difference_type; static std::size_t element_count(std::uint32_t binary_data_length, header hdr) noexcept { - return std::size_t(binary_data_length - header_size) * std::size_t(8u) - std::size_t(hdr[1] & 7u); + return std::size_t{binary_data_length - header_size} * std::size_t{8u} - std::size_t{hdr[1] & 7u}; } static byte_iterator make_byte_iterator(iterator element, iterator element_end) noexcept { diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/elements.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/elements.hpp index 6b9662e78b..5e2030a49a 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/elements.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/elements.hpp @@ -123,7 +123,7 @@ class packed_bit_element { /// Copy the referenced value from another reference of the same type packed_bit_element const& operator=(packed_bit_element const& v) const noexcept { - return *this = value_type(v); + return *this = value_type{v}; } /// Operator ^=, emulating bool reference behavior @@ -147,7 +147,7 @@ class packed_bit_element { friend class iterators::packed_bit_element; constexpr packed_bit_element(Iterator byte_iter, uint8_t bit_index) noexcept - : byte(byte_iter), mask(uint8_t(0x80u >> bit_index)) {} + : byte{byte_iter}, mask{uint8_t(0x80u >> bit_index)} {} Iterator byte; std::uint8_t mask; @@ -236,12 +236,12 @@ class packed_bit_byte { return *this = *this >> other; } - constexpr packed_bit_byte(packed_bit_byte const& other) : byte(other.byte), mask(other.mask) {} + constexpr packed_bit_byte(packed_bit_byte const& other) : byte{other.byte}, mask{other.mask} {} private: friend class iterators::packed_bit_byte; - constexpr packed_bit_byte(Iterator byte_iter, uint8_t byte_mask) noexcept : byte(byte_iter), mask(byte_mask) {} + constexpr packed_bit_byte(Iterator byte_iter, uint8_t byte_mask) noexcept : byte{byte_iter}, mask{byte_mask} {} Iterator byte; std::uint8_t mask; diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/iterators.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/iterators.hpp index ced501205c..5ac75df790 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/iterators.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/iterators.hpp @@ -96,7 +96,7 @@ class packed_bit_element { /// If the iterator goes out of range, behavior is undefined. constexpr packed_bit_element operator+(difference_type const& other) const noexcept { return { - byte + ((other >> 3) + ((difference_type(bit) + (other & 7)) >> 3)), + byte + ((other >> 3) + ((difference_type{bit} + (other & 7)) >> 3)), std::uint8_t((bit + unsigned(other)) & 7u)}; } @@ -110,7 +110,7 @@ class packed_bit_element { /// @brief Calculate the difference in position between two bit iterators /// If the two iterators do not point into the same vector, behavior is undefined. constexpr difference_type operator-(packed_bit_element const& other) const noexcept { - return {(byte - other.byte) * 8 + (difference_type(bit) - difference_type(other.bit))}; + return {(byte - other.byte) * 8 + (difference_type{bit} - difference_type{other.bit})}; } /// Advance this iterator forward by the indicated number of bits @@ -125,12 +125,12 @@ class packed_bit_element { /// Pre-increment packed_bit_element& operator++() noexcept { - return *this += difference_type(1); + return *this += difference_type{1}; } /// Pre-decrement packed_bit_element& operator--() noexcept { - return *this -= difference_type(1); + return *this -= difference_type{1}; } /// Post-increment @@ -153,7 +153,7 @@ class packed_bit_element { friend class accessor; constexpr packed_bit_element(Iterator byte_iter, std::uint8_t bit_index = 0) noexcept - : byte(byte_iter), bit(bit_index) {} + : byte{byte_iter}, bit{bit_index} {} Iterator byte; std::uint8_t bit; @@ -184,7 +184,7 @@ class packed_bit_byte { /// @brief Dereference the byte iterator /// @return A bsoncxx::v_noabi::elements::packed_bit_byte that can be used like a byte reference. constexpr reference operator*() const noexcept { - return {byte, (byte + 1) == byte_end ? last_byte_mask : value_type(0xFFu)}; + return {byte, (byte + 1) == byte_end ? last_byte_mask : value_type{0xFFu}}; } /// Compare two byte iterators @@ -249,12 +249,12 @@ class packed_bit_byte { /// Pre-increment packed_bit_byte& operator++() noexcept { - return *this += difference_type(1); + return *this += difference_type{1}; } /// Pre-decrement packed_bit_byte& operator--() noexcept { - return *this -= difference_type(1); + return *this -= difference_type{1}; } /// Post-increment @@ -276,12 +276,12 @@ class packed_bit_byte { friend struct detail::format_traits; constexpr packed_bit_byte(packed_bit_element element, packed_bit_element element_end) - : byte(element.byte), - byte_end((element_end + 7u).byte), - last_byte_mask(value_type(0xFFu << (-element_end.bit & 7u))) {} + : byte{element.byte}, + byte_end{(element_end + 7u).byte}, + last_byte_mask{value_type(0xFFu << (-element_end.bit & 7u))} {} constexpr packed_bit_byte(Iterator byte, Iterator byte_end, value_type last_byte_mask) - : byte(byte), byte_end(byte_end), last_byte_mask(last_byte_mask) {} + : byte{byte}, byte_end{byte_end}, last_byte_mask{last_byte_mask} {} Iterator byte; Iterator byte_end; diff --git a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/vector.cpp b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/vector.cpp index 8adc71e589..4f39c448b9 100644 --- a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/vector.cpp +++ b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/vector.cpp @@ -100,7 +100,7 @@ void f_packed_bit::write_frame(std::uint8_t* binary_data, std::uint32_t binary_d detail::make_header( detail::element_type::unsigned_integer, detail::element_size::bits_1, - std::uint8_t(std::size_t(7u) & -element_count))); + std::uint8_t(std::size_t{7u} & -element_count))); } void formats::f_int8::validate(types::b_binary const& binary) { diff --git a/src/bsoncxx/test/vector.cpp b/src/bsoncxx/test/vector.cpp index 3dc87c7d3d..02be047baf 100644 --- a/src/bsoncxx/test/vector.cpp +++ b/src/bsoncxx/test/vector.cpp @@ -218,7 +218,7 @@ TEMPLATE_TEST_CASE( binary_sub_type::k_binary, binary_sub_type::k_encrypted, binary_sub_type::k_uuid, binary_sub_type::k_user); types::b_binary const binary{invalid_type, bytes.size(), bytes.data()}; CHECK_THROWS_WITH_CODE( - vector::accessor(binary), bsoncxx::v_noabi::error_code::k_invalid_vector); + vector::accessor{binary}, bsoncxx::v_noabi::error_code::k_invalid_vector); } SECTION("reject binary data that's too short to include a header") { @@ -227,7 +227,7 @@ TEMPLATE_TEST_CASE( REQUIRE(bytes.size() >= bytes_to_remove); types::b_binary const binary{binary_sub_type::k_vector, uint32_t(bytes.size() - bytes_to_remove), bytes.data()}; CHECK_THROWS_WITH_CODE( - vector::accessor(binary), bsoncxx::v_noabi::error_code::k_invalid_vector); + vector::accessor{binary}, bsoncxx::v_noabi::error_code::k_invalid_vector); } SECTION("reject empty vectors with any modified header bits") { @@ -236,7 +236,7 @@ TEMPLATE_TEST_CASE( bytes[bit_index >> 3u] ^= std::uint8_t(1u << (bit_index & 7u)); types::b_binary const binary{binary_sub_type::k_vector, bytes.size(), bytes.data()}; CHECK_THROWS_WITH_CODE( - vector::accessor(binary), bsoncxx::v_noabi::error_code::k_invalid_vector); + vector::accessor{binary}, bsoncxx::v_noabi::error_code::k_invalid_vector); } } @@ -406,7 +406,7 @@ TEST_CASE("vector accessor float32", "[bsoncxx::vector::accessor]") { auto invalid_length = GENERATE(0u, 1u, 3u, 4u, 5u, 7u, 8u, 9u); types::b_binary const binary{binary_sub_type::k_vector, uint32_t(invalid_length), bytes}; CHECK_THROWS_WITH_CODE( - vector::accessor(binary), bsoncxx::v_noabi::error_code::k_invalid_vector); + vector::accessor{binary}, bsoncxx::v_noabi::error_code::k_invalid_vector); } SECTION("rejects binary data from other vector formats") { @@ -415,7 +415,7 @@ TEST_CASE("vector accessor float32", "[bsoncxx::vector::accessor]") { format_specific::bytes_empty()); types::b_binary const binary{binary_sub_type::k_vector, bytes.size(), bytes.data()}; CHECK_THROWS_WITH_CODE( - vector::accessor(binary), bsoncxx::v_noabi::error_code::k_invalid_vector); + vector::accessor{binary}, bsoncxx::v_noabi::error_code::k_invalid_vector); } SECTION("accepts and correctly decodes elements with infinite value") { @@ -445,7 +445,7 @@ TEST_CASE("vector accessor int8_t", "[bsoncxx::vector::accessor]") { format_specific::bytes_empty()); types::b_binary const binary{binary_sub_type::k_vector, bytes.size(), bytes.data()}; CHECK_THROWS_WITH_CODE( - vector::accessor(binary), bsoncxx::v_noabi::error_code::k_invalid_vector); + vector::accessor{binary}, bsoncxx::v_noabi::error_code::k_invalid_vector); } } @@ -456,7 +456,7 @@ TEST_CASE("vector accessor packed_bit", "[bsoncxx::vector::accessor]") { bytes[1] = uint8_t(byte_value); types::b_binary const binary{binary_sub_type::k_vector, bytes.size(), bytes.data()}; CHECK_THROWS_WITH_CODE( - vector::accessor(binary), + vector::accessor{binary}, bsoncxx::v_noabi::error_code::k_invalid_vector); } } @@ -466,7 +466,7 @@ TEST_CASE("vector accessor packed_bit", "[bsoncxx::vector::accessor]") { uint8_t const bytes[] = {0x10, uint8_t(byte_value), 0x00}; types::b_binary const binary{binary_sub_type::k_vector, sizeof bytes, bytes}; CHECK_THROWS_WITH_CODE( - vector::accessor(binary), + vector::accessor{binary}, bsoncxx::v_noabi::error_code::k_invalid_vector); } } @@ -476,7 +476,7 @@ TEST_CASE("vector accessor packed_bit", "[bsoncxx::vector::accessor]") { uint8_t bytes[] = {0x10, uint8_t(byte_value), 0xff}; types::b_binary const binary{binary_sub_type::k_vector, sizeof bytes, bytes}; CHECK_THROWS_WITH_CODE( - vector::accessor(binary), + vector::accessor{binary}, bsoncxx::v_noabi::error_code::k_invalid_vector); // Succeeds when unused bits are then zeroed bytes[2] = 0; @@ -534,7 +534,7 @@ TEST_CASE("vector accessor packed_bit", "[bsoncxx::vector::accessor]") { format_specific::bytes_empty()); types::b_binary const binary{binary_sub_type::k_vector, bytes.size(), bytes.data()}; CHECK_THROWS_WITH_CODE( - vector::accessor(binary), + vector::accessor{binary}, bsoncxx::v_noabi::error_code::k_invalid_vector); } From e66887d7c66929cfbad3f766db4ab7067fc23613 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Tue, 1 Apr 2025 13:31:40 -0700 Subject: [PATCH 81/83] Add test for swap() --- src/bsoncxx/test/vector.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/bsoncxx/test/vector.cpp b/src/bsoncxx/test/vector.cpp index 02be047baf..458e091b79 100644 --- a/src/bsoncxx/test/vector.cpp +++ b/src/bsoncxx/test/vector.cpp @@ -153,6 +153,19 @@ void iterator_operations( std::sort(begin, end); std::for_each(begin, end, [&](auto const& value) { CHECK(value == element_unit); }); + // Verify ADL chooses our swap() even when std::swap is in scope + *begin = Element{0}; + CHECK(*begin < *(end - 1)); + CHECK_FALSE(*(end - 1) < *begin); + { + using std::swap; + swap(*begin, *(end - 1)); + } + CHECK(*(end - 1) < *begin); + CHECK_FALSE(*begin < *(end - 1)); + *begin = element_unit; + + // Sort, check that a 0 moves from the back to the front. *(end - 1) = Element{0}; std::sort(begin, end); CHECK(*begin == Element{0}); From 9872b74a5c80d9ecb7ab6366f0378ef13105df41 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Tue, 1 Apr 2025 13:59:57 -0700 Subject: [PATCH 82/83] Portability: replace arithmetic right shift with signed division --- .../include/bsoncxx/v_noabi/bsoncxx/vector/iterators.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/iterators.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/iterators.hpp index 5ac75df790..487cbc726c 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/iterators.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/iterators.hpp @@ -96,8 +96,8 @@ class packed_bit_element { /// If the iterator goes out of range, behavior is undefined. constexpr packed_bit_element operator+(difference_type const& other) const noexcept { return { - byte + ((other >> 3) + ((difference_type{bit} + (other & 7)) >> 3)), - std::uint8_t((bit + unsigned(other)) & 7u)}; + byte + ((difference_type{bit} + other - ((difference_type{bit} + other) & 7)) / 8), + std::uint8_t((difference_type{bit} + other) & 7)}; } /// @brief Calculate a signed subtraction of a ptrdiff_t from this iterator, moving it backward or forward the From 4b87eb06d959708d6f22789bf6f2c001018c7f5a Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Tue, 1 Apr 2025 14:01:29 -0700 Subject: [PATCH 83/83] Clarify test name --- src/bsoncxx/test/vector.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bsoncxx/test/vector.cpp b/src/bsoncxx/test/vector.cpp index 458e091b79..38c2d27c5b 100644 --- a/src/bsoncxx/test/vector.cpp +++ b/src/bsoncxx/test/vector.cpp @@ -474,7 +474,7 @@ TEST_CASE("vector accessor packed_bit", "[bsoncxx::vector::accessor]") { } } - SECTION("rejects nonempty vectors with reserved bits set in header padding byte") { + SECTION("rejects nonempty vectors with reserved values in header padding byte") { for (unsigned byte_value = 8u; byte_value <= UINT8_MAX; byte_value++) { uint8_t const bytes[] = {0x10, uint8_t(byte_value), 0x00}; types::b_binary const binary{binary_sub_type::k_vector, sizeof bytes, bytes};