-
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?
Changes from all commits
9fc87c6
b034251
e51551b
f258f76
25354e4
b2a4393
1bc5302
877cd50
9e3d254
2cfc2d7
8de4ee1
a3fd459
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,12 +16,24 @@ | |
|
||
// | ||
|
||
#include <bsoncxx/v1/exception.hpp> | ||
|
||
#include <bsoncxx/v1/document/view.hh> | ||
#include <bsoncxx/v1/element/view.hh> | ||
|
||
#include <cstdint> | ||
|
||
#include <bsoncxx/private/bson.hh> | ||
#include <bsoncxx/private/immortal.hh> | ||
#include <bsoncxx/private/itoa.hh> | ||
#include <bsoncxx/private/type_traits.hh> | ||
|
||
namespace bsoncxx { | ||
namespace v1 { | ||
namespace array { | ||
|
||
using code = v1::document::view::errc; | ||
|
||
static_assert(is_regular<view>::value, "bsoncxx::v1::array::view must be regular"); | ||
static_assert(is_semitrivial<view>::value, "bsoncxx::v1::array::view must be semitrivial"); | ||
|
||
|
@@ -30,6 +42,29 @@ static_assert( | |
is_nothrow_moveable<view::const_iterator>::value, | ||
"bsoncxx::v1::array::view::const_iterator must be nothrow moveable"); | ||
|
||
view::const_iterator view::find(std::uint32_t i) const { | ||
if (!_view) { | ||
return this->cend(); | ||
} | ||
|
||
bsoncxx::itoa key{i}; | ||
|
||
bson_t bson; | ||
|
||
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(); | ||
} | ||
Comment on lines
+54
to
+62
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is slightly different to v_noabi's |
||
|
||
return const_iterator::internal::make_const_iterator( | ||
_view.data(), _view.length(), bson_iter_offset(&iter), bson_iter_key_len(&iter)); | ||
} | ||
Comment on lines
+64
to
+66
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
||
} // namespace array | ||
} // namespace v1 | ||
} // namespace bsoncxx |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,13 +16,117 @@ | |
|
||
// | ||
|
||
#include <bsoncxx/v1/exception.hpp> | ||
|
||
#include <climits> | ||
#include <cstddef> | ||
#include <string> | ||
#include <system_error> | ||
|
||
#include <bsoncxx/private/bson.hh> | ||
#include <bsoncxx/private/immortal.hh> | ||
#include <bsoncxx/private/type_traits.hh> | ||
|
||
namespace bsoncxx { | ||
namespace v1 { | ||
|
||
using code = v1::decimal128::errc; | ||
|
||
static_assert(is_regular<decimal128>::value, "bsoncxx::v1::decimal128 must be regular"); | ||
static_assert(is_semitrivial<decimal128>::value, "bsoncxx::v1::decimal128 must be semitrivial"); | ||
|
||
decimal128::decimal128(v1::stdx::string_view sv) { | ||
if (sv.empty()) { | ||
throw v1::exception{code::empty_string}; | ||
} | ||
|
||
if (sv.size() > std::size_t{INT_MAX}) { | ||
throw v1::exception{code::invalid_string_length}; | ||
} | ||
Comment on lines
+39
to
+45
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These checks are not present in v_noabi. |
||
|
||
bson_decimal128_t d128; | ||
|
||
if (!bson_decimal128_from_string_w_len(sv.data(), static_cast<int>(sv.size()), &d128)) { | ||
throw v1::exception{code::invalid_string_data}; | ||
} | ||
|
||
_high = d128.high; | ||
_low = d128.low; | ||
} | ||
|
||
std::string decimal128::to_string() const { | ||
bson_decimal128_t d128; | ||
d128.high = _high; | ||
d128.low = _low; | ||
char str[BSON_DECIMAL128_STRING]; | ||
bson_decimal128_to_string(&d128, str); | ||
return {str}; | ||
} | ||
|
||
std::error_category const& decimal128::error_category() { | ||
class type final : public std::error_category { | ||
char const* name() const noexcept override { | ||
return "bsoncxx::v1::decimal128"; | ||
} | ||
|
||
std::string message(int v) const noexcept override { | ||
switch (static_cast<code>(v)) { | ||
case code::zero: | ||
return "zero"; | ||
case code::empty_string: | ||
return "string must not be empty"; | ||
case code::invalid_string_length: | ||
return "length of string is too long (exceeds INT_MAX)"; | ||
case code::invalid_string_data: | ||
return "string is not a valid Decimal128 representation"; | ||
default: | ||
return "unknown: " + std::to_string(v); | ||
} | ||
} | ||
|
||
bool equivalent(int v, std::error_condition const& ec) const noexcept override { | ||
if (ec.category() == v1::source_error_category()) { | ||
using condition = v1::source_errc; | ||
|
||
auto const source = static_cast<condition>(ec.value()); | ||
|
||
switch (static_cast<code>(v)) { | ||
case code::empty_string: | ||
case code::invalid_string_length: | ||
case code::invalid_string_data: | ||
return source == condition::bsoncxx; | ||
|
||
case code::zero: | ||
default: | ||
return false; | ||
} | ||
} | ||
|
||
if (ec.category() == v1::type_error_category()) { | ||
using condition = v1::type_errc; | ||
|
||
auto const type = static_cast<condition>(ec.value()); | ||
|
||
switch (static_cast<code>(v)) { | ||
case code::empty_string: | ||
case code::invalid_string_length: | ||
case code::invalid_string_data: | ||
return type == condition::invalid_argument; | ||
|
||
case code::zero: | ||
default: | ||
return false; | ||
} | ||
} | ||
|
||
return false; | ||
} | ||
}; | ||
|
||
static bsoncxx::immortal<type> const instance; | ||
|
||
return instance.value(); | ||
} | ||
|
||
} // namespace v1 | ||
} // namespace bsoncxx |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,16 +12,29 @@ | |
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
#include <bsoncxx/v1/document/view.hpp> | ||
#include <bsoncxx/v1/document/view.hh> | ||
|
||
// | ||
|
||
#include <bsoncxx/v1/exception.hpp> | ||
|
||
#include <bsoncxx/v1/element/view.hh> | ||
|
||
#include <cstdint> | ||
#include <string> | ||
#include <system_error> | ||
|
||
#include <bsoncxx/private/bson.hh> | ||
#include <bsoncxx/private/immortal.hh> | ||
#include <bsoncxx/private/itoa.hh> | ||
#include <bsoncxx/private/type_traits.hh> | ||
|
||
namespace bsoncxx { | ||
namespace v1 { | ||
namespace document { | ||
|
||
using code = v1::document::view::errc; | ||
|
||
static_assert(is_regular<view>::value, "bsoncxx::v1::document::view must be regular"); | ||
static_assert(is_semitrivial<view>::value, "bsoncxx::v1::document::view must be semitrivial"); | ||
|
||
|
@@ -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 commentThe reason will be displayed to describe this comment to others. Learn more. This is the special empty document representation that is used to avoid |
||
|
||
} // namespace | ||
|
||
view::view() : view{k_default_view} {} | ||
|
||
view::view(std::uint8_t const* data, std::size_t length) : view{data} { | ||
if (length < _empty_length || length < this->size()) { | ||
throw v1::exception{v1::document::view::errc::invalid_length}; | ||
} | ||
Comment on lines
+55
to
+57
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These checks are not present in v_noabi. This is a consequence of the new "embedded" length representation (as computed by This is the only time the |
||
} | ||
|
||
view::const_iterator view::cbegin() const { | ||
if (!this->operator bool()) { | ||
return this->cend(); | ||
} | ||
Comment on lines
+61
to
+63
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This check (and the one in |
||
|
||
bson_iter_t iter; | ||
|
||
if (!bson_iter_init_from_data(&iter, _data, this->size())) { | ||
throw v1::exception{code::invalid_data}; | ||
} | ||
|
||
if (!bson_iter_next(&iter)) { | ||
return this->cend(); | ||
} | ||
|
||
return const_iterator::internal::make_const_iterator( | ||
_data, this->size(), bson_iter_offset(&iter), bson_iter_key_len(&iter)); | ||
Comment on lines
+75
to
+76
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
} | ||
|
||
view::const_iterator view::find(v1::stdx::string_view key) const { | ||
if (!this->operator bool()) { | ||
return this->cend(); | ||
} | ||
|
||
if (key.size() >= std::size_t{INT_MAX}) { | ||
return this->cend(); | ||
} | ||
Comment on lines
+84
to
+86
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This check is not present in v_noabi. This guards the cast to |
||
|
||
// Support null as equivalent to empty. | ||
if (!key.data()) { | ||
key = ""; | ||
} | ||
Comment on lines
+88
to
+91
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Preserves v_noabi behavior. |
||
|
||
bson_t bson; | ||
|
||
if (!bson_init_static(&bson, _data, this->size())) { | ||
throw v1::exception{code::invalid_data}; | ||
} | ||
|
||
bson_iter_t iter; | ||
|
||
if (!bson_iter_init_find_w_len(&iter, &bson, key.data(), static_cast<int>(key.size()))) { | ||
return this->end(); | ||
} | ||
|
||
return const_iterator::internal::make_const_iterator( | ||
_data, this->size(), bson_iter_offset(&iter), bson_iter_key_len(&iter)); | ||
} | ||
|
||
std::error_category const& view::error_category() { | ||
class type final : public std::error_category { | ||
char const* name() const noexcept override { | ||
return "bsoncxx::v1::document::view"; | ||
} | ||
|
||
std::string message(int v) const noexcept override { | ||
switch (static_cast<code>(v)) { | ||
case code::zero: | ||
return "zero"; | ||
case code::invalid_length: | ||
return "length is invalid"; | ||
case code::invalid_data: | ||
return "data is invalid"; | ||
default: | ||
return "unknown: " + std::to_string(v); | ||
} | ||
} | ||
|
||
bool equivalent(int v, std::error_condition const& ec) const noexcept override { | ||
if (ec.category() == v1::source_error_category()) { | ||
using condition = v1::source_errc; | ||
|
||
auto const source = static_cast<condition>(ec.value()); | ||
|
||
switch (static_cast<code>(v)) { | ||
case code::invalid_length: | ||
case code::invalid_data: | ||
return source == condition::bsoncxx; | ||
|
||
case code::zero: | ||
default: | ||
return false; | ||
} | ||
} | ||
|
||
if (ec.category() == v1::type_error_category()) { | ||
using condition = v1::type_errc; | ||
|
||
auto const type = static_cast<condition>(ec.value()); | ||
|
||
switch (static_cast<code>(v)) { | ||
case code::invalid_length: | ||
return type == condition::invalid_argument; | ||
|
||
case code::invalid_data: | ||
return type == condition::runtime_error; | ||
Comment on lines
+154
to
+155
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As a reminder, |
||
|
||
case code::zero: | ||
default: | ||
return false; | ||
} | ||
} | ||
|
||
return false; | ||
} | ||
}; | ||
|
||
static bsoncxx::immortal<type> const instance; | ||
|
||
return instance.value(); | ||
} | ||
|
||
view::const_iterator& view::const_iterator::operator++() { | ||
if (!_element) { | ||
return *this; | ||
} | ||
|
||
auto iter_opt = to_bson_iter(_element); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is using ADL to invoke |
||
if (!iter_opt) { | ||
throw v1::exception{code::invalid_data}; | ||
} | ||
auto& iter = *iter_opt; | ||
|
||
if (bson_iter_next(&iter)) { | ||
_element = v1::element::view::internal::make( | ||
_element.raw(), _element.length(), bson_iter_offset(&iter), bson_iter_key_len(&iter)); | ||
} else { | ||
_element = {}; | ||
} | ||
|
||
return *this; | ||
} | ||
|
||
view::const_iterator::const_iterator(v1::element::view element) : _element(element) {} | ||
|
||
view::const_iterator view::const_iterator::internal::make_const_iterator( | ||
std::uint8_t const* raw, | ||
std::size_t length, | ||
std::uint32_t offset, | ||
std::uint32_t keylen) { | ||
return const_iterator{v1::element::view::internal::make( | ||
raw, | ||
static_cast<std::uint32_t>(length), // Guarded by `bson_init_static`. | ||
offset, | ||
keylen)}; | ||
} | ||
|
||
} // namespace document | ||
} // namespace v1 | ||
} // namespace bsoncxx |
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.