-
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
Changes from 12 commits
9fc87c6
b034251
e51551b
f258f76
25354e4
b2a4393
1bc5302
877cd50
9e3d254
2cfc2d7
8de4ee1
a3fd459
1a94bf7
2b76d2c
4c6b735
81fa5c0
22c67c2
4258c04
116890e
3de63ff
e5c7fa9
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}; | ||
vector-of-bool marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
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(); | ||
} | ||
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 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.
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. Good catch. Yes, it should throw |
||
|
||
return const_iterator::internal::make_const_iterator( | ||
_view.data(), _view.length(), bson_iter_offset(&iter), bson_iter_key_len(&iter)); | ||
} | ||
eramongodb marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
} // 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 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. Minor: Can this be a |
||
|
||
} // 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}; | ||
} | ||
eramongodb marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
view::const_iterator view::cbegin() const { | ||
if (!this->operator bool()) { | ||
return this->cend(); | ||
} | ||
Comment on lines
+62
to
+64
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)) { | ||
vector-of-bool marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return this->cend(); | ||
} | ||
|
||
return const_iterator::internal::make_const_iterator( | ||
_data, this->size(), bson_iter_offset(&iter), bson_iter_key_len(&iter)); | ||
eramongodb marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
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
+89
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. 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
+93
to
+96
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; | ||
eramongodb marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
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); | ||
eramongodb marked this conversation as resolved.
Show resolved
Hide resolved
|
||
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.