Skip to content

Commit d48afed

Browse files
authored
CXX-3077 BSON Binary Vector accessor, sub_binary builder (#1356)
* bsoncxx::builder::basic::sub_binary * binary_sub_type::k_vector * bsoncxx::vector * error_code values for use with bsoncxx::vector
1 parent 6dc4af2 commit d48afed

29 files changed

+2694
-72
lines changed

Diff for: examples/bsoncxx/bson_binary_vector.cpp

+205
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
// Copyright 2009-present MongoDB, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#include <algorithm>
16+
#include <cmath>
17+
#include <cstdlib>
18+
#include <iostream>
19+
20+
#include <bsoncxx/builder/basic/document.hpp>
21+
#include <bsoncxx/builder/basic/kvp.hpp>
22+
#include <bsoncxx/builder/basic/sub_binary.hpp>
23+
#include <bsoncxx/json.hpp>
24+
#include <bsoncxx/types.hpp>
25+
#include <bsoncxx/vector/accessor.hpp>
26+
#include <bsoncxx/vector/formats.hpp>
27+
28+
#include <examples/macros.hh>
29+
30+
int EXAMPLES_CDECL main() {
31+
using bsoncxx::binary_sub_type;
32+
using bsoncxx::builder::basic::kvp;
33+
using bsoncxx::builder::basic::make_document;
34+
using bsoncxx::builder::basic::sub_binary;
35+
using bsoncxx::vector::accessor;
36+
using bsoncxx::vector::formats::f_float32;
37+
using bsoncxx::vector::formats::f_int8;
38+
using bsoncxx::vector::formats::f_packed_bit;
39+
40+
bsoncxx::document::value doc = make_document(
41+
42+
//
43+
// Added along with BSON Binary Vector support, the new sub_binary builder
44+
// allows allocating any type of BSON Binary item in-place. A callback taking
45+
// a sub_binary argument can calculate the required space before calling allocate()
46+
// on the sub_binary to get a pointer to the new in-place allocation.
47+
//
48+
// Every byte of the allocated binary region must be written or the resulting BSON
49+
// will have undefined contents. If allocate() isn't called exactly once,
50+
// an exception will be thrown.
51+
//
52+
kvp("binary",
53+
[&](sub_binary sbin) {
54+
uint32_t len = 10;
55+
uint8_t* data = sbin.allocate(binary_sub_type::k_binary, len);
56+
memset(data, 0x55, len);
57+
}),
58+
59+
//
60+
// The sub_binary also provides an allocate() method for BSON Binary Vector.
61+
// Instead of a sub_type and byte length, this takes a vector format
62+
// and an element count.
63+
//
64+
// This example uses the f_int8 vector format, which has int8_t elements.
65+
// The allocate() call here returns a bsoncxx::vector::accessor instance
66+
// that works like a random access container but does not own memory directly.
67+
//
68+
kvp("vector_int8",
69+
[&](sub_binary sbin) {
70+
auto vec = sbin.allocate(f_int8{}, 10);
71+
int8_t i = -5;
72+
std::generate(vec.begin(), vec.end(), [&] { return ++i; });
73+
}),
74+
75+
//
76+
// BSON Binary Vector supports formats that do not map directly to C++
77+
// built-in types. The f_float32 format is an unaligned little endian
78+
// serialization of IEEE 754 32-bit binary floating point. On some platforms,
79+
// this sort of data could be accessed using a raw float*, but for consistent
80+
// portability we have a bsoncxx::v_noabi::vector::elements::float32 type which
81+
// has the unaligned little-endian representation in memory but supports automatic
82+
// conversion to and from 'float'.
83+
//
84+
// The vector accessor works like a container of floats. Elements can be assigned
85+
// from float expressions or used as float expressions. Assignment operators
86+
// operate by automatically convering to float and then back to elements::float32.
87+
//
88+
kvp("vector_float32",
89+
[&](sub_binary sbin) {
90+
auto vec = sbin.allocate(f_float32{}, 10);
91+
// Calculate a fibonacci sequence starting near the smallest representable value
92+
vec[0] = 0.f;
93+
vec[1] = 1e-38f;
94+
for (size_t i = 2; i < vec.size(); i++) {
95+
vec[i] = vec[i - 1] + vec[i - 2];
96+
}
97+
// Demonstrate assignment operators
98+
vec[0] += 1.f;
99+
vec[1] *= 1e38f;
100+
vec[1] /= 2.f;
101+
vec[1] -= 1.f + vec[0];
102+
}),
103+
104+
//
105+
// packed_bit vectors support any number of single-bit elements,
106+
// using an accessor that works like a random-access container of
107+
// bool values. This works using a reference-proxy type
108+
// bsoncxx::v_noabi::vector::elements::packed_bit_element and an iterator
109+
// bsoncxx::v_noabi::vector::iterators::packed_bit_element.
110+
//
111+
// Every bsoncxx::vector::accessor can be accessed either in per-element
112+
// or per-byte mode. Byte mode is particularly useful for applications that
113+
// may want to use packed_bit vectors in the serialized format without
114+
// accessing individual elements.
115+
//
116+
kvp("vector_packed_bit", [&](sub_binary sbin) {
117+
auto vec = sbin.allocate(f_packed_bit{}, 61);
118+
// Start by setting all bits to 1
119+
std::fill(vec.begin(), vec.end(), true);
120+
// Flip a bit using a boolean expression
121+
vec[5] = !vec[5];
122+
// Assignment of a packed_bit_element reference copies the referenced bit value
123+
vec[6] = vec[1];
124+
vec[7] = vec[5];
125+
// Bits can be assigned from boolean expressions, and from zero.
126+
vec[8] = 0;
127+
vec[60] = false;
128+
// Demonstrate addressing bits backward from the end of the vector
129+
std::fill(vec.end() - 20, vec.end() - 4, false);
130+
std::fill(vec.end() - 8, vec.end() - 5, true);
131+
// Flip all bits, operating an entire byte at a time.
132+
// The last byte will have bits that do not correspond to any elements, and writes to these are ignored.
133+
for (auto i = vec.byte_begin(); i != vec.byte_end(); i++) {
134+
*i ^= 0xFF;
135+
}
136+
// Demonstrate copying bit ranges and byte ranges using std::copy
137+
std::copy(vec.byte_begin(), vec.byte_begin() + 2, vec.byte_begin() + 2);
138+
std::copy(vec.begin() + 5, vec.begin() + 9, vec.begin() + 56);
139+
}));
140+
141+
// Demonstrate extended JSON serialization of the entire document
142+
std::cout << bsoncxx::to_json(doc) << std::endl;
143+
144+
// Iterate over elements in the int8 vector
145+
{
146+
accessor<f_int8 const> vec{doc["vector_int8"].get_binary()};
147+
std::cout << "int8: " << vec.size() << std::endl;
148+
for (auto&& i : vec) {
149+
std::cout << int{i} << " ";
150+
}
151+
std::cout << std::endl;
152+
}
153+
154+
// Iterate over bytes in the int8 vector
155+
{
156+
accessor<f_int8 const> vec{doc["vector_int8"].get_binary()};
157+
std::cout << "int8 bytes: " << vec.byte_size() << std::hex << std::endl;
158+
for (auto i = vec.byte_begin(); i != vec.byte_end(); i++) {
159+
std::cout << int{*i} << " ";
160+
}
161+
std::cout << std::dec << std::endl;
162+
}
163+
164+
// Iterate over elements in the float32 vector
165+
{
166+
accessor<f_float32 const> vec{doc["vector_float32"].get_binary()};
167+
std::cout << "float32: " << vec.size() << std::endl;
168+
for (auto&& i : vec) {
169+
std::cout << i << " ";
170+
}
171+
std::cout << std::endl;
172+
}
173+
174+
// Iterate over bytes in the float32 vector
175+
{
176+
accessor<f_float32 const> vec{doc["vector_float32"].get_binary()};
177+
std::cout << "float32 bytes: " << vec.byte_size() << std::hex << std::endl;
178+
for (auto i = vec.byte_begin(); i != vec.byte_end(); i++) {
179+
std::cout << int{*i} << " ";
180+
}
181+
std::cout << std::dec << std::endl;
182+
}
183+
184+
// Iterate over elements in the packed_bit vector
185+
{
186+
accessor<f_packed_bit const> vec{doc["vector_packed_bit"].get_binary()};
187+
std::cout << "packed_bit: " << vec.size() << std::endl;
188+
for (auto&& i : vec) {
189+
std::cout << i << " ";
190+
}
191+
std::cout << std::endl;
192+
}
193+
194+
// Iterate over bytes in the packed_bit vector
195+
{
196+
accessor<f_packed_bit const> vec{doc["vector_packed_bit"].get_binary()};
197+
std::cout << "packed_bit bytes: " << vec.byte_size() << std::hex << std::endl;
198+
for (auto i = vec.byte_begin(); i != vec.byte_end(); i++) {
199+
std::cout << int{*i} << " ";
200+
}
201+
std::cout << std::dec << std::endl;
202+
}
203+
204+
return 0;
205+
}

Diff for: src/bsoncxx/include/bsoncxx/docs/top.hpp

+10
Original file line numberDiff line numberDiff line change
@@ -88,3 +88,13 @@
8888
/// @namespace bsoncxx::types::bson_value
8989
/// Declares entities representing any BSON value type.
9090
///
91+
92+
///
93+
/// @namespace bsoncxx::vector
94+
/// Declarations related to the BSON Binary Vector subtype.
95+
///
96+
97+
///
98+
/// @namespace bsoncxx::vector::formats
99+
/// Declares supported BSON Binary Vector formats.
100+
///

Diff for: src/bsoncxx/include/bsoncxx/docs/v_noabi.hpp

+25
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,11 @@
9696
/// Provides headers declaring entities in @ref bsoncxx::v_noabi::types::bson_value.
9797
///
9898

99+
///
100+
/// @dir bsoncxx/v_noabi/bsoncxx/vector
101+
/// Provides headers declaring entities in @ref bsoncxx::v_noabi::vector.
102+
///
103+
99104
///
100105
/// @namespace bsoncxx::v_noabi
101106
/// Declares entities whose ABI stability is NOT guaranteed.
@@ -148,3 +153,23 @@
148153
/// @namespace bsoncxx::v_noabi::types::bson_value
149154
/// Declares entities representing any BSON value type.
150155
///
156+
157+
///
158+
/// @namespace bsoncxx::v_noabi::vector
159+
/// @copydoc bsoncxx::vector
160+
///
161+
162+
///
163+
/// @namespace bsoncxx::v_noabi::vector::formats
164+
/// @copydoc bsoncxx::vector::formats
165+
///
166+
167+
///
168+
/// @namespace bsoncxx::v_noabi::vector::elements
169+
/// Declares element accessor types for BSON Binary Vector.
170+
///
171+
172+
///
173+
/// @namespace bsoncxx::v_noabi::vector::iterators
174+
/// Declares iterator types for BSON Binary Vector.
175+
///

Diff for: src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/document.hpp

+4-1
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,12 @@
1414

1515
#pragma once
1616

17-
#include <bsoncxx/builder/basic/array-fwd.hpp>
1817
#include <bsoncxx/builder/basic/document-fwd.hpp>
1918

19+
//
20+
21+
#include <bsoncxx/builder/basic/array-fwd.hpp>
22+
2023
#include <bsoncxx/builder/basic/impl.hpp>
2124
#include <bsoncxx/builder/basic/kvp.hpp>
2225
#include <bsoncxx/builder/basic/sub_document.hpp>

Diff for: src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/basic/impl.hpp

+16-5
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#pragma once
1616

1717
#include <bsoncxx/builder/basic/sub_array.hpp>
18+
#include <bsoncxx/builder/basic/sub_binary.hpp>
1819
#include <bsoncxx/builder/basic/sub_document.hpp>
1920
#include <bsoncxx/stdx/type_traits.hpp>
2021

@@ -29,21 +30,31 @@ namespace impl {
2930
template <typename T>
3031
detail::requires_t<void, detail::is_invocable<T, sub_document>> generic_append(core* core, T&& func) {
3132
core->open_document();
32-
detail::invoke(std::forward<T>(func), sub_document(core));
33+
detail::invoke(std::forward<T>(func), sub_document{core});
3334
core->close_document();
3435
}
3536

3637
template <typename T, typename Placeholder = void> // placeholder 'void' for VS2015 compat
3738
detail::requires_t<void, detail::is_invocable<T, sub_array>> generic_append(core* core, T&& func) {
3839
core->open_array();
39-
detail::invoke(std::forward<T>(func), sub_array(core));
40+
detail::invoke(std::forward<T>(func), sub_array{core});
4041
core->close_array();
4142
}
4243

44+
template <typename T>
45+
detail::requires_t<void, detail::is_invocable<T, sub_binary>> generic_append(core* core, T&& func) {
46+
// Opened by the user invoking `sub_binary::allocate()` in `func`.
47+
detail::invoke(std::forward<T>(func), sub_binary{core});
48+
core->close_binary();
49+
}
50+
4351
template <typename T, typename = void, typename = void>
44-
detail::requires_not_t<void, detail::is_invocable<T, sub_document>, detail::is_invocable<T, sub_array>> generic_append(
45-
core* core,
46-
T&& t) {
52+
detail::requires_not_t<
53+
void,
54+
detail::is_invocable<T, sub_document>,
55+
detail::is_invocable<T, sub_array>,
56+
detail::is_invocable<T, sub_binary>>
57+
generic_append(core* core, T&& t) {
4758
core->append(std::forward<T>(t));
4859
}
4960

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Copyright 2009-present MongoDB, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#pragma once
16+
17+
namespace bsoncxx {
18+
namespace v_noabi {
19+
namespace builder {
20+
namespace basic {
21+
22+
class sub_binary;
23+
24+
} // namespace basic
25+
} // namespace builder
26+
} // namespace v_noabi
27+
} // namespace bsoncxx
28+
29+
namespace bsoncxx {
30+
namespace builder {
31+
namespace basic {
32+
33+
using ::bsoncxx::v_noabi::builder::basic::sub_binary;
34+
35+
} // namespace basic
36+
} // namespace builder
37+
} // namespace bsoncxx
38+
39+
///
40+
/// @file
41+
/// Declares @ref bsoncxx::v_noabi::builder::basic::sub_binary
42+
///

0 commit comments

Comments
 (0)