-
Notifications
You must be signed in to change notification settings - Fork 544
CXX-3233 add bsoncxx v1 implementations and tests #1430
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
base: master
Are you sure you want to change the base?
Conversation
if (!_view) { | ||
return this->cend(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This check is not present in v_noabi). This is a consequence of the new, well-defined "invalid" state of an array view.
if (!bson_init_static(&bson, _view.data(), _view.length())) { | ||
throw v1::exception{code::invalid_data}; | ||
} | ||
|
||
bson_iter_t iter; | ||
|
||
if (!bson_iter_init_find_w_len(&iter, &bson, key.c_str(), static_cast<int>(key.length()))) { | ||
return this->end(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is slightly different to v_noabi's bson_init_static
-> bson_iter_init
-> bson_iter_init_find
implementation, but should still be equivalent in observable behavior.
return const_iterator::internal::make_const_iterator( | ||
_view.data(), _view.length(), bson_iter_offset(&iter), bson_iter_key_len(&iter)); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (sv.empty()) { | ||
throw v1::exception{code::empty_string}; | ||
} | ||
|
||
if (sv.size() > std::size_t{INT_MAX}) { | ||
throw v1::exception{code::invalid_string_length}; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These checks are not present in v_noabi.
@@ -30,6 +43,167 @@ static_assert( | |||
is_nothrow_moveable<view::const_iterator>::value, | |||
"bsoncxx::v1::document::view::const_iterator must be nothrow moveable"); | |||
|
|||
namespace { | |||
|
|||
constexpr std::uint8_t k_default_view[5] = {5u, 0u, 0u, 0u, 0u}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the special empty document representation that is used to avoid v1::document::value
allocation (with a no-op deleter).
if (!bytes) { | ||
throw v1::exception{code::null_bytes_ptr}; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This check is not present in v_noabi, which may lead to library-level undefined behavior when invoking memcpy()
.
// For backward compatibility, do not prematurely truncate strings in bsoncxx API. Instead, defer handling of potential | ||
// embedded null bytes to the bson library. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment documents an observation that v_noabi's make_copy_for_libbson
(which in hindsight should really be moved out of private
and into v_noabi
along with a few more current private
headers) uses memcpy
rather than str(n)cpy
to create owning BSON strings. The v1 implementation preserves this behavior, avoiding truncation and deferring null byte validation to the bson library.
#pragma pop_macro("X") | ||
} | ||
|
||
// BSONCXX_V1_TYPES_XMACRO: update below. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The overloads below implement the behavior currently handled by v_noabi's convert_to_libbson()
in convert.hh, but without exposing .bson_value_t
to dependent components
if (v.value.size() > UINT32_MAX) { | ||
throw v1::exception{code::invalid_length_u32}; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These UINT32_MAX
checks are not in v_noabi and guard the subsequent casts to std::uint32_t
.
|
||
} // namespace | ||
|
||
view view::internal::make(bson_value_t const& v) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This implements the behavior currently handled by v_noabi's convert_from_libbson()
in convert.hh, but without exposing .bson_value_t
to dependent components
static v1::stdx::optional<bson_iter_t> to_bson_iter(view const& v); | ||
|
||
private: | ||
friend view; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider moving the private static methods of element::view::internal
to element::view::impl
:
// In bsoncxx::v1::element::view::impl:
static view::impl const& to_impl(view const& self) {
return *reinterpret_cast<view::impl const*>(self._storage.data());
}
static view::impl const* to_impl(view const* self) {
return reinterpret_cast<view::impl const*>(self->_storage.data());
}
static view::impl* to_impl(view* self) {
return reinterpret_cast<view::impl*>(self->_storage.data());
}
That appears to allow removing the friend
declaration. IIUC the internal
classes are intended as a controlled internal view into private API from other components. In this case, no other components need to (or can) call these private static methods.
Comment similarly applies to types::value::internal
.
Resolves CXX-3233. Followup to #1412.
This is 3 out of an estimated 7 major PRs which in total are expected to resolve CXX-2745.
This PR provides implementations and tests for the v1 API introduced by CXX-3232 in #1412.
Important
This PR deliberately leaves the v_noabi API interfaces, implementations, and tests unchanged to facilitate direct, side-by-side comparisons between v1 and v_noabi. Redundancy and duplication between v1 and v_noabi will be addressed by the bsoncxx v_noabi refactor (CXX-3234).
In summary, notable changes (relative to the v_noabi API's implementation and tests) include:
builder::*
,validate::*
, andvector::*
, which bring the v_noabi symbol count up to 325.array::*
function defined in terms ofdocument::*
exceptv1::array::view::find(std::uint32_t) const
.types::value
constructors in terms ofb_<type>
overloads only.lib/**/*.hh
..cpp
to minimize recompilations).internal
classes instead offriend
declarations to access "private" interfaces or data.internal
classes declare the exact set of private data being exposed for use by dependent components (including tests).internal
public static member functions explicitly documents-as-code the dependents that require corresponding private data.bsoncxx::v1::decimal128
) or the error code enumeration otherwise (e.g.bsoncxx::v1::source_errc
).equivalent()
mapping to thesource_errc
andtype_errc
error condition enumerations.BSONCXX_V1_TYPES_XMACRO
X-macro pattern in place of#include <bsoncxx/enums/type.hpp>
X-macro headers.impl
object into reserved data member storage rather than dynamic allocation).v1::document::element
used to implement the alternative approach to CXX-2120. Note the deliberate lack of any mention of this state in the public API: it is meant to be entirely unobservable except in service of corresponding exception error messages.test/**/*.hh
) defining Catch stringification for tested entities.bsoncxx/test/catch.hh
header to minimize recompilations.StringMaker<T>
specializations. 🫠bsoncxx::test::stringify()
as equivalent toCatch::Detail::Stringify()
(deducesT
in call toStringMaker<T>::convert()
)."stringify"
test cases for Catch expression decomposition behavior (implicit "to string" test coverage).--success
flag.v1::document::value
to ensure correctimpl
and custom deleter behavior.CHECK_NOFAIL
used to document behavior which may vary across standard library implementations (surprising!).[namespace][to][component]
for better test case filtering.[error]
tag for testing error-code-specific behavior (e.g. mapping codes to conditions).[test]
tag for test-suite-specific behavior (e.g. Catch stringification).CHECK_THROWS_WITH_CODE
(excludingv1::oid::oid()
...).Note
To avoid v1 test components depending on the v_noabi API (no v1 library or test component includes v_noabi headers), BSON data are hand-written as binary data (e.g.
std::uint8_t data[] = {...}
) instead of using thebsoncxx::v_noabi::builder::*
API. These may eventually be substituted with a v1 builder API, but I think there is also merit to keeping them independent of any builder API, such that the test cases are not dependent on unrelated behavior and minimizes cross-component test behavior dependencies. 🤔