Skip to content

CXX-3232 add bsoncxx v1 declarations #1412

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 45 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
98521ae
CXX-3232 add v1 interface declarations
eramongodb May 28, 2025
7451133
Use copydoc for v1::array::view iterators
eramongodb Jun 2, 2025
a5b2cde
Rename Legacy -> Cpp17 for consistency with C++20 spec
eramongodb Jun 2, 2025
0720b5d
Merge remote-tracking branch 'upstream/master' into cxx-abi-v1-decls
eramongodb Jun 16, 2025
5c06c49
Apply "cheap-to-copy" heuristic to pass-by-value parameters
eramongodb Jun 23, 2025
dd8be8c
Remove extraneous include doc entry
eramongodb Jun 23, 2025
268ddd6
Reword "BSON binary data" -> "BSON bytes"
eramongodb Jun 23, 2025
f1ac5f3
Document algorithmic complexity of element lookup
eramongodb Jun 23, 2025
d85e22f
Fix swapped documentation for BSON min/max key
eramongodb Jun 23, 2025
aa5c4b3
Fix documentation referencing size of pointed-to storage regions
eramongodb Jun 23, 2025
fadc090
Improve accuracy of invalid element documentation
eramongodb Jun 23, 2025
9f44ae6
Revert v1::element::view to be non-equality-comparable
eramongodb Jun 23, 2025
8dbd861
Change result of comparing unsupported types from "true" to "unspecif…
eramongodb Jun 23, 2025
b814afc
Tweak wording: "represents" -> "point to"
eramongodb Jun 23, 2025
011887c
Make bsoncxx::v1::document::value default ctor explicit
eramongodb Jun 27, 2025
5b34deb
Tidy up include directives
eramongodb Jul 3, 2025
c499de5
Use std::array instead of C arrays
eramongodb Jul 3, 2025
cf4f160
Remove redundant BSONCXX_PRIVATE_FWD
eramongodb Jul 3, 2025
a65f489
Fix implicit vs. explicit documentation for v1::types::value ctors
eramongodb Jul 3, 2025
8ca3115
cpx: cxx-evg-rhel95
eramongodb Jul 9, 2025
44c9710
Merge remote-tracking branch 'upstream/master' into HEAD
eramongodb Jul 9, 2025
dde9211
Fix documentation for find vs. subscript
eramongodb Jul 9, 2025
4b351fe
Consistently use noexcept for defaulted move SMFs
eramongodb Jul 9, 2025
b80e6a8
Avoid false-positive -Wdocumentation Clang warnings
eramongodb Jul 9, 2025
3dbcc85
Use BSON bytes to store and represent document length
eramongodb Jul 9, 2025
f7966e6
Make v1::document::value default-initialize as an empty document
eramongodb Jul 9, 2025
167f7bc
Revert explicit default constructors for list-initialization
eramongodb Jul 9, 2025
667c740
Change v1::types::id from uint8_t to int8_t
eramongodb Jul 9, 2025
12b5435
Add bsoncxx/v1/detail/bit.hpp
eramongodb Jul 9, 2025
8e93526
Revert v1::oid::size to static member function (again)
eramongodb Jul 3, 2025
ba187b5
Update Clang 18 -> Clang 19 for rhel95 distro (#1421)
eramongodb Jul 10, 2025
386f555
Merge remote-tracking branch 'upstream/master' into cxx-abi-v1-decls
eramongodb Jul 10, 2025
86e978c
Improve consistency of subscript documentation
eramongodb Jul 10, 2025
b9744b1
Define v1::document::value::noop_deleter_type
eramongodb Jul 10, 2025
ca0836a
Merge remote-tracking branch 'upstream/master' into cxx-abi-v1-decls
eramongodb Jul 10, 2025
88efd0c
Add missing explicit
eramongodb Jul 11, 2025
9888b1f
Remove all use of __cdecl in v1
eramongodb Jul 11, 2025
dfb80be
An invalid view -> an invalid value
eramongodb Jul 11, 2025
f19ab7e
Add length validation overloads
eramongodb Jul 11, 2025
a1a7c90
Revert GCC 4.X compatibility workarounds
eramongodb Jul 11, 2025
099f6f2
ClangFormat
eramongodb Jul 11, 2025
a2a51fc
Revert "Remove all use of __cdecl in v1" (CXX-3310)
eramongodb Jul 14, 2025
356031e
Merge remote-tracking branch 'upstream/master' into HEAD
eramongodb Jul 14, 2025
7087d8a
v1::array::view::cbegin() can reuse v1::document::view::cbegin()
eramongodb Jul 14, 2025
9a77b17
Support implicit assignment from view to value
eramongodb Jul 14, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions .evergreen/scripts/abidiff-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
185 changes: 184 additions & 1 deletion src/bsoncxx/include/bsoncxx/v1/array/value.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,14 @@

#include <bsoncxx/v1/detail/prelude.hpp>

#include <bsoncxx/v1/array/view.hpp>
#include <bsoncxx/v1/config/export.hpp>
#include <bsoncxx/v1/document/value.hpp>

#include <cstdint>
#include <type_traits>
#include <utility>

namespace bsoncxx {
namespace v1 {
namespace array {
Expand All @@ -29,7 +37,178 @@ namespace array {
///
/// @attention This feature is experimental! It is not ready for use!
///
class value {};
class value {
private:
v1::document::value _value;
Copy link
Contributor Author

@eramongodb eramongodb May 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All behavior for this class is defined in terms of v1::document::value or v1::array::view, including error codes and Doxygen documentation.


template <typename T>
struct is_valid_deleter : std::is_constructible<v1::document::value, std::uint8_t*, T> {};

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 = default;

/// @copydoc v1::document::value::operator=(v1::document::value&& other) noexcept
value& operator=(value&& other) noexcept = default;

/// @copydoc v1::document::value::value(v1::document::value const& other)
value(value const& other) : _value(other._value) {}

/// @copydoc v1::document::value::operator=(v1::document::view view)
value& operator=(v1::array::view view) {
this->reset(view);
return *this;
}

/// @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, Deleter deleter)
template <typename Deleter, detail::enable_if_t<is_valid_deleter<Deleter>::value>* = nullptr>
value(std::uint8_t* data, Deleter deleter) : _value{data, std::move(deleter)} {}

/// @copydoc v1::document::value::value(std::uint8_t* data, std::size_t length, Deleter deleter)
template <typename Deleter, detail::enable_if_t<is_valid_deleter<Deleter>::value>* = nullptr>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this use detail::requires_t instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I considered using detail::requires_t but opted to avoid it due to quality of diagnostic errors on constraint failure and better consistency with typical and well-recognized enable_if-based SFINAE which does not rely on unique user-defined type traits. The requires_t machinery seems to hurt diagnostic readability more than it helps.


Using this piece of code as a case example:

struct invalid {};
(void)bsoncxx::v1::array::value(nullptr, 0u, invalid());

Given detail::enable_if_t<is_valid_deleter<Deleter>::value>* = nullptr, Clang 21 diagnostics (file paths omitted for brevity):

error: no matching constructor for initialization of 'bsoncxx::v1::array::value'
note: candidate template ignored: requirement 'is_valid_deleter<invalid>::value' was not satisfied [with Deleter = invalid]

and GCC 13.3 diagnostics:

error: no matching function for call to ‘bsoncxx::v1::array::value::value(std::nullptr_t, unsigned int, invalid)’
  112 |     (void)bsoncxx::v1::array::value(nullptr, 0u, invalid());
      |                                                           ^
note: candidate: ‘template<class Deleter, bsoncxx::detail::enable_if_t<bsoncxx::v1::array::value::is_valid_deleter<T>::value>* <anonymous> > bsoncxx::v1::array::value::value(uint8_t*, std::size_t, Deleter)’
   89 |     value(std::uint8_t* data, std::size_t length, Deleter deleter) : _value{data, length, std::move(deleter)} {}
      |     ^~~~~
note:   template argument deduction/substitution failed:
In file included from ...:
In substitution of ‘template<bool B, class T> using bsoncxx::detail::enable_if_t = typename std::enable_if::type [with bool B = false; T = void]’:
...:  required from here
error: no type named ‘type’ in ‘struct std::enable_if<false, void>’
   36 | using enable_if_t = typename std::enable_if<B, T>::type;
      |       ^~~~~~~~~~~

Given detail::requires_t<int, is_valid_deleter<Deleter>> = 0, Clang 21 diagnostics:

error: no matching constructor for initialization of 'bsoncxx::v1::array::value'
  112 |     (void)bsoncxx::v1::array::value(nullptr, 0u, invalid());
      |           ^                         ~~~~~~~~~~~~~~~~~~~~~~
note: candidate template ignored: substitution failure [with Deleter = invalid]: no matching function for call to 'explain'
   89 |     value(std::uint8_t* data, std::size_t length, Deleter deleter) : _value{data, length, std::move(deleter)} {}
      |     ^

and GCC 13.3 diagnostics:

error: no matching function for call to ‘bsoncxx::v1::array::value::value(std::nullptr_t, unsigned int, invalid)’
  112 |     (void)bsoncxx::v1::array::value(nullptr, 0u, invalid());
      |                                                           ^
note: candidate: ‘template<class Deleter, decltype (typename bsoncxx::detail::impl_requires::requirement<bsoncxx::detail::conjunction<bsoncxx::v1::array::value::is_valid_deleter<Deleter> >, void>::test::explain<int>(0)) <anonymous> > bsoncxx::v1::array::value::value(uint8_t*, std::size_t, Deleter)’
   89 |     value(std::uint8_t* data, std::size_t length, Deleter deleter) : _value{data, length, std::move(deleter)} {}
      |     ^~~~~
note:   template argument deduction/substitution failed:
In file included from ...:
error: no matching function for call to ‘bsoncxx::detail::impl_requires::failed_requirement<bsoncxx::detail::conjunction<bsoncxx::v1::array::value::is_valid_deleter<invalid> > >::explain<int>(int)’
  336 | using requires_t = decltype(impl_requires::requirement<conjunction<Traits...>>::test::template explain<Type>(0));
      |                             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~
note: candidate: ‘template<class T> static bsoncxx::detail::common_type_t<decltype (typename bsoncxx::detail::impl_requires::requirement<SubRequirements, void>::test::explain<T>(0))...> bsoncxx::detail::impl_requires::failed_requirement<bsoncxx::detail::conjunction<SubRequirements ...> >::explain(int) [with SubRequirements = {bsoncxx::v1::array::value::is_valid_deleter<invalid>}]’
  306 |     static auto explain(int) -> common_type_t<decltype(requirement<SubRequirements>::test::template explain<T>(0))...>;
      |                 ^~~~~~~
note:   template argument deduction/substitution failed:
In substitution of ‘template<class T> static bsoncxx::detail::common_type_t<decltype (explain<T>(0))> bsoncxx::detail::impl_requires::failed_requirement<bsoncxx::detail::conjunction<bsoncxx::v1::array::value::is_valid_deleter<invalid> > >::explain(int) [with T = int]’:
...:  required from here
error: use of deleted function ‘bsoncxx::detail::impl_requires::failed_requirement<FailingRequirement>::failed_requirement(int) [with FailingRequirement = bsoncxx::v1::array::value::is_valid_deleter<invalid>]’
  306 |     static auto explain(int) -> common_type_t<decltype(requirement<SubRequirements>::test::template explain<T>(0))...>;
      |                                                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~
note: declared here
  295 |     failed_requirement(int) = delete;
      |     ^~~~~~~~~~~~~~~~~~

Given requires_t and given array::is_valid_deleter<T> is defined as a type alias instead of a struct, Clang 21 diagnostics:

error: no matching constructor for initialization of 'bsoncxx::v1::array::value'
  112 |     (void)bsoncxx::v1::array::value(nullptr, 0u, invalid());
      |           ^                         ~~~~~~~~~~~~~~~~~~~~~~
note: candidate template ignored: substitution failure [with Deleter = invalid]: no matching function for call to 'explain'
   89 |     value(std::uint8_t* data, std::size_t length, Deleter deleter) : _value{data, length, std::move(deleter)} {}
      |     ^

and GCC 13.3 diagnostics:

error: no matching function for call to ‘bsoncxx::v1::array::value::value(std::nullptr_t, unsigned int, invalid)’
  112 |     (void)bsoncxx::v1::array::value(nullptr, 0u, invalid());
      |                                                           ^
note: candidate: ‘template<class Deleter, decltype (typename bsoncxx::detail::impl_requires::requirement<bsoncxx::detail::conjunction<std::is_constructible<bsoncxx::v1::document::value, unsigned char*, long unsigned int, T> >, void>::test::explain<int>(0)) <anonymous> > bsoncxx::v1::array::value::value(uint8_t*, std::size_t, Deleter)’
   89 |     value(std::uint8_t* data, std::size_t length, Deleter deleter) : _value{data, length, std::move(deleter)} {}
      |     ^~~~~
note:   template argument deduction/substitution failed:
In file included from ...:
error: no matching function for call to ‘bsoncxx::detail::impl_requires::failed_requirement<bsoncxx::detail::conjunction<std::is_constructible<bsoncxx::v1::document::value, unsigned char*, long unsigned int, invalid> > >::explain<int>(int)’
  336 | using requires_t = decltype(impl_requires::requirement<conjunction<Traits...>>::test::template explain<Type>(0));
      |                             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~
note: candidate: ‘template<class T> static bsoncxx::detail::common_type_t<decltype (typename bsoncxx::detail::impl_requires::requirement<SubRequirements, void>::test::explain<T>(0))...> bsoncxx::detail::impl_requires::failed_requirement<bsoncxx::detail::conjunction<SubRequirements ...> >::explain(int) [with SubRequirements = {std::is_constructible<bsoncxx::v1::document::value, unsigned char*, long unsigned int, invalid>}]’
  306 |     static auto explain(int) -> common_type_t<decltype(requirement<SubRequirements>::test::template explain<T>(0))...>;
      |                 ^~~~~~~
note:   template argument deduction/substitution failed:
In substitution of ‘template<class T> static bsoncxx::detail::common_type_t<decltype (explain<T>(0))> bsoncxx::detail::impl_requires::failed_requirement<bsoncxx::detail::conjunction<std::is_constructible<bsoncxx::v1::document::value, unsigned char*, long unsigned int, invalid> > >::explain(int) [with T = int]’:
...:  required from here
error: use of deleted function ‘bsoncxx::detail::impl_requires::failed_requirement<FailingRequirement>::failed_requirement(int) [with FailingRequirement = std::is_constructible<bsoncxx::v1::document::value, unsigned char*, long unsigned int, invalid>]’
  306 |     static auto explain(int) -> common_type_t<decltype(requirement<SubRequirements>::test::template explain<T>(0))...>;
      |                                                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~
note: declared here
  295 |     failed_requirement(int) = delete;
      |     ^~~~~~~~~~~~~~~~~~

Aside: none of these make any difference with MSVC 19.44 (VS 2022 17.14). 😅

error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'bsoncxx::v1::array::value'
note: 'bsoncxx::v1::array::value::value': function does not take 3 arguments
note: could be 'bsoncxx::v1::array::value::value(uint8_t *,size_t,Deleter)'
note: while trying to match the argument list '(nullptr, unsigned int, invalid)'

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)
explicit value(std::uint8_t* data) : _value{data} {}

/// @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)
explicit value(unique_ptr_type ptr) : _value{std::move(ptr)} {}

/// @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 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 v)
void reset(v1::array::view v) {
*this = value{v};
}

///
/// Return a view of the BSON bytes as an array.
///
v1::array::view view() const {
return v1::array::view{_value.data()};
}

///
/// 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 lhs, v1::array::view rhs)
friend bool operator==(value const& lhs, value const& rhs) {
return lhs.view() == rhs.view();
}

/// @copydoc v1::array::view::operator!=(v1::array::view lhs, v1::array::view rhs)
friend bool operator!=(value const& lhs, value const& rhs) {
return !(lhs == rhs);
}
};

} // namespace array
} // namespace v1
Expand All @@ -41,3 +220,7 @@ class value {};
/// @file
/// Provides @ref bsoncxx::v1::array::value.
///
/// @par Includes
/// - @ref bsoncxx/v1/array/view.hpp
/// - @ref bsoncxx/v1/document/value.hpp
///
133 changes: 132 additions & 1 deletion src/bsoncxx/include/bsoncxx/v1/array/view.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,143 @@

#include <bsoncxx/v1/detail/prelude.hpp>

#include <bsoncxx/v1/config/export.hpp>
#include <bsoncxx/v1/document/view.hpp>
#include <bsoncxx/v1/element/view.hpp>

#include <cstddef>
#include <cstdint>

namespace bsoncxx {
namespace v1 {
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 bytes 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;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Due to the similarity in behavior between v1::document::view and v1::array::view, the latter is primarily implemented in terms of the former, including error codes and Doxygen documentation.


public:
/// @copydoc v1::document::view::view()
view() = default;

/// @copydoc v1::document::view::view(std::uint8_t const* data)
explicit view(std::uint8_t const* data) : _view{data} {}

/// @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
const_iterator cbegin() const {
return _view.cbegin();
}

/// @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` via key string comparison.
///
/// If this view is invalid or the requested field is not found, returns an end iterator.
///
/// @par Complexity
/// Linear.
///
/// @exception bsoncxx::v1::exception with @ref bsoncxx::v1::error::document::view::invalid_data if this operation
/// failed due to invalid BSON bytes.
///
BSONCXX_ABI_EXPORT_CDECL(const_iterator) find(std::uint32_t i) const;

///
/// Return the first element within the represented BSON array whose key compares equal to `i`.
///
/// @returns An invalid element if this view is invalid or the requested field is not found.
///
/// @par Complexity
/// Linear.
///
/// @exception bsoncxx::v1::exception with @ref bsoncxx::v1::error::document::view::invalid_data if this operation
/// failed due to invalid BSON bytes.
///
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 lhs, v1::document::view rhs)
friend bool operator==(view lhs, view rhs) {
return lhs._view == rhs._view;
}

/// @copydoc v1::document::view::operator!=(v1::document::view lhs, v1::document::view rhs)
friend bool operator!=(view lhs, view rhs) {
return !(lhs == rhs);
}
};

} // namespace array
} // namespace v1
Expand All @@ -41,3 +168,7 @@ class view {};
/// @file
/// Provides @ref bsoncxx::v1::array::view.
///
/// @par Includes
/// - @ref bsoncxx/v1/document/view.hpp
/// - @ref bsoncxx/v1/element/view.hpp
///
Loading