diff --git a/src/bsoncxx/include/bsoncxx/v1/oid.hpp b/src/bsoncxx/include/bsoncxx/v1/oid.hpp index 129876c0af..77ff574f79 100644 --- a/src/bsoncxx/include/bsoncxx/v1/oid.hpp +++ b/src/bsoncxx/include/bsoncxx/v1/oid.hpp @@ -189,6 +189,13 @@ class oid { friend std::error_code make_error_code(errc v) { return {static_cast(v), error_category()}; } + + class internal; + + private: + struct for_overwrite_tag {}; + + /* explicit(false) */ oid(for_overwrite_tag) : _bytes{} {} }; } // namespace v1 diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/array/element-fwd.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/array/element-fwd.hpp index 21d6f78394..54984beb89 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/array/element-fwd.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/array/element-fwd.hpp @@ -14,6 +14,8 @@ #pragma once +#include + #include namespace bsoncxx { @@ -29,7 +31,7 @@ class element; namespace bsoncxx { namespace array { -using ::bsoncxx::v_noabi::array::element; +using v_noabi::array::element; } // namespace array } // namespace bsoncxx @@ -40,3 +42,6 @@ using ::bsoncxx::v_noabi::array::element; /// @file /// Declares @ref bsoncxx::v_noabi::array::element. /// +/// @par Includes +/// - @ref bsoncxx/v1/element/view-fwd.hpp +/// diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/array/element.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/array/element.hpp index c5e971b750..79921b2b16 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/array/element.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/array/element.hpp @@ -14,10 +14,15 @@ #pragma once +#include + +// + +#include + #include #include -#include #include #include @@ -36,50 +41,41 @@ namespace array { /// interrogated by calling type() and a specific value can be extracted through /// get_X() accessors. /// -class element : private document::element { +class element : private v_noabi::document::element { public: - BSONCXX_ABI_EXPORT_CDECL() element(); - - using document::element::operator bool; - - using document::element::type; - - using document::element::get_array; - using document::element::get_binary; - using document::element::get_bool; - using document::element::get_code; - using document::element::get_codewscope; - using document::element::get_date; - using document::element::get_dbpointer; - using document::element::get_decimal128; - using document::element::get_document; - using document::element::get_double; - using document::element::get_int32; - using document::element::get_int64; - using document::element::get_maxkey; - using document::element::get_minkey; - using document::element::get_null; - using document::element::get_oid; - using document::element::get_regex; - using document::element::get_string; - using document::element::get_symbol; - using document::element::get_timestamp; - using document::element::get_undefined; - - using document::element::get_value; - - using document::element::operator[]; - - using document::element::key; - using document::element::keylen; - using document::element::length; - using document::element::offset; - using document::element::raw; - - private: - friend ::bsoncxx::v_noabi::array::view; - - explicit element(std::uint8_t const* raw, std::uint32_t length, std::uint32_t offset, std::uint32_t keylen); + element() : v_noabi::document::element() {} + + /* explicit(false) */ element(v1::element::view const& v) : v_noabi::document::element{v} {} + + using v_noabi::document::element::operator v1::element::view; + + using v_noabi::document::element::operator bool; + + using v_noabi::document::element::raw; + + using v_noabi::document::element::length; + + using v_noabi::document::element::offset; + + using v_noabi::document::element::keylen; + + using v_noabi::document::element::type; + + using v_noabi::document::element::key; + +#pragma push_macro("X") +#undef X +#define X(_name, _value) using v_noabi::document::element::get_##_name; + BSONCXX_V1_TYPES_XMACRO(X) +#pragma pop_macro("X") + + using v_noabi::document::element::get_value; + + using v_noabi::document::element::get_owning_value; + + using v_noabi::document::element::operator[]; + + friend bool operator==(element const& lhs, v_noabi::types::bson_value::view const& rhs); }; /// @@ -90,16 +86,24 @@ class element : private document::element { /// @{ /// @relatesalso bsoncxx::v_noabi::array::element -BSONCXX_ABI_EXPORT_CDECL(bool) operator==(element const& elem, types::bson_value::view const& v); +inline bool operator==(element const& lhs, v_noabi::types::bson_value::view const& rhs) { + return static_cast(lhs) == rhs; +} /// @relatesalso bsoncxx::v_noabi::array::element -BSONCXX_ABI_EXPORT_CDECL(bool) operator==(types::bson_value::view const& v, element const& elem); +inline bool operator==(v_noabi::types::bson_value::view const& lhs, element const& rhs) { + return rhs == lhs; +} /// @relatesalso bsoncxx::v_noabi::array::element -BSONCXX_ABI_EXPORT_CDECL(bool) operator!=(element const& elem, types::bson_value::view const& v); +inline bool operator!=(element const& lhs, v_noabi::types::bson_value::view const& rhs) { + return !(lhs == rhs); +} /// @relatesalso bsoncxx::v_noabi::array::element -BSONCXX_ABI_EXPORT_CDECL(bool) operator!=(types::bson_value::view const& v, element const& elem); +inline bool operator!=(v_noabi::types::bson_value::view const& lhs, element const& rhs) { + return !(lhs == rhs); +} /// @} /// @@ -108,11 +112,29 @@ BSONCXX_ABI_EXPORT_CDECL(bool) operator!=(types::bson_value::view const& v, elem } // namespace v_noabi } // namespace bsoncxx +namespace bsoncxx { +namespace v_noabi { + +// Ambiguous whether `v1::element::view` should be converted to `v_noabi::array::element` or +// `v_noabi::document::element.` Require users to explicitly cast to the expected type instead. +// +// v_noabi::array::element from_v1(v1::element::view const& v); + +/// +/// Convert to the @ref bsoncxx::v1 equivalent of `v`. +/// +inline v1::element::view to_v1(v_noabi::array::element const& v) { + return v1::element::view{v}; +} + +} // namespace v_noabi +} // namespace bsoncxx + namespace bsoncxx { namespace array { -using ::bsoncxx::v_noabi::array::operator==; -using ::bsoncxx::v_noabi::array::operator!=; +using v_noabi::array::operator==; +using v_noabi::array::operator!=; } // namespace array } // namespace bsoncxx @@ -123,3 +145,7 @@ using ::bsoncxx::v_noabi::array::operator!=; /// @file /// Provides @ref bsoncxx::v_noabi::array::element. /// +/// @par Includes +/// - @ref bsoncxx/document/element.hpp +/// - @ref bsoncxx/v1/element/view.hpp +/// diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/array/value-fwd.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/array/value-fwd.hpp index 8c9c63ed00..d3a2addea8 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/array/value-fwd.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/array/value-fwd.hpp @@ -14,6 +14,8 @@ #pragma once +#include + #include namespace bsoncxx { @@ -29,7 +31,7 @@ class value; namespace bsoncxx { namespace array { -using ::bsoncxx::v_noabi::array::value; +using v_noabi::array::value; } // namespace array } // namespace bsoncxx @@ -40,3 +42,6 @@ using ::bsoncxx::v_noabi::array::value; /// @file /// Declares @ref bsoncxx::v_noabi::array::value. /// +/// @par Includes +/// - @ref bsoncxx/v1/array/value-fwd.hpp +/// diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/array/value.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/array/value.hpp index 2fa6131b05..9d8a3eed5a 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/array/value.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/array/value.hpp @@ -14,11 +14,15 @@ #pragma once +#include + +// + +#include + #include #include -#include - #include #include @@ -35,34 +39,69 @@ namespace array { /// should be used sparingly; array::view should be used instead wherever possible. /// class value { + private: + v1::array::value _value; + std::size_t _length; + public: + /// @copydoc v_noabi::document::value::deleter_type using deleter_type = void(BSONCXX_ABI_CDECL*)(std::uint8_t*); + + /// @copydoc v_noabi::document::value::unique_ptr_type using unique_ptr_type = std::unique_ptr; + /// @copydoc v_noabi::document::value::const_iterator + using const_iterator = v_noabi::array::view::const_iterator; + + /// @copydoc v_noabi::document::value::iterator + using iterator = const_iterator; + + ~value() = default; + + value(value&&) = default; + value& operator=(value&&) = default; + + value(value const& other) : value{other.view()} {} + + value& operator=(value const& other) { + *this = value{other.view()}; + return *this; + } + /// /// Constructs a value from a buffer. + /// /// This constructor transfers ownership of the buffer to the resulting /// value. A user-provided deleter is used to destroy the buffer. /// + /// @warning For backward compatibility, `length` is NOT validated. When `length` is inconsistent with the embedded + /// length as indicated by the BSON bytes, the BSON bytes may be parsed as "invalid" despite the BSON bytes + /// themselves being valid. + /// /// @param data /// A pointer to a buffer containing a valid BSON array. /// @param length /// The length of the document. - /// @param dtor + /// @param deleter /// A user provided deleter. /// - BSONCXX_ABI_EXPORT_CDECL() value(std::uint8_t* data, std::size_t length, deleter_type dtor); + value(std::uint8_t* data, std::size_t length, deleter_type deleter) + : _value{data, std::move(deleter)}, _length{length} {} /// /// Constructs a value from a std::unique_ptr to a buffer. The ownership /// of the buffer is transferred to the resulting value. /// + /// @warning For backward compatibility, `length` is NOT validated. When `length` is inconsistent with the embedded + /// length as indicated by the BSON bytes, the BSON bytes may be parsed as "invalid" despite the BSON bytes + /// themselves being valid. + /// /// @param ptr /// A pointer to a buffer containing a valid BSON array. /// @param length /// The length of the document. /// - BSONCXX_ABI_EXPORT_CDECL() value(unique_ptr_type ptr, std::size_t length); + value(unique_ptr_type ptr, std::size_t length) : _value{std::move(ptr)}, _length{length} {} /// /// Constructs a value from a view of an array. The data referenced @@ -72,19 +111,107 @@ class value { /// @param view /// A view of another array to copy. /// - explicit BSONCXX_ABI_EXPORT_CDECL() value(array::view view); + explicit BSONCXX_ABI_EXPORT_CDECL() value(v_noabi::array::view view); - BSONCXX_ABI_EXPORT_CDECL() value(value const&); - BSONCXX_ABI_EXPORT_CDECL(value&) operator=(value const&); + /// + /// Convert to the @ref bsoncxx::v1 equivalent. + /// + /// @par Preconditions: + /// - If `this->data()` is not null, the size of the storage region pointed to by `data` must be greater than or + /// equal to 5. + /// - The "total number of bytes comprising the document" as indicated by the BSON bytes pointed-to by + /// `this->data()` must be less than or equal to the size of the storage region pointed to by `data`. + /// + /// @note `this->size()` is ignored. + /// + explicit operator v1::array::value() const& { + return _value; + } - value(value&&) = default; - value& operator=(value&&) = default; + /// + /// Convert to the @ref bsoncxx::v1 equivalent. + /// + /// @par Preconditions: + /// - If `this->data()` is not null, the size of the storage region pointed to by `data` must be greater than or + /// equal to 5. + /// - The "total number of bytes comprising the document" as indicated by the BSON bytes pointed-to by + /// `this->data()` must be less than or equal to the size of the storage region pointed to by `data`. + /// + /// @note `this->size()` is ignored. + /// + explicit operator v1::array::value() && { + _length = 0u; + return std::move(_value); + } + + /// + /// @returns A const_iterator to the first element of the array. + /// + const_iterator cbegin() const { + return this->view().cbegin(); + } + + /// + /// @returns A const_iterator to the past-the-end element of the array. + /// + const_iterator cend() const { + return this->view().cend(); + } + + /// + /// @returns A const_iterator to the first element of the array. + /// + const_iterator begin() const { + return this->view().begin(); + } + + /// + /// @returns A const_iterator to the past-the-end element of the array. + /// + const_iterator end() const { + return this->view().end(); + } + + /// @copydoc bsoncxx::v_noabi::array::view::find(std::uint32_t i) const + const_iterator find(std::uint32_t i) const { + return const_iterator{*_value.view().find(i)}; + } + + /// @copydoc bsoncxx::v_noabi::array::view::operator[](std::uint32_t i) const + v_noabi::document::element operator[](std::uint32_t i) const { + return _value.operator[](i); + } + + /// @copydoc bsoncxx::v_noabi::array::view::data() const + std::uint8_t const* data() const { + return _value.data(); + } + + /// @copydoc bsoncxx::v_noabi::array::view::size() const + std::size_t size() const { + return _length; // Do NOT use _value.size(). + } + /// @copydoc bsoncxx::v_noabi::array::view::length() const + std::size_t length() const { + return _length; // Do NOT use _value.length(). + } + + /// + /// Return true when `this->length() == 5`. /// - /// Get a view over the document owned by this value. + /// @warning For backward compatibility, this function does NOT check if the underlying BSON bytes represent a valid + /// empty document. /// - array::view view() const noexcept { - return array::view{static_cast(_data.get()), _length}; + bool empty() const { + return _length == 5; // Do NOT use _value.empty(). + } + + /// + /// Get a view over the array owned by this value. + /// + v_noabi::array::view view() const noexcept { + return {_value.data(), _length}; } /// @@ -92,8 +219,8 @@ class value { /// /// @return A view over the value. /// - operator array::view() const noexcept { - return view(); + /* explicit(false) */ operator v_noabi::array::view() const noexcept { + return this->view(); } /// @@ -105,17 +232,57 @@ class value { /// /// @return A std::unique_ptr with ownership of the buffer. /// - BSONCXX_ABI_EXPORT_CDECL(unique_ptr_type) release(); + unique_ptr_type release() { + auto ptr = _value.release(); - private: - unique_ptr_type _data; - std::size_t _length{0}; + // Invariant: the underlying deleter type MUST be `deleter_type`. + auto const deleter_ptr = ptr.get_deleter().target(); + + // Invariant: `ptr` implies `deleter_ptr`, but not the reverse. + return {ptr.release(), deleter_ptr ? *deleter_ptr : nullptr}; + } + + /// + /// Replace the formerly-owned buffer with the new view. + /// This will make a copy of the passed-in view. + /// + void reset(v_noabi::array::view view) { + _value.reset(to_v1(view)); + } }; } // namespace array } // namespace v_noabi } // namespace bsoncxx +namespace bsoncxx { +namespace v_noabi { + +/// +/// Convert from the @ref bsoncxx::v1 equivalent of `v`. +/// +inline v_noabi::array::value from_v1(v1::array::value const& v) { + return v_noabi::array::value{from_v1(v.view())}; +} + +/// +/// Convert from the @ref bsoncxx::v1 equivalent of `v`. +/// +/// @throws bsoncxx::v_noabi::exception with bsoncxx::v_noabi::error_code::k_invalid_deleter_type if the type of the +/// deleter for `value` is not @ref bsoncxx::v_noabi::array::value::deleter_type. +/// +BSONCXX_ABI_EXPORT_CDECL(v_noabi::array::value) from_v1(v1::array::value&& v); + +/// +/// Convert to the @ref bsoncxx::v1 equivalent of `v`. +/// +inline v1::array::value to_v1(v_noabi::array::value v) { + return v1::array::value{std::move(v)}; +} + +} // namespace v_noabi +} // namespace bsoncxx + #include /// diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/array/view-fwd.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/array/view-fwd.hpp index a34798fe56..7854e695b9 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/array/view-fwd.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/array/view-fwd.hpp @@ -14,6 +14,8 @@ #pragma once +#include + #include namespace bsoncxx { @@ -29,7 +31,7 @@ class view; namespace bsoncxx { namespace array { -using ::bsoncxx::v_noabi::array::view; +using v_noabi::array::view; } // namespace array } // namespace bsoncxx @@ -40,3 +42,6 @@ using ::bsoncxx::v_noabi::array::view; /// @file /// Declares @ref bsoncxx::v_noabi::array::view. /// +/// @par Includes +/// - @ref bsoncxx/v1/array/view-fwd.hpp +/// diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/array/view.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/array/view.hpp index 63a88d4eaf..599b2804d7 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/array/view.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/array/view.hpp @@ -14,11 +14,16 @@ #pragma once +#include + +// + +#include + #include #include #include -#include #include #include @@ -34,29 +39,54 @@ namespace array { /// A read-only, non-owning view of a BSON document. /// class view { + private: + v_noabi::document::view _view; + public: class const_iterator; - using iterator = const_iterator; /// - /// @returns A const_iterator to the first element of the array. + /// Equivalent to @ref const_iterator. /// - BSONCXX_ABI_EXPORT_CDECL(const_iterator) cbegin() const; + using iterator = const_iterator; + + /// @copydoc bsoncxx::v_noabi::document::view::view() + view() = default; /// - /// @returns A const_iterator to the past-the-end element of the array. + /// Construct with the @ref bsoncxx::v1 equivalent. /// - BSONCXX_ABI_EXPORT_CDECL(const_iterator) cend() const; + /* explicit(false) */ view(v1::array::view const& v) : _view{v} {} + + /// @copydoc bsoncxx::v_noabi::document::view::view(std::uint8_t const* data, std::size_t length) + view(std::uint8_t const* data, std::size_t length) : _view{data, length} {} /// - /// @returns A const_iterator to the first element of the array. + /// Convert to the @ref bsoncxx::v1 equivalent. /// - BSONCXX_ABI_EXPORT_CDECL(const_iterator) begin() const; - + /// @par Preconditions: + /// - If `this->data()` is not null, the size of the storage region pointed to by `data` must be greater than or + /// equal to 5. + /// - The "total number of bytes comprising the document" as indicated by the BSON bytes pointed-to by + /// `this->data()` must be less than or equal to the size of the storage region pointed to by `data`. /// - /// @returns A const_iterator to the past-the-end element of the array. + /// @note `this->size()` is ignored. /// - BSONCXX_ABI_EXPORT_CDECL(const_iterator) end() const; + explicit operator v1::array::view() const { + return v1::array::view{_view.data()}; + } + + /// @copydoc bsoncxx::v_noabi::document::view::cbegin() const + BSONCXX_ABI_EXPORT_CDECL(const_iterator) cbegin() const; + + /// @copydoc bsoncxx::v_noabi::document::view::cend() const + const_iterator cend() const; + + /// @copydoc bsoncxx::v_noabi::document::view::begin() const + const_iterator begin() const; + + /// @copydoc bsoncxx::v_noabi::document::view::end() const + const_iterator end() const; /// /// Indexes into this BSON array. If the index is out-of-bounds, a past-the-end iterator @@ -80,54 +110,43 @@ class view { /// /// @return The element if it exists, or the invalid element. /// - BSONCXX_ABI_EXPORT_CDECL(element) operator[](std::uint32_t i) const; - - /// - /// Default constructs a view. The resulting view will be initialized to point at - /// an empty BSON array. - /// - BSONCXX_ABI_EXPORT_CDECL() view(); - - /// - /// Constructs a view from a buffer. The caller is responsible for ensuring that - /// the lifetime of the resulting view is a subset of the buffer's. - /// - /// @param data - /// A buffer containing a valid BSON array. - /// @param length - /// The size of the buffer, in bytes. - /// - BSONCXX_ABI_EXPORT_CDECL() view(std::uint8_t const* data, std::size_t length); + v_noabi::array::element operator[](std::uint32_t i) const; /// /// Access the raw bytes of the underlying array. /// /// @return A (non-owning) pointer to the view's buffer. /// - BSONCXX_ABI_EXPORT_CDECL(std::uint8_t const*) data() const; + std::uint8_t const* data() const { + return _view.data(); + } - /// - /// Gets the length of the underlying buffer. - /// - /// @remark This is not the number of elements in the array. - /// To compute the number of elements, use std::distance. - /// - /// @return The length of the array, in bytes. - /// - BSONCXX_ABI_EXPORT_CDECL(std::size_t) length() const; + /// @copydoc bsoncxx::v_noabi::document::view::size() const + std::size_t size() const { + return _view.size(); + } + + /// @copydoc size() const + std::size_t length() const { + return _view.length(); + } /// - /// Checks if the underlying buffer is empty, i.e. it is equivalent to - /// the trivial array '[]'. + /// Return true when `this->length() == 5`. /// - /// @return true if the underlying document is empty. + /// @warning For backward compatibility, this function does NOT check if the underlying BSON bytes represent a valid + /// empty document. /// - BSONCXX_ABI_EXPORT_CDECL(bool) empty() const; + bool empty() const { + return _view.empty(); + } /// /// Conversion operator unwrapping a document::view /// - BSONCXX_ABI_EXPORT_CDECL() operator document::view() const; + operator v_noabi::document::view() const { + return _view; + } /// /// @relates bsoncx::v_noabi::document::view @@ -135,13 +154,15 @@ class view { /// Compare two views for (in)-equality /// /// @{ - friend BSONCXX_ABI_EXPORT_CDECL(bool) operator==(view, view); - friend BSONCXX_ABI_EXPORT_CDECL(bool) operator!=(view, view); + friend bool operator==(view lhs, view rhs) { + return lhs._view == rhs._view; + } + + friend bool operator!=(view lhs, view rhs) { + return !(lhs == rhs); + } /// @} /// - - private: - document::view _view; }; /// @@ -161,14 +182,25 @@ class view::const_iterator { using iterator_category = std::forward_iterator_tag; using difference_type = std::ptrdiff_t; - BSONCXX_ABI_EXPORT_CDECL() const_iterator(); - BSONCXX_ABI_EXPORT_CDECL(explicit) const_iterator(element const& element); + const_iterator() = default; + + explicit const_iterator(element const& element) : _element{element} {} - BSONCXX_ABI_EXPORT_CDECL(reference) operator*(); - BSONCXX_ABI_EXPORT_CDECL(pointer) operator->(); + reference operator*() { + return _element; + } + + pointer operator->() { + return &_element; + } BSONCXX_ABI_EXPORT_CDECL(const_iterator&) operator++(); - BSONCXX_ABI_EXPORT_CDECL(const_iterator) operator++(int); + + const_iterator operator++(int) { + const_iterator before(*this); + operator++(); + return before; + } /// /// @relates bsoncxx::v_noabi::array::view::const_iterator @@ -176,8 +208,13 @@ class view::const_iterator { /// Compare two const_iterators for (in)-equality. /// /// @{ - friend BSONCXX_ABI_EXPORT_CDECL(bool) operator==(const_iterator const&, const_iterator const&); - friend BSONCXX_ABI_EXPORT_CDECL(bool) operator!=(const_iterator const&, const_iterator const&); + friend bool operator==(const_iterator const& lhs, const_iterator const& rhs) { + return lhs._element.raw() == rhs._element.raw() && lhs._element.offset() == rhs._element.offset(); + } + + friend bool operator!=(const_iterator const& lhs, const_iterator const& rhs) { + return !(lhs == rhs); + } /// @} /// @@ -185,13 +222,52 @@ class view::const_iterator { element _element; }; +inline v_noabi::array::element view::operator[](std::uint32_t i) const { + return *(this->find(i)); +} + +inline view::const_iterator view::cend() const { + return {}; +} + +inline view::const_iterator view::begin() const { + return this->cbegin(); +} + +inline view::const_iterator view::end() const { + return this->cend(); +} + } // namespace array } // namespace v_noabi } // namespace bsoncxx +namespace bsoncxx { +namespace v_noabi { + +/// +/// Convert to the @ref bsoncxx::v_noabi equivalent of `v`. +/// +inline v_noabi::array::view from_v1(v1::array::view const& v) { + return {v}; +} + +/// +/// Convert to the @ref bsoncxx::v1 equivalent of `v`. +/// +inline v1::array::view to_v1(v_noabi::array::view const& v) { + return v1::array::view{v}; +} + +} // namespace v_noabi +} // namespace bsoncxx + #include /// /// @file /// Provides @ref bsoncxx::v_noabi::array::view. /// +/// @par Includes +/// - @ref bsoncxx/v1/array/view.hpp +/// diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/decimal128-fwd.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/decimal128-fwd.hpp index 852526d143..65046258b9 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/decimal128-fwd.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/decimal128-fwd.hpp @@ -14,6 +14,8 @@ #pragma once +#include + #include namespace bsoncxx { @@ -26,7 +28,7 @@ class decimal128; namespace bsoncxx { -using ::bsoncxx::v_noabi::decimal128; +using v_noabi::decimal128; } // namespace bsoncxx @@ -36,3 +38,6 @@ using ::bsoncxx::v_noabi::decimal128; /// @file /// Declares @ref bsoncxx::v_noabi::decimal128. /// +/// @par Includes +/// - @ref bsoncxx/v1/decimal128-fwd.hpp +/// diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/decimal128.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/decimal128.hpp index 559560f640..8563b73716 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/decimal128.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/decimal128.hpp @@ -14,11 +14,16 @@ #pragma once +#include + +// + +#include +#include + #include #include -#include - #include #include @@ -38,12 +43,20 @@ namespace v_noabi { /// - [BSON Decimal128 (MongoDB Specifications)](https://specifications.readthedocs.io/en/latest/bson-decimal128/decimal128/) /// class decimal128 { + private: + v1::decimal128 _d128; + public: /// /// Constructs a BSON Decimal128 value representing zero. /// decimal128() = default; + /// + /// Construct with the @ref bsoncxx::v1 equivalent. + /// + /* explicit(false) */ decimal128(v1::decimal128 const& d128) noexcept : _d128{d128} {} + /// /// Constructs a BSON Decimal128 from high and low 64-bit big-endian parts. /// @@ -52,7 +65,7 @@ class decimal128 { /// @param low /// The low 64-bits. /// - decimal128(uint64_t high, uint64_t low) noexcept : _high(high), _low(low) {} + decimal128(std::uint64_t high, std::uint64_t low) : _d128{high, low} {} /// /// Constructs a BSON Decimal128 from a string. @@ -63,45 +76,71 @@ class decimal128 { /// @throws bsoncxx::v_noabi::exception if the string isn't a valid BSON Decimal128 /// representation. /// - explicit BSONCXX_ABI_EXPORT_CDECL() decimal128(stdx::string_view str); + explicit BSONCXX_ABI_EXPORT_CDECL() decimal128(v1::stdx::string_view str); + + /// + /// Convert to the @ref bsoncxx::v1 equivalent. + /// + explicit operator v1::decimal128() const noexcept { + return _d128; + } /// /// Converts this decimal128 value to a string representation. /// /// @return A string representation of a IEEE 754-2008 decimal number. /// - BSONCXX_ABI_EXPORT_CDECL(std::string) to_string() const; + std::string to_string() const { + return _d128.to_string(); + } /// - /// @relates bsoncxx::v_noabi::decimal128 + /// Accessor for high 64 bits. /// - /// Relational operators for decimal128 + std::uint64_t high() const { + return _d128.high(); + } + /// - /// @{ - friend BSONCXX_ABI_EXPORT_CDECL(bool) operator==(decimal128 const& lhs, decimal128 const& rhs); - friend BSONCXX_ABI_EXPORT_CDECL(bool) operator!=(decimal128 const& lhs, decimal128 const& rhs); - /// @} + /// Accessor for low 64 bits. /// + std::uint64_t low() const { + return _d128.low(); + } /// - /// Accessor for high 64 bits. + /// @relates bsoncxx::v_noabi::decimal128 + /// + /// Equality comparison operator. /// - uint64_t high() const { - return _high; + friend bool operator==(decimal128 const& lhs, decimal128 const& rhs) { + return lhs._d128 == rhs._d128; } /// - /// Accessor for low 64 bits. + /// @relates bsoncxx::v_noabi::decimal128 + /// + /// Equality comparison operator. /// - uint64_t low() const { - return _low; + friend bool operator!=(decimal128 const& lhs, decimal128 const& rhs) { + return lhs._d128 != rhs._d128; } - - private: - uint64_t _high = 0; - uint64_t _low = 0; }; +/// +/// Convert to the @ref bsoncxx::v_noabi equivalent of `v`. +/// +inline v_noabi::decimal128 from_v1(v1::decimal128 const& v) { + return {v}; +} + +/// +/// Convert to the @ref bsoncxx::v1 equivalent of `v`. +/// +inline v1::decimal128 to_v1(v_noabi::decimal128 const& v) { + return v1::decimal128{v}; +} + } // namespace v_noabi } // namespace bsoncxx @@ -111,3 +150,6 @@ class decimal128 { /// @file /// Provides @ref bsoncxx::v_noabi::decimal128. /// +/// @par Includes +/// - @ref bsoncxx/v1/decimal128.hpp +/// diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/document/element-fwd.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/document/element-fwd.hpp index 648eccb064..6fa4b0bbf6 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/document/element-fwd.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/document/element-fwd.hpp @@ -14,6 +14,8 @@ #pragma once +#include + #include namespace bsoncxx { @@ -29,7 +31,7 @@ class element; namespace bsoncxx { namespace document { -using ::bsoncxx::v_noabi::document::element; +using v_noabi::document::element; } // namespace document } // namespace bsoncxx @@ -40,3 +42,6 @@ using ::bsoncxx::v_noabi::document::element; /// @file /// Declares @ref bsoncxx::v_noabi::document::element. /// +/// @par Includes +/// - @ref bsoncxx/v1/element/view-fwd.hpp +/// diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/document/element.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/document/element.hpp index 5d96670321..03ed760126 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/document/element.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/document/element.hpp @@ -14,6 +14,12 @@ #pragma once +#include + +// + +#include + #include #include @@ -44,6 +50,9 @@ namespace document { /// - @ref bsoncxx::v_noabi::array::element /// class element { + private: + v1::element::view _view; + public: /// /// Construct an invalid element. @@ -51,248 +60,96 @@ class element { /// This is useful when mapping the end iterator of a document or array /// view. /// - BSONCXX_ABI_EXPORT_CDECL() element(); + element() = default; + + /// + /// Construct with the @ref bsoncxx::v1 equivalent. + /// + /* explicit(false) */ element(v1::element::view const& v) : _view{v} {} + + /// + /// Convert to the @ref bsoncxx::v1 equivalent. + /// + explicit operator v1::element::view() const { + return _view; + } /// /// Conversion operator to bool which is true for valid elements /// and false for invalid elements. /// - explicit BSONCXX_ABI_EXPORT_CDECL() operator bool() const; + explicit operator bool() const { + return _view.operator bool(); + } /// /// Getter for the raw bson bytes the element points to. /// /// @return a pointer to the raw bson bytes. /// - BSONCXX_ABI_EXPORT_CDECL(std::uint8_t const*) raw() const; + std::uint8_t const* raw() const { + return _view.raw(); + } /// /// Getter for length of the raw bson bytes the element points to. /// /// @return a pointer to the length of the raw bson bytes. /// - BSONCXX_ABI_EXPORT_CDECL(std::uint32_t) length() const; + std::uint32_t length() const { + return _view.length(); + } /// /// Getter for the offset into the raw bson bytes the element points to. /// /// @return the offset into the raw bson bytes. /// - BSONCXX_ABI_EXPORT_CDECL(std::uint32_t) offset() const; - - /// - /// Getter for the type of the element. - /// - /// @return the element's type. - /// - /// @throws bsoncxx::v_noabi::exception if this element is invalid. - /// - BSONCXX_ABI_EXPORT_CDECL(bsoncxx::v_noabi::type) type() const; - - /// - /// Getter for the element's key. - /// - /// @return the element's key. - /// - /// @throws bsoncxx::v_noabi::exception if this element is invalid. - /// - BSONCXX_ABI_EXPORT_CDECL(stdx::string_view) key() const; + std::uint32_t offset() const { + return _view.offset(); + } /// /// Getter for the element's key length. /// /// @return the element's key length. /// - BSONCXX_ABI_EXPORT_CDECL(std::uint32_t) keylen() const; - - /// - /// Getter for elements of the b_double type. - /// - /// @throws bsoncxx::v_noabi::exception if this element is not a b_double. - /// - /// @return the element's value. - /// - BSONCXX_ABI_EXPORT_CDECL(types::b_double) get_double() const; - - /// - /// Getter for elements of the b_string type. - /// - /// @throws bsoncxx::v_noabi::exception if this element is not a b_string. - /// - /// @return the element's value. - /// - BSONCXX_ABI_EXPORT_CDECL(types::b_string) get_string() const; - - /// - /// Getter for elements of the b_document type. - /// - /// @throws bsoncxx::v_noabi::exception if this element is not a b_document. - /// - /// @return the element's value. - /// - BSONCXX_ABI_EXPORT_CDECL(types::b_document) get_document() const; - - /// - /// Getter for elements of the b_array type. - /// - /// @throws bsoncxx::v_noabi::exception if this element is not a b_array. - /// - /// @return the element's value. - /// - BSONCXX_ABI_EXPORT_CDECL(types::b_array) get_array() const; - - /// - /// Getter for elements of the b_binary type. - /// - /// @throws bsoncxx::v_noabi::exception if this element is not a b_binary. - /// - /// @return the element's value. - /// - BSONCXX_ABI_EXPORT_CDECL(types::b_binary) get_binary() const; - - /// - /// Getter for elements of the b_undefined type. - /// - /// @throws bsoncxx::v_noabi::exception if this element is not a b_undefined. - /// - /// @return the element's value. - /// - BSONCXX_ABI_EXPORT_CDECL(types::b_undefined) get_undefined() const; - - /// - /// Getter for elements of the b_oid type. - /// - /// @throws bsoncxx::v_noabi::exception if this element is not a b_oid. - /// - /// @return the element's value. - /// - BSONCXX_ABI_EXPORT_CDECL(types::b_oid) get_oid() const; - - /// - /// Getter for elements of the b_bool type. - /// - /// @throws bsoncxx::v_noabi::exception if this element is not a b_bool. - /// - /// @return the element's value. - /// - BSONCXX_ABI_EXPORT_CDECL(types::b_bool) get_bool() const; - - /// - /// Getter for elements of the b_date type. - /// - /// @throws bsoncxx::v_noabi::exception if this element is not a b_date. - /// - /// @return the element's value. - /// - BSONCXX_ABI_EXPORT_CDECL(types::b_date) get_date() const; + std::uint32_t keylen() const { + return _view.keylen(); + } /// - /// Getter for elements of the b_null type. - /// - /// @throws bsoncxx::v_noabi::exception if this element is not a b_null. - /// - /// @return the element's value. - /// - BSONCXX_ABI_EXPORT_CDECL(types::b_null) get_null() const; - - /// - /// Getter for elements of the b_regex type. - /// - /// @throws bsoncxx::v_noabi::exception if this element is not a b_regex. - /// - /// @return the element's value. - /// - BSONCXX_ABI_EXPORT_CDECL(types::b_regex) get_regex() const; - - /// - /// Getter for elements of the b_dbpointer type. - /// - /// @throws bsoncxx::v_noabi::exception if this element is not a b_dbpointer. - /// - /// @return the element's value. - /// - BSONCXX_ABI_EXPORT_CDECL(types::b_dbpointer) get_dbpointer() const; - - /// - /// Getter for elements of the b_code type. - /// - /// @throws bsoncxx::v_noabi::exception if this element is not a b_code. - /// - /// @return the element's value. - /// - BSONCXX_ABI_EXPORT_CDECL(types::b_code) get_code() const; - - /// - /// Getter for elements of the b_symbol type. - /// - /// @throws bsoncxx::v_noabi::exception if this element is not a b_symbol. - /// - /// @return the element's value. - /// - BSONCXX_ABI_EXPORT_CDECL(types::b_symbol) get_symbol() const; - - /// - /// Getter for elements of the b_codewscope type. - /// - /// @throws bsoncxx::v_noabi::exception if this element is not a b_codewscope. - /// - /// @return the element's value. - /// - BSONCXX_ABI_EXPORT_CDECL(types::b_codewscope) get_codewscope() const; - - /// - /// Getter for elements of the b_int32 type. - /// - /// @throws bsoncxx::v_noabi::exception if this element is not a b_int32. - /// - /// @return the element's value. - /// - BSONCXX_ABI_EXPORT_CDECL(types::b_int32) get_int32() const; - - /// - /// Getter for elements of the b_timestamp type. - /// - /// @throws bsoncxx::v_noabi::exception if this element is not a b_timestamp. - /// - /// @return the element's value. - /// - BSONCXX_ABI_EXPORT_CDECL(types::b_timestamp) get_timestamp() const; - - /// - /// Getter for elements of the b_int64 type. + /// Getter for the type of the element. /// - /// @throws bsoncxx::v_noabi::exception if this element is not a b_int64. + /// @return the element's type. /// - /// @return the element's value. + /// @throws bsoncxx::v_noabi::exception if this element is invalid. /// - BSONCXX_ABI_EXPORT_CDECL(types::b_int64) get_int64() const; + BSONCXX_ABI_EXPORT_CDECL(v_noabi::type) type() const; /// - /// Getter for elements of the b_decimal128 type. + /// Getter for the element's key. /// - /// @throws bsoncxx::v_noabi::exception if this element is not a b_decimal128. + /// @return the element's key. /// - /// @return the element's value. + /// @throws bsoncxx::v_noabi::exception if this element is invalid. /// - BSONCXX_ABI_EXPORT_CDECL(types::b_decimal128) get_decimal128() const; + BSONCXX_ABI_EXPORT_CDECL(v1::stdx::string_view) key() const; - /// - /// Getter for elements of the b_minkey type. - /// - /// @throws bsoncxx::v_noabi::exception if this element is not a b_minkey. - /// - /// @return the element's value. - /// - BSONCXX_ABI_EXPORT_CDECL(types::b_minkey) get_minkey() const; +#pragma push_macro("X") +#undef X +#define X(_name, _value) BSONCXX_ABI_EXPORT_CDECL(v_noabi::types::b_##_name) get_##_name() const; /// - /// Getter for elements of the b_maxkey type. + /// Return the BSON type value of this element. /// - /// @throws bsoncxx::v_noabi::exception if this element is not a b_maxkey. + /// @throws bsoncxx::v_noabi::exception if this element is not the requested type. /// - /// @return the element's value. + /// @{ + BSONCXX_V1_TYPES_XMACRO(X) + /// @} /// - BSONCXX_ABI_EXPORT_CDECL(types::b_maxkey) get_maxkey() const; +#pragma pop_macro("X") /// /// Getter for a types::bson_value::view variant wrapper of the value portion of the @@ -300,7 +157,7 @@ class element { /// /// @return the element's value. /// - BSONCXX_ABI_EXPORT_CDECL(types::bson_value::view) get_value() const; + BSONCXX_ABI_EXPORT_CDECL(v_noabi::types::bson_value::view) get_value() const; /// /// Getter for a types::bson_value::value variant wrapper of the value portion of @@ -308,7 +165,7 @@ class element { /// /// @return an owning version of the element's value. /// - BSONCXX_ABI_EXPORT_CDECL(types::bson_value::value) get_owning_value() const; + BSONCXX_ABI_EXPORT_CDECL(v_noabi::types::bson_value::value) get_owning_value() const; /// /// If this element is a document, finds the first element of the document @@ -324,7 +181,7 @@ class element { /// /// @return The matching element, if found, or an invalid element. /// - BSONCXX_ABI_EXPORT_CDECL(element) operator[](stdx::string_view key) const; + BSONCXX_ABI_EXPORT_CDECL(element) operator[](v1::stdx::string_view key) const; /// /// If this element is an array, indexes into this BSON array. If the @@ -340,30 +197,7 @@ class element { /// /// @return The element if it exists, or an invalid element. /// - BSONCXX_ABI_EXPORT_CDECL(array::element) operator[](std::uint32_t i) const; - - private: - /// - /// Construct an element as an offset into a buffer of bson bytes. - /// - /// @param raw - /// A pointer to the raw bson bytes. - /// - /// @param length - /// The size of the bson buffer. - /// - /// @param offset - /// The element's offset into the buffer. - /// - explicit element(std::uint8_t const* raw, std::uint32_t length, std::uint32_t offset, std::uint32_t keylen); - - friend ::bsoncxx::v_noabi::array::element; - friend ::bsoncxx::v_noabi::document::view; - - std::uint8_t const* _raw; - std::uint32_t _length; - std::uint32_t _offset; - std::uint32_t _keylen; + BSONCXX_ABI_EXPORT_CDECL(v_noabi::array::element) operator[](std::uint32_t i) const; }; /// @@ -374,16 +208,22 @@ class element { /// @{ /// @relatesalso bsoncxx::v_noabi::document::element -BSONCXX_ABI_EXPORT_CDECL(bool) operator==(element const& elem, types::bson_value::view const& v); +BSONCXX_ABI_EXPORT_CDECL(bool) operator==(element const& lhs, v_noabi::types::bson_value::view const& rhs); /// @relatesalso bsoncxx::v_noabi::document::element -BSONCXX_ABI_EXPORT_CDECL(bool) operator==(types::bson_value::view const& v, element const& elem); +inline bool operator==(v_noabi::types::bson_value::view const& lhs, element const& rhs) { + return rhs == lhs; +} /// @relatesalso bsoncxx::v_noabi::document::element -BSONCXX_ABI_EXPORT_CDECL(bool) operator!=(element const& elem, types::bson_value::view const& v); +inline bool operator!=(element const& lhs, v_noabi::types::bson_value::view const& rhs) { + return !(lhs == rhs); +} /// @relatesalso bsoncxx::v_noabi::document::element -BSONCXX_ABI_EXPORT_CDECL(bool) operator!=(types::bson_value::view const& v, element const& elem); +inline bool operator!=(v_noabi::types::bson_value::view const& lhs, element const& rhs) { + return !(lhs == rhs); +} /// @} /// @@ -392,11 +232,29 @@ BSONCXX_ABI_EXPORT_CDECL(bool) operator!=(types::bson_value::view const& v, elem } // namespace v_noabi } // namespace bsoncxx +namespace bsoncxx { +namespace v_noabi { + +// Ambiguous whether `v1::element::view` should be converted to `v_noabi::array::element` or +// `v_noabi::document::element.` Require users to explicitly cast to the expected type instead. +// +// v_noabi::document::element from_v1(v1::element::view const& v); + +/// +/// Convert to the @ref bsoncxx::v1 equivalent of `v`. +/// +inline v1::element::view to_v1(v_noabi::document::element const& v) { + return v1::element::view{v}; +} + +} // namespace v_noabi +} // namespace bsoncxx + namespace bsoncxx { namespace document { -using ::bsoncxx::v_noabi::document::operator==; -using ::bsoncxx::v_noabi::document::operator!=; +using v_noabi::document::operator==; +using v_noabi::document::operator!=; } // namespace document } // namespace bsoncxx @@ -407,3 +265,6 @@ using ::bsoncxx::v_noabi::document::operator!=; /// @file /// Provides @ref bsoncxx::v_noabi::document::element. /// +/// @par Includes +/// - @ref bsoncxx/v1/element/view.hpp +/// diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/document/value-fwd.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/document/value-fwd.hpp index d10d6e4c0c..b4cc48c81d 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/document/value-fwd.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/document/value-fwd.hpp @@ -14,6 +14,8 @@ #pragma once +#include + #include namespace bsoncxx { @@ -29,7 +31,7 @@ class value; namespace bsoncxx { namespace document { -using ::bsoncxx::v_noabi::document::value; +using v_noabi::document::value; } // namespace document } // namespace bsoncxx @@ -40,3 +42,6 @@ using ::bsoncxx::v_noabi::document::value; /// @file /// Declares @ref bsoncxx::v_noabi::document::value. /// +/// @par Includes +/// - @ref bsoncxx/v1/document/value-fwd.hpp +/// diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/document/value.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/document/value.hpp index 4b9d9798a1..fcbfd557c3 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/document/value.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/document/value.hpp @@ -14,12 +14,16 @@ #pragma once +#include + +// + +#include + #include #include #include -#include - #include #include #include @@ -37,34 +41,73 @@ namespace document { /// should be used sparingly; document::view should be used instead wherever possible. /// class value { + private: + v1::document::value _value; + std::size_t _length; + public: + /// + /// The type of the deleter used to free the underlying BSON binary data. + /// using deleter_type = void(BSONCXX_ABI_CDECL*)(std::uint8_t*); - using unique_ptr_type = std::unique_ptr; + + /// + /// The type of the unique pointer used to manage the underlying BSON binary data. + /// + using unique_ptr_type = std::unique_ptr; + + /// @copydoc v_noabi::document::view::const_iterator + using const_iterator = v_noabi::document::view::const_iterator; + + /// @copydoc v_noabi::document::view::iterator + using iterator = const_iterator; + + ~value() = default; + + value(value&&) = default; + value& operator=(value&&) = default; + + value(value const& other) : value{other.view()} {} + + value& operator=(value const& other) { + *this = value{other.view()}; + return *this; + } /// /// Constructs a value from a buffer. + /// /// This constructor transfers ownership of the buffer to the resulting /// value. A user-provided deleter is used to destroy the buffer. /// + /// @warning For backward compatibility, `length` is NOT validated. When `length` is inconsistent with the embedded + /// length as indicated by the BSON bytes, the BSON bytes may be parsed as "invalid" despite the BSON bytes + /// themselves being valid. + /// /// @param data /// A pointer to a buffer containing a valid BSON document. /// @param length /// The length of the document. - /// @param dtor + /// @param deleter /// A user provided deleter. /// - BSONCXX_ABI_EXPORT_CDECL() value(std::uint8_t* data, std::size_t length, deleter_type dtor); + value(std::uint8_t* data, std::size_t length, deleter_type deleter) + : _value{data, std::move(deleter)}, _length{length} {} /// /// Constructs a value from a std::unique_ptr to a buffer. The ownership /// of the buffer is transferred to the constructed value. /// + /// @warning For backward compatibility, `length` is NOT validated. When `length` is inconsistent with the embedded + /// length as indicated by the BSON bytes, the BSON bytes may be parsed as "invalid" despite the BSON bytes + /// themselves being valid. + /// /// @param ptr /// A pointer to a buffer containing a valid BSON document. /// @param length /// The length of the document. /// - BSONCXX_ABI_EXPORT_CDECL() value(unique_ptr_type ptr, std::size_t length); + value(unique_ptr_type ptr, std::size_t length) : _value{std::move(ptr)}, _length{length} {} /// /// Constructs a value from a view of a document. The data referenced @@ -74,21 +117,16 @@ class value { /// @param view /// A view of another document to copy. /// - explicit BSONCXX_ABI_EXPORT_CDECL() value(document::view view); - - ~value() = default; - - BSONCXX_ABI_EXPORT_CDECL() value(value const&); - BSONCXX_ABI_EXPORT_CDECL(value&) operator=(value const&); - - value(value&&) = default; - value& operator=(value&&) = default; + explicit BSONCXX_ABI_EXPORT_CDECL() value(v_noabi::document::view view); /// /// Constructor used for serialization of user objects. This uses argument-dependent lookup /// to find the function declaration /// `void to_bson(T& t, bsoncxx::v_noabi::document::value doc)`. /// + /// @par Constraints: + /// - `T` is not @ref bsoncxx::v_noabi::array::view. + /// /// @param t /// A user-defined object to serialize into a BSON object. /// @@ -96,6 +134,17 @@ class value { explicit value(T const& t) : value({}) { to_bson(t, *this); } + + /// + /// Assignment used for serialization of user objects. This uses argument-dependent lookup + /// to find the function declaration + /// `void to_bson(T& t, bsoncxx::v_noabi::document::value doc)`. + /// + /// @note `T` is not constrained! + /// + /// @param t + /// A user-defined object to serialize into a BSON object. + /// template value& operator=(T const& t) { *this = value{t}; @@ -103,41 +152,68 @@ class value { } /// - /// @returns A const_iterator to the first element of the document. + /// Convert to the @ref bsoncxx::v1 equivalent. + /// + /// @par Preconditions: + /// - If `this->data()` is not null, the size of the storage region pointed to by `data` must be greater than or + /// equal to 5. + /// - The "total number of bytes comprising the document" as indicated by the BSON bytes pointed-to by + /// `this->data()` must be less than or equal to the size of the storage region pointed to by `data`. + /// + /// @note `this->size()` is ignored. /// - BSONCXX_ABI_EXPORT_CDECL(document::view::const_iterator) cbegin() const; + explicit operator v1::document::value() const& { + return _value; + } /// - /// @returns A const_iterator to the past-the-end element of the document. + /// Convert to the @ref bsoncxx::v1 equivalent. + /// + /// @par Preconditions: + /// - If `this->data()` is not null, the size of the storage region pointed to by `data` must be greater than or + /// equal to 5. + /// - The "total number of bytes comprising the document" as indicated by the BSON bytes pointed-to by + /// `this->data()` must be less than or equal to the size of the storage region pointed to by `data`. /// - BSONCXX_ABI_EXPORT_CDECL(document::view::const_iterator) cend() const; + /// @note `this->size()` is ignored. + /// + explicit operator v1::document::value() && { + _length = 0u; + return std::move(_value); + } /// /// @returns A const_iterator to the first element of the document. /// - BSONCXX_ABI_EXPORT_CDECL(document::view::const_iterator) begin() const; + const_iterator cbegin() const { + return this->view().cbegin(); + } /// /// @returns A const_iterator to the past-the-end element of the document. /// - BSONCXX_ABI_EXPORT_CDECL(document::view::const_iterator) end() const; + const_iterator cend() const { + return this->view().cend(); + } /// - /// Finds the first element of the document with the provided key. If there is - /// no such element, the past-the-end iterator will be returned. The runtime of - /// find() is linear in the length of the document. This method only searches - /// the top-level document, and will not recurse to any subdocuments. - /// - /// @remark In BSON, keys are not required to be unique. If there are multiple - /// elements with a matching key in the document, the first matching element from - /// the start will be returned. + /// @returns A const_iterator to the first element of the document. /// - /// @param key - /// The key to search for. + const_iterator begin() const { + return this->view().begin(); + } + /// - /// @return An iterator to the matching element, if found, or the past-the-end iterator. + /// @returns A const_iterator to the past-the-end element of the document. /// - BSONCXX_ABI_EXPORT_CDECL(document::view::const_iterator) find(stdx::string_view key) const; + const_iterator end() const { + return this->view().end(); + } + + /// @copydoc bsoncxx::v_noabi::document::view::find(bsoncxx::v1::stdx::string_view key) const + const_iterator find(v1::stdx::string_view key) const { + return const_iterator{*_value.find(key)}; + } /// /// Finds the first element of the document with the provided key. If there is no @@ -149,14 +225,18 @@ class value { /// /// @return The matching element, if found, or the invalid element. /// - BSONCXX_ABI_EXPORT_CDECL(element) operator[](stdx::string_view key) const; + v_noabi::document::element operator[](v1::stdx::string_view key) const { + return _value.operator[](key); + } /// /// Access the raw bytes of the underlying document. /// /// @return A pointer to the value's buffer. /// - BSONCXX_ABI_EXPORT_CDECL(std::uint8_t const*) data() const; + std::uint8_t const* data() const { + return _value.data(); + } /// /// Gets the length of the underlying buffer. @@ -166,25 +246,30 @@ class value { /// /// @return The length of the document, in bytes. /// - BSONCXX_ABI_EXPORT_CDECL(std::size_t) length() const; + std::size_t size() const { + return _length; // Do NOT use _value.size(). + } + + /// @copydoc size() const + std::size_t length() const { + return _length; // Do NOT use _value.length(). + } /// - /// Checks if the underlying document is empty, i.e. it is equivalent to - /// the trivial document '{}'. + /// Return true when `this->length() == 5`. /// - /// @return true if the underlying document is empty. + /// @warning For backward compatibility, this function does NOT check if the underlying BSON bytes represent a valid + /// empty document. /// - BSONCXX_ABI_EXPORT_CDECL(bool) empty() const; + bool empty() const { + return _length == 5; // Do NOT use _value.empty(). + } /// /// Get a view over the document owned by this value. /// - document::view view() const noexcept { - // Silence false positive with g++ 10.2.1 on Debian 11. - BSONCXX_PRIVATE_WARNINGS_PUSH(); - BSONCXX_PRIVATE_WARNINGS_DISABLE(GCC("-Wmaybe-uninitialized")); - return document::view{static_cast(_data.get()), _length}; - BSONCXX_PRIVATE_WARNINGS_POP(); + v_noabi::document::view view() const noexcept { + return {_value.data(), _length}; // Do NOT use _value.view(). } /// @@ -192,8 +277,8 @@ class value { /// /// @return A view over the value. /// - operator document::view() const noexcept { - return view(); + /* explicit(false) */ operator v_noabi::document::view() const noexcept { + return this->view(); } /// @@ -231,19 +316,25 @@ class value { /// After calling release() it is illegal to call any methods /// on this class, unless it is subsequently moved into. /// - /// @return A std::unique_ptr with ownership of the buffer. + /// @return A std::unique_ptr with ownership of the buffer. If the pointer is null, the deleter may also be null. /// - BSONCXX_ABI_EXPORT_CDECL(unique_ptr_type) release(); + unique_ptr_type release() { + auto ptr = _value.release(); + + // Invariant: the underlying deleter type MUST be `deleter_type`. + auto const deleter_ptr = ptr.get_deleter().target(); + + // Invariant: `ptr` implies `deleter_ptr`, but not the reverse. + return {ptr.release(), deleter_ptr ? *deleter_ptr : nullptr}; + } /// /// Replace the formerly-owned buffer with the new view. /// This will make a copy of the passed-in view. /// - BSONCXX_ABI_EXPORT_CDECL(void) reset(document::view view); - - private: - unique_ptr_type _data; - std::size_t _length{0}; + void reset(v_noabi::document::view view) { + _value.reset(to_v1(view)); + } }; /// @@ -268,11 +359,36 @@ inline bool operator!=(value const& lhs, value const& rhs) { } // namespace v_noabi } // namespace bsoncxx +namespace bsoncxx { +namespace v_noabi { + +/// +/// Convert from the @ref bsoncxx::v1 equivalent of `v`. +/// +inline v_noabi::document::value from_v1(v1::document::value const& v) { + return v_noabi::document::value{from_v1(v.view())}; +} + +/// +/// Convert from the @ref bsoncxx::v1 equivalent of `v`. +/// +BSONCXX_ABI_EXPORT_CDECL(v_noabi::document::value) from_v1(v1::document::value&& v); + +/// +/// Convert to the @ref bsoncxx::v1 equivalent of `v`. +/// +inline v1::document::value to_v1(v_noabi::document::value v) { + return v1::document::value{std::move(v)}; +} + +} // namespace v_noabi +} // namespace bsoncxx + namespace bsoncxx { namespace document { -using ::bsoncxx::v_noabi::document::operator==; -using ::bsoncxx::v_noabi::document::operator!=; +using v_noabi::document::operator==; +using v_noabi::document::operator!=; } // namespace document } // namespace bsoncxx @@ -283,3 +399,6 @@ using ::bsoncxx::v_noabi::document::operator!=; /// @file /// Provides @ref bsoncxx::v_noabi::document::value. /// +/// @par Includes +/// - @ref bsoncxx/v1/document/value.hpp +/// diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/document/view-fwd.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/document/view-fwd.hpp index 4fc7fae2ec..d38cf60456 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/document/view-fwd.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/document/view-fwd.hpp @@ -14,6 +14,8 @@ #pragma once +#include + #include namespace bsoncxx { @@ -29,7 +31,7 @@ class view; namespace bsoncxx { namespace document { -using ::bsoncxx::v_noabi::document::view; +using v_noabi::document::view; } // namespace document } // namespace bsoncxx @@ -40,3 +42,6 @@ using ::bsoncxx::v_noabi::document::view; /// @file /// Declares @ref bsoncxx::v_noabi::document::view. /// +/// @par Includes +/// - @ref bsoncxx/v1/document/view-fwd.hpp +/// diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/document/view.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/document/view.hpp index 5c14099eb0..4923d02381 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/document/view.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/document/view.hpp @@ -14,12 +14,17 @@ #pragma once +#include + +// + +#include + #include #include +#include #include -#include - #include #include @@ -33,26 +38,62 @@ namespace document { /// A read-only, non-owning view of a BSON document. /// class view { + private: + v1::document::view _view; + std::size_t _length; + public: class const_iterator; + + /// + /// Equivalent to @ref const_iterator. + /// using iterator = const_iterator; /// - /// Default constructs a view. The resulting view will be initialized to point at - /// an empty BSON document. + /// Default constructs a view. + /// + /// @par Postconditions: + /// - `this->data() != nullptr` + /// - `this->size() == 5` + /// - `this->empty() == true` /// - BSONCXX_ABI_EXPORT_CDECL() view(); + view() : _view{}, _length{_view.length()} {} + + /// + /// Construct with the @ref bsoncxx::v1 equivalent. + /// + /* explicit(false) */ view(v1::document::view const& v) : _view{v}, _length{v.length()} {} /// /// Constructs a view from a buffer. The caller is responsible for ensuring that /// the lifetime of the resulting view is a subset of the buffer's. /// + /// @warning For backward compatibility, `length` is NOT validated. When `length` is inconsistent with the embedded + /// length as indicated by the BSON bytes, the BSON bytes may be parsed as "invalid" despite the BSON bytes + /// themselves being valid. + /// /// @param data - /// A buffer containing a valid BSON document. + /// A pointer to valid BSON data. /// @param length - /// The size of the buffer, in bytes. + /// The size of the BSON data in bytes. /// - BSONCXX_ABI_EXPORT_CDECL() view(std::uint8_t const* data, std::size_t length); + view(std::uint8_t const* data, std::size_t length) : _view{data}, _length{length} {} + + /// + /// Convert to the @ref bsoncxx::v1 equivalent. + /// + /// @par Preconditions: + /// - If `this->data()` is not null, the size of the storage region pointed to by `data` must be greater than or + /// equal to 5. + /// - The "total number of bytes comprising the document" as indicated by the BSON bytes pointed-to by + /// `this->data()` must be less than or equal to the size of the storage region pointed to by `data`. + /// + /// @note `this->size()` is ignored. + /// + explicit operator v1::document::view() const { + return _view; + } /// /// @returns A const_iterator to the first element of the document. @@ -62,17 +103,17 @@ class view { /// /// @returns A const_iterator to the past-the-end element of the document. /// - BSONCXX_ABI_EXPORT_CDECL(const_iterator) cend() const; + const_iterator cend() const; /// /// @returns A const_iterator to the first element of the document. /// - BSONCXX_ABI_EXPORT_CDECL(const_iterator) begin() const; + const_iterator begin() const; /// /// @returns A const_iterator to the past-the-end element of the document. /// - BSONCXX_ABI_EXPORT_CDECL(const_iterator) end() const; + const_iterator end() const; /// /// Finds the first element of the document with the provided key. If there is @@ -89,7 +130,7 @@ class view { /// /// @return An iterator to the matching element, if found, or the past-the-end iterator. /// - BSONCXX_ABI_EXPORT_CDECL(const_iterator) find(stdx::string_view key) const; + BSONCXX_ABI_EXPORT_CDECL(const_iterator) find(v1::stdx::string_view key) const; /// /// Finds the first element of the document with the provided key. If there is no @@ -101,32 +142,42 @@ class view { /// /// @return The matching element, if found, or the invalid element. /// - BSONCXX_ABI_EXPORT_CDECL(element) operator[](stdx::string_view key) const; + v_noabi::document::element operator[](v1::stdx::string_view key) const; /// /// Access the raw bytes of the underlying document. /// /// @return A (non-owning) pointer to the view's buffer. /// - BSONCXX_ABI_EXPORT_CDECL(std::uint8_t const*) data() const; + std::uint8_t const* data() const { + return _view.data(); + } /// - /// Gets the length of the underlying buffer. + /// Gets the length of the underlying buffer in bytes. /// - /// @remark This is not the number of elements in the document. - /// To compute the number of elements, use std::distance. + /// @remark This is not the number of BSON elements. To compute the number of elements, use `std::distance`. /// /// @return The length of the document, in bytes. /// - BSONCXX_ABI_EXPORT_CDECL(std::size_t) length() const; + std::size_t size() const { + return _length; // Do NOT use _view.size(). + } + + /// @copydoc size() const + std::size_t length() const { + return _length; // Do NOT use _view.length(). + } /// - /// Checks if the underlying document is empty, i.e. it is equivalent to - /// the trivial document '{}'. + /// Return true when `this->length() == 5`. /// - /// @return true if the underlying document is empty. + /// @warning For backward compatibility, this function does NOT check if the underlying BSON bytes represent a valid + /// empty document. /// - BSONCXX_ABI_EXPORT_CDECL(bool) empty() const; + bool empty() const { + return _length == 5u; // Do NOT use _view.empty(). + } /// /// @relates bsoncxx::v_noabi::document::view @@ -134,14 +185,15 @@ class view { /// Compare two document views for (in)-equality. /// /// @{ - friend BSONCXX_ABI_EXPORT_CDECL(bool) operator==(view, view); - friend BSONCXX_ABI_EXPORT_CDECL(bool) operator!=(view, view); + friend bool operator==(view lhs, view rhs) { + return (lhs._length == rhs._length) && (std::memcmp(lhs.data(), rhs.data(), lhs._length) == 0); + } + + friend bool operator!=(view lhs, view rhs) { + return !(lhs == rhs); + } /// @} /// - - private: - std::uint8_t const* _data; - std::size_t _length; }; /// @@ -151,6 +203,9 @@ class view { /// view elements. /// class view::const_iterator { + private: + v_noabi::document::element _element; + public: /// /// std::iterator_traits @@ -161,14 +216,25 @@ class view::const_iterator { using iterator_category = std::forward_iterator_tag; using difference_type = std::ptrdiff_t; - BSONCXX_ABI_EXPORT_CDECL() const_iterator(); - explicit BSONCXX_ABI_EXPORT_CDECL() const_iterator(element const& element); + const_iterator() = default; + + explicit const_iterator(v_noabi::document::element const& element) : _element(element) {} - BSONCXX_ABI_EXPORT_CDECL(reference) operator*(); - BSONCXX_ABI_EXPORT_CDECL(pointer) operator->(); + reference operator*() { + return _element; + } + + pointer operator->() { + return &_element; + } BSONCXX_ABI_EXPORT_CDECL(const_iterator&) operator++(); - BSONCXX_ABI_EXPORT_CDECL(const_iterator) operator++(int); + + const_iterator operator++(int) { + const_iterator before(*this); + operator++(); + return before; + } /// /// @relates bsoncxx::v_noabi::document::view::const_iterator @@ -176,22 +242,63 @@ class view::const_iterator { /// Compares two const_iterators for (in)-equality. /// /// @{ - friend BSONCXX_ABI_EXPORT_CDECL(bool) operator==(const_iterator const&, const_iterator const&); - friend BSONCXX_ABI_EXPORT_CDECL(bool) operator!=(const_iterator const&, const_iterator const&); + friend bool operator==(const_iterator const& lhs, const_iterator const& rhs) { + return lhs._element.raw() == rhs._element.raw() && lhs._element.offset() == rhs._element.offset(); + } + + friend bool operator!=(const_iterator const& lhs, const_iterator const& rhs) { + return !(lhs == rhs); + } /// @} /// - - private: - element _element; }; +inline v_noabi::document::element view::operator[](v1::stdx::string_view key) const { + return *(this->find(key)); +} + +inline view::const_iterator view::cend() const { + return {}; +} + +inline view::const_iterator view::begin() const { + return this->cbegin(); +} + +inline view::const_iterator view::end() const { + return this->cend(); +} + } // namespace document } // namespace v_noabi } // namespace bsoncxx +namespace bsoncxx { +namespace v_noabi { + +/// +/// Convert to the @ref bsoncxx::v_noabi equivalent of `v`. +/// +inline v_noabi::document::view from_v1(v1::document::view const& v) { + return {v}; +} + +/// +/// Convert to the @ref bsoncxx::v1 equivalent of `v`. +/// +inline v1::document::view to_v1(v_noabi::document::view const& v) { + return v1::document::view{v}; +} + +} // namespace v_noabi +} // namespace bsoncxx + #include /// /// @file /// Provides @ref bsoncxx::v_noabi::document::view. /// +/// @par Includes +/// - @ref bsoncxx/v1/document/view.hpp +/// diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/exception/error_code-fwd.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/exception/error_code-fwd.hpp index bd0d18dde0..e014b172a6 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/exception/error_code-fwd.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/exception/error_code-fwd.hpp @@ -27,7 +27,7 @@ enum class error_code : std::int32_t; namespace bsoncxx { -using ::bsoncxx::v_noabi::error_code; +using v_noabi::error_code; } // namespace bsoncxx @@ -42,3 +42,6 @@ struct is_error_code_enum; /// @file /// Declares @ref bsoncxx::v_noabi::error_code. /// +/// @par Includes +/// - @ref bsoncxx/v1/exception-fwd.hpp +/// 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 c8a96a4d09..cea41789af 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 @@ -14,11 +14,15 @@ #pragma once +#include + +// + +#include + #include #include -#include - #include namespace bsoncxx { @@ -177,8 +181,8 @@ inline std::error_code make_error_code(error_code error) { namespace bsoncxx { -using ::bsoncxx::v_noabi::error_category; -using ::bsoncxx::v_noabi::make_error_code; +using v_noabi::error_category; +using v_noabi::make_error_code; } // namespace bsoncxx @@ -186,10 +190,8 @@ using ::bsoncxx::v_noabi::make_error_code; namespace std { -// @cond DOXYGEN_DISABLE template <> struct is_error_code_enum : public true_type {}; -// @endcond } // namespace std @@ -197,3 +199,6 @@ struct is_error_code_enum : public true_type {}; /// @file /// Provides @ref bsoncxx::v_noabi::error_code. /// +/// @par Includes +/// - @ref bsoncxx/v1/exception.hpp +/// diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/exception/exception-fwd.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/exception/exception-fwd.hpp index be22eef64e..1dee228313 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/exception/exception-fwd.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/exception/exception-fwd.hpp @@ -14,6 +14,8 @@ #pragma once +#include + #include namespace bsoncxx { @@ -26,7 +28,7 @@ class BSONCXX_ABI_EXPORT exception; namespace bsoncxx { -using ::bsoncxx::v_noabi::exception; +using v_noabi::exception; } // namespace bsoncxx @@ -36,3 +38,6 @@ using ::bsoncxx::v_noabi::exception; /// @file /// Declares @ref bsoncxx::v_noabi::exception. /// +/// @par Includes +/// - @ref bsoncxx/v1/exception-fwd.hpp +/// diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/exception/exception.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/exception/exception.hpp index 01dcda80d9..180f71895f 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/exception/exception.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/exception/exception.hpp @@ -14,10 +14,14 @@ #pragma once -#include - #include +// + +#include + +#include + #include namespace bsoncxx { @@ -53,3 +57,6 @@ BSONCXX_PRIVATE_WARNINGS_POP(); /// @file /// Provides @ref bsoncxx::v_noabi::exception. /// +/// @par Includes +/// - @ref bsoncxx/v1/exception.hpp +/// diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/oid-fwd.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/oid-fwd.hpp index 11338fbcec..bfaadf7514 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/oid-fwd.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/oid-fwd.hpp @@ -14,6 +14,8 @@ #pragma once +#include + #include namespace bsoncxx { @@ -26,7 +28,7 @@ class oid; namespace bsoncxx { -using ::bsoncxx::v_noabi::oid; +using v_noabi::oid; } // namespace bsoncxx @@ -36,3 +38,6 @@ using ::bsoncxx::v_noabi::oid; /// @file /// Declares @ref bsoncxx::v_noabi::oid. /// +/// @par Includes +/// - @ref bsoncxx/v1/oid-fwd.hpp +/// diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/oid.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/oid.hpp index 01d0a58213..514fa09998 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/oid.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/oid.hpp @@ -14,12 +14,17 @@ #pragma once +#include + +// + +#include +#include + #include #include #include -#include - #include #include @@ -34,14 +39,22 @@ namespace v_noabi { /// - [BSON Types (MongoDB Manual)](https://www.mongodb.com/docs/manual/reference/bson-types/) /// class oid { + private: + v1::oid _oid; + public: - static constexpr std::size_t k_oid_length = 12; + static constexpr BSONCXX_ABI_EXPORT std::size_t k_oid_length = v1::oid::k_oid_length; /// /// Constructs an oid and initializes it to a newly generated ObjectId. /// BSONCXX_ABI_EXPORT_CDECL() oid(); + /// + /// Construct with the @ref bsoncxx::v1 equivalent. + /// + /* explicit(false) */ oid(v1::oid const& oid) noexcept : _oid{oid} {} + /// /// Constructs an oid initializes it to the contents of the provided buffer. /// @@ -63,14 +76,23 @@ class oid { /// @throws bsoncxx::v_noabi::exception if the string isn't an OID-sized hex /// string. /// - explicit BSONCXX_ABI_EXPORT_CDECL() oid(stdx::string_view const& str); + explicit BSONCXX_ABI_EXPORT_CDECL() oid(v1::stdx::string_view const& str); + + /// + /// Convert to the @ref bsoncxx::v1 equivalent. + /// + explicit operator v1::oid() const noexcept { + return _oid; + } /// /// Converts this oid to a hexadecimal string. /// /// @return A hexadecimal string representation of this ObjectId. /// - BSONCXX_ABI_EXPORT_CDECL(std::string) to_string() const; + std::string to_string() const { + return _oid.to_string(); + } /// /// Returns the number of bytes in this ObjectId. @@ -81,42 +103,75 @@ class oid { return k_oid_length; } - /// - /// @relates bsoncxx::v_noabi::oid - /// - /// Relational operators for OIDs. - /// - /// @{ - friend BSONCXX_ABI_EXPORT_CDECL(bool) operator<(oid const& lhs, oid const& rhs); - friend BSONCXX_ABI_EXPORT_CDECL(bool) operator>(oid const& lhs, oid const& rhs); - friend BSONCXX_ABI_EXPORT_CDECL(bool) operator<=(oid const& lhs, oid const& rhs); - friend BSONCXX_ABI_EXPORT_CDECL(bool) operator>=(oid const& lhs, oid const& rhs); - friend BSONCXX_ABI_EXPORT_CDECL(bool) operator==(oid const& lhs, oid const& rhs); - friend BSONCXX_ABI_EXPORT_CDECL(bool) operator!=(oid const& lhs, oid const& rhs); - /// @} - /// - /// /// @memberof bsoncxx::v_noabi::oid /// Extracts the timestamp portion of the underlying ObjectId. /// /// @return A std::time_t initialized to the timestamp. /// - BSONCXX_ABI_EXPORT_CDECL(std::time_t) get_time_t() const; + std::time_t get_time_t() const { + return _oid.get_time_t(); + } /// /// An accessor for the internal data buffer in the oid. /// /// @return A pointer to the internal buffer holding the oid bytes. /// - BSONCXX_ABI_EXPORT_CDECL(char const*) bytes() const; + char const* bytes() const { + return reinterpret_cast(_oid.bytes()); + } + + /// + /// @relates bsoncxx::v_noabi::oid + /// + /// Relational comparison operator. + /// + /// @{ + friend bool operator<(oid const& lhs, oid const& rhs) { + return lhs._oid < rhs._oid; + } - private: - friend int oid_compare(oid const& lhs, oid const& rhs); + friend bool operator>(oid const& lhs, oid const& rhs) { + return lhs._oid > rhs._oid; + } + + friend bool operator<=(oid const& lhs, oid const& rhs) { + return lhs._oid <= rhs._oid; + } - std::array _bytes; + friend bool operator>=(oid const& lhs, oid const& rhs) { + return lhs._oid >= rhs._oid; + } + + friend bool operator==(oid const& lhs, oid const& rhs) { + return lhs._oid == rhs._oid; + } + + friend bool operator!=(oid const& lhs, oid const& rhs) { + return lhs._oid != rhs._oid; + } + /// @} + /// + + private: + friend BSONCXX_ABI_EXPORT_CDECL(int) oid_compare(oid const& lhs, oid const& rhs); }; +/// +/// Convert to the @ref bsoncxx::v_noabi equivalent of `v`. +/// +inline oid from_v1(v1::oid const& v) { + return {v}; +} + +/// +/// Convert to the @ref bsoncxx::v1 equivalent of `v`. +/// +inline v1::oid to_v1(v_noabi::oid const& v) { + return v1::oid{v}; +} + } // namespace v_noabi } // namespace bsoncxx @@ -126,3 +181,6 @@ class oid { /// @file /// Provides @ref bsoncxx::v_noabi::oid. /// +/// @par Includes +/// - @ref bsoncxx/v1/oid.hpp +/// diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/types-fwd.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/types-fwd.hpp index cc252fc3c7..3bc465951d 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/types-fwd.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/types-fwd.hpp @@ -14,6 +14,8 @@ #pragma once +#include + #include #include @@ -59,35 +61,35 @@ struct b_minkey; namespace bsoncxx { -using ::bsoncxx::v_noabi::binary_sub_type; -using ::bsoncxx::v_noabi::type; +using v_noabi::binary_sub_type; +using v_noabi::type; } // namespace bsoncxx namespace bsoncxx { namespace types { -using ::bsoncxx::v_noabi::types::b_array; -using ::bsoncxx::v_noabi::types::b_binary; -using ::bsoncxx::v_noabi::types::b_bool; -using ::bsoncxx::v_noabi::types::b_code; -using ::bsoncxx::v_noabi::types::b_codewscope; -using ::bsoncxx::v_noabi::types::b_date; -using ::bsoncxx::v_noabi::types::b_dbpointer; -using ::bsoncxx::v_noabi::types::b_decimal128; -using ::bsoncxx::v_noabi::types::b_document; -using ::bsoncxx::v_noabi::types::b_double; -using ::bsoncxx::v_noabi::types::b_int32; -using ::bsoncxx::v_noabi::types::b_int64; -using ::bsoncxx::v_noabi::types::b_maxkey; -using ::bsoncxx::v_noabi::types::b_minkey; -using ::bsoncxx::v_noabi::types::b_null; -using ::bsoncxx::v_noabi::types::b_oid; -using ::bsoncxx::v_noabi::types::b_regex; -using ::bsoncxx::v_noabi::types::b_string; -using ::bsoncxx::v_noabi::types::b_symbol; -using ::bsoncxx::v_noabi::types::b_timestamp; -using ::bsoncxx::v_noabi::types::b_undefined; +using v_noabi::types::b_array; +using v_noabi::types::b_binary; +using v_noabi::types::b_bool; +using v_noabi::types::b_code; +using v_noabi::types::b_codewscope; +using v_noabi::types::b_date; +using v_noabi::types::b_dbpointer; +using v_noabi::types::b_decimal128; +using v_noabi::types::b_document; +using v_noabi::types::b_double; +using v_noabi::types::b_int32; +using v_noabi::types::b_int64; +using v_noabi::types::b_maxkey; +using v_noabi::types::b_minkey; +using v_noabi::types::b_null; +using v_noabi::types::b_oid; +using v_noabi::types::b_regex; +using v_noabi::types::b_string; +using v_noabi::types::b_symbol; +using v_noabi::types::b_timestamp; +using v_noabi::types::b_undefined; } // namespace types } // namespace bsoncxx @@ -98,3 +100,6 @@ using ::bsoncxx::v_noabi::types::b_undefined; /// @file /// Declares entities used to represent BSON types. /// +/// @par Includes +/// - @ref bsoncxx/v1/types/view-fwd.hpp +/// diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/types.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/types.hpp index 13ed5655a1..044e6af8d3 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/types.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/types.hpp @@ -14,24 +14,26 @@ #pragma once +#include + +// + +#include +#include +#include + #include #include #include -#include - #include #include #include #include #include -#include #include -BSONCXX_PRIVATE_WARNINGS_PUSH(); -BSONCXX_PRIVATE_WARNINGS_DISABLE(GNU("-Wfloat-equal")); - namespace bsoncxx { namespace v_noabi { @@ -83,6 +85,34 @@ enum class binary_sub_type : std::uint8_t { k_user = 0x80, ///< User defined. }; +/// +/// Convert from the @ref bsoncxx::v1 equivalent of `v`. +/// +inline type from_v1(v1::types::id v) { + return static_cast(v); +} + +/// +/// Convert to the @ref bsoncxx::v1 equivalent of `v`. +/// +inline v1::types::id to_v1(type v) { + return static_cast(v); +} + +/// +/// Convert from the @ref bsoncxx::v1 equivalent of `v`. +/// +inline binary_sub_type from_v1(v1::types::binary_subtype v) { + return static_cast(v); +} + +/// +/// Convert to the @ref bsoncxx::v1 equivalent of `v`. +/// +inline v1::types::binary_subtype to_v1(binary_sub_type v) { + return static_cast(v); +} + /// /// Returns a stringification of the given type. /// @@ -91,7 +121,9 @@ enum class binary_sub_type : std::uint8_t { /// /// @return a std::string representation of the type. /// -BSONCXX_ABI_EXPORT_CDECL(std::string) to_string(type rhs); +inline std::string to_string(type rhs) { + return v1::types::to_string(to_v1(rhs)); +} /// /// Returns a stringification of the given binary sub type. @@ -101,7 +133,9 @@ BSONCXX_ABI_EXPORT_CDECL(std::string) to_string(type rhs); /// /// @return a std::string representation of the type. /// -BSONCXX_ABI_EXPORT_CDECL(std::string) to_string(binary_sub_type rhs); +inline std::string to_string(binary_sub_type rhs) { + return v1::types::to_string(to_v1(rhs)); +} namespace types { @@ -109,7 +143,7 @@ namespace types { /// A BSON double value. /// struct b_double { - BSONCXX_ABI_EXPORT static constexpr auto type_id = type::k_double; + static constexpr BSONCXX_ABI_EXPORT auto type_id = type::k_double; double value; @@ -127,14 +161,17 @@ struct b_double { /// @relatesalso bsoncxx::v_noabi::types::b_double /// inline bool operator==(b_double const& lhs, b_double const& rhs) { + BSONCXX_PRIVATE_WARNINGS_PUSH(); + BSONCXX_PRIVATE_WARNINGS_DISABLE(GNU("-Wfloat-equal")); return lhs.value == rhs.value; + BSONCXX_PRIVATE_WARNINGS_POP(); } /// /// A BSON UTF-8 encoded string value. /// struct b_string { - BSONCXX_ABI_EXPORT static constexpr auto type_id = type::k_string; + static constexpr BSONCXX_ABI_EXPORT auto type_id = type::k_string; /// /// Constructor for b_string. @@ -168,7 +205,7 @@ inline bool operator==(b_string const& lhs, b_string const& rhs) { /// A BSON document value. /// struct b_document { - BSONCXX_ABI_EXPORT static constexpr auto type_id = type::k_document; + static constexpr BSONCXX_ABI_EXPORT auto type_id = type::k_document; document::view value; @@ -200,7 +237,7 @@ inline bool operator==(b_document const& lhs, b_document const& rhs) { /// A BSON array value. /// struct b_array { - BSONCXX_ABI_EXPORT static constexpr auto type_id = type::k_array; + static constexpr BSONCXX_ABI_EXPORT auto type_id = type::k_array; array::view value; @@ -225,7 +262,7 @@ inline bool operator==(b_array const& lhs, b_array const& rhs) { /// A BSON binary data value. /// struct b_binary { - BSONCXX_ABI_EXPORT static constexpr auto type_id = type::k_binary; + static constexpr BSONCXX_ABI_EXPORT auto type_id = type::k_binary; binary_sub_type sub_type; uint32_t size; @@ -248,7 +285,7 @@ inline bool operator==(b_binary const& lhs, b_binary const& rhs) { /// @deprecated This BSON type is deprecated. Usage is discouraged. /// struct b_undefined { - BSONCXX_ABI_EXPORT static constexpr auto type_id = type::k_undefined; + static constexpr BSONCXX_ABI_EXPORT auto type_id = type::k_undefined; }; /// @@ -264,7 +301,7 @@ inline bool operator==(b_undefined const&, b_undefined const&) { /// A BSON ObjectId value. /// struct b_oid { - BSONCXX_ABI_EXPORT static constexpr auto type_id = type::k_oid; + static constexpr BSONCXX_ABI_EXPORT auto type_id = type::k_oid; oid value; }; @@ -282,7 +319,7 @@ inline bool operator==(b_oid const& lhs, b_oid const& rhs) { /// A BSON boolean value. /// struct b_bool { - BSONCXX_ABI_EXPORT static constexpr auto type_id = type::k_bool; + static constexpr BSONCXX_ABI_EXPORT auto type_id = type::k_bool; bool value; @@ -307,7 +344,7 @@ inline bool operator==(b_bool const& lhs, b_bool const& rhs) { /// A BSON date value. /// struct b_date { - BSONCXX_ABI_EXPORT static constexpr auto type_id = type::k_date; + static constexpr BSONCXX_ABI_EXPORT auto type_id = type::k_date; /// /// Constructor for b_date @@ -364,7 +401,7 @@ inline bool operator==(b_date const& lhs, b_date const& rhs) { /// A BSON null value. /// struct b_null { - BSONCXX_ABI_EXPORT static constexpr auto type_id = type::k_null; + static constexpr BSONCXX_ABI_EXPORT auto type_id = type::k_null; }; /// @@ -380,7 +417,7 @@ inline bool operator==(b_null const&, b_null const&) { /// A BSON regex value. /// struct b_regex { - BSONCXX_ABI_EXPORT static constexpr auto type_id = type::k_regex; + static constexpr BSONCXX_ABI_EXPORT auto type_id = type::k_regex; /// /// Constructor for b_regex @@ -413,7 +450,7 @@ inline bool operator==(b_regex const& lhs, b_regex const& rhs) { /// @deprecated This BSON type is deprecated. Usage is discouraged. /// struct b_dbpointer { - BSONCXX_ABI_EXPORT static constexpr auto type_id = type::k_dbpointer; + static constexpr BSONCXX_ABI_EXPORT auto type_id = type::k_dbpointer; stdx::string_view collection; oid value; @@ -432,7 +469,7 @@ inline bool operator==(b_dbpointer const& lhs, b_dbpointer const& rhs) { /// A BSON JavaScript code value. /// struct b_code { - BSONCXX_ABI_EXPORT static constexpr auto type_id = type::k_code; + static constexpr BSONCXX_ABI_EXPORT auto type_id = type::k_code; /// /// Constructor for b_code. @@ -468,7 +505,7 @@ inline bool operator==(b_code const& lhs, b_code const& rhs) { /// @deprecated This BSON type is deprecated. Usage is discouraged. /// struct b_symbol { - BSONCXX_ABI_EXPORT static constexpr auto type_id = type::k_symbol; + static constexpr BSONCXX_ABI_EXPORT auto type_id = type::k_symbol; /// /// Constructor for b_symbol. @@ -502,7 +539,7 @@ inline bool operator==(b_symbol const& lhs, b_symbol const& rhs) { /// A BSON JavaScript code with scope value. /// struct b_codewscope { - BSONCXX_ABI_EXPORT static constexpr auto type_id = type::k_codewscope; + static constexpr BSONCXX_ABI_EXPORT auto type_id = type::k_codewscope; /// /// Constructor for b_codewscope. @@ -533,7 +570,7 @@ inline bool operator==(b_codewscope const& lhs, b_codewscope const& rhs) { /// A BSON signed 32-bit integer value. /// struct b_int32 { - BSONCXX_ABI_EXPORT static constexpr auto type_id = type::k_int32; + static constexpr BSONCXX_ABI_EXPORT auto type_id = type::k_int32; int32_t value; @@ -558,7 +595,7 @@ inline bool operator==(b_int32 const& lhs, b_int32 const& rhs) { /// A BSON replication timestamp value. /// struct b_timestamp { - BSONCXX_ABI_EXPORT static constexpr auto type_id = type::k_timestamp; + static constexpr BSONCXX_ABI_EXPORT auto type_id = type::k_timestamp; uint32_t increment; uint32_t timestamp; @@ -577,7 +614,7 @@ inline bool operator==(b_timestamp const& lhs, b_timestamp const& rhs) { /// A BSON 64-bit signed integer value. /// struct b_int64 { - BSONCXX_ABI_EXPORT static constexpr auto type_id = type::k_int64; + static constexpr BSONCXX_ABI_EXPORT auto type_id = type::k_int64; int64_t value; @@ -602,7 +639,7 @@ inline bool operator==(b_int64 const& lhs, b_int64 const& rhs) { /// A BSON Decimal128 value. /// struct b_decimal128 { - BSONCXX_ABI_EXPORT static constexpr auto type_id = type::k_decimal128; + static constexpr BSONCXX_ABI_EXPORT auto type_id = type::k_decimal128; decimal128 value; @@ -629,7 +666,7 @@ inline bool operator==(b_decimal128 const& lhs, b_decimal128 const& rhs) { /// A BSON min-key value. /// struct b_minkey { - BSONCXX_ABI_EXPORT static constexpr auto type_id = type::k_minkey; + static constexpr BSONCXX_ABI_EXPORT auto type_id = type::k_minkey; }; /// @@ -645,7 +682,7 @@ inline bool operator==(b_minkey const&, b_minkey const&) { /// A BSON max-key value. /// struct b_maxkey { - BSONCXX_ABI_EXPORT static constexpr auto type_id = type::k_maxkey; + static constexpr BSONCXX_ABI_EXPORT auto type_id = type::k_maxkey; }; /// @@ -847,22 +884,217 @@ inline bool operator!=(b_maxkey const& lhs, b_maxkey const& rhs) { } } // namespace types + +// BSONCXX_V1_TYPES_XMACRO: update below. + +/// +/// Convert to the @ref bsoncxx::v_noabi equivalent of `v`. +/// +/// @{ + +inline v_noabi::types::b_double from_v1(v1::types::b_double const& v) { + return {v.value}; +} + +inline v_noabi::types::b_string from_v1(v1::types::b_string const& v) { + return v_noabi::types::b_string{v.value}; +} + +inline v_noabi::types::b_document from_v1(v1::types::b_document const& v) { + return {v.value}; +} + +inline v_noabi::types::b_array from_v1(v1::types::b_array const& v) { + return {v.value}; +} + +inline v_noabi::types::b_binary from_v1(v1::types::b_binary const& v) { + return {from_v1(v.subtype), v.size, v.bytes}; +} + +inline v_noabi::types::b_undefined from_v1(v1::types::b_undefined const& v) { + (void)v; + return {}; +} + +inline v_noabi::types::b_oid from_v1(v1::types::b_oid const& v) { + return {v.value}; +} + +inline v_noabi::types::b_bool from_v1(v1::types::b_bool const& v) { + return {v.value}; +} + +inline v_noabi::types::b_date from_v1(v1::types::b_date const& v) { + return v_noabi::types::b_date{v.value}; +} + +inline v_noabi::types::b_null from_v1(v1::types::b_null const& v) { + (void)v; + return {}; +} + +inline v_noabi::types::b_regex from_v1(v1::types::b_regex const& v) { + return v_noabi::types::b_regex{v.regex, v.options}; +} + +inline v_noabi::types::b_dbpointer from_v1(v1::types::b_dbpointer const& v) { + return {v.collection, v.value}; +} + +inline v_noabi::types::b_code from_v1(v1::types::b_code const& v) { + return v_noabi::types::b_code{v.code}; +} + +inline v_noabi::types::b_symbol from_v1(v1::types::b_symbol const& v) { + return v_noabi::types::b_symbol{v.symbol}; +} + +inline v_noabi::types::b_codewscope from_v1(v1::types::b_codewscope const& v) { + return v_noabi::types::b_codewscope{v.code, v.scope}; +} + +inline v_noabi::types::b_int32 from_v1(v1::types::b_int32 const& v) { + return {v.value}; +} + +inline v_noabi::types::b_timestamp from_v1(v1::types::b_timestamp const& v) { + return {v.increment, v.timestamp}; +} + +inline v_noabi::types::b_int64 from_v1(v1::types::b_int64 const& v) { + return {v.value}; +} + +inline v_noabi::types::b_decimal128 from_v1(v1::types::b_decimal128 const& v) { + return v_noabi::types::b_decimal128{v.value}; +} + +inline v_noabi::types::b_maxkey from_v1(v1::types::b_maxkey const& v) { + (void)v; + return {}; +} + +inline v_noabi::types::b_minkey from_v1(v1::types::b_minkey const& v) { + (void)v; + return {}; +} + +/// @} +/// + +/// +/// Convert to the @ref bsoncxx::v1 equivalent of `v`. +/// +/// @{ + +inline v1::types::b_double to_v1(v_noabi::types::b_double const& v) { + return v1::types::b_double{v.value}; +} + +inline v1::types::b_string to_v1(v_noabi::types::b_string const& v) { + return v1::types::b_string{v.value}; +} + +inline v1::types::b_document to_v1(v_noabi::types::b_document const& v) { + return v1::types::b_document{to_v1(v.value)}; +} + +inline v1::types::b_array to_v1(v_noabi::types::b_array const& v) { + return v1::types::b_array{to_v1(v.value)}; +} + +inline v1::types::b_binary to_v1(v_noabi::types::b_binary const& v) { + return v1::types::b_binary{to_v1(v.sub_type), v.size, v.bytes}; +} + +inline v1::types::b_undefined to_v1(v_noabi::types::b_undefined const& v) { + (void)v; + return v1::types::b_undefined{}; +} + +inline v1::types::b_oid to_v1(v_noabi::types::b_oid const& v) { + return v1::types::b_oid{to_v1(v.value)}; +} + +inline v1::types::b_bool to_v1(v_noabi::types::b_bool const& v) { + return v1::types::b_bool{v.value}; +} + +inline v1::types::b_date to_v1(v_noabi::types::b_date const& v) { + return v1::types::b_date{v.value}; +} + +inline v1::types::b_null to_v1(v_noabi::types::b_null const& v) { + (void)v; + return v1::types::b_null{}; +} + +inline v1::types::b_regex to_v1(v_noabi::types::b_regex const& v) { + return v1::types::b_regex{v.regex, v.options}; +} + +inline v1::types::b_dbpointer to_v1(v_noabi::types::b_dbpointer const& v) { + return v1::types::b_dbpointer{v.collection, to_v1(v.value)}; +} + +inline v1::types::b_code to_v1(v_noabi::types::b_code const& v) { + return v1::types::b_code{v.code}; +} + +inline v1::types::b_symbol to_v1(v_noabi::types::b_symbol const& v) { + return v1::types::b_symbol{v.symbol}; +} + +inline v1::types::b_codewscope to_v1(v_noabi::types::b_codewscope const& v) { + return v1::types::b_codewscope{v.code, to_v1(v.scope)}; +} + +inline v1::types::b_int32 to_v1(v_noabi::types::b_int32 const& v) { + return v1::types::b_int32{v.value}; +} + +inline v1::types::b_timestamp to_v1(v_noabi::types::b_timestamp const& v) { + return v1::types::b_timestamp{v.increment, v.timestamp}; +} + +inline v1::types::b_int64 to_v1(v_noabi::types::b_int64 const& v) { + return v1::types::b_int64{v.value}; +} + +inline v1::types::b_decimal128 to_v1(v_noabi::types::b_decimal128 const& v) { + return v1::types::b_decimal128{to_v1(v.value)}; +} + +inline v1::types::b_maxkey to_v1(v_noabi::types::b_maxkey const& v) { + (void)v; + return v1::types::b_maxkey{}; +} + +inline v1::types::b_minkey to_v1(v_noabi::types::b_minkey const& v) { + (void)v; + return v1::types::b_minkey{}; +} + +/// @} +/// + +// BSONCXX_V1_TYPES_XMACRO: update above. + } // namespace v_noabi } // namespace bsoncxx -BSONCXX_PRIVATE_WARNINGS_POP(); - namespace bsoncxx { -using ::bsoncxx::v_noabi::to_string; +using v_noabi::to_string; } // namespace bsoncxx namespace bsoncxx { namespace types { -using ::bsoncxx::v_noabi::types::operator==; -using ::bsoncxx::v_noabi::types::operator!=; +using v_noabi::types::operator==; +using v_noabi::types::operator!=; } // namespace types } // namespace bsoncxx @@ -873,3 +1105,6 @@ using ::bsoncxx::v_noabi::types::operator!=; /// @file /// Provides entities used to represent BSON types. /// +/// @par Includes +/// - @ref bsoncxx/v1/types/view.hpp +/// diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/types/bson_value/value-fwd.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/types/bson_value/value-fwd.hpp index cf5567072c..e3b78816e0 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/types/bson_value/value-fwd.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/types/bson_value/value-fwd.hpp @@ -14,6 +14,8 @@ #pragma once +#include + #include namespace bsoncxx { @@ -24,6 +26,9 @@ namespace bson_value { class value; } // namespace bson_value + +using bson_value::value; + } // namespace types } // namespace v_noabi } // namespace bsoncxx @@ -32,9 +37,12 @@ namespace bsoncxx { namespace types { namespace bson_value { -using ::bsoncxx::v_noabi::types::bson_value::value; +using v_noabi::types::bson_value::value; } // namespace bson_value + +using bson_value::value; + } // namespace types } // namespace bsoncxx @@ -44,3 +52,6 @@ using ::bsoncxx::v_noabi::types::bson_value::value; /// @file /// Declares @ref bsoncxx::v_noabi::types::bson_value::value. /// +/// @par Includes +/// - @ref bsoncxx/v1/types/value-fwd.hpp +/// diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/types/bson_value/value.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/types/bson_value/value.hpp index 64f05a0ad1..4364d3bfb6 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/types/bson_value/value.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/types/bson_value/value.hpp @@ -14,13 +14,20 @@ #pragma once +#include + +// + +#include +#include + #include #include #include +#include #include #include -#include #include #include @@ -46,99 +53,114 @@ namespace bson_value { /// - @ref bsoncxx::v_noabi::types::bson_value::view /// class value { + private: + v1::types::value _value; + + template + using is_value = detail::is_alike; + + template + using from_v1_expr = decltype(from_v1(std::declval())); + + template + struct has_from_v1 : detail::conjunction>, detail::is_detected> {}; + public: + /// @copydoc v1::types::value::value() + value() = default; + + /// + /// Construct with the @ref bsoncxx::v1 equivalent. + /// + /* explicit(false) */ value(v1::types::value v) : _value{std::move(v)} {} + + /// + /// Construct with the @ref bsoncxx::v1 equivalent. + /// + /// @par Constraints: + /// - `from_v1(v)` is found via ADL. + /// + template ::value>* = nullptr> + /* explicit(false) */ value(T v) : value{from_v1(v)} {} + +#pragma push_macro("X") +#undef X +#define X(_name, _unused) \ + /* explicit(false) */ value(v_noabi::types::b_##_name v) : _value{to_v1(v)} {} + /// /// Construct a bson_value::value from the provided BSON type. /// /// @{ - BSONCXX_ABI_EXPORT_CDECL() value(b_double v); - BSONCXX_ABI_EXPORT_CDECL() value(b_string v); - BSONCXX_ABI_EXPORT_CDECL() value(b_document v); - BSONCXX_ABI_EXPORT_CDECL() value(b_array v); - BSONCXX_ABI_EXPORT_CDECL() value(b_binary v); - BSONCXX_ABI_EXPORT_CDECL() value(b_undefined v); - BSONCXX_ABI_EXPORT_CDECL() value(b_oid v); - BSONCXX_ABI_EXPORT_CDECL() value(b_bool v); - BSONCXX_ABI_EXPORT_CDECL() value(b_date v); - BSONCXX_ABI_EXPORT_CDECL() value(b_null); - BSONCXX_ABI_EXPORT_CDECL() value(b_regex v); - BSONCXX_ABI_EXPORT_CDECL() value(b_dbpointer v); - BSONCXX_ABI_EXPORT_CDECL() value(b_code v); - BSONCXX_ABI_EXPORT_CDECL() value(b_symbol v); - BSONCXX_ABI_EXPORT_CDECL() value(b_codewscope v); - BSONCXX_ABI_EXPORT_CDECL() value(b_int32 v); - BSONCXX_ABI_EXPORT_CDECL() value(b_timestamp v); - BSONCXX_ABI_EXPORT_CDECL() value(b_int64 v); - BSONCXX_ABI_EXPORT_CDECL() value(b_decimal128 v); - BSONCXX_ABI_EXPORT_CDECL() value(b_maxkey v); - BSONCXX_ABI_EXPORT_CDECL() value(b_minkey v); + BSONCXX_V1_TYPES_XMACRO(X) /// @} /// +#pragma pop_macro("X") /// /// Constructs a BSON UTF-8 string value. /// - BSONCXX_ABI_EXPORT_CDECL() value(char const* v); + /* explicit(false) */ value(char const* v) : _value{v} {} /// /// Constructs a BSON UTF-8 string value. /// - BSONCXX_ABI_EXPORT_CDECL() value(std::string v); + /* explicit(false) */ value(std::string v) : _value{std::move(v)} {} /// /// Constructs a BSON UTF-8 string value. /// - BSONCXX_ABI_EXPORT_CDECL() value(stdx::string_view v); + /* explicit(false) */ value(v1::stdx::string_view v) : _value{v} {} /// /// Constructs a BSON 32-bit signed integer value. /// - BSONCXX_ABI_EXPORT_CDECL() value(int32_t v); + /* explicit(false) */ value(std::int32_t v) : _value{v} {} /// /// Constructs a BSON 64-bit signed integer value. /// - BSONCXX_ABI_EXPORT_CDECL() value(int64_t v); + /* explicit(false) */ value(std::int64_t v) : _value{v} {} /// /// Constructs a BSON double value. /// - BSONCXX_ABI_EXPORT_CDECL() value(double v); + /* explicit(false) */ value(double v) : _value{v} {} /// /// Constructs a BSON boolean value. /// - BSONCXX_ABI_EXPORT_CDECL() value(bool v); + /* explicit(false) */ value(bool v) : _value{v} {} /// /// Constructs a BSON ObjectId value. /// - BSONCXX_ABI_EXPORT_CDECL() value(oid v); + /* explicit(false) */ value(v_noabi::oid v) : _value{to_v1(v)} {} /// /// Constructs a BSON Decimal128 value. /// - BSONCXX_ABI_EXPORT_CDECL() value(decimal128 v); + /* explicit(false) */ value(v_noabi::decimal128 v) : _value{to_v1(v)} {} /// /// Constructs a BSON date value. /// - BSONCXX_ABI_EXPORT_CDECL() value(std::chrono::milliseconds v); + /* explicit(false) */ value(std::chrono::milliseconds v) : _value{v} {} /// /// Constructs a BSON null value. /// - BSONCXX_ABI_EXPORT_CDECL() value(std::nullptr_t); + /* explicit(false) */ value(std::nullptr_t) : _value{nullptr} {} /// /// Constructs a BSON document value. /// - BSONCXX_ABI_EXPORT_CDECL() value(bsoncxx::v_noabi::document::view v); + /* explicit(false) */ value(v_noabi::document::view v) : _value{to_v1(v)} {} /// /// Constructs a BSON array value. /// - BSONCXX_ABI_EXPORT_CDECL() value(bsoncxx::v_noabi::array::view v); + /* explicit(false) */ value(v_noabi::array::view v) : _value{to_v1(v)} {} /// /// Constructs a BSON binary data value. @@ -148,8 +170,9 @@ class value { /// @param sub_type /// an optional binary sub type. Defaults to type::k_binary /// - BSONCXX_ABI_EXPORT_CDECL() - value(std::vector v, binary_sub_type const sub_type = {}); + /* explicit(false) */ + value(std::vector v, v_noabi::binary_sub_type const sub_type = {}) + : _value{reinterpret_cast(v.data()), v.size(), to_v1(sub_type)} {} /// /// Constructs a BSON binary data value. @@ -161,8 +184,9 @@ class value { /// @param sub_type /// an optional binary sub type. Defaults to type::k_binary /// - BSONCXX_ABI_EXPORT_CDECL() - value(uint8_t const* data, size_t size, binary_sub_type const sub_type = {}); + /* explicit(false) */ + value(std::uint8_t const* data, std::size_t size, v_noabi::binary_sub_type const sub_type = {}) + : _value{data, size, to_v1(sub_type)} {} /// /// Constructs a BSON DBPointer value. @@ -174,7 +198,8 @@ class value { /// /// @warning The DBPointer (aka DBRef) BSON type is deprecated. Usage is discouraged. /// - BSONCXX_ABI_EXPORT_CDECL() value(stdx::string_view collection, oid value); + /* explicit(false) */ value(v1::stdx::string_view collection, v_noabi::oid value) + : _value{collection, to_v1(value)} {} /// /// Constructs a BSON JavaScript code with scope value. @@ -184,8 +209,8 @@ class value { /// @param scope /// a bson document view holding the scope environment /// - BSONCXX_ABI_EXPORT_CDECL() - value(stdx::string_view code, bsoncxx::v_noabi::document::view_or_value scope); + /* explicit(false) */ value(v1::stdx::string_view code, v_noabi::document::view_or_value scope) + : _value{code, to_v1(scope.view())} {} /// /// Constructs a BSON regex value with options. @@ -195,7 +220,8 @@ class value { /// @param options /// The regex options /// - BSONCXX_ABI_EXPORT_CDECL() value(stdx::string_view regex, stdx::string_view options); + /* explicit(false) */ value(v1::stdx::string_view regex, v1::stdx::string_view options) + : _value{v1::types::b_regex{regex, options}} {} /// /// Constructs one of the following BSON values (each specified by the parenthesized type): @@ -214,7 +240,7 @@ class value { /// @warning The Symbol BSON type is deprecated. Usage is discouraged. /// @warning The Undefined BSON type is deprecated. Usage is discouraged. /// - BSONCXX_ABI_EXPORT_CDECL() value(type const id, stdx::string_view v); + /* explicit(false) */ BSONCXX_ABI_EXPORT_CDECL() value(v_noabi::type const id, v1::stdx::string_view v); /// /// Constructs one of the following BSON values (each specified by the parenthesized type): @@ -228,7 +254,7 @@ class value { /// @throws bsoncxx::v_noabi::exception if the type's value is not k_maxkey, k_minkey, or /// k_undefined. /// - BSONCXX_ABI_EXPORT_CDECL() value(type const id); + /* explicit(false) */ BSONCXX_ABI_EXPORT_CDECL() value(type const id); /// /// Constructs one of the following BSON values (each specified by the parenthesized type): @@ -250,44 +276,40 @@ class value { /// The BSON timestamp type is used internally by the MongoDB server - use by clients /// is discouraged. /// - BSONCXX_ABI_EXPORT_CDECL() value(type const id, uint64_t a, uint64_t b); - - BSONCXX_ABI_EXPORT_CDECL() ~value(); + BSONCXX_ABI_EXPORT_CDECL() value(v_noabi::type const id, std::uint64_t a, std::uint64_t b); - BSONCXX_ABI_EXPORT_CDECL() value(value const&); - BSONCXX_ABI_EXPORT_CDECL(value&) operator=(value const&); + /// + /// Create an owning copy of a bson_value::view. + /// + explicit value(v_noabi::types::bson_value::view const& v) : _value{to_v1(v)} {} - BSONCXX_ABI_EXPORT_CDECL() value(value&&) noexcept; - BSONCXX_ABI_EXPORT_CDECL(value&) operator=(value&&) noexcept; + /// + /// Convert to the @ref bsoncxx::v1 equivalent. + /// + explicit operator v1::types::value() && { + return std::move(_value); + } /// - /// Create an owning copy of a bson_value::view. + /// Convert to the @ref bsoncxx::v1 equivalent. /// - explicit BSONCXX_ABI_EXPORT_CDECL() value(bson_value::view const&); + explicit operator v1::types::value() const& { + return _value; + } /// /// Get a view over the bson_value owned by this object. /// - BSONCXX_ABI_EXPORT_CDECL(bson_value::view) view() const noexcept; + v_noabi::types::bson_value::view view() const noexcept { + return _value.view(); + } /// /// Conversion operator that provides a bson_value::view given a bson_value::value. /// - BSONCXX_ABI_EXPORT_CDECL() operator bson_value::view() const noexcept; - - private: - friend ::bsoncxx::v_noabi::document::element; - - value(std::uint8_t const* raw, std::uint32_t length, std::uint32_t offset, std::uint32_t keylen); - - // Makes a copy of 'internal_value' and owns the copy. - // Export is required by mongocxx via make_owning_bson. - BSONCXX_ABI_EXPORT_CDECL() value(void* internal_value); - - friend value make_owning_bson(void* internal_value); - - class impl; - std::unique_ptr _impl; + /* explicit(false) */ operator v_noabi::types::bson_value::view() const noexcept { + return _value.view(); + } }; /// @@ -341,12 +363,32 @@ inline bool operator!=(view const& lhs, value const& rhs) { } // namespace v_noabi } // namespace bsoncxx +namespace bsoncxx { +namespace v_noabi { + +/// +/// Convert to the @ref bsoncxx::v_noabi equivalent of `v`. +/// +inline v_noabi::types::bson_value::value from_v1(v1::types::value v) { + return {std::move(v)}; +} + +/// +/// Convert to the @ref bsoncxx::v1 equivalent of `v`. +/// +inline v1::types::value to_v1(v_noabi::types::bson_value::value v) { + return v1::types::value{std::move(v)}; +} + +} // namespace v_noabi +} // namespace bsoncxx + namespace bsoncxx { namespace types { namespace bson_value { -using ::bsoncxx::v_noabi::types::bson_value::operator==; -using ::bsoncxx::v_noabi::types::bson_value::operator!=; +using v_noabi::types::bson_value::operator==; +using v_noabi::types::bson_value::operator!=; } // namespace bson_value } // namespace types @@ -358,3 +400,6 @@ using ::bsoncxx::v_noabi::types::bson_value::operator!=; /// @file /// Provides @ref bsoncxx::v_noabi::types::bson_value::value. /// +/// @par Includes +/// - @ref bsoncxx/v1/types/value.hpp +/// diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/types/bson_value/view-fwd.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/types/bson_value/view-fwd.hpp index f96f17cfac..756b914b2e 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/types/bson_value/view-fwd.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/types/bson_value/view-fwd.hpp @@ -14,6 +14,8 @@ #pragma once +#include + #include namespace bsoncxx { @@ -24,6 +26,9 @@ namespace bson_value { class view; } // namespace bson_value + +using bson_value::view; + } // namespace types } // namespace v_noabi } // namespace bsoncxx @@ -32,9 +37,12 @@ namespace bsoncxx { namespace types { namespace bson_value { -using ::bsoncxx::v_noabi::types::bson_value::view; +using v_noabi::types::bson_value::view; } // namespace bson_value + +using bson_value::view; + } // namespace types } // namespace bsoncxx @@ -44,3 +52,6 @@ using ::bsoncxx::v_noabi::types::bson_value::view; /// @file /// Declares @ref bsoncxx::v_noabi::types::bson_value::view. /// +/// @par Includes +/// - @ref bsoncxx/v1/types/view-fwd.hpp +/// diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/types/bson_value/view.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/types/bson_value/view.hpp index 792e95c923..905657427c 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/types/bson_value/view.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/types/bson_value/view.hpp @@ -14,13 +14,18 @@ #pragma once +#include + +// + +#include + #include #include #include #include #include -#include #include #include @@ -32,10 +37,10 @@ namespace detail { template using is_bson_view_compatible = detail::conjunction< - std::is_constructible, + std::is_constructible, detail::negation, - detail::is_alike>>>; + detail::is_alike, + detail::is_alike>>>; } // namespace detail } // namespace bsoncxx @@ -53,266 +58,109 @@ namespace bson_value { /// to be thrown. /// class view { - public: - /// - /// Construct a bson_value::view from the provided BSON type. - /// - /// @{ - explicit BSONCXX_ABI_EXPORT_CDECL() view(b_double v) noexcept; - explicit BSONCXX_ABI_EXPORT_CDECL() view(b_string v) noexcept; - explicit BSONCXX_ABI_EXPORT_CDECL() view(b_document v) noexcept; - explicit BSONCXX_ABI_EXPORT_CDECL() view(b_array v) noexcept; - explicit BSONCXX_ABI_EXPORT_CDECL() view(b_binary v) noexcept; - explicit BSONCXX_ABI_EXPORT_CDECL() view(b_undefined v) noexcept; - explicit BSONCXX_ABI_EXPORT_CDECL() view(b_oid v) noexcept; - explicit BSONCXX_ABI_EXPORT_CDECL() view(b_bool v) noexcept; - explicit BSONCXX_ABI_EXPORT_CDECL() view(b_date v) noexcept; - explicit BSONCXX_ABI_EXPORT_CDECL() view(b_null v) noexcept; - explicit BSONCXX_ABI_EXPORT_CDECL() view(b_regex v) noexcept; - explicit BSONCXX_ABI_EXPORT_CDECL() view(b_dbpointer v) noexcept; - explicit BSONCXX_ABI_EXPORT_CDECL() view(b_code v) noexcept; - explicit BSONCXX_ABI_EXPORT_CDECL() view(b_symbol v) noexcept; - explicit BSONCXX_ABI_EXPORT_CDECL() view(b_codewscope v) noexcept; - explicit BSONCXX_ABI_EXPORT_CDECL() view(b_int32 v) noexcept; - explicit BSONCXX_ABI_EXPORT_CDECL() view(b_timestamp v) noexcept; - explicit BSONCXX_ABI_EXPORT_CDECL() view(b_int64 v) noexcept; - explicit BSONCXX_ABI_EXPORT_CDECL() view(b_decimal128 v) noexcept; - explicit BSONCXX_ABI_EXPORT_CDECL() view(b_maxkey v) noexcept; - explicit BSONCXX_ABI_EXPORT_CDECL() view(b_minkey v) noexcept; - /// @} - /// - - /// - /// Default constructs a bson_value::view. The resulting view will be initialized - /// to point at a bson_value of type k_null. - /// - BSONCXX_ABI_EXPORT_CDECL() view() noexcept; - - BSONCXX_ABI_EXPORT_CDECL() view(view const&) noexcept; - BSONCXX_ABI_EXPORT_CDECL(view&) operator=(view const&) noexcept; - - BSONCXX_ABI_EXPORT_CDECL() ~view(); - - /// - /// @relates bsoncxx::v_noabi::types::bson_value::view - /// - /// Compare two bson_value::views for equality - /// - /// @{ - friend BSONCXX_ABI_EXPORT_CDECL(bool) operator==(bson_value::view const&, bson_value::view const&); - friend BSONCXX_ABI_EXPORT_CDECL(bool) operator!=(bson_value::view const&, bson_value::view const&); - /// @} - /// - - /// - /// Returns the type of the underlying BSON value stored in this object. - /// - BSONCXX_ABI_EXPORT_CDECL(bsoncxx::v_noabi::type) type() const; - - /// - /// Returns the underlying BSON double value. - /// - /// @warning - /// Calling the wrong get_ method will cause an exception to be thrown. - /// - BSONCXX_ABI_EXPORT_CDECL(b_double const&) get_double() const; - - /// - /// Returns the underlying BSON UTF-8 string value. - /// - /// @warning - /// Calling the wrong get_ method will cause an exception to be thrown. - /// - BSONCXX_ABI_EXPORT_CDECL(b_string const&) get_string() const; + private: + v_noabi::type _id; - /// - /// Returns the underlying BSON document value. - /// - /// @warning - /// Calling the wrong get_ method will cause an exception to be thrown. - /// - BSONCXX_ABI_EXPORT_CDECL(b_document const&) get_document() const; +#pragma push_macro("X") +#undef X +#define X(_name, _value) b_##_name _b_##_name; - /// - /// Returns the underlying BSON array value. - /// - /// @warning - /// Calling the wrong get_ method will cause an exception to be thrown. - /// - BSONCXX_ABI_EXPORT_CDECL(b_array const&) get_array() const; + union { + BSONCXX_V1_TYPES_XMACRO(X) + }; +#pragma pop_macro("X") + public: /// - /// Returns the underlying BSON binary data value. - /// - /// @warning - /// Calling the wrong get_ method will cause an exception to be thrown. + /// Default constructs a bson_value::view. The resulting view will be initialized + /// to point at a bson_value of type k_null. /// - BSONCXX_ABI_EXPORT_CDECL(b_binary const&) get_binary() const; + view() noexcept : _id{v_noabi::type::k_null}, _b_null{} {} /// - /// Returns the underlying BSON undefined value. - /// - /// @warning - /// Calling the wrong get_ method will cause an exception to be thrown. + /// Construct with the @ref bsoncxx::v1 equivalent. /// - BSONCXX_ABI_EXPORT_CDECL(b_undefined const&) get_undefined() const; + /* explicit(false) */ view(v1::types::view const& v) : _id{from_v1(v.type_id())} { +#pragma push_macro("X") +#undef X +#define X(_name, _value) \ + case v_noabi::type::k_##_name: \ + _b_##_name = from_v1(v.get_##_name()); \ + break; - /// - /// Returns the underlying BSON ObjectId value. - /// - /// @warning - /// Calling the wrong get_ method will cause an exception to be thrown. - /// - BSONCXX_ABI_EXPORT_CDECL(b_oid const&) get_oid() const; + switch (_id) { BSONCXX_V1_TYPES_XMACRO(X) } +#pragma pop_macro("X") + } - /// - /// Returns the underlying BSON boolean value. - /// - /// @warning - /// Calling the wrong get_ method will cause an exception to be thrown. - /// - BSONCXX_ABI_EXPORT_CDECL(b_bool const&) get_bool() const; +#pragma push_macro("X") +#undef X +#define X(_name, _value) \ + explicit view(v_noabi::types::b_##_name v) noexcept : _id{v.type_id}, _b_##_name{v} {} /// - /// Returns the underlying BSON date value. - /// - /// @warning - /// Calling the wrong get_ method will cause an exception to be thrown. - /// - BSONCXX_ABI_EXPORT_CDECL(b_date const&) get_date() const; - - /// - /// Returns the underlying BSON null value. + /// Construct a bson_value::view from the provided BSON type. /// - /// @warning - /// Calling the wrong get_ method will cause an exception to be thrown. + /// @{ + BSONCXX_V1_TYPES_XMACRO(X) + /// @} /// - BSONCXX_ABI_EXPORT_CDECL(b_null const&) get_null() const; +#pragma pop_macro("X") /// - /// Returns the underlying BSON regex value. + /// Convert to the @ref bsoncxx::v1 equivalent. /// - /// @warning - /// Calling the wrong get_ method will cause an exception to be thrown. - /// - BSONCXX_ABI_EXPORT_CDECL(b_regex const&) get_regex() const; + explicit operator v1::types::view() const { +#pragma push_macro("X") +#undef X +#define X(_name, _value) \ + case v_noabi::type::k_##_name: \ + return {to_v1(_b_##_name)}; - /// - /// Returns the underlying BSON DBPointer value. - /// - /// @warning - /// Calling the wrong get_ method will cause an exception to be thrown. - /// - BSONCXX_ABI_EXPORT_CDECL(b_dbpointer const&) get_dbpointer() const; + switch (_id) { + BSONCXX_V1_TYPES_XMACRO(X) - /// - /// Returns the underlying BSON JavaScript code value. - /// - /// @warning - /// Calling the wrong get_ method will cause an exception to be thrown. - /// - BSONCXX_ABI_EXPORT_CDECL(b_code const&) get_code() const; + default: + return {}; // Unreachable. + } +#pragma pop_macro("X") + } /// - /// Returns the underlying BSON symbol value. - /// - /// @warning - /// Calling the wrong get_ method will cause an exception to be thrown. - /// - BSONCXX_ABI_EXPORT_CDECL(b_symbol const&) get_symbol() const; - - /// - /// Returns the underlying BSON JavaScript code with scope value. - /// - /// @warning - /// Calling the wrong get_ method will cause an exception to be thrown. - /// - BSONCXX_ABI_EXPORT_CDECL(b_codewscope const&) get_codewscope() const; - - /// - /// Returns the underlying BSON 32-bit signed integer value. - /// - /// @warning - /// Calling the wrong get_ method will cause an exception to be thrown. + /// Returns the type of the underlying BSON value stored in this object. /// - BSONCXX_ABI_EXPORT_CDECL(b_int32 const&) get_int32() const; + v_noabi::type type() const { + return _id; + } - /// - /// Returns the underlying BSON replication timestamp value. - /// - /// @warning - /// Calling the wrong get_ method will cause an exception to be thrown. - /// - BSONCXX_ABI_EXPORT_CDECL(b_timestamp const&) get_timestamp() const; +#pragma push_macro("X") +#undef X +#define X(_name, _value) BSONCXX_ABI_EXPORT_CDECL(v_noabi::types::b_##_name const&) get_##_name() const; /// - /// Returns the underlying BSON 64-bit signed integer value. + /// Return the underlying BSON type value. /// /// @warning /// Calling the wrong get_ method will cause an exception to be thrown. /// - BSONCXX_ABI_EXPORT_CDECL(b_int64 const&) get_int64() const; - - /// - /// Returns the underlying BSON Decimal128 value. - /// - /// @warning - /// Calling the wrong get_ method will cause an exception to be thrown. + /// @{ + BSONCXX_V1_TYPES_XMACRO(X) + /// @} /// - BSONCXX_ABI_EXPORT_CDECL(b_decimal128 const&) get_decimal128() const; +#pragma pop_macro("X") /// - /// Returns the underlying BSON min-key value. + /// @relates bsoncxx::v_noabi::types::bson_value::view /// - /// @warning - /// Calling the wrong get_ method will cause an exception to be thrown. + /// Compare two bson_value::views for equality /// - BSONCXX_ABI_EXPORT_CDECL(b_minkey const&) get_minkey() const; + /// @{ + friend BSONCXX_ABI_EXPORT_CDECL(bool) operator==(view const& lhs, view const& rhs); + friend bool operator!=(view const& lhs, view const& rhs) { + return !(lhs == rhs); + } + /// @} /// - /// Returns the underlying BSON max-key value. - /// - /// @warning - /// Calling the wrong get_ method will cause an exception to be thrown. - /// - BSONCXX_ABI_EXPORT_CDECL(b_maxkey const&) get_maxkey() const; - - private: - friend ::bsoncxx::v_noabi::types::bson_value::value; - friend ::bsoncxx::v_noabi::document::element; - - view(std::uint8_t const* raw, std::uint32_t length, std::uint32_t offset, std::uint32_t keylen); - view(void* internal_value) noexcept; - - void _init(void* internal_value) noexcept; - - void destroy() noexcept; - - bsoncxx::v_noabi::type _type; - - union { - struct b_double _b_double; - struct b_string _b_string; - struct b_document _b_document; - struct b_array _b_array; - struct b_binary _b_binary; - struct b_undefined _b_undefined; - struct b_oid _b_oid; - struct b_bool _b_bool; - struct b_date _b_date; - struct b_null _b_null; - struct b_regex _b_regex; - struct b_dbpointer _b_dbpointer; - struct b_code _b_code; - struct b_symbol _b_symbol; - struct b_codewscope _b_codewscope; - struct b_int32 _b_int32; - struct b_timestamp _b_timestamp; - struct b_int64 _b_int64; - struct b_decimal128 _b_decimal128; - struct b_minkey _b_minkey; - struct b_maxkey _b_maxkey; - }; }; /// @@ -325,26 +173,26 @@ class view { /// @relatesalso bsoncxx::v_noabi::types::bson_value::view template -detail::requires_t> operator==(bson_value::view const& lhs, T&& rhs) { - return lhs == bson_value::view{std::forward(rhs)}; +detail::requires_t> operator==(view const& lhs, T&& rhs) { + return lhs == view{std::forward(rhs)}; } /// @relatesalso bsoncxx::v_noabi::types::bson_value::view template -detail::requires_t> operator==(T&& lhs, bson_value::view const& rhs) { - return bson_value::view{std::forward(lhs)} == rhs; +detail::requires_t> operator==(T&& lhs, view const& rhs) { + return view{std::forward(lhs)} == rhs; } /// @relatesalso bsoncxx::v_noabi::types::bson_value::view template -detail::requires_t> operator!=(bson_value::view const& lhs, T&& rhs) { - return lhs != bson_value::view{std::forward(rhs)}; +detail::requires_t> operator!=(view const& lhs, T&& rhs) { + return lhs != view{std::forward(rhs)}; } /// @relatesalso bsoncxx::v_noabi::types::bson_value::view template -detail::requires_t> operator!=(T&& lhs, bson_value::view const& rhs) { - return bson_value::view{std::forward(lhs)} != rhs; +detail::requires_t> operator!=(T&& lhs, view const& rhs) { + return view{std::forward(lhs)} != rhs; } /// @} @@ -355,12 +203,32 @@ detail::requires_t> operator!=(T&& lhs, } // namespace v_noabi } // namespace bsoncxx +namespace bsoncxx { +namespace v_noabi { + +/// +/// Convert to the @ref bsoncxx::v_noabi equivalent of `v`. +/// +inline v_noabi::types::bson_value::view from_v1(v1::types::view const& v) { + return {v}; +} + +/// +/// Convert to the @ref bsoncxx::v1 equivalent of `v`. +/// +inline v1::types::view to_v1(v_noabi::types::bson_value::view const& v) { + return v1::types::view{v}; +} + +} // namespace v_noabi +} // namespace bsoncxx + namespace bsoncxx { namespace types { namespace bson_value { -using ::bsoncxx::v_noabi::types::bson_value::operator==; -using ::bsoncxx::v_noabi::types::bson_value::operator!=; +using v_noabi::types::bson_value::operator==; +using v_noabi::types::bson_value::operator!=; } // namespace bson_value } // namespace types @@ -372,3 +240,6 @@ using ::bsoncxx::v_noabi::types::bson_value::operator!=; /// @file /// Provides @ref bsoncxx::v_noabi::types::bson_value::view. /// +/// @par Includes +/// - @ref bsoncxx/v1/types/view.hpp +/// 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 5e2030a49a..891d88f5b0 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/elements.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/vector/elements.hpp @@ -18,9 +18,7 @@ // -#ifndef _WIN32 -#include // Endian detection -#endif +#include #include #include @@ -36,43 +34,19 @@ namespace elements { /// @brief A 32-bit float value in packed little-endian format class float32 { + template + void construct(float value); + + template + float convert() const; + 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(_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 = __builtin_bswap32(u32); - std::memcpy(bytes, &u32, sizeof value); -#else -#error No implementation for storing 32-bit little endian unaligned float -#endif - } + float32(float value) noexcept; /// Convert a packed little-endian floating point value back to the local byte order. - operator float() const noexcept { - float value; -#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 = __builtin_bswap32(u32); - std::memcpy(&value, &u32, sizeof value); -#else -#error No implementation for loading 32-bit little endian unaligned float -#endif - return value; - } + operator float() const noexcept; /// Operator +=, emulating normal float behavior float32& operator+=(float const& other) noexcept { @@ -98,6 +72,46 @@ class float32 { std::uint8_t bytes[4]; }; +template <> +inline void float32::construct(float value) { + std::memcpy(bytes, &value, sizeof value); +} + +template <> +inline void float32::construct(float value) { + auto const ptr = reinterpret_cast(&value); + bytes[0] = ptr[3]; + bytes[1] = ptr[2]; + bytes[2] = ptr[1]; + bytes[3] = ptr[0]; +} + +template <> +inline float float32::convert() const { + float value; + std::memcpy(&value, bytes, sizeof value); + return value; +} + +template <> +inline float float32::convert() const { + float value; + auto const ptr = reinterpret_cast(&value); + ptr[0] = bytes[3]; + ptr[1] = bytes[2]; + ptr[2] = bytes[1]; + ptr[3] = bytes[0]; + return value; +} + +inline float32::float32(float value) noexcept { + this->construct(value); +} + +inline float32::operator float() const noexcept { + return this->convert(); +} + /// @brief Reference to a single element in a packed_bit vector. /// @tparam Iterator Underlying byte iterator type, optionally const. template diff --git a/src/bsoncxx/lib/CMakeLists.txt b/src/bsoncxx/lib/CMakeLists.txt index 8bb70e33f8..69383facb0 100644 --- a/src/bsoncxx/lib/CMakeLists.txt +++ b/src/bsoncxx/lib/CMakeLists.txt @@ -101,7 +101,6 @@ set_dist_list(src_bsoncxx_lib_DIST ${bsoncxx_sources_v1} bsoncxx/private/b64_ntop.hh bsoncxx/private/config/config.hh.in - bsoncxx/private/convert.hh bsoncxx/private/export.hh bsoncxx/private/helpers.hh bsoncxx/private/immortal.hh @@ -112,11 +111,11 @@ set_dist_list(src_bsoncxx_lib_DIST bsoncxx/private/suppress_deprecation_warnings.hh bsoncxx/private/type_traits.hh bsoncxx/private/version.hh - bsoncxx/v_noabi/bsoncxx/types/bson_value/value.hh bsoncxx/v1/config/config.hpp.in bsoncxx/v1/config/version.hpp.in bsoncxx/v1/document/view.hh bsoncxx/v1/element/view.hh + bsoncxx/v1/oid.hh bsoncxx/v1/types/value.hh bsoncxx/v1/types/view.hh ) diff --git a/src/bsoncxx/lib/bsoncxx/private/convert.hh b/src/bsoncxx/lib/bsoncxx/private/convert.hh deleted file mode 100644 index 543fc30b69..0000000000 --- a/src/bsoncxx/lib/bsoncxx/private/convert.hh +++ /dev/null @@ -1,329 +0,0 @@ -// 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 - -namespace bsoncxx { -namespace v_noabi { -namespace types { - -inline char* make_copy_for_libbson(stdx::string_view s, uint32_t* len_out = nullptr) { - // Append a nul byte to the end of the string - auto copy = static_cast(bson_malloc0(s.length() + 1)); - std::memcpy(copy, s.data(), s.length()); - copy[s.length()] = '\0'; - - if (len_out) { - *len_out = static_cast(s.length()); - } - - return copy; -} - -inline void convert_to_libbson(b_binary const& binary, bson_value_t* v) { - v->value_type = BSON_TYPE_BINARY; - - v->value.v_binary.subtype = static_cast(binary.sub_type); - v->value.v_binary.data_len = binary.size; - v->value.v_binary.data = static_cast(bson_malloc0(binary.size)); - std::memcpy(v->value.v_binary.data, binary.bytes, binary.size); -} - -inline void convert_to_libbson(b_string const& str, bson_value_t* v) { - v->value_type = BSON_TYPE_UTF8; - v->value.v_utf8.str = make_copy_for_libbson(str.value, &(v->value.v_utf8.len)); -} - -inline void convert_to_libbson(b_double const& val, bson_value_t* v) { - v->value_type = BSON_TYPE_DOUBLE; - v->value.v_double = val.value; -} - -inline void convert_to_libbson(b_int32 const& val, bson_value_t* v) { - v->value_type = BSON_TYPE_INT32; - v->value.v_int32 = val.value; -} - -inline void convert_to_libbson(b_int64 const& val, bson_value_t* v) { - v->value_type = BSON_TYPE_INT64; - v->value.v_int64 = val.value; -} - -inline void convert_to_libbson(b_undefined const&, bson_value_t* v) { - v->value_type = BSON_TYPE_UNDEFINED; -} - -inline void convert_to_libbson(b_oid const& val, bson_value_t* v) { - v->value_type = BSON_TYPE_OID; - std::memcpy(&v->value.v_oid.bytes, val.value.bytes(), val.value.k_oid_length); -} - -inline void convert_to_libbson(b_decimal128 const& decimal, bson_value_t* v) { - v->value_type = BSON_TYPE_DECIMAL128; - - v->value.v_decimal128.high = decimal.value.high(); - v->value.v_decimal128.low = decimal.value.low(); -} - -inline void convert_to_libbson(b_bool const& val, bson_value_t* v) { - v->value_type = BSON_TYPE_BOOL; - v->value.v_bool = val.value; -} - -inline void convert_to_libbson(b_date const& date, bson_value_t* v) { - v->value_type = BSON_TYPE_DATE_TIME; - v->value.v_datetime = date.value.count(); -} - -inline void convert_to_libbson(b_null const&, bson_value_t* v) { - v->value_type = BSON_TYPE_NULL; -} - -inline void convert_to_libbson(b_regex const& regex, bson_value_t* v) { - v->value_type = BSON_TYPE_REGEX; - v->value.v_regex.options = make_copy_for_libbson(regex.options); - v->value.v_regex.regex = make_copy_for_libbson(regex.regex); -} - -inline void convert_to_libbson(b_dbpointer const& db, bson_value_t* v) { - v->value_type = BSON_TYPE_DBPOINTER; - - v->value.v_dbpointer.collection = make_copy_for_libbson(db.collection, &(v->value.v_dbpointer.collection_len)); - - std::memcpy((v->value.v_dbpointer.oid.bytes), db.value.bytes(), db.value.k_oid_length); -} - -inline void convert_to_libbson(b_code const& code, bson_value_t* v) { - v->value_type = BSON_TYPE_CODE; - v->value.v_code.code = make_copy_for_libbson(code.code, &(v->value.v_code.code_len)); -} - -inline void convert_to_libbson(b_symbol const& symbol, bson_value_t* v) { - v->value_type = BSON_TYPE_SYMBOL; - v->value.v_symbol.symbol = make_copy_for_libbson(symbol.symbol, &(v->value.v_symbol.len)); -} - -inline void convert_to_libbson(b_codewscope const& code, bson_value_t* v) { - v->value_type = BSON_TYPE_CODEWSCOPE; - - // Copy the code - v->value.v_codewscope.code = make_copy_for_libbson(code.code, &(v->value.v_codewscope.code_len)); - - // Copy the scope - if (code.scope.length() == 0) { - v->value.v_codewscope.scope_data = nullptr; - v->value.v_codewscope.scope_len = 0; - } else { - v->value.v_codewscope.scope_data = static_cast(bson_malloc0(code.scope.length())); - v->value.v_codewscope.scope_len = static_cast(code.scope.length()); - std::memcpy(v->value.v_codewscope.scope_data, code.scope.data(), code.scope.length()); - } -} - -inline void convert_to_libbson(b_timestamp const& t, bson_value_t* v) { - v->value_type = BSON_TYPE_TIMESTAMP; - v->value.v_timestamp.timestamp = t.timestamp; - v->value.v_timestamp.increment = t.increment; -} - -inline void convert_to_libbson(b_minkey const&, bson_value_t* v) { - v->value_type = BSON_TYPE_MINKEY; -} - -inline void convert_to_libbson(b_maxkey const&, bson_value_t* v) { - v->value_type = BSON_TYPE_MAXKEY; -} - -inline void convert_to_libbson(b_document const& doc, bson_value_t* v) { - v->value_type = BSON_TYPE_DOCUMENT; - - v->value.v_doc.data_len = static_cast(doc.value.length()); - if (0 == (v->value.v_doc.data_len)) { - v->value.v_doc.data = nullptr; - } else { - v->value.v_doc.data = static_cast(bson_malloc0(v->value.v_doc.data_len)); - std::memcpy(v->value.v_doc.data, doc.value.data(), v->value.v_doc.data_len); - } -} - -inline void convert_to_libbson(b_array const& arr, bson_value_t* v) { - v->value_type = BSON_TYPE_ARRAY; - // The bson_value_t struct does not have a separate union - // member for arrays. They are handled the same as the document - // BSON type. - v->value.v_doc.data_len = static_cast(arr.value.length()); - if (v->value.v_doc.data_len == 0) { - v->value.v_doc.data = nullptr; - } else { - v->value.v_doc.data = static_cast(bson_malloc0(arr.value.length())); - std::memcpy(v->value.v_doc.data, arr.value.data(), arr.value.length()); - } -} - -// -// Helper to convert without caller being aware of the underlying bson type. -// -inline void convert_to_libbson(bson_value_t* v, bson_value::view const& bson_view) { - switch (bson_view.type()) { -#define BSONCXX_ENUM(name, val) \ - case bsoncxx::v_noabi::type::k_##name: { \ - auto value = bson_view.get_##name(); \ - convert_to_libbson(value, v); \ - break; \ - } -#include -#undef BSONCXX_ENUM - default: - BSONCXX_PRIVATE_UNREACHABLE; - } -} - -inline void convert_from_libbson(bson_value_t const* v, b_binary* out) { - bson_subtype_t subtype = v->value.v_binary.subtype; - std::uint32_t len = v->value.v_binary.data_len; - std::uint8_t const* binary = v->value.v_binary.data; - - *out = {static_cast(subtype), len, binary}; -} - -inline void convert_from_libbson(bson_value_t const* v, b_string* out) { - uint32_t len = v->value.v_utf8.len; - char const* val = v->value.v_utf8.str; - - *out = b_string{stdx::string_view{val, len}}; -} - -inline void convert_from_libbson(bson_value_t const* v, b_double* out) { - *out = b_double{v->value.v_double}; -} - -inline void convert_from_libbson(bson_value_t const* v, b_int32* out) { - *out = b_int32{v->value.v_int32}; -} - -inline void convert_from_libbson(bson_value_t const* v, b_int64* out) { - *out = b_int64{v->value.v_int64}; -} - -inline void convert_from_libbson(bson_value_t const*, b_undefined* out) { - *out = b_undefined{}; -} - -inline void convert_from_libbson(bson_value_t const* v, b_oid* out) { - bson_oid_t const* boid = &(v->value.v_oid); - oid val_oid(reinterpret_cast(boid->bytes), sizeof(boid->bytes)); - *out = b_oid{std::move(val_oid)}; -} - -inline void convert_from_libbson(bson_value_t const* v, b_decimal128* out) { - bson_decimal128_t d128 = v->value.v_decimal128; - *out = b_decimal128{decimal128{d128.high, d128.low}}; -} - -inline void convert_from_libbson(bson_value_t const* v, b_bool* out) { - *out = b_bool{v->value.v_bool}; -} - -inline void convert_from_libbson(bson_value_t const* v, b_date* out) { - *out = b_date{std::chrono::milliseconds{v->value.v_datetime}}; -} - -inline void convert_from_libbson(bson_value_t const*, b_null* out) { - *out = b_null{}; -} - -inline void convert_from_libbson(bson_value_t const* v, b_regex* out) { - char const* options = v->value.v_regex.options; - char const* regex = v->value.v_regex.regex; - *out = b_regex{regex, options ? options : stdx::string_view{}}; -} - -inline void convert_from_libbson(bson_value_t const* v, b_dbpointer* out) { - uint32_t collection_len = v->value.v_dbpointer.collection_len; - char const* collection = v->value.v_dbpointer.collection; - bson_oid_t const* boid = &(v->value.v_dbpointer.oid); - - oid oid{reinterpret_cast(boid->bytes), sizeof(boid->bytes)}; - - *out = b_dbpointer{stdx::string_view{collection, collection_len}, std::move(oid)}; -} - -inline void convert_from_libbson(bson_value_t const* v, b_code* out) { - uint32_t len = v->value.v_code.code_len; - char const* code = v->value.v_code.code; - - *out = b_code{stdx::string_view{code, len}}; -} - -inline void convert_from_libbson(bson_value_t const* v, b_symbol* out) { - uint32_t len = v->value.v_symbol.len; - char const* symbol = v->value.v_symbol.symbol; - - *out = b_symbol{stdx::string_view{symbol, len}}; -} - -inline void convert_from_libbson(bson_value_t const* v, b_codewscope* out) { - uint32_t code_len = v->value.v_codewscope.code_len; - uint8_t const* scope_ptr = v->value.v_codewscope.scope_data; - uint32_t scope_len = v->value.v_codewscope.scope_len; - char const* code = v->value.v_codewscope.code; - document::view view(scope_ptr, scope_len); - - *out = b_codewscope{stdx::string_view{code, code_len}, view}; -} - -inline void convert_from_libbson(bson_value_t const* v, b_timestamp* out) { - uint32_t timestamp = v->value.v_timestamp.timestamp; - uint32_t increment = v->value.v_timestamp.increment; - *out = {increment, timestamp}; -} - -inline void convert_from_libbson(bson_value_t const*, b_minkey* out) { - *out = b_minkey{}; -} - -inline void convert_from_libbson(bson_value_t const*, b_maxkey* out) { - *out = b_maxkey{}; -} - -inline void convert_from_libbson(bson_value_t const* v, b_document* out) { - std::uint8_t const* buf = v->value.v_doc.data; - std::uint32_t len = v->value.v_doc.data_len; - - *out = b_document{document::view{buf, len}}; -} - -inline void convert_from_libbson(bson_value_t const* v, b_array* out) { - // The bson_value_t struct does not have a separate union - // member for arrays. They are handled the same as the document - // BSON type. - std::uint8_t const* buf = v->value.v_doc.data; - std::uint32_t len = v->value.v_doc.data_len; - - *out = b_array{array::view{buf, len}}; -} - -} // namespace types -} // namespace v_noabi -} // namespace bsoncxx diff --git a/src/bsoncxx/lib/bsoncxx/private/type_traits.hh b/src/bsoncxx/lib/bsoncxx/private/type_traits.hh index 4d993ccd21..4e70531926 100644 --- a/src/bsoncxx/lib/bsoncxx/private/type_traits.hh +++ b/src/bsoncxx/lib/bsoncxx/private/type_traits.hh @@ -75,4 +75,17 @@ struct is_semitrivial : detail::conjunction< std::is_trivially_copy_constructible, std::is_trivially_copy_assignable> {}; +// Equivalent to `is_constructible_v && !is_convertible_v`. +// Use `is_constructible` to avoid implying "is also not implicitly convertible". +template +struct is_explicitly_convertible : bsoncxx::detail::conjunction< + std::is_constructible, + bsoncxx::detail::negation>> {}; + +// Equivalent to `is_constructible_v && is_convertible_v`. +// Use `is_convertible` to avoid implying "is also explicitly convertible". +template +struct is_implicitly_convertible + : bsoncxx::detail::conjunction, std::is_convertible> {}; + } // namespace bsoncxx diff --git a/src/bsoncxx/lib/bsoncxx/v1/oid.cpp b/src/bsoncxx/lib/bsoncxx/v1/oid.cpp index cf72e185f4..c92c41e283 100644 --- a/src/bsoncxx/lib/bsoncxx/v1/oid.cpp +++ b/src/bsoncxx/lib/bsoncxx/v1/oid.cpp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include +#include // diff --git a/src/bsoncxx/lib/bsoncxx/v1/oid.hh b/src/bsoncxx/lib/bsoncxx/v1/oid.hh new file mode 100644 index 0000000000..3800374a59 --- /dev/null +++ b/src/bsoncxx/lib/bsoncxx/v1/oid.hh @@ -0,0 +1,39 @@ +// 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 + +namespace bsoncxx { +namespace v1 { + +class oid::internal { + public: + // Required by bsoncxx::v_noabi::oid::oid(). + static std::array& bytes(oid& o) { + return o._bytes; + } + + // Required by bsoncxx::v_noabi::oid::oid(). + static oid make_oid_for_overwrite() { + return {oid::for_overwrite_tag{}}; + } +}; + +} // namespace v1 +} // namespace bsoncxx diff --git a/src/bsoncxx/lib/bsoncxx/v1/types/value.cpp b/src/bsoncxx/lib/bsoncxx/v1/types/value.cpp index 9f0302b01f..12fe51fa62 100644 --- a/src/bsoncxx/lib/bsoncxx/v1/types/value.cpp +++ b/src/bsoncxx/lib/bsoncxx/v1/types/value.cpp @@ -477,6 +477,10 @@ value::internal::make(std::uint8_t const* raw, std::uint32_t length, std::uint32 return ret; } +bson_value_t& value::internal::get_bson_value(value& v) { + return impl::with(v)._value; +} + } // namespace types } // namespace v1 } // namespace bsoncxx diff --git a/src/bsoncxx/lib/bsoncxx/v1/types/value.hh b/src/bsoncxx/lib/bsoncxx/v1/types/value.hh index 982005dd24..507a179c62 100644 --- a/src/bsoncxx/lib/bsoncxx/v1/types/value.hh +++ b/src/bsoncxx/lib/bsoncxx/v1/types/value.hh @@ -16,6 +16,7 @@ // +#include #include #include @@ -30,6 +31,9 @@ class value::internal { public: static v1::stdx::optional make(std::uint8_t const* raw, std::uint32_t length, std::uint32_t offset, std::uint32_t keylen); + + // Required by mongocxx::detail::scoped_bson_value. + static BSONCXX_ABI_EXPORT_CDECL(bson_value_t&) get_bson_value(value& v); }; } // namespace types diff --git a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/array/element.cpp b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/array/element.cpp index f384b12e1f..4892716150 100644 --- a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/array/element.cpp +++ b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/array/element.cpp @@ -12,35 +12,27 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include - #include -#include - -namespace bsoncxx { -namespace v_noabi { -namespace array { -element::element() : document::element() {} +// -element::element(std::uint8_t const* raw, std::uint32_t length, std::uint32_t offset, std::uint32_t keylen) - : document::element(raw, length, offset, keylen) {} +#include -bool operator==(element const& elem, types::bson_value::view const& v) { - return elem.get_value() == v; -} +#include -bool operator==(types::bson_value::view const& v, element const& elem) { - return elem == v; -} +#include -bool operator!=(element const& elem, types::bson_value::view const& v) { - return !(elem == v); -} +namespace bsoncxx { +namespace v_noabi { +namespace array { -bool operator!=(types::bson_value::view const& v, element const& elem) { - return !(elem == v); -} +// MSVC: `std::is_constructible` does not work with using-declared conversion functions to class type...? +#if !defined(_MSC_VER) +static_assert(is_explicitly_convertible::value, "v_noabi -> v1 must be explicit"); +static_assert(is_explicitly_convertible::value, "v_noabi -> v1 must be explicit"); +static_assert(is_implicitly_convertible::value, "v1 -> v_noabi must be implicit"); +static_assert(is_implicitly_convertible::value, "v1 -> v_noabi must be implicit"); +#endif // !defined(_MSC_VER) } // namespace array } // namespace v_noabi diff --git a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/array/value.cpp b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/array/value.cpp index 20e1202e2a..96a23d8670 100644 --- a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/array/value.cpp +++ b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/array/value.cpp @@ -12,17 +12,24 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include + +// + #include -#include +#include namespace bsoncxx { namespace v_noabi { namespace array { -value::value(std::uint8_t* data, std::size_t length, deleter_type dtor) : _data(data, dtor), _length(length) {} +static_assert(is_explicitly_convertible::value, "v_noabi -> v1 must be explicit"); +static_assert(is_explicitly_convertible::value, "v_noabi -> v1 must be explicit"); -value::value(unique_ptr_type ptr, std::size_t length) : _data(std::move(ptr)), _length(length) {} +// Backward compatibility with lack of default destructor and `value({})` prevents the following conversions. +static_assert(!is_explicitly_convertible::value, "v1 -> v_noabi is not supported"); +static_assert(!is_explicitly_convertible::value, "v1 -> v_noabi is not supported"); namespace { @@ -32,23 +39,33 @@ void uint8_t_deleter(std::uint8_t* ptr) { } // namespace -value::value(array::view view) - : _data(new std::uint8_t[static_cast(view.length())], uint8_t_deleter), _length(view.length()) { - std::copy(view.data(), view.data() + view.length(), _data.get()); -} +value::value(v_noabi::array::view view) + : _value{[&]() -> unique_ptr_type { + auto res = unique_ptr_type{new std::uint8_t[view.size()], uint8_t_deleter}; + std::memcpy(res.get(), view.data(), view.size()); + return res; + }()}, + _length{view.size()} {} + +} // namespace array +} // namespace v_noabi +} // namespace bsoncxx + +namespace bsoncxx { +namespace v_noabi { -value::value(value const& rhs) : value(rhs.view()) {} +v_noabi::array::value from_v1(v1::array::value&& v) { + auto const deleter_ptr = v.get_deleter().target(); -value& value::operator=(value const& rhs) { - *this = value{rhs.view()}; - return *this; -} + if (!deleter_ptr || *deleter_ptr == &v1::document::value::noop_deleter) { + return from_v1(static_cast(v)); // Fallback to copy. + } -value::unique_ptr_type value::release() { - _length = 0; - return std::move(_data); + auto const length = v.length(); + auto const deleter = *deleter_ptr; + + return {v.release().release(), length, deleter}; } -} // namespace array } // namespace v_noabi } // namespace bsoncxx diff --git a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/array/view.cpp b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/array/view.cpp index ed462a8c7d..bc0e262e30 100644 --- a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/array/view.cpp +++ b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/array/view.cpp @@ -12,39 +12,39 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include -#include - #include + +// + +#include + +#include + #include #include #include #include +#include namespace bsoncxx { namespace v_noabi { namespace array { +static_assert(is_explicitly_convertible::value, "v_noabi -> v1 must be explicit"); +static_assert(is_explicitly_convertible::value, "v_noabi -> v1 must be explicit"); +static_assert(is_implicitly_convertible::value, "v1 -> v_noabi must be implicit"); +static_assert(is_implicitly_convertible::value, "v1 -> v_noabi must be implicit"); + namespace { -bson_iter_t to_bson_iter_t(element e) { + +bson_iter_t to_bson_iter_t(v_noabi::array::element e) { bson_iter_t iter{}; - bson_iter_init_from_data_at_offset(&iter, e.raw(), e.length(), e.offset(), e.keylen()); + (void)bson_iter_init_from_data_at_offset(&iter, e.raw(), e.length(), e.offset(), e.keylen()); return iter; } -} // namespace -view::const_iterator::const_iterator() {} - -view::const_iterator::const_iterator(element const& element) : _element(element) {} - -view::const_iterator::reference view::const_iterator::operator*() { - return _element; -} - -view::const_iterator::pointer view::const_iterator::operator->() { - return &_element; -} +} // namespace view::const_iterator& view::const_iterator::operator++() { if (!_element) { @@ -58,107 +58,50 @@ view::const_iterator& view::const_iterator::operator++() { bson_iter_t iter = to_bson_iter_t(_element); if (!bson_iter_next(&iter)) { - _element = element{}; + _element = {}; } else { - _element = element{raw, len, bson_iter_offset(&iter), bson_iter_key_len(&iter)}; + _element = v1::element::view::internal::make(raw, len, bson_iter_offset(&iter), bson_iter_key_len(&iter)); } return *this; } -view::const_iterator view::const_iterator::operator++(int) { - const_iterator before(*this); - operator++(); - return before; -} - -bool operator==(view::const_iterator const& lhs, view::const_iterator const& rhs) { - return std::forward_as_tuple(lhs._element.raw(), lhs._element.offset()) == - std::forward_as_tuple(rhs._element.raw(), rhs._element.offset()); -} - -bool operator!=(view::const_iterator const& lhs, view::const_iterator const& rhs) { - return !(lhs == rhs); -} - view::const_iterator view::cbegin() const { bson_iter_t iter; - if (!bson_iter_init_from_data(&iter, data(), length())) { - return cend(); + if (!bson_iter_init_from_data(&iter, this->data(), this->length())) { + return this->cend(); } if (!bson_iter_next(&iter)) { - return cend(); + return this->cend(); } - return const_iterator{ - element{data(), static_cast(length()), bson_iter_offset(&iter), bson_iter_key_len(&iter)}}; -} - -view::const_iterator view::cend() const { - return const_iterator{}; -} - -view::const_iterator view::begin() const { - return cbegin(); -} - -view::const_iterator view::end() const { - return cend(); + return const_iterator{v1::element::view::internal::make( + this->data(), static_cast(this->length()), bson_iter_offset(&iter), bson_iter_key_len(&iter))}; } view::const_iterator view::find(std::uint32_t i) const { - itoa key(i); + itoa key{i}; - bson_t b; - bson_iter_t iter; + bson_t bson; - if (!bson_init_static(&b, data(), length())) { - return const_iterator(); + if (!bson_init_static(&bson, this->data(), this->length())) { + return this->cend(); } - if (!bson_iter_init(&iter, &b)) { - return const_iterator(); - } + bson_iter_t iter; - if (!bson_iter_init_find(&iter, &b, key.c_str())) { - return const_iterator(); + if (!bson_iter_init(&iter, &bson)) { + return this->cend(); } - return const_iterator( - element(data(), static_cast(length()), bson_iter_offset(&iter), bson_iter_key_len(&iter))); -} - -element view::operator[](std::uint32_t i) const { - return *(this->find(i)); -} - -view::view(std::uint8_t const* data, std::size_t length) : _view(data, length) {} - -view::view() : _view() {} - -std::uint8_t const* view::data() const { - return _view.data(); -} -std::size_t view::length() const { - return _view.length(); -} - -bool view::empty() const { - return _view.empty(); -} - -view::operator document::view() const { - return _view; -} - -bool operator==(view lhs, view rhs) { - return (lhs.length() == rhs.length()) && (std::memcmp(lhs.data(), rhs.data(), lhs.length()) == 0); -} + if (!bson_iter_init_find(&iter, &bson, key.c_str())) { + return this->cend(); + } -bool operator!=(view lhs, view rhs) { - return !(lhs == rhs); + return const_iterator{v1::element::view::internal::make( + this->data(), static_cast(this->length()), bson_iter_offset(&iter), bson_iter_key_len(&iter))}; } } // namespace array 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 5f6734eae8..59b19e3176 100644 --- a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/builder/core.cpp +++ b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/builder/core.cpp @@ -660,14 +660,15 @@ core& core::concatenate(bsoncxx::v_noabi::document::view const& view) { } core& core::append(types::bson_value::view const& value) { - switch (static_cast(value.type())) { -#define BSONCXX_ENUM(type, val) \ - case val: \ - append(value.get_##type()); \ +#pragma push_macro("X") +#undef X +#define X(_name, _value) \ + case type::k_##_name: \ + append(value.get_##_name()); \ break; -#include -#undef BSONCXX_ENUM - } + + switch (value.type()) { BSONCXX_V1_TYPES_XMACRO(X) } +#pragma pop_macro("X") return *this; } diff --git a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/decimal128.cpp b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/decimal128.cpp index b9e4552d45..cf6f49cacc 100644 --- a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/decimal128.cpp +++ b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/decimal128.cpp @@ -13,40 +13,28 @@ // limitations under the License. #include + +// + +#include +#include + #include #include -#include -#include -#include +#include namespace bsoncxx { namespace v_noabi { -decimal128::decimal128(stdx::string_view str) { - bson_decimal128_t d128; - if (!bson_decimal128_from_string(string::to_string(str).c_str(), &d128)) { - throw bsoncxx::v_noabi::exception{error_code::k_invalid_decimal128}; - } - _high = d128.high; - _low = d128.low; -} - -std::string decimal128::to_string() const { - bson_decimal128_t d128; - d128.high = _high; - d128.low = _low; - char str[BSON_DECIMAL128_STRING]; - bson_decimal128_to_string(&d128, str); - return {str}; -} - -bool operator==(decimal128 const& lhs, decimal128 const& rhs) { - return lhs._high == rhs._high && lhs._low == rhs._low; -} +static_assert(is_explicitly_convertible::value, "v_noabi -> v1 must be explicit"); +static_assert(is_explicitly_convertible::value, "v_noabi -> v1 must be explicit"); +static_assert(is_implicitly_convertible::value, "v1 -> v_noabi must be implicit"); +static_assert(is_implicitly_convertible::value, "v1 -> v_noabi must be implicit"); -bool operator!=(decimal128 const& lhs, decimal128 const& rhs) { - return !(lhs == rhs); +decimal128::decimal128(v1::stdx::string_view str) try : _d128{str} { +} catch (v1::exception const&) { + throw v_noabi::exception{v_noabi::error_code::k_invalid_decimal128}; } } // namespace v_noabi diff --git a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/document/element.cpp b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/document/element.cpp index c1f1398e83..e69509d7d6 100644 --- a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/document/element.cpp +++ b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/document/element.cpp @@ -18,6 +18,9 @@ #include +#include +#include + #include #include @@ -28,120 +31,83 @@ #include #include -#include - -#define BSONCXX_CITER \ - bson_iter_t iter; \ - bson_iter_init_from_data_at_offset(&iter, _raw, _length, _offset, _keylen); \ - ((void)0) +#include namespace bsoncxx { namespace v_noabi { namespace document { -element::element() : element(nullptr, 0, 0, 0) {} - -element::element(std::uint8_t const* raw, std::uint32_t length, std::uint32_t offset, std::uint32_t keylen) - : _raw(raw), _length(length), _offset(offset), _keylen(keylen) {} - -std::uint8_t const* element::raw() const { - return _raw; -} - -std::uint32_t element::length() const { - return _length; -} -std::uint32_t element::offset() const { - return _offset; -} - -std::uint32_t element::keylen() const { - return _keylen; +static_assert(is_implicitly_convertible::value, "v1 -> v_noabi must be implicit"); +static_assert(is_implicitly_convertible::value, "v1 -> v_noabi must be implicit"); +static_assert(is_explicitly_convertible::value, "v_noabi -> v1 must be explicit"); +static_assert(is_explicitly_convertible::value, "v_noabi -> v1 must be explicit"); + +v_noabi::type element::type() const try { + return static_cast(_view.type_id()); +} catch (v1::exception const& ex) { + throw v_noabi::exception{ + v_noabi::error_code::k_unset_element, + std::string{"cannot return the type of uninitialized element: "} + ex.what()}; } -bsoncxx::v_noabi::type element::type() const { - if (_raw == nullptr) { - throw bsoncxx::v_noabi::exception{ - error_code::k_unset_element, "cannot return the type of uninitialized element"}; - } - - BSONCXX_CITER; - return static_cast(bson_iter_type(&iter)); +v1::stdx::string_view element::key() const try { return _view.key(); } catch (v1::exception const& ex) { + throw v_noabi::exception{ + v_noabi::error_code::k_unset_element, + std::string{"cannot return the key from an uninitialized element: "} + ex.what()}; } -stdx::string_view element::key() const { - if (_raw == nullptr) { - throw bsoncxx::v_noabi::exception{ - error_code::k_unset_element, "cannot return the key from an uninitialized element"}; +#pragma push_macro("X") +#undef X +#define X(_name, _value) \ + v_noabi::types::b_##_name element::get_##_name() const try { \ + return from_v1(_view.get_##_name()); \ + } catch (v1::exception const& ex) { \ + throw v_noabi::exception{ \ + error_code::k_need_element_type_k_##_name, \ + std::string{"cannot get " #_name " from an uninitialized element: "} + ex.what()}; \ } - BSONCXX_CITER; +BSONCXX_V1_TYPES_XMACRO(X) +#pragma pop_macro("X") - char const* key = bson_iter_key(&iter); +v_noabi::types::bson_value::view element::get_value() const { +#pragma push_macro("X") +#undef X +#define X(_name, _value) \ + case v_noabi::type::k_##_name: \ + return {_view.get_##_name()}; - return stdx::string_view{key}; -} + switch (this->type()) { + BSONCXX_V1_TYPES_XMACRO(X) -#define BSONCXX_ENUM(name, val) \ - types::b_##name element::get_##name() const { \ - if (_raw == nullptr) { \ - throw bsoncxx::v_noabi::exception{ \ - error_code::k_unset_element, "cannot get " #name " from an uninitialized element"}; \ - } \ - types::bson_value::view v{_raw, _length, _offset, _keylen}; \ - return v.get_##name(); \ + default: + BSONCXX_PRIVATE_UNREACHABLE; } -#include -#undef BSONCXX_ENUM - -types::bson_value::view element::get_value() const { - switch (static_cast(type())) { -#define BSONCXX_ENUM(type, val) \ - case val: \ - return types::bson_value::view{get_##type()}; -#include -#undef BSONCXX_ENUM - } - - BSONCXX_PRIVATE_UNREACHABLE; -} - -types::bson_value::value element::get_owning_value() const { - return types::bson_value::value{_raw, _length, _offset, _keylen}; -} - -element element::operator[](stdx::string_view key) const { - if (_raw == nullptr || type() != bsoncxx::v_noabi::type::k_document) - return element(); - document::view doc = get_document(); - return doc[key]; +#pragma pop_macro("X") } -array::element element::operator[](std::uint32_t i) const { - if (_raw == nullptr || type() != bsoncxx::v_noabi::type::k_array) - return array::element(); - array::view arr = get_array(); - return arr[i]; -} - -element::operator bool() const { - return _raw != nullptr; -} - -bool operator==(element const& elem, types::bson_value::view const& v) { - return elem.get_value() == v; +v_noabi::types::bson_value::value element::get_owning_value() const { + auto value_opt = v1::types::value::internal::make(this->raw(), this->length(), this->offset(), this->keylen()); + if (!value_opt) { + return {}; + } + return {std::move(*value_opt)}; } -bool operator==(types::bson_value::view const& v, element const& elem) { - return elem == v; +element element::operator[](stdx::string_view key) const try { return _view[key]; } catch (v1::exception const&) { + // For backward compatibility, convert any exceptions into an invalid element. + return {}; } -bool operator!=(element const& elem, types::bson_value::view const& v) { - return !(elem == v); +v_noabi::array::element element::operator[](std::uint32_t i) const try { + return _view[i]; +} catch (v1::exception const&) { + // For backward compatibility, convert any exceptions into an invalid element. + return {}; } -bool operator!=(types::bson_value::view const& v, element const& elem) { - return !(elem == v); +bool operator==(element const& lhs, types::bson_value::view const& rhs) { + return lhs.get_value() == rhs; } } // namespace document diff --git a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/document/value.cpp b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/document/value.cpp index 0a48995727..a9135c5143 100644 --- a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/document/value.cpp +++ b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/document/value.cpp @@ -12,17 +12,33 @@ // 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 document { -value::value(std::uint8_t* data, std::size_t length, deleter_type dtor) : _data(data, dtor), _length(length) {} +static_assert(is_explicitly_convertible::value, "v_noabi -> v1 must be explicit"); +static_assert(is_explicitly_convertible::value, "v_noabi -> v1 must be explicit"); + +// Unconstrained template parameters for value(T const& t)` and `operator=(T const& t)` result in the following lies. +static_assert(is_explicitly_convertible::value, "v1 -> v_noabi: this is a lie!"); +static_assert(is_explicitly_convertible::value, "v1 -> v_noabi: this is a lie!"); -value::value(unique_ptr_type ptr, std::size_t length) : _data(std::move(ptr)), _length(length) {} +// Backward compatibility with unconstrained `operator=(T const&)` permits the following. +static_assert(std::is_assignable::value, "v1 -> v_noabi: assignment is supported"); +static_assert(std::is_assignable::value, "v1 -> v_noabi: assignment is supported"); + +// Backward compatibility with lack of default destructor and `value({})` prevent implicit conversions. +static_assert(!is_implicitly_convertible::value, "v1 -> v_noabi is not supported"); +static_assert(!is_implicitly_convertible::value, "v1 -> v_noabi is not supported"); namespace { @@ -32,66 +48,33 @@ void uint8_t_deleter(std::uint8_t* ptr) { } // namespace -value::value(document::view view) - : _data(new std::uint8_t[static_cast(view.length())], uint8_t_deleter), _length(view.length()) { - std::copy(view.data(), view.data() + view.length(), _data.get()); -} - -value::value(value const& rhs) : value(rhs.view()) {} - -value& value::operator=(value const& rhs) { - *this = value{rhs.view()}; - return *this; -} - -document::view::const_iterator value::cbegin() const { - return this->view().cbegin(); -} - -document::view::const_iterator value::cend() const { - return this->view().cend(); -} - -document::view::const_iterator value::begin() const { - return cbegin(); -} - -document::view::const_iterator value::end() const { - return cend(); -} - -document::view::const_iterator value::find(stdx::string_view key) const { - return this->view().find(key); -} +value::value(v_noabi::document::view view) + : _value{[&]() -> unique_ptr_type { + auto res = unique_ptr_type{new std::uint8_t[view.size()], uint8_t_deleter}; + std::memcpy(res.get(), view.data(), view.size()); + return res; + }()}, + _length{view.size()} {} -element value::operator[](stdx::string_view key) const { - auto view = this->view(); - return view[key]; -} +} // namespace document +} // namespace v_noabi +} // namespace bsoncxx -std::uint8_t const* value::data() const { - return _data.get(); -} +namespace bsoncxx { +namespace v_noabi { -std::size_t value::length() const { - return _length; -} +v_noabi::document::value from_v1(v1::document::value&& v) { + auto const deleter_ptr = v.get_deleter().target(); -bool value::empty() const { - return _length == 5; -} + if (!deleter_ptr || *deleter_ptr == &v1::document::value::noop_deleter) { + return from_v1(static_cast(v)); // Fallback to copy. + } -value::unique_ptr_type value::release() { - _length = 0; - return std::move(_data); -} + auto const length = v.length(); + auto const deleter = *deleter_ptr; -void value::reset(document::view view) { - _data.reset(new std::uint8_t[static_cast(view.length())]); - _length = view.length(); - std::copy(view.data(), view.data() + view.length(), _data.get()); + return {v.release().release(), length, deleter}; } -} // namespace document } // namespace v_noabi } // namespace bsoncxx diff --git a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/document/view.cpp b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/document/view.cpp index 38c5a057f9..2303beecb9 100644 --- a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/document/view.cpp +++ b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/document/view.cpp @@ -12,161 +12,91 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include - #include -#include -#include + +// + +#include +#include + +#include + +#include #include +#include namespace bsoncxx { namespace v_noabi { namespace document { +static_assert(is_explicitly_convertible::value, "v_noabi -> v1 must be explicit"); +static_assert(is_explicitly_convertible::value, "v_noabi -> v1 must be explicit"); +static_assert(is_implicitly_convertible::value, "v1 -> v_noabi must be implicit"); +static_assert(is_implicitly_convertible::value, "v1 -> v_noabi must be implicit"); + namespace { -bson_iter_t to_bson_iter_t(element e) { +bson_iter_t to_bson_iter_t(v_noabi::document::element e) { bson_iter_t iter{}; - bson_iter_init_from_data_at_offset(&iter, e.raw(), e.length(), e.offset(), e.keylen()); + (void)bson_iter_init_from_data_at_offset(&iter, e.raw(), e.length(), e.offset(), e.keylen()); return iter; } } // namespace -view::const_iterator::const_iterator() {} - -view::const_iterator::const_iterator(element const& element) : _element(element) {} - -view::const_iterator::reference view::const_iterator::operator*() { - return _element; -} - -view::const_iterator::pointer view::const_iterator::operator->() { - return &_element; -} - view::const_iterator& view::const_iterator::operator++() { if (!_element) { return *this; } - // the bson_t pointer and length remain unchanged while iterating. - auto raw = _element.raw(); - auto len = _element.length(); - - bson_iter_t iter = to_bson_iter_t(_element); + auto iter = to_bson_iter_t(_element); if (!bson_iter_next(&iter)) { - _element = element{}; + _element = {}; } else { - _element = element{raw, len, bson_iter_offset(&iter), bson_iter_key_len(&iter)}; + _element = v1::element::view::internal::make( + _element.raw(), _element.length(), bson_iter_offset(&iter), bson_iter_key_len(&iter)); } return *this; } -view::const_iterator view::const_iterator::operator++(int) { - const_iterator before(*this); - operator++(); - return before; -} - -bool operator==(view::const_iterator const& lhs, view::const_iterator const& rhs) { - return std::forward_as_tuple(lhs._element.raw(), lhs._element.offset()) == - std::forward_as_tuple(rhs._element.raw(), rhs._element.offset()); -} - -bool operator!=(view::const_iterator const& lhs, view::const_iterator const& rhs) { - return !(lhs == rhs); -} - view::const_iterator view::cbegin() const { bson_iter_t iter; - if (!bson_iter_init_from_data(&iter, data(), length())) { - return cend(); + if (!bson_iter_init_from_data(&iter, _view.data(), _length)) { + return this->cend(); } if (!bson_iter_next(&iter)) { - return cend(); + return this->cend(); } - return const_iterator{ - element{data(), static_cast(length()), bson_iter_offset(&iter), bson_iter_key_len(&iter)}}; + return const_iterator{v1::element::view::internal::make( + _view.data(), static_cast(_length), bson_iter_offset(&iter), bson_iter_key_len(&iter))}; } -view::const_iterator view::cend() const { - return const_iterator{}; -} - -view::const_iterator view::begin() const { - return cbegin(); -} +view::const_iterator view::find(v1::stdx::string_view key) const { + bson_t bson; -view::const_iterator view::end() const { - return cend(); -} - -view::const_iterator view::find(stdx::string_view key) const { - bson_t b; - if (!bson_init_static(&b, _data, _length)) { - return const_iterator(); + if (!bson_init_static(&bson, _view.data(), _length)) { + return this->cend(); } - bson_iter_t iter; - - // Logically, a default constructed string_view represents the - // empty string just as does string_view(""), but they have, - // potentially, different represntations, the former having .data - // returning nullptr though the latter probably does not. But the - // C functions like strncmp below can't be called with nullptr. If - // we were called with a string_data such that its .data() member - // returns nullptr, then, barring undefined behavior, its length - // is known to be zero, and it is equivalent to the empty string, - // an instance of which we reset it to. if (key.data() == nullptr) { - key = ""; + key = ""; // Null-terminated. } - if (!bson_iter_init_find_w_len(&iter, &b, key.data(), static_cast(key.size()))) { - // returning `cend()` returns an element without a key or value. - return const_iterator(); + bson_iter_t iter; + + if (!bson_iter_init_find_w_len(&iter, &bson, key.data(), static_cast(key.size()))) { + return this->cend(); } return const_iterator( - element(_data, static_cast(_length), bson_iter_offset(&iter), bson_iter_key_len(&iter))); -} - -element view::operator[](stdx::string_view key) const { - return *(this->find(key)); -} - -view::view(std::uint8_t const* data, std::size_t length) : _data(data), _length(length) {} - -namespace { -uint8_t const k_default_view[5] = {5, 0, 0, 0, 0}; -} // namespace - -view::view() : _data(k_default_view), _length(sizeof(k_default_view)) {} - -std::uint8_t const* view::data() const { - return _data; -} -std::size_t view::length() const { - return _length; -} - -bool view::empty() const { - return _length == 5; -} - -bool operator==(view lhs, view rhs) { - return (lhs.length() == rhs.length()) && (std::memcmp(lhs.data(), rhs.data(), lhs.length()) == 0); -} - -bool operator!=(view lhs, view rhs) { - return !(lhs == rhs); + v1::element::view::internal::make( + _view.data(), static_cast(_length), bson_iter_offset(&iter), bson_iter_key_len(&iter))); } } // namespace document 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 6d5c7f1596..d3986eed5d 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 @@ -12,9 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include + +// + +#include + #include -#include +#include namespace bsoncxx { namespace v_noabi { @@ -39,11 +45,15 @@ class error_category_impl final : public std::error_category { return "tried to operate on document, but this is an array"; case error_code::k_cannot_perform_document_operation_on_array: return "tried to operate on array, but this is a document"; -#define BSONCXX_ENUM(name, value) \ - case error_code::k_need_element_type_k_##name: \ - return {"expected element type k_" #name}; -#include -#undef BSONCXX_ENUM + +#pragma push_macro("X") +#undef X +#define X(_name, _value) \ + case error_code::k_need_element_type_k_##_name: \ + return {"expected element type k_" #_name}; + BSONCXX_V1_TYPES_XMACRO(X) +#pragma pop_macro("X") + case error_code::k_need_key: return "expected a key but found none"; case error_code::k_no_array_to_close: @@ -76,11 +86,15 @@ class error_category_impl final : public std::error_category { return "invalid BSON binary subtype"; case error_code::k_invalid_bson_type_id: return "invalid BSON type identifier"; -#define BSONCXX_ENUM(name, value) \ - case error_code::k_cannot_append_##name: \ - return {"unable to append " #name}; -#include -#undef BSONCXX_ENUM + +#pragma push_macro("X") +#undef X +#define X(_name, _value) \ + case error_code::k_cannot_append_##_name: \ + return {"unable to append " #_name}; + BSONCXX_V1_TYPES_XMACRO(X) +#pragma pop_macro("X") + case error_code::k_invalid_vector: return "invalid BSON vector"; case error_code::k_vector_too_large: @@ -96,8 +110,8 @@ class error_category_impl final : public std::error_category { } // namespace std::error_category const& error_category() { - static error_category_impl const instance{}; - return instance; + static bsoncxx::immortal const instance; + return instance.value(); } } // namespace v_noabi diff --git a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/oid.cpp b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/oid.cpp index d48a8b9541..de56573044 100644 --- a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/oid.cpp +++ b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/oid.cpp @@ -12,93 +12,57 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include + +// + +#include + +#include + #include #include #include -#include #include +#include namespace bsoncxx { namespace v_noabi { -oid::oid() { - bson_oid_t oid; - bson_oid_init(&oid, nullptr); +static_assert(is_explicitly_convertible::value, "v_noabi -> v1 must be explicit"); +static_assert(is_explicitly_convertible::value, "v_noabi -> v1 must be explicit"); +static_assert(is_implicitly_convertible::value, "v1 -> v_noabi must be implicit"); +static_assert(is_implicitly_convertible::value, "v1 -> v_noabi must be implicit"); - std::memcpy(_bytes.data(), oid.bytes, sizeof(oid.bytes)); -} +constexpr std::size_t oid::k_oid_length; -oid::oid(stdx::string_view const& str) { - if (!bson_oid_is_valid(str.data(), str.size())) { - throw bsoncxx::v_noabi::exception{error_code::k_invalid_oid}; - } - bson_oid_t oid; - bson_oid_init_from_string(&oid, str.data()); - memcpy(_bytes.data(), oid.bytes, _bytes.size()); -} +oid::oid() : _oid{v1::oid::internal::make_oid_for_overwrite()} { + try { + _oid = v1::oid{}; + } catch (...) { + // For backward compatibility, ignore any exceptions and initialize anyways. + bson_oid_t oid; + bson_oid_init(&oid, nullptr); -oid::oid(char const* bytes, std::size_t len) { - if (len != this->size()) { - throw bsoncxx::v_noabi::exception{error_code::k_invalid_oid}; + auto& _bytes = v1::oid::internal::bytes(_oid); + std::memcpy(_bytes.data(), oid.bytes, sizeof(oid.bytes)); } - std::memcpy(_bytes.data(), bytes, _bytes.size()); } -std::string oid::to_string() const { - bson_oid_t oid; - std::memcpy(oid.bytes, _bytes.data(), sizeof(oid.bytes)); - char str[25]; - - bson_oid_to_string(&oid, str); - - return std::string(str); -} - -std::time_t oid::get_time_t() const { - bson_oid_t oid; - std::memcpy(oid.bytes, _bytes.data(), sizeof(oid.bytes)); - - return bson_oid_get_time_t(&oid); +oid::oid(stdx::string_view const& str) try : _oid{str} { +} catch (v1::exception const&) { + throw v_noabi::exception{v_noabi::error_code::k_invalid_oid}; } -char const* oid::bytes() const { - return _bytes.data(); +oid::oid(char const* bytes, std::size_t len) try : _oid{reinterpret_cast(bytes), len} { +} catch (v1::exception const&) { + throw v_noabi::exception{v_noabi::error_code::k_invalid_oid}; } int oid_compare(oid const& lhs, oid const& rhs) { - bson_oid_t lhs_oid; - bson_oid_t rhs_oid; - - std::memcpy(lhs_oid.bytes, lhs.bytes(), sizeof(lhs_oid.bytes)); - std::memcpy(rhs_oid.bytes, rhs.bytes(), sizeof(rhs_oid.bytes)); - - return bson_oid_compare(&lhs_oid, &rhs_oid); -} - -bool operator<(oid const& lhs, oid const& rhs) { - return oid_compare(lhs, rhs) < 0; -} - -bool operator>(oid const& lhs, oid const& rhs) { - return oid_compare(lhs, rhs) > 0; -} - -bool operator<=(oid const& lhs, oid const& rhs) { - return oid_compare(lhs, rhs) <= 0; -} - -bool operator>=(oid const& lhs, oid const& rhs) { - return oid_compare(lhs, rhs) >= 0; -} - -bool operator==(oid const& lhs, oid const& rhs) { - return oid_compare(lhs, rhs) == 0; -} - -bool operator!=(oid const& lhs, oid const& rhs) { - return oid_compare(lhs, rhs) != 0; + return lhs._oid.compare(rhs._oid); } } // namespace v_noabi diff --git a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/types.cpp b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/types.cpp index 9b06353a48..f22097cfcf 100644 --- a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/types.cpp +++ b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/types.cpp @@ -14,38 +14,20 @@ #include -namespace bsoncxx { -namespace v_noabi { +// -#define BSONCXX_ENUM(name, val) constexpr type types::b_##name::type_id; -#include -#undef BSONCXX_ENUM +#include -std::string to_string(type rhs) { - switch (static_cast(rhs)) { -#define BSONCXX_ENUM(name, val) \ - case val: \ - return (#name); \ - break; -#include -#undef BSONCXX_ENUM - default: - return "?"; - } -} +namespace bsoncxx { +namespace v_noabi { +namespace types { -std::string to_string(binary_sub_type rhs) { - switch (static_cast(rhs)) { -#define BSONCXX_ENUM(name, val) \ - case val: \ - return (#name); \ - break; -#include -#undef BSONCXX_ENUM - default: - return "?"; - } -} +#pragma push_macro("X") +#undef X +#define X(_name, _value) constexpr v_noabi::type b_##_name::type_id; +BSONCXX_V1_TYPES_XMACRO(X) +#pragma pop_macro("X") +} // namespace types } // namespace v_noabi } // namespace bsoncxx diff --git a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/types/bson_value/value.cpp b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/types/bson_value/value.cpp index 2f4b67a4c8..3328e3820c 100644 --- a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/types/bson_value/value.cpp +++ b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/types/bson_value/value.cpp @@ -12,281 +12,128 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include +#include // #include #include -#include -#include +#include namespace bsoncxx { namespace v_noabi { namespace types { namespace bson_value { -value::value(b_double v) : value(v.value) {} -value::value(double v) : _impl{make_unique()} { - _impl->_value.value_type = BSON_TYPE_DOUBLE; - _impl->_value.value.v_double = v; -} - -value::value(b_int32 v) : value(v.value) {} -value::value(int32_t v) : _impl{make_unique()} { - _impl->_value.value_type = BSON_TYPE_INT32; - _impl->_value.value.v_int32 = v; -} - -value::value(b_int64 v) : value(v.value) {} -value::value(int64_t v) : _impl{make_unique()} { - _impl->_value.value_type = BSON_TYPE_INT64; - _impl->_value.value.v_int64 = v; -} - -value::value(char const* v) : value(stdx::string_view{v}) {} -value::value(std::string v) : value(stdx::string_view{v}) {} -value::value(b_string v) : value(v.value) {} -value::value(stdx::string_view v) : _impl{make_unique()} { - _impl->_value.value_type = BSON_TYPE_UTF8; - _impl->_value.value.v_utf8.str = make_copy_for_libbson(v); - _impl->_value.value.v_utf8.len = static_cast(v.size()); -} - -value::value(b_null) : value(nullptr) {} -value::value(std::nullptr_t) : _impl{make_unique()} { - _impl->_value.value_type = BSON_TYPE_NULL; -} - -value::value(b_date v) : value(v.value) {} -value::value(std::chrono::milliseconds v) : _impl{make_unique()} { - _impl->_value.value_type = BSON_TYPE_DATE_TIME; - _impl->_value.value.v_datetime = v.count(); -} - -value::value(b_oid v) : value(v.value) {} -value::value(oid v) : _impl{make_unique()} { - _impl->_value.value_type = BSON_TYPE_OID; - std::memcpy(_impl->_value.value.v_oid.bytes, v.bytes(), v.k_oid_length); -} - -value::value(b_bool v) : value(v.value) {} -value::value(bool v) : _impl{make_unique()} { - _impl->_value.value_type = BSON_TYPE_BOOL; - _impl->_value.value.v_bool = v; -} +static_assert(is_explicitly_convertible::value, "v_noabi -> v1 must be explicit"); +static_assert(is_explicitly_convertible::value, "v_noabi -> v1 must be explicit"); +static_assert(is_implicitly_convertible::value, "v1 -> v_noabi must be implicit"); +static_assert(is_implicitly_convertible::value, "v1 -> v_noabi must be implicit"); -value::value(b_maxkey) : value(type::k_maxkey) {} -value::value(b_minkey) : value(type::k_minkey) {} -value::value(b_undefined) : value(type::k_undefined) {} -value::value(type const id) : _impl{make_unique()} { +value::value(v_noabi::type const id, v1::stdx::string_view v) { switch (id) { - case type::k_minkey: - _impl->_value.value_type = BSON_TYPE_MINKEY; + case v_noabi::type::k_regex: + _value = v1::types::value{v1::types::b_regex{v}}; break; - case type::k_maxkey: - _impl->_value.value_type = BSON_TYPE_MAXKEY; + case v_noabi::type::k_code: + _value = v1::types::value{v1::types::b_code{v}}; break; - case type::k_undefined: - _impl->_value.value_type = BSON_TYPE_UNDEFINED; + case v_noabi::type::k_symbol: + _value = v1::types::value{v1::types::b_symbol{v}}; break; - case type::k_double: - case type::k_string: - case type::k_document: - case type::k_array: - case type::k_binary: - case type::k_oid: - case type::k_bool: - case type::k_date: - case type::k_null: - case type::k_regex: - case type::k_dbpointer: - case type::k_code: - case type::k_symbol: - case type::k_codewscope: - case type::k_int32: - case type::k_timestamp: - case type::k_int64: - case type::k_decimal128: + case v_noabi::type::k_double: + case v_noabi::type::k_string: + case v_noabi::type::k_document: + case v_noabi::type::k_array: + case v_noabi::type::k_binary: + case v_noabi::type::k_undefined: + case v_noabi::type::k_oid: + case v_noabi::type::k_bool: + case v_noabi::type::k_date: + case v_noabi::type::k_null: + case v_noabi::type::k_dbpointer: + case v_noabi::type::k_codewscope: + case v_noabi::type::k_int32: + case v_noabi::type::k_timestamp: + case v_noabi::type::k_int64: + case v_noabi::type::k_decimal128: + case v_noabi::type::k_maxkey: + case v_noabi::type::k_minkey: default: - throw bsoncxx::v_noabi::exception(error_code::k_invalid_bson_type_id); + throw v_noabi::exception(v_noabi::error_code::k_invalid_bson_type_id); } } -value::value(b_regex v) : value(v.regex, v.options) {} -value::value(stdx::string_view regex, stdx::string_view options) : _impl{make_unique()} { - _impl->_value.value_type = BSON_TYPE_REGEX; - _impl->_value.value.v_regex.regex = make_copy_for_libbson(regex); - _impl->_value.value.v_regex.options = options.empty() ? nullptr : make_copy_for_libbson(options); -} - -value::value(b_code v) : value(v.type_id, v) {} -value::value(b_symbol v) : value(v.type_id, v) {} -value::value(type const id, stdx::string_view v) : _impl{make_unique()} { +value::value(v_noabi::type const id) { switch (id) { - case type::k_regex: - _impl->_value.value_type = BSON_TYPE_REGEX; - _impl->_value.value.v_regex.regex = make_copy_for_libbson(v); - _impl->_value.value.v_regex.options = nullptr; + case v_noabi::type::k_minkey: + _value = v1::types::value{v1::types::b_minkey{}}; break; - case type::k_code: - _impl->_value.value_type = BSON_TYPE_CODE; - _impl->_value.value.v_code.code = make_copy_for_libbson(v); - _impl->_value.value.v_code.code_len = static_cast(v.length()); + case v_noabi::type::k_maxkey: + _value = v1::types::value{v1::types::b_maxkey{}}; break; - case type::k_symbol: - _impl->_value.value_type = BSON_TYPE_SYMBOL; - _impl->_value.value.v_symbol.symbol = make_copy_for_libbson(v); - _impl->_value.value.v_symbol.len = static_cast(v.length()); + case v_noabi::type::k_undefined: + _value = v1::types::value{v1::types::b_undefined{}}; break; - case type::k_double: - case type::k_string: - case type::k_document: - case type::k_array: - case type::k_binary: - case type::k_undefined: - case type::k_oid: - case type::k_bool: - case type::k_date: - case type::k_null: - case type::k_dbpointer: - case type::k_codewscope: - case type::k_int32: - case type::k_timestamp: - case type::k_int64: - case type::k_decimal128: - case type::k_maxkey: - case type::k_minkey: + case v_noabi::type::k_double: + case v_noabi::type::k_string: + case v_noabi::type::k_document: + case v_noabi::type::k_array: + case v_noabi::type::k_binary: + case v_noabi::type::k_oid: + case v_noabi::type::k_bool: + case v_noabi::type::k_date: + case v_noabi::type::k_null: + case v_noabi::type::k_regex: + case v_noabi::type::k_dbpointer: + case v_noabi::type::k_code: + case v_noabi::type::k_symbol: + case v_noabi::type::k_codewscope: + case v_noabi::type::k_int32: + case v_noabi::type::k_timestamp: + case v_noabi::type::k_int64: + case v_noabi::type::k_decimal128: default: - throw bsoncxx::v_noabi::exception(error_code::k_invalid_bson_type_id); + throw v_noabi::exception(v_noabi::error_code::k_invalid_bson_type_id); } } - -value::value(b_decimal128 v) : value(v.value) {} -value::value(decimal128 v) : value(type::k_decimal128, v.high(), v.low()) {} -value::value(b_timestamp v) : value(v.type_id, v.increment, v.timestamp) {} -value::value(type id, uint64_t a, uint64_t b) : _impl{make_unique()} { +value::value(v_noabi::type id, std::uint64_t a, std::uint64_t b) { switch (id) { - case type::k_decimal128: - _impl->_value.value_type = BSON_TYPE_DECIMAL128; - _impl->_value.value.v_decimal128.high = a; - _impl->_value.value.v_decimal128.low = b; + case v_noabi::type::k_decimal128: + _value = v1::types::value{v1::types::b_decimal128{{a, b}}}; break; - case type::k_timestamp: - _impl->_value.value_type = BSON_TYPE_TIMESTAMP; - _impl->_value.value.v_timestamp.increment = static_cast(a); - _impl->_value.value.v_timestamp.timestamp = static_cast(b); + case v_noabi::type::k_timestamp: + _value = + v1::types::value{v1::types::b_timestamp{static_cast(a), static_cast(b)}}; break; - case type::k_double: - case type::k_string: - case type::k_document: - case type::k_array: - case type::k_binary: - case type::k_undefined: - case type::k_oid: - case type::k_bool: - case type::k_date: - case type::k_null: - case type::k_regex: - case type::k_dbpointer: - case type::k_code: - case type::k_symbol: - case type::k_codewscope: - case type::k_int32: - case type::k_int64: - case type::k_maxkey: - case type::k_minkey: + case v_noabi::type::k_double: + case v_noabi::type::k_string: + case v_noabi::type::k_document: + case v_noabi::type::k_array: + case v_noabi::type::k_binary: + case v_noabi::type::k_undefined: + case v_noabi::type::k_oid: + case v_noabi::type::k_bool: + case v_noabi::type::k_date: + case v_noabi::type::k_null: + case v_noabi::type::k_regex: + case v_noabi::type::k_dbpointer: + case v_noabi::type::k_code: + case v_noabi::type::k_symbol: + case v_noabi::type::k_codewscope: + case v_noabi::type::k_int32: + case v_noabi::type::k_int64: + case v_noabi::type::k_maxkey: + case v_noabi::type::k_minkey: default: throw bsoncxx::v_noabi::exception(error_code::k_invalid_bson_type_id); } } -value::value(b_dbpointer v) : value(v.collection, v.value) {} -value::value(stdx::string_view collection, oid value) : _impl{make_unique()} { - _impl->_value.value_type = BSON_TYPE_DBPOINTER; - _impl->_value.value.v_dbpointer.collection = make_copy_for_libbson(collection); - _impl->_value.value.v_dbpointer.collection_len = static_cast(collection.length()); - std::memcpy(_impl->_value.value.v_dbpointer.oid.bytes, value.bytes(), value.k_oid_length); -} - -value::value(b_codewscope v) : value(v.code, v.scope) {} -value::value(stdx::string_view code, bsoncxx::v_noabi::document::view_or_value scope) : _impl{make_unique()} { - _impl->_value.value_type = BSON_TYPE_CODEWSCOPE; - _impl->_value.value.v_codewscope.code = make_copy_for_libbson(code); - _impl->_value.value.v_codewscope.code_len = static_cast(code.length()); - _impl->_value.value.v_codewscope.scope_len = static_cast(scope.view().length()); - _impl->_value.value.v_codewscope.scope_data = static_cast(bson_malloc(scope.view().length())); - std::memcpy(_impl->_value.value.v_codewscope.scope_data, scope.view().data(), scope.view().length()); -} - -value::value(b_binary v) : value(v.bytes, v.size, v.sub_type) {} -value::value(std::vector v, binary_sub_type sub_type) : value(v.data(), v.size(), sub_type) {} -value::value(uint8_t const* data, size_t size, binary_sub_type const sub_type) : _impl{make_unique()} { - _impl->_value.value_type = BSON_TYPE_BINARY; - _impl->_value.value.v_binary.subtype = static_cast(sub_type); - _impl->_value.value.v_binary.data_len = static_cast(size); - _impl->_value.value.v_binary.data = static_cast(bson_malloc(size)); - if (size) - std::memcpy(_impl->_value.value.v_binary.data, data, size); -} - -value::value(b_document v) : value(v.view()) {} -value::value(bsoncxx::v_noabi::document::view v) : _impl{make_unique()} { - _impl->_value.value_type = BSON_TYPE_DOCUMENT; - _impl->_value.value.v_doc.data_len = static_cast(v.length()); - _impl->_value.value.v_doc.data = static_cast(bson_malloc(v.length())); - std::memcpy(_impl->_value.value.v_doc.data, v.data(), v.length()); -} - -value::value(b_array v) : value(v.value) {} -value::value(bsoncxx::v_noabi::array::view v) : _impl{make_unique()} { - _impl->_value.value_type = BSON_TYPE_ARRAY; - _impl->_value.value.v_doc.data_len = static_cast(v.length()); - _impl->_value.value.v_doc.data = static_cast(bson_malloc(v.length())); - std::memcpy(_impl->_value.value.v_doc.data, v.data(), v.length()); -} - -value::~value() = default; - -value::value(value&&) noexcept = default; - -value& value::operator=(value&&) noexcept = default; - -value::value(std::uint8_t const* raw, std::uint32_t length, std::uint32_t offset, std::uint32_t keylen) { - bson_iter_t iter; - - bson_iter_init_from_data_at_offset(&iter, raw, length, offset, keylen); - auto value = bson_iter_value(&iter); - - _impl = make_unique(value); -} - -value::value(void* internal_value) : _impl(make_unique(static_cast(internal_value))) {} - -value::value(value const& rhs) : value(&rhs._impl->_value) {} - -value::value(bson_value::view const& bson_view) { - _impl = make_unique(); - convert_to_libbson(&_impl->_value, bson_view); -} - -value& value::operator=(value const& rhs) { - *this = value{rhs}; - return *this; -} - -bson_value::view value::view() const noexcept { - return _impl->view(); -} - -value::operator bson_value::view() const noexcept { - return view(); -} - } // namespace bson_value } // namespace types } // namespace v_noabi diff --git a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/types/bson_value/value.hh b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/types/bson_value/value.hh deleted file mode 100644 index b9af7b4fda..0000000000 --- a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/types/bson_value/value.hh +++ /dev/null @@ -1,68 +0,0 @@ -// 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 types { -namespace bson_value { - -class value::impl { - public: - impl(bson_value_t const* value) { - bson_value_copy(value, &_value); - } - - impl() { - // Initialize the value to null for safe destruction. - _value.value_type = BSON_TYPE_NULL; - _value.padding = 0; - } - - ~impl() { - bson_value_destroy(&_value); - } - - impl(impl&&) = delete; - impl operator=(impl&&) = delete; - impl(impl const&) = delete; - impl operator=(impl const&) = delete; - - bson_value::view view() const noexcept { - // ABI backward compatibility. Const is restored in `view::_init`. - return bson_value::view{const_cast(static_cast(&_value))}; - } - - bson_value_t _value; -}; - -// Helper to create a value from an existing bson_value_t -// (for mongocxx callers who cannot be added as friends) -inline bson_value::value make_owning_bson(void* internal_value) { - return bson_value::value{internal_value}; -} - -} // namespace bson_value -} // namespace types -} // namespace v_noabi -} // namespace bsoncxx diff --git a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/types/bson_value/view.cpp b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/types/bson_value/view.cpp index 55793ee25c..2bf979c3e4 100644 --- a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/types/bson_value/view.cpp +++ b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/types/bson_value/view.cpp @@ -12,162 +12,68 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include - -#include -#include #include -#include -#include -#include +// -#define BSONCXX_CITER \ - bson_iter_t iter; \ - bson_iter_init_from_data_at_offset(&iter, raw, length, offset, keylen); \ - ((void)0) +#include -#define BSONCXX_TYPE_CHECK(name) \ - do { \ - if (type() != bsoncxx::v_noabi::type::k_##name) { \ - throw bsoncxx::v_noabi::exception{error_code::k_need_element_type_k_##name}; \ - } \ - } while (0) +#include + +#include +#include + +#include namespace bsoncxx { namespace v_noabi { namespace types { namespace bson_value { -view::view() noexcept : view(nullptr) {} - -#define BSONCXX_ENUM(name, val) \ - view::view(b_##name v) noexcept : _type(static_cast(val)), _b_##name(std::move(v)) { \ - static_assert(std::is_nothrow_copy_constructible::value, "Copy may throw"); \ - static_assert(std::is_nothrow_copy_assignable::value, "Copy may throw"); \ - static_assert(std::is_nothrow_destructible::value, "Destruction may throw"); \ - } - -#include -#undef BSONCXX_ENUM - -view::view(view const& rhs) noexcept { - switch (static_cast(rhs._type)) { -#define BSONCXX_ENUM(type, val) \ - case val: \ - new (&_b_##type) b_##type(rhs.get_##type()); \ - break; -#include -#undef BSONCXX_ENUM +static_assert(is_explicitly_convertible::value, "v_noabi -> v1 must be explicit"); +static_assert(is_explicitly_convertible::value, "v_noabi -> v1 must be explicit"); +static_assert(is_implicitly_convertible::value, "v1 -> v_noabi must be implicit"); +static_assert(is_implicitly_convertible::value, "v1 -> v_noabi must be implicit"); + +#pragma push_macro("X") +#undef X +#define X(_name, _value) \ + v_noabi::types::b_##_name const& view::get_##_name() const { \ + if (_id != type::k_##_name) { \ + throw v_noabi::exception{v_noabi::error_code::k_need_element_type_k_##_name}; \ + } \ + return _b_##_name; \ } - _type = rhs._type; -} - -view& view::operator=(view const& rhs) noexcept { - if (this == &rhs) { - return *this; - } - - destroy(); - - switch (static_cast(rhs._type)) { -#define BSONCXX_ENUM(type, val) \ - case val: \ - new (&_b_##type) b_##type(rhs.get_##type()); \ - break; -#include -#undef BSONCXX_ENUM - default: - break; - } - - _type = rhs._type; - return *this; -} - -view::~view() { - destroy(); -} - -bsoncxx::v_noabi::type view::type() const { - return _type; -} - -#define BSONCXX_ENUM(type, val) \ - types::b_##type const& view::get_##type() const { \ - BSONCXX_TYPE_CHECK(type); \ - return _b_##type; \ - } -#include -#undef BSONCXX_ENUM - -view::view(std::uint8_t const* raw, std::uint32_t length, std::uint32_t offset, std::uint32_t keylen) { - BSONCXX_CITER; - - auto value = bson_iter_value(&iter); - - // ABI backward compatibility. Const is restored in `view::_init`. - _init(const_cast(static_cast(value))); -} - -view::view(void* internal_value) noexcept { - _init(internal_value); -} - -void view::_init(void* internal_value) noexcept { - if (!internal_value) { - _type = bsoncxx::v_noabi::type::k_null; - _b_null = bsoncxx::v_noabi::types::b_null{}; - return; - } - - auto v = static_cast(internal_value); - _type = static_cast(v->value_type); - - switch (_type) { -#define BSONCXX_ENUM(name, val) \ - case bsoncxx::v_noabi::type::k_##name: { \ - ::bsoncxx::v_noabi::types::convert_from_libbson(v, &_b_##name); \ - break; \ - } -#include -#undef BSONCXX_ENUM - default: - BSONCXX_PRIVATE_UNREACHABLE; - } -} +/// +/// Return the BSON type value of this element. +/// +/// @throws bsoncxx::v_noabi::exception if this element is not the requested type. +/// +/// @{ +BSONCXX_V1_TYPES_XMACRO(X) +/// @} +/// +#pragma pop_macro("X") bool operator==(view const& lhs, view const& rhs) { - if (lhs.type() != rhs.type()) { + if (lhs._id != rhs._id) { return false; } - switch (static_cast(lhs.type())) { -#define BSONCXX_ENUM(type, val) \ - case val: \ - return lhs.get_##type() == rhs.get_##type(); -#include -#undef BSONCXX_ENUM - } - - // Silence compiler warnings about failing to return a value. - BSONCXX_PRIVATE_UNREACHABLE; -} - -bool operator!=(view const& lhs, view const& rhs) { - return !(lhs == rhs); -} +#pragma push_macro("X") +#undef X +#define X(_name, _value) \ + case v_noabi::type::k_##_name: \ + return lhs._b_##_name == rhs._b_##_name; -void view::destroy() noexcept { - switch (static_cast(_type)) { -#define BSONCXX_ENUM(type, val) \ - case val: \ - _b_##type.~b_##type(); \ - break; -#include -#undef BSONCXX_ENUM + switch (lhs._id) { + BSONCXX_V1_TYPES_XMACRO(X) + default: + // Silence compiler warnings about failing to return a value. + BSONCXX_PRIVATE_UNREACHABLE; } +#pragma pop_macro("X") } } // namespace bson_value diff --git a/src/bsoncxx/test/CMakeLists.txt b/src/bsoncxx/test/CMakeLists.txt index 42e6e9f2d6..1b481296b9 100644 --- a/src/bsoncxx/test/CMakeLists.txt +++ b/src/bsoncxx/test/CMakeLists.txt @@ -41,6 +41,7 @@ set(bsoncxx_test_sources_v_noabi v_noabi/bson_util_itoa.cpp v_noabi/bson_validate.cpp v_noabi/bson_value.cpp + v_noabi/decimal128.cpp v_noabi/json.cpp v_noabi/oid.cpp v_noabi/vector.cpp diff --git a/src/bsoncxx/test/v1/array/view.hh b/src/bsoncxx/test/v1/array/view.hh index 2a6034faf2..6bfc60d6da 100644 --- a/src/bsoncxx/test/v1/array/view.hh +++ b/src/bsoncxx/test/v1/array/view.hh @@ -20,11 +20,13 @@ #include // StringMaker +#include + #include #include template <> struct Catch::StringMaker { - static std::string convert(bsoncxx::v1::array::view const& value); + static std::string BSONCXX_ABI_CDECL convert(bsoncxx::v1::array::view const& value); }; diff --git a/src/bsoncxx/test/v1/document/value.cpp b/src/bsoncxx/test/v1/document/value.cpp index 491b44c4aa..fcd61ea71f 100644 --- a/src/bsoncxx/test/v1/document/value.cpp +++ b/src/bsoncxx/test/v1/document/value.cpp @@ -16,8 +16,6 @@ // -#include - #include #include @@ -27,6 +25,8 @@ #include #include +#include + #include #include #include @@ -723,7 +723,7 @@ static_assert( !bsoncxx::detail::is_detected::value, "Q does not have a valid from_bson() overload"); -static_assert(!std::is_convertible::value, "to_bson() ctor must be explicit"); +static_assert(bsoncxx::is_explicitly_convertible::value, "to_bson() ctor must be explicit"); static_assert(std::is_constructible::value, "S::to_bson() must be found via ADL"); static_assert(std::is_assignable::value, "S::to_bson() must be found via ADL"); diff --git a/src/bsoncxx/test/v1/document/view.hh b/src/bsoncxx/test/v1/document/view.hh index c5c4f7fc4d..3a714bcf4c 100644 --- a/src/bsoncxx/test/v1/document/view.hh +++ b/src/bsoncxx/test/v1/document/view.hh @@ -20,13 +20,15 @@ #include // StringMaker +#include + #include #include template <> struct Catch::StringMaker { - static std::string convert(bsoncxx::v1::document::view const& value); + static std::string BSONCXX_ABI_CDECL convert(bsoncxx::v1::document::view const& value); }; template <> diff --git a/src/bsoncxx/test/v1/element/view.hh b/src/bsoncxx/test/v1/element/view.hh index b7b3b415f3..3eee8e7355 100644 --- a/src/bsoncxx/test/v1/element/view.hh +++ b/src/bsoncxx/test/v1/element/view.hh @@ -18,9 +18,11 @@ // +#include + #include template <> struct Catch::StringMaker { - static std::string convert(bsoncxx::v1::element::view const& value); + static std::string BSONCXX_ABI_CDECL convert(bsoncxx::v1::element::view const& value); }; diff --git a/src/bsoncxx/test/v1/types/value.cpp b/src/bsoncxx/test/v1/types/value.cpp index b546e15756..0914d2b5fb 100644 --- a/src/bsoncxx/test/v1/types/value.cpp +++ b/src/bsoncxx/test/v1/types/value.cpp @@ -18,6 +18,7 @@ #include +#include #include #include @@ -313,6 +314,38 @@ TEST_CASE("b_types", "[bsoncxx][v1][types][value]") { #pragma pop_macro("X") } +TEST_CASE("get_bson_value", "[bsoncxx][v1][types][value][internal]") { + SECTION("empty string") { + value v{b_string{}}; + + REQUIRE(v.type_id() == id::k_string); + CHECK(v.get_string().value.empty()); + CHECK(v.get_string().value.data() == nullptr); + + auto& bson_value = value::internal::get_bson_value(v); + + REQUIRE(bson_value.value_type == BSON_TYPE_UTF8); + CHECK(bson_value.value.v_utf8.len == 0u); + CHECK(bson_value.value.v_utf8.str == nullptr); + } + + SECTION("empty binary") { + value v{b_binary{}}; + + REQUIRE(v.type_id() == id::k_binary); + CHECK(v.get_binary().subtype == binary_subtype::k_binary); + CHECK(v.get_binary().size == 0u); + CHECK(v.get_binary().bytes == nullptr); + + auto& bson_value = value::internal::get_bson_value(v); + + REQUIRE(bson_value.value_type == BSON_TYPE_BINARY); + CHECK(bson_value.value.v_binary.subtype == BSON_SUBTYPE_BINARY); + CHECK(bson_value.value.v_binary.data_len == 0u); + CHECK(bson_value.value.v_binary.data == nullptr); + } +} + TEST_CASE("constructors", "[bsoncxx][v1][types][value]") { auto const k_binary = binary_subtype::k_binary; auto const k_encrypted = binary_subtype::k_encrypted; diff --git a/src/bsoncxx/test/v1/types/view.cpp b/src/bsoncxx/test/v1/types/view.cpp index b45e46ba9a..5c3e7f9cfe 100644 --- a/src/bsoncxx/test/v1/types/view.cpp +++ b/src/bsoncxx/test/v1/types/view.cpp @@ -16,8 +16,6 @@ // -#include - #include #include #include @@ -27,6 +25,8 @@ #include #include +#include + #include #include @@ -474,17 +474,8 @@ namespace single_value_types { // BType -> Value is implicit, but Value -> BType is explicit. template struct one_way_implicit_convertible { - template - struct is_explicitly_convertible : bsoncxx::detail::conjunction< - std::is_constructible, - bsoncxx::detail::negation>> {}; - - template - struct is_implicitly_convertible - : bsoncxx::detail::conjunction, std::is_convertible> {}; - - static_assert(is_explicitly_convertible::value, "must be explicit"); - static_assert(is_implicitly_convertible::value, "must be implicit"); + static_assert(bsoncxx::is_explicitly_convertible::value, "must be explicit"); + static_assert(bsoncxx::is_implicitly_convertible::value, "must be implicit"); }; // b_minkey diff --git a/src/bsoncxx/test/v_noabi/array.cpp b/src/bsoncxx/test/v_noabi/array.cpp index 0c5c0b53e3..933e32b876 100644 --- a/src/bsoncxx/test/v_noabi/array.cpp +++ b/src/bsoncxx/test/v_noabi/array.cpp @@ -74,4 +74,62 @@ TEST_CASE("array element lookup with std::find", "[bsoncxx::array::view]") { REQUIRE(*it == val); } } + +TEST_CASE("v1", "[bsoncxx][v_noabi][array][element]") { + using v1 = v1::element::view; + using v_noabi = v_noabi::array::element; + using bsoncxx::v_noabi::from_v1; + using bsoncxx::v_noabi::to_v1; + + auto const owner = bsoncxx::builder::basic::make_array(1); + auto const arr = owner.view(); + auto const e = arr[0]; + + SECTION("from_v1") { + v1 from{e}; + v_noabi const to = from; + + CHECK(to.raw() == to_v1(to).raw()); + CHECK(to.raw() == from.raw()); + CHECK(to.raw() != v1{}.raw()); + } + + SECTION("to_v1") { + v_noabi from{e}; + v1 const to{from}; + + CHECK(to.raw() == v_noabi{to}.raw()); // No from_v1(). + CHECK(to.raw() == from.raw()); + CHECK(to.raw() != v_noabi{}.raw()); + } +} + +TEST_CASE("v1", "[bsoncxx][v_noabi][array][view]") { + using v1 = v1::array::view; + using v_noabi = v_noabi::array::view; + using bsoncxx::v_noabi::from_v1; + using bsoncxx::v_noabi::to_v1; + + auto const owner = bsoncxx::builder::basic::make_array(1); + auto const arr = owner.view(); + + SECTION("from_v1") { + v1 from{arr.data()}; + v_noabi const to = from; + + CHECK(to == to_v1(to)); + CHECK(to == from); + CHECK(to != v1{}); + } + + SECTION("to_v1") { + v_noabi from{arr.data(), arr.size()}; + v1 const to{from}; + + CHECK(to == from_v1(to)); + CHECK(to == from); + CHECK(to != v_noabi{}); + } +} + } // namespace diff --git a/src/bsoncxx/test/v_noabi/bson_get_values.cpp b/src/bsoncxx/test/v_noabi/bson_get_values.cpp index 810742f736..a03cac9af7 100644 --- a/src/bsoncxx/test/v_noabi/bson_get_values.cpp +++ b/src/bsoncxx/test/v_noabi/bson_get_values.cpp @@ -12,6 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include +#include + #include #include @@ -387,4 +390,243 @@ TEST_CASE("document::values have a superset of document::view's methods") { } } +TEST_CASE("v1", "[bsoncxx][v_noabi][document][element]") { + using v1 = v1::element::view; + using v_noabi = v_noabi::document::element; + using bsoncxx::v_noabi::from_v1; + using bsoncxx::v_noabi::to_v1; + + auto const owner = bsoncxx::from_json(R"({"x": 1})"); + auto const doc = owner.view(); + auto const e = doc["x"]; + + SECTION("from_v1") { + v1 from{e}; + v_noabi const to = from; + + CHECK(to.raw() == to_v1(to).raw()); + CHECK(to.raw() == from.raw()); + CHECK(to.raw() != v1{}.raw()); + } + + SECTION("to_v1") { + v_noabi from{e}; + v1 const to{from}; + + CHECK(to.raw() == v_noabi{to}.raw()); // No from_v1(). + CHECK(to.raw() == from.raw()); + CHECK(to.raw() != v_noabi{}.raw()); + } +} + +TEST_CASE("v1", "[bsoncxx][v_noabi][document][view]") { + using v1 = v1::document::view; + using v_noabi = v_noabi::document::view; + using bsoncxx::v_noabi::from_v1; + using bsoncxx::v_noabi::to_v1; + + auto const owner = bsoncxx::from_json(R"({"x": 1})"); + auto const doc = owner.view(); + + SECTION("from_v1") { + v1 from{doc.data()}; + v_noabi const to = from; + + CHECK(to == to_v1(to)); + CHECK(to == from); + CHECK(to != v1{}); + } + + SECTION("to_v1") { + v_noabi from{doc.data(), doc.size()}; + v1 const to{from}; + + CHECK(to == from_v1(to)); + CHECK(to == from); + CHECK(to != v_noabi{}); + } +} + +template +bsoncxx::v1::stdx::optional get_deleter(T const& v) { + if (auto const deleter_ptr = v.get_deleter().template target()) { + return *deleter_ptr; + } + return {}; +} + +TEST_CASE("v1", "[bsoncxx][v_noabi][document][value]") { + using v1 = v1::document::value; + using v_noabi = v_noabi::document::value; + using bsoncxx::v_noabi::from_v1; + using bsoncxx::v_noabi::to_v1; + + auto tmp = bsoncxx::from_json(R"({"x": 1})"); + + auto const bson_free_deleter = bsoncxx::from_json("{}").release().get_deleter(); + auto const uint8_t_deleter = v_noabi{{}}.release().get_deleter(); + auto const noop_deleter = &v1::noop_deleter; + + REQUIRE(bson_free_deleter); + REQUIRE(uint8_t_deleter); + REQUIRE(noop_deleter); + + CAPTURE(bson_free_deleter); + CAPTURE(uint8_t_deleter); + CAPTURE(noop_deleter); + + SECTION("from_v1") { + auto const size = tmp.size(); + auto ptr = tmp.release(); + auto const data = ptr.release(); + auto const deleter = ptr.get_deleter(); // bson_free_deleter + + SECTION("default") { + (void)v_noabi{data, size, deleter}; // Unused. + + bsoncxx::v1::document::view const empty; + + v1 from; + + CHECK(from.data() == empty.data()); + CHECK(from.size() == empty.size()); + CHECK(get_deleter(from) == noop_deleter); + + SECTION("copy") { + v_noabi to = from_v1(from); // noop_deleter -> uint8_t_deleter (copy) + + CHECK(to.data() != empty.data()); + CHECK(to.size() == empty.size()); + CHECK(to.release().get_deleter() == uint8_t_deleter); + } + + SECTION("move") { + v_noabi to = from_v1(std::move(from)); // noop_deleter -> uint8_t_deleter (fallback to copy) + + CHECK(from.data() == empty.data()); + CHECK(from.size() == empty.size()); + CHECK(get_deleter(from) == noop_deleter); + + CHECK(to.data() != empty.data()); + CHECK(to.size() == empty.size()); + CHECK(to.release().get_deleter() == uint8_t_deleter); + } + } + + SECTION("copy") { + v1 const from{data, deleter}; + + CHECK(from.data() == data); + CHECK(from.size() == size); + CHECK(get_deleter(from) == bson_free_deleter); + + v_noabi to = from_v1(from); // bson_free_deleter -> uint8_t_deleter (copy) + + CHECK(from.data() == data); + CHECK(from.size() == size); + CHECK(get_deleter(from) == bson_free_deleter); + + CHECK(to.data() != data); + CHECK(to.size() == size); + CHECK(to.release().get_deleter() == uint8_t_deleter); + } + + SECTION("move") { + v1 from{data, deleter}; + + CHECK(from.data() == data); + CHECK(from.size() == size); + CHECK(get_deleter(from) == bson_free_deleter); + + v_noabi to = from_v1(std::move(from)); // bson_free_deleter (move) + + CHECK(from.data() == nullptr); + CHECK(from.size() == 0u); + + // A moved-from std::function is in "a valid with an unspecified value". + CHECK_NOFAIL(get_deleter(from) == nullptr); + + CHECK(to.data() == data); + CHECK(to.size() == size); + CHECK(to.release().get_deleter() == bson_free_deleter); + } + + SECTION("invalid deleter type") { + v1 const owner{data, deleter}; + v1 from = owner; // bson_free_deleter -> default_deleter_type (copy) + + CHECK(from.data() != data); + CHECK(from.size() == size); + CHECK(get_deleter(from).has_value()); + + auto const from_data = from.data(); + + SECTION("copy") { + v_noabi to = from_v1(from); // default_deleter_type -> uint8_t_deleter (copy) + + CHECK(from.data() == from_data); + CHECK(from.size() == size); + CHECK(get_deleter(from).has_value()); + + CHECK(to.data() != from_data); + CHECK(to.size() == size); + CHECK(to.release().get_deleter() == uint8_t_deleter); + } + + SECTION("move") { + v_noabi to = from_v1(std::move(from)); // default_deleter_type -> uint8_t_deleter (fallback to copy) + + CHECK(from.data() == from_data); + CHECK(from.size() == size); + CHECK(get_deleter(from).has_value()); + + CHECK(to.data() != from_data); + CHECK(to.size() == size); + CHECK(to.release().get_deleter() == uint8_t_deleter); + } + } + } + + SECTION("to_v1") { + auto const size = tmp.size(); + auto ptr = tmp.release(); + auto const data = ptr.release(); + auto const deleter = ptr.get_deleter(); + + v_noabi from{data, size, deleter}; + + SECTION("copy") { + CHECK(from.data() == data); + CHECK(from.size() == size); + + v1 const to = to_v1(from); // bson_free_deleter -> uint8_t_deleter (copy) + + CHECK(from.data() == data); + CHECK(from.size() == size); + CHECK(from.release().get_deleter() == bson_free_deleter); + + CHECK(to.data() != data); + CHECK(to.size() == size); + CHECK(get_deleter(to) == uint8_t_deleter); + } + + SECTION("move") { + CHECK(from.data() == data); + CHECK(from.size() == size); + + v1 const to = to_v1(std::move(from)); // bson_free_deleter (move) + + CHECK(from.data() == nullptr); + CHECK(from.size() == size); + + // A moved-from std::function is in "a valid with an unspecified value". + CHECK_NOFAIL(from.release().get_deleter() == nullptr); + + CHECK(to.data() == data); + CHECK(to.size() == size); + CHECK(get_deleter(to) == bson_free_deleter); + } + } +} + } // namespace diff --git a/src/bsoncxx/test/v_noabi/bson_types.cpp b/src/bsoncxx/test/v_noabi/bson_types.cpp index 957c3547ed..4796b1fb62 100644 --- a/src/bsoncxx/test/v_noabi/bson_types.cpp +++ b/src/bsoncxx/test/v_noabi/bson_types.cpp @@ -194,9 +194,11 @@ TEST_CASE("getting types from an uninitialized element throws", "[bsoncxx::docum element elem{}; REQUIRE_THROWS(elem.get_value()); -#define BSONCXX_ENUM(name, val) REQUIRE_THROWS(elem.get_##name()); -#include -#undef BSONCXX_ENUM +#pragma push_macro("X") +#undef X +#define X(_name, _value) REQUIRE_THROWS(elem.get_##_name()); + BSONCXX_V1_TYPES_XMACRO(X) +#pragma pop_macro("X") } TEST_CASE("bson_value::view returns correct type", "[bsoncxx::types::bson_value::view]") { @@ -369,14 +371,21 @@ TEST_CASE("document uninitialized element throws exceptions", "") { using bsoncxx::builder::basic::make_document; bsoncxx::document::value doc = make_document(kvp("foo", "bar")); + REQUIRE_THROWS_WITH( + doc["foo"]["doesnotexist"].get_value(), + Catch::Matchers::Equals( + R"(cannot return the type of uninitialized element: last known element key "foo": view is invalid: unset document::element)")); + REQUIRE_THROWS_WITH( doc["doesnotexist"].get_string().value, - Catch::Matchers::Equals("cannot get string from an uninitialized element: unset document::element")); + Catch::Matchers::Equals( + "cannot get string from an uninitialized element: view is invalid: expected element type k_string")); REQUIRE_THROWS_WITH( doc["alsodoesnotexist"].get_value(), - Catch::Matchers::Equals("cannot return the type of uninitialized element: unset document::element")); + Catch::Matchers::Equals( + "cannot return the type of uninitialized element: view is invalid: unset document::element")); // Ensure a non-existing element evaluates to false. REQUIRE(!doc["doesnotexist"]); @@ -385,7 +394,8 @@ TEST_CASE("document uninitialized element throws exceptions", "") { // Ensure getting a key from a non-existing element results in an exception. REQUIRE_THROWS_WITH( doc["doesnotexist"].key(), - Catch::Matchers::Equals("cannot return the key from an uninitialized element: unset document::element")); + Catch::Matchers::Equals( + "cannot return the key from an uninitialized element: view is invalid: unset document::element")); } TEST_CASE("array uninitialized element throws exceptions", "") { @@ -393,9 +403,15 @@ TEST_CASE("array uninitialized element throws exceptions", "") { using bsoncxx::builder::basic::make_array; bsoncxx::array::value arr = make_array("a", "b", "c"); + REQUIRE_THROWS_WITH( + arr.view()[0]["doesnotexist"].get_value(), + Catch::Matchers::Equals( + R"(cannot return the type of uninitialized element: last known element key "0": view is invalid: unset document::element)")); + REQUIRE_THROWS_WITH( arr.view()[3].get_string().value, - Catch::Matchers::Equals("cannot get string from an uninitialized element: unset document::element")); + Catch::Matchers::Equals( + "cannot get string from an uninitialized element: view is invalid: expected element type k_string")); // Ensure a non-existing element evaluates to false. REQUIRE(!arr.view()[3]); // Ensure finding a non-existing element results in an end iterator. @@ -403,7 +419,8 @@ TEST_CASE("array uninitialized element throws exceptions", "") { // Ensure getting a key from a non-existing element results in an exception. REQUIRE_THROWS_WITH( arr.view()[3].key(), - Catch::Matchers::Equals("cannot return the key from an uninitialized element: unset document::element")); + Catch::Matchers::Equals( + "cannot return the key from an uninitialized element: view is invalid: unset document::element")); } } // namespace diff --git a/src/bsoncxx/test/v_noabi/decimal128.cpp b/src/bsoncxx/test/v_noabi/decimal128.cpp new file mode 100644 index 0000000000..b0a8d179d7 --- /dev/null +++ b/src/bsoncxx/test/v_noabi/decimal128.cpp @@ -0,0 +1,68 @@ +// 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 + +namespace { + +using bsoncxx::v_noabi::decimal128; +using code = bsoncxx::v_noabi::error_code; + +TEST_CASE("exceptions", "[bsoncxx][v_noabi][decimal128]") { + CHECK_THROWS_WITH_CODE(decimal128{bsoncxx::stdx::string_view{}}, code::k_invalid_decimal128); + CHECK_THROWS_WITH_CODE(decimal128{"invalid"}, code::k_invalid_decimal128); +} + +TEST_CASE("basic", "[bsoncxx][v_noabi][decimal128]") { + SECTION("to_string") { + CHECK(decimal128{}.to_string() == "0E-6176"); + } +} + +TEST_CASE("v1", "[bsoncxx][v_noabi][decimal128]") { + using v1 = bsoncxx::v1::decimal128; + using v_noabi = bsoncxx::v_noabi::decimal128; + using bsoncxx::v_noabi::from_v1; + using bsoncxx::v_noabi::to_v1; + + SECTION("from_v1") { + v1 from{1, 1}; + v_noabi to = from; + + CHECK(to == to_v1(to)); + CHECK(to == from); + CHECK(to != v1{}); + } + + SECTION("to_v1") { + v_noabi from{1, 1}; + v1 const to{from}; + + CHECK(to == from_v1(to)); + CHECK(to == from); + CHECK(to != v_noabi{}); + } +} + +} // namespace diff --git a/src/bsoncxx/test/v_noabi/oid.cpp b/src/bsoncxx/test/v_noabi/oid.cpp index f494214095..e54af09c17 100644 --- a/src/bsoncxx/test/v_noabi/oid.cpp +++ b/src/bsoncxx/test/v_noabi/oid.cpp @@ -12,113 +12,167 @@ // 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 +#include -#include +namespace { -using namespace bsoncxx; +using bsoncxx::v_noabi::oid; +using code = bsoncxx::v_noabi::error_code; -namespace { +TEST_CASE("exceptions", "[bsoncxx][v_noabi][oid]") { + char const zeroes[oid::k_oid_length] = {}; + + CHECK_THROWS_WITH_CODE(oid{bsoncxx::stdx::string_view{}}, code::k_invalid_oid); + CHECK_THROWS_WITH_CODE(oid{"invalid"}, code::k_invalid_oid); + + CHECK_THROWS_WITH_CODE((oid{zeroes, oid::k_oid_length - 1u}), code::k_invalid_oid); + CHECK_NOTHROW((oid{zeroes, oid::k_oid_length + 0u})); + CHECK_THROWS_WITH_CODE((oid{zeroes, oid::k_oid_length + 1u}), code::k_invalid_oid); +} struct parsed_oid { - uint32_t timestamp; - uint64_t rand; - uint32_t counter; + std::uint32_t timestamp; + std::uint64_t rand; + std::uint32_t counter; }; parsed_oid parse_oid(oid const& oid) { parsed_oid parsed{}; // Parse into component sections - auto bytes = oid.bytes(); + auto const bytes = oid.bytes(); std::memcpy(&parsed.timestamp, bytes, 4); std::memcpy(&parsed.rand, bytes + 1, 8); std::memcpy(&parsed.counter, bytes + 8, 4); -#if BSON_BYTE_ORDER != BSON_BIG_ENDIAN -#ifndef _WIN32 - parsed.timestamp = __builtin_bswap32(parsed.timestamp); - parsed.rand = __builtin_bswap64(parsed.rand) & 0x000000FFFFFFFFFF; - parsed.counter = __builtin_bswap32(parsed.counter) & 0x00FFFFFF; + if (bsoncxx::detail::endian::native != bsoncxx::detail::endian::big) { +#if defined(_WIN32) + parsed.timestamp = _byteswap_ulong(parsed.timestamp); + parsed.rand = _byteswap_uint64(parsed.rand) & 0x000000FFFFFFFFFF; + parsed.counter = _byteswap_ulong(parsed.counter) & 0x00FFFFFF; #else - parsed.timestamp = _byteswap_ulong(parsed.timestamp); - parsed.rand = _byteswap_uint64(parsed.rand) & 0x000000FFFFFFFFFF; - parsed.counter = _byteswap_ulong(parsed.counter) & 0x00FFFFFF; -#endif + parsed.timestamp = __builtin_bswap32(parsed.timestamp); + parsed.rand = __builtin_bswap64(parsed.rand) & 0x000000FFFFFFFFFF; + parsed.counter = __builtin_bswap32(parsed.counter) & 0x00FFFFFF; #endif + } return parsed; } -void compare_string(std::time_t const& t, std::string time) { - char time_str[48]; +void compare_string(std::time_t const& t, bsoncxx::stdx::string_view time) { + char time_str[48] = {}; + CHECK(0 != (std::strftime(time_str, sizeof(time_str), "%b %e, %Y %H:%M:%S UTC", std::gmtime(&t)))); + CHECK(time_str == time); +} - REQUIRE(0 != (strftime(time_str, sizeof(time_str), "%b %e, %Y %H:%M:%S UTC", std::gmtime(&t)))); +TEST_CASE("basic", "[bsoncxx][v_noabi][oid]") { + SECTION("get_time_t") { + oid const a{"000000000000000000000000"}; // 0x00000000: "Jan 1st, 1970 00:00:00 UTC" + oid const b{"7FFFFFFF0000000000000000"}; // 0x7FFFFFFF: "Jan 19th, 2038 03:14:07 UTC" + oid const c{"800000000000000000000000"}; // 0x80000000: "Jan 19th, 2038 03:14:08 UTC" + oid const d{"FFFFFFFF0000000000000000"}; // 0xFFFFFFFF: "Feb 7th, 2106 06:28:15 UTC" + + auto const ta = a.get_time_t(); + auto const tb = b.get_time_t(); + auto const tc = c.get_time_t(); + auto const td = d.get_time_t(); + + REQUIRE(ta == 0x00000000); + REQUIRE(tb == 0x7FFFFFFF); + REQUIRE(tc == 0x80000000); + REQUIRE(td == 0xFFFFFFFF); + + compare_string(ta, "Jan 1, 1970 00:00:00 UTC"); + compare_string(tb, "Jan 19, 2038 03:14:07 UTC"); + compare_string(tc, "Jan 19, 2038 03:14:08 UTC"); + compare_string(td, "Feb 7, 2106 06:28:15 UTC"); + } - REQUIRE(time_str == time); -} + // Ensure that after a new process is created through a fork() or similar process creation operation, the "random + // number unique to a machine and process" is no longer the same as the parent process that created the new process. + // Defer testing multi-process (fork) behavior to the C Driver. + SECTION("rand and counter") { + oid oid1; + oid oid2; + + auto const parsed1 = parse_oid(oid1); + auto const parsed2 = parse_oid(oid2); + + CHECK(parsed1.rand == parsed2.rand); + CHECK(parsed2.counter == parsed1.counter + 1u); + } -TEST_CASE("oid", "[bsoncxx::oid]") { - SECTION( - "represents the Timestamp field as an unsigned 32-bit representing the number of seconds " - "since the Epoch") { - // 0x00000000: To match "Jan 1st, 1970 00:00:00 UTC" - oid a{"000000000000000000000000"}; - auto t = a.get_time_t(); - REQUIRE(t == 0x00000000); - compare_string(t, "Jan 1, 1970 00:00:00 UTC"); - - // 0x7FFFFFFF: To match "Jan 19th, 2038 03:14:07 UTC" - oid b{"7FFFFFFF0000000000000000"}; - t = b.get_time_t(); - REQUIRE(t == 0x7FFFFFFF); - compare_string(t, "Jan 19, 2038 03:14:07 UTC"); - - // 0x80000000: To match "Jan 19th, 2038 03:14:08 UTC" - oid c{"800000000000000000000000"}; - t = c.get_time_t(); - REQUIRE(t == 0x80000000); - compare_string(t, "Jan 19, 2038 03:14:08 UTC"); - - // 0xFFFFFFFF: To match "Feb 7th, 2106 06:28:15 UTC" - oid d{"FFFFFFFF0000000000000000"}; - t = d.get_time_t(); - REQUIRE(t == 0xFFFFFFFF); - compare_string(t, "Feb 7, 2106 06:28:15 UTC"); + SECTION("to_string") { + char const zeroes[oid::k_oid_length]{}; + oid o{zeroes, sizeof(zeroes)}; + CHECK((oid{zeroes, sizeof(zeroes)}).to_string() == "000000000000000000000000"); } - SECTION("overflows predictably") { - /* The C++ driver does not have the ability to set a context for oids, so we - rely on the C driver's testing of this behaviour */ + SECTION("comparison") { + // Timestamp: 946771199 (0x386e94ff) + // Value: 286462997 (0x11131415) + // Counter: 2171427 (0x212223) + oid const o{"386e94ff1112131415212223"}; + + CHECK(o == o); + CHECK_FALSE(o != o); + CHECK_FALSE(o > o); + CHECK_FALSE(o < o); + CHECK(o >= o); + CHECK(o <= o); + + { + std::time_t time = o.get_time_t(); + char str[sizeof("YYYY-MM-DD HH:MM:SS")]; + CHECK(std::strftime(str, sizeof(str), "%F %T", std::gmtime(&time)) == sizeof(str) - 1u); + CHECK(std::string(str) == "2000-01-01 23:59:59"); + } + + CHECK(o < oid{"389622001112131415212223"}); // Timestamp: 2000-02-01 00:00:00 + CHECK(o > oid{"386d43801112131415212223"}); // Timestamp: 2000-01-01 00:00:00 + CHECK(o < oid{"386e94ffffffffffff212223"}); // Value: 1099511627775 + CHECK(o > oid{"386e94ff0000000000212223"}); // Value: 0 + CHECK(o < oid{"386e94ff1112131415ffffff"}); // Counter: 16777215 + CHECK(o > oid{"386e94ff1112131415000000"}); // Counter: 0 } +} + +TEST_CASE("v1", "[bsoncxx][v_noabi][oid]") { + using v1 = bsoncxx::v1::oid; + using v_noabi = bsoncxx::v_noabi::oid; + using bsoncxx::v_noabi::from_v1; + using bsoncxx::v_noabi::to_v1; + + SECTION("from_v1") { + v1 from{"111111111111111111111111"}; + v_noabi const to = from; + + CHECK(to == to_v1(to)); + CHECK(to == from); + CHECK(to != v1{"000000000000000000000000"}); + } + + SECTION("to_v1") { + v_noabi from{"111111111111111111111111"}; + v1 const to{from}; - SECTION("oid", "uses a different machine/process number after fork is called") { - /* Ensure that after a new process is created through a fork() or similar - process creation operation, the "random number unique to a machine and - process" is no longer the same as the parent process that created - the new process. */ - bsoncxx::oid oid1{}; - bsoncxx::oid oid2{}; - auto parsed1 = parse_oid(oid1); - auto parsed2 = parse_oid(oid2); - - // Two oids created in the same process should have the same random number - REQUIRE(parsed1.rand == parsed2.rand); - REQUIRE(parsed2.counter == parsed1.counter + 1); - - // Unfortunately, the catch framework does not support forking at this time: - // https://github.com/catchorg/Catch2/issues/853 - // - // We rely on the C driver's testing of this behavior. + CHECK(to == from_v1(to)); + CHECK(to == from); + CHECK(to != v_noabi{"000000000000000000000000"}); } } diff --git a/src/mongocxx/lib/mongocxx/private/client_encryption.hh b/src/mongocxx/lib/mongocxx/private/client_encryption.hh index 8b261919e0..3d2111af27 100644 --- a/src/mongocxx/lib/mongocxx/private/client_encryption.hh +++ b/src/mongocxx/lib/mongocxx/private/client_encryption.hh @@ -25,10 +25,7 @@ #include #include -#include - #include -#include #include #include @@ -99,7 +96,7 @@ class client_encryption::impl { throw_exception(error); } - return bsoncxx::v_noabi::types::bson_value::make_owning_bson(keyid.get()); + return bsoncxx::v1::types::value{std::move(keyid)}; } bsoncxx::v_noabi::types::bson_value::value encrypt( @@ -120,7 +117,7 @@ class client_encryption::impl { throw_exception(error); } - return bsoncxx::v_noabi::types::bson_value::make_owning_bson(ciphertext.get()); + return bsoncxx::v1::types::value{std::move(ciphertext)}; } bsoncxx::v_noabi::document::value encrypt_expression( @@ -156,7 +153,7 @@ class client_encryption::impl { throw_exception(error); } - return bsoncxx::v_noabi::types::bson_value::make_owning_bson(decrypted_value.get()); + return bsoncxx::v1::types::value{std::move(decrypted_value)}; } result::rewrap_many_datakey rewrap_many_datakey( diff --git a/src/mongocxx/lib/mongocxx/private/scoped_bson_value.hh b/src/mongocxx/lib/mongocxx/private/scoped_bson_value.hh index 07697f779d..5dcde7db58 100644 --- a/src/mongocxx/lib/mongocxx/private/scoped_bson_value.hh +++ b/src/mongocxx/lib/mongocxx/private/scoped_bson_value.hh @@ -14,61 +14,60 @@ #pragma once +#include + #include #include -#include - #include namespace mongocxx { namespace detail { struct scoped_bson_value { - bson_value_t value = {}; + bsoncxx::v1::types::value value; // Allow obtaining a pointer to this->value even in rvalue expressions. bson_value_t* get() noexcept { - return &value; + auto& v = bsoncxx::v1::types::value::internal::get_bson_value(value); + + // CSFLE API requires empty strings to be not-null. + if (v.value_type == BSON_TYPE_UTF8 && v.value.v_utf8.str == nullptr) { + v.value.v_utf8.str = static_cast(bson_malloc0(1u)); + } + + return &v; } // Communicate this->value is to be initialized via the resulting pointer. bson_value_t* value_for_init() noexcept { - return &this->value; + return &bsoncxx::v1::types::value::internal::get_bson_value(value); } - template - auto convert(T const& value) - // Use trailing return type syntax to SFINAE without triggering GCC -Wignored-attributes - // warnings due to using decltype within template parameters. - -> decltype(bsoncxx::v_noabi::types::convert_to_libbson( - std::declval(), - std::declval())) { - bsoncxx::v_noabi::types::convert_to_libbson(value, &this->value); + explicit operator bsoncxx::v1::types::value() && { + return std::move(value); } - template - explicit scoped_bson_value(T const& value) { - convert(value); + explicit operator bsoncxx::v1::types::value() const& { + return value; } - explicit scoped_bson_value(bsoncxx::v_noabi::types::bson_value::view const& view) { - // Argument order is reversed for bsoncxx::v_noabi::types::bson_value::view. - bsoncxx::v_noabi::types::convert_to_libbson(&this->value, view); - } + scoped_bson_value() = default; - ~scoped_bson_value() { - bson_value_destroy(&value); - } + template + explicit scoped_bson_value(T const& v) : value{convert(v)} {} - // Expectation is that value_for_init() will be used to initialize this->value. - scoped_bson_value() = default; + explicit scoped_bson_value(bsoncxx::v1::types::view const& v) : value{v} {} + + explicit scoped_bson_value(bsoncxx::v_noabi::types::bson_value::view const& v) + : scoped_bson_value{bsoncxx::v_noabi::to_v1(v)} {} - scoped_bson_value(scoped_bson_value const&) = delete; - scoped_bson_value(scoped_bson_value&&) = delete; - scoped_bson_value& operator=(scoped_bson_value const&) = delete; - scoped_bson_value& operator=(scoped_bson_value&&) = delete; + private: + template + auto convert(BType const& v) -> decltype(bsoncxx::v1::types::value{bsoncxx::v_noabi::to_v1(v)}) { + return bsoncxx::v1::types::value{bsoncxx::v_noabi::to_v1(v)}; + } }; } // namespace detail diff --git a/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/options/encrypt.cpp b/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/options/encrypt.cpp index b686419e81..a0563a69d7 100644 --- a/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/options/encrypt.cpp +++ b/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/options/encrypt.cpp @@ -18,8 +18,6 @@ #include #include -#include - #include #include #include diff --git a/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/options/rewrap_many_datakey.cpp b/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/options/rewrap_many_datakey.cpp index 7523bfbae0..fae719a78e 100644 --- a/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/options/rewrap_many_datakey.cpp +++ b/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/options/rewrap_many_datakey.cpp @@ -16,8 +16,6 @@ #include #include -#include - #include #include diff --git a/src/mongocxx/test/CMakeLists.txt b/src/mongocxx/test/CMakeLists.txt index ab0695b61a..daf41f5ebf 100644 --- a/src/mongocxx/test/CMakeLists.txt +++ b/src/mongocxx/test/CMakeLists.txt @@ -34,6 +34,7 @@ endif() set(mongocxx_test_sources_private private/numeric_casting.cpp private/scoped_bson_t.cpp + private/scoped_bson_value.cpp private/write_concern.cpp private/mongoc_version.cpp ) diff --git a/src/mongocxx/test/private/scoped_bson_value.cpp b/src/mongocxx/test/private/scoped_bson_value.cpp new file mode 100644 index 0000000000..60e5b0e1e2 --- /dev/null +++ b/src/mongocxx/test/private/scoped_bson_value.cpp @@ -0,0 +1,131 @@ +// 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 + +namespace { + +using value = mongocxx::detail::scoped_bson_value; + +using namespace bsoncxx::v_noabi::types; + +TEST_CASE("basic", "[mongocxx][private][scoped_bson_value]") { + SECTION("default") { + value v; + CHECK(v.get()->value_type == BSON_TYPE_NULL); + } + + SECTION("b_types") { + SECTION("int32") { + value v{b_int32{123}}; + REQUIRE(v.get()->value_type == BSON_TYPE_INT32); + CHECK(v.get()->value.v_int32 == 123); + } + + SECTION("string") { + SECTION("empty") { + value v{b_string{bsoncxx::stdx::string_view{}}}; + REQUIRE(v.get()->value_type == BSON_TYPE_UTF8); + auto const& v_utf8 = v.get()->value.v_utf8; + CHECK(v_utf8.len == 0u); + CHECK(static_cast(v_utf8.str) != nullptr); + CHECK(v_utf8.str[0] == '\0'); + } + + SECTION("owning") { + auto const str = b_string{"value"}; + value v{str}; + REQUIRE(v.get()->value_type == BSON_TYPE_UTF8); + auto const& v_utf8 = v.get()->value.v_utf8; + CHECK(static_cast(v_utf8.str) != static_cast(str.value.data())); + CHECK(bsoncxx::stdx::string_view{v_utf8.str, v_utf8.len} == str.value); + } + } + + SECTION("binary") { + SECTION("empty") { + value v{b_binary{}}; + REQUIRE(v.get()->value_type == BSON_TYPE_BINARY); + auto const& v_binary = v.get()->value.v_binary; + CHECK(v_binary.subtype == BSON_SUBTYPE_BINARY); + CHECK(v_binary.data_len == 0u); + CHECK(static_cast(v_binary.data) == nullptr); + } + + SECTION("owning") { + std::uint8_t data[1]{0x12}; + value v{b_binary{bsoncxx::v_noabi::binary_sub_type::k_binary, sizeof(data), data}}; + REQUIRE(v.get()->value_type == BSON_TYPE_BINARY); + auto const& v_binary = v.get()->value.v_binary; + CHECK(v_binary.subtype == BSON_SUBTYPE_BINARY); + CHECK(v_binary.data_len == 1u); + CHECK(static_cast(v_binary.data) != static_cast(data)); + REQUIRE(v_binary.data != nullptr); + CHECK(v_binary.data[0] == data[0]); + } + } + } + + SECTION("view") { + SECTION("int32") { + value v{bson_value::view{b_int32{123}}}; + REQUIRE(v.get()->value_type == BSON_TYPE_INT32); + CHECK(v.get()->value.v_int32 == 123); + } + + SECTION("string") { + auto const str = b_string{"value"}; + value v{bson_value::view{str}}; + REQUIRE(v.get()->value_type == BSON_TYPE_UTF8); + auto const& v_utf8 = v.get()->value.v_utf8; + CHECK(static_cast(v_utf8.str) != static_cast(str.value.data())); + CHECK(bsoncxx::stdx::string_view{v_utf8.str, v_utf8.len} == str); + } + } + + SECTION("ownership") { + value v{b_string{"one"}}; + { + bsoncxx::v1::types::value copy{std::move(v)}; + REQUIRE(v.get()->value_type == BSON_TYPE_NULL); + CHECK(copy.type_id() == bsoncxx::v1::types::id::k_string); + CHECK(copy.get_string().value == "one"); + } + + v = value{b_string{"two"}}; + v = value{b_string{"three"}}; + + { + bsoncxx::v1::types::value copy{std::move(v)}; + REQUIRE(v.get()->value_type == BSON_TYPE_NULL); + CHECK(copy.type_id() == bsoncxx::v1::types::id::k_string); + CHECK(copy.get_string().value == "three"); + } + } +} + +} // namespace