diff --git a/.evergreen/scripts/abidiff-test.sh b/.evergreen/scripts/abidiff-test.sh index cc4ea1de2b..75069842df 100755 --- a/.evergreen/scripts/abidiff-test.sh +++ b/.evergreen/scripts/abidiff-test.sh @@ -54,7 +54,11 @@ echo "---" >>cxx-noabi/mongocxx.txt # Allow task to upload the diff reports despite failed status. echo "Comparing stable ABI for bsoncxx..." -if ! abidiff "${abi_flags[@]:?}" install/old/lib/libbsoncxx.so install/new/lib/libbsoncxx.so >>cxx-abi/bsoncxx.txt; then +abidiff "${abi_flags[@]:?}" install/old/lib/libbsoncxx.so install/new/lib/libbsoncxx.so >>cxx-abi/bsoncxx.txt && ret="$?" || ret="$?" +if (("$ret" & 0x03)); then # ABIDIFF_ERROR (1) | ABIDIFF_USAGE_ERROR (2) + echo "abidiff error" >&2 + exit 1 +elif (("$ret" & 0x08)); then # ABIDIFF_ABI_INCOMPATIBLE_CHANGE (8). declare status status='{"status":"failed", "type":"test", "should_continue":true, "desc":"abidiff returned an error for bsoncxx (stable)"}' curl -sS -d "${status:?}" -H "Content-Type: application/json" -X POST localhost:2285/task_status || true @@ -63,7 +67,11 @@ echo "Comparing stable ABI for bsoncxx... done." # Allow task to upload the diff reports despite failed status. echo "Comparing stable ABI for mongocxx..." -if ! abidiff "${abi_flags[@]:?}" install/old/lib/libmongocxx.so install/new/lib/libmongocxx.so >>cxx-abi/mongocxx.txt; then +abidiff "${abi_flags[@]:?}" install/old/lib/libmongocxx.so install/new/lib/libmongocxx.so >>cxx-abi/mongocxx.txt && ret="$?" || ret="$?" +if (("$ret" & 0x03)); then # ABIDIFF_ERROR (1) | ABIDIFF_USAGE_ERROR (2) + echo "abidiff error" >&2 + exit 1 +elif (("$ret" & 0x08)); then # ABIDIFF_ABI_INCOMPATIBLE_CHANGE (8) declare status status='{"status":"failed", "type":"test", "should_continue":true, "desc":"abidiff returned an error for mongocxx (stable)"}' curl -sS -d "${status:?}" -H "Content-Type: application/json" -X POST localhost:2285/task_status || true diff --git a/src/bsoncxx/include/bsoncxx/v1/array/value.hpp b/src/bsoncxx/include/bsoncxx/v1/array/value.hpp index 71e0545e2d..00ca2db62a 100644 --- a/src/bsoncxx/include/bsoncxx/v1/array/value.hpp +++ b/src/bsoncxx/include/bsoncxx/v1/array/value.hpp @@ -20,6 +20,17 @@ #include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + namespace bsoncxx { namespace v1 { namespace array { @@ -29,7 +40,165 @@ namespace array { /// /// @attention This feature is experimental! It is not ready for use! /// -class value {}; +class value { + private: + v1::document::value _value; + + template + struct is_valid_deleter : std::is_constructible {}; + + public: + /// @copydoc v1::document::value::deleter_type + using deleter_type = v1::document::value::deleter_type; + + /// @copydoc v1::document::value::default_deleter_type + using default_deleter_type = v1::document::value::default_deleter_type; + + /// @copydoc v1::document::value::unique_ptr_type + using unique_ptr_type = v1::document::value::unique_ptr_type; + + /// @copydoc v1::document::view::const_iterator + using const_iterator = v1::document::view::const_iterator; + + /// @copydoc v1::document::view::iterator + using iterator = const_iterator; + + /// @copydoc v1::document::value::~value() + ~value() = default; + + /// @copydoc v1::document::value::value(v1::document::value&& other) noexcept + value(value&& other) noexcept : _value{std::move(other._value)} {} + + /// @copydoc v1::document::value::operator=(v1::document::value&& other) noexcept + value& operator=(value&& other) noexcept { + _value = std::move(other._value); + return *this; + } + + /// @copydoc v1::document::value::value(v1::document::value const& other) + value(value const& other) : _value(other._value) {} + + /// @copydoc v1::document::value::operator=(v1::document::value const& other) + value& operator=(value const& other) { + _value = other._value; + return *this; + } + + /// @copydoc v1::document::value::value() + value() = default; + + /// @copydoc v1::document::value::value(std::uint8_t* data, std::size_t length, Deleter deleter) + template ::value>* = nullptr> + value(std::uint8_t* data, std::size_t length, Deleter deleter) : _value{data, length, std::move(deleter)} {} + + /// @copydoc v1::document::value::value(std::uint8_t* data, std::size_t length) + value(std::uint8_t* data, std::size_t length) : _value{data, length} {} + + /// @copydoc v1::document::value::value(v1::document::value::unique_ptr_type ptr, std::size_t length) + value(unique_ptr_type ptr, std::size_t length) : _value{std::move(ptr), length} {} + + /// @copydoc v1::document::value::value(v1::document::view const& view) + explicit value(v1::array::view view) : _value{view} {} + + /// @copydoc v1::document::value::get_deleter() const + deleter_type const& get_deleter() const { + return _value.get_deleter(); + } + + /// @copydoc v1::document::value::release() + unique_ptr_type release() { + return _value.release(); + } + + /// @copydoc v1::document::value::reset(v1::document::value v) + void reset(value v) { + _value = std::move(v._value); + } + + /// @copydoc v1::document::value::reset(v1::document::view const& v) + void reset(v1::array::view v) { + *this = value{v}; + } + + /// + /// Return a view of the BSON binary data as an array. + /// + v1::array::view view() const { + return {_value.data(), _value.size()}; + } + + /// + /// Implicitly convert to `this->view()`. + /// + /* explicit(false) */ operator v1::array::view() const { + return this->view(); + } + + /// @copydoc v1::array::view::cbegin() const + v1::array::view::const_iterator cbegin() const { + return this->view().cbegin(); + } + + /// @copydoc v1::array::view::cend() const + v1::array::view::const_iterator cend() const { + return this->view().cend(); + } + + /// @copydoc v1::array::view::begin() const + v1::array::view::const_iterator begin() const { + return this->view().begin(); + } + + /// @copydoc v1::array::view::end() const + v1::array::view::const_iterator end() const { + return this->view().end(); + } + + /// @copydoc v1::array::view::find(std::uint32_t i) const + v1::array::view::const_iterator find(std::uint32_t i) const { + return this->view().find(i); + } + + /// @copydoc v1::array::view::operator[](std::uint32_t i) const + v1::element::view operator[](std::uint32_t i) const { + return this->view()[i]; + } + + /// @copydoc v1::array::view::data() const + std::uint8_t const* data() const { + return this->view().data(); + } + + /// @copydoc v1::array::view::size() const + std::size_t size() const { + return this->view().size(); + } + + /// @copydoc v1::array::view::length() const + std::size_t length() const { + return this->view().length(); + } + + /// @copydoc v1::array::view::empty() const + bool empty() const { + return this->view().empty(); + } + + /// @copydoc v1::array::view::operator bool() const + explicit operator bool() const { + return this->view().operator bool(); + } + + /// @copydoc v1::array::view::operator==(v1::array::view const& lhs, v1::array::view const& rhs) + friend bool operator==(value const& lhs, value const& rhs) { + return lhs.view() == rhs.view(); + } + + /// @copydoc v1::array::view::operator!=(v1::array::view const& lhs, v1::array::view const& rhs) + friend bool operator!=(value const& lhs, value const& rhs) { + return !(lhs == rhs); + } +}; } // namespace array } // namespace v1 @@ -41,3 +210,8 @@ class value {}; /// @file /// Provides @ref bsoncxx::v1::array::value. /// +/// @par Includes +/// - @ref bsoncxx/v1/array/view.hpp +/// - @ref bsoncxx/v1/document/value.hpp +/// - @ref bsoncxx/v1/element/view.hpp +/// diff --git a/src/bsoncxx/include/bsoncxx/v1/array/view.hpp b/src/bsoncxx/include/bsoncxx/v1/array/view.hpp index 202c4b956a..3fff07a0b7 100644 --- a/src/bsoncxx/include/bsoncxx/v1/array/view.hpp +++ b/src/bsoncxx/include/bsoncxx/v1/array/view.hpp @@ -20,6 +20,14 @@ #include +#include +#include +#include + +#include +#include +#include + namespace bsoncxx { namespace v1 { namespace array { @@ -27,9 +35,111 @@ namespace array { /// /// A non-owning, read-only BSON array. /// +/// An "invalid" view, as indicated by @ref operator bool() const, does not satisfy the minimum requirements of a valid +/// BSON document, which are that: +/// +/// - @ref data() is not null, and +/// - @ref size() is not less than `5` (the minimum size of a BSON document). +/// +/// The BSON binary data being represented is only validated as minimally required to satisfy a requested operation. +/// When an operation is not satisfiable due to invalid data, the operation will throw an @ref bsoncxx::v1::exception +/// with @ref bsoncxx::v1::error::document::view::invalid_data. +/// /// @attention This feature is experimental! It is not ready for use! /// -class view {}; +class view { + public: + /// @copydoc v1::document::view::const_iterator + using const_iterator = v1::document::view::const_iterator; + + /// @copydoc v1::document::view::iterator + using iterator = const_iterator; + + private: + v1::document::view _view; + + public: + /// @copydoc v1::document::view::view() + view() = default; + + /// @copydoc v1::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} {} + + /// @copydoc v1::document::view::data() const + std::uint8_t const* data() const { + return _view.data(); + } + + /// @copydoc v1::document::view::size() const + std::size_t size() const { + return _view.size(); + } + + /// @copydoc v1::document::view::length() const + std::size_t length() const { + return _view.length(); + } + + /// @copydoc v1::document::view::empty() const + bool empty() const { + return _view.empty(); + } + + /// @copydoc v1::document::view::operator bool() const + explicit operator bool() const { + return _view.operator bool(); + } + + /// @copydoc v1::document::view::cbegin() const + BSONCXX_ABI_EXPORT_CDECL(const_iterator) cbegin() const; + + /// @copydoc v1::document::view::cend() const + const_iterator cend() const { + return {}; + } + + /// @copydoc v1::document::view::cbegin() const + const_iterator begin() const { + return this->cbegin(); + } + + /// @copydoc v1::document::view::cend() const + const_iterator end() const { + return this->cend(); + } + + /// + /// Return a const iterator to the element within the represented BSON array at index `i`. + /// + /// If this view is invalid, returns an end iterator. + /// + /// @exception bsoncxx::v1::exception with @ref bsoncxx::v1::error::document::view::invalid_data if this operation + /// failed due to invalid BSON binary data. + /// + BSONCXX_ABI_EXPORT_CDECL(const_iterator) find(std::uint32_t i) const; + + /// @copydoc find(std::uint32_t i) const + v1::element::view operator[](std::uint32_t i) const { + return *(this->find(i)); + } + + /// + /// Implicitly convert to a @ref bsoncxx::v1::document::view. + /// + /* explicit(false) */ operator v1::document::view() const { + return _view; + } + + /// @copydoc v1::document::view::operator==(v1::document::view const& lhs, v1::document::view const& rhs) + friend bool operator==(view const& lhs, view const& rhs) { + return lhs._view == rhs._view; + } + + /// @copydoc v1::document::view::operator!=(v1::document::view const& lhs, v1::document::view const& rhs) + friend bool operator!=(view const& lhs, view const& rhs) { + return !(lhs == rhs); + } +}; } // namespace array } // namespace v1 @@ -41,3 +151,7 @@ class view {}; /// @file /// Provides @ref bsoncxx::v1::array::view. /// +/// @par Includes +/// - @ref bsoncxx/v1/document/view.hpp +/// - @ref bsoncxx/v1/element/view.hpp +/// diff --git a/src/bsoncxx/include/bsoncxx/v1/decimal128.hpp b/src/bsoncxx/include/bsoncxx/v1/decimal128.hpp index 4f9c12612b..842e8987af 100644 --- a/src/bsoncxx/include/bsoncxx/v1/decimal128.hpp +++ b/src/bsoncxx/include/bsoncxx/v1/decimal128.hpp @@ -20,6 +20,65 @@ #include +#include +#include + +#include +#include + +namespace bsoncxx { +namespace v1 { +namespace error { +namespace category { + +/// +/// The error category for @ref bsoncxx::v1::error::decimal128. +/// +/// @attention This feature is experimental! It is not ready for use! +/// +BSONCXX_ABI_EXPORT_CDECL(std::error_category const&) decimal128(); + +} // namespace category +} // namespace error +} // namespace v1 +} // namespace bsoncxx + +namespace bsoncxx { +namespace v1 { +namespace error { + +/// +/// Errors codes which may be returned by @ref bsoncxx::v1::decimal128. +/// +/// @attention This feature is experimental! It is not ready for use! +/// +enum class decimal128 { + zero, ///< Zero. + empty_string, ///< String must not be empty. + invalid_string_length, ///< Length of string is too long (exceeds `INT_MAX`). + invalid_string_data, ///< String is not a valid Decimal128 representation. +}; + +/// +/// Support implicit conversion to `std::error_code`. +/// +/// @attention This feature is experimental! It is not ready for use! +/// +inline std::error_code make_error_code(decimal128 v) { + return {static_cast(v), v1::error::category::decimal128()}; +} + +} // namespace error +} // namespace v1 +} // namespace bsoncxx + +namespace std { + +template <> +struct is_error_code_enum : true_type {}; + +} // namespace std + namespace bsoncxx { namespace v1 { @@ -28,7 +87,68 @@ namespace v1 { /// /// @attention This feature is experimental! It is not ready for use! /// -class decimal128 {}; +class decimal128 { + private: + std::uint64_t _high = 0u; + std::uint64_t _low = 0u; + + public: + /// + /// Zero-initialize the byte representation. + /// + /// @note The result is equivalent to `"0E-6176"`, not `"0"`. + /// + decimal128() = default; + + /// + /// Initialize with the given `high` and `low` byte representations. + /// + decimal128(std::uint64_t high, std::uint64_t low) : _high{high}, _low{low} {} + + /// + /// Initialize with the given Decimal128 string representation. + /// + /// @throws bsoncxx::v1::exception with @ref bsoncxx::v1::error::decimal128::empty_string if `str` is null. + /// @throws bsoncxx::v1::exception with @ref bsoncxx::v1::error::decimal128::invalid_string_length if the length of + /// `str` exceeds `INT_MAX`. + /// @throws bsoncxx::v1::exception with @ref bsoncxx::v1::error::decimal128::invalid_string_data if `str` is not a + /// valid Decimal128 string representation. + /// + explicit BSONCXX_ABI_EXPORT_CDECL() decimal128(v1::stdx::string_view str); + + /// + /// Return the string representation. + /// + BSONCXX_ABI_EXPORT_CDECL(std::string) to_string() const; + + /// + /// Return the high-order bytes. + /// + std::uint64_t high() const { + return _high; + } + + /// + /// Return the low-order bytes. + /// + std::uint64_t low() const { + return _low; + } + + /// + /// Compare equal when the byte representations compare equal. + /// + /// @{ + friend bool operator==(decimal128 const& lhs, decimal128 const& rhs) { + return lhs._high == rhs._high && lhs._low == rhs._low; + } + + friend bool operator!=(decimal128 const& lhs, decimal128 const& rhs) { + return !(lhs == rhs); + } + /// @} + /// +}; } // namespace v1 } // namespace bsoncxx diff --git a/src/bsoncxx/include/bsoncxx/v1/detail/macros.hpp b/src/bsoncxx/include/bsoncxx/v1/detail/macros.hpp index d70cba09c1..337610dbb9 100644 --- a/src/bsoncxx/include/bsoncxx/v1/detail/macros.hpp +++ b/src/bsoncxx/include/bsoncxx/v1/detail/macros.hpp @@ -83,6 +83,13 @@ #define BSONCXX_PRIVATE_CONSTEXPR_CXX14 inline #endif +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56019 +#if defined(__GNUC__) && (__GNUC__ < 5) && !defined(__clang__) +#define BSONCXX_PRIVATE_MAX_ALIGN_T max_align_t +#else +#define BSONCXX_PRIVATE_MAX_ALIGN_T std::max_align_t +#endif + #define BSONCXX_PRIVATE_IF_MSVC(...) #define BSONCXX_PRIVATE_IF_GCC(...) #define BSONCXX_PRIVATE_IF_CLANG(...) diff --git a/src/bsoncxx/include/bsoncxx/v1/document/value.hpp b/src/bsoncxx/include/bsoncxx/v1/document/value.hpp index 06ca4d5c9b..d8a3705332 100644 --- a/src/bsoncxx/include/bsoncxx/v1/document/value.hpp +++ b/src/bsoncxx/include/bsoncxx/v1/document/value.hpp @@ -20,6 +20,18 @@ #include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + namespace bsoncxx { namespace v1 { namespace document { @@ -29,7 +41,348 @@ namespace document { /// /// @attention This feature is experimental! It is not ready for use! /// -class value {}; +class value { + public: + /// + /// The type of the deleter used to free the underlying BSON binary data. + /// + /// A deleter `D` that is wrapped by @ref deleter_type must: + /// + /// - be `std::is_nothrow_destructible`, + /// - be `std::is_nothrow_move_constructible`, + /// - not throw an exception when invoked with a `std::uint8_t*`. + /// + /// These requirements are the same as those for a `std::unique_ptr` deleter `D`, but do not include nothrow + /// move assignability due to being wrapped by @ref deleter_type. + /// + /// @important Despite being a `std::function`, @ref deleter_type is assumed to behave like a C++23 + /// `std::move_only_function`. That is, it is assumed to be nothrow destructible, nothrow move constructible, and + /// nothrow move assignable. + /// + using deleter_type = std::function; + + /// + /// The deleter used to free copied BSON binary data when a user-provided deleter is not specified. + /// + using default_deleter_type = std::default_delete; + + /// + /// The type of the unique pointer used to manage the underlying BSON binary data. + /// + using unique_ptr_type = std::unique_ptr; + + private: + unique_ptr_type _data; + std::size_t _length = 0u; + + template + using is_value = detail::is_alike; + + template + using to_bson_expr = decltype(to_bson(std::declval(), std::declval())); + + template + struct has_to_bson : detail::conjunction>, detail::is_detected> {}; + + template + using from_bson_expr = decltype(from_bson(std::declval(), std::declval())); + + template + struct has_from_bson : detail::conjunction>, detail::is_detected> { + }; + + template + struct is_valid_deleter + : detail::disjunction< + // std::function may not be nothrow move constructible across all pre-C++20 implementations. + // Deliberately allow an exemption that assumes it is de facto nothrow move constructible. + std::is_same, + // Same requirements for D in std::unique_ptr but without (nothrow) move assignability which is not + // required for T in std::function. + detail::conjunction< + std::is_convertible, + std::is_nothrow_destructible, + std::is_nothrow_move_constructible>> {}; + + public: + /// @copydoc v1::document::view::const_iterator + using const_iterator = v1::document::view::const_iterator; + + /// @copydoc v1::document::view::iterator + using iterator = const_iterator; + + /// + /// Destroy this object. + /// + ~value() = default; + + /// + /// Move construction. + /// + /// @par Postconditions: + /// - `other` is equivalent to a default-initialized value. + /// + value(value&& other) noexcept : _data{std::move(other._data)}, _length{other._length} { + other._length = 0u; + } + + /// + /// Move assignment. + /// + /// @par Postconditions: + /// - `other` is equivalent to a default-initialized value. + /// + value& operator=(value&& other) noexcept { + _data = std::move(other._data); + + _length = other._length; + other._length = 0u; + + return *this; + } + + /// + /// Copy construction. + /// + /// The copied value is allocated using `operator new[]` and the deleter is set to @ref + /// default_deleter_type. + /// + value(value const& other) : value{other.view()} {} + + /// + /// Copy assignment. + /// + /// The copied value is allocated using `operator new[]` and the deleter is set to @ref + /// default_deleter_type. + /// + value& operator=(value const& other) { + *this = value{other.view()}; + return *this; + } + + /// + /// Initialize without any underlying BSON binary data or deleter. + /// + /// @par Postconditions: + /// - `this->data() == nullptr` + /// - `static_cast(this->get_deleter()) == false` + /// - `this->size() == 0` + /// + value() = default; + + /// + /// Initialize as owning `data` which will be freed with `deleter`. + /// + /// @par Constraints: + /// - `Deleter` must satisfy the requirements described by @ref deleter_type. + /// + /// @par Preconditions: + /// - `length` must be less than or equal to the storage region pointed to by `data`. + /// - `deleter` must be capable of freeing the storage region pointed to by `data`. + /// + template ::value>* = nullptr> + value(std::uint8_t* data, std::size_t length, Deleter deleter) : _data{data, std::move(deleter)}, _length{length} {} + + /// + /// Initialize as owning `data` which will be freed with @ref default_deleter_type. + /// + /// @par Preconditions: + /// - `length` must be less than or equal to the storage region pointed to by `data`. + /// - `deleter` must be capable of freeing the storage region pointed to by `data`. + /// + value(std::uint8_t* data, std::size_t length) : value{data, length, default_deleter_type{}} {} + + /// + /// Initialize as owning `ptr`. + /// + /// @par Preconditions: + /// - `length` must be less than or equal to the storage region pointed to by `data`. + /// + value(unique_ptr_type ptr, std::size_t length) : _data{std::move(ptr)}, _length{length} {} + + /// + /// Initialize with a copy of the BSON binary data referenced by `view`. + /// + /// If `view` is invalid, this value is default-initialized. + /// + /// The copied value is allocated using `operator new[]` and the deleter is set to @ref + /// default_deleter_type. + /// + explicit value(v1::document::view const& view) + : _data{view ? unique_ptr_type{new std::uint8_t[view.size()], default_deleter_type{}} : unique_ptr_type{}}, + _length{view ? view.size() : 0u} { + if (view) { + std::memcpy(_data.get(), view.data(), view.size()); + } + } + + /// + /// Equivalent to `to_bson(v, *this);` after default-initialization. + /// + /// @par Constraints: + /// - `T` is not @ref bsoncxx::v1::document::value. + /// - `to_bson(v, *this)` is a valid and unambiguous overload found by ADL. + /// + template ::value>* = nullptr> + explicit value(T const& v) : value{} { + to_bson(v, *this); // ADL. + } + + /// + /// Equivalent to `*this = value{v}`. + /// + /// @par Constraints: + /// - `T` is not @ref bsoncxx::v1::document::value. + /// - `to_bson(v, *this)` is a valid and unambiguous overload found by ADL. + /// + template ::value>* = nullptr> + value& operator=(T const& v) { + *this = value{v}; + return *this; + } + + /// + /// Equivalent to `from_bson(v, this->view())`. + /// + /// @par Constraints: + /// - `T` is not @ref bsoncxx::v1::document::value. + /// - `from_bson(v, this->view())` is a valid and unambiguous overload found by ADL. + /// + template ::value>* = nullptr> + void get(T& v) const { + from_bson(v, this->view()); // ADL. + } + + /// + /// Equivalent to `T value; this->get(value); return value;`. + /// + /// @par Constraints: + /// - `T` is not @ref bsoncxx::v1::document::value. + /// - `T` is default-constructible. + /// - `from_bson(v, this->view())` is a valid and unambiguous overload found by ADL. + /// + template < + typename T, + detail::enable_if_t, has_from_bson>::value>* = nullptr> + T get() const { + T res; + this->get(res); + return res; + } + + /// + /// Return the current deleter. + /// + deleter_type const& get_deleter() const { + return _data.get_deleter(); + } + + /// + /// Release ownership of the underlying BSON binary data. + /// + unique_ptr_type release() { + _length = 0u; + return std::move(_data); + } + + /// + /// Replace the underlying BSON binary data with `v`. + /// + void reset(value v) { + *this = std::move(v); + } + + /// + /// Replace the underlying BSON binary data with a copy of `v`. + /// + /// If `v` is invalid, reset to a default-initialized value. + /// + /// The copied value is allocated using `operator new[]` and the deleter is set to @ref + /// default_deleter_type. + /// + void reset(v1::document::view const& v) { + *this = value{v}; + } + + /// + /// Return a view of the BSON binary data as a document. + /// + v1::document::view view() const { + return {_data.get(), _length}; + } + + /// + /// Implicitly convert to `this->view()`. + /// + /* explicit(false) */ operator v1::document::view() const { + return this->view(); + } + + /// @copydoc v1::document::view::cbegin() const + const_iterator cbegin() const { + return this->view().cbegin(); + } + + /// @copydoc v1::document::view::cend() const + const_iterator cend() const { + return this->view().cend(); + } + + /// @copydoc v1::document::view::begin() const + const_iterator begin() const { + return this->view().begin(); + } + + /// @copydoc v1::document::view::end() const + const_iterator end() const { + return this->view().end(); + } + + /// @copydoc v1::document::view::find(v1::stdx::string_view key) const + const_iterator find(v1::stdx::string_view key) const { + return this->view().find(key); + } + + /// @copydoc v1::document::view::operator[](v1::stdx::string_view key) const + v1::element::view operator[](v1::stdx::string_view key) const { + return this->view()[key]; + } + + /// @copydoc v1::document::view::data() const + std::uint8_t const* data() const { + return _data.get(); + } + + /// @copydoc v1::document::view::size() const + std::size_t size() const { + return this->view().size(); + } + + /// @copydoc v1::document::view::length() const + std::size_t length() const { + return this->view().length(); + } + + /// @copydoc v1::document::view::empty() const + bool empty() const { + return this->view().empty(); + } + + /// @copydoc v1::document::view::operator bool() const + explicit operator bool() const { + return this->view().operator bool(); + } + + /// @copydoc v1::document::view::operator==(v1::document::view const& lhs, v1::document::view const& rhs) + friend bool operator==(value const& lhs, value const& rhs) { + return lhs.view() == rhs.view(); + } + + /// @copydoc v1::document::view::operator!=(v1::document::view const& lhs, v1::document::view const& rhs) + friend bool operator!=(value const& lhs, value const& rhs) { + return !(lhs == rhs); + } +}; } // namespace document } // namespace v1 @@ -41,3 +394,7 @@ class value {}; /// @file /// Provides @ref bsoncxx::v1::document::value. /// +/// @par Includes +/// - @ref bsoncxx/v1/document/view.hpp +/// - @ref bsoncxx/v1/element/view.hpp +/// diff --git a/src/bsoncxx/include/bsoncxx/v1/document/view.hpp b/src/bsoncxx/include/bsoncxx/v1/document/view.hpp index 204d834719..ce4f81d7c6 100644 --- a/src/bsoncxx/include/bsoncxx/v1/document/view.hpp +++ b/src/bsoncxx/include/bsoncxx/v1/document/view.hpp @@ -20,6 +20,79 @@ #include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace bsoncxx { +namespace v1 { +namespace error { +namespace category { + +/// +/// Declares error categories for error codes declared in @ref bsoncxx::v1::error::document. +/// +namespace document { + +/// +/// The error category for @ref bsoncxx::v1::error::document::view. +/// +/// @attention This feature is experimental! It is not ready for use! +/// +BSONCXX_ABI_EXPORT_CDECL(std::error_category const&) view(); + +} // namespace document +} // namespace category +} // namespace error +} // namespace v1 +} // namespace bsoncxx + +namespace bsoncxx { +namespace v1 { +namespace error { + +/// +/// Declares error codes returned by @ref bsoncxx::v1::document interfaces. +/// +namespace document { + +/// +/// Errors codes which may be returned by @ref bsoncxx::v1::document::view. +/// +/// @attention This feature is experimental! It is not ready for use! +/// +enum class view { + zero, ///< Zero. + invalid_data, ///< Data is invalid. +}; + +/// +/// Support implicit conversion to `std::error_code`. +/// +/// @attention This feature is experimental! It is not ready for use! +/// +inline std::error_code make_error_code(view v) { + return {static_cast(v), v1::error::category::document::view()}; +} + +} // namespace document +} // namespace error +} // namespace v1 +} // namespace bsoncxx + +namespace std { + +template <> +struct is_error_code_enum : true_type {}; + +} // namespace std + namespace bsoncxx { namespace v1 { namespace document { @@ -27,9 +100,259 @@ namespace document { /// /// A non-owning, read-only BSON document. /// +/// An "invalid" view, as indicated by @ref operator bool() const, does not satisfy the minimum requirements of a valid +/// BSON document, which are that: +/// +/// - @ref data() is not null, and +/// - @ref size() is not less than `5` (the minimum size of a BSON document). +/// +/// The BSON binary data being represented is only validated as minimally required to satisfy a requested operation. +/// When an operation is not satisfiable due to invalid data, the operation will throw an @ref bsoncxx::v1::exception +/// with @ref bsoncxx::v1::error::document::view::invalid_data. +/// /// @attention This feature is experimental! It is not ready for use! /// -class view {}; +class view { + public: + class const_iterator; + + /// + /// Equivalent to @ref const_iterator. + /// + using iterator = const_iterator; + + private: + enum : std::size_t { _empty_length = 5u }; + + std::uint8_t const* _data; + std::size_t _length; + + public: + /// + /// Initialize as an empty view. + /// + /// @par Postconditions: + /// - `this->data() != nullptr` + /// - `this->size() == 5` + /// - `this->empty() == true` + /// + BSONCXX_ABI_EXPORT_CDECL() view(); + + /// + /// Initialize with the given BSON binary data. + /// + /// @par Preconditions: + /// - `length` must be less than or equal to the storage region pointed to by `data`. + /// + view(std::uint8_t const* data, std::size_t length) : _data(data), _length(length) {} + + /// + /// Return a pointer to the BSON binary data being represented. + /// + std::uint8_t const* data() const { + return _data; + } + + /// + /// Return the length of the BSON binary data being represented. + /// + /// @note This returns the length as specified during initialization, not the length of the BSON binary data as + /// indicated by the BSON binary data itself. + /// + std::size_t size() const { + return _length; + } + + /// @copydoc size() const + std::size_t length() const { + return _length; + } + + /// + /// Return true when the BSON binary data represents an empty view. + /// + /// @note This does not return true when this view is invalid. + /// + bool empty() const { + return this->operator bool() && _data[4] == 0u; + } + + /// + /// Return true when this view is valid. + /// + /// @note This does not validate the BSON binary data being represented. + /// + explicit operator bool() const { + return _data && _length >= _empty_length; + } + + /// + /// Return a const iterator to the beginning of the range of BSON elements within this view. + /// + /// If this view is invalid, returns an end iterator. + /// + /// @exception bsoncxx::v1::exception with @ref bsoncxx::v1::error::document::view::invalid_data if this operation + /// failed due to invalid BSON binary data. + /// + BSONCXX_ABI_EXPORT_CDECL(const_iterator) cbegin() const; + + /// + /// Return a const iterator to the end of the range of BSON elements within this view. + /// + const_iterator cend() const; + + /// @copydoc cbegin() const + const_iterator begin() const; + + /// @copydoc cend() const + const_iterator end() const; + + /// + /// Return a const iterator to the element within the represented BSON document whose key compares equal to `key`. + /// + /// If this view is invalid, returns an end iterator. + /// + /// @exception bsoncxx::v1::exception with @ref bsoncxx::v1::error::document::view::invalid_data if this operation + /// failed due to invalid BSON binary data. + /// + BSONCXX_ABI_EXPORT_CDECL(const_iterator) find(v1::stdx::string_view key) const; + + /// @copydoc find(v1::stdx::string_view key) const + v1::element::view operator[](v1::stdx::string_view key) const; + + /// + /// Compare equal when the BSON binary data represented by `lhs` and `rhs` compare equal. + /// + /// An invalid view only compares equal to another invalid view. The underlying BSON binary data (if any) is ignored + /// for an invalid document. + /// + /// @{ + friend bool operator==(view const& lhs, view const& rhs) { + if (!lhs != !rhs) { + return false; + } + + return !lhs || (lhs.length() == rhs.length() && std::memcmp(lhs.data(), rhs.data(), lhs.length()) == 0); + } + + friend bool operator!=(view const& lhs, view const& rhs) { + return !(lhs == rhs); + } + /// @} + /// +}; + +/// +/// A const iterator over the elements of a view. +/// +/// @note This iterator almost satisfies Cpp17ForwardIterator, but `std::iterator_traits::reference` is defined as +/// `value_type`, similar to `std::vector::iterator` and `std::istreambuf_iterator`. Therefore, this iterator +/// only fully satisfies Cpp17InputIterator. +/// +/// @attention This feature is experimental! It is not ready for use! +/// +class view::const_iterator { + private: + v1::element::view _element; + + public: + /// + /// Provide `std::iterator_traits::iterator_category`. + /// + using iterator_category = std::input_iterator_tag; + + /// + /// Provide `std::iterator_traits::value_type`. + /// + using value_type = v1::element::view; + + /// + /// Provide `std::iterator_traits::difference_type`. + /// + using difference_type = std::ptrdiff_t; + + /// + /// Provide `std::iterator_traits::pointer`. + /// + using pointer = value_type const*; + + /// + /// Provide `std::iterator_traits::reference`. + /// + using reference = value_type; + + /// + /// Initialize as an end iterator. + /// + const_iterator() = default; + + /// + /// Return the current element. + /// + /// If this is an end iterator, returns an invalid element. + /// + reference operator*() const { + return _element; + } + + /// + /// Access the current element. + /// + /// If this is an end iterator, accesses an invalid element. + /// + pointer operator->() const { + return &_element; + } + + /// + /// Pre-increment this iterator. + /// + /// If this is an end iterator, it remains an end iterator. + /// + BSONCXX_ABI_EXPORT_CDECL(const_iterator&) operator++(); + + /// + /// Post-increment this iterator. + /// + /// If this is an end iterator, it remains an end iterator. + /// + const_iterator operator++(int) { + const_iterator tmp = *this; + this->operator++(); + return tmp; + } + + /// @copydoc v1::element::view::operator==(v1::element::view const& lhs, v1::element::view const& rhs) + friend bool operator==(const_iterator const& lhs, const_iterator const& rhs) { + return lhs._element == rhs._element; + } + + /// @copydoc v1::element::view::operator!=(v1::element::view const& lhs, v1::element::view const& rhs) + friend bool operator!=(const_iterator const& lhs, const_iterator const& rhs) { + return !(lhs == rhs); + } + + class internal; + + private: + explicit BSONCXX_ABI_EXPORT_CDECL() const_iterator(v1::element::view element); +}; + +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(); +} + +inline v1::element::view view::operator[](v1::stdx::string_view key) const { + return *(this->find(key)); +} } // namespace document } // namespace v1 @@ -41,3 +364,6 @@ class view {}; /// @file /// Provides @ref bsoncxx::v1::document::view. /// +/// @par Includes +/// - @ref bsoncxx/v1/element/view.hpp +/// diff --git a/src/bsoncxx/include/bsoncxx/v1/element/view.hpp b/src/bsoncxx/include/bsoncxx/v1/element/view.hpp index 84df4c2b05..53769a74f2 100644 --- a/src/bsoncxx/include/bsoncxx/v1/element/view.hpp +++ b/src/bsoncxx/include/bsoncxx/v1/element/view.hpp @@ -20,6 +20,84 @@ #include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace bsoncxx { +namespace v1 { +namespace error { +namespace category { + +/// +/// Declares error categories for error codes declared in @ref bsoncxx::v1::error::element. +/// +namespace element { + +/// +/// The error category for @ref bsoncxx::v1::error::element::view. +/// +/// @attention This feature is experimental! It is not ready for use! +/// +BSONCXX_ABI_EXPORT_CDECL(std::error_category const&) view(); + +} // namespace element +} // namespace category +} // namespace error +} // namespace v1 +} // namespace bsoncxx + +namespace bsoncxx { +namespace v1 { +namespace error { + +/// +/// Declares error codes returned by @ref bsoncxx::v1::element interfaces. +/// +namespace element { + +/// +/// Errors codes which may be returned by @ref bsoncxx::v1::element::view. +/// +/// @attention This feature is experimental! It is not ready for use! +/// +enum class view { + zero, ///< Zero. + invalid_view, ///< View is invalid. + invalid_data, ///< Data is invalid. +}; + +/// +/// Support implicit conversion to `std::error_code`. +/// +/// @attention This feature is experimental! It is not ready for use! +/// +inline std::error_code make_error_code(view v) { + return {static_cast(v), v1::error::category::element::view()}; +} + +} // namespace element +} // namespace error +} // namespace v1 +} // namespace bsoncxx + +namespace std { + +template <> +struct is_error_code_enum : true_type {}; + +} // namespace std + namespace bsoncxx { namespace v1 { namespace element { @@ -27,9 +105,204 @@ namespace element { /// /// A non-owning, read-only BSON element. /// +/// An "invalid" element, as indicated by @ref operator bool() const, does not represent a BSON element and does not +/// have an underlying key or value. Attempting to query the key or value of an invalid element will throw an exception. +/// However, subscripting will not throw an exception when the requested field does not exist; instead it will return an +/// invalid element to facilitate chaining. +/// +/// ```cpp +/// a = doc["a"]; // If "a" exists, `a` is valid. Otherwise, `a` is invalid. +/// b = a["2"]; // If "a.b" exists and is a document, `b` is valid. Otherwise, `b` is invalid. +/// c = b[3]; // If "a.b.c" exists and is an array, `c` is valid. Otherwise, `c` is invalid. +/// +/// a.key(); // Throws an exception if invalid. +/// b.type_id(); // Throws an exception if invalid. +/// c.get_int32(); // Throws an exception if invalid. +/// ``` +/// +/// Do not chain subscripts (e.g. `doc["a"]["b"]`) or immediately query element properties (e.g. `doc["x"].key()`) +/// if you need to identify which field may be missing. +/// +/// ```cpp +/// // Unclear whether "x" or "x.y" was missing when an exception is thrown. +/// try { doc["x"]["y"].type_id(); } catch (...) {} +/// +/// // Check validity prior to further access to identify the missing field. +/// if (x = doc["x"]) { +/// if (y = x["y"]) {} // Field "x.y" is present. +/// else {} // Field "x.y" is missing. +/// } else {} // Field "x" is missing. +/// +/// // A less efficient but more concise approach. +/// if (doc["x"]["y"]) {} // Field "x.y" is present. +/// else if (doc["x"]) {} // Field "x.y" is missing. +/// else {} // Field "x" is missing. +/// ``` +/// +/// The BSON binary data being represented is only validated as minimally required to satisfy a requested operation. +/// When an operation is not satisfiable due to invalid data, the operation will throw an @ref bsoncxx::v1::exception +/// with @ref bsoncxx::v1::error::document::view::invalid_data. +/// /// @attention This feature is experimental! It is not ready for use! /// -class view {}; +class view { + private: + class impl; + + alignas(BSONCXX_PRIVATE_MAX_ALIGN_T) unsigned char _storage[32]; + + public: + /// + /// Destroy this object. + /// + BSONCXX_ABI_EXPORT_CDECL() ~view(); + + // Handled by the nothrow copy constructor. + // view(view&& other) noexcept; + + // Handled by the nothrow copy assignment operator. + // view& operator=(view&& other) noexcept; + + /// + /// Copy (or move) construction. + /// + BSONCXX_ABI_EXPORT_CDECL() view(view const& other) noexcept; + + /// + /// Copy (or move) assignment. + /// + BSONCXX_ABI_EXPORT_CDECL(view&) operator=(view const& other) noexcept; + + /// + /// Initialize as an invalid element without any associated BSON binary data. + /// + BSONCXX_ABI_EXPORT_CDECL() view(); + + /// + /// Return true when this is a valid element. + /// + /// @note This does not validate the BSON binary data being represented. + /// + explicit BSONCXX_ABI_EXPORT_CDECL() operator bool() const; + + /// + /// Return the "raw" component of the underlying BSON binary data. + /// + /// The value is unspecified when this element is invalid. + /// + BSONCXX_ABI_EXPORT_CDECL(std::uint8_t const*) raw() const; + + /// + /// Return the "length" component of the underlying BSON binary data. + /// + /// The value is unspecified when this element is invalid. + /// + BSONCXX_ABI_EXPORT_CDECL(std::uint32_t) length() const; + + /// + /// Return the "offset" component of the underlying BSON binary data. + /// + /// The value is unspecified when this element is invalid. + /// + BSONCXX_ABI_EXPORT_CDECL(std::uint32_t) offset() const; + + /// + /// Return the "keylen" component of the underlying BSON binary data. + /// + /// The value is unspecified when this element is invalid. + /// + BSONCXX_ABI_EXPORT_CDECL(std::uint32_t) keylen() const; + + /// + /// Return the type. + /// + /// @exception bsoncxx::v1::exception with @ref bsoncxx::v1::error::element::view::invalid_view if this element is + /// invalid. + /// + BSONCXX_ABI_EXPORT_CDECL(v1::types::id) type_id() const; + + /// + /// Return the key. + /// + /// @exception bsoncxx::v1::exception with @ref bsoncxx::v1::error::element::view::invalid_view if this element is + /// invalid. + /// + BSONCXX_ABI_EXPORT_CDECL(v1::stdx::string_view) key() const; + +#pragma push_macro("X") +#undef X +#define X(_name, _value) BSONCXX_ABI_EXPORT_CDECL(v1::types::b_##_name) get_##_name() const; + + /// + /// Return the underlying BSON type value. + /// + /// @exception bsoncxx::v1::exception with @ref bsoncxx::v1::error::element::view::invalid_view if this element is + /// invalid. + /// @exception bsoncxx::v1::exception with @ref bsoncxx::v1::error::types::view::type_mismatch if the BSON type + /// value does not match the requested type. + /// + /// @{ + BSONCXX_V1_TYPES_XMACRO(X) + /// @} + /// +#pragma pop_macro("X") + + /// + /// Return a view of the underlying BSON type value. + /// + /// @exception bsoncxx::v1::exception with @ref bsoncxx::v1::error::element::view::invalid_view if this element is + /// invalid. + /// + BSONCXX_ABI_EXPORT_CDECL(v1::types::view) type_view() const; + + /// + /// Return a deep copy of the underlying BSON type value. + /// + /// @exception bsoncxx::v1::exception with @ref bsoncxx::v1::error::element::view::invalid_view if this element is + /// invalid. + /// + BSONCXX_ABI_EXPORT_CDECL(v1::types::value) type_value() const; + + /// + /// Return an element representing the requested field. + /// + /// @returns An invalid element if the requested field does not exist. + /// + /// @exception bsoncxx::v1::exception with @ref bsoncxx::v1::error::element::view::invalid_data if this operation + /// failed due to invalid BSON binary data. + /// + /// @{ + BSONCXX_ABI_EXPORT_CDECL(v1::element::view) operator[](v1::stdx::string_view key) const; + BSONCXX_ABI_EXPORT_CDECL(v1::element::view) operator[](std::uint32_t idx) const; + /// @} + /// + + /// + /// Compare equal when `lhs` and `rhs` represent the same field within the same BSON binary data. + /// + /// An invalid element only compares equal to another invalid element. The underlying BSON binary data (if any) is + /// ignored for an invalid element. + /// + friend bool operator==(view const& lhs, view const& rhs) { + if (!lhs != !rhs) { + return false; + } + + return !lhs || (lhs.raw() == rhs.raw() && lhs.offset() == rhs.offset()); + } + + /// + /// Equivalent to `!(lhs == rhs)`. + /// + friend bool operator!=(view const& lhs, view const& rhs) { + return !(lhs == rhs); + } + + class internal; + + private: + explicit view(impl i); +}; } // namespace element } // namespace v1 diff --git a/src/bsoncxx/include/bsoncxx/v1/exception-fwd.hpp b/src/bsoncxx/include/bsoncxx/v1/exception-fwd.hpp index 44c105e0a4..c393252d47 100644 --- a/src/bsoncxx/include/bsoncxx/v1/exception-fwd.hpp +++ b/src/bsoncxx/include/bsoncxx/v1/exception-fwd.hpp @@ -16,6 +16,8 @@ #include +#include + namespace bsoncxx { namespace v1 { namespace error { @@ -31,7 +33,7 @@ enum class type; namespace bsoncxx { namespace v1 { -class exception; +class BSONCXX_ABI_EXPORT exception; } // namespace v1 } // namespace bsoncxx diff --git a/src/bsoncxx/include/bsoncxx/v1/exception.hpp b/src/bsoncxx/include/bsoncxx/v1/exception.hpp index ad2fbd0a51..47a9f9b9d4 100644 --- a/src/bsoncxx/include/bsoncxx/v1/exception.hpp +++ b/src/bsoncxx/include/bsoncxx/v1/exception.hpp @@ -20,10 +20,46 @@ #include +#include +#include + #include +#include + +namespace bsoncxx { +namespace v1 { +namespace error { + +/// +/// Declares error categories for error codes and error conditions declared in @ref bsoncxx::v1::error. +/// +namespace category { + +/// +/// The error category for @ref bsoncxx::v1::error::source. +/// +/// @attention This feature is experimental! It is not ready for use! +/// +BSONCXX_ABI_EXPORT_CDECL(std::error_category const&) source(); + +/// +/// The error category for @ref bsoncxx::v1::error::type. +/// +/// @attention This feature is experimental! It is not ready for use! +/// +BSONCXX_ABI_EXPORT_CDECL(std::error_category const&) type(); + +} // namespace category +} // namespace error +} // namespace v1 +} // namespace bsoncxx namespace bsoncxx { namespace v1 { + +/// +/// Declares error codes and error conditions returned by @ref bsoncxx::v1 interfaces. +/// namespace error { /// @@ -31,28 +67,83 @@ namespace error { /// /// @attention This feature is experimental! It is not ready for use! /// -enum class source {}; +enum class source { + zero, ///< Zero. + bsoncxx, ///< From the bsoncxx library. + bson, ///< From the bson library. +}; + +/// +/// Support implicit conversion to `std::error_condition`. +/// +/// @attention This feature is experimental! It is not ready for use! +/// +inline std::error_condition make_error_condition(source code) { + return {static_cast(code), v1::error::category::source()}; +} /// /// Enumeration identifying the type (cause) of a @ref bsoncxx::v1 error. /// /// @attention This feature is experimental! It is not ready for use! /// -enum class type {}; +enum class type { + zero, ///< Zero. + invalid_argument, ///< An invalid argument passed to the throwing function. + runtime_error, ///< An erroneous condition was detected at runtime. +}; + +/// +/// Support implicit conversion to `std::error_condition`. +/// +/// @attention This feature is experimental! It is not ready for use! +/// +inline std::error_condition make_error_condition(type code) { + return {static_cast(code), v1::error::category::type()}; +} } // namespace error } // namespace v1 } // namespace bsoncxx +namespace std { + +template <> +struct is_error_condition_enum : true_type {}; + +template <> +struct is_error_condition_enum : true_type {}; + +} // namespace std + namespace bsoncxx { namespace v1 { +BSONCXX_PRIVATE_WARNINGS_PUSH(); +BSONCXX_PRIVATE_WARNINGS_DISABLE(MSVC(4251)); +BSONCXX_PRIVATE_WARNINGS_DISABLE(MSVC(4275)); + /// /// Base class for all exceptions thrown by @ref bsoncxx::v1. /// +/// @par Inherits: +/// - `std::system_error` +/// /// @attention This feature is experimental! It is not ready for use! /// -class exception {}; +class exception : public std::system_error { + public: + ~exception() override; + + exception(exception&&) = default; + exception& operator=(exception&&) = default; + exception(exception const&) = default; + exception& operator=(exception const&) = default; + + using std::system_error::system_error; +}; + +BSONCXX_PRIVATE_WARNINGS_POP(); } // namespace v1 } // namespace bsoncxx diff --git a/src/bsoncxx/include/bsoncxx/v1/oid.hpp b/src/bsoncxx/include/bsoncxx/v1/oid.hpp index 02c24211de..79ab8b4c3c 100644 --- a/src/bsoncxx/include/bsoncxx/v1/oid.hpp +++ b/src/bsoncxx/include/bsoncxx/v1/oid.hpp @@ -20,6 +20,71 @@ #include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace bsoncxx { +namespace v1 { +namespace error { +namespace category { + +/// +/// The error category for @ref bsoncxx::v1::error::oid. +/// +/// @attention This feature is experimental! It is not ready for use! +/// +BSONCXX_ABI_EXPORT_CDECL(std::error_category const&) oid(); + +} // namespace category +} // namespace error +} // namespace v1 +} // namespace bsoncxx + +namespace bsoncxx { +namespace v1 { +namespace error { + +/// +/// Errors codes may be returned by @ref bsoncxx::v1::oid. +/// +/// @attention This feature is experimental! It is not ready for use! +/// +enum class oid { + zero, ///< Zero. + null_bytes_ptr, ///< Bytes pointer must not be null. + invalid_length, ///< Byte length must equal @ref bsoncxx::v1::oid::k_oid_length. + empty_string, ///< String must not be empty. + invalid_string, ///< String is not a valid ObjectID representation. +}; + +/// +/// Support implicit conversion to `std::error_code`. +/// +/// @attention This feature is experimental! It is not ready for use! +/// +inline std::error_code make_error_code(oid v) { + return {static_cast(v), v1::error::category::oid()}; +} + +} // namespace error +} // namespace v1 +} // namespace bsoncxx + +namespace std { + +template <> +struct is_error_code_enum : true_type {}; + +} // namespace std + namespace bsoncxx { namespace v1 { @@ -28,7 +93,125 @@ namespace v1 { /// /// @attention This feature is experimental! It is not ready for use! /// -class oid {}; +class oid { + public: + /// + /// The number of bytes required to represent an ObjectID. + /// + static constexpr BSONCXX_ABI_EXPORT std::size_t k_oid_length = 12; + + private: + std::array _bytes; + + public: + /// + /// Initialize with a unique ObjectID. + /// + /// The ObjectID is generated using the bson library's + /// [`bson_oid_init`](https://mongoc.org/libbson/current/bson_oid_init.html) function with the default + /// [`bson_context_t`](https://mongoc.org/libbson/current/bson_context_t.html). + /// + /// @throws bsoncxx::v1::exception (on Windows only) with a `std::system_category()` error code + /// (as returned by + /// [`WSAGetLastError()`](https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-wsagetlasterror)) + /// on failure to initialize the Winsock library with + /// [`WSAStartup()`](https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-wsastartup). + /// + BSONCXX_ABI_EXPORT_CDECL() oid(); + + /// + /// Initialize with the given ObjectID byte representation. + /// + /// @param bytes A pointer to the ObjectID byte representation. + /// @param len The length of the array pointed to by `bytes`. + /// + /// @throws bsoncxx::v1::exception with @ref bsoncxx::v1::error::oid::null_bytes_ptr if `bytes` is null. + /// @throws bsoncxx::v1::exception with @ref bsoncxx::v1::error::oid::invalid_length if `len` is not equal to @ref + /// k_oid_length. + /// + BSONCXX_ABI_EXPORT_CDECL() oid(std::uint8_t const* bytes, std::size_t len); + + /// + /// Initialize with the given ObjectID hexadecimal string representation. + /// + /// @param str A valid ObjectID represented. + /// + /// @throws bsoncxx::v1::exception with @ref bsoncxx::v1::error::oid::empty_string if `str` is empty. + /// @throws bsoncxx::v1::exception with @ref bsoncxx::v1::error::oid::invalid_string if `str` is invalid. + /// + explicit BSONCXX_ABI_EXPORT_CDECL() oid(v1::stdx::string_view str); + + /// + /// Return @ref k_oid_length. + /// + std::size_t size() const { + return k_oid_length; + } + + /// + /// Return a pointer to the byte representation. + /// + std::uint8_t const* bytes() const { + return _bytes.data(); + } + + /// + /// Return the hexadecimal representation. + /// + BSONCXX_ABI_EXPORT_CDECL(std::string) to_string() const; + + /// + /// Return the timestamp component. + /// + BSONCXX_ABI_EXPORT_CDECL(std::time_t) get_time_t() const; + + /// + /// Equivalent to [`bson_oid_compare`](https://mongoc.org/libbson/current/bson_oid_compare.html). + /// + BSONCXX_ABI_EXPORT_CDECL(int) compare(oid const& other) const; + + /// + /// Equivalent to `lhs.compare(rhs) == 0`. + /// + friend bool operator==(oid const& lhs, oid const& rhs) { + return lhs.compare(rhs) == 0; + } + + /// + /// Equivalent to `lhs.compare(rhs) != 0`. + /// + friend bool operator!=(oid const& lhs, oid const& rhs) { + return lhs.compare(rhs) != 0; + } + + /// + /// Equivalent to `lhs.compare(rhs) < 0`. + /// + friend bool operator<(oid const& lhs, oid const& rhs) { + return lhs.compare(rhs) < 0; + } + + /// + /// Equivalent to `lhs.compare(rhs) <= 0`. + /// + friend bool operator<=(oid const& lhs, oid const& rhs) { + return lhs.compare(rhs) <= 0; + } + + /// + /// Equivalent to `lhs.compare(rhs) > 0`. + /// + friend bool operator>(oid const& lhs, oid const& rhs) { + return lhs.compare(rhs) > 0; + } + + /// + /// Equivalent to `lhs.compare(rhs) >= 0`. + /// + friend bool operator>=(oid const& lhs, oid const& rhs) { + return lhs.compare(rhs) >= 0; + } +}; } // namespace v1 } // namespace bsoncxx diff --git a/src/bsoncxx/include/bsoncxx/v1/types/id.hpp b/src/bsoncxx/include/bsoncxx/v1/types/id.hpp index 89a43808e5..67838113df 100644 --- a/src/bsoncxx/include/bsoncxx/v1/types/id.hpp +++ b/src/bsoncxx/include/bsoncxx/v1/types/id.hpp @@ -20,6 +20,10 @@ #include +#include + +#include + namespace bsoncxx { namespace v1 { namespace types { @@ -31,7 +35,36 @@ namespace types { /// /// @showenumvalues /// -enum class id : std::uint8_t {}; +enum class id : std::uint8_t { + k_double = 0x01, ///< 64-bit binary floating point. + k_string = 0x02, ///< UTF-8 string. + k_document = 0x03, ///< Embedded document. + k_array = 0x04, ///< Array. + k_binary = 0x05, ///< Binary data. + k_undefined = 0x06, ///< Undefined value. @deprecated + k_oid = 0x07, ///< ObjectId. + k_bool = 0x08, ///< Boolean. + k_date = 0x09, ///< UTC datetime. + k_null = 0x0A, ///< Null value. + k_regex = 0x0B, ///< Regular expression. + k_dbpointer = 0x0C, ///< DBPointer. @deprecated + k_code = 0x0D, ///< JavaScript code. + k_symbol = 0x0E, ///< Symbol. @deprecated + k_codewscope = 0x0F, ///< JavaScript code with scope. @deprecated + k_int32 = 0x10, ///< 32-bit integer. + k_timestamp = 0x11, ///< Timestamp. + k_int64 = 0x12, ///< 64-bit integer. + k_decimal128 = 0x13, ///< 128-bit decimal floating point. + k_maxkey = 0x7F, ///< Min key. + k_minkey = 0xFF, ///< Max key. +}; + +/// +/// Return the name of the enumerator (e.g. `"double"` given `k_double`). +/// +/// @attention This feature is experimental! It is not ready for use! +/// +BSONCXX_ABI_EXPORT_CDECL(std::string) to_string(id rhs); /// /// Enumeration identifying a BSON binary subtype. @@ -40,7 +73,26 @@ enum class id : std::uint8_t {}; /// /// @showenumvalues /// -enum class binary_subtype : std::uint8_t {}; +enum class binary_subtype : std::uint8_t { + k_binary = 0x00, ///< Generic binary subtype. + k_function = 0x01, ///< Function. + k_binary_deprecated = 0x02, ///< Binary (Old). @deprecated + k_uuid_deprecated = 0x03, ///< UUID (Old). @deprecated + k_uuid = 0x04, ///< UUID. + k_md5 = 0x05, ///< MD5. + k_encrypted = 0x06, ///< Encrypted BSON value. + k_column = 0x07, ///< Compressed BSON column. + k_sensitive = 0x08, ///< Sensitive. + k_vector = 0x09, ///< Vector. + k_user = 0x80, ///< User defined. +}; + +/// +/// Return the name of the enumerator (e.g. `"binary"` given `k_binary`). +/// +/// @attention This feature is experimental! It is not ready for use! +/// +BSONCXX_ABI_EXPORT_CDECL(std::string) to_string(binary_subtype rhs); } // namespace types } // namespace v1 diff --git a/src/bsoncxx/include/bsoncxx/v1/types/value.hpp b/src/bsoncxx/include/bsoncxx/v1/types/value.hpp index fe5fe54126..21b6d5bf11 100644 --- a/src/bsoncxx/include/bsoncxx/v1/types/value.hpp +++ b/src/bsoncxx/include/bsoncxx/v1/types/value.hpp @@ -20,6 +20,89 @@ #include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace bsoncxx { +namespace v1 { +namespace error { +namespace category { + +/// +/// Declares error categories for error codes declared in @ref bsoncxx::v1::error::types. +/// +namespace types { + +/// +/// The error category for @ref bsoncxx::v1::error::types::value. +/// +/// @attention This feature is experimental! It is not ready for use! +/// +BSONCXX_ABI_EXPORT_CDECL(std::error_category const&) value(); + +} // namespace types +} // namespace category +} // namespace error +} // namespace v1 +} // namespace bsoncxx + +namespace bsoncxx { +namespace v1 { +namespace error { + +/// +/// Declares error codes returned by @ref bsoncxx::v1::types interfaces. +/// +namespace types { + +/// +/// Errors codes which may be returned by @ref bsoncxx::v1::types::value. +/// +/// @attention This feature is experimental! It is not ready for use! +/// +enum class value { + zero, ///< Zero. + invalid_type, ///< Requested BSON type is not supported. + invalid_length_u32, ///< Length is too long (exceeds `UINT32_MAX`). +}; + +/// +/// Support implicit conversion to `std::error_code`. +/// +/// @attention This feature is experimental! It is not ready for use! +/// +inline std::error_code make_error_code(value v) { + return {static_cast(v), v1::error::category::types::value()}; +} + +} // namespace types +} // namespace error +} // namespace v1 +} // namespace bsoncxx + +namespace std { + +template <> +struct is_error_code_enum : true_type {}; + +} // namespace std + namespace bsoncxx { namespace v1 { namespace types { @@ -31,7 +114,249 @@ namespace types { /// /// @note A "BSON type value" refers to the value of a BSON element without its key. /// -class value {}; +class value { + private: + class impl; + + alignas(BSONCXX_PRIVATE_MAX_ALIGN_T) unsigned char _storage[32]; + + public: + /// + /// Destroy this object. + /// + BSONCXX_ABI_EXPORT_CDECL() ~value(); + + /// + /// Move construction. + /// + /// @par Postconditions: + /// - `other` is equivalent to a default-initialized value. + /// + BSONCXX_ABI_EXPORT_CDECL() value(value&& other) noexcept; + + /// + /// Move assignment. + /// + /// @par Postconditions: + /// - `other` is equivalent to a default-initialized value. + /// + BSONCXX_ABI_EXPORT_CDECL(value&) operator=(value&& other) noexcept; + + /// + /// Copy construction. + /// + /// The copied BSON type value is allocated (when necessary) using + /// [`bson_value_copy`](https://mongoc.org/libbson/current/bson_value_copy.html). + /// + BSONCXX_ABI_EXPORT_CDECL() value(value const& other); + + /// + /// Copy assignment. + /// + /// The copied value is allocated (when necessary) using + /// [`bson_value_copy`](https://mongoc.org/libbson/current/bson_value_copy.html). + /// + BSONCXX_ABI_EXPORT_CDECL(value&) operator=(value const& other); + + /// + /// Initialize with @ref bsoncxx::v1::types::b_null. + /// + value() : value{v1::types::b_null{}} {} + + /// + /// Initialize with a deep copy of the underlying BSON type value. + /// + /// The copied value is allocated (when necessary) using + /// [`bson_malloc`](https://mongoc.org/libbson/current/bson_malloc.html). + /// + /// @exception bsoncxx::v1::exception with @ref bsoncxx::v1::error::types::value::invalid_type if `v.type_id()` is + /// not a supported value (not defined by @ref BSONCXX_V1_TYPES_XMACRO). + /// @exception bsoncxx::v1::exception with @ref bsoncxx::v1::error::types::value::invalid_length_u32 if the length + /// of any underlying BSON type value component is not representable as an `std::uint32_t`. + /// + explicit BSONCXX_ABI_EXPORT_CDECL() value(v1::types::view const& v); + +#pragma push_macro("X") +#undef X +#define X(_name, _value) explicit BSONCXX_ABI_EXPORT_CDECL() value(v1::types::b_##_name v); + + /// + /// Implicitly convert `v` as a deep copy. + /// + /// The copied value is allocated (when necessary) using + /// [`bson_malloc`](https://mongoc.org/libbson/current/bson_malloc.html). + /// + /// @exception bsoncxx::v1::exception with @ref bsoncxx::v1::error::types::value::invalid_length_u32 if the length + /// of any underlying BSON type value component is not representable as an `std::uint32_t` as required by the + /// corresponding `bsoncxx::v1::types::b_`. + /// + /// @{ + BSONCXX_V1_TYPES_XMACRO(X) + /// @} + /// +#pragma pop_macro("X") + + /// + /// Initialize as a @ref bsoncxx::v1::types::b_null. + /// + explicit value(std::nullptr_t) : value{v1::types::b_null{}} {} + + /// + /// Initialize as a @ref bsoncxx::v1::types::b_string. + /// + explicit value(v1::stdx::string_view v) : value{v1::types::b_string{v}} {} + + /// + /// Initialize as a @ref bsoncxx::v1::types::b_int32. + /// + explicit value(std::int32_t v) : value{v1::types::b_int32{v}} {} + + /// + /// Initialize as a @ref bsoncxx::v1::types::b_int64. + /// + explicit value(std::int64_t v) : value{v1::types::b_int64{v}} {} + + /// + /// Initialize as a @ref bsoncxx::v1::types::b_double. + /// + explicit value(double v) : value{v1::types::b_double{v}} {} + + /// + /// Initialize as a @ref bsoncxx::v1::types::b_bool. + /// + explicit value(bool v) : value{v1::types::b_bool{v}} {} + + /// + /// Initialize as a @ref bsoncxx::v1::types::b_oid. + /// + explicit value(v1::oid v) : value{v1::types::b_oid{v}} {} + + /// + /// Initialize as a @ref bsoncxx::v1::types::b_decimal128. + /// + explicit value(v1::decimal128 v) : value{v1::types::b_decimal128{v}} {} + + /// + /// Initialize as a @ref bsoncxx::v1::types::b_date. + /// + explicit value(std::chrono::milliseconds v) : value{v1::types::b_date{v}} {} + + /// + /// Initialize as a @ref bsoncxx::v1::types::b_document. + /// + explicit value(v1::document::view v) : value{v1::types::b_document{v}} {} + + /// + /// Initialize as a @ref bsoncxx::v1::types::b_array. + /// + explicit value(v1::array::view v) : value{v1::types::b_array{v}} {} + + /// + /// Initialize as a @ref bsoncxx::v1::types::b_binary with @ref + /// bsoncxx::v1::types::binary_subtype::k_binary. + /// + explicit value(std::vector const& v) + : value{v.data(), v.size(), v1::types::binary_subtype::k_binary} {} + + /// + /// Initialize with `v` as a @ref bsoncxx::v1::types::b_binary with `subtype`. + /// + explicit value(std::vector const& v, v1::types::binary_subtype subtype) + : value{v.data(), v.size(), subtype} {} + + /// + /// Initialize as a @ref bsoncxx::v1::types::b_dbpointer. + /// + explicit value(v1::stdx::string_view c, v1::oid v) : value{v1::types::b_dbpointer{c, v}} {} + + /// + /// Initialize as a @ref bsoncxx::v1::types::b_codewscope. + /// + explicit value(v1::stdx::string_view code, v1::document::view scope) + : value{v1::types::b_codewscope{code, scope}} {} + + /// + /// Initialize as a @ref bsoncxx::v1::types::b_regex. + /// + explicit value(v1::stdx::string_view regex, v1::stdx::string_view options) + : value{v1::types::b_regex{regex, options}} {} + + /// + /// Initialize as a @ref bsoncxx::v1::types::b_string. + /// + explicit value(char const* v) : value{v1::stdx::string_view{v}} {} + + /// + /// Initialize as a @ref bsoncxx::v1::types::b_string. + /// + explicit value(std::string const& v) : value{v1::stdx::string_view{v}} {} + + /// + /// Initialize as a @ref bsoncxx::v1::types::b_binary with @ref + /// bsoncxx::v1::types::binary_subtype::k_binary. + /// + explicit value(std::uint8_t const* data, std::size_t size) + : value{data, size, v1::types::binary_subtype::k_binary} {} + + /// + /// Initialize as a @ref bsoncxx::v1::types::b_binary with `subtype`. + /// + explicit BSONCXX_ABI_EXPORT_CDECL() + value(std::uint8_t const* data, std::size_t size, v1::types::binary_subtype const sub_type); + + /// + /// Return the type of the underlying BSON type value. + /// + BSONCXX_ABI_EXPORT_CDECL(v1::types::id) type_id() const; + + /// + /// Return a view of the underlying BSON type value. + /// + BSONCXX_ABI_EXPORT_CDECL(v1::types::view) view() const; + + /// + /// Implicitly convert to `this->view()`. + /// + /* explicit(false) */ operator v1::types::view() const { + return this->view(); + } + +#pragma push_macro("X") +#undef X +#define X(_name, _value) \ + v1::types::b_##_name get_##_name() const { \ + return this->view().get_##_name(); \ + } + + /// + /// Equivalent to `this->view().get_type()` where `get_type` is the correct name for the requested BSON type value + /// (e.g. `this->view().get_double()` given `this->get_double()`). + /// + /// @exception bsoncxx::v1::exception with @ref bsoncxx::v1::error::types::view::type_mismatch if the underlying + /// BSON type value does not match the requested type. + /// + /// @{ + BSONCXX_V1_TYPES_XMACRO(X) + /// @} + /// +#pragma pop_macro("X") + + /// + /// Equivalent to `lhs.view() == rhs.view()`. + /// + friend bool operator==(value const& lhs, value const& rhs) { + return lhs.view() == rhs.view(); + } + + /// + /// Equivalent to `!(lhs == rhs)`. + /// + friend bool operator!=(value const& lhs, value const& rhs) { + return !(lhs == rhs); + } + + class internal; +}; } // namespace types } // namespace v1 @@ -44,3 +369,6 @@ class value {}; /// @file /// Provides @ref bsoncxx::v1::types::value. /// +/// @par Includes +/// - @ref bsoncxx/v1/types/view.hpp +/// diff --git a/src/bsoncxx/include/bsoncxx/v1/types/view.hpp b/src/bsoncxx/include/bsoncxx/v1/types/view.hpp index 5ceabc143b..c514736f5b 100644 --- a/src/bsoncxx/include/bsoncxx/v1/types/view.hpp +++ b/src/bsoncxx/include/bsoncxx/v1/types/view.hpp @@ -20,156 +20,1052 @@ #include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace bsoncxx { +namespace v1 { +namespace error { +namespace category { + +/// +/// Declares error categories for error codes declared in @ref bsoncxx::v1::error::types. +/// +namespace types { + +/// +/// The error category for @ref bsoncxx::v1::error::types::view. +/// +/// @attention This feature is experimental! It is not ready for use! +/// +BSONCXX_ABI_EXPORT_CDECL(std::error_category const&) view(); + +} // namespace types +} // namespace category +} // namespace error +} // namespace v1 +} // namespace bsoncxx + +namespace bsoncxx { +namespace v1 { +namespace error { + +/// +/// Declares error codes returned by @ref bsoncxx::v1::types interfaces. +/// +namespace types { + +/// +/// Errors codes which may be returned by @ref bsoncxx::v1::types::view. +/// +/// @attention This feature is experimental! It is not ready for use! +/// +enum class view { + zero, ///< Zero. + type_mismatch, ///< Requested type does not match the underlying type. +}; + +/// +/// Support implicit conversion to `std::error_code`. +/// +/// @attention This feature is experimental! It is not ready for use! +/// +inline std::error_code make_error_code(view v) { + return {static_cast(v), v1::error::category::types::view()}; +} + +} // namespace types +} // namespace error +} // namespace v1 +} // namespace bsoncxx + +namespace std { + +template <> +struct is_error_code_enum : true_type {}; + +} // namespace std + namespace bsoncxx { namespace v1 { namespace types { +// BSONCXX_V1_TYPES_XMACRO: update below. + /// /// BSON type value "64-bit Binary Floating Point". /// /// @attention This feature is experimental! It is not ready for use! /// -struct b_double {}; +struct b_double { + /// + /// The type represented by this BSON type value. + /// + static constexpr BSONCXX_ABI_EXPORT id type_id = id::k_double; + + /// + /// The represented value. + /// + double value = {}; + + /// + /// Zero-initialize the represented value. + /// + b_double() = default; + + /// + /// Initialize with `value`. + /// + explicit b_double(double value) : value{value} {} + + /// + /// Implicitly convert to @ref value. + /// + /* explicit(false) */ operator double() const { + return value; + } + + /// + /// Equivalent to `lhs.value == rhs.value`. + /// + friend 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(); + } + + /// + /// Equivalent to `!(lhs == rhs)`. + /// + friend bool operator!=(b_double const& lhs, b_double const& rhs) { + return !(lhs == rhs); + } +}; /// /// BSON type value "UTF-8 String". /// /// @attention This feature is experimental! It is not ready for use! /// -struct b_string {}; +struct b_string { + /// + /// The type represented by this BSON type value. + /// + static constexpr BSONCXX_ABI_EXPORT id type_id = id::k_string; + + /// + /// The represented value. + /// + v1::stdx::string_view value; + + /// + /// Zero-initialize the represented value. + /// + b_string() = default; + + /// + /// Initialize with `value`. + /// + explicit b_string(v1::stdx::string_view value) : value{value} {} + + /// + /// Implicitly convert to @ref value. + /// + /* explicit(false) */ operator v1::stdx::string_view() const { + return value; + } + + /// + /// Equivalent to `lhs.value == rhs.value`. + /// + friend bool operator==(b_string const& lhs, b_string const& rhs) { + return lhs.value == rhs.value; + } + + /// + /// Equivalent to `!(lhs == rhs)`. + /// + friend bool operator!=(b_string const& lhs, b_string const& rhs) { + return !(lhs == rhs); + } +}; /// /// BSON type value "Embedded Document". /// /// @attention This feature is experimental! It is not ready for use! /// -struct b_document {}; +struct b_document { + /// + /// The type represented by this BSON type value. + /// + static constexpr BSONCXX_ABI_EXPORT id type_id = id::k_document; + + /// + /// The represented value. + /// + v1::document::view value; + + /// + /// Zero-initialize the represented value. + /// + b_document() = default; + + /// + /// Initialize with `value`. + /// + explicit b_document(v1::document::view value) : value{value} {} + + /// + /// Implicitly convert to @ref value. + /// + /* explicit(false) */ operator v1::document::view() const { + return value; + } + + v1::document::view view() { + return value; + } + + /// + /// Equivalent to `lhs.value == rhs.value`. + /// + friend bool operator==(b_document const& lhs, b_document const& rhs) { + return lhs.value == rhs.value; + } + + /// + /// Equivalent to `!(lhs == rhs)`. + /// + friend bool operator!=(b_document const& lhs, b_document const& rhs) { + return !(lhs == rhs); + } +}; /// /// BSON type value "Array". /// /// @attention This feature is experimental! It is not ready for use! /// -struct b_array {}; +struct b_array { + /// + /// The type represented by this BSON type value. + /// + static constexpr BSONCXX_ABI_EXPORT id type_id = id::k_array; + + /// + /// The represented value. + /// + v1::array::view value; + + /// + /// Zero-initialize the represented value. + /// + b_array() = default; + + /// + /// Initialize with `value`. + /// + explicit b_array(v1::array::view value) : value{value} {} + + /// + /// Implicitly convert to @ref value. + /// + /* explicit(false) */ operator v1::array::view() const { + return value; + } + + /// + /// Equivalent to `lhs.value == rhs.value`. + /// + friend bool operator==(b_array const& lhs, b_array const& rhs) { + return lhs.value == rhs.value; + } + + /// + /// Equivalent to `!(lhs == rhs)`. + /// + friend bool operator!=(b_array const& lhs, b_array const& rhs) { + return !(lhs == rhs); + } +}; /// /// BSON type value "Binary Data". /// /// @attention This feature is experimental! It is not ready for use! /// -struct b_binary {}; +struct b_binary { + /// + /// The type represented by this BSON type value. + /// + static constexpr BSONCXX_ABI_EXPORT id type_id = id::k_binary; + + /// + /// The represented value's binary subtype component. + /// + binary_subtype subtype = {}; + + /// + /// The represented value's length of binary data. + /// + std::uint32_t size = {}; + + /// + /// The represented value's binary data. + /// + std::uint8_t const* bytes = {}; + + /// + /// Zero-initialize the represented value. + /// + b_binary() = default; + + /// + /// Initialize with the given binary subtype and pointer to binary data. + /// + b_binary(binary_subtype subtype, std::uint32_t size, std::uint8_t const* bytes) + : subtype{subtype}, size{size}, bytes{bytes} {} + + /// + /// Compare equal when the binary subtype and pointed-to bytes compare equal. + /// + /// An "empty" range of bytes (when @ref bytes is null or @ref size is zero) only compares equal to another + /// "empty" range of bytes. The value of @ref subtype is ignored for an empty range of bytes. + /// + /// @{ + friend bool operator==(b_binary const& lhs, b_binary const& rhs) { + if (lhs.size != rhs.size) { + return false; + } + + if (!lhs.bytes != !rhs.bytes) { + return false; + } + + if (!lhs.bytes || lhs.size == 0u) { + return true; // Empty. + } + + return lhs.subtype == rhs.subtype && (std::memcmp(lhs.bytes, rhs.bytes, lhs.size) == 0); + } + + friend bool operator!=(b_binary const& lhs, b_binary const& rhs) { + return !(lhs == rhs); + } + /// @} + /// +}; /// /// BSON type value "Undefined (Value)". /// +/// @deprecated This BSON type is deprecated. +/// /// @attention This feature is experimental! It is not ready for use! /// -struct b_undefined {}; +struct b_undefined { + /// + /// The type represented by this BSON type value. + /// + static constexpr BSONCXX_ABI_EXPORT id type_id = id::k_undefined; + + /// + /// Return true. + /// + friend bool operator==(b_undefined const&, b_undefined const&) { + return true; + } + + /// + /// Return false. + /// + friend bool operator!=(b_undefined const& lhs, b_undefined const& rhs) { + return !(lhs == rhs); + } +}; /// /// BSON type value "ObjectID". /// /// @attention This feature is experimental! It is not ready for use! /// -struct b_oid {}; +struct b_oid { + /// + /// The type represented by this BSON type value. + /// + static constexpr BSONCXX_ABI_EXPORT id type_id = id::k_oid; + + /// + /// The represented value. + /// + v1::oid value; + + /// + /// Zero-initialize the represented value. + /// + b_oid() = default; + + /// + /// Initialize with `value`. + /// + explicit b_oid(v1::oid const& value) : value{value} {} + + /// + /// Implicitly convert to @ref value. + /// + /* explicit(false) */ operator v1::oid() const { + return value; + } + + /// + /// Equivalent to `lhs.value == rhs.value`. + /// + friend bool operator==(b_oid const& lhs, b_oid const& rhs) { + return lhs.value == rhs.value; + } + + /// + /// Equivalent to `!(lhs == rhs)`. + /// + friend bool operator!=(b_oid const& lhs, b_oid const& rhs) { + return !(lhs == rhs); + } +}; /// /// BSON type value "Boolean". /// /// @attention This feature is experimental! It is not ready for use! /// -struct b_bool {}; +struct b_bool { + /// + /// The type represented by this BSON type value. + /// + static constexpr BSONCXX_ABI_EXPORT id type_id = id::k_bool; + + /// + /// The represented value. + /// + bool value = false; + + /// + /// Zero-initialize the represented value. + /// + b_bool() = default; + + /// + /// Initialize with `value`. + /// + explicit b_bool(bool value) : value{value} {} + + /// + /// Implicitly convert to @ref value. + /// + /* explicit(false) */ operator bool() const { + return value; + } + + /// + /// Equivalent to `lhs.value == rhs.value`. + /// + friend bool operator==(b_bool const& lhs, b_bool const& rhs) { + return lhs.value == rhs.value; + } + + /// + /// Equivalent to `!(lhs == rhs)`. + /// + friend bool operator!=(b_bool const& lhs, b_bool const& rhs) { + return !(lhs == rhs); + } +}; /// /// BSON type value "UTC Datetime". /// /// @attention This feature is experimental! It is not ready for use! /// -struct b_date {}; +struct b_date { + /// + /// The type represented by this BSON type value. + /// + static constexpr BSONCXX_ABI_EXPORT id type_id = id::k_date; + + /// + /// The represented value (milliseconds relative to the Unix epoch). + /// + std::chrono::milliseconds value = {}; + + /// + /// Zero-initialize the represented value. + /// + b_date() = default; + + /// + /// Initialize with `value` (milliseconds relative to the Unix epoch). + /// + explicit b_date(std::chrono::milliseconds value) : value{value} {} + + /// + /// Initialize with `tp` (assuming the epoch of `std::chrono::system_clock` is the Unix epoch). + /// + explicit b_date(std::chrono::system_clock::time_point tp) + : value{std::chrono::duration_cast(tp.time_since_epoch())} {} + + /// + /// Implicitly convert to @ref value. + /// + /* explicit(false) */ operator std::chrono::milliseconds() const { + return value; + } + + explicit operator std::chrono::system_clock::time_point() const { + return std::chrono::system_clock::time_point( + std::chrono::duration_cast(value)); + } + + /// + /// Equivalent to `lhs.value == rhs.value`. + /// + friend bool operator==(b_date const& lhs, b_date const& rhs) { + return lhs.value == rhs.value; + } + + /// + /// Equivalent to `!(lhs == rhs)`. + /// + friend bool operator!=(b_date const& lhs, b_date const& rhs) { + return !(lhs == rhs); + } +}; /// /// BSON type value "Null Value". /// /// @attention This feature is experimental! It is not ready for use! /// -struct b_null {}; +struct b_null { + /// + /// The type represented by this BSON type value. + /// + static constexpr BSONCXX_ABI_EXPORT id type_id = id::k_null; + + /// + /// Return true. + /// + friend bool operator==(b_null const& /* lhs */, b_null const& /* rhs */) { + return true; + } + + /// + /// Return false. + /// + friend bool operator!=(b_null const& lhs, b_null const& rhs) { + return !(lhs == rhs); + } +}; /// /// BSON type value "Regular Expression". /// /// @attention This feature is experimental! It is not ready for use! /// -struct b_regex {}; +struct b_regex { + /// + /// The type represented by this BSON type value. + /// + static constexpr BSONCXX_ABI_EXPORT id type_id = id::k_regex; + + /// + /// The represented value's "pattern" component. + /// + v1::stdx::string_view regex; + + /// + /// The represented value's "options" component. + /// + v1::stdx::string_view options; + + /// + /// Zero-initialize the represented value. + /// + b_regex() = default; + + /// + /// Initialize with `regex` and an empty @ref options. + /// + explicit b_regex(v1::stdx::string_view regex) : regex{regex}, options{} {} + + /// + /// Initialize with `regex` and `options`. + /// + b_regex(v1::stdx::string_view regex, v1::stdx::string_view options) : regex{regex}, options{options} {} + + /// + /// Equivalent to `lhs.regex == rhs.regex && lhs.options == rhs.options`. + /// + friend bool operator==(b_regex const& lhs, b_regex const& rhs) { + return lhs.regex == rhs.regex && lhs.options == rhs.options; + } + + /// + /// Equivalent to `!(lhs == rhs)`. + /// + friend bool operator!=(b_regex const& lhs, b_regex const& rhs) { + return !(lhs == rhs); + } +}; /// /// BSON type value "DBPointer". /// +/// @deprecated This BSON type is deprecated. +/// /// @attention This feature is experimental! It is not ready for use! /// -struct b_dbpointer {}; +struct b_dbpointer { + /// + /// The type represented by this BSON type value. + /// + static constexpr BSONCXX_ABI_EXPORT id type_id = id::k_dbpointer; + + /// + /// The represented value's "$ref" (namespace) component. + /// + v1::stdx::string_view collection; + + /// + /// The represented value's "$id" (ObjectID) component. + /// + v1::oid value; + + /// + /// Zero-initialize the represented value. + /// + b_dbpointer() = default; + + /// + /// Initialize with `collection` and `value`. + /// + b_dbpointer(v1::stdx::string_view collection, v1::oid value) : collection{collection}, value{value} {} + + /// + /// Equivalent to `lhs.collection == rhs.collection && lhs.value == rhs.value`. + /// + friend bool operator==(b_dbpointer const& lhs, b_dbpointer const& rhs) { + return lhs.collection == rhs.collection && lhs.value == rhs.value; + } + + /// + /// Equivalent to `!(lhs == rhs)`. + /// + friend bool operator!=(b_dbpointer const& lhs, b_dbpointer const& rhs) { + return !(lhs == rhs); + } +}; /// /// BSON type value "JavaScript Code". /// /// @attention This feature is experimental! It is not ready for use! /// -struct b_code {}; +struct b_code { + /// + /// The type represented by this BSON type value. + /// + static constexpr BSONCXX_ABI_EXPORT id type_id = id::k_code; + + /// + /// The represented value. + /// + v1::stdx::string_view code; + + /// + /// Zero-initialize the represented value. + /// + b_code() = default; + + /// + /// Initialize with `code`. + /// + explicit b_code(v1::stdx::string_view code) : code{code} {} + + /// + /// Implicitly convert to @ref code. + /// + /* explicit(false) */ operator v1::stdx::string_view() const { + return code; + } + + /// + /// Equivalent to `lhs.code == rhs.code`. + /// + friend bool operator==(b_code const& lhs, b_code const& rhs) { + return lhs.code == rhs.code; + } + + /// + /// Equivalent to `!(lhs == rhs)`. + /// + friend bool operator!=(b_code const& lhs, b_code const& rhs) { + return !(lhs == rhs); + } +}; /// /// BSON type value "Symbol". /// +/// @deprecated This BSON type is deprecated. +/// /// @attention This feature is experimental! It is not ready for use! /// -struct b_symbol {}; +struct b_symbol { + /// + /// The type represented by this BSON type value. + /// + static constexpr BSONCXX_ABI_EXPORT id type_id = id::k_symbol; + + /// + /// The represented value. + /// + v1::stdx::string_view symbol; + + /// + /// Zero-initialize the represented value. + /// + b_symbol() = default; + + /// + /// Initialize with `symbol`. + /// + explicit b_symbol(v1::stdx::string_view symbol) : symbol{symbol} {} + + /// + /// Implicitly convert to @ref symbol. + /// + /* explicit(false) */ operator v1::stdx::string_view() const { + return symbol; + } + + /// + /// Equivalent to `lhs.symbol == rhs.symbol`. + /// + friend bool operator==(b_symbol const& lhs, b_symbol const& rhs) { + return lhs.symbol == rhs.symbol; + } + + /// + /// Equivalent to `!(lhs == rhs)`. + /// + friend bool operator!=(b_symbol const& lhs, b_symbol const& rhs) { + return !(lhs == rhs); + } +}; /// /// BSON type value "JavaScript Code With Scope". /// +/// @deprecated This BSON type is deprecated. +/// /// @attention This feature is experimental! It is not ready for use! /// -struct b_codewscope {}; +struct b_codewscope { + /// + /// The type represented by this BSON type value. + /// + static constexpr BSONCXX_ABI_EXPORT id type_id = id::k_codewscope; + + /// + /// The represented value's "$code" component. + /// + v1::stdx::string_view code; + + /// + /// The represented value's "$scope" component. + /// + v1::document::view scope; + + /// + /// Zero-initialize the represented value. + /// + b_codewscope() = default; + + /// + /// Initialize with `code` and `scope`. + /// + b_codewscope(v1::stdx::string_view code, v1::document::view scope) : code{code}, scope{scope} {} + + /// + /// Equivalent to `lhs.code == rhs.code && lhs.scope == rhs.scope`. + /// + friend bool operator==(b_codewscope const& lhs, b_codewscope const& rhs) { + return lhs.code == rhs.code && lhs.scope == rhs.scope; + } + + /// + /// Equivalent to `!(lhs == rhs)`. + /// + friend bool operator!=(b_codewscope const& lhs, b_codewscope const& rhs) { + return !(lhs == rhs); + } +}; /// /// BSON type value "32-bit Integer". /// /// @attention This feature is experimental! It is not ready for use! /// -struct b_int32 {}; +struct b_int32 { + /// + /// The type represented by this BSON type value. + /// + static constexpr BSONCXX_ABI_EXPORT id type_id = id::k_int32; + + /// + /// The represented value. + /// + std::int32_t value = {}; + + /// + /// Zero-initialize the represented value. + /// + b_int32() = default; + + /// + /// Initialize with `value`. + /// + explicit b_int32(std::int32_t value) : value{value} {} + + /// + /// Implicitly convert to @ref value. + /// + /* explicit(false) */ operator std::int32_t() const { + return value; + } + + /// + /// Equivalent to `lhs.value == rhs.value`. + /// + friend bool operator==(b_int32 const& lhs, b_int32 const& rhs) { + return lhs.value == rhs.value; + } + + /// + /// Equivalent to `!(lhs == rhs)`. + /// + friend bool operator!=(b_int32 const& lhs, b_int32 const& rhs) { + return !(lhs == rhs); + } +}; /// /// BSON type value "Timestamp". /// /// @attention This feature is experimental! It is not ready for use! /// -struct b_timestamp {}; +struct b_timestamp { + /// + /// The type represented by this BSON type value. + /// + static constexpr BSONCXX_ABI_EXPORT id type_id = id::k_timestamp; + + /// + /// The represented value's "i" component. + /// + std::uint32_t increment = {}; + + /// + /// The represented value's "t" component. + /// + std::uint32_t timestamp = {}; + + /// + /// Zero-initialize the represented value. + /// + b_timestamp() = default; + + /// + /// Initialize with `increment` and `timestamp`. + /// + b_timestamp(std::uint32_t increment, std::uint32_t timestamp) : increment{increment}, timestamp{timestamp} {} + + /// + /// Equivalent to `lhs.timestamp == rhs.timestamp`. + /// + friend bool operator==(b_timestamp const& lhs, b_timestamp const& rhs) { + return lhs.timestamp == rhs.timestamp; + } + + /// + /// Equivalent to `!(lhs == rhs)`. + /// + friend bool operator!=(b_timestamp const& lhs, b_timestamp const& rhs) { + return !(lhs == rhs); + } +}; /// /// BSON type value "64-bit Integer". /// /// @attention This feature is experimental! It is not ready for use! /// -struct b_int64 {}; +struct b_int64 { + /// + /// The type represented by this BSON type value. + /// + static constexpr BSONCXX_ABI_EXPORT id type_id = id::k_int64; + + /// + /// The represented value. + /// + std::int64_t value = {}; + + /// + /// Zero-initialize the represented value. + /// + b_int64() = default; + + /// + /// Initialize with `value`. + /// + explicit b_int64(std::int64_t value) : value{value} {} + + /// + /// Implicitly convert to @ref value. + /// + /* explicit(false) */ operator std::int64_t() const { + return value; + } + + /// + /// Equivalent to `lhs.value == rhs.value`. + /// + friend bool operator==(b_int64 const& lhs, b_int64 const& rhs) { + return lhs.value == rhs.value; + } + + /// + /// Equivalent to `!(lhs == rhs)`. + /// + friend bool operator!=(b_int64 const& lhs, b_int64 const& rhs) { + return !(lhs == rhs); + } +}; /// /// BSON type value "Decimal128". /// /// @attention This feature is experimental! It is not ready for use! /// -struct b_decimal128 {}; +struct b_decimal128 { + /// + /// The type represented by this BSON type value. + /// + static constexpr BSONCXX_ABI_EXPORT id type_id = id::k_decimal128; + + /// + /// The represented value. + /// + v1::decimal128 value; + + /// + /// Zero-initialize the represented value. + /// + b_decimal128() = default; + + /// + /// Initialize with `value`. + /// + explicit b_decimal128(v1::decimal128 value) : value{value} {} + + /// + /// Implicitly convert to @ref value. + /// + /* explicit(false) */ operator v1::decimal128() const { + return value; + } + + /// + /// Equivalent to `lhs.value == rhs.value`. + /// + friend bool operator==(b_decimal128 const& lhs, b_decimal128 const& rhs) { + return lhs.value == rhs.value; + } + + /// + /// Equivalent to `!(lhs == rhs)`. + /// + friend bool operator!=(b_decimal128 const& lhs, b_decimal128 const& rhs) { + return !(lhs == rhs); + } +}; /// /// BSON type value "Max Key". /// /// @attention This feature is experimental! It is not ready for use! /// -struct b_maxkey {}; +struct b_maxkey { + /// + /// The type represented by this BSON type value. + /// + static constexpr BSONCXX_ABI_EXPORT id type_id = id::k_maxkey; + + /// + /// Return true. + /// + friend bool operator==(b_maxkey const&, b_maxkey const&) { + return true; + } + + /// + /// Return false. + /// + friend bool operator!=(b_maxkey const& lhs, b_maxkey const& rhs) { + return !(lhs == rhs); + } +}; /// /// BSON type value "Min Key". /// /// @attention This feature is experimental! It is not ready for use! /// -struct b_minkey {}; +struct b_minkey { + /// + /// The type represented by this BSON type value. + /// + static constexpr BSONCXX_ABI_EXPORT id type_id = id::k_minkey; + + /// + /// Return true. + /// + friend bool operator==(b_minkey const&, b_minkey const&) { + return true; + } + + /// + /// Return false. + /// + friend bool operator!=(b_minkey const& lhs, b_minkey const& rhs) { + return !(lhs == rhs); + } +}; + +// BSONCXX_V1_TYPES_XMACRO: update above. /// /// A non-owning, read-only union of BSON type values. @@ -179,7 +1075,174 @@ struct b_minkey {}; /// /// @attention This feature is experimental! It is not ready for use! /// -class view {}; +class view { + private: + id _id; + +#pragma push_macro("X") +#undef X +#define X(_name, _value) b_##_name _b_##_name; + + union { + BSONCXX_V1_TYPES_XMACRO(X) + }; +#pragma pop_macro("X") + + template + using is_view = detail::is_alike; + + template + struct is_equality_comparable_with + : detail::conjunction>, std::is_constructible> {}; + + public: + /// Initialize with @ref bsoncxx::v1::types::b_null. + view() : _id{id::k_null}, _b_null{} {} + +#pragma push_macro("X") +#undef X + // GCC 4.X misinterprets list-initialization of _b_##_name: "too many initializers". +#define X(_name, _value) \ + /* explicit(false) */ view(b_##_name v) : _id{v.type_id}, _b_##_name(v) {} + + /// + /// Implicitly convert `v`. + /// + /// @{ + BSONCXX_V1_TYPES_XMACRO(X) + /// @} + /// +#pragma pop_macro("X") + + /// + /// Return the type of the underlying BSON type value. + /// + id type_id() const { + return _id; + } + +#pragma push_macro("X") +#undef X +#define X(_name, _value) BSONCXX_ABI_EXPORT_CDECL(b_##_name) get_##_name() const; + + /// + /// Return the requested underlying BSON type value. + /// + /// @exception bsoncxx::v1::exception with @ref bsoncxx::v1::error::types::view::type_mismatch if the underlying + /// BSON type value does not match the requested type. + /// + /// @{ + BSONCXX_V1_TYPES_XMACRO(X) + /// @} + /// +#pragma pop_macro("X") + + /// + /// Compare equal when the underlying BSON type values have the same type and compare equal. + /// + /// Equivalent to: + /// ```cpp + /// lhs.type_id() == rhs.type_id() && lhs.get_type() == rhs.get_type() + /// ``` + /// where `get_type` is the correct name for the underlying BSON type values (e.g. `get_double()` when + /// `type_id() == bsoncxx::v1::types::id::k_double`). + /// + /// When the type of `lhs` and `rhs` compare equal but are not a supported value (not defined by @ref + /// BSONCXX_V1_TYPES_XMACRO), the result is always `true`. + /// + friend bool operator==(view const& lhs, view const& rhs) { + if (lhs.type_id() != rhs.type_id()) { + return false; + } + +#pragma push_macro("X") +#undef X +#define X(_name, _value) \ + case v1::types::id::k_##_name: \ + return lhs.get_##_name() == rhs.get_##_name(); + + switch (lhs.type_id()) { + BSONCXX_V1_TYPES_XMACRO(X) + + default: + return true; + } +#pragma pop_macro("X") + } + + /// + /// Equivalent to `!(lhs == rhs)`. + /// + friend bool operator!=(view const& lhs, view const& rhs) { + return !(lhs == rhs); + } + + /// + /// Equivalent to `v == e.type_view()`. + /// + /// @{ + friend bool operator==(view const& v, v1::element::view const& e) { + return v == e.type_view(); + } + + friend bool operator==(v1::element::view const& e, view const& v) { + return v == e.type_view(); + } + /// @} + /// + + /// + /// Equivalent to `!(v == e)`. + /// + /// @{ + friend bool operator!=(view const& v, v1::element::view const& e) { + return !(v == e); + } + + friend bool operator!=(v1::element::view const& e, view const& v) { + return !(v == e); + } + /// @} + /// + + /// + /// Equivalent to `v == bsoncxx::v1::types::view{value}`. + /// + /// @par Constraints: + /// - `T` is not @ref bsoncxx::v1::types::view. + /// - @ref bsoncxx::v1::types::view is constructible with `T`. + /// + /// @{ + template ::value>* = nullptr> + friend bool operator==(view const& v, T const& value) { + return v == view{BSONCXX_PRIVATE_FWD(value)}; + } + + template ::value>* = nullptr> + friend bool operator==(T const& value, view const& v) { + return v == view{BSONCXX_PRIVATE_FWD(value)}; + } + /// @} + /// + + /// + /// Equivalent to `!(v == value)`. + /// + /// @{ + template ::value>* = nullptr> + friend bool operator!=(view const& v, T const& value) { + return !(v == value); + } + + template ::value>* = nullptr> + friend bool operator!=(T const& value, view const& v) { + return !(v == value); + } + /// @} + /// + + class internal; +}; } // namespace types } // namespace v1 @@ -193,3 +1256,10 @@ class view {}; /// /// @note A "BSON type value" refers to the value of a BSON element without its key. /// +/// @par Includes +/// - @ref bsoncxx/v1/array/view.hpp +/// - @ref bsoncxx/v1/decimal128.hpp +/// - @ref bsoncxx/v1/document/view.hpp +/// - @ref bsoncxx/v1/oid.hpp +/// - @ref bsoncxx/v1/types/id.hpp +/// diff --git a/src/bsoncxx/lib/bsoncxx/private/type_traits.hh b/src/bsoncxx/lib/bsoncxx/private/type_traits.hh index 4d993ccd21..6f9205932c 100644 --- a/src/bsoncxx/lib/bsoncxx/private/type_traits.hh +++ b/src/bsoncxx/lib/bsoncxx/private/type_traits.hh @@ -68,11 +68,19 @@ struct is_regular : detail::conjunction, detail::is_equality_c // Equivalent to `is_trivial` without requiring trivial default constructibility. template -struct is_semitrivial : detail::conjunction< - std::is_trivially_destructible, - std::is_trivially_move_constructible, - std::is_trivially_move_assignable, - std::is_trivially_copy_constructible, - std::is_trivially_copy_assignable> {}; +struct is_semitrivial +// https://gcc.gnu.org/onlinedocs/gcc-4.9.0/libstdc++/manual/manual/status.html +#if defined(__GNUC__) && (__GNUC__ < 5) && !defined(__clang__) + : std::true_type +#else + : detail::conjunction< + std::is_trivially_destructible, + std::is_trivially_move_constructible, + std::is_trivially_move_assignable, + std::is_trivially_copy_constructible, + std::is_trivially_copy_assignable> +#endif +{ +}; } // namespace bsoncxx diff --git a/src/bsoncxx/lib/bsoncxx/v1/array/value.cpp b/src/bsoncxx/lib/bsoncxx/v1/array/value.cpp index d7e80e8ede..9799f052d7 100644 --- a/src/bsoncxx/lib/bsoncxx/v1/array/value.cpp +++ b/src/bsoncxx/lib/bsoncxx/v1/array/value.cpp @@ -13,3 +13,18 @@ // limitations under the License. #include + +// + +#include + +namespace bsoncxx { +namespace v1 { +namespace array { + +static_assert(is_regular::value, "bsoncxx::v1::array::value must be regular"); +static_assert(is_nothrow_moveable::value, "bsoncxx::v1::array::value must be nothrow moveable"); + +} // namespace array +} // namespace v1 +} // namespace bsoncxx diff --git a/src/bsoncxx/lib/bsoncxx/v1/array/view.cpp b/src/bsoncxx/lib/bsoncxx/v1/array/view.cpp index 8eafdc8eb8..898e9e4a02 100644 --- a/src/bsoncxx/lib/bsoncxx/v1/array/view.cpp +++ b/src/bsoncxx/lib/bsoncxx/v1/array/view.cpp @@ -13,3 +13,23 @@ // limitations under the License. #include + +// + +#include + +namespace bsoncxx { +namespace v1 { +namespace array { + +static_assert(is_regular::value, "bsoncxx::v1::array::view must be regular"); +static_assert(is_semitrivial::value, "bsoncxx::v1::array::view must be semitrivial"); + +static_assert(is_regular::value, "bsoncxx::v1::array::view::const_iterator must be regular"); +static_assert( + is_nothrow_moveable::value, + "bsoncxx::v1::array::view::const_iterator must be nothrow moveable"); + +} // namespace array +} // namespace v1 +} // namespace bsoncxx diff --git a/src/bsoncxx/lib/bsoncxx/v1/decimal128.cpp b/src/bsoncxx/lib/bsoncxx/v1/decimal128.cpp index e2c2d465b4..981a0975be 100644 --- a/src/bsoncxx/lib/bsoncxx/v1/decimal128.cpp +++ b/src/bsoncxx/lib/bsoncxx/v1/decimal128.cpp @@ -13,3 +13,16 @@ // limitations under the License. #include + +// + +#include + +namespace bsoncxx { +namespace v1 { + +static_assert(is_regular::value, "bsoncxx::v1::decimal128 must be regular"); +static_assert(is_semitrivial::value, "bsoncxx::v1::decimal128 must be semitrivial"); + +} // namespace v1 +} // namespace bsoncxx diff --git a/src/bsoncxx/lib/bsoncxx/v1/document/value.cpp b/src/bsoncxx/lib/bsoncxx/v1/document/value.cpp index 04d1e03673..83db595903 100644 --- a/src/bsoncxx/lib/bsoncxx/v1/document/value.cpp +++ b/src/bsoncxx/lib/bsoncxx/v1/document/value.cpp @@ -13,3 +13,18 @@ // limitations under the License. #include + +// + +#include + +namespace bsoncxx { +namespace v1 { +namespace document { + +static_assert(is_regular::value, "bsoncxx::v1::document::value must be regular"); +static_assert(is_nothrow_moveable::value, "bsoncxx::v1::document::value must be nothrow moveable"); + +} // namespace document +} // namespace v1 +} // namespace bsoncxx diff --git a/src/bsoncxx/lib/bsoncxx/v1/document/view.cpp b/src/bsoncxx/lib/bsoncxx/v1/document/view.cpp index 949f6a95eb..a8c878016d 100644 --- a/src/bsoncxx/lib/bsoncxx/v1/document/view.cpp +++ b/src/bsoncxx/lib/bsoncxx/v1/document/view.cpp @@ -13,3 +13,23 @@ // limitations under the License. #include + +// + +#include + +namespace bsoncxx { +namespace v1 { +namespace document { + +static_assert(is_regular::value, "bsoncxx::v1::document::view must be regular"); +static_assert(is_semitrivial::value, "bsoncxx::v1::document::view must be semitrivial"); + +static_assert(is_regular::value, "bsoncxx::v1::document::view::const_iterator must be regular"); +static_assert( + is_nothrow_moveable::value, + "bsoncxx::v1::document::view::const_iterator must be nothrow moveable"); + +} // namespace document +} // namespace v1 +} // namespace bsoncxx diff --git a/src/bsoncxx/lib/bsoncxx/v1/element/view.cpp b/src/bsoncxx/lib/bsoncxx/v1/element/view.cpp index 9f7b1fac53..a19fba1bc6 100644 --- a/src/bsoncxx/lib/bsoncxx/v1/element/view.cpp +++ b/src/bsoncxx/lib/bsoncxx/v1/element/view.cpp @@ -13,3 +13,18 @@ // limitations under the License. #include + +// + +#include + +namespace bsoncxx { +namespace v1 { +namespace element { + +static_assert(is_regular::value, "bsoncxx::v1::element::view must be regular"); +static_assert(is_nothrow_moveable::value, "bsoncxx::v1::element::view must be nothrow moveable"); + +} // namespace element +} // namespace v1 +} // namespace bsoncxx diff --git a/src/bsoncxx/lib/bsoncxx/v1/exception.cpp b/src/bsoncxx/lib/bsoncxx/v1/exception.cpp index 50b176a8a8..07900b8c77 100644 --- a/src/bsoncxx/lib/bsoncxx/v1/exception.cpp +++ b/src/bsoncxx/lib/bsoncxx/v1/exception.cpp @@ -13,3 +13,13 @@ // limitations under the License. #include + +// + +namespace bsoncxx { +namespace v1 { + +exception::~exception() = default; + +} // namespace v1 +} // namespace bsoncxx diff --git a/src/bsoncxx/lib/bsoncxx/v1/oid.cpp b/src/bsoncxx/lib/bsoncxx/v1/oid.cpp index cfa9b0e6af..9bf5da8ef0 100644 --- a/src/bsoncxx/lib/bsoncxx/v1/oid.cpp +++ b/src/bsoncxx/lib/bsoncxx/v1/oid.cpp @@ -13,3 +13,16 @@ // limitations under the License. #include + +// + +#include + +namespace bsoncxx { +namespace v1 { + +static_assert(is_regular::value, "bsoncxx::v1::oid must be regular"); +static_assert(is_semitrivial::value, "bsoncxx::v1::oid must be semitrivial"); + +} // 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 2a04af19a0..8dd7dc8c97 100644 --- a/src/bsoncxx/lib/bsoncxx/v1/types/value.cpp +++ b/src/bsoncxx/lib/bsoncxx/v1/types/value.cpp @@ -13,3 +13,18 @@ // limitations under the License. #include + +// + +#include + +namespace bsoncxx { +namespace v1 { +namespace types { + +static_assert(is_regular::value, "bsoncxx::v1::types::value must be regular"); +static_assert(is_nothrow_moveable::value, "bsoncxx::v1::types::value must be nothrow moveable"); + +} // namespace types +} // namespace v1 +} // namespace bsoncxx diff --git a/src/bsoncxx/lib/bsoncxx/v1/types/view.cpp b/src/bsoncxx/lib/bsoncxx/v1/types/view.cpp index c57193c1c5..cce4161d2f 100644 --- a/src/bsoncxx/lib/bsoncxx/v1/types/view.cpp +++ b/src/bsoncxx/lib/bsoncxx/v1/types/view.cpp @@ -13,3 +13,27 @@ // limitations under the License. #include + +// + +#include + +namespace bsoncxx { +namespace v1 { +namespace types { + +#pragma push_macro("X") +#undef X +#define X(_name, _value) \ + static_assert(is_regular::value, "bsoncxx::v1::types::b_" #_name " must be regular"); \ + static_assert(is_semitrivial::value, "bsoncxx::v1::types::b_" #_name " must be semitrivial"); + +BSONCXX_V1_TYPES_XMACRO(X) +#pragma pop_macro("X") + +static_assert(is_regular::value, "bsoncxx::v1::types::view must be regular"); +static_assert(is_semitrivial::value, "bsoncxx::v1::types::view must be semitrivial"); + +} // namespace types +} // namespace v1 +} // namespace bsoncxx