From 2b0af51214b15b855a5d011ce5b70e1bd32086a5 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Fri, 14 Feb 2025 15:24:12 -0800 Subject: [PATCH 01/51] Sync bson_corpus spec tests From specifications repository commit 585b797c110b6709f81def6200b946b94c8d9c55 --- .../tests/json/bson_corpus/binary.json | 30 +++++++++++++++++++ src/libbson/tests/json/bson_corpus/top.json | 4 +-- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/libbson/tests/json/bson_corpus/binary.json b/src/libbson/tests/json/bson_corpus/binary.json index 20aaef743b0..0e0056f3a2c 100644 --- a/src/libbson/tests/json/bson_corpus/binary.json +++ b/src/libbson/tests/json/bson_corpus/binary.json @@ -74,6 +74,36 @@ "description": "$type query operator (conflicts with legacy $binary form with $type field)", "canonical_bson": "180000000378001000000010247479706500020000000000", "canonical_extjson": "{\"x\" : { \"$type\" : {\"$numberInt\": \"2\"}}}" + }, + { + "description": "subtype 0x09 Vector FLOAT32", + "canonical_bson": "170000000578000A0000000927000000FE420000E04000", + "canonical_extjson": "{\"x\": {\"$binary\": {\"base64\": \"JwAAAP5CAADgQA==\", \"subType\": \"09\"}}}" + }, + { + "description": "subtype 0x09 Vector INT8", + "canonical_bson": "11000000057800040000000903007F0700", + "canonical_extjson": "{\"x\": {\"$binary\": {\"base64\": \"AwB/Bw==\", \"subType\": \"09\"}}}" + }, + { + "description": "subtype 0x09 Vector PACKED_BIT", + "canonical_bson": "11000000057800040000000910007F0700", + "canonical_extjson": "{\"x\": {\"$binary\": {\"base64\": \"EAB/Bw==\", \"subType\": \"09\"}}}" + }, + { + "description": "subtype 0x09 Vector (Zero-length) FLOAT32", + "canonical_bson": "0F0000000578000200000009270000", + "canonical_extjson": "{\"x\": {\"$binary\": {\"base64\": \"JwA=\", \"subType\": \"09\"}}}" + }, + { + "description": "subtype 0x09 Vector (Zero-length) INT8", + "canonical_bson": "0F0000000578000200000009030000", + "canonical_extjson": "{\"x\": {\"$binary\": {\"base64\": \"AwA=\", \"subType\": \"09\"}}}" + }, + { + "description": "subtype 0x09 Vector (Zero-length) PACKED_BIT", + "canonical_bson": "0F0000000578000200000009100000", + "canonical_extjson": "{\"x\": {\"$binary\": {\"base64\": \"EAA=\", \"subType\": \"09\"}}}" } ], "decodeErrors": [ diff --git a/src/libbson/tests/json/bson_corpus/top.json b/src/libbson/tests/json/bson_corpus/top.json index 7eca5aa70ca..9c649b5e3f0 100644 --- a/src/libbson/tests/json/bson_corpus/top.json +++ b/src/libbson/tests/json/bson_corpus/top.json @@ -96,11 +96,11 @@ }, { "description": "Bad $regularExpression (pattern is number, not string)", - "string": "{\"x\" : {\"$regularExpression\" : { \"pattern\": 42, \"$options\" : \"\"}}}" + "string": "{\"x\" : {\"$regularExpression\" : { \"pattern\": 42, \"options\" : \"\"}}}" }, { "description": "Bad $regularExpression (options are number, not string)", - "string": "{\"x\" : {\"$regularExpression\" : { \"pattern\": \"a\", \"$options\" : 0}}}" + "string": "{\"x\" : {\"$regularExpression\" : { \"pattern\": \"a\", \"options\" : 0}}}" }, { "description" : "Bad $regularExpression (missing pattern field)", From c22ad4ebbaf38672eef823050b8920c0ce41f96e Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Wed, 12 Feb 2025 16:44:10 -0800 Subject: [PATCH 02/51] Sync bson binary vector spec tests From specifications repository commit 585b797c110b6709f81def6200b946b94c8d9c55 --- .../json/bson_binary_vector/float32.json | 65 +++++++++++++++ .../tests/json/bson_binary_vector/int8.json | 57 +++++++++++++ .../json/bson_binary_vector/packed_bit.json | 83 +++++++++++++++++++ 3 files changed, 205 insertions(+) create mode 100644 src/libbson/tests/json/bson_binary_vector/float32.json create mode 100644 src/libbson/tests/json/bson_binary_vector/int8.json create mode 100644 src/libbson/tests/json/bson_binary_vector/packed_bit.json diff --git a/src/libbson/tests/json/bson_binary_vector/float32.json b/src/libbson/tests/json/bson_binary_vector/float32.json new file mode 100644 index 00000000000..845f504ff3c --- /dev/null +++ b/src/libbson/tests/json/bson_binary_vector/float32.json @@ -0,0 +1,65 @@ +{ + "description": "Tests of Binary subtype 9, Vectors, with dtype FLOAT32", + "test_key": "vector", + "tests": [ + { + "description": "Simple Vector FLOAT32", + "valid": true, + "vector": [127.0, 7.0], + "dtype_hex": "0x27", + "dtype_alias": "FLOAT32", + "padding": 0, + "canonical_bson": "1C00000005766563746F72000A0000000927000000FE420000E04000" + }, + { + "description": "Vector with decimals and negative value FLOAT32", + "valid": true, + "vector": [127.7, -7.7], + "dtype_hex": "0x27", + "dtype_alias": "FLOAT32", + "padding": 0, + "canonical_bson": "1C00000005766563746F72000A0000000927006666FF426666F6C000" + }, + { + "description": "Empty Vector FLOAT32", + "valid": true, + "vector": [], + "dtype_hex": "0x27", + "dtype_alias": "FLOAT32", + "padding": 0, + "canonical_bson": "1400000005766563746F72000200000009270000" + }, + { + "description": "Infinity Vector FLOAT32", + "valid": true, + "vector": ["-inf", 0.0, "inf"], + "dtype_hex": "0x27", + "dtype_alias": "FLOAT32", + "padding": 0, + "canonical_bson": "2000000005766563746F72000E000000092700000080FF000000000000807F00" + }, + { + "description": "FLOAT32 with padding", + "valid": false, + "vector": [127.0, 7.0], + "dtype_hex": "0x27", + "dtype_alias": "FLOAT32", + "padding": 3, + "canonical_bson": "1C00000005766563746F72000A0000000927030000FE420000E04000" + }, + { + "description": "Insufficient vector data with 3 bytes FLOAT32", + "valid": false, + "dtype_hex": "0x27", + "dtype_alias": "FLOAT32", + "canonical_bson": "1700000005766563746F7200050000000927002A2A2A00" + }, + { + "description": "Insufficient vector data with 5 bytes FLOAT32", + "valid": false, + "dtype_hex": "0x27", + "dtype_alias": "FLOAT32", + "canonical_bson": "1900000005766563746F7200070000000927002A2A2A2A2A00" + } + ] +} diff --git a/src/libbson/tests/json/bson_binary_vector/int8.json b/src/libbson/tests/json/bson_binary_vector/int8.json new file mode 100644 index 00000000000..29524fb6178 --- /dev/null +++ b/src/libbson/tests/json/bson_binary_vector/int8.json @@ -0,0 +1,57 @@ +{ + "description": "Tests of Binary subtype 9, Vectors, with dtype INT8", + "test_key": "vector", + "tests": [ + { + "description": "Simple Vector INT8", + "valid": true, + "vector": [127, 7], + "dtype_hex": "0x03", + "dtype_alias": "INT8", + "padding": 0, + "canonical_bson": "1600000005766563746F7200040000000903007F0700" + }, + { + "description": "Empty Vector INT8", + "valid": true, + "vector": [], + "dtype_hex": "0x03", + "dtype_alias": "INT8", + "padding": 0, + "canonical_bson": "1400000005766563746F72000200000009030000" + }, + { + "description": "Overflow Vector INT8", + "valid": false, + "vector": [128], + "dtype_hex": "0x03", + "dtype_alias": "INT8", + "padding": 0 + }, + { + "description": "Underflow Vector INT8", + "valid": false, + "vector": [-129], + "dtype_hex": "0x03", + "dtype_alias": "INT8", + "padding": 0 + }, + { + "description": "INT8 with padding", + "valid": false, + "vector": [127, 7], + "dtype_hex": "0x03", + "dtype_alias": "INT8", + "padding": 3, + "canonical_bson": "1600000005766563746F7200040000000903037F0700" + }, + { + "description": "INT8 with float inputs", + "valid": false, + "vector": [127.77, 7.77], + "dtype_hex": "0x03", + "dtype_alias": "INT8", + "padding": 0 + } + ] +} diff --git a/src/libbson/tests/json/bson_binary_vector/packed_bit.json b/src/libbson/tests/json/bson_binary_vector/packed_bit.json new file mode 100644 index 00000000000..a220e7e318e --- /dev/null +++ b/src/libbson/tests/json/bson_binary_vector/packed_bit.json @@ -0,0 +1,83 @@ +{ + "description": "Tests of Binary subtype 9, Vectors, with dtype PACKED_BIT", + "test_key": "vector", + "tests": [ + { + "description": "Padding specified with no vector data PACKED_BIT", + "valid": false, + "vector": [], + "dtype_hex": "0x10", + "dtype_alias": "PACKED_BIT", + "padding": 1, + "canonical_bson": "1400000005766563746F72000200000009100100" + }, + { + "description": "Simple Vector PACKED_BIT", + "valid": true, + "vector": [127, 7], + "dtype_hex": "0x10", + "dtype_alias": "PACKED_BIT", + "padding": 0, + "canonical_bson": "1600000005766563746F7200040000000910007F0700" + }, + { + "description": "Empty Vector PACKED_BIT", + "valid": true, + "vector": [], + "dtype_hex": "0x10", + "dtype_alias": "PACKED_BIT", + "padding": 0, + "canonical_bson": "1400000005766563746F72000200000009100000" + }, + { + "description": "PACKED_BIT with padding", + "valid": true, + "vector": [127, 7], + "dtype_hex": "0x10", + "dtype_alias": "PACKED_BIT", + "padding": 3, + "canonical_bson": "1600000005766563746F7200040000000910037F0700" + }, + { + "description": "Overflow Vector PACKED_BIT", + "valid": false, + "vector": [256], + "dtype_hex": "0x10", + "dtype_alias": "PACKED_BIT", + "padding": 0 + }, + { + "description": "Underflow Vector PACKED_BIT", + "valid": false, + "vector": [-1], + "dtype_hex": "0x10", + "dtype_alias": "PACKED_BIT", + "padding": 0 + }, + { + "description": "Vector with float values PACKED_BIT", + "valid": false, + "vector": [127.5], + "dtype_hex": "0x10", + "dtype_alias": "PACKED_BIT", + "padding": 0 + }, + { + "description": "Exceeding maximum padding PACKED_BIT", + "valid": false, + "vector": [1], + "dtype_hex": "0x10", + "dtype_alias": "PACKED_BIT", + "padding": 8, + "canonical_bson": "1500000005766563746F7200030000000910080100" + }, + { + "description": "Negative padding PACKED_BIT", + "valid": false, + "vector": [1], + "dtype_hex": "0x10", + "dtype_alias": "PACKED_BIT", + "padding": -1 + } + ] +} From 92879719c4632d81e773d14a875686ac7d413d7d Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Fri, 14 Feb 2025 13:24:07 -0800 Subject: [PATCH 03/51] New documentation pages --- src/libbson/doc/binary_vector.rst | 149 ++++++++++++++++++ .../doc/bson_append_array_from_vector.rst | 40 +++++ .../bson_append_array_from_vector_float32.rst | 40 +++++ .../bson_append_array_from_vector_int8.rst | 40 +++++ ...n_append_array_from_vector_packed_bits.rst | 40 +++++ src/libbson/doc/bson_append_binary_uninit.rst | 43 +++++ .../doc/bson_append_vector_float32.rst | 42 +++++ .../bson_append_vector_float32_from_array.rst | 45 ++++++ src/libbson/doc/bson_append_vector_int8.rst | 42 +++++ .../bson_append_vector_int8_from_array.rst | 46 ++++++ .../doc/bson_append_vector_packed_bits.rst | 42 +++++ ...n_append_vector_packed_bits_from_array.rst | 46 ++++++ ...n_array_builder_append_vector_elements.rst | 38 +++++ ...builder_append_vector_float32_elements.rst | 35 ++++ ...ay_builder_append_vector_int8_elements.rst | 35 ++++ ...der_append_vector_packed_bits_elements.rst | 35 ++++ src/libbson/doc/bson_iter_binary_equal.rst | 30 ++++ src/libbson/doc/bson_iter_binary_subtype.rst | 24 +++ .../doc/bson_iter_overwrite_binary.rst | 38 +++++ src/libbson/doc/bson_vector_error_code_t.rst | 30 ++++ ...bson_vector_float32_binary_data_length.rst | 31 ++++ ...on_vector_float32_const_view_from_iter.rst | 37 +++++ .../bson_vector_float32_const_view_init.rst | 39 +++++ .../bson_vector_float32_const_view_length.rst | 33 ++++ .../bson_vector_float32_const_view_read.rst | 41 +++++ .../doc/bson_vector_float32_const_view_t.rst | 62 ++++++++ .../doc/bson_vector_float32_view_as_const.rst | 29 ++++ .../bson_vector_float32_view_from_iter.rst | 37 +++++ .../doc/bson_vector_float32_view_init.rst | 39 +++++ .../doc/bson_vector_float32_view_length.rst | 33 ++++ .../doc/bson_vector_float32_view_read.rst | 41 +++++ .../doc/bson_vector_float32_view_t.rst | 59 +++++++ .../doc/bson_vector_float32_view_write.rst | 37 +++++ .../bson_vector_int8_binary_data_length.rst | 31 ++++ .../bson_vector_int8_const_view_from_iter.rst | 37 +++++ .../doc/bson_vector_int8_const_view_init.rst | 39 +++++ .../bson_vector_int8_const_view_length.rst | 33 ++++ .../doc/bson_vector_int8_const_view_read.rst | 41 +++++ .../doc/bson_vector_int8_const_view_t.rst | 62 ++++++++ .../doc/bson_vector_int8_view_as_const.rst | 29 ++++ .../doc/bson_vector_int8_view_from_iter.rst | 37 +++++ .../doc/bson_vector_int8_view_init.rst | 39 +++++ .../doc/bson_vector_int8_view_length.rst | 33 ++++ .../doc/bson_vector_int8_view_read.rst | 41 +++++ src/libbson/doc/bson_vector_int8_view_t.rst | 59 +++++++ .../doc/bson_vector_int8_view_write.rst | 37 +++++ ..._vector_packed_bits_binary_data_length.rst | 31 ++++ ...ector_packed_bits_const_view_from_iter.rst | 37 +++++ ...son_vector_packed_bits_const_view_init.rst | 39 +++++ ...n_vector_packed_bits_const_view_length.rst | 33 ++++ ...or_packed_bits_const_view_length_bytes.rst | 34 ++++ ..._vector_packed_bits_const_view_padding.rst | 34 ++++ ...tor_packed_bits_const_view_read_packed.rst | 45 ++++++ .../bson_vector_packed_bits_const_view_t.rst | 75 +++++++++ ...tor_packed_bits_const_view_unpack_bool.rst | 41 +++++ .../bson_vector_packed_bits_view_as_const.rst | 29 ++++ ...bson_vector_packed_bits_view_from_iter.rst | 33 ++++ .../doc/bson_vector_packed_bits_view_init.rst | 35 ++++ .../bson_vector_packed_bits_view_length.rst | 29 ++++ ...n_vector_packed_bits_view_length_bytes.rst | 30 ++++ ...bson_vector_packed_bits_view_pack_bool.rst | 37 +++++ .../bson_vector_packed_bits_view_padding.rst | 34 ++++ ...on_vector_packed_bits_view_read_packed.rst | 45 ++++++ .../doc/bson_vector_packed_bits_view_t.rst | 85 ++++++++++ ...on_vector_packed_bits_view_unpack_bool.rst | 41 +++++ ...n_vector_packed_bits_view_write_packed.rst | 45 ++++++ 66 files changed, 2728 insertions(+) create mode 100644 src/libbson/doc/binary_vector.rst create mode 100644 src/libbson/doc/bson_append_array_from_vector.rst create mode 100644 src/libbson/doc/bson_append_array_from_vector_float32.rst create mode 100644 src/libbson/doc/bson_append_array_from_vector_int8.rst create mode 100644 src/libbson/doc/bson_append_array_from_vector_packed_bits.rst create mode 100644 src/libbson/doc/bson_append_binary_uninit.rst create mode 100644 src/libbson/doc/bson_append_vector_float32.rst create mode 100644 src/libbson/doc/bson_append_vector_float32_from_array.rst create mode 100644 src/libbson/doc/bson_append_vector_int8.rst create mode 100644 src/libbson/doc/bson_append_vector_int8_from_array.rst create mode 100644 src/libbson/doc/bson_append_vector_packed_bits.rst create mode 100644 src/libbson/doc/bson_append_vector_packed_bits_from_array.rst create mode 100644 src/libbson/doc/bson_array_builder_append_vector_elements.rst create mode 100644 src/libbson/doc/bson_array_builder_append_vector_float32_elements.rst create mode 100644 src/libbson/doc/bson_array_builder_append_vector_int8_elements.rst create mode 100644 src/libbson/doc/bson_array_builder_append_vector_packed_bits_elements.rst create mode 100644 src/libbson/doc/bson_iter_binary_equal.rst create mode 100644 src/libbson/doc/bson_iter_binary_subtype.rst create mode 100644 src/libbson/doc/bson_iter_overwrite_binary.rst create mode 100644 src/libbson/doc/bson_vector_error_code_t.rst create mode 100644 src/libbson/doc/bson_vector_float32_binary_data_length.rst create mode 100644 src/libbson/doc/bson_vector_float32_const_view_from_iter.rst create mode 100644 src/libbson/doc/bson_vector_float32_const_view_init.rst create mode 100644 src/libbson/doc/bson_vector_float32_const_view_length.rst create mode 100644 src/libbson/doc/bson_vector_float32_const_view_read.rst create mode 100644 src/libbson/doc/bson_vector_float32_const_view_t.rst create mode 100644 src/libbson/doc/bson_vector_float32_view_as_const.rst create mode 100644 src/libbson/doc/bson_vector_float32_view_from_iter.rst create mode 100644 src/libbson/doc/bson_vector_float32_view_init.rst create mode 100644 src/libbson/doc/bson_vector_float32_view_length.rst create mode 100644 src/libbson/doc/bson_vector_float32_view_read.rst create mode 100644 src/libbson/doc/bson_vector_float32_view_t.rst create mode 100644 src/libbson/doc/bson_vector_float32_view_write.rst create mode 100644 src/libbson/doc/bson_vector_int8_binary_data_length.rst create mode 100644 src/libbson/doc/bson_vector_int8_const_view_from_iter.rst create mode 100644 src/libbson/doc/bson_vector_int8_const_view_init.rst create mode 100644 src/libbson/doc/bson_vector_int8_const_view_length.rst create mode 100644 src/libbson/doc/bson_vector_int8_const_view_read.rst create mode 100644 src/libbson/doc/bson_vector_int8_const_view_t.rst create mode 100644 src/libbson/doc/bson_vector_int8_view_as_const.rst create mode 100644 src/libbson/doc/bson_vector_int8_view_from_iter.rst create mode 100644 src/libbson/doc/bson_vector_int8_view_init.rst create mode 100644 src/libbson/doc/bson_vector_int8_view_length.rst create mode 100644 src/libbson/doc/bson_vector_int8_view_read.rst create mode 100644 src/libbson/doc/bson_vector_int8_view_t.rst create mode 100644 src/libbson/doc/bson_vector_int8_view_write.rst create mode 100644 src/libbson/doc/bson_vector_packed_bits_binary_data_length.rst create mode 100644 src/libbson/doc/bson_vector_packed_bits_const_view_from_iter.rst create mode 100644 src/libbson/doc/bson_vector_packed_bits_const_view_init.rst create mode 100644 src/libbson/doc/bson_vector_packed_bits_const_view_length.rst create mode 100644 src/libbson/doc/bson_vector_packed_bits_const_view_length_bytes.rst create mode 100644 src/libbson/doc/bson_vector_packed_bits_const_view_padding.rst create mode 100644 src/libbson/doc/bson_vector_packed_bits_const_view_read_packed.rst create mode 100644 src/libbson/doc/bson_vector_packed_bits_const_view_t.rst create mode 100644 src/libbson/doc/bson_vector_packed_bits_const_view_unpack_bool.rst create mode 100644 src/libbson/doc/bson_vector_packed_bits_view_as_const.rst create mode 100644 src/libbson/doc/bson_vector_packed_bits_view_from_iter.rst create mode 100644 src/libbson/doc/bson_vector_packed_bits_view_init.rst create mode 100644 src/libbson/doc/bson_vector_packed_bits_view_length.rst create mode 100644 src/libbson/doc/bson_vector_packed_bits_view_length_bytes.rst create mode 100644 src/libbson/doc/bson_vector_packed_bits_view_pack_bool.rst create mode 100644 src/libbson/doc/bson_vector_packed_bits_view_padding.rst create mode 100644 src/libbson/doc/bson_vector_packed_bits_view_read_packed.rst create mode 100644 src/libbson/doc/bson_vector_packed_bits_view_t.rst create mode 100644 src/libbson/doc/bson_vector_packed_bits_view_unpack_bool.rst create mode 100644 src/libbson/doc/bson_vector_packed_bits_view_write_packed.rst diff --git a/src/libbson/doc/binary_vector.rst b/src/libbson/doc/binary_vector.rst new file mode 100644 index 00000000000..249364232b9 --- /dev/null +++ b/src/libbson/doc/binary_vector.rst @@ -0,0 +1,149 @@ +:man_page: libbson_binary_vector + +BSON Binary Vector subtype +========================== + +In Libbson, we use the term *Vector* to refer to a data representation for compact storage of uniform elements, defined by the `BSON Binary Subtype 9 - Vector `_ specification. + +Libbson includes API support for Vectors: + +* The *view* APIs provide an efficient way to access elements of Vector fields that reside within :symbol:`bson_t` storage. +* Integration between *views* and other Libbson features: append, array builder, iter. +* Vectors can be converted to and from a plain BSON Array, subject to the specification's type conversion rules. + +The specification currently defines three element types, which Libbson interprets as: + +* ``int8``: signed integer elements, equivalent to C ``int8_t``. +* ``float32``: IEEE 754 floating point, 32 bits per element, least-significant byte first. After alignment and byte swapping, elements are equivalent to C ``float``. +* ``packed_bits``: single-bit integer elements, packed most-significant bit first. Accessible in packed form as C ``uint8_t`` or as unpacked elements using C ``bool``. + +Vector Views +------------ + +.. toctree:: + :titlesonly: + :maxdepth: 1 + + bson_vector_int8_view_t + bson_vector_int8_const_view_t + bson_vector_float32_view_t + bson_vector_float32_const_view_t + bson_vector_packed_bits_view_t + bson_vector_packed_bits_const_view_t + +Integration +----------- + +* Allocating Vectors inside :symbol:`bson_t`: + + .. toctree:: + :titlesonly: + :maxdepth: 1 + + bson_append_vector_int8 + bson_append_vector_float32 + bson_append_vector_packed_bits + +* Accessing an existing Vector via :symbol:`bson_iter_t`: + + .. code-block:: c + + #define BSON_ITER_HOLDS_VECTOR(iter) /* ... */ + #define BSON_ITER_HOLDS_VECTOR_INT8(iter) /* ... */ + #define BSON_ITER_HOLDS_VECTOR_FLOAT32(iter) /* ... */ + #define BSON_ITER_HOLDS_VECTOR_PACKED_BITS(iter) /* ... */ + + .. toctree:: + :titlesonly: + :maxdepth: 1 + + bson_vector_int8_view_from_iter + bson_vector_int8_const_view_from_iter + bson_vector_float32_view_from_iter + bson_vector_float32_const_view_from_iter + bson_vector_packed_bits_view_from_iter + bson_vector_packed_bits_const_view_from_iter + +Array Conversion +---------------- + +* Polymorphic array-from-vector: + + .. toctree:: + :titlesonly: + :maxdepth: 1 + + bson_append_array_from_vector + +* Type specific array-from-vector: + + .. toctree:: + :titlesonly: + :maxdepth: 1 + + bson_append_array_from_vector_int8 + bson_append_array_from_vector_float32 + bson_append_array_from_vector_packed_bits + +* Using :symbol:`bson_array_builder_t` for array-from-vector: + + .. toctree:: + :titlesonly: + :maxdepth: 1 + + bson_array_builder_append_vector_int8_elements + bson_array_builder_append_vector_float32_elements + bson_array_builder_append_vector_packed_bits_elements + bson_array_builder_append_vector_elements + +* Type specific vector-from-array: + + .. toctree:: + :titlesonly: + :maxdepth: 1 + + bson_append_vector_int8_from_array + bson_append_vector_float32_from_array + bson_append_vector_packed_bits_from_array + +Additional Definitions +---------------------- + +* Binary subtype: + + .. code-block:: c + + typedef enum { + BSON_SUBTYPE_VECTOR = 0x09, + /* ... */ + } bson_subtype_t; + +* Byte length of the Vector header: + + .. code-block:: c + + // Length of the required header for BSON_SUBTYPE_VECTOR, in bytes + #define BSON_VECTOR_HEADER_LEN 2 + +* Byte length for a Vector with specific element type and count: + + .. toctree:: + :titlesonly: + :maxdepth: 1 + + bson_vector_int8_binary_data_length + bson_vector_float32_binary_data_length + bson_vector_packed_bits_binary_data_length + +* Errors: + + .. code-block:: c + + // Error "domain" + #define BSON_ERROR_VECTOR 4 + + .. toctree:: + :titlesonly: + :maxdepth: 1 + + bson_vector_error_code_t diff --git a/src/libbson/doc/bson_append_array_from_vector.rst b/src/libbson/doc/bson_append_array_from_vector.rst new file mode 100644 index 00000000000..8f65922180a --- /dev/null +++ b/src/libbson/doc/bson_append_array_from_vector.rst @@ -0,0 +1,40 @@ +:man_page: bson_append_array_from_vector + +bson_append_array_from_vector() +=============================== + +Synopsis +-------- + +.. code-block:: c + + #define BSON_APPEND_ARRAY_FROM_VECTOR(b, key, iter) \ + bson_append_array_from_vector (b, key, (int) strlen (key), iter) + + bool + bson_append_array_from_vector (bson_t *bson, + const char *key, + int key_length, + const bson_iter_t *iter); + +Parameters +---------- + +* ``bson``: A :symbol:`bson_t`. +* ``key``: An ASCII C string containing the name of the field. +* ``key_length``: The length of ``key`` in bytes, or -1 to determine the length with ``strlen()``. +* ``iter``: A :symbol:`bson_iter_t` pointing to any supported :doc:`binary_vector` field. + +Description +----------- + +Converts the Vector pointed to by ``iter`` into a plain BSON Array, written to ``bson`` under the name ``key``. + +Returns +------- + +Returns ``true`` if the operation was applied successfully. The function fails if appending the array grows ``bson`` larger than INT32_MAX, or if ``iter`` doesn't point to a valid recognized Vector type. + +.. seealso:: + + | :symbol:`bson_array_builder_append_vector_elements` diff --git a/src/libbson/doc/bson_append_array_from_vector_float32.rst b/src/libbson/doc/bson_append_array_from_vector_float32.rst new file mode 100644 index 00000000000..5b012d5ecdd --- /dev/null +++ b/src/libbson/doc/bson_append_array_from_vector_float32.rst @@ -0,0 +1,40 @@ +:man_page: bson_append_array_from_vector_float32 + +bson_append_array_from_vector_float32() +======================================= + +Synopsis +-------- + +.. code-block:: c + + #define BSON_APPEND_ARRAY_FROM_VECTOR_FLOAT32(b, key, view) \ + bson_append_array_from_vector_float32 (b, key, (int) strlen (key), view) + + bool + bson_append_array_from_vector_float32 (bson_t *bson, + const char *key, + int key_length, + bson_vector_float32_const_view_t view); + +Parameters +---------- + +* ``bson``: A :symbol:`bson_t`. +* ``key``: An ASCII C string containing the name of the field. +* ``key_length``: The length of ``key`` in bytes, or -1 to determine the length with ``strlen()``. +* ``view``: A :symbol:`bson_vector_float32_const_view_t` pointing to validated ``float32`` :doc:`binary_vector` data. + +Description +----------- + +Converts the Vector pointed to by ``view`` into a plain BSON Array, written to ``bson`` under the name ``key``. + +Returns +------- + +Returns ``true`` if the operation was applied successfully. The function fails if appending the array grows ``bson`` larger than INT32_MAX. + +.. seealso:: + + | :symbol:`bson_array_builder_append_vector_float32_elements` diff --git a/src/libbson/doc/bson_append_array_from_vector_int8.rst b/src/libbson/doc/bson_append_array_from_vector_int8.rst new file mode 100644 index 00000000000..cfd55726d37 --- /dev/null +++ b/src/libbson/doc/bson_append_array_from_vector_int8.rst @@ -0,0 +1,40 @@ +:man_page: bson_append_array_from_vector_int8 + +bson_append_array_from_vector_int8() +==================================== + +Synopsis +-------- + +.. code-block:: c + + #define BSON_APPEND_ARRAY_FROM_VECTOR_INT8(b, key, view) \ + bson_append_array_from_vector_int8 (b, key, (int) strlen (key), view) + + bool + bson_append_array_from_vector_int8 (bson_t *bson, + const char *key, + int key_length, + bson_vector_int8_const_view_t view); + +Parameters +---------- + +* ``bson``: A :symbol:`bson_t`. +* ``key``: An ASCII C string containing the name of the field. +* ``key_length``: The length of ``key`` in bytes, or -1 to determine the length with ``strlen()``. +* ``view``: A :symbol:`bson_vector_int8_const_view_t` pointing to validated ``int8`` :doc:`binary_vector` data. + +Description +----------- + +Converts the Vector pointed to by ``view`` into a plain BSON Array, written to ``bson`` under the name ``key``. + +Returns +------- + +Returns ``true`` if the operation was applied successfully. The function fails if appending the array grows ``bson`` larger than INT32_MAX. + +.. seealso:: + + | :symbol:`bson_array_builder_append_vector_int8_elements` diff --git a/src/libbson/doc/bson_append_array_from_vector_packed_bits.rst b/src/libbson/doc/bson_append_array_from_vector_packed_bits.rst new file mode 100644 index 00000000000..dd4ecb5d5b9 --- /dev/null +++ b/src/libbson/doc/bson_append_array_from_vector_packed_bits.rst @@ -0,0 +1,40 @@ +:man_page: bson_append_array_from_vector_packed_bits + +bson_append_array_from_vector_packed_bits() +=========================================== + +Synopsis +-------- + +.. code-block:: c + + #define BSON_APPEND_ARRAY_FROM_VECTOR_PACKED_BITS(b, key, view) \ + bson_append_array_from_vector_packed_bits (b, key, (int) strlen (key), view) + + bool + bson_append_array_from_vector_packed_bits (bson_t *bson, + const char *key, + int key_length, + bson_vector_packed_bits_const_view_t view); + +Parameters +---------- + +* ``bson``: A :symbol:`bson_t`. +* ``key``: An ASCII C string containing the name of the field. +* ``key_length``: The length of ``key`` in bytes, or -1 to determine the length with ``strlen()``. +* ``view``: A :symbol:`bson_vector_packed_bits_const_view_t` pointing to validated ``packed_bits`` :doc:`binary_vector` data. + +Description +----------- + +Converts the Vector pointed to by ``view`` into a plain BSON Array, written to ``bson`` under the name ``key``. + +Returns +------- + +Returns ``true`` if the operation was applied successfully. The function fails if appending the array grows ``bson`` larger than INT32_MAX. + +.. seealso:: + + | :symbol:`bson_array_builder_append_vector_packed_bits_elements` diff --git a/src/libbson/doc/bson_append_binary_uninit.rst b/src/libbson/doc/bson_append_binary_uninit.rst new file mode 100644 index 00000000000..7b14213490d --- /dev/null +++ b/src/libbson/doc/bson_append_binary_uninit.rst @@ -0,0 +1,43 @@ +:man_page: bson_append_binary_uninit + +bson_append_binary_uninit() +=========================== + +Synopsis +-------- + +.. code-block:: c + + #define BSON_APPEND_BINARY_UNINIT(b, key, subtype, val, len) \ + bson_append_binary_uninit (b, key, (int) strlen (key), subtype, val, len) + + bool + bson_append_binary_uninit (bson_t *bson, + const char *key, + int key_length, + bson_subtype_t subtype, + uint8_t **binary, + uint32_t length); + +Parameters +---------- + +* ``bson``: A :symbol:`bson_t`. +* ``key``: The key name. +* ``key_length``: The length of ``key`` in bytes or -1 to use strlen(). +* ``subtype``: A bson_subtype_t indicating the binary subtype. +* ``binary``: Location for a pointer that will receive a writable pointer to the uninitialized binary data block. +* ``length``: The length of ``buffer`` in bytes. + +Description +----------- + +The :symbol:`bson_append_binary_uninit()` function is an alternative to :symbol:`bson_append_binary()` which allows applications to assemble the contents of the binary field within the :symbol:`bson_t`, without an additional temporary buffer. +On success, the caller MUST write to every byte of the binary data block if the resulting :symbol:`bson_t` is to be used. +The buffer that ``binary`` points to is only valid until the iterator's :symbol:`bson_t` is otherwise modified or freed. + + +Returns +------- + +Returns ``true`` if the uninitialized ``binary`` item was appended. The function will fail if appending ``binary`` grows ``bson`` larger than INT32_MAX. diff --git a/src/libbson/doc/bson_append_vector_float32.rst b/src/libbson/doc/bson_append_vector_float32.rst new file mode 100644 index 00000000000..22f85217e97 --- /dev/null +++ b/src/libbson/doc/bson_append_vector_float32.rst @@ -0,0 +1,42 @@ +:man_page: bson_append_vector_float32 + +bson_append_vector_float32() +============================ + +Synopsis +-------- + +.. code-block:: c + + #define BSON_APPEND_VECTOR_FLOAT32(b, key, count, view) \ + bson_append_vector_float32 (b, key, (int) strlen (key), count, view) + + bool + bson_append_vector_float32 (bson_t *bson, + const char *key, + int key_length, + size_t element_count, + bson_vector_float32_view_t *view_out); + +Parameters +---------- + +* ``bson``: A :symbol:`bson_t`. +* ``key``: An ASCII C string containing the name of the field. +* ``key_length``: The length of ``key`` in bytes, or -1 to determine the length with ``strlen()``. +* ``element_count``: Number of elements to allocate space for. +* ``view_out``: Receives a :symbol:`bson_vector_float32_view_t` with uninitialized elements. + +Description +----------- + +Appends a new field to ``bson`` by allocating a Vector with the indicated number of ``float32`` elements. +The elements will be uninitialized. +On success, the caller must write every element in the Vector if the resulting :symbol:`bson_t` is to be used. + +The pointer written to ``*view_out`` is only valid until ``bson`` is otherwise modified or freed. + +Returns +------- + +Returns ``true`` if the operation was applied successfully. The function fails if appending the array grows ``bson`` larger than INT32_MAX. diff --git a/src/libbson/doc/bson_append_vector_float32_from_array.rst b/src/libbson/doc/bson_append_vector_float32_from_array.rst new file mode 100644 index 00000000000..5f230edddb6 --- /dev/null +++ b/src/libbson/doc/bson_append_vector_float32_from_array.rst @@ -0,0 +1,45 @@ +:man_page: bson_append_vector_float32_from_array + +bson_append_vector_float32_from_array() +======================================= + +Synopsis +-------- + +.. code-block:: c + + #define BSON_APPEND_VECTOR_FLOAT32_FROM_ARRAY(b, key, iter, err) \ + bson_append_vector_float32_from_array (b, key, (int) strlen (key), iter, err) + + bool + bson_append_vector_float32_from_array (bson_t *bson, + const char *key, + int key_length, + const bson_iter_t *iter, + bson_error_t *error); + +Parameters +---------- + +* ``bson``: A :symbol:`bson_t`. +* ``key``: An ASCII C string containing the name of the field. +* ``key_length``: The length of ``key`` in bytes, or -1 to determine the length with ``strlen()``. +* ``iter``: A :symbol:`bson_iter_t` referencing array elements that will be converted. +* ``error``: Optional :symbol:`bson_error_t` for detail about conversion failures. + +Description +----------- + +Appends a new field to ``bson`` by converting an Array to a Vector of ``float32`` elements. + +For the conversion to succeed, every item in the Array must be double-precision floating point number. (``BSON_TYPE_DOUBLE``) + +The provided ``iter`` must be positioned just prior to the first element of the BSON Array. +If your input is a bare BSON Array, set up ``iter`` using :symbol:`bson_iter_init`. +If the input is within a document field, use :symbol:`bson_iter_recurse`. + +Returns +------- + +Returns ``true`` if the operation was applied successfully. On error, returns ``false`` and writes additional error information to ``error`` without modifying ``bson``. +The error will have a ``domain`` of ``BSON_ERROR_VECTOR`` and a ``code`` from :symbol:`bson_vector_error_code_t`. diff --git a/src/libbson/doc/bson_append_vector_int8.rst b/src/libbson/doc/bson_append_vector_int8.rst new file mode 100644 index 00000000000..69ca769137f --- /dev/null +++ b/src/libbson/doc/bson_append_vector_int8.rst @@ -0,0 +1,42 @@ +:man_page: bson_append_vector_int8 + +bson_append_vector_int8() +========================= + +Synopsis +-------- + +.. code-block:: c + + #define BSON_APPEND_VECTOR_INT8(b, key, count, view) \ + bson_append_vector_int8 (b, key, (int) strlen (key), count, view) + + bool + bson_append_vector_int8 (bson_t *bson, + const char *key, + int key_length, + size_t element_count, + bson_vector_int8_view_t *view_out); + +Parameters +---------- + +* ``bson``: A :symbol:`bson_t`. +* ``key``: An ASCII C string containing the name of the field. +* ``key_length``: The length of ``key`` in bytes, or -1 to determine the length with ``strlen()``. +* ``element_count``: Number of elements to allocate space for. +* ``view_out``: Receives a :symbol:`bson_vector_int8_view_t` with uninitialized elements. + +Description +----------- + +Appends a new field to ``bson`` by allocating a Vector with the indicated number of ``int8`` elements. +The elements will be uninitialized. +On success, the caller must write every element in the Vector if the resulting :symbol:`bson_t` is to be used. + +The pointer written to ``*view_out`` is only valid until ``bson`` is otherwise modified or freed. + +Returns +------- + +Returns ``true`` if the operation was applied successfully. The function fails if appending the array grows ``bson`` larger than INT32_MAX. diff --git a/src/libbson/doc/bson_append_vector_int8_from_array.rst b/src/libbson/doc/bson_append_vector_int8_from_array.rst new file mode 100644 index 00000000000..de58e09873f --- /dev/null +++ b/src/libbson/doc/bson_append_vector_int8_from_array.rst @@ -0,0 +1,46 @@ +:man_page: bson_append_vector_int8_from_array + +bson_append_vector_int8_from_array() +==================================== + +Synopsis +-------- + +.. code-block:: c + + #define BSON_APPEND_VECTOR_INT8_FROM_ARRAY(b, key, iter, err) \ + bson_append_vector_int8_from_array (b, key, (int) strlen (key), iter, err) + + bool + bson_append_vector_int8_from_array (bson_t *bson, + const char *key, + int key_length, + const bson_iter_t *iter, + bson_error_t *error); + +Parameters +---------- + +* ``bson``: A :symbol:`bson_t`. +* ``key``: An ASCII C string containing the name of the field. +* ``key_length``: The length of ``key`` in bytes, or -1 to determine the length with ``strlen()``. +* ``iter``: A :symbol:`bson_iter_t` referencing array elements that will be converted. +* ``error``: Optional :symbol:`bson_error_t` for detail about conversion failures. + +Description +----------- + +Appends a new field to ``bson`` by converting an Array to a Vector of ``int8`` elements. + +For the conversion to succeed, every item in the Array must be an integer (``BSON_TYPE_INT32`` or ``BSON_TYPE_INT64``) in the range ``INT8_MIN`` (-128) through ``INT8_MAX`` (127) inclusive. +If any element has an incorrect type or an out-of-range value, the conversion fails with an ``error`` message providing details, and no changes are made to ``bson``. + +The provided ``iter`` must be positioned just prior to the first element of the BSON Array. +If your input is a bare BSON Array, set up ``iter`` using :symbol:`bson_iter_init`. +If the input is within a document field, use :symbol:`bson_iter_recurse`. + +Returns +------- + +Returns ``true`` if the operation was applied successfully. On error, returns ``false`` and writes additional error information to ``error`` without modifying ``bson``. +The error will have a ``domain`` of ``BSON_ERROR_VECTOR`` and a ``code`` from :symbol:`bson_vector_error_code_t`. diff --git a/src/libbson/doc/bson_append_vector_packed_bits.rst b/src/libbson/doc/bson_append_vector_packed_bits.rst new file mode 100644 index 00000000000..068788f9a44 --- /dev/null +++ b/src/libbson/doc/bson_append_vector_packed_bits.rst @@ -0,0 +1,42 @@ +:man_page: bson_append_vector_packed_bits + +bson_append_vector_packed_bits() +================================ + +Synopsis +-------- + +.. code-block:: c + + #define BSON_APPEND_VECTOR_PACKED_BITS(b, key, count, view) \ + bson_append_vector_packed_bits (b, key, (int) strlen (key), count, view) + + bool + bson_append_vector_packed_bits (bson_t *bson, + const char *key, + int key_length, + size_t element_count, + bson_vector_packed_bits_view_t *view_out); + +Parameters +---------- + +* ``bson``: A :symbol:`bson_t`. +* ``key``: An ASCII C string containing the name of the field. +* ``key_length``: The length of ``key`` in bytes, or -1 to determine the length with ``strlen()``. +* ``element_count``: Number of elements to allocate space for. +* ``view_out``: Receives a :symbol:`bson_vector_packed_bits_view_t` with uninitialized elements. + +Description +----------- + +Appends a new field to ``bson`` by allocating a Vector with the indicated number of ``packed_bits`` elements. +The elements will be uninitialized. +On success, the caller must write every element in the Vector if the resulting :symbol:`bson_t` is to be used. + +The pointer written to ``*view_out`` is only valid until ``bson`` is otherwise modified or freed. + +Returns +------- + +Returns ``true`` if the operation was applied successfully. The function fails if appending the array grows ``bson`` larger than INT32_MAX. diff --git a/src/libbson/doc/bson_append_vector_packed_bits_from_array.rst b/src/libbson/doc/bson_append_vector_packed_bits_from_array.rst new file mode 100644 index 00000000000..5728fab286f --- /dev/null +++ b/src/libbson/doc/bson_append_vector_packed_bits_from_array.rst @@ -0,0 +1,46 @@ +:man_page: bson_append_vector_packed_bits_from_array + +bson_append_vector_packed_bits_from_array() +=========================================== + +Synopsis +-------- + +.. code-block:: c + + #define BSON_APPEND_VECTOR_PACKED_BITS_FROM_ARRAY(b, key, iter, err) \ + bson_append_vector_packed_bits_from_array (b, key, (int) strlen (key), iter, err) + + bool + bson_append_vector_packed_bits_from_array (bson_t *bson, + const char *key, + int key_length, + const bson_iter_t *iter, + bson_error_t *error); + +Parameters +---------- + +* ``bson``: A :symbol:`bson_t`. +* ``key``: An ASCII C string containing the name of the field. +* ``key_length``: The length of ``key`` in bytes, or -1 to determine the length with ``strlen()``. +* ``iter``: A :symbol:`bson_iter_t` referencing array elements that will be converted. +* ``error``: Optional :symbol:`bson_error_t` for detail about conversion failures. + +Description +----------- + +Appends a new field to ``bson`` by converting an Array to a Vector of ``packed_bits`` elements. + +For the conversion to succeed, every item in the Array must be either an integer (``BSON_TYPE_INT32`` or ``BSON_TYPE_INT64``) with the values ``0`` or ``1``, or boolean (``BSON_TYPE_BOOL``). +If any element has an incorrect type or an out-of-range value, the conversion fails with an ``error`` message providing details, and no changes are made to ``bson``. + +The provided ``iter`` must be positioned just prior to the first element of the BSON Array. +If your input is a bare BSON Array, set up ``iter`` using :symbol:`bson_iter_init`. +If the input is within a document field, use :symbol:`bson_iter_recurse`. + +Returns +------- + +Returns ``true`` if the operation was applied successfully. On error, returns ``false`` and writes additional error information to ``error`` without modifying ``bson``. +The error will have a ``domain`` of ``BSON_ERROR_VECTOR`` and a ``code`` from :symbol:`bson_vector_error_code_t`. diff --git a/src/libbson/doc/bson_array_builder_append_vector_elements.rst b/src/libbson/doc/bson_array_builder_append_vector_elements.rst new file mode 100644 index 00000000000..1de13a7ccd7 --- /dev/null +++ b/src/libbson/doc/bson_array_builder_append_vector_elements.rst @@ -0,0 +1,38 @@ +:man_page: bson_array_builder_append_vector_elements + +bson_array_builder_append_vector_elements() +=========================================== + +Synopsis +-------- + +.. code-block:: c + + bool + bson_array_builder_append_vector_elements (bson_array_builder_t *builder, + const bson_iter_t *iter); + +Parameters +---------- + +* ``builder``: A valid :symbol:`bson_array_builder_t`. +* ``iter``: A :symbol:`bson_iter_t` pointing to any supported :doc:`binary_vector` field. + +Description +----------- + +Converts the Vector pointed to by ``iter`` into elements of a plain BSON Array, written to ``builder``. +This conversion is polymorphic: A converted element type will be chosen based on the type of the input Vector. +For details, see the type-specific versions of this function. + +Returns +------- + +Returns ``true`` if the operation was applied successfully. The function fails if appending the array grows ``bson`` larger than INT32_MAX, or if ``iter`` doesn't point to a valid recognized Vector type. + +.. seealso:: + + | :symbol:`bson_append_array_from_vector` + | :symbol:`bson_array_builder_append_vector_int8_elements` + | :symbol:`bson_array_builder_append_vector_float32_elements` + | :symbol:`bson_array_builder_append_vector_packed_bits_elements` diff --git a/src/libbson/doc/bson_array_builder_append_vector_float32_elements.rst b/src/libbson/doc/bson_array_builder_append_vector_float32_elements.rst new file mode 100644 index 00000000000..cc798474aab --- /dev/null +++ b/src/libbson/doc/bson_array_builder_append_vector_float32_elements.rst @@ -0,0 +1,35 @@ +:man_page: bson_array_builder_append_vector_float32_elements + +bson_array_builder_append_vector_float32_elements() +=================================================== + +Synopsis +-------- + +.. code-block:: c + + bool + bson_array_builder_append_vector_float32_elements (bson_array_builder_t *builder, + bson_vector_float32_const_view_t view); + +Parameters +---------- + +* ``builder``: A valid :symbol:`bson_array_builder_t`. +* ``view``: A :symbol:`bson_vector_float32_const_view_t` pointing to validated ``float32`` :doc:`binary_vector` data. + +Description +----------- + +Converts the Vector pointed to by ``view`` into elements of a plain BSON Array, written to ``builder``. +Every element will be converted from ``float`` to ``double`` precision. + +Returns +------- + +Returns ``true`` if the operation was applied successfully. The function fails if appending the array grows ``bson`` larger than INT32_MAX. + +.. seealso:: + + | :symbol:`bson_append_array_from_vector` + | :symbol:`bson_array_builder_append_vector_elements` diff --git a/src/libbson/doc/bson_array_builder_append_vector_int8_elements.rst b/src/libbson/doc/bson_array_builder_append_vector_int8_elements.rst new file mode 100644 index 00000000000..477835309ab --- /dev/null +++ b/src/libbson/doc/bson_array_builder_append_vector_int8_elements.rst @@ -0,0 +1,35 @@ +:man_page: bson_array_builder_append_vector_int8_elements + +bson_array_builder_append_vector_int8_elements() +================================================ + +Synopsis +-------- + +.. code-block:: c + + bool + bson_array_builder_append_vector_int8_elements (bson_array_builder_t *builder, + bson_vector_int8_const_view_t view); + +Parameters +---------- + +* ``builder``: A valid :symbol:`bson_array_builder_t`. +* ``view``: A :symbol:`bson_vector_int8_const_view_t` pointing to validated ``int8`` :doc:`binary_vector` data. + +Description +----------- + +Converts the Vector pointed to by ``view`` into elements of a plain BSON Array, written to ``builder``. +Every element will be losslessly extended from ``int8_t`` to ``int32_t``. + +Returns +------- + +Returns ``true`` if the operation was applied successfully. The function fails if appending the array grows ``bson`` larger than INT32_MAX. + +.. seealso:: + + | :symbol:`bson_append_array_from_vector` + | :symbol:`bson_array_builder_append_vector_elements` diff --git a/src/libbson/doc/bson_array_builder_append_vector_packed_bits_elements.rst b/src/libbson/doc/bson_array_builder_append_vector_packed_bits_elements.rst new file mode 100644 index 00000000000..36b6afc1085 --- /dev/null +++ b/src/libbson/doc/bson_array_builder_append_vector_packed_bits_elements.rst @@ -0,0 +1,35 @@ +:man_page: bson_array_builder_append_vector_packed_bits_elements + +bson_array_builder_append_vector_packed_bits_elements() +======================================================= + +Synopsis +-------- + +.. code-block:: c + + bool + bson_array_builder_append_vector_packed_bits_elements (bson_array_builder_t *builder, + bson_vector_packed_bits_const_view_t view); + +Parameters +---------- + +* ``builder``: A valid :symbol:`bson_array_builder_t`. +* ``view``: A :symbol:`bson_vector_packed_bits_const_view_t` pointing to validated ``packed_bits`` :doc:`binary_vector` data. + +Description +----------- + +Converts the Vector pointed to by ``view`` into elements of a plain BSON Array, written to ``builder``. +Every element will be ``0`` or ``1`` written as a ``BSON_TYPE_INT32``. + +Returns +------- + +Returns ``true`` if the operation was applied successfully. The function fails if appending the array grows ``bson`` larger than INT32_MAX. + +.. seealso:: + + | :symbol:`bson_append_array_from_vector` + | :symbol:`bson_array_builder_append_vector_elements` diff --git a/src/libbson/doc/bson_iter_binary_equal.rst b/src/libbson/doc/bson_iter_binary_equal.rst new file mode 100644 index 00000000000..13e6284de31 --- /dev/null +++ b/src/libbson/doc/bson_iter_binary_equal.rst @@ -0,0 +1,30 @@ +:man_page: bson_iter_binary_equal + +bson_iter_binary_equal() +======================== + +Synopsis +-------- + +.. code-block:: c + + bool + bson_iter_binary_equal (const bson_iter_t *iter_a, const bson_iter_t *iter_b); + +Parameters +---------- + +* ``iter_a``: A :symbol:`bson_iter_t`. +* ``iter_b``: A :symbol:`bson_iter_t`. + +Description +----------- + +Compare two BSON_TYPE_BINARY fields for exact equality. + +This is the preferred way to compare :doc:`binary_vector` values for equality. + +Returns +------- + +``true`` if both iterators point to BSON_TYPE_BINARY fields with identical subtype and contents. ``false`` if there is any difference in subtype, length, or content, or if the fields are not binary type. \ No newline at end of file diff --git a/src/libbson/doc/bson_iter_binary_subtype.rst b/src/libbson/doc/bson_iter_binary_subtype.rst new file mode 100644 index 00000000000..615e4234a25 --- /dev/null +++ b/src/libbson/doc/bson_iter_binary_subtype.rst @@ -0,0 +1,24 @@ +:man_page: bson_iter_binary_subtype + +bson_iter_binary_subtype() +========================== + +Synopsis +-------- + +.. code-block:: c + + bson_subtype_t + bson_iter_binary_subtype (const bson_iter_t *iter); + +Parameters +---------- + +* ``iter``: A :symbol:`bson_iter_t`. + +Description +----------- + +This function shall return the subtype of a BSON_TYPE_BINARY element. It is a programming error to call this function on a field that is not of type BSON_TYPE_BINARY. You can check this with the BSON_ITER_HOLDS_BINARY() macro or :symbol:`bson_iter_type()`. + +Equivalent to the ``subtype`` output parameter of :symbol:`bson_iter_binary`. diff --git a/src/libbson/doc/bson_iter_overwrite_binary.rst b/src/libbson/doc/bson_iter_overwrite_binary.rst new file mode 100644 index 00000000000..a41385f327c --- /dev/null +++ b/src/libbson/doc/bson_iter_overwrite_binary.rst @@ -0,0 +1,38 @@ +:man_page: bson_iter_overwrite_binary + +bson_iter_overwrite_binary() +============================ + +Synopsis +-------- + +.. code-block:: c + + void + bson_iter_overwrite_binary (bson_iter_t *iter, + bson_subtype_t subtype, + uint32_t *binary_len, + uint8_t **binary); + +Parameters +---------- + +* ``iter``: A :symbol:`bson_iter_t`. +* ``subtype``: The expected :symbol:`bson_subtype_t`. +* ``binary_len``: A location for the length of ``binary``. +* ``binary``: A location for a pointer to the mutable buffer. + +Description +----------- + +The ``bson_iter_overwrite_binary()`` function obtains mutable access to a BSON_TYPE_BINARY element in place. + +This may only be done when the underlying bson document allows mutation. + +It is a programming error to call this function when ``iter`` is not observing an element of type BSON_TYPE_BINARY and the provided ``subtype``. + +The buffer that ``binary`` points to is only valid until the iterator's :symbol:`bson_t` is otherwise modified or freed. + +.. seealso:: + + | :symbol:`bson_iter_binary` diff --git a/src/libbson/doc/bson_vector_error_code_t.rst b/src/libbson/doc/bson_vector_error_code_t.rst new file mode 100644 index 00000000000..2e7b63db5b0 --- /dev/null +++ b/src/libbson/doc/bson_vector_error_code_t.rst @@ -0,0 +1,30 @@ +:man_page: bson_vector_error_code_t + +bson_vector_error_code_t +======================== + +BSON Error codes for :doc:`binary_vector` operations that could fail in multiple ways. + +Synopsis +-------- + +.. code-block:: c + + #define BSON_ERROR_VECTOR 4 + + typedef enum { + BSON_VECTOR_ERROR_ARRAY_ELEMENT_TYPE = 1, + BSON_VECTOR_ERROR_ARRAY_ELEMENT_VALUE = 2, + BSON_VECTOR_ERROR_ARRAY_KEY = 3, + BSON_VECTOR_ERROR_MAX_SIZE = 4, + } bson_vector_error_code_t; + +Description +----------- + +The error ``code`` values in ``bson_vector_error_code_t`` apply to :symbol:`bson_error_t` values with a ``category`` of ``BSON_ERROR_CATEGORY`` and a ``domain`` of ``BSON_ERROR_VECTOR``. + +* ``BSON_VECTOR_ERROR_ARRAY_ELEMENT_TYPE``: An element was encountered with incorrect type. Location and type details in ``message``. +* ``BSON_VECTOR_ERROR_ARRAY_ELEMENT_VALUE``: An element was encountered with out-of-range value. Location and value details in ``message``. +* ``BSON_VECTOR_ERROR_ARRAY_KEY``: An input BSON Array did not contain the expected numeric key value. Expected and actual keys in ``message``. +* ``BSON_VECTOR_ERROR_MAX_SIZE``: The BSON maximum document size would be exceeded. Equivalent to a failure from ``bson_append_*`` functions that do not return an ``error``. diff --git a/src/libbson/doc/bson_vector_float32_binary_data_length.rst b/src/libbson/doc/bson_vector_float32_binary_data_length.rst new file mode 100644 index 00000000000..77676801efa --- /dev/null +++ b/src/libbson/doc/bson_vector_float32_binary_data_length.rst @@ -0,0 +1,31 @@ +:man_page: bson_vector_float32_binary_data_length + +bson_vector_float32_binary_data_length() +======================================== + +Calculate the size of a BSON Binary field that would be needed to store a Vector with the indicated number of ``float32`` elements. + +Synopsis +-------- + +.. code-block:: c + + uint32_t + bson_vector_float32_binary_data_length (size_t element_count); + +Parameters +---------- + +* ``element_count``: Number of elements, as a ``size_t``. + +Description +----------- + +Checks ``element_count`` against the maximum representable size, and calculates the required Binary size. + +Returns +------- + +On success, returns the required Binary size as a ``uint32_t`` greater than or equal to ``BSON_VECTOR_HEADER_LEN``. +This length includes the 2-byte Vector header, but not the Binary subtype header or any other BSON headers. +If the ``element_count`` is too large to represent, returns 0. diff --git a/src/libbson/doc/bson_vector_float32_const_view_from_iter.rst b/src/libbson/doc/bson_vector_float32_const_view_from_iter.rst new file mode 100644 index 00000000000..5a1934be727 --- /dev/null +++ b/src/libbson/doc/bson_vector_float32_const_view_from_iter.rst @@ -0,0 +1,37 @@ +:man_page: bson_vector_float32_const_view_from_iter + +bson_vector_float32_const_view_from_iter() +========================================== + +Initialize a :symbol:`bson_vector_float32_const_view_t` from a :symbol:`bson_iter_t` pointing to a valid Vector of ``float32`` element type. + +Synopsis +-------- + +.. code-block:: c + + bool + bson_vector_float32_const_view_from_iter (bson_vector_float32_const_view_t *view_out, + const bson_iter_t *iter); + +Parameters +---------- + +* ``view_out``: A :symbol:`bson_vector_float32_const_view_t` is written here on success. +* ``iter``: A valid :symbol:`bson_iter_t`. + +Description +----------- + +The provided iterator, which must point to some kind of BSON item, will be checked for a valid Vector of ``float32`` element type. +On success, a :symbol:`bson_vector_float32_const_view_t` is set to point to the same underlying :symbol:`bson_t` buffer as the provided :symbol:`bson_iter_t`. +The view will only be valid until the containing document is destroyed or modified. + +Returns +------- + +Returns true if the view was successfully initialized. + +.. seealso:: + + | :symbol:`bson_vector_float32_view_from_iter` diff --git a/src/libbson/doc/bson_vector_float32_const_view_init.rst b/src/libbson/doc/bson_vector_float32_const_view_init.rst new file mode 100644 index 00000000000..db8f872d154 --- /dev/null +++ b/src/libbson/doc/bson_vector_float32_const_view_init.rst @@ -0,0 +1,39 @@ +:man_page: bson_vector_float32_const_view_init + +bson_vector_float32_const_view_init() +===================================== + +Initialize a :symbol:`bson_vector_float32_const_view_t` from a const ``uint8_t`` buffer. + +Synopsis +-------- + +.. code-block:: c + + bool + bson_vector_float32_const_view_init (bson_vector_float32_const_view_t *view_out, + const uint8_t *binary_data, + uint32_t binary_data_len); + +Parameters +---------- + +* ``view_out``: A :symbol:`bson_vector_float32_const_view_t` is written here on success. +* ``binary_data``: A pointer to the BSON Binary data block to be validated. +* ``binary_data_len``: Length of the binary data block, in bytes. + +Description +----------- + +The length and header of the provided binary data block will be checked for a valid Vector of ``float32`` element type. +On success, the pointer and length are packaged as a :symbol:`bson_vector_float32_const_view_t` written to ``*view_out``. +The view will only be valid as long as ``binary_data`` is valid. + +Returns +------- + +Returns true if the view was successfully initialized. + +.. seealso:: + + | :symbol:`bson_vector_float32_view_init` diff --git a/src/libbson/doc/bson_vector_float32_const_view_length.rst b/src/libbson/doc/bson_vector_float32_const_view_length.rst new file mode 100644 index 00000000000..e7288377eb5 --- /dev/null +++ b/src/libbson/doc/bson_vector_float32_const_view_length.rst @@ -0,0 +1,33 @@ +:man_page: bson_vector_float32_const_view_length + +bson_vector_float32_const_view_length() +======================================= + +Return the number of elements in a Vector referenced by a :symbol:`bson_vector_float32_const_view_t`. + +Synopsis +-------- + +.. code-block:: c + + size_t + bson_vector_float32_const_view_length (bson_vector_float32_const_view_t view); + +Parameters +---------- + +* ``view``: A valid :symbol:`bson_vector_float32_const_view_t`. + +Description +----------- + +An element count is calculated from the view's stored binary block length. + +Returns +------- + +The number of elements, as a ``size_t``. + +.. seealso:: + + | :symbol:`bson_vector_float32_view_length` diff --git a/src/libbson/doc/bson_vector_float32_const_view_read.rst b/src/libbson/doc/bson_vector_float32_const_view_read.rst new file mode 100644 index 00000000000..536d70c6b6f --- /dev/null +++ b/src/libbson/doc/bson_vector_float32_const_view_read.rst @@ -0,0 +1,41 @@ +:man_page: bson_vector_float32_const_view_read + +bson_vector_float32_const_view_read() +===================================== + +Copy a contiguous block of elements from a :symbol:`bson_vector_float32_const_view_t` into a C array of ``float``. + +Synopsis +-------- + +.. code-block:: c + + bool + bson_vector_float32_const_view_read (bson_vector_float32_const_view_t view, + float *values_out, + size_t element_count, + size_t vector_offset_elements); + +Parameters +---------- + +* ``view``: A valid :symbol:`bson_vector_float32_const_view_t`. +* ``values_out``: Location where the ``float`` elements will be read to. +* ``element_count``: Number of elements to read. +* ``vector_offset_elements``: The vector index of the first element to read. + +Description +----------- + +Elements are copied in bulk from the view to the provided output pointer. + +Returns +------- + +If the ``element_count`` and ``vector_offset_elements`` parameters overflow the bounds of the Vector, returns false without taking any other action. +If the parameters are in range, this is guaranteed to succeed. +On success, returns true and reads ``element_count`` elements into ``*values_out``. + +.. seealso:: + + | :symbol:`bson_vector_float32_view_read` diff --git a/src/libbson/doc/bson_vector_float32_const_view_t.rst b/src/libbson/doc/bson_vector_float32_const_view_t.rst new file mode 100644 index 00000000000..94102e731d9 --- /dev/null +++ b/src/libbson/doc/bson_vector_float32_const_view_t.rst @@ -0,0 +1,62 @@ +:man_page: bson_vector_float32_const_view_t + +bson_vector_float32_const_view_t +================================ + +A reference to non-owned const BSON Binary data holding a valid Vector of ``float32`` element type. + +Synopsis +-------- + +.. code-block:: c + + #include + + typedef struct bson_vector_float32_const_view_t { + /*< private >*/ + } bson_vector_float32_const_view_t; + +Description +----------- + +:symbol:`bson_vector_float32_const_view_t` is a structure that acts as an opaque const reference to a block of memory that has been validated as a ``float32`` vector. + +It is meant to be passed by value and can be discarded at any time. The contents of the structure should be considered private. + +The :symbol:`bson_t` *MUST* be valid for the lifetime of the view and it is an error to modify the :symbol:`bson_t` while using the view. + +.. only:: html + + Functions + --------- + + .. toctree:: + :titlesonly: + :maxdepth: 1 + + bson_vector_float32_const_view_init + bson_vector_float32_const_view_from_iter + bson_vector_float32_const_view_length + bson_vector_float32_const_view_read + +Example +------- + +.. code-block:: c + + bson_iter_t iter; + bson_vector_float32_const_view_t view; + + if (bson_iter_init_find (&iter, &doc, "vector") && bson_vector_float32_const_view_from_iter (&view, &iter)) { + size_t length = bson_vector_float32_const_view_length (view); + printf ("Elements in 'vector':\n"); + for (size_t i = 0; i < length; i++) { + float element; + BSON_ASSERT (bson_vector_float32_const_view_read (view, &element, 1, i)); + printf (" [%d] = %f\n", (int) i, element); + } + } + +.. seealso:: + + | :symbol:`bson_vector_float32_view_t` diff --git a/src/libbson/doc/bson_vector_float32_view_as_const.rst b/src/libbson/doc/bson_vector_float32_view_as_const.rst new file mode 100644 index 00000000000..f86774c5a9d --- /dev/null +++ b/src/libbson/doc/bson_vector_float32_view_as_const.rst @@ -0,0 +1,29 @@ +:man_page: bson_vector_float32_view_as_const + +bson_vector_float32_view_as_const() +=================================== + +Convert a :symbol:`bson_vector_float32_view_t` into a :symbol:`bson_vector_float32_const_view_t`. + +Synopsis +-------- + +.. code-block:: c + + bson_vector_float32_const_view_t + bson_vector_float32_view_as_const (bson_vector_float32_view_t view); + +Parameters +---------- + +* ``view``: A valid :symbol:`bson_vector_float32_view_t`. + +Description +----------- + +This adds a ``const`` qualifier to the view without re-validating the underlying data. + +Returns +------- + +Always returns a :symbol:`bson_vector_float32_const_view_t`. diff --git a/src/libbson/doc/bson_vector_float32_view_from_iter.rst b/src/libbson/doc/bson_vector_float32_view_from_iter.rst new file mode 100644 index 00000000000..8c2b0a9dcae --- /dev/null +++ b/src/libbson/doc/bson_vector_float32_view_from_iter.rst @@ -0,0 +1,37 @@ +:man_page: bson_vector_float32_view_from_iter + +bson_vector_float32_view_from_iter() +==================================== + +Initialize a :symbol:`bson_vector_float32_view_t` from a :symbol:`bson_iter_t` pointing to a valid Vector of ``float32`` element type. + +Synopsis +-------- + +.. code-block:: c + + bool + bson_vector_float32_view_from_iter (bson_vector_float32_view_t *view_out, + bson_iter_t *iter); + +Parameters +---------- + +* ``view_out``: A :symbol:`bson_vector_float32_view_t` is written here on success. +* ``iter``: A valid :symbol:`bson_iter_t`. + +Description +----------- + +The provided iterator, which must point to some kind of BSON item, will be checked for a valid Vector of ``float32`` element type. +On success, a :symbol:`bson_vector_float32_view_t` is set to point to the same underlying :symbol:`bson_t` buffer as the provided :symbol:`bson_iter_t`. +The view will only be valid until the containing document is destroyed or otherwise modified. + +Returns +------- + +Returns true if the view was successfully initialized. + +.. seealso:: + + | :symbol:`bson_vector_float32_const_view_from_iter` diff --git a/src/libbson/doc/bson_vector_float32_view_init.rst b/src/libbson/doc/bson_vector_float32_view_init.rst new file mode 100644 index 00000000000..77d0aab630a --- /dev/null +++ b/src/libbson/doc/bson_vector_float32_view_init.rst @@ -0,0 +1,39 @@ +:man_page: bson_vector_float32_view_init + +bson_vector_float32_view_init() +=============================== + +Initialize a :symbol:`bson_vector_float32_view_t` from a mutable ``uint8_t`` buffer. + +Synopsis +-------- + +.. code-block:: c + + bool + bson_vector_float32_view_init (bson_vector_float32_view_t *view_out, + uint8_t *binary_data, + uint32_t binary_data_len); + +Parameters +---------- + +* ``view_out``: A :symbol:`bson_vector_float32_view_t` is written here on success. +* ``binary_data``: A pointer to the BSON Binary data block to be validated. +* ``binary_data_len``: Length of the binary data block, in bytes. + +Description +----------- + +The length and header of the provided binary data block will be checked for a valid Vector of ``float32`` element type. +On success, the pointer and length are packaged as a :symbol:`bson_vector_float32_view_t` written to ``*view_out``. +The view will only be valid as long as ``binary_data`` is valid. + +Returns +------- + +Returns true if the view was successfully initialized. + +.. seealso:: + + | :symbol:`bson_vector_float32_const_view_init` diff --git a/src/libbson/doc/bson_vector_float32_view_length.rst b/src/libbson/doc/bson_vector_float32_view_length.rst new file mode 100644 index 00000000000..8ac74234951 --- /dev/null +++ b/src/libbson/doc/bson_vector_float32_view_length.rst @@ -0,0 +1,33 @@ +:man_page: bson_vector_float32_view_length + +bson_vector_float32_view_length() +================================= + +Return the number of elements in a Vector referenced by a :symbol:`bson_vector_float32_view_t`. + +Synopsis +-------- + +.. code-block:: c + + size_t + bson_vector_float32_view_length (bson_vector_float32_view_t view); + +Parameters +---------- + +* ``view``: A valid :symbol:`bson_vector_float32_view_t`. + +Description +----------- + +An element count is calculated from the view's stored binary block length. + +Returns +------- + +The number of elements, as a ``size_t``. + +.. seealso:: + + | :symbol:`bson_vector_float32_const_view_length` diff --git a/src/libbson/doc/bson_vector_float32_view_read.rst b/src/libbson/doc/bson_vector_float32_view_read.rst new file mode 100644 index 00000000000..fe6db04148a --- /dev/null +++ b/src/libbson/doc/bson_vector_float32_view_read.rst @@ -0,0 +1,41 @@ +:man_page: bson_vector_float32_view_read + +bson_vector_float32_view_read() +=============================== + +Copy a contiguous block of elements from a :symbol:`bson_vector_float32_view_t` into a C array of ``float``. + +Synopsis +-------- + +.. code-block:: c + + bool + bson_vector_float32_view_read (bson_vector_float32_view_t view, + float *values_out, + size_t element_count, + size_t vector_offset_elements); + +Parameters +---------- + +* ``view``: A valid :symbol:`bson_vector_float32_view_t`. +* ``values_out``: Location where the ``float`` elements will be read to. +* ``element_count``: Number of elements to read. +* ``vector_offset_elements``: The vector index of the first element to read. + +Description +----------- + +Elements are copied in bulk from the view to the provided output pointer. + +Returns +------- + +If the ``element_count`` and ``vector_offset_elements`` parameters overflow the bounds of the Vector, returns false without taking any other action. +If the parameters are in range, this is guaranteed to succeed. +On success, returns true and reads ``element_count`` elements into ``*values_out``. + +.. seealso:: + + | :symbol:`bson_vector_float32_const_view_read` diff --git a/src/libbson/doc/bson_vector_float32_view_t.rst b/src/libbson/doc/bson_vector_float32_view_t.rst new file mode 100644 index 00000000000..7dabfc8d5ba --- /dev/null +++ b/src/libbson/doc/bson_vector_float32_view_t.rst @@ -0,0 +1,59 @@ +:man_page: bson_vector_float32_view_t + +bson_vector_float32_view_t +========================== + +A reference to mutable non-owned BSON Binary data holding a valid Vector of ``float32`` element type. + +Synopsis +-------- + +.. code-block:: c + + #include + + typedef struct bson_vector_float32_view_t { + /*< private >*/ + } bson_vector_float32_view_t; + +Description +----------- + +:symbol:`bson_vector_float32_view_t` is a structure that acts as an opaque reference to a block of memory that has been validated as a ``float32`` vector. + +It is meant to be passed by value and can be discarded at any time. The contents of the structure should be considered private. + +The :symbol:`bson_t` *MUST* be valid for the lifetime of the view and it is an error to modify the :symbol:`bson_t` while using the view. + +.. only:: html + + Functions + --------- + + .. toctree:: + :titlesonly: + :maxdepth: 1 + + bson_vector_float32_view_init + bson_vector_float32_view_from_iter + bson_vector_float32_view_as_const + bson_vector_float32_view_length + bson_vector_float32_view_read + bson_vector_float32_view_write + +Example +------- + +.. code-block:: c + + static const float values[] = {1.0f, 2.0f, 3.0f}; + const size_t values_count = sizeof values / sizeof values[0]; + + bson_vector_float32_view_t view; + BSON_ASSERT (BSON_APPEND_VECTOR_FLOAT32 (&doc, "vector", values_count, &view)); + BSON_ASSERT (bson_vector_float32_view_write (view, values, values_count, 0)); + +.. seealso:: + + | :symbol:`bson_append_vector_float32` + | :symbol:`bson_vector_float32_const_view_t` diff --git a/src/libbson/doc/bson_vector_float32_view_write.rst b/src/libbson/doc/bson_vector_float32_view_write.rst new file mode 100644 index 00000000000..84788183bfb --- /dev/null +++ b/src/libbson/doc/bson_vector_float32_view_write.rst @@ -0,0 +1,37 @@ +:man_page: bson_vector_float32_view_write + +bson_vector_float32_view_write() +================================ + +Copy a contiguous block of elements from a C ``float`` array into a :symbol:`bson_vector_float32_view_t`. + +Synopsis +-------- + +.. code-block:: c + + bool + bson_vector_float32_view_write (bson_vector_float32_view_t view, + const float *values, + size_t element_count, + size_t vector_offset_elements) + +Parameters +---------- + +* ``view``: A valid :symbol:`bson_vector_float32_view_t`. +* ``values``: Location where the ``float`` elements will be copied from. +* ``element_count``: Number of elements to write. +* ``vector_offset_elements``: The vector index of the first element to write. + +Description +----------- + +Elements are copied in bulk from the provided pointer into the view. + +Returns +------- + +If the ``element_count`` and ``vector_offset_elements`` parameters overflow the bounds of the Vector, returns false without taking any other action. +If the parameters are in range, this is guaranteed to succeed. +On success, returns true and writes to ``element_count`` elements in the Vector starting at ``vector_offset_elements``. diff --git a/src/libbson/doc/bson_vector_int8_binary_data_length.rst b/src/libbson/doc/bson_vector_int8_binary_data_length.rst new file mode 100644 index 00000000000..cc4dbd4fb3f --- /dev/null +++ b/src/libbson/doc/bson_vector_int8_binary_data_length.rst @@ -0,0 +1,31 @@ +:man_page: bson_vector_int8_binary_data_length + +bson_vector_int8_binary_data_length() +===================================== + +Calculate the size of a BSON Binary field that would be needed to store a Vector with the indicated number of ``int8`` elements. + +Synopsis +-------- + +.. code-block:: c + + uint32_t + bson_vector_int8_binary_data_length (size_t element_count); + +Parameters +---------- + +* ``element_count``: Number of elements, as a ``size_t``. + +Description +----------- + +Checks ``element_count`` against the maximum representable size, and calculates the required Binary size. + +Returns +------- + +On success, returns the required Binary size as a ``uint32_t`` greater than or equal to ``BSON_VECTOR_HEADER_LEN``. +This length includes the 2-byte Vector header, but not the Binary subtype header or any other BSON headers. +If the ``element_count`` is too large to represent, returns 0. diff --git a/src/libbson/doc/bson_vector_int8_const_view_from_iter.rst b/src/libbson/doc/bson_vector_int8_const_view_from_iter.rst new file mode 100644 index 00000000000..abbe0bc6ce8 --- /dev/null +++ b/src/libbson/doc/bson_vector_int8_const_view_from_iter.rst @@ -0,0 +1,37 @@ +:man_page: bson_vector_int8_const_view_from_iter + +bson_vector_int8_const_view_from_iter() +======================================= + +Initialize a :symbol:`bson_vector_int8_const_view_t` from a :symbol:`bson_iter_t` pointing to a valid Vector of ``int8`` element type. + +Synopsis +-------- + +.. code-block:: c + + bool + bson_vector_int8_const_view_from_iter (bson_vector_int8_const_view_t *view_out, + const bson_iter_t *iter); + +Parameters +---------- + +* ``view_out``: A :symbol:`bson_vector_int8_const_view_t` is written here on success. +* ``iter``: A valid :symbol:`bson_iter_t`. + +Description +----------- + +The provided iterator, which must point to some kind of BSON item, will be checked for a valid Vector of ``int8`` element type. +On success, a :symbol:`bson_vector_int8_const_view_t` is set to point to the same underlying :symbol:`bson_t` buffer as the provided :symbol:`bson_iter_t`. +The view will only be valid until the containing document is destroyed or modified. + +Returns +------- + +Returns true if the view was successfully initialized. + +.. seealso:: + + | :symbol:`bson_vector_int8_view_from_iter` diff --git a/src/libbson/doc/bson_vector_int8_const_view_init.rst b/src/libbson/doc/bson_vector_int8_const_view_init.rst new file mode 100644 index 00000000000..d78fe69ebe8 --- /dev/null +++ b/src/libbson/doc/bson_vector_int8_const_view_init.rst @@ -0,0 +1,39 @@ +:man_page: bson_vector_int8_const_view_init + +bson_vector_int8_const_view_init() +================================== + +Initialize a :symbol:`bson_vector_int8_const_view_t` from a const ``uint8_t`` buffer. + +Synopsis +-------- + +.. code-block:: c + + bool + bson_vector_int8_const_view_init (bson_vector_int8_const_view_t *view_out, + const uint8_t *binary_data, + uint32_t binary_data_len); + +Parameters +---------- + +* ``view_out``: A :symbol:`bson_vector_int8_const_view_t` is written here on success. +* ``binary_data``: A pointer to the BSON Binary data block to be validated. +* ``binary_data_len``: Length of the binary data block, in bytes. + +Description +----------- + +The length and header of the provided binary data block will be checked for a valid Vector of ``int8`` element type. +On success, the pointer and length are packaged as a :symbol:`bson_vector_int8_const_view_t` written to ``*view_out``. +The view will only be valid as long as ``binary_data`` is valid. + +Returns +------- + +Returns true if the view was successfully initialized. + +.. seealso:: + + | :symbol:`bson_vector_int8_view_init` diff --git a/src/libbson/doc/bson_vector_int8_const_view_length.rst b/src/libbson/doc/bson_vector_int8_const_view_length.rst new file mode 100644 index 00000000000..4f584e57cb0 --- /dev/null +++ b/src/libbson/doc/bson_vector_int8_const_view_length.rst @@ -0,0 +1,33 @@ +:man_page: bson_vector_int8_const_view_length + +bson_vector_int8_const_view_length() +==================================== + +Return the number of elements in a Vector referenced by a :symbol:`bson_vector_int8_const_view_t`. + +Synopsis +-------- + +.. code-block:: c + + size_t + bson_vector_int8_const_view_length (bson_vector_int8_const_view_t view); + +Parameters +---------- + +* ``view``: A valid :symbol:`bson_vector_int8_const_view_t`. + +Description +----------- + +An element count is calculated from the view's stored binary block length. + +Returns +------- + +The number of elements, as a ``size_t``. + +.. seealso:: + + | :symbol:`bson_vector_int8_view_length` diff --git a/src/libbson/doc/bson_vector_int8_const_view_read.rst b/src/libbson/doc/bson_vector_int8_const_view_read.rst new file mode 100644 index 00000000000..8f66a1c0ffe --- /dev/null +++ b/src/libbson/doc/bson_vector_int8_const_view_read.rst @@ -0,0 +1,41 @@ +:man_page: bson_vector_int8_const_view_read + +bson_vector_int8_const_view_read() +================================== + +Copy a contiguous block of elements from a :symbol:`bson_vector_int8_const_view_t` into a C array of ``int8_t``. + +Synopsis +-------- + +.. code-block:: c + + bool + bson_vector_int8_const_view_read (bson_vector_int8_const_view_t view, + int8_t *values_out, + size_t element_count, + size_t vector_offset_elements); + +Parameters +---------- + +* ``view``: A valid :symbol:`bson_vector_int8_const_view_t`. +* ``values_out``: Location where the ``int8_t`` elements will be read to. +* ``element_count``: Number of elements to read. +* ``vector_offset_elements``: The vector index of the first element to read. + +Description +----------- + +Elements are copied in bulk from the view to the provided output pointer. + +Returns +------- + +If the ``element_count`` and ``vector_offset_elements`` parameters overflow the bounds of the Vector, returns false without taking any other action. +If the parameters are in range, this is guaranteed to succeed. +On success, returns true and reads ``element_count`` elements into ``*values_out``. + +.. seealso:: + + | :symbol:`bson_vector_int8_view_read` diff --git a/src/libbson/doc/bson_vector_int8_const_view_t.rst b/src/libbson/doc/bson_vector_int8_const_view_t.rst new file mode 100644 index 00000000000..81468f105bf --- /dev/null +++ b/src/libbson/doc/bson_vector_int8_const_view_t.rst @@ -0,0 +1,62 @@ +:man_page: bson_vector_int8_const_view_t + +bson_vector_int8_const_view_t +============================= + +A reference to non-owned const BSON Binary data holding a valid Vector of ``int8`` element type. + +Synopsis +-------- + +.. code-block:: c + + #include + + typedef struct bson_vector_int8_const_view_t { + /*< private >*/ + } bson_vector_int8_const_view_t; + +Description +----------- + +:symbol:`bson_vector_int8_const_view_t` is a structure that acts as an opaque const reference to a block of memory that has been validated as an ``int8`` vector. + +It is meant to be passed by value and can be discarded at any time. The contents of the structure should be considered private. + +The :symbol:`bson_t` *MUST* be valid for the lifetime of the view and it is an error to modify the :symbol:`bson_t` while using the view. + +.. only:: html + + Functions + --------- + + .. toctree:: + :titlesonly: + :maxdepth: 1 + + bson_vector_int8_const_view_init + bson_vector_int8_const_view_from_iter + bson_vector_int8_const_view_length + bson_vector_int8_const_view_read + +Example +------- + +.. code-block:: c + + bson_iter_t iter; + bson_vector_int8_const_view_t view; + + if (bson_iter_init_find (&iter, &doc, "vector") && bson_vector_int8_const_view_from_iter (&view, &iter)) { + size_t length = bson_vector_int8_const_view_length (view); + printf ("Elements in 'vector':\n"); + for (size_t i = 0; i < length; i++) { + int8_t element; + BSON_ASSERT (bson_vector_int8_const_view_read (view, &element, 1, i)); + printf (" [%d] = %d\n", (int) i, (int) element); + } + } + +.. seealso:: + + | :symbol:`bson_vector_int8_view_t` diff --git a/src/libbson/doc/bson_vector_int8_view_as_const.rst b/src/libbson/doc/bson_vector_int8_view_as_const.rst new file mode 100644 index 00000000000..9c1704b7149 --- /dev/null +++ b/src/libbson/doc/bson_vector_int8_view_as_const.rst @@ -0,0 +1,29 @@ +:man_page: bson_vector_int8_view_as_const + +bson_vector_int8_view_as_const() +================================ + +Convert a :symbol:`bson_vector_int8_view_t` into a :symbol:`bson_vector_int8_const_view_t`. + +Synopsis +-------- + +.. code-block:: c + + bson_vector_int8_const_view_t + bson_vector_int8_view_as_const (bson_vector_int8_view_t view); + +Parameters +---------- + +* ``view``: A valid :symbol:`bson_vector_int8_view_t`. + +Description +----------- + +This adds a ``const`` qualifier to the view without re-validating the underlying data. + +Returns +------- + +Always returns a :symbol:`bson_vector_int8_const_view_t`. diff --git a/src/libbson/doc/bson_vector_int8_view_from_iter.rst b/src/libbson/doc/bson_vector_int8_view_from_iter.rst new file mode 100644 index 00000000000..0c9bbd80a2c --- /dev/null +++ b/src/libbson/doc/bson_vector_int8_view_from_iter.rst @@ -0,0 +1,37 @@ +:man_page: bson_vector_int8_view_from_iter + +bson_vector_int8_view_from_iter() +================================= + +Initialize a :symbol:`bson_vector_int8_view_t` from a :symbol:`bson_iter_t` pointing to a valid Vector of ``int8`` element type. + +Synopsis +-------- + +.. code-block:: c + + bool + bson_vector_int8_view_from_iter (bson_vector_int8_view_t *view_out, + bson_iter_t *iter); + +Parameters +---------- + +* ``view_out``: A :symbol:`bson_vector_int8_view_t` is written here on success. +* ``iter``: A valid :symbol:`bson_iter_t`. + +Description +----------- + +The provided iterator, which must point to some kind of BSON item, will be checked for a valid Vector of ``int8`` element type. +On success, a :symbol:`bson_vector_int8_view_t` is set to point to the same underlying :symbol:`bson_t` buffer as the provided :symbol:`bson_iter_t`. +The view will only be valid until the containing document is destroyed or otherwise modified. + +Returns +------- + +Returns true if the view was successfully initialized. + +.. seealso:: + + | :symbol:`bson_vector_int8_const_view_from_iter` diff --git a/src/libbson/doc/bson_vector_int8_view_init.rst b/src/libbson/doc/bson_vector_int8_view_init.rst new file mode 100644 index 00000000000..f53fff299fe --- /dev/null +++ b/src/libbson/doc/bson_vector_int8_view_init.rst @@ -0,0 +1,39 @@ +:man_page: bson_vector_int8_view_init + +bson_vector_int8_view_init() +============================ + +Initialize a :symbol:`bson_vector_int8_view_t` from a mutable ``uint8_t`` buffer. + +Synopsis +-------- + +.. code-block:: c + + bool + bson_vector_int8_view_init (bson_vector_int8_view_t *view_out, + uint8_t *binary_data, + uint32_t binary_data_len); + +Parameters +---------- + +* ``view_out``: A :symbol:`bson_vector_int8_view_t` is written here on success. +* ``binary_data``: A pointer to the BSON Binary data block to be validated. +* ``binary_data_len``: Length of the binary data block, in bytes. + +Description +----------- + +The length and header of the provided binary data block will be checked for a valid Vector of ``int8`` element type. +On success, the pointer and length are packaged as a :symbol:`bson_vector_int8_view_t` written to ``*view_out``. +The view will only be valid as long as ``binary_data`` is valid. + +Returns +------- + +Returns true if the view was successfully initialized. + +.. seealso:: + + | :symbol:`bson_vector_int8_const_view_init` diff --git a/src/libbson/doc/bson_vector_int8_view_length.rst b/src/libbson/doc/bson_vector_int8_view_length.rst new file mode 100644 index 00000000000..21dbf4cff57 --- /dev/null +++ b/src/libbson/doc/bson_vector_int8_view_length.rst @@ -0,0 +1,33 @@ +:man_page: bson_vector_int8_view_length + +bson_vector_int8_view_length() +============================== + +Return the number of elements in a Vector referenced by a :symbol:`bson_vector_int8_view_t`. + +Synopsis +-------- + +.. code-block:: c + + size_t + bson_vector_int8_view_length (bson_vector_int8_view_t view); + +Parameters +---------- + +* ``view``: A valid :symbol:`bson_vector_int8_view_t`. + +Description +----------- + +An element count is calculated from the view's stored binary block length. + +Returns +------- + +The number of elements, as a ``size_t``. + +.. seealso:: + + | :symbol:`bson_vector_int8_const_view_length` diff --git a/src/libbson/doc/bson_vector_int8_view_read.rst b/src/libbson/doc/bson_vector_int8_view_read.rst new file mode 100644 index 00000000000..7f12d08b04c --- /dev/null +++ b/src/libbson/doc/bson_vector_int8_view_read.rst @@ -0,0 +1,41 @@ +:man_page: bson_vector_int8_view_read + +bson_vector_int8_view_read() +============================ + +Copy a contiguous block of elements from a :symbol:`bson_vector_int8_view_t` into a C array of ``int8_t``. + +Synopsis +-------- + +.. code-block:: c + + bool + bson_vector_int8_view_read (bson_vector_int8_view_t view, + int8_t *values_out, + size_t element_count, + size_t vector_offset_elements); + +Parameters +---------- + +* ``view``: A valid :symbol:`bson_vector_int8_view_t`. +* ``values_out``: Location where the ``int8_t`` elements will be read to. +* ``element_count``: Number of elements to read. +* ``vector_offset_elements``: The vector index of the first element to read. + +Description +----------- + +Elements are copied in bulk from the view to the provided output pointer. + +Returns +------- + +If the ``element_count`` and ``vector_offset_elements`` parameters overflow the bounds of the Vector, returns false without taking any other action. +If the parameters are in range, this is guaranteed to succeed. +On success, returns true and reads ``element_count`` elements into ``*values_out``. + +.. seealso:: + + | :symbol:`bson_vector_int8_const_view_read` diff --git a/src/libbson/doc/bson_vector_int8_view_t.rst b/src/libbson/doc/bson_vector_int8_view_t.rst new file mode 100644 index 00000000000..f024651c917 --- /dev/null +++ b/src/libbson/doc/bson_vector_int8_view_t.rst @@ -0,0 +1,59 @@ +:man_page: bson_vector_int8_view_t + +bson_vector_int8_view_t +======================= + +A reference to mutable non-owned BSON Binary data holding a valid Vector of ``int8`` element type. + +Synopsis +-------- + +.. code-block:: c + + #include + + typedef struct bson_vector_int8_view_t { + /*< private >*/ + } bson_vector_int8_view_t; + +Description +----------- + +:symbol:`bson_vector_int8_view_t` is a structure that acts as an opaque reference to a block of memory that has been validated as an ``int8`` vector. + +It is meant to be passed by value and can be discarded at any time. The contents of the structure should be considered private. + +The :symbol:`bson_t` *MUST* be valid for the lifetime of the view and it is an error to modify the :symbol:`bson_t` while using the view. + +.. only:: html + + Functions + --------- + + .. toctree:: + :titlesonly: + :maxdepth: 1 + + bson_vector_int8_view_init + bson_vector_int8_view_from_iter + bson_vector_int8_view_as_const + bson_vector_int8_view_length + bson_vector_int8_view_read + bson_vector_int8_view_write + +Example +------- + +.. code-block:: c + + static const int8_t values[] = {1, 2, 3}; + const size_t values_count = sizeof values / sizeof values[0]; + + bson_vector_int8_view_t view; + BSON_ASSERT (BSON_APPEND_VECTOR_INT8 (&doc, "vector", values_count, &view)); + BSON_ASSERT (bson_vector_int8_view_write (view, values, values_count, 0)); + +.. seealso:: + + | :symbol:`bson_append_vector_int8` + | :symbol:`bson_vector_int8_const_view_t` diff --git a/src/libbson/doc/bson_vector_int8_view_write.rst b/src/libbson/doc/bson_vector_int8_view_write.rst new file mode 100644 index 00000000000..317c24f2b6c --- /dev/null +++ b/src/libbson/doc/bson_vector_int8_view_write.rst @@ -0,0 +1,37 @@ +:man_page: bson_vector_int8_view_write + +bson_vector_int8_view_write() +============================= + +Copy a contiguous block of elements from a C ``int8_t`` array into a :symbol:`bson_vector_int8_view_t`. + +Synopsis +-------- + +.. code-block:: c + + bool + bson_vector_int8_view_write (bson_vector_int8_view_t view, + const int8_t *values, + size_t element_count, + size_t vector_offset_elements); + +Parameters +---------- + +* ``view``: A valid :symbol:`bson_vector_int8_view_t`. +* ``values``: Location where the ``int8_t`` elements will be copied from. +* ``element_count``: Number of elements to write. +* ``vector_offset_elements``: The vector index of the first element to write. + +Description +----------- + +Elements are copied in bulk from the provided pointer into the view. + +Returns +------- + +If the ``element_count`` and ``vector_offset_elements`` parameters overflow the bounds of the Vector, returns false without taking any other action. +If the parameters are in range, this is guaranteed to succeed. +On success, returns true and writes to ``element_count`` elements in the Vector starting at ``vector_offset_elements``. diff --git a/src/libbson/doc/bson_vector_packed_bits_binary_data_length.rst b/src/libbson/doc/bson_vector_packed_bits_binary_data_length.rst new file mode 100644 index 00000000000..499f78441bb --- /dev/null +++ b/src/libbson/doc/bson_vector_packed_bits_binary_data_length.rst @@ -0,0 +1,31 @@ +:man_page: bson_vector_packed_bits_binary_data_length + +bson_vector_packed_bits_binary_data_length() +============================================ + +Calculate the size of a BSON Binary field that would be needed to store a Vector with the indicated number of ``packed_bits`` elements. + +Synopsis +-------- + +.. code-block:: c + + uint32_t + bson_vector_packed_bits_binary_data_length (size_t element_count); + +Parameters +---------- + +* ``element_count``: Number of single-bit elements, as a ``size_t``. + +Description +----------- + +Checks ``element_count`` against the maximum representable size, and calculates the required Binary size. + +Returns +------- + +On success, returns the required Binary size as a ``uint32_t`` greater than or equal to ``BSON_VECTOR_HEADER_LEN``. +This length includes the 2-byte Vector header, but not the Binary subtype header or any other BSON headers. +If the ``element_count`` is too large to represent, returns 0. diff --git a/src/libbson/doc/bson_vector_packed_bits_const_view_from_iter.rst b/src/libbson/doc/bson_vector_packed_bits_const_view_from_iter.rst new file mode 100644 index 00000000000..9187fc96073 --- /dev/null +++ b/src/libbson/doc/bson_vector_packed_bits_const_view_from_iter.rst @@ -0,0 +1,37 @@ +:man_page: bson_vector_packed_bits_const_view_from_iter + +bson_vector_packed_bits_const_view_from_iter() +============================================== + +Initialize a :symbol:`bson_vector_packed_bits_const_view_t` from a :symbol:`bson_iter_t` pointing to a valid Vector of ``packed_bits`` element type. + +Synopsis +-------- + +.. code-block:: c + + bool + bson_vector_packed_bits_const_view_from_iter (bson_vector_packed_bits_const_view_t *view_out, + const bson_iter_t *iter); + +Parameters +---------- + +* ``view_out``: A :symbol:`bson_vector_packed_bits_const_view_t` is written here on success. +* ``iter``: A valid :symbol:`bson_iter_t`. + +Description +----------- + +The provided iterator, which must point to some kind of BSON item, will be checked for a valid Vector of ``packed_bits`` element type. +On success, a :symbol:`bson_vector_packed_bits_const_view_t` is set to point to the same underlying :symbol:`bson_t` buffer as the provided :symbol:`bson_iter_t`. +The view will only be valid until the containing document is destroyed or modified. + +Returns +------- + +Returns true if the view was successfully initialized. + +.. seealso:: + + | :symbol:`bson_vector_packed_bits_view_from_iter` diff --git a/src/libbson/doc/bson_vector_packed_bits_const_view_init.rst b/src/libbson/doc/bson_vector_packed_bits_const_view_init.rst new file mode 100644 index 00000000000..80ce23120fd --- /dev/null +++ b/src/libbson/doc/bson_vector_packed_bits_const_view_init.rst @@ -0,0 +1,39 @@ +:man_page: bson_vector_packed_bits_const_view_init + +bson_vector_packed_bits_const_view_init() +========================================= + +Initialize a :symbol:`bson_vector_packed_bits_const_view_t` from a const ``uint8_t`` buffer. + +Synopsis +-------- + +.. code-block:: c + + bool + bson_vector_packed_bits_const_view_init (bson_vector_packed_bits_const_view_t *view_out, + const uint8_t *binary_data, + uint32_t binary_data_len); + +Parameters +---------- + +* ``view_out``: A :symbol:`bson_vector_packed_bits_const_view_t` is written here on success. +* ``binary_data``: A pointer to the BSON Binary data block to be validated. +* ``binary_data_len``: Length of the binary data block, in bytes. + +Description +----------- + +The length, header, and trailing padding of the provided binary data block will be checked for a valid Vector of ``packed_bits`` element type. +On success, the pointer and length are packaged as a :symbol:`bson_vector_packed_bits_const_view_t` written to ``*view_out``. +The view will only be valid as long as ``binary_data`` is valid. + +Returns +------- + +Returns true if the view was successfully initialized. + +.. seealso:: + + | :symbol:`bson_vector_packed_bits_view_init` diff --git a/src/libbson/doc/bson_vector_packed_bits_const_view_length.rst b/src/libbson/doc/bson_vector_packed_bits_const_view_length.rst new file mode 100644 index 00000000000..b590894874b --- /dev/null +++ b/src/libbson/doc/bson_vector_packed_bits_const_view_length.rst @@ -0,0 +1,33 @@ +:man_page: bson_vector_packed_bits_const_view_length + +bson_vector_packed_bits_const_view_length() +=========================================== + +Return the number of elements in a Vector referenced by a :symbol:`bson_vector_packed_bits_const_view_t`. + +Synopsis +-------- + +.. code-block:: c + + size_t + bson_vector_packed_bits_const_view_length (bson_vector_packed_bits_const_view_t view); + +Parameters +---------- + +* ``view``: A valid :symbol:`bson_vector_packed_bits_const_view_t`. + +Description +----------- + +An element count is calculated from information stored inside the `bson_vector_packed_bits_const_view_t` value. + +Returns +------- + +The number of elements, as a ``size_t``. + +.. seealso:: + + | :symbol:`bson_vector_packed_bits_view_length` diff --git a/src/libbson/doc/bson_vector_packed_bits_const_view_length_bytes.rst b/src/libbson/doc/bson_vector_packed_bits_const_view_length_bytes.rst new file mode 100644 index 00000000000..0a9d5db6ae0 --- /dev/null +++ b/src/libbson/doc/bson_vector_packed_bits_const_view_length_bytes.rst @@ -0,0 +1,34 @@ +:man_page: bson_vector_packed_bits_const_view_length_bytes + +bson_vector_packed_bits_const_view_length_bytes() +================================================= + +Return the number of packed bytes in a Vector referenced by a :symbol:`bson_vector_packed_bits_const_view_t`. + +Synopsis +-------- + +.. code-block:: c + + size_t + bson_vector_packed_bits_const_view_length_bytes (bson_vector_packed_bits_const_view_t view); + +Parameters +---------- + +* ``view``: A valid :symbol:`bson_vector_packed_bits_const_view_t`. + +Description +----------- + +A byte count is calculated from the view's stored binary block length. +If the element count isn't a multiple of 8, the final byte will include bits that do not belong to any element. + +Returns +------- + +The number of bytes, as a ``size_t``. + +.. seealso:: + + | :symbol:`bson_vector_packed_bits_view_length_bytes` diff --git a/src/libbson/doc/bson_vector_packed_bits_const_view_padding.rst b/src/libbson/doc/bson_vector_packed_bits_const_view_padding.rst new file mode 100644 index 00000000000..b3922a8d66f --- /dev/null +++ b/src/libbson/doc/bson_vector_packed_bits_const_view_padding.rst @@ -0,0 +1,34 @@ +:man_page: bson_vector_packed_bits_const_view_padding + +bson_vector_packed_bits_const_view_padding() +============================================ + +Returns the number of unused bits in a Vector referenced by a :symbol:`bson_vector_packed_bits_const_view_t`. + +Synopsis +-------- + +.. code-block:: c + + size_t + bson_vector_packed_bits_const_view_padding (bson_vector_packed_bits_const_view_t view); + +Parameters +---------- + +* ``view``: A valid :symbol:`bson_vector_packed_bits_const_view_t`. + +Description +----------- + +The 3-bit ``padding`` field is extracted from a copy of the Vector header inside ``view``. + +Returns +------- + +The number of unused bits in the final packed byte. Guaranteed to be between 0 and 7 inclusive. +Vector validation guarantees that empty Vectors have a ``padding`` of 0. + +.. seealso:: + + | :symbol:`bson_vector_packed_bits_view_padding` diff --git a/src/libbson/doc/bson_vector_packed_bits_const_view_read_packed.rst b/src/libbson/doc/bson_vector_packed_bits_const_view_read_packed.rst new file mode 100644 index 00000000000..01069904e2e --- /dev/null +++ b/src/libbson/doc/bson_vector_packed_bits_const_view_read_packed.rst @@ -0,0 +1,45 @@ +:man_page: bson_vector_packed_bits_const_view_read_packed + +bson_vector_packed_bits_const_view_read_packed() +================================================ + +Copy a contiguous block of packed bytes out of a :symbol:`bson_vector_packed_bits_const_view_t`. + +Synopsis +-------- + +.. code-block:: c + + bool + bson_vector_packed_bits_const_view_read_packed (bson_vector_packed_bits_const_view_t view, + uint8_t *packed_values_out, + size_t byte_count, + size_t vector_offset_bytes); + +Parameters +---------- + +* ``view``: A valid :symbol:`bson_vector_packed_bits_const_view_t`. +* ``packed_values_out``: Location where the packed bytes will be read to. +* ``byte_count``: Number of bytes to read. +* ``vector_offset_bytes``: The byte index of the first packed byte to read. + +Description +----------- + +Packed bytes are copied in bulk from the view to the provided output pointer. + +If the Vector's element count isn't a multiple of 8, its final byte will include bits that do not belong to any element. +Vector validation checks that these bits are zero. + +Returns +------- + +If the ``byte_count`` and ``vector_offset_bytes`` parameters overflow the bounds of the Vector, returns false without taking any other action. +If the parameters are in range, this is guaranteed to succeed. +On success, returns true and reads ``byte_count`` bytes into ``*packed_values_out``. + +.. seealso:: + + | :symbol:`bson_vector_packed_bits_view_read_packed` + | :symbol:`bson_vector_packed_bits_view_write_packed` diff --git a/src/libbson/doc/bson_vector_packed_bits_const_view_t.rst b/src/libbson/doc/bson_vector_packed_bits_const_view_t.rst new file mode 100644 index 00000000000..01e72f7ff86 --- /dev/null +++ b/src/libbson/doc/bson_vector_packed_bits_const_view_t.rst @@ -0,0 +1,75 @@ +:man_page: bson_vector_packed_bits_const_view_t + +bson_vector_packed_bits_const_view_t +==================================== + +A reference to non-owned const BSON Binary data holding a valid Vector of ``packed_bits`` element type. + +Synopsis +-------- + +.. code-block:: c + + #include + + typedef struct bson_vector_packed_bits_const_view_t { + /*< private >*/ + } bson_vector_packed_bits_const_view_t; + +Description +----------- + +:symbol:`bson_vector_packed_bits_const_view_t` is a structure that acts as an opaque const reference to a block of memory that has been validated as a ``packed_bits`` vector. + +It is meant to be passed by value and can be discarded at any time. The contents of the structure should be considered private. + +The :symbol:`bson_t` *MUST* be valid for the lifetime of the view and it is an error to modify the :symbol:`bson_t` while using the view. + +.. only:: html + + Functions + --------- + + .. toctree:: + :titlesonly: + :maxdepth: 1 + + bson_vector_packed_bits_const_view_init + bson_vector_packed_bits_const_view_from_iter + bson_vector_packed_bits_const_view_length + bson_vector_packed_bits_const_view_length_bytes + bson_vector_packed_bits_const_view_padding + bson_vector_packed_bits_const_view_read_packed + bson_vector_packed_bits_const_view_unpack_bool + +Example +------- + +.. code-block:: c + + bson_iter_t iter; + bson_vector_packed_bits_const_view_t view; + + if (bson_iter_init_find (&iter, &doc, "vector") && bson_vector_packed_bits_const_view_from_iter (&view, &iter)) { + size_t length = bson_vector_packed_bits_const_view_length (view); + size_t length_bytes = bson_vector_packed_bits_const_view_length_bytes (view); + size_t padding = bson_vector_packed_bits_const_view_padding (view); + + printf ("Elements in 'vector':\n"); + for (size_t i = 0; i < length; i++) { + bool element; + BSON_ASSERT (bson_vector_packed_bits_const_view_unpack_bool (view, &element, 1, i)); + printf (" elements[%d] = %d\n", (int) i, (int) element); + } + + printf ("Bytes in 'vector': (%d bits unused)\n", (int) padding); + for (size_t i = 0; i < length_bytes; i++) { + uint8_t packed_byte; + BSON_ASSERT (bson_vector_packed_bits_const_view_read_packed (view, &packed_byte, 1, i)); + printf (" bytes[%d] = 0x%02x\n", (int) i, (unsigned) packed_byte); + } + } + +.. seealso:: + + | :symbol:`bson_vector_packed_bits_view_t` diff --git a/src/libbson/doc/bson_vector_packed_bits_const_view_unpack_bool.rst b/src/libbson/doc/bson_vector_packed_bits_const_view_unpack_bool.rst new file mode 100644 index 00000000000..41593315c4a --- /dev/null +++ b/src/libbson/doc/bson_vector_packed_bits_const_view_unpack_bool.rst @@ -0,0 +1,41 @@ +:man_page: bson_vector_packed_bits_const_view_unpack_bool + +bson_vector_packed_bits_const_view_unpack_bool() +================================================ + +Unpack a contiguous block of elements from a :symbol:`bson_vector_packed_bits_const_view_t` into a C array of ``bool``. + +Synopsis +-------- + +.. code-block:: c + + bool + bson_vector_packed_bits_const_view_unpack_bool (bson_vector_packed_bits_const_view_t view, + bool *unpacked_values_out, + size_t element_count, + size_t vector_offset_elements); + +Parameters +---------- + +* ``view``: A valid :symbol:`bson_vector_packed_bits_const_view_t`. +* ``unpacked_values_out``: Location where the ``bool`` elements will be unpacked to. +* ``element_count``: Number of elements to unpack. +* ``vector_offset_elements``: The vector index of the first element to unpack. + +Description +----------- + +Elements are unpacked from individual bits into a C array of ``bool``. + +Returns +------- + +If the ``element_count`` and ``vector_offset_elements`` parameters overflow the bounds of the Vector, returns false without taking any other action. +If the parameters are in range, this is guaranteed to succeed. +On success, returns true and unpacks ``element_count`` elements into ``*unpacked_values_out``. + +.. seealso:: + + | :symbol:`bson_vector_packed_bits_view_unpack_bool` diff --git a/src/libbson/doc/bson_vector_packed_bits_view_as_const.rst b/src/libbson/doc/bson_vector_packed_bits_view_as_const.rst new file mode 100644 index 00000000000..369fe9c97c6 --- /dev/null +++ b/src/libbson/doc/bson_vector_packed_bits_view_as_const.rst @@ -0,0 +1,29 @@ +:man_page: bson_vector_packed_bits_view_as_const + +bson_vector_packed_bits_view_as_const() +======================================= + +Convert a :symbol:`bson_vector_packed_bits_view_t` into a :symbol:`bson_vector_packed_bits_const_view_t`. + +Synopsis +-------- + +.. code-block:: c + + bson_vector_packed_bits_const_view_t + bson_vector_packed_bits_view_as_const (bson_vector_packed_bits_view_t view); + +Parameters +---------- + +* ``view``: A valid :symbol:`bson_vector_packed_bits_view_t`. + +Description +----------- + +This adds a ``const`` qualifier to the view without re-validating the underlying data. + +Returns +------- + +Always returns a :symbol:`bson_vector_packed_bits_const_view_t`. diff --git a/src/libbson/doc/bson_vector_packed_bits_view_from_iter.rst b/src/libbson/doc/bson_vector_packed_bits_view_from_iter.rst new file mode 100644 index 00000000000..be8c88f4e3d --- /dev/null +++ b/src/libbson/doc/bson_vector_packed_bits_view_from_iter.rst @@ -0,0 +1,33 @@ +:man_page: bson_vector_packed_bits_view_from_iter + +bson_vector_packed_bits_view_from_iter() +======================================== + +Initialize a :symbol:`bson_vector_packed_bits_view_t` from a :symbol:`bson_iter_t` pointing to a valid Vector of ``packed_bits`` element type. + +Synopsis +-------- + +.. code-block:: c + + bool + bson_vector_packed_bits_view_from_iter (bson_vector_packed_bits_view_t *view_out, + bson_iter_t *iter); + +Parameters +---------- + +* ``view_out``: A :symbol:`bson_vector_packed_bits_view_t` is written here on success. +* ``iter``: A valid :symbol:`bson_iter_t`. + +Description +----------- + +The provided iterator, which must point to some kind of BSON item, will be checked for a valid Vector of ``packed_bits`` element type. +On success, a :symbol:`bson_vector_packed_bits_view_t` is set to point to the same underlying :symbol:`bson_t` buffer as the provided :symbol:`bson_iter_t`. +The view will only be valid until the containing document is destroyed or otherwise modified. + +Returns +------- + +Returns true if the view was successfully initialized. diff --git a/src/libbson/doc/bson_vector_packed_bits_view_init.rst b/src/libbson/doc/bson_vector_packed_bits_view_init.rst new file mode 100644 index 00000000000..b2c2622e08a --- /dev/null +++ b/src/libbson/doc/bson_vector_packed_bits_view_init.rst @@ -0,0 +1,35 @@ +:man_page: bson_vector_packed_bits_view_init + +bson_vector_packed_bits_view_init() +=================================== + +Initialize a :symbol:`bson_vector_packed_bits_view_t` from a mutable ``uint8_t`` buffer. + +Synopsis +-------- + +.. code-block:: c + + bool + bson_vector_packed_bits_view_init (bson_vector_packed_bits_view_t *view_out, + uint8_t *binary_data, + uint32_t binary_data_len); + +Parameters +---------- + +* ``view_out``: A :symbol:`bson_vector_packed_bits_view_t` is written here on success. +* ``binary_data``: A pointer to the BSON Binary data block to be validated. +* ``binary_data_len``: Length of the binary data block, in bytes. + +Description +----------- + +The length, header, and trailing padding of the provided binary data block will be checked for a valid Vector of ``packed_bits`` element type. +On success, the pointer and length are packaged as a :symbol:`bson_vector_packed_bits_view_t` written to ``*view_out``. +The view will only be valid as long as ``binary_data`` is valid. + +Returns +------- + +Returns true if the view was successfully initialized. diff --git a/src/libbson/doc/bson_vector_packed_bits_view_length.rst b/src/libbson/doc/bson_vector_packed_bits_view_length.rst new file mode 100644 index 00000000000..4f89f1b68c5 --- /dev/null +++ b/src/libbson/doc/bson_vector_packed_bits_view_length.rst @@ -0,0 +1,29 @@ +:man_page: bson_vector_packed_bits_view_length + +bson_vector_packed_bits_view_length() +===================================== + +Return the number of elements in a Vector referenced by a :symbol:`bson_vector_packed_bits_view_t`. + +Synopsis +-------- + +.. code-block:: c + + size_t + bson_vector_packed_bits_view_length (bson_vector_packed_bits_view_t view); + +Parameters +---------- + +* ``view``: A valid :symbol:`bson_vector_packed_bits_view_t`. + +Description +----------- + +An element count is calculated from information stored inside the `bson_vector_packed_bits_view_t` value. + +Returns +------- + +The number of elements, as a ``size_t``. diff --git a/src/libbson/doc/bson_vector_packed_bits_view_length_bytes.rst b/src/libbson/doc/bson_vector_packed_bits_view_length_bytes.rst new file mode 100644 index 00000000000..c800d5ecd4d --- /dev/null +++ b/src/libbson/doc/bson_vector_packed_bits_view_length_bytes.rst @@ -0,0 +1,30 @@ +:man_page: bson_vector_packed_bits_view_length_bytes + +bson_vector_packed_bits_view_length_bytes() +=========================================== + +Return the number of packed bytes in a Vector referenced by a :symbol:`bson_vector_packed_bits_view_t`. + +Synopsis +-------- + +.. code-block:: c + + size_t + bson_vector_packed_bits_view_length_bytes (bson_vector_packed_bits_view_t view); + +Parameters +---------- + +* ``view``: A valid :symbol:`bson_vector_packed_bits_view_t`. + +Description +----------- + +A byte count is calculated from the view's stored binary block length. +If the element count isn't a multiple of 8, the final byte will include bits that do not belong to any element. + +Returns +------- + +The number of bytes, as a ``size_t``. diff --git a/src/libbson/doc/bson_vector_packed_bits_view_pack_bool.rst b/src/libbson/doc/bson_vector_packed_bits_view_pack_bool.rst new file mode 100644 index 00000000000..6310debd928 --- /dev/null +++ b/src/libbson/doc/bson_vector_packed_bits_view_pack_bool.rst @@ -0,0 +1,37 @@ +:man_page: bson_vector_packed_bits_view_pack_bool + +bson_vector_packed_bits_view_pack_bool() +======================================== + +Pack a contiguous block of elements from a C ``bool`` array into a :symbol:`bson_vector_packed_bits_view_t`. + +Synopsis +-------- + +.. code-block:: c + + bool + bson_vector_packed_bits_view_pack_bool (bson_vector_packed_bits_view_t view, + const bool *unpacked_values, + size_t element_count, + size_t vector_offset_elements) + +Parameters +---------- + +* ``view``: A valid :symbol:`bson_vector_packed_bits_view_t`. +* ``unpacked_values``: Location where the ``bool`` elements will be packed from. +* ``element_count``: Number of elements to pack. +* ``vector_offset_elements``: The vector index of the first element to pack. + +Description +----------- + +Elements are packed into individual Vector bits from a C ``bool`` array. + +Returns +------- + +If the ``element_count`` and ``vector_offset_elements`` parameters overflow the bounds of the Vector, returns false without taking any other action. +If the parameters are in range, this is guaranteed to succeed. +On success, returns true and writes to ``element_count`` elements in the Vector starting at ``vector_offset_elements``. diff --git a/src/libbson/doc/bson_vector_packed_bits_view_padding.rst b/src/libbson/doc/bson_vector_packed_bits_view_padding.rst new file mode 100644 index 00000000000..0caf28ec6b2 --- /dev/null +++ b/src/libbson/doc/bson_vector_packed_bits_view_padding.rst @@ -0,0 +1,34 @@ +:man_page: bson_vector_packed_bits_view_padding + +bson_vector_packed_bits_view_padding() +====================================== + +Returns the number of unused bits in a Vector referenced by a :symbol:`bson_vector_packed_bits_view_t`. + +Synopsis +-------- + +.. code-block:: c + + size_t + bson_vector_packed_bits_view_padding (bson_vector_packed_bits_view_t view); + +Parameters +---------- + +* ``view``: A valid :symbol:`bson_vector_packed_bits_view_t`. + +Description +----------- + +The 3-bit ``padding`` field is extracted from a copy of the Vector header inside ``view``. + +Returns +------- + +The number of unused bits in the final packed byte. Guaranteed to be between 0 and 7 inclusive. +Vector validation guarantees that empty Vectors have a ``padding`` of 0. + +.. seealso:: + + | :symbol:`bson_vector_packed_bits_const_view_padding` diff --git a/src/libbson/doc/bson_vector_packed_bits_view_read_packed.rst b/src/libbson/doc/bson_vector_packed_bits_view_read_packed.rst new file mode 100644 index 00000000000..0b6f2d93598 --- /dev/null +++ b/src/libbson/doc/bson_vector_packed_bits_view_read_packed.rst @@ -0,0 +1,45 @@ +:man_page: bson_vector_packed_bits_view_read_packed + +bson_vector_packed_bits_view_read_packed() +=========================================== + +Copy a contiguous block of packed bytes out of a :symbol:`bson_vector_packed_bits_view_t`. + +Synopsis +-------- + +.. code-block:: c + + bool + bson_vector_packed_bits_view_read_packed (bson_vector_packed_bits_view_t view, + uint8_t *packed_values_out, + size_t byte_count, + size_t vector_offset_bytes); + +Parameters +---------- + +* ``view``: A valid :symbol:`bson_vector_packed_bits_view_t`. +* ``packed_values_out``: Location where the packed bytes will be read to. +* ``byte_count``: Number of bytes to read. +* ``vector_offset_bytes``: The byte index of the first packed byte to read. + +Description +----------- + +Packed bytes are copied in bulk from the view to the provided output pointer. + +If the Vector's element count isn't a multiple of 8, its final byte will include bits that do not belong to any element. +Vector validation checks that these bits are zero. + +Returns +------- + +If the ``byte_count`` and ``vector_offset_bytes`` parameters overflow the bounds of the Vector, returns false without taking any other action. +If the parameters are in range, this is guaranteed to succeed. +On success, returns true and reads ``byte_count`` bytes into ``*packed_values_out``. + +.. seealso:: + + | :symbol:`bson_vector_packed_bits_const_view_read_packed` + | :symbol:`bson_vector_packed_bits_view_write_packed` diff --git a/src/libbson/doc/bson_vector_packed_bits_view_t.rst b/src/libbson/doc/bson_vector_packed_bits_view_t.rst new file mode 100644 index 00000000000..b9bc576279f --- /dev/null +++ b/src/libbson/doc/bson_vector_packed_bits_view_t.rst @@ -0,0 +1,85 @@ +:man_page: bson_vector_packed_bits_view_t + +bson_vector_packed_bits_view_t +============================== + +A reference to mutable non-owned BSON Binary data holding a valid Vector of ``packed_bits`` element type. + +Synopsis +-------- + +.. code-block:: c + + #include + + typedef struct bson_vector_packed_bits_view_t { + /*< private >*/ + } bson_vector_packed_bits_view_t; + +Description +----------- + +:symbol:`bson_vector_packed_bits_view_t` is a structure that acts as an opaque reference to a block of memory that has been validated as a ``packed_bits`` vector. + +It is meant to be passed by value and can be discarded at any time. The contents of the structure should be considered private. + +The :symbol:`bson_t` *MUST* be valid for the lifetime of the view and it is an error to modify the :symbol:`bson_t` while using the view. + +.. only:: html + + Functions + --------- + + .. toctree:: + :titlesonly: + :maxdepth: 1 + + bson_vector_packed_bits_view_init + bson_vector_packed_bits_view_from_iter + bson_vector_packed_bits_view_as_const + bson_vector_packed_bits_view_length + bson_vector_packed_bits_view_length_bytes + bson_vector_packed_bits_view_padding + bson_vector_packed_bits_view_read_packed + bson_vector_packed_bits_view_write_packed + bson_vector_packed_bits_view_unpack_bool + bson_vector_packed_bits_view_pack_bool + +Example +------- + +.. code-block:: c + + // Fill a new vector with individual boolean elements + { + static const bool bool_values[] = {true, false, true, true, false}; + const size_t bool_values_count = sizeof bool_values / sizeof bool_values[0]; + + bson_vector_packed_bits_view_t view; + BSON_ASSERT (BSON_APPEND_VECTOR_PACKED_BITS (&doc, "from_bool", bool_values_count, &view)); + BSON_ASSERT (bson_vector_packed_bits_view_pack_bool (view, bool_values, bool_values_count, 0)); + } + + // Fill another new vector with packed bytes + { + static const uint8_t packed_bytes[] = {0xb0}; + const size_t unused_bits_count = 3; + const size_t packed_values_count = sizeof packed_bytes * 8 - unused_bits_count; + + bson_vector_packed_bits_view_t view; + BSON_ASSERT (BSON_APPEND_VECTOR_PACKED_BITS (&doc, "from_packed", packed_values_count, &view)); + BSON_ASSERT (bson_vector_packed_bits_view_write_packed (view, packed_bytes, sizeof packed_bytes, 0)); + } + + // Compare both vectors. They match exactly. + { + bson_iter_t from_bool_iter, from_packed_iter; + BSON_ASSERT (bson_iter_init_find (&from_bool_iter, &doc, "from_bool")); + BSON_ASSERT (bson_iter_init_find (&from_packed_iter, &doc, "from_packed")); + BSON_ASSERT (bson_iter_binary_equal (&from_bool_iter, &from_packed_iter)); + } + +.. seealso:: + + | :symbol:`bson_append_vector_packed_bits` + | :symbol:`bson_vector_packed_bits_const_view_t` diff --git a/src/libbson/doc/bson_vector_packed_bits_view_unpack_bool.rst b/src/libbson/doc/bson_vector_packed_bits_view_unpack_bool.rst new file mode 100644 index 00000000000..80c733d12f2 --- /dev/null +++ b/src/libbson/doc/bson_vector_packed_bits_view_unpack_bool.rst @@ -0,0 +1,41 @@ +:man_page: bson_vector_packed_bits_view_unpack_bool + +bson_vector_packed_bits_view_unpack_bool() +================================================ + +Unpack a contiguous block of elements from a :symbol:`bson_vector_packed_bits_view_t` into a C array of ``bool``. + +Synopsis +-------- + +.. code-block:: c + + bool + bson_vector_packed_bits_view_unpack_bool (bson_vector_packed_bits_view_t view, + bool *unpacked_values_out, + size_t element_count, + size_t vector_offset_elements); + +Parameters +---------- + +* ``view``: A valid :symbol:`bson_vector_packed_bits_view_t`. +* ``unpacked_values_out``: Location where the ``bool`` elements will be unpacked to. +* ``element_count``: Number of elements to unpack. +* ``vector_offset_elements``: The vector index of the first element to unpack. + +Description +----------- + +Elements are unpacked from individual bits into a C array of ``bool``. + +Returns +------- + +If the ``element_count`` and ``vector_offset_elements`` parameters overflow the bounds of the Vector, returns false without taking any other action. +If the parameters are in range, this is guaranteed to succeed. +On success, returns true and unpacks ``element_count`` elements into ``*unpacked_values_out``. + +.. seealso:: + + | :symbol:`bson_vector_packed_bits_const_view_unpack_bool` diff --git a/src/libbson/doc/bson_vector_packed_bits_view_write_packed.rst b/src/libbson/doc/bson_vector_packed_bits_view_write_packed.rst new file mode 100644 index 00000000000..684836dbc3c --- /dev/null +++ b/src/libbson/doc/bson_vector_packed_bits_view_write_packed.rst @@ -0,0 +1,45 @@ +:man_page: bson_vector_packed_bits_view_write_packed + +bson_vector_packed_bits_view_write_packed() +=========================================== + +Copy a contiguous block of packed bytes into a :symbol:`bson_vector_packed_bits_view_t`. + +Synopsis +-------- + +.. code-block:: c + + bool + bson_vector_packed_bits_view_write_packed (bson_vector_packed_bits_view_t view, + const uint8_t *packed_values, + size_t byte_count, + size_t vector_offset_bytes); + +Parameters +---------- + +* ``view``: A valid :symbol:`bson_vector_packed_bits_view_t`. +* ``packed_values``: Location where the packed bytes will be copied from. +* ``byte_count``: Number of bytes to write. +* ``vector_offset_bytes``: The byte index of the first packed byte to write. + +Description +----------- + +Packed bytes are copied in bulk from the input pointer to the provided view. + +If the Vector's element count isn't a multiple of 8, its final byte will include bits that do not belong to any element. +This function cannot be used to modify the unused bits, they will be explicitly zeroed if set. + +Returns +------- + +If the ``byte_count`` and ``vector_offset_bytes`` parameters overflow the bounds of the Vector, returns false without taking any other action. +If the parameters are in range, this is guaranteed to succeed. +On success, returns true and writes ``byte_count`` bytes from ``*packed_values`` into the Vector starting at byte index ``vector_offset_bytes``. + +.. seealso:: + + | :symbol:`bson_vector_packed_bits_view_read_packed` + | :symbol:`bson_vector_packed_bits_const_view_read_packed` From b01c76931882fcb8a1a82dcace7b5ba24cc89d32 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Fri, 14 Feb 2025 13:25:01 -0800 Subject: [PATCH 04/51] New source files for the implementation of BSON Binary Vector --- src/libbson/src/bson/bson-vector-private.h | 60 + src/libbson/src/bson/bson-vector.c | 681 ++++++++++ src/libbson/src/bson/bson-vector.h | 578 ++++++++ src/libbson/tests/test-bson-vector.c | 1400 ++++++++++++++++++++ 4 files changed, 2719 insertions(+) create mode 100644 src/libbson/src/bson/bson-vector-private.h create mode 100644 src/libbson/src/bson/bson-vector.c create mode 100644 src/libbson/src/bson/bson-vector.h create mode 100644 src/libbson/tests/test-bson-vector.c diff --git a/src/libbson/src/bson/bson-vector-private.h b/src/libbson/src/bson/bson-vector-private.h new file mode 100644 index 00000000000..14867e1ed3f --- /dev/null +++ b/src/libbson/src/bson/bson-vector-private.h @@ -0,0 +1,60 @@ +/* + * Copyright 2009-present MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#ifndef BSON_VECTOR_PRIVATE_H +#define BSON_VECTOR_PRIVATE_H + +#include +#include + +BSON_BEGIN_DECLS + + +typedef enum { + BSON_VECTOR_ELEMENT_SIGNED_INT = 0, + BSON_VECTOR_ELEMENT_UNSIGNED_INT = 1, + BSON_VECTOR_ELEMENT_FLOAT = 2, +} bson_vector_element_type_t; + +typedef enum { + BSON_VECTOR_ELEMENT_1_BIT = 0, + BSON_VECTOR_ELEMENT_8_BITS = 3, + BSON_VECTOR_ELEMENT_32_BITS = 7, +} bson_vector_element_size_t; + + +static BSON_INLINE uint8_t +bson_vector_header_byte_0 (bson_vector_element_type_t element_type, bson_vector_element_size_t element_size) +{ + BSON_ASSERT ((unsigned) element_type <= 0x0f); + BSON_ASSERT ((unsigned) element_size <= 0x0f); + return (uint8_t) element_type << 4 | (uint8_t) element_size; +} + +// See also `bson_vector_padding_from_header_byte_1` defined in for use by public inline functions. +static BSON_INLINE uint8_t +bson_vector_header_byte_1 (size_t padding) +{ + BSON_ASSERT (padding <= 7); + return (uint8_t) padding; +} + + +BSON_END_DECLS + +#endif /* BSON_VECTOR_PRIVATE_H */ diff --git a/src/libbson/src/bson/bson-vector.c b/src/libbson/src/bson/bson-vector.c new file mode 100644 index 00000000000..c488d6f1c32 --- /dev/null +++ b/src/libbson/src/bson/bson-vector.c @@ -0,0 +1,681 @@ +/* + * Copyright 2009-present MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include +#include + + +static BSON_INLINE bool +bson_vector_binary_header_impl_init (bson_vector_binary_header_impl_t *header_out, + const uint8_t *binary_data, + uint32_t binary_data_len) +{ + if (binary_data_len >= BSON_VECTOR_HEADER_LEN) { + memcpy (header_out->bytes, binary_data, BSON_VECTOR_HEADER_LEN); + return true; + } else { + return false; + } +} + +static BSON_INLINE bool +bson_vector_int8_validate (bson_vector_binary_header_impl_t header) +{ + return header.bytes[0] == bson_vector_header_byte_0 (BSON_VECTOR_ELEMENT_SIGNED_INT, BSON_VECTOR_ELEMENT_8_BITS) && + header.bytes[1] == bson_vector_header_byte_1 (0); +} + +static BSON_INLINE bool +bson_vector_float32_validate (bson_vector_binary_header_impl_t header, uint32_t binary_data_len) +{ + return (binary_data_len - BSON_VECTOR_HEADER_LEN) % sizeof (float) == 0 && + header.bytes[0] == bson_vector_header_byte_0 (BSON_VECTOR_ELEMENT_FLOAT, BSON_VECTOR_ELEMENT_32_BITS) && + header.bytes[1] == bson_vector_header_byte_1 (0); +} + +static BSON_INLINE bool +bson_vector_packed_bits_validate (bson_vector_binary_header_impl_t header, + const uint8_t *binary_data, + uint32_t binary_data_len) +{ + if (header.bytes[0] == bson_vector_header_byte_0 (BSON_VECTOR_ELEMENT_UNSIGNED_INT, BSON_VECTOR_ELEMENT_1_BIT)) { + size_t padding = bson_vector_padding_from_header_byte_1 (header.bytes[1]); + if (header.bytes[1] != bson_vector_header_byte_1 (padding)) { + return false; + } + uint32_t vector_data_len = binary_data_len - BSON_VECTOR_HEADER_LEN; + if (vector_data_len == 0) { + return padding == 0; + } else { + // We need to read the last byte of the binary block to validate that unused bits are zero. + uint8_t last_data_byte = binary_data[binary_data_len - 1]; + uint8_t mask_of_unused_bits = (1 << padding) - 1; + return (last_data_byte & mask_of_unused_bits) == 0; + } + } else { + return false; + } +} + + +bool +bson_vector_int8_view_init (bson_vector_int8_view_t *view_out, uint8_t *binary_data, uint32_t binary_data_len) +{ + BSON_OPTIONAL_PARAM (view_out); + BSON_ASSERT_PARAM (binary_data); + bson_vector_binary_header_impl_t header; + if (bson_vector_binary_header_impl_init (&header, binary_data, binary_data_len) && + bson_vector_int8_validate (header)) { + if (view_out) { + *view_out = (bson_vector_int8_view_t){ + .binary.data = binary_data, .binary.data_len = binary_data_len, .binary.header_copy = header}; + } + return true; + } else { + return false; + } +} + +bool +bson_vector_int8_const_view_init (bson_vector_int8_const_view_t *view_out, + const uint8_t *binary_data, + uint32_t binary_data_len) +{ + BSON_OPTIONAL_PARAM (view_out); + BSON_ASSERT_PARAM (binary_data); + bson_vector_binary_header_impl_t header; + if (bson_vector_binary_header_impl_init (&header, binary_data, binary_data_len) && + bson_vector_int8_validate (header)) { + if (view_out) { + *view_out = (bson_vector_int8_const_view_t){ + .binary.data = binary_data, .binary.data_len = binary_data_len, .binary.header_copy = header}; + } + return true; + } else { + return false; + } +} + +bool +bson_vector_float32_view_init (bson_vector_float32_view_t *view_out, uint8_t *binary_data, uint32_t binary_data_len) +{ + BSON_OPTIONAL_PARAM (view_out); + BSON_ASSERT_PARAM (binary_data); + bson_vector_binary_header_impl_t header; + if (bson_vector_binary_header_impl_init (&header, binary_data, binary_data_len) && + bson_vector_float32_validate (header, binary_data_len)) { + if (view_out) { + *view_out = (bson_vector_float32_view_t){ + .binary.data = binary_data, .binary.data_len = binary_data_len, .binary.header_copy = header}; + } + return true; + } else { + return false; + } +} + +bool +bson_vector_float32_const_view_init (bson_vector_float32_const_view_t *view_out, + const uint8_t *binary_data, + uint32_t binary_data_len) +{ + BSON_OPTIONAL_PARAM (view_out); + BSON_ASSERT_PARAM (binary_data); + bson_vector_binary_header_impl_t header; + if (bson_vector_binary_header_impl_init (&header, binary_data, binary_data_len) && + bson_vector_float32_validate (header, binary_data_len)) { + if (view_out) { + *view_out = (bson_vector_float32_const_view_t){ + .binary.data = binary_data, .binary.data_len = binary_data_len, .binary.header_copy = header}; + } + return true; + } else { + return false; + } +} + +bool +bson_vector_packed_bits_view_init (bson_vector_packed_bits_view_t *view_out, + uint8_t *binary_data, + uint32_t binary_data_len) +{ + BSON_OPTIONAL_PARAM (view_out); + BSON_ASSERT_PARAM (binary_data); + bson_vector_binary_header_impl_t header; + if (bson_vector_binary_header_impl_init (&header, binary_data, binary_data_len) && + bson_vector_packed_bits_validate (header, binary_data, binary_data_len)) { + if (view_out) { + *view_out = (bson_vector_packed_bits_view_t){ + .binary.data = binary_data, .binary.data_len = binary_data_len, .binary.header_copy = header}; + } + return true; + } else { + return false; + } +} + +bool +bson_vector_packed_bits_const_view_init (bson_vector_packed_bits_const_view_t *view_out, + const uint8_t *binary_data, + uint32_t binary_data_len) +{ + BSON_OPTIONAL_PARAM (view_out); + BSON_ASSERT_PARAM (binary_data); + bson_vector_binary_header_impl_t header; + if (bson_vector_binary_header_impl_init (&header, binary_data, binary_data_len) && + bson_vector_packed_bits_validate (header, binary_data, binary_data_len)) { + if (view_out) { + *view_out = (bson_vector_packed_bits_const_view_t){ + .binary.data = binary_data, .binary.data_len = binary_data_len, .binary.header_copy = header}; + } + return true; + } else { + return false; + } +} + + +bool +bson_vector_int8_view_from_iter (bson_vector_int8_view_t *view_out, bson_iter_t *iter) +{ + BSON_OPTIONAL_PARAM (view_out); + BSON_ASSERT_PARAM (iter); + if (BSON_ITER_HOLDS_BINARY (iter)) { + uint32_t binary_len; + uint8_t *binary; + bson_iter_overwrite_binary (iter, BSON_SUBTYPE_VECTOR, &binary_len, &binary); + return binary && bson_vector_int8_view_init (view_out, binary, binary_len); + } else { + return false; + } +} + +bool +bson_vector_int8_const_view_from_iter (bson_vector_int8_const_view_t *view_out, const bson_iter_t *iter) +{ + BSON_OPTIONAL_PARAM (view_out); + BSON_ASSERT_PARAM (iter); + if (BSON_ITER_HOLDS_BINARY (iter)) { + bson_subtype_t subtype; + uint32_t binary_len; + const uint8_t *binary; + bson_iter_binary (iter, &subtype, &binary_len, &binary); + return binary && subtype == BSON_SUBTYPE_VECTOR && + bson_vector_int8_const_view_init (view_out, binary, binary_len); + } else { + return false; + } +} + +bool +bson_vector_float32_view_from_iter (bson_vector_float32_view_t *view_out, bson_iter_t *iter) +{ + BSON_OPTIONAL_PARAM (view_out); + BSON_ASSERT_PARAM (iter); + if (BSON_ITER_HOLDS_BINARY (iter)) { + uint32_t binary_len; + uint8_t *binary; + bson_iter_overwrite_binary (iter, BSON_SUBTYPE_VECTOR, &binary_len, &binary); + return binary && bson_vector_float32_view_init (view_out, binary, binary_len); + } else { + return false; + } +} + +bool +bson_vector_float32_const_view_from_iter (bson_vector_float32_const_view_t *view_out, const bson_iter_t *iter) +{ + BSON_OPTIONAL_PARAM (view_out); + BSON_ASSERT_PARAM (iter); + if (BSON_ITER_HOLDS_BINARY (iter)) { + bson_subtype_t subtype; + uint32_t binary_len; + const uint8_t *binary; + bson_iter_binary (iter, &subtype, &binary_len, &binary); + return binary && subtype == BSON_SUBTYPE_VECTOR && + bson_vector_float32_const_view_init (view_out, binary, binary_len); + } else { + return false; + } +} + +bool +bson_vector_packed_bits_view_from_iter (bson_vector_packed_bits_view_t *view_out, bson_iter_t *iter) +{ + BSON_OPTIONAL_PARAM (view_out); + BSON_ASSERT_PARAM (iter); + if (BSON_ITER_HOLDS_BINARY (iter)) { + uint32_t binary_len; + uint8_t *binary; + bson_iter_overwrite_binary (iter, BSON_SUBTYPE_VECTOR, &binary_len, &binary); + return binary && bson_vector_packed_bits_view_init (view_out, binary, binary_len); + } else { + return false; + } +} + +bool +bson_vector_packed_bits_const_view_from_iter (bson_vector_packed_bits_const_view_t *view_out, const bson_iter_t *iter) +{ + BSON_OPTIONAL_PARAM (view_out); + BSON_ASSERT_PARAM (iter); + if (BSON_ITER_HOLDS_BINARY (iter)) { + bson_subtype_t subtype; + uint32_t binary_len; + const uint8_t *binary; + bson_iter_binary (iter, &subtype, &binary_len, &binary); + return binary && subtype == BSON_SUBTYPE_VECTOR && + bson_vector_packed_bits_const_view_init (view_out, binary, binary_len); + } else { + return false; + } +} + + +bool +bson_append_vector_int8 ( + bson_t *bson, const char *key, int key_length, size_t element_count, bson_vector_int8_view_t *view_out) +{ + BSON_ASSERT_PARAM (bson); + BSON_ASSERT_PARAM (view_out); + + uint32_t length = bson_vector_int8_binary_data_length (element_count); + if (length < BSON_VECTOR_HEADER_LEN) { + return false; + } + uint8_t *binary; + if (bson_append_binary_uninit (bson, key, key_length, BSON_SUBTYPE_VECTOR, &binary, length)) { + bson_vector_binary_header_impl_t header = { + .bytes[0] = bson_vector_header_byte_0 (BSON_VECTOR_ELEMENT_SIGNED_INT, BSON_VECTOR_ELEMENT_8_BITS), + .bytes[1] = bson_vector_header_byte_1 (0)}; + memcpy (binary, header.bytes, BSON_VECTOR_HEADER_LEN); + *view_out = + (bson_vector_int8_view_t){.binary.data = binary, .binary.data_len = length, .binary.header_copy = header}; + return true; + } else { + return false; + } +} + +bool +bson_append_vector_float32 ( + bson_t *bson, const char *key, int key_length, size_t element_count, bson_vector_float32_view_t *view_out) +{ + BSON_ASSERT_PARAM (bson); + BSON_ASSERT_PARAM (view_out); + + uint32_t length = bson_vector_float32_binary_data_length (element_count); + if (length < BSON_VECTOR_HEADER_LEN) { + return false; + } + uint8_t *binary; + if (bson_append_binary_uninit (bson, key, key_length, BSON_SUBTYPE_VECTOR, &binary, length)) { + bson_vector_binary_header_impl_t header = { + .bytes[0] = bson_vector_header_byte_0 (BSON_VECTOR_ELEMENT_FLOAT, BSON_VECTOR_ELEMENT_32_BITS), + .bytes[1] = bson_vector_header_byte_1 (0)}; + memcpy (binary, header.bytes, BSON_VECTOR_HEADER_LEN); + *view_out = + (bson_vector_float32_view_t){.binary.data = binary, .binary.data_len = length, .binary.header_copy = header}; + return true; + } else { + return false; + } +} + +bool +bson_append_vector_packed_bits ( + bson_t *bson, const char *key, int key_length, size_t element_count, bson_vector_packed_bits_view_t *view_out) +{ + BSON_ASSERT_PARAM (bson); + BSON_ASSERT_PARAM (view_out); + + uint32_t length = bson_vector_packed_bits_binary_data_length (element_count); + if (length < BSON_VECTOR_HEADER_LEN) { + return false; + } + uint8_t *binary; + if (bson_append_binary_uninit (bson, key, key_length, BSON_SUBTYPE_VECTOR, &binary, length)) { + size_t padding = (size_t) 7 & -element_count; + bson_vector_binary_header_impl_t header = { + .bytes[0] = bson_vector_header_byte_0 (BSON_VECTOR_ELEMENT_UNSIGNED_INT, BSON_VECTOR_ELEMENT_1_BIT), + .bytes[1] = bson_vector_header_byte_1 (padding)}; + memcpy (binary, header.bytes, BSON_VECTOR_HEADER_LEN); + if (element_count > 0 && padding > 0) { + // We must explicitly zero bits in the final byte that aren't part of any element. + // No reason to read-modify-write here, it's better to write the whole byte. + binary[length - 1u] = 0u; + } + *view_out = (bson_vector_packed_bits_view_t){ + .binary.data = binary, .binary.data_len = length, .binary.header_copy = header}; + return true; + } else { + return false; + } +} + +static bool +bson_vector_from_array_expect_key (const bson_iter_t *iter, size_t numeric_key, bson_error_t *error) +{ + char buffer[16]; + const char *key; + bson_uint32_to_string (numeric_key, &key, buffer, sizeof buffer); + if (0 == strcmp (key, bson_iter_key (iter))) { + return true; + } else { + bson_set_error (error, + BSON_ERROR_VECTOR, + BSON_VECTOR_ERROR_ARRAY_KEY, + "expected BSON array key '%s', found key '%s'", + key, + bson_iter_key (iter)); + return false; + } +} + +static void +bson_vector_set_error_max_size (bson_error_t *error) +{ + bson_set_error ( + error, BSON_ERROR_VECTOR, BSON_VECTOR_ERROR_MAX_SIZE, "maximum BSON document size would be exceeded"); +} + +bool +bson_append_vector_int8_from_array ( + bson_t *bson, const char *key, int key_length, const bson_iter_t *iter, bson_error_t *error) +{ + BSON_ASSERT_PARAM (bson); + BSON_ASSERT_PARAM (key); + BSON_ASSERT_PARAM (iter); + + size_t element_count = 0; + { + bson_iter_t validation_iter = *iter; + while (bson_iter_next (&validation_iter)) { + if (!bson_vector_from_array_expect_key (&validation_iter, element_count, error)) { + return false; + } + if (!BSON_ITER_HOLDS_INT (&validation_iter)) { + bson_set_error (error, + BSON_ERROR_VECTOR, + BSON_VECTOR_ERROR_ARRAY_ELEMENT_TYPE, + "expected int32 or int64 in BSON array key '%s', found item type 0x%02X", + bson_iter_key (&validation_iter), + (unsigned) bson_iter_type (&validation_iter)); + return false; + } + int64_t element_as_int64 = bson_iter_as_int64 (&validation_iter); + if (element_as_int64 < INT8_MIN || element_as_int64 > INT8_MAX) { + bson_set_error (error, + BSON_ERROR_VECTOR, + BSON_VECTOR_ERROR_ARRAY_ELEMENT_VALUE, + "BSON array key '%s' value %" PRId64 " is out of range for vector of int8", + bson_iter_key (&validation_iter), + element_as_int64); + return false; + } + element_count++; + } + } + + bson_vector_int8_view_t view; + if (!bson_append_vector_int8 (bson, key, key_length, element_count, &view)) { + bson_vector_set_error_max_size (error); + return false; + } + bson_iter_t copy_iter = *iter; + for (size_t i = 0; i < element_count; i++) { + BSON_ASSERT (bson_iter_next (©_iter)); + int8_t element = (int8_t) bson_iter_as_int64 (©_iter); + BSON_ASSERT (bson_vector_int8_view_write (view, &element, 1, i)); + } + return true; +} + +bool +bson_append_vector_float32_from_array ( + bson_t *bson, const char *key, int key_length, const bson_iter_t *iter, bson_error_t *error) +{ + BSON_ASSERT_PARAM (bson); + BSON_ASSERT_PARAM (key); + BSON_ASSERT_PARAM (iter); + + size_t element_count = 0; + { + bson_iter_t validation_iter = *iter; + while (bson_iter_next (&validation_iter)) { + if (!bson_vector_from_array_expect_key (&validation_iter, element_count, error)) { + return false; + } + if (!BSON_ITER_HOLDS_DOUBLE (&validation_iter)) { + bson_set_error (error, + BSON_ERROR_VECTOR, + BSON_VECTOR_ERROR_ARRAY_ELEMENT_TYPE, + "expected 'double' number type in BSON array key '%s', found item type 0x%02X", + bson_iter_key (&validation_iter), + (unsigned) bson_iter_type (&validation_iter)); + return false; + } + element_count++; + } + } + + bson_vector_float32_view_t view; + if (!bson_append_vector_float32 (bson, key, key_length, element_count, &view)) { + bson_vector_set_error_max_size (error); + return false; + } + bson_iter_t copy_iter = *iter; + for (size_t i = 0; i < element_count; i++) { + BSON_ASSERT (bson_iter_next (©_iter)); + float element = (float) bson_iter_double (©_iter); + BSON_ASSERT (bson_vector_float32_view_write (view, &element, 1, i)); + } + return true; +} + +bool +bson_append_vector_packed_bits_from_array ( + bson_t *bson, const char *key, int key_length, const bson_iter_t *iter, bson_error_t *error) +{ + BSON_ASSERT_PARAM (bson); + BSON_ASSERT_PARAM (key); + BSON_ASSERT_PARAM (iter); + + size_t element_count = 0; + { + bson_iter_t validation_iter = *iter; + while (bson_iter_next (&validation_iter)) { + if (!bson_vector_from_array_expect_key (&validation_iter, element_count, error)) { + return false; + } + if (!BSON_ITER_HOLDS_INT (&validation_iter) && !BSON_ITER_HOLDS_BOOL (&validation_iter)) { + bson_set_error (error, + BSON_ERROR_VECTOR, + BSON_VECTOR_ERROR_ARRAY_ELEMENT_TYPE, + "expected int32, int64, or bool in BSON array key '%s', found item type 0x%02X", + bson_iter_key (&validation_iter), + (unsigned) bson_iter_type (&validation_iter)); + return false; + } + int64_t element_as_int64 = bson_iter_as_int64 (&validation_iter); + if (element_as_int64 < 0 || element_as_int64 > 1) { + bson_set_error (error, + BSON_ERROR_VECTOR, + BSON_VECTOR_ERROR_ARRAY_ELEMENT_VALUE, + "BSON array key '%s' value %" PRId64 " is out of range for vector of packed_bits", + bson_iter_key (&validation_iter), + element_as_int64); + return false; + } + element_count++; + } + } + + bson_vector_packed_bits_view_t view; + if (!bson_append_vector_packed_bits (bson, key, key_length, element_count, &view)) { + bson_vector_set_error_max_size (error); + return false; + } + bson_iter_t copy_iter = *iter; + for (size_t i = 0; i < element_count; i++) { + BSON_ASSERT (bson_iter_next (©_iter)); + bool element_as_bool = (bool) bson_iter_as_int64 (©_iter); + BSON_ASSERT (bson_vector_packed_bits_view_pack_bool (view, &element_as_bool, 1, i)); + } + return true; +} + + +bool +bson_array_builder_append_vector_int8_elements (bson_array_builder_t *builder, bson_vector_int8_const_view_t view) +{ + BSON_ASSERT_PARAM (builder); + size_t length = bson_vector_int8_const_view_length (view); + for (size_t i = 0; i < length; i++) { + // Note, the zero initializer is only needed due to a false positive -Wmaybe-uninitialized warning in uncommon + // configurations where the compiler does not have visibility into memcpy(). + int8_t element = 0; + BSON_ASSERT (bson_vector_int8_const_view_read (view, &element, 1, i)); + if (!bson_array_builder_append_int32 (builder, (int32_t) element)) { + return false; + } + } + return true; +} + +bool +bson_array_builder_append_vector_float32_elements (bson_array_builder_t *builder, bson_vector_float32_const_view_t view) +{ + BSON_ASSERT_PARAM (builder); + size_t length = bson_vector_float32_const_view_length (view); + for (size_t i = 0; i < length; i++) { + float element; + BSON_ASSERT (bson_vector_float32_const_view_read (view, &element, 1, i)); + if (!bson_array_builder_append_double (builder, (double) element)) { + return false; + } + } + return true; +} + +bool +bson_array_builder_append_vector_packed_bits_elements (bson_array_builder_t *builder, + bson_vector_packed_bits_const_view_t view) +{ + BSON_ASSERT_PARAM (builder); + size_t length = bson_vector_packed_bits_const_view_length (view); + for (size_t i = 0; i < length; i++) { + bool element; + BSON_ASSERT (bson_vector_packed_bits_const_view_unpack_bool (view, &element, 1, i)); + if (!bson_array_builder_append_int32 (builder, element ? 1 : 0)) { + return false; + } + } + return true; +} + + +bool +bson_array_builder_append_vector_elements (bson_array_builder_t *builder, const bson_iter_t *iter) +{ + BSON_ASSERT_PARAM (builder); + BSON_ASSERT_PARAM (iter); + { + bson_vector_int8_const_view_t view; + if (bson_vector_int8_const_view_from_iter (&view, iter)) { + return bson_array_builder_append_vector_int8_elements (builder, view); + } + } + { + bson_vector_float32_const_view_t view; + if (bson_vector_float32_const_view_from_iter (&view, iter)) { + return bson_array_builder_append_vector_float32_elements (builder, view); + } + } + { + bson_vector_packed_bits_const_view_t view; + if (bson_vector_packed_bits_const_view_from_iter (&view, iter)) { + return bson_array_builder_append_vector_packed_bits_elements (builder, view); + } + } + return false; +} + + +bool +bson_append_array_from_vector_int8 (bson_t *bson, const char *key, int key_length, bson_vector_int8_const_view_t view) +{ + BSON_ASSERT_PARAM (bson); + BSON_ASSERT_PARAM (key); + bson_array_builder_t *child; + if (bson_append_array_builder_begin (bson, key, key_length, &child)) { + bool ok = bson_array_builder_append_vector_int8_elements (child, view); + return bson_append_array_builder_end (bson, child) && ok; + } else { + return false; + } +} + +bool +bson_append_array_from_vector_float32 (bson_t *bson, + const char *key, + int key_length, + bson_vector_float32_const_view_t view) +{ + BSON_ASSERT_PARAM (bson); + BSON_ASSERT_PARAM (key); + bson_array_builder_t *child; + if (bson_append_array_builder_begin (bson, key, key_length, &child)) { + bool ok = bson_array_builder_append_vector_float32_elements (child, view); + return bson_append_array_builder_end (bson, child) && ok; + } else { + return false; + } +} + +bool +bson_append_array_from_vector_packed_bits (bson_t *bson, + const char *key, + int key_length, + bson_vector_packed_bits_const_view_t view) +{ + BSON_ASSERT_PARAM (bson); + BSON_ASSERT_PARAM (key); + bson_array_builder_t *child; + if (bson_append_array_builder_begin (bson, key, key_length, &child)) { + bool ok = bson_array_builder_append_vector_packed_bits_elements (child, view); + return bson_append_array_builder_end (bson, child) && ok; + } else { + return false; + } +} + + +bool +bson_append_array_from_vector (bson_t *bson, const char *key, int key_length, const bson_iter_t *iter) +{ + BSON_ASSERT_PARAM (bson); + BSON_ASSERT_PARAM (key); + BSON_ASSERT_PARAM (iter); + bson_array_builder_t *child; + if (bson_append_array_builder_begin (bson, key, key_length, &child)) { + bool ok = bson_array_builder_append_vector_elements (child, iter); + return bson_append_array_builder_end (bson, child) && ok; + } else { + return false; + } +} diff --git a/src/libbson/src/bson/bson-vector.h b/src/libbson/src/bson/bson-vector.h new file mode 100644 index 00000000000..7f78d7f3b28 --- /dev/null +++ b/src/libbson/src/bson/bson-vector.h @@ -0,0 +1,578 @@ +/* + * Copyright 2009-present MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#ifndef BSON_VECTOR_H +#define BSON_VECTOR_H + +#include +#include +#include + +BSON_BEGIN_DECLS + + +// Length of the required header for BSON_SUBTYPE_VECTOR, in bytes +#define BSON_VECTOR_HEADER_LEN 2 + +// Forward declaration (typedef bson_array_builder_t in bson.h) +struct _bson_array_builder_t; + +/** @brief Error codes for domain BSON_ERROR_VECTOR */ +typedef enum { + BSON_VECTOR_ERROR_ARRAY_ELEMENT_TYPE = 1, + BSON_VECTOR_ERROR_ARRAY_ELEMENT_VALUE, + BSON_VECTOR_ERROR_ARRAY_KEY, + BSON_VECTOR_ERROR_MAX_SIZE, +} bson_vector_error_code_t; + + +/** @brief Implementation detail. A copy of the BSON_SUBTYPE_VECTOR header, suitable for pass-by-value. */ +typedef struct bson_vector_binary_header_impl_t { + uint8_t bytes[BSON_VECTOR_HEADER_LEN]; +} bson_vector_binary_header_impl_t; + +/** @brief Implementation detail. A reference to non-owned const BSON Binary data of subtype BSON_SUBTYPE_VECTOR */ +typedef struct bson_vector_binary_const_view_impl_t { + const uint8_t *data; + uint32_t data_len; + bson_vector_binary_header_impl_t header_copy; +} bson_vector_binary_const_view_impl_t; + +/** @brief Implementation detail. A reference to non-owned BSON Binary data of subtype BSON_SUBTYPE_VECTOR */ +typedef struct bson_vector_binary_view_impl_t { + uint8_t *data; + uint32_t data_len; + bson_vector_binary_header_impl_t header_copy; +} bson_vector_binary_view_impl_t; + +/** @brief Implementation detail. Obtain a const reference from a non-const reference without re-validating. */ +static BSON_INLINE bson_vector_binary_const_view_impl_t +bson_vector_binary_view_impl_as_const (bson_vector_binary_view_impl_t view) +{ + bson_vector_binary_const_view_impl_t result; + result.data = view.data; + result.data_len = view.data_len; + result.header_copy = view.header_copy; + return result; +} + + +/** @brief A reference to non-owned BSON Binary data holding a valid Vector of int8 element type */ +typedef struct bson_vector_int8_view_t { + bson_vector_binary_view_impl_t binary; +} bson_vector_int8_view_t; + +/** @brief A reference to non-owned const BSON Binary data holding a valid Vector of int8 element type */ +typedef struct bson_vector_int8_const_view_t { + bson_vector_binary_const_view_impl_t binary; +} bson_vector_int8_const_view_t; + +/** @brief A reference to non-owned BSON Binary data holding a valid Vector of float32 element type */ +typedef struct bson_vector_float32_view_t { + bson_vector_binary_view_impl_t binary; +} bson_vector_float32_view_t; + +/** @brief A reference to non-owned const BSON Binary data holding a valid Vector of float32 element type */ +typedef struct bson_vector_float32_const_view_t { + bson_vector_binary_const_view_impl_t binary; +} bson_vector_float32_const_view_t; + +/** @brief A reference to non-owned BSON Binary data holding a valid Vector of packed_bits */ +typedef struct bson_vector_packed_bits_view_t { + bson_vector_binary_view_impl_t binary; +} bson_vector_packed_bits_view_t; + +/** @brief A reference to non-owned const BSON Binary data holding a valid Vector of packed_bits */ +typedef struct bson_vector_packed_bits_const_view_t { + bson_vector_binary_const_view_impl_t binary; +} bson_vector_packed_bits_const_view_t; + + +static BSON_INLINE bson_vector_int8_const_view_t +bson_vector_int8_view_as_const (bson_vector_int8_view_t view) +{ + bson_vector_int8_const_view_t result; + result.binary = bson_vector_binary_view_impl_as_const (view.binary); + return result; +} + +static BSON_INLINE bson_vector_float32_const_view_t +bson_vector_float32_view_as_const (bson_vector_float32_view_t view) +{ + bson_vector_float32_const_view_t result; + result.binary = bson_vector_binary_view_impl_as_const (view.binary); + return result; +} + +static BSON_INLINE bson_vector_packed_bits_const_view_t +bson_vector_packed_bits_view_as_const (bson_vector_packed_bits_view_t view) +{ + bson_vector_packed_bits_const_view_t result; + result.binary = bson_vector_binary_view_impl_as_const (view.binary); + return result; +} + + +BSON_EXPORT (bool) +bson_vector_int8_view_init (bson_vector_int8_view_t *view_out, uint8_t *binary_data, uint32_t binary_data_len); + +BSON_EXPORT (bool) +bson_vector_int8_const_view_init (bson_vector_int8_const_view_t *view_out, + const uint8_t *binary_data, + uint32_t binary_data_len); + +BSON_EXPORT (bool) +bson_vector_float32_view_init (bson_vector_float32_view_t *view_out, uint8_t *binary_data, uint32_t binary_data_len); + + +BSON_EXPORT (bool) +bson_vector_float32_const_view_init (bson_vector_float32_const_view_t *view_out, + const uint8_t *binary_data, + uint32_t binary_data_len); + +BSON_EXPORT (bool) +bson_vector_packed_bits_view_init (bson_vector_packed_bits_view_t *view_out, + uint8_t *binary_data, + uint32_t binary_data_len); + +BSON_EXPORT (bool) +bson_vector_packed_bits_const_view_init (bson_vector_packed_bits_const_view_t *view_out, + const uint8_t *binary_data, + uint32_t binary_data_len); + + +BSON_EXPORT (bool) +bson_vector_int8_view_from_iter (bson_vector_int8_view_t *view_out, bson_iter_t *iter); + +BSON_EXPORT (bool) +bson_vector_int8_const_view_from_iter (bson_vector_int8_const_view_t *view_out, const bson_iter_t *iter); + +BSON_EXPORT (bool) +bson_vector_float32_view_from_iter (bson_vector_float32_view_t *view_out, bson_iter_t *iter); + +BSON_EXPORT (bool) +bson_vector_float32_const_view_from_iter (bson_vector_float32_const_view_t *view_out, const bson_iter_t *iter); + +BSON_EXPORT (bool) +bson_vector_packed_bits_view_from_iter (bson_vector_packed_bits_view_t *view_out, bson_iter_t *iter); + +BSON_EXPORT (bool) +bson_vector_packed_bits_const_view_from_iter (bson_vector_packed_bits_const_view_t *view_out, const bson_iter_t *iter); + + +BSON_EXPORT (bool) +bson_array_builder_append_vector_int8_elements (struct _bson_array_builder_t *builder, + bson_vector_int8_const_view_t view); + +BSON_EXPORT (bool) +bson_array_builder_append_vector_float32_elements (struct _bson_array_builder_t *builder, + bson_vector_float32_const_view_t view); + +BSON_EXPORT (bool) +bson_array_builder_append_vector_packed_bits_elements (struct _bson_array_builder_t *builder, + bson_vector_packed_bits_const_view_t view); + +BSON_EXPORT (bool) +bson_array_builder_append_vector_elements (struct _bson_array_builder_t *builder, const bson_iter_t *iter); + + +BSON_EXPORT (bool) +bson_append_vector_int8 ( + bson_t *bson, const char *key, int key_length, size_t element_count, bson_vector_int8_view_t *view_out); + +#define BSON_APPEND_VECTOR_INT8(b, key, count, view) bson_append_vector_int8 (b, key, (int) strlen (key), count, view) + +BSON_EXPORT (bool) +bson_append_vector_float32 ( + bson_t *bson, const char *key, int key_length, size_t element_count, bson_vector_float32_view_t *view_out); + +#define BSON_APPEND_VECTOR_FLOAT32(b, key, count, view) \ + bson_append_vector_float32 (b, key, (int) strlen (key), count, view) + +BSON_EXPORT (bool) +bson_append_vector_packed_bits ( + bson_t *bson, const char *key, int key_length, size_t element_count, bson_vector_packed_bits_view_t *view_out); + +#define BSON_APPEND_VECTOR_PACKED_BITS(b, key, count, view) \ + bson_append_vector_packed_bits (b, key, (int) strlen (key), count, view) + + +BSON_EXPORT (bool) +bson_append_vector_int8_from_array ( + bson_t *bson, const char *key, int key_length, const bson_iter_t *iter, bson_error_t *error); + +#define BSON_APPEND_VECTOR_INT8_FROM_ARRAY(b, key, iter, err) \ + bson_append_vector_int8_from_array (b, key, (int) strlen (key), iter, err) + +BSON_EXPORT (bool) +bson_append_vector_float32_from_array ( + bson_t *bson, const char *key, int key_length, const bson_iter_t *iter, bson_error_t *error); + +#define BSON_APPEND_VECTOR_FLOAT32_FROM_ARRAY(b, key, iter, err) \ + bson_append_vector_float32_from_array (b, key, (int) strlen (key), iter, err) + +BSON_EXPORT (bool) +bson_append_vector_packed_bits_from_array ( + bson_t *bson, const char *key, int key_length, const bson_iter_t *iter, bson_error_t *error); + +#define BSON_APPEND_VECTOR_PACKED_BITS_FROM_ARRAY(b, key, iter, err) \ + bson_append_vector_packed_bits_from_array (b, key, (int) strlen (key), iter, err) + + +BSON_EXPORT (bool) +bson_append_array_from_vector_int8 (bson_t *bson, const char *key, int key_length, bson_vector_int8_const_view_t view); + +#define BSON_APPEND_ARRAY_FROM_VECTOR_INT8(b, key, view) \ + bson_append_array_from_vector_int8 (b, key, (int) strlen (key), view) + +BSON_EXPORT (bool) +bson_append_array_from_vector_float32 (bson_t *bson, + const char *key, + int key_length, + bson_vector_float32_const_view_t view); + +#define BSON_APPEND_ARRAY_FROM_VECTOR_FLOAT32(b, key, view) \ + bson_append_array_from_vector_float32 (b, key, (int) strlen (key), view) + +BSON_EXPORT (bool) +bson_append_array_from_vector_packed_bits (bson_t *bson, + const char *key, + int key_length, + bson_vector_packed_bits_const_view_t view); + +#define BSON_APPEND_ARRAY_FROM_VECTOR_PACKED_BITS(b, key, view) \ + bson_append_array_from_vector_packed_bits (b, key, (int) strlen (key), view) + + +static BSON_INLINE uint32_t +bson_vector_int8_binary_data_length (size_t element_count) +{ + const size_t max_representable = (size_t) UINT32_MAX - (size_t) BSON_VECTOR_HEADER_LEN; + return element_count > max_representable ? 0u : (uint32_t) element_count + (uint32_t) BSON_VECTOR_HEADER_LEN; +} + +static BSON_INLINE uint32_t +bson_vector_float32_binary_data_length (size_t element_count) +{ + const size_t max_representable = ((size_t) UINT32_MAX - (size_t) BSON_VECTOR_HEADER_LEN) / sizeof (float); + return element_count > max_representable + ? 0u + : (uint32_t) element_count * sizeof (float) + (uint32_t) BSON_VECTOR_HEADER_LEN; +} + +static BSON_INLINE uint32_t +bson_vector_packed_bits_binary_data_length (size_t element_count) +{ + const size_t max_representable = (size_t) BSON_MIN ( + (uint64_t) SIZE_MAX, ((uint64_t) UINT32_MAX - (uint64_t) BSON_VECTOR_HEADER_LEN) * (uint64_t) 8); + return element_count > max_representable + ? 0u + : (uint32_t) ((element_count + (size_t) 7) / (size_t) 8) + (uint32_t) BSON_VECTOR_HEADER_LEN; +} + + +static BSON_INLINE size_t +bson_vector_int8_const_view_length (bson_vector_int8_const_view_t view) +{ + return view.binary.data_len - (uint32_t) BSON_VECTOR_HEADER_LEN; +} + +static BSON_INLINE size_t +bson_vector_int8_view_length (bson_vector_int8_view_t view) +{ + return bson_vector_int8_const_view_length (bson_vector_int8_view_as_const (view)); +} + +static BSON_INLINE size_t +bson_vector_float32_const_view_length (bson_vector_float32_const_view_t view) +{ + return (view.binary.data_len - (uint32_t) BSON_VECTOR_HEADER_LEN) / (uint32_t) sizeof (float); +} + +static BSON_INLINE size_t +bson_vector_float32_view_length (bson_vector_float32_view_t view) +{ + return bson_vector_float32_const_view_length (bson_vector_float32_view_as_const (view)); +} + +static BSON_INLINE size_t +bson_vector_packed_bits_const_view_length_bytes (bson_vector_packed_bits_const_view_t view) +{ + return view.binary.data_len - (uint32_t) BSON_VECTOR_HEADER_LEN; +} + +static BSON_INLINE size_t +bson_vector_packed_bits_view_length_bytes (bson_vector_packed_bits_view_t view) +{ + return bson_vector_packed_bits_const_view_length_bytes (bson_vector_packed_bits_view_as_const (view)); +} + +// Implementation detail, not part of documented API. +static BSON_INLINE size_t +bson_vector_padding_from_header_byte_1 (uint8_t byte_1) +{ + return byte_1 & 7; +} + +static BSON_INLINE size_t +bson_vector_packed_bits_const_view_padding (bson_vector_packed_bits_const_view_t view) +{ + return bson_vector_padding_from_header_byte_1 (view.binary.header_copy.bytes[1]); +} + +static BSON_INLINE size_t +bson_vector_packed_bits_view_padding (bson_vector_packed_bits_view_t view) +{ + return bson_vector_packed_bits_const_view_padding (bson_vector_packed_bits_view_as_const (view)); +} + +static BSON_INLINE size_t +bson_vector_packed_bits_const_view_length (bson_vector_packed_bits_const_view_t view) +{ + return bson_vector_packed_bits_const_view_length_bytes (view) * (size_t) 8 - + bson_vector_packed_bits_const_view_padding (view); +} + +static BSON_INLINE size_t +bson_vector_packed_bits_view_length (bson_vector_packed_bits_view_t view) +{ + return bson_vector_packed_bits_const_view_length (bson_vector_packed_bits_view_as_const (view)); +} + + +static BSON_INLINE bool +bson_vector_int8_const_view_read (bson_vector_int8_const_view_t view, + int8_t *BSON_RESTRICT values_out, + size_t element_count, + size_t vector_offset_elements) +{ + size_t length = bson_vector_int8_const_view_length (view); + if (BSON_LIKELY (vector_offset_elements <= length && element_count <= length - vector_offset_elements)) { + memcpy (values_out, view.binary.data + BSON_VECTOR_HEADER_LEN + vector_offset_elements, element_count); + return true; + } else { + return false; + } +} + +static BSON_INLINE bool +bson_vector_int8_view_read (bson_vector_int8_view_t view, + int8_t *BSON_RESTRICT values_out, + size_t element_count, + uint32_t vector_offset_elements) +{ + return bson_vector_int8_const_view_read ( + bson_vector_int8_view_as_const (view), values_out, element_count, vector_offset_elements); +} + +static BSON_INLINE bool +bson_vector_int8_view_write (bson_vector_int8_view_t view, + const int8_t *BSON_RESTRICT values, + size_t element_count, + size_t vector_offset_elements) +{ + size_t length = bson_vector_int8_view_length (view); + if (BSON_LIKELY (vector_offset_elements <= length && element_count <= length - vector_offset_elements)) { + memcpy (view.binary.data + BSON_VECTOR_HEADER_LEN + vector_offset_elements, values, element_count); + return true; + } else { + return false; + } +} + + +BSON_STATIC_ASSERT2 (float_is_float32, sizeof (float) == 4); + +static BSON_INLINE bool +bson_vector_float32_const_view_read (bson_vector_float32_const_view_t view, + float *BSON_RESTRICT values_out, + size_t element_count, + size_t vector_offset_elements) +{ + size_t length = bson_vector_float32_const_view_length (view); + if (BSON_LIKELY (vector_offset_elements <= length && element_count <= length - vector_offset_elements)) { + size_t byte_offset = BSON_VECTOR_HEADER_LEN + vector_offset_elements * 4; +#if BSON_BYTE_ORDER == BSON_LITTLE_ENDIAN + memcpy (values_out, view.binary.data + byte_offset, element_count * 4); +#else + size_t i; + for (i = 0; i < element_count; i++) { + float aligned_tmp; + memcpy (&aligned_tmp, view.binary.data + byte_offset + i * 4, 4); + values_out[i] = BSON_FLOAT_FROM_LE (aligned_tmp); + } +#endif + return true; + } else { + return false; + } +} + +static BSON_INLINE bool +bson_vector_float32_view_read (bson_vector_float32_view_t view, + float *BSON_RESTRICT values_out, + size_t element_count, + size_t vector_offset_elements) +{ + return bson_vector_float32_const_view_read ( + bson_vector_float32_view_as_const (view), values_out, element_count, vector_offset_elements); +} + +static BSON_INLINE bool +bson_vector_float32_view_write (bson_vector_float32_view_t view, + const float *BSON_RESTRICT values, + size_t element_count, + size_t vector_offset_elements) +{ + size_t length = bson_vector_float32_view_length (view); + if (BSON_LIKELY (vector_offset_elements <= length && element_count <= length - vector_offset_elements)) { + size_t byte_offset = BSON_VECTOR_HEADER_LEN + vector_offset_elements * 4; +#if BSON_BYTE_ORDER == BSON_LITTLE_ENDIAN + memcpy (view.binary.data + byte_offset, values, element_count * 4); +#else + size_t i; + for (i = 0; i < element_count; i++) { + float aligned_tmp = BSON_FLOAT_TO_LE (values[i]); + memcpy (view.binary.data + byte_offset + i * 4, &aligned_tmp, 4); + } +#endif + return true; + } else { + return false; + } +} + + +static BSON_INLINE bool +bson_vector_packed_bits_const_view_read_packed (bson_vector_packed_bits_const_view_t view, + uint8_t *BSON_RESTRICT packed_values_out, + size_t byte_count, + size_t vector_offset_bytes) +{ + size_t length_bytes = bson_vector_packed_bits_const_view_length_bytes (view); + if (BSON_LIKELY (vector_offset_bytes <= length_bytes && byte_count <= length_bytes - vector_offset_bytes)) { + memcpy (packed_values_out, view.binary.data + BSON_VECTOR_HEADER_LEN + vector_offset_bytes, byte_count); + return true; + } else { + return false; + } +} + +static BSON_INLINE bool +bson_vector_packed_bits_view_read_packed (bson_vector_packed_bits_view_t view, + uint8_t *BSON_RESTRICT packed_values_out, + size_t byte_count, + size_t vector_offset_bytes) +{ + return bson_vector_packed_bits_const_view_read_packed ( + bson_vector_packed_bits_view_as_const (view), packed_values_out, byte_count, vector_offset_bytes); +} + +static BSON_INLINE bool +bson_vector_packed_bits_view_write_packed (bson_vector_packed_bits_view_t view, + const uint8_t *BSON_RESTRICT packed_values, + size_t byte_count, + size_t vector_offset_bytes) +{ + size_t length_bytes = bson_vector_packed_bits_view_length_bytes (view); + if (BSON_LIKELY (vector_offset_bytes <= length_bytes && byte_count <= length_bytes - vector_offset_bytes)) { + if (byte_count == length_bytes - vector_offset_bytes && byte_count >= 1u) { + // This write touches the last byte in the vector: + // special-case that byte so we can ensure unused bits remain set to zero. + size_t other_bytes = byte_count - 1u; + memcpy (view.binary.data + BSON_VECTOR_HEADER_LEN + vector_offset_bytes, packed_values, other_bytes); + view.binary.data[BSON_VECTOR_HEADER_LEN + vector_offset_bytes + other_bytes] = + ((uint8_t) 0xFF << bson_vector_packed_bits_view_padding (view)) & packed_values[other_bytes]; + } else { + memcpy (view.binary.data + BSON_VECTOR_HEADER_LEN + vector_offset_bytes, packed_values, byte_count); + } + return true; + } else { + return false; + } +} + + +static BSON_INLINE bool +bson_vector_packed_bits_const_view_unpack_bool (bson_vector_packed_bits_const_view_t view, + bool *BSON_RESTRICT unpacked_values_out, + size_t element_count, + size_t vector_offset_elements) +{ + size_t length = bson_vector_packed_bits_const_view_length (view); + if (BSON_LIKELY (vector_offset_elements <= length && element_count <= length - vector_offset_elements)) { + size_t i; + for (i = 0; i < element_count; i++) { + size_t element_index = vector_offset_elements + i; + uint8_t packed_byte = view.binary.data[BSON_VECTOR_HEADER_LEN + (element_index >> 3)]; + unpacked_values_out[i] = 0 != (packed_byte & ((uint8_t) 0x80 >> (element_index & 7))); + } + return true; + } else { + return false; + } +} + +static BSON_INLINE bool +bson_vector_packed_bits_view_unpack_bool (bson_vector_packed_bits_view_t view, + bool *BSON_RESTRICT unpacked_values_out, + size_t element_count, + size_t vector_offset_elements) +{ + return bson_vector_packed_bits_const_view_unpack_bool ( + bson_vector_packed_bits_view_as_const (view), unpacked_values_out, element_count, vector_offset_elements); +} + +static BSON_INLINE bool +bson_vector_packed_bits_view_pack_bool (bson_vector_packed_bits_view_t view, + const bool *BSON_RESTRICT unpacked_values, + size_t element_count, + size_t vector_offset_elements) +{ + size_t length = bson_vector_packed_bits_view_length (view); + if (BSON_LIKELY (vector_offset_elements <= length && element_count <= length - vector_offset_elements)) { + while (element_count > 0) { + uint8_t *BSON_RESTRICT packed_byte = &view.binary.data[BSON_VECTOR_HEADER_LEN + (vector_offset_elements >> 3)]; + if (element_count >= 8 && (vector_offset_elements & 7) == 0) { + uint8_t complete_byte = 0; + unsigned i; + for (i = 0; i < 8; i++) { + complete_byte |= unpacked_values[i] ? ((uint8_t) 0x80 >> i) : 0; + } + *packed_byte = complete_byte; + unpacked_values += 8; + vector_offset_elements += 8; + element_count -= 8; + } else { + uint8_t mask = (uint8_t) 0x80 >> (vector_offset_elements & 7); + *packed_byte = (*packed_byte & ~mask) | (*unpacked_values ? mask : 0); + unpacked_values++; + vector_offset_elements++; + element_count--; + } + } + return true; + } else { + return false; + } +} + + +BSON_END_DECLS + +#endif /* BSON_VECTOR_H */ diff --git a/src/libbson/tests/test-bson-vector.c b/src/libbson/tests/test-bson-vector.c new file mode 100644 index 00000000000..fc1b694d6b8 --- /dev/null +++ b/src/libbson/tests/test-bson-vector.c @@ -0,0 +1,1400 @@ +/* + * Copyright 2009-present MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include + +#include "bsonutil/bson-parser.h" +#include "TestSuite.h" +#include "test-conveniences.h" +#include "json-test.h" + +#ifdef _MSC_VER +#define SSCANF sscanf_s +#else +#define SSCANF sscanf +#endif + +struct view_abi_reference_type { + void *data; + uint32_t data_len; + uint8_t header_0; + uint8_t header_1; +}; + +/* ABI: Make sure vector views have the expected size. */ +#define EXPECTED_VECTOR_VIEW_SIZE (sizeof (struct view_abi_reference_type)) +BSON_STATIC_ASSERT2 (sizeof_bson_vector_int8_const_view_t, + sizeof (bson_vector_int8_const_view_t) == EXPECTED_VECTOR_VIEW_SIZE); +BSON_STATIC_ASSERT2 (sizeof_bson_vector_int8_view_t, sizeof (bson_vector_int8_view_t) == EXPECTED_VECTOR_VIEW_SIZE); +BSON_STATIC_ASSERT2 (sizeof_bson_vector_float32_const_view_t, + sizeof (bson_vector_float32_const_view_t) == EXPECTED_VECTOR_VIEW_SIZE); +BSON_STATIC_ASSERT2 (sizeof_bson_vector_float32_view_t, + sizeof (bson_vector_float32_view_t) == EXPECTED_VECTOR_VIEW_SIZE); +BSON_STATIC_ASSERT2 (sizeof_bson_vector_packed_bits_const_view_t, + sizeof (bson_vector_packed_bits_const_view_t) == EXPECTED_VECTOR_VIEW_SIZE); +BSON_STATIC_ASSERT2 (sizeof_bson_vector_packed_bits_view_t, + sizeof (bson_vector_packed_bits_view_t) == EXPECTED_VECTOR_VIEW_SIZE); +#undef EXPECTED_VECTOR_VIEW_SIZE + +typedef struct vector_json_test_case_t { + char *scenario_description, *scenario_test_key; + char *test_description, *test_dtype_hex_str, *test_dtype_alias_str, *test_canonical_bson_str; + bson_t *test_vector_array; + int64_t *test_padding; + bool *test_valid; +} vector_json_test_case_t; + +static void +translate_json_test_vector (bson_t *array_in, bson_t *array_out) +{ + // Patches JSON tests until DRIVERS-3095 is resolved: + // - convert "inf" to a double +Infinity + // - convert "-inf" to a double -Infinity + + bson_iter_t iter_in; + BSON_ASSERT (bson_iter_init (&iter_in, array_in)); + bson_array_builder_t *builder = bson_array_builder_new (); + while (bson_iter_next (&iter_in)) { + if (BSON_ITER_HOLDS_UTF8 (&iter_in) && 0 == strcmp ("inf", bson_iter_utf8 (&iter_in, NULL))) { + BSON_ASSERT (bson_array_builder_append_double (builder, INFINITY)); + } else if (BSON_ITER_HOLDS_UTF8 (&iter_in) && 0 == strcmp ("-inf", bson_iter_utf8 (&iter_in, NULL))) { + BSON_ASSERT (bson_array_builder_append_double (builder, -INFINITY)); + } else { + BSON_ASSERT (bson_array_builder_append_iter (builder, &iter_in)); + } + } + BSON_ASSERT (bson_array_builder_build (builder, array_out)); + bson_array_builder_destroy (builder); +} + +static bool +append_vector_packed_bits_from_packed_array ( + bson_t *bson, const char *key, int key_length, const bson_iter_t *iter, int64_t padding, bson_error_t *error) +{ + // (TODO for DRIVERS-3095, DRIVERS-3097) This implements something the test covers that our API doesn't. If the test + // were modified to cover element-by-element conversion, this can be replaced with + // bson_append_vector_packed_bits_from_array. + + BSON_ASSERT_PARAM (bson); + BSON_ASSERT_PARAM (key); + BSON_ASSERT_PARAM (iter); + + size_t byte_count = 0; + { + bson_iter_t validation_iter = *iter; + while (bson_iter_next (&validation_iter)) { + if (!BSON_ITER_HOLDS_INT (&validation_iter)) { + bson_set_error (error, + BSON_ERROR_VECTOR, + BSON_VECTOR_ERROR_ARRAY_ELEMENT_TYPE, + "expected int32 or int64 in BSON array key '%s', found item type 0x%02X", + bson_iter_key (&validation_iter), + (unsigned) bson_iter_type (&validation_iter)); + return false; + } + int64_t byte_as_int64 = bson_iter_as_int64 (&validation_iter); + if (byte_as_int64 < 0 || byte_as_int64 > UINT8_MAX) { + bson_set_error (error, + BSON_ERROR_VECTOR, + BSON_VECTOR_ERROR_ARRAY_ELEMENT_VALUE, + "BSON array key '%s' value %" PRId64 " is out of range for packed byte", + bson_iter_key (&validation_iter), + byte_as_int64); + return false; + } + byte_count++; + } + } + + if (padding < 0 || padding > 7) { + bson_set_error (error, + TEST_ERROR_DOMAIN, + TEST_ERROR_CODE, + "'padding' parameter (%" PRId64 + ") for append_vector_packed_bits_from_packed_array is out of range", + padding); + return false; + } + if (byte_count < 1 && padding > 0) { + bson_set_error (error, + TEST_ERROR_DOMAIN, + TEST_ERROR_CODE, + "nonzero 'padding' parameter (%" PRId64 + ") for zero-length append_vector_packed_bits_from_packed_array", + padding); + return false; + } + + bson_vector_packed_bits_view_t view; + if (bson_append_vector_packed_bits (bson, key, key_length, byte_count * 8 - padding, &view)) { + bson_iter_t copy_iter = *iter; + for (size_t i = 0; i < byte_count; i++) { + BSON_ASSERT (bson_iter_next (©_iter)); + uint8_t packed_byte = (uint8_t) bson_iter_as_int64 (©_iter); + BSON_ASSERT (bson_vector_packed_bits_view_write_packed (view, &packed_byte, 1, i)); + } + return true; + } else { + return false; + } +} + +static void +hex_str_to_bson (bson_t *bson_out, const char *hex_str) +{ + uint32_t size = strlen (hex_str) / 2; + uint8_t *buffer = bson_reserve_buffer (bson_out, size); + for (uint32_t i = 0; i < size; i++) { + unsigned int byte; + BSON_ASSERT (SSCANF (&hex_str[i * 2], "%2x", &byte) == 1); + buffer[i] = (uint8_t) byte; + } +} + +// Implement spec tests, given parsed arguments +static void +test_bson_vector_json_case (vector_json_test_case_t *test_case) +{ + bson_t expected_bson = BSON_INITIALIZER; + if (test_case->test_canonical_bson_str) { + hex_str_to_bson (&expected_bson, test_case->test_canonical_bson_str); + } + + BSON_ASSERT (test_case->test_valid); + BSON_ASSERT (test_case->test_dtype_hex_str); + BSON_ASSERT (test_case->scenario_test_key); + + bson_t vector_from_array = BSON_INITIALIZER; + bson_error_t vector_from_array_error; + bool vector_from_array_ok; + + // (TODO for DRIVERS-3095, DRIVERS-3097) Patch test cases that have unused bits set to '1' when '0' is required. + if (0 == strcmp ("PACKED_BIT with padding", test_case->test_description)) { + bson_iter_t iter; + BSON_ASSERT (bson_iter_init_find (&iter, &expected_bson, test_case->scenario_test_key)); + uint32_t binary_len; + uint8_t *binary; + bson_iter_overwrite_binary (&iter, BSON_SUBTYPE_VECTOR, &binary_len, &binary); + BSON_ASSERT (binary_len > BSON_VECTOR_HEADER_LEN); + binary[binary_len - 1] &= (uint8_t) 0xFF << bson_vector_padding_from_header_byte_1 (binary[1]); + } + + // Try a format conversion from array to the indicated vector format. + // The spec calls the first header byte "dtype" (combining the element type and element size fields) + if (0 == strcmp ("0x03", test_case->test_dtype_hex_str)) { + // int8 vector from int32/int64 array + bson_iter_t iter; + bool padding_ok = !test_case->test_padding || *test_case->test_padding == 0; + vector_from_array_ok = test_case->test_vector_array && padding_ok && + bson_iter_init (&iter, test_case->test_vector_array) && + BSON_APPEND_VECTOR_INT8_FROM_ARRAY ( + &vector_from_array, test_case->scenario_test_key, &iter, &vector_from_array_error); + } else if (0 == strcmp ("0x27", test_case->test_dtype_hex_str)) { + // float32 vector from float64 array + // (TODO for DRIVERS-3095) Convert the unusual numeric array format to a standard array + bson_t converted = BSON_INITIALIZER; + bool padding_ok = !test_case->test_padding || *test_case->test_padding == 0; + if (test_case->test_vector_array && padding_ok) { + bson_iter_t iter; + translate_json_test_vector (test_case->test_vector_array, &converted); + vector_from_array_ok = bson_iter_init (&iter, &converted) && + BSON_APPEND_VECTOR_FLOAT32_FROM_ARRAY ( + &vector_from_array, test_case->scenario_test_key, &iter, &vector_from_array_error); + } else { + vector_from_array_ok = false; + } + bson_destroy (&converted); + } else if (0 == strcmp ("0x10", test_case->test_dtype_hex_str)) { + // packed_bits from packed bytes in an int array, with "padding" parameter supplied separately. + // TODO for DRIVERS-3095, DRIVERS-3097: + // - Array-to-Vector should be defined as an element-by-element conversion. This test shouldn't operate on packed + // representations. + // - Include additional JSON tests for packed access, distinct from Array conversion. + // - Tests should keep the unused bits zeroed as required. + bson_iter_t iter; + if (!test_case->test_padding) { + test_error ("test '%s' is missing required 'padding' field", test_case->test_description); + } + vector_from_array_ok = test_case->test_vector_array && bson_iter_init (&iter, test_case->test_vector_array) && + append_vector_packed_bits_from_packed_array (&vector_from_array, + test_case->scenario_test_key, + -1, + &iter, + *test_case->test_padding, + &vector_from_array_error); + } else { + test_error ( + "test '%s' has unsupported dtype_hex format '%s'", test_case->test_description, test_case->test_dtype_hex_str); + } + + if (*test_case->test_valid) { + /* + * "To prove correct in a valid case (valid: true), one MUST + * - encode a document from the numeric values, dtype, and padding, along with the "test_key", and assert this + * matches the canonical_bson string. + * - decode the canonical_bson into its binary form, and then assert that the numeric values, dtype, and padding + * all match those provided in the JSON." + */ + + // Check the vector-from-array performed above ("encode") + + if (!test_case->test_vector_array) { + test_error ("test '%s' should be valid, but missing 'vector' field", test_case->test_description); + } + + if (!vector_from_array_ok) { + test_error ("test '%s' should be valid, but vector-from-array failed: %s", + test_case->test_description, + vector_from_array_error.message); + } + + if (0 != bson_compare (&vector_from_array, &expected_bson)) { + test_error ("test '%s' did not exactly match the reference document.\n " + "Actual: %s\n Expected: %s", + test_case->test_description, + tmp_json (&vector_from_array), + tmp_json (&expected_bson)); + } + + // Perform an array-from-vector and check it ("decode") + + bson_iter_t iter; + BSON_ASSERT (bson_iter_init_find (&iter, &expected_bson, test_case->scenario_test_key)); + + bson_t array_from_vector = BSON_INITIALIZER; + { + bson_array_builder_t *array_builder = bson_array_builder_new (); + if (!bson_array_builder_append_vector_elements (array_builder, &iter)) { + test_error ("test '%s' should be valid but failed array-from-vector conversion", + test_case->test_description); + } + BSON_ASSERT (bson_array_builder_build (array_builder, &array_from_vector)); + bson_array_builder_destroy (array_builder); + } + + // (TODO for DRIVERS-3095, DRIVERS-3097) Due to loosely defined element types and rounding behavior in the test + // vectors, this comparison can't be exact. Temporary special cases are needed for float32 and packed_bits. + + if (BSON_ITER_HOLDS_VECTOR_FLOAT32 (&iter)) { + // float32 special case: We need to handle the nonstandard "inf" and "-inf" forms, and + // due to underspecified rounding and conversion rules we compare value inexactly. + + bson_iter_t actual_iter, expected_iter; + BSON_ASSERT (bson_iter_init (&actual_iter, &array_from_vector)); + BSON_ASSERT (bson_iter_init (&expected_iter, test_case->test_vector_array)); + + for (size_t i = 0;; i++) { + bool actual_next = bson_iter_next (&actual_iter); + bool expected_next = bson_iter_next (&expected_iter); + if (!actual_next && !expected_next) { + break; + } else if (!actual_next) { + test_error ("converted array is shorter than expected"); + } else if (!expected_next) { + test_error ("converted array is longer than expected"); + } + + if (!BSON_ITER_HOLDS_DOUBLE (&actual_iter)) { + test_error ("converted array element %d has unexpected type, should be double", (int) i); + } + double actual_double = bson_iter_double (&actual_iter); + + double expected_double; + if (BSON_ITER_HOLDS_UTF8 (&expected_iter) && 0 == strcmp ("inf", bson_iter_utf8 (&expected_iter, NULL))) { + expected_double = INFINITY; + } else if (BSON_ITER_HOLDS_UTF8 (&expected_iter) && + 0 == strcmp ("-inf", bson_iter_utf8 (&expected_iter, NULL))) { + expected_double = -INFINITY; + } else if (BSON_ITER_HOLDS_DOUBLE (&expected_iter)) { + expected_double = bson_iter_double (&expected_iter); + } else { + test_error ("test-vector array element %d has unexpected type, should be double, 'inf', or '-inf'.", + (int) i); + } + + bool is_sorta_equal = false; + if (expected_double != expected_double) { + // Expect NaN, any type is fine. + if (actual_double != actual_double) { + is_sorta_equal = true; + } + } else if (expected_double == 0 || expected_double * 0 != 0) { + // Infinity or zero, equality comparison is fine. + is_sorta_equal = expected_double == actual_double; + } else { + // Finite number, allow +/- error relative to the scale of the expected value. + // Note that ASSERT_EQUAL_DOUBLE() in TestSuite exists but its fixed error threshold of 20% seems too + // loose for this application. + static const double allowed_relative_error = 1e-7; + double allowed_absolute_error = fabs (allowed_relative_error * expected_double); + is_sorta_equal = actual_double >= expected_double - allowed_absolute_error && + actual_double <= expected_double + allowed_absolute_error; + } + if (!is_sorta_equal) { + test_error ("test-vector array element %d failed inexact float32 match. Actual: %f Expected: %f", + (int) i, + actual_double, + expected_double); + } + } + + } else if (BSON_ITER_HOLDS_VECTOR_PACKED_BITS (&iter)) { + // packed_bits special case: The tests for packed_bits aren't actually testing vector-to-array conversion as we + // understand it, they're operating on bytes rather than elements. This is the inverse of + // append_vector_packed_bits_from_packed_array() above, and it bypasses the vector-to-array conversion. + // 'array_from_vector' is ignored on this path. + + bson_iter_t expected_iter; + BSON_ASSERT (bson_iter_init (&expected_iter, test_case->test_vector_array)); + bson_vector_packed_bits_const_view_t actual_view; + BSON_ASSERT (bson_vector_packed_bits_const_view_from_iter (&actual_view, &iter)); + + size_t byte_count = 0; + while (bson_iter_next (&expected_iter)) { + int64_t expected_byte; + if (BSON_ITER_HOLDS_INT (&expected_iter)) { + expected_byte = bson_iter_as_int64 (&expected_iter); + } else { + test_error ("test-vector array element %d has unexpected type, should be int.", (int) byte_count); + } + + // (TODO for DRIVERS-3095, DRIVERS-3097) Packed writes can't set unused bits to '1' in libbson, but the spec + // tests allow padding bits to take on undefined values. Modify the expected values to keep padding bits + // zeroed. + if (0 == strcmp ("PACKED_BIT with padding", test_case->test_description) && + byte_count == bson_vector_packed_bits_const_view_length_bytes (actual_view) - 1u) { + expected_byte &= ((int64_t) 0xFF << *test_case->test_padding) & 0xFF; + } + + // Note, the zero initializer is only needed due to a false positive -Wmaybe-uninitialized warning in + // uncommon configurations where the compiler does not have visibility into memcpy(). + uint8_t actual_byte = 0; + BSON_ASSERT (bson_vector_packed_bits_const_view_read_packed (actual_view, &actual_byte, 1, byte_count)); + + if (expected_byte != (int64_t) actual_byte) { + test_error ("failed to match packed byte %d of packed_bits test-vector. Actual: 0x%02x Expected: 0x%02x", + (int) byte_count, + (unsigned) actual_byte, + (unsigned) expected_byte); + } + byte_count++; + } + ASSERT_CMPSIZE_T (byte_count, ==, bson_vector_packed_bits_const_view_length_bytes (actual_view)); + + } else { + // No special case, expect an exact match. (Used for int8 vectors) + if (0 != bson_compare (&array_from_vector, test_case->test_vector_array)) { + test_error ("bson_binary_vector JSON scenario '%s' test '%s' did not exactly match the reference array " + "after array-from-vector.\n " + "Actual: %s\n Expected: %s", + test_case->scenario_description, + test_case->test_description, + tmp_json (&array_from_vector), + tmp_json (test_case->test_vector_array)); + } + } + + bson_destroy (&array_from_vector); + } else { + /* + * "To prove correct in an invalid case (valid:false), one MUST + * - if the vector field is present, raise an exception when attempting to encode a document from the numeric + * values, dtype, and padding. + * - if the canonical_bson field is present, raise an exception when attempting to deserialize it into the + * corresponding numeric values, as the field contains corrupted data." + */ + + if (vector_from_array_ok) { + test_error ("bson_binary_vector JSON scenario '%s' test '%s' should be invalid but vector-from-array " + "succeeded with result: %s", + test_case->scenario_description, + test_case->test_description, + tmp_json (&vector_from_array)); + } + + if (test_case->test_canonical_bson_str) { + bson_t array_from_vector = BSON_INITIALIZER; + bson_iter_t iter; + BSON_ASSERT (bson_iter_init_find (&iter, &expected_bson, test_case->scenario_test_key)); + if (BSON_APPEND_ARRAY_FROM_VECTOR (&array_from_vector, "should_fail", &iter)) { + test_error ("bson_binary_vector JSON scenario '%s' test '%s' should be invalid but array-from-vector " + "succeeded with result: %s", + test_case->scenario_description, + test_case->test_description, + tmp_json (&array_from_vector)); + } + bson_destroy (&array_from_vector); + } + } + + bson_destroy (&expected_bson); +} + +// callback for install_json_test_suite_with_check, implements JSON spec tests +static void +test_bson_vector_json_cb (void *test_arg) +{ + BSON_ASSERT_PARAM (test_arg); + bson_t *scenario = (bson_t *) test_arg; + bson_error_t error; + vector_json_test_case_t test_case; + + bson_parser_t *scenario_opts = bson_parser_new (); + bson_t *tests; + bson_parser_utf8 (scenario_opts, "description", &test_case.scenario_description); + bson_parser_utf8 (scenario_opts, "test_key", &test_case.scenario_test_key); + bson_parser_array (scenario_opts, "tests", &tests); + if (!bson_parser_parse (scenario_opts, scenario, &error)) { + test_error ("format error in bson_binary_vector JSON scenario: %s", error.message); + } + + bson_iter_t tests_iter; + ASSERT (bson_iter_init (&tests_iter, tests)); + while (bson_iter_next (&tests_iter)) { + bson_t test_subdoc; + bson_iter_bson (&tests_iter, &test_subdoc); + + bson_parser_t *test_opts = bson_parser_new (); + bson_parser_utf8 (test_opts, "description", &test_case.test_description); + bson_parser_bool (test_opts, "valid", &test_case.test_valid); + bson_parser_array_optional (test_opts, "vector", &test_case.test_vector_array); + bson_parser_utf8 (test_opts, "dtype_hex", &test_case.test_dtype_hex_str); + bson_parser_utf8 (test_opts, "dtype_alias", &test_case.test_dtype_alias_str); + bson_parser_int_optional (test_opts, "padding", &test_case.test_padding); + bson_parser_utf8_optional (test_opts, "canonical_bson", &test_case.test_canonical_bson_str); + if (!bson_parser_parse (test_opts, &test_subdoc, &error)) { + test_error ( + "format error in bson_binary_vector JSON test for '%s': %s", test_case.scenario_description, error.message); + } + + if (test_suite_debug_output ()) { + printf ("bson_binary_vector JSON scenario '%s' test '%s'\n", + test_case.scenario_description, + test_case.test_description); + } + + test_bson_vector_json_case (&test_case); + bson_parser_destroy_with_parsed_fields (test_opts); + } + bson_parser_destroy_with_parsed_fields (scenario_opts); +} + +static void +test_bson_vector_view_api_usage_int8 (void) +{ + bson_t doc = BSON_INITIALIZER; + + // Construct a small vector by writing individual elements + { + bson_vector_int8_view_t view; + const size_t length = 25; + ASSERT (BSON_APPEND_VECTOR_INT8 (&doc, "vector", length, &view)); + for (size_t i = 0; i < length; i++) { + int8_t v = (int8_t) i - 9; + bson_vector_int8_view_write (view, &v, 1, i); + } + } + + ASSERT_CMPJSON ( + bson_as_canonical_extended_json (&doc, NULL), + BSON_STR ({"vector" : {"$binary" : {"base64" : "AwD3+Pn6+/z9/v8AAQIDBAUGBwgJCgsMDQ4P", "subType" : "09"}}})); + + // Construct a longer vector by writing individual elements + { + bson_vector_int8_view_t view; + const size_t length = 50000; + ASSERT (bson_append_vector_int8 (&doc, "longer_vector", -1, length, &view)); + for (size_t i = 0; i < length; i++) { + int8_t v = (int8_t) (uint8_t) i; + bson_vector_int8_view_write (view, &v, 1, i); + } + } + + // Fail appending a vector that would be too large to represent + { + bson_vector_int8_view_t view; + const size_t length = UINT32_MAX - 1; + ASSERT (!bson_append_vector_int8 (&doc, "overlong_vector", -1, length, &view)); + } + + // Use a mutable view to partially overwrite "vector" + { + bson_iter_t iter; + ASSERT (bson_iter_init_find (&iter, &doc, "vector")); + bson_vector_int8_view_t view; + ASSERT (bson_vector_int8_view_from_iter (&view, &iter)); + ASSERT (bson_vector_int8_view_length (view) == 25); + int8_t values[5] = {12, 34, 56, 78, 90}; + ASSERT (bson_vector_int8_view_write (view, values, sizeof values / sizeof values[0], 3)); + } + + // Read the modified small vector into an int8_t array + { + bson_iter_t iter; + ASSERT (bson_iter_init_find (&iter, &doc, "vector")); + ASSERT (BSON_ITER_HOLDS_BINARY (&iter)); + ASSERT (BSON_ITER_HOLDS_VECTOR (&iter)); + ASSERT (BSON_ITER_HOLDS_VECTOR_INT8 (&iter)); + ASSERT (!BSON_ITER_HOLDS_VECTOR_FLOAT32 (&iter)); + ASSERT (!BSON_ITER_HOLDS_VECTOR_PACKED_BITS (&iter)); + bson_vector_int8_const_view_t view; + ASSERT (bson_vector_int8_const_view_from_iter (&view, &iter)); + ASSERT (bson_vector_int8_const_view_length (view) == 25); + int8_t values[25]; + static const int8_t expected_values[25] = {-9, -8, -7, 12, 34, 56, 78, 90, -1, 0, 1, 2, 3, + 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; + ASSERT (bson_vector_int8_const_view_read (view, values, sizeof values / sizeof values[0], 0)); + ASSERT_MEMCMP (values, expected_values, (int) sizeof expected_values); + } + + // Convert the small vector to a BSON Array, and check the resulting canonical extended JSON. + // Each element will be losslessly converted to int32. + // Convert the output back, and add a "round_trip" key to the original document. + { + bson_t converted = BSON_INITIALIZER; + bson_iter_t iter; + ASSERT (bson_iter_init_find (&iter, &doc, "vector")); + ASSERT (BSON_APPEND_ARRAY_FROM_VECTOR (&converted, "array", &iter)); + ASSERT_CMPJSON (bson_as_canonical_extended_json (&converted, NULL), BSON_STR ({ + "array" : [ + {"$numberInt" : "-9"}, {"$numberInt" : "-8"}, {"$numberInt" : "-7"}, {"$numberInt" : "12"}, + {"$numberInt" : "34"}, {"$numberInt" : "56"}, {"$numberInt" : "78"}, {"$numberInt" : "90"}, + {"$numberInt" : "-1"}, {"$numberInt" : "0"}, {"$numberInt" : "1"}, {"$numberInt" : "2"}, + {"$numberInt" : "3"}, {"$numberInt" : "4"}, {"$numberInt" : "5"}, {"$numberInt" : "6"}, + {"$numberInt" : "7"}, {"$numberInt" : "8"}, {"$numberInt" : "9"}, {"$numberInt" : "10"}, + {"$numberInt" : "11"}, {"$numberInt" : "12"}, {"$numberInt" : "13"}, {"$numberInt" : "14"}, + {"$numberInt" : "15"} + ] + })); + + ASSERT (bson_iter_init_find (&iter, &converted, "array")); + ASSERT (BSON_ITER_HOLDS_ARRAY (&iter)); + ASSERT (bson_iter_recurse (&iter, &iter)); + ASSERT (BSON_APPEND_VECTOR_INT8_FROM_ARRAY (&doc, "round_trip", &iter, NULL)); + bson_destroy (&converted); + } + + // The original small vector and round_trip small vector must be identical + { + bson_iter_t a, b; + ASSERT (bson_iter_init_find (&a, &doc, "vector")); + ASSERT (bson_iter_init_find (&b, &doc, "round_trip")); + ASSERT (bson_iter_binary_equal (&a, &b)); + } + + // Try the same round trip conversion with our longer vector + // (Note that BSON arrays special-case keys below "1000") + { + bson_t converted = BSON_INITIALIZER; + bson_iter_t iter; + ASSERT (bson_iter_init_find (&iter, &doc, "longer_vector")); + ASSERT (BSON_APPEND_ARRAY_FROM_VECTOR (&converted, "array", &iter)); + ASSERT (bson_iter_init_find (&iter, &converted, "array")); + ASSERT (BSON_ITER_HOLDS_ARRAY (&iter)); + ASSERT (bson_iter_recurse (&iter, &iter)); + ASSERT (BSON_APPEND_VECTOR_INT8_FROM_ARRAY (&doc, "longer_round_trip", &iter, NULL)); + bson_destroy (&converted); + } + { + bson_iter_t a, b; + ASSERT (bson_iter_init_find (&a, &doc, "longer_vector")); + ASSERT (bson_iter_init_find (&b, &doc, "longer_round_trip")); + ASSERT (bson_iter_binary_equal (&a, &b)); + } + + bson_destroy (&doc); +} + +static void +test_bson_vector_view_api_usage_float32 (void) +{ + bson_t doc = BSON_INITIALIZER; + + // Construct a small vector by writing individual elements + { + bson_vector_float32_view_t view; + const size_t length = 5; + ASSERT (BSON_APPEND_VECTOR_FLOAT32 (&doc, "vector", length, &view)); + for (size_t i = 0; i < length; i++) { + float v = 1.0f + 0.25f * (float) i; + bson_vector_float32_view_write (view, &v, 1, i); + } + } + + ASSERT_CMPJSON ( + bson_as_canonical_extended_json (&doc, NULL), + BSON_STR ({"vector" : {"$binary" : {"base64" : "JwAAAIA/AACgPwAAwD8AAOA/AAAAQA==", "subType" : "09"}}})); + + // Construct a longer vector by writing individual elements + { + bson_vector_float32_view_t view; + const size_t length = 10000; + ASSERT (bson_append_vector_float32 (&doc, "longer_vector", -1, length, &view)); + for (size_t i = 0; i < length; i++) { + float v = (float) i; + bson_vector_float32_view_write (view, &v, 1, i); + } + } + + // Fail appending a vector that would be too large to represent + { + bson_vector_float32_view_t view; + const size_t length = (UINT32_MAX - 1) / 4; + ASSERT (!bson_append_vector_float32 (&doc, "overlong_vector", -1, length, &view)); + } + + // Read the small vector into a float array + { + bson_iter_t iter; + ASSERT (bson_iter_init_find (&iter, &doc, "vector")); + ASSERT (BSON_ITER_HOLDS_BINARY (&iter)); + ASSERT (BSON_ITER_HOLDS_VECTOR (&iter)); + ASSERT (!BSON_ITER_HOLDS_VECTOR_INT8 (&iter)); + ASSERT (BSON_ITER_HOLDS_VECTOR_FLOAT32 (&iter)); + ASSERT (!BSON_ITER_HOLDS_VECTOR_PACKED_BITS (&iter)); + bson_vector_float32_const_view_t view; + ASSERT (bson_vector_float32_const_view_from_iter (&view, &iter)); + ASSERT (bson_vector_float32_const_view_length (view) == 5); + float values[5]; + static const float expected_values[5] = {1.0f, 1.25f, 1.5f, 1.75f, 2.0f}; + ASSERT (bson_vector_float32_const_view_read (view, values, sizeof values / sizeof values[0], 0)); + ASSERT_MEMCMP (values, expected_values, (int) sizeof expected_values); + } + + // Convert the small vector to a BSON Array, and check the resulting canonical extended JSON. + // Each element will be converted from 32-bit to 64-bit float. + // Convert the output back, and add a "round_trip" key to the original document. + { + bson_t converted = BSON_INITIALIZER; + bson_iter_t iter; + ASSERT (bson_iter_init_find (&iter, &doc, "vector")); + ASSERT (BSON_APPEND_ARRAY_FROM_VECTOR (&converted, "array", &iter)); + ASSERT_CMPJSON (bson_as_canonical_extended_json (&converted, NULL), BSON_STR ({ + "array" : [ + {"$numberDouble" : "1.0"}, + {"$numberDouble" : "1.25"}, + {"$numberDouble" : "1.5"}, + {"$numberDouble" : "1.75"}, + {"$numberDouble" : "2.0"} + ] + })); + + ASSERT (bson_iter_init_find (&iter, &converted, "array")); + ASSERT (BSON_ITER_HOLDS_ARRAY (&iter)); + ASSERT (bson_iter_recurse (&iter, &iter)); + ASSERT (BSON_APPEND_VECTOR_FLOAT32_FROM_ARRAY (&doc, "round_trip", &iter, NULL)); + bson_destroy (&converted); + } + + // The original small vector and round_trip small vector must be identical + { + bson_iter_t a, b; + ASSERT (bson_iter_init_find (&a, &doc, "vector")); + ASSERT (bson_iter_init_find (&b, &doc, "round_trip")); + ASSERT (bson_iter_binary_equal (&a, &b)); + } + + // Try the same round trip conversion with our longer vector + // (Note that BSON arrays special-case keys below "1000") + { + bson_t converted = BSON_INITIALIZER; + bson_iter_t iter; + ASSERT (bson_iter_init_find (&iter, &doc, "longer_vector")); + ASSERT (BSON_APPEND_ARRAY_FROM_VECTOR (&converted, "array", &iter)); + ASSERT (bson_iter_init_find (&iter, &converted, "array")); + ASSERT (BSON_ITER_HOLDS_ARRAY (&iter)); + ASSERT (bson_iter_recurse (&iter, &iter)); + ASSERT (BSON_APPEND_VECTOR_FLOAT32_FROM_ARRAY (&doc, "longer_round_trip", &iter, NULL)); + bson_destroy (&converted); + } + { + bson_iter_t a, b; + ASSERT (bson_iter_init_find (&a, &doc, "longer_vector")); + ASSERT (bson_iter_init_find (&b, &doc, "longer_round_trip")); + ASSERT (bson_iter_binary_equal (&a, &b)); + } + + bson_destroy (&doc); +} + +static void +test_bson_vector_view_api_usage_packed_bits (void) +{ + bson_t doc = BSON_INITIALIZER; + + // Construct a small vector by packing individual elements from a 'bool' source + { + bson_vector_packed_bits_view_t view; + const size_t length = 123; + ASSERT (BSON_APPEND_VECTOR_PACKED_BITS (&doc, "vector", length, &view)); + for (size_t i = 0; i < length; i++) { + bool v = (i & 1) != 0; + bson_vector_packed_bits_view_pack_bool (view, &v, 1, i); + } + } + + ASSERT_CMPJSON (bson_as_canonical_extended_json (&doc, NULL), + BSON_STR ({"vector" : {"$binary" : {"base64" : "EAVVVVVVVVVVVVVVVVVVVVVA", "subType" : "09"}}})); + + // Construct a longer vector by packing individual elements from a 'bool' source + { + bson_vector_packed_bits_view_t view; + const size_t length = 100002; + ASSERT (bson_append_vector_packed_bits (&doc, "longer_vector", -1, length, &view)); + for (size_t i = 0; i < length; i++) { + bool v = (i & 3) != 0; + bson_vector_packed_bits_view_pack_bool (view, &v, 1, i); + } + } + + // Fail appending a vector that would be too large to represent + { + bson_vector_int8_view_t view; + const size_t length = (UINT32_MAX - 1) * (size_t) 8; + ASSERT (!bson_append_vector_int8 (&doc, "overlong_vector", -1, length, &view)); + } + + // Unpack the small vector into a bool array + { + bson_iter_t iter; + ASSERT (bson_iter_init_find (&iter, &doc, "vector")); + ASSERT (BSON_ITER_HOLDS_BINARY (&iter)); + ASSERT (BSON_ITER_HOLDS_VECTOR (&iter)); + ASSERT (!BSON_ITER_HOLDS_VECTOR_INT8 (&iter)); + ASSERT (!BSON_ITER_HOLDS_VECTOR_FLOAT32 (&iter)); + ASSERT (BSON_ITER_HOLDS_VECTOR_PACKED_BITS (&iter)); + bson_vector_packed_bits_const_view_t view; + ASSERT (bson_vector_packed_bits_const_view_from_iter (&view, &iter)); + ASSERT (bson_vector_packed_bits_const_view_length (view) == 123); + bool values[123]; + bool expected_values[123]; + for (size_t i = 0; i < sizeof expected_values / sizeof expected_values[0]; i++) { + expected_values[i] = (i & 1) != 0; + } + ASSERT (bson_vector_packed_bits_const_view_unpack_bool (view, values, sizeof values / sizeof values[0], 0)); + ASSERT_MEMCMP (values, expected_values, (int) sizeof expected_values); + } + + // Read the packed representation without unpacking + { + bson_iter_t iter; + ASSERT (bson_iter_init_find (&iter, &doc, "vector")); + bson_vector_packed_bits_const_view_t view; + ASSERT (bson_vector_packed_bits_const_view_from_iter (&view, &iter)); + ASSERT (bson_vector_packed_bits_const_view_length (view) == 123); + uint8_t packed[16]; + static const uint8_t expected_packed[16] = { + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x40}; + ASSERT (bson_vector_packed_bits_const_view_read_packed (view, packed, sizeof packed, 0)); + ASSERT_MEMCMP (packed, expected_packed, (int) sizeof expected_packed); + } + + // Partial overwrite of the packed representation + { + bson_iter_t iter; + ASSERT (bson_iter_init_find (&iter, &doc, "vector")); + bson_vector_packed_bits_view_t view; + ASSERT (bson_vector_packed_bits_view_from_iter (&view, &iter)); + uint8_t packed[2] = {0x12, 0x34}; + ASSERT (bson_vector_packed_bits_view_write_packed (view, packed, sizeof packed, 12)); + } + + // Partial read of the packed representation + { + bson_iter_t iter; + ASSERT (bson_iter_init_find (&iter, &doc, "vector")); + bson_vector_packed_bits_const_view_t view; + ASSERT (bson_vector_packed_bits_const_view_from_iter (&view, &iter)); + uint8_t packed[5]; + static const uint8_t expected_packed[5] = {0x55, 0x12, 0x34, 0x55, 0x40}; + ASSERT (bson_vector_packed_bits_const_view_read_packed (view, packed, sizeof packed, 11)); + ASSERT_MEMCMP (packed, expected_packed, (int) sizeof expected_packed); + } + + // Partial write from a bool array, spanning complete and partial packed bytes + { + bson_iter_t iter; + ASSERT (bson_iter_init_find (&iter, &doc, "vector")); + bson_vector_packed_bits_view_t view; + ASSERT (bson_vector_packed_bits_view_from_iter (&view, &iter)); + bool values[24] = { + false, false, false, true, false, false, false, true, true, true, false, true, + true, false, false, false, false, true, false, false, false, false, false, true, + }; + ASSERT (bson_vector_packed_bits_view_pack_bool (view, values, sizeof values / sizeof values[0], 3)); + } + + // Convert the small vector to a BSON Array, and check the resulting canonical extended JSON. + // Each element will be losslessly converted to int32. + // Convert the output back, and add a "round_trip" key to the original document. + { + bson_t converted = BSON_INITIALIZER; + bson_iter_t iter; + ASSERT (bson_iter_init_find (&iter, &doc, "vector")); + ASSERT (BSON_APPEND_ARRAY_FROM_VECTOR (&converted, "array", &iter)); + ASSERT_CMPJSON (bson_as_canonical_extended_json (&converted, NULL), BSON_STR ({ + "array" : [ + {"$numberInt" : "0"}, {"$numberInt" : "1"}, {"$numberInt" : "0"}, {"$numberInt" : "0"}, + {"$numberInt" : "0"}, {"$numberInt" : "0"}, {"$numberInt" : "1"}, {"$numberInt" : "0"}, + {"$numberInt" : "0"}, {"$numberInt" : "0"}, {"$numberInt" : "1"}, {"$numberInt" : "1"}, + {"$numberInt" : "1"}, {"$numberInt" : "0"}, {"$numberInt" : "1"}, {"$numberInt" : "1"}, + {"$numberInt" : "0"}, {"$numberInt" : "0"}, {"$numberInt" : "0"}, {"$numberInt" : "0"}, + {"$numberInt" : "1"}, {"$numberInt" : "0"}, {"$numberInt" : "0"}, {"$numberInt" : "0"}, + {"$numberInt" : "0"}, {"$numberInt" : "0"}, {"$numberInt" : "1"}, {"$numberInt" : "1"}, + {"$numberInt" : "0"}, {"$numberInt" : "1"}, {"$numberInt" : "0"}, {"$numberInt" : "1"}, + {"$numberInt" : "0"}, {"$numberInt" : "1"}, {"$numberInt" : "0"}, {"$numberInt" : "1"}, + {"$numberInt" : "0"}, {"$numberInt" : "1"}, {"$numberInt" : "0"}, {"$numberInt" : "1"}, + {"$numberInt" : "0"}, {"$numberInt" : "1"}, {"$numberInt" : "0"}, {"$numberInt" : "1"}, + {"$numberInt" : "0"}, {"$numberInt" : "1"}, {"$numberInt" : "0"}, {"$numberInt" : "1"}, + {"$numberInt" : "0"}, {"$numberInt" : "1"}, {"$numberInt" : "0"}, {"$numberInt" : "1"}, + {"$numberInt" : "0"}, {"$numberInt" : "1"}, {"$numberInt" : "0"}, {"$numberInt" : "1"}, + {"$numberInt" : "0"}, {"$numberInt" : "1"}, {"$numberInt" : "0"}, {"$numberInt" : "1"}, + {"$numberInt" : "0"}, {"$numberInt" : "1"}, {"$numberInt" : "0"}, {"$numberInt" : "1"}, + {"$numberInt" : "0"}, {"$numberInt" : "1"}, {"$numberInt" : "0"}, {"$numberInt" : "1"}, + {"$numberInt" : "0"}, {"$numberInt" : "1"}, {"$numberInt" : "0"}, {"$numberInt" : "1"}, + {"$numberInt" : "0"}, {"$numberInt" : "1"}, {"$numberInt" : "0"}, {"$numberInt" : "1"}, + {"$numberInt" : "0"}, {"$numberInt" : "1"}, {"$numberInt" : "0"}, {"$numberInt" : "1"}, + {"$numberInt" : "0"}, {"$numberInt" : "1"}, {"$numberInt" : "0"}, {"$numberInt" : "1"}, + {"$numberInt" : "0"}, {"$numberInt" : "1"}, {"$numberInt" : "0"}, {"$numberInt" : "1"}, + {"$numberInt" : "0"}, {"$numberInt" : "1"}, {"$numberInt" : "0"}, {"$numberInt" : "1"}, + {"$numberInt" : "0"}, {"$numberInt" : "1"}, {"$numberInt" : "0"}, {"$numberInt" : "1"}, + {"$numberInt" : "0"}, {"$numberInt" : "0"}, {"$numberInt" : "0"}, {"$numberInt" : "1"}, + {"$numberInt" : "0"}, {"$numberInt" : "0"}, {"$numberInt" : "1"}, {"$numberInt" : "0"}, + {"$numberInt" : "0"}, {"$numberInt" : "0"}, {"$numberInt" : "1"}, {"$numberInt" : "1"}, + {"$numberInt" : "0"}, {"$numberInt" : "1"}, {"$numberInt" : "0"}, {"$numberInt" : "0"}, + {"$numberInt" : "0"}, {"$numberInt" : "1"}, {"$numberInt" : "0"}, {"$numberInt" : "1"}, + {"$numberInt" : "0"}, {"$numberInt" : "1"}, {"$numberInt" : "0"}, {"$numberInt" : "1"}, + {"$numberInt" : "0"}, {"$numberInt" : "1"}, {"$numberInt" : "0"} + ] + })); + + ASSERT (bson_iter_init_find (&iter, &converted, "array")); + ASSERT (BSON_ITER_HOLDS_ARRAY (&iter)); + ASSERT (bson_iter_recurse (&iter, &iter)); + ASSERT (BSON_APPEND_VECTOR_PACKED_BITS_FROM_ARRAY (&doc, "round_trip", &iter, NULL)); + bson_destroy (&converted); + } + + // The original small vector and round_trip small vector must be identical + { + bson_iter_t a, b; + ASSERT (bson_iter_init_find (&a, &doc, "vector")); + ASSERT (bson_iter_init_find (&b, &doc, "round_trip")); + ASSERT (bson_iter_binary_equal (&a, &b)); + } + + // Try the same round trip conversion with our longer vector + // (Note that BSON arrays special-case keys below "1000") + { + bson_t converted = BSON_INITIALIZER; + bson_iter_t iter; + ASSERT (bson_iter_init_find (&iter, &doc, "longer_vector")); + ASSERT (BSON_APPEND_ARRAY_FROM_VECTOR (&converted, "array", &iter)); + ASSERT (bson_iter_init_find (&iter, &converted, "array")); + ASSERT (BSON_ITER_HOLDS_ARRAY (&iter)); + ASSERT (bson_iter_recurse (&iter, &iter)); + ASSERT (BSON_APPEND_VECTOR_PACKED_BITS_FROM_ARRAY (&doc, "longer_round_trip", &iter, NULL)); + bson_destroy (&converted); + } + { + bson_iter_t a, b; + ASSERT (bson_iter_init_find (&a, &doc, "longer_vector")); + ASSERT (bson_iter_init_find (&b, &doc, "longer_round_trip")); + ASSERT (bson_iter_binary_equal (&a, &b)); + } + + // Padding bits will be initialized to zero when a packed_bits vector is first allocated by + // bson_append_vector_packed_bits + { + // Set the uninitialized part of 'doc' to a known value + static const uint32_t reserve_len = 512; + memset (bson_reserve_buffer (&doc, doc.len + reserve_len) + doc.len, 0xdd, reserve_len); + + bson_vector_packed_bits_view_t view; + ASSERT (BSON_APPEND_VECTOR_PACKED_BITS (&doc, "padding_init_test", 12, &view)); + ASSERT (bson_vector_packed_bits_view_length_bytes (view) == 2); + ASSERT (bson_vector_packed_bits_view_padding (view) == 4); + + // BSON validity only requires the low 4 bits to be zero, but the entire last + // byte will be zeroed by our implementation. + uint8_t bytes[2]; + ASSERT (bson_vector_packed_bits_view_read_packed (view, bytes, sizeof bytes, 0)); + ASSERT_CMPUINT ((unsigned) bytes[0], ==, 0xdd); + ASSERT_CMPUINT ((unsigned) bytes[1], ==, 0x00); + } + + // Padding bits can't be forcibly given nonzero values using bson_vector_packed_bits_view_write_packed + { + bson_vector_packed_bits_view_t view; + ASSERT (BSON_APPEND_VECTOR_PACKED_BITS (&doc, "padding_mask_test", 13, &view)); + ASSERT (bson_vector_packed_bits_view_length_bytes (view) == 2); + ASSERT (bson_vector_packed_bits_view_padding (view) == 3); + + uint8_t bytes[2] = {0xff, 0xff}; + ASSERT (bson_vector_packed_bits_view_write_packed (view, bytes, sizeof bytes, 0)); + ASSERT (bson_vector_packed_bits_view_read_packed (view, bytes, sizeof bytes, 0)); + ASSERT_CMPUINT ((unsigned) bytes[0], ==, 0xff); + ASSERT_CMPUINT ((unsigned) bytes[1], ==, 0xf8); + } + + bson_destroy (&doc); +} + +#define MAX_TESTED_VECTOR_LENGTH 10000 +#define FUZZ_TEST_ITERS 5000 + +static void +test_bson_vector_view_api_fuzz_int8 (void) +{ + size_t current_length = 0; + bson_t vector_doc = BSON_INITIALIZER; + int8_t *expected_elements = bson_malloc (MAX_TESTED_VECTOR_LENGTH * sizeof *expected_elements); + int8_t *actual_elements = bson_malloc (MAX_TESTED_VECTOR_LENGTH * sizeof *actual_elements); + for (int fuzz_iter = 0; fuzz_iter < FUZZ_TEST_ITERS; fuzz_iter++) { + int r = rand (); + int r_operation = r & 0xF; + int r_param = r >> 4; + + if (current_length == 0 || r_operation == 15) { + // Resize and fill + size_t new_length = (size_t) r_param % MAX_TESTED_VECTOR_LENGTH; + bson_reinit (&vector_doc); + bson_vector_int8_view_t view; + BSON_ASSERT (BSON_APPEND_VECTOR_INT8 (&vector_doc, "vector", new_length, &view)); + for (size_t i = 0; i < new_length; i++) { + expected_elements[i] = (int8_t) (uint8_t) rand (); + } + BSON_ASSERT (bson_vector_int8_view_write (view, expected_elements, new_length, 0)); + current_length = new_length; + + } else if (r_operation < 7) { + // Partial write + size_t element_count = r_param % current_length; + size_t offset = rand () % (current_length - element_count); + for (size_t i = 0; i < element_count; i++) { + expected_elements[offset + i] = (int8_t) (uint8_t) rand (); + } + bson_vector_int8_view_t view; + bson_iter_t iter; + BSON_ASSERT (bson_iter_init_find (&iter, &vector_doc, "vector")); + BSON_ASSERT (bson_vector_int8_view_from_iter (&view, &iter)); + BSON_ASSERT (bson_vector_int8_view_write (view, expected_elements + offset, element_count, offset)); + + } else { + // Partial read + size_t element_count = r_param % current_length; + size_t offset = rand () % (current_length - element_count); + bson_vector_int8_const_view_t view; + bson_iter_t iter; + BSON_ASSERT (bson_iter_init_find (&iter, &vector_doc, "vector")); + BSON_ASSERT (bson_vector_int8_const_view_from_iter (&view, &iter)); + BSON_ASSERT (bson_vector_int8_const_view_read (view, actual_elements, element_count, offset)); + for (size_t i = 0; i < element_count; i++) { + BSON_ASSERT (actual_elements[i] == expected_elements[i + offset]); + } + } + } + bson_destroy (&vector_doc); + bson_free (expected_elements); + bson_free (actual_elements); +} + +static void +test_bson_vector_view_api_fuzz_float32 (void) +{ + size_t current_length = 0; + bson_t vector_doc = BSON_INITIALIZER; + float *expected_elements = bson_malloc (MAX_TESTED_VECTOR_LENGTH * sizeof *expected_elements); + float *actual_elements = bson_malloc (MAX_TESTED_VECTOR_LENGTH * sizeof *actual_elements); + for (int fuzz_iter = 0; fuzz_iter < FUZZ_TEST_ITERS; fuzz_iter++) { + int r = rand (); + int r_operation = r & 0xF; + int r_param = r >> 4; + + if (current_length == 0 || r_operation == 15) { + // Resize and fill + size_t new_length = (size_t) r_param % MAX_TESTED_VECTOR_LENGTH; + bson_reinit (&vector_doc); + bson_vector_float32_view_t view; + BSON_ASSERT (BSON_APPEND_VECTOR_FLOAT32 (&vector_doc, "vector", new_length, &view)); + for (size_t i = 0; i < new_length; i++) { + expected_elements[i] = (float) rand (); + } + BSON_ASSERT (bson_vector_float32_view_write (view, expected_elements, new_length, 0)); + current_length = new_length; + + } else if (r_operation < 7) { + // Partial write + size_t element_count = r_param % current_length; + size_t offset = rand () % (current_length - element_count); + for (size_t i = 0; i < element_count; i++) { + expected_elements[offset + i] = (float) rand (); + } + bson_vector_float32_view_t view; + bson_iter_t iter; + BSON_ASSERT (bson_iter_init_find (&iter, &vector_doc, "vector")); + BSON_ASSERT (bson_vector_float32_view_from_iter (&view, &iter)); + BSON_ASSERT (bson_vector_float32_view_write (view, expected_elements + offset, element_count, offset)); + + } else { + // Partial read + size_t element_count = r_param % current_length; + size_t offset = rand () % (current_length - element_count); + bson_vector_float32_const_view_t view; + bson_iter_t iter; + BSON_ASSERT (bson_iter_init_find (&iter, &vector_doc, "vector")); + BSON_ASSERT (bson_vector_float32_const_view_from_iter (&view, &iter)); + BSON_ASSERT (bson_vector_float32_const_view_read (view, actual_elements, element_count, offset)); + for (size_t i = 0; i < element_count; i++) { + BSON_ASSERT (actual_elements[i] == expected_elements[i + offset]); + } + } + } + bson_destroy (&vector_doc); + bson_free (expected_elements); + bson_free (actual_elements); +} + +static void +test_bson_vector_view_api_fuzz_packed_bits (void) +{ + size_t current_length = 0; + bson_t vector_doc = BSON_INITIALIZER; + bool *expected_elements = bson_malloc (MAX_TESTED_VECTOR_LENGTH * sizeof *expected_elements); + bool *actual_elements = bson_malloc (MAX_TESTED_VECTOR_LENGTH * sizeof *actual_elements); + uint8_t *packed_buffer = bson_malloc ((MAX_TESTED_VECTOR_LENGTH + 7) / 8); + for (int fuzz_iter = 0; fuzz_iter < FUZZ_TEST_ITERS; fuzz_iter++) { + int r = rand (); + int r_operation = r & 0xF; + int r_param = r >> 4; + + if (current_length == 0 || r_operation == 15) { + // Resize and fill from unpacked bool source + size_t new_length = (size_t) r_param % MAX_TESTED_VECTOR_LENGTH; + bson_reinit (&vector_doc); + bson_vector_packed_bits_view_t view; + BSON_ASSERT (BSON_APPEND_VECTOR_PACKED_BITS (&vector_doc, "vector", new_length, &view)); + for (size_t i = 0; i < new_length; i++) { + expected_elements[i] = (rand () & 1) != 0; + } + BSON_ASSERT (bson_vector_packed_bits_view_pack_bool (view, expected_elements, new_length, 0)); + current_length = new_length; + + } else if (r_operation < 7) { + // Partial write + if (r_operation & 1) { + // Partial write from unpacked bool source + size_t element_count = r_param % current_length; + size_t offset = rand () % (current_length - element_count); + for (size_t i = 0; i < element_count; i++) { + expected_elements[offset + i] = (rand () & 1) != 0; + } + bson_vector_packed_bits_view_t view; + bson_iter_t iter; + BSON_ASSERT (bson_iter_init_find (&iter, &vector_doc, "vector")); + BSON_ASSERT (bson_vector_packed_bits_view_from_iter (&view, &iter)); + BSON_ASSERT (bson_vector_packed_bits_view_length (view) == current_length); + BSON_ASSERT ( + bson_vector_packed_bits_view_pack_bool (view, expected_elements + offset, element_count, offset)); + } else { + // Partial write of packed bytes + size_t current_length_bytes = (current_length + 7) / 8; + size_t byte_count = r_param % current_length_bytes; + size_t byte_offset = rand () % (current_length_bytes - byte_count); + for (size_t i = 0; i < byte_count; i++) { + uint8_t packed_byte = (uint8_t) rand (); + packed_buffer[i] = packed_byte; + for (unsigned bit = 0; bit < 8; bit++) { + expected_elements[(byte_offset + i) * 8 + bit] = (packed_byte & (0x80 >> bit)) != 0; + } + } + bson_vector_packed_bits_view_t view; + bson_iter_t iter; + BSON_ASSERT (bson_iter_init_find (&iter, &vector_doc, "vector")); + BSON_ASSERT (bson_vector_packed_bits_view_from_iter (&view, &iter)); + BSON_ASSERT (bson_vector_packed_bits_view_length (view) == current_length); + BSON_ASSERT (bson_vector_packed_bits_view_length_bytes (view) == current_length_bytes); + BSON_ASSERT (bson_vector_packed_bits_view_write_packed (view, packed_buffer, byte_count, byte_offset)); + } + } else { + // Partial read + if (r_operation & 1) { + // Partial read to unpacked bool destination + size_t element_count = r_param % current_length; + size_t offset = rand () % (current_length - element_count); + bson_vector_packed_bits_const_view_t view; + bson_iter_t iter; + BSON_ASSERT (bson_iter_init_find (&iter, &vector_doc, "vector")); + BSON_ASSERT (bson_vector_packed_bits_const_view_from_iter (&view, &iter)); + BSON_ASSERT (bson_vector_packed_bits_const_view_length (view) == current_length); + BSON_ASSERT (bson_vector_packed_bits_const_view_unpack_bool (view, actual_elements, element_count, offset)); + for (size_t i = 0; i < element_count; i++) { + BSON_ASSERT (actual_elements[i] == expected_elements[i + offset]); + } + } else { + // Partial read of packed bytes + size_t current_length_bytes = (current_length + 7) / 8; + size_t byte_count = r_param % current_length_bytes; + size_t byte_offset = rand () % (current_length_bytes - byte_count); + bson_vector_packed_bits_const_view_t view; + bson_iter_t iter; + BSON_ASSERT (bson_iter_init_find (&iter, &vector_doc, "vector")); + BSON_ASSERT (bson_vector_packed_bits_const_view_from_iter (&view, &iter)); + BSON_ASSERT (bson_vector_packed_bits_const_view_length (view) == current_length); + BSON_ASSERT (bson_vector_packed_bits_const_view_length_bytes (view) == current_length_bytes); + BSON_ASSERT (bson_vector_packed_bits_const_view_read_packed (view, packed_buffer, byte_count, byte_offset)); + for (size_t i = 0; i < byte_count; i++) { + uint8_t packed_byte = packed_buffer[i]; + for (unsigned bit = 0; bit < 8; bit++) { + BSON_ASSERT (expected_elements[(byte_offset + i) * 8 + bit] == ((packed_byte & (0x80 >> bit)) != 0)); + } + } + } + } + } + bson_destroy (&vector_doc); + bson_free (expected_elements); + bson_free (actual_elements); + bson_free (packed_buffer); +} + +static void +test_bson_vector_example_int8_const_view (void) +{ + // setup: construct a sample document + bson_t doc = BSON_INITIALIZER; + { + static const int8_t values[] = {12, 34, -56}; + bson_vector_int8_view_t view; + BSON_ASSERT (BSON_APPEND_VECTOR_INT8 (&doc, "vector", sizeof values / sizeof values[0], &view)); + BSON_ASSERT (bson_vector_int8_view_write (view, values, sizeof values / sizeof values[0], 0)); + } + + // bson_vector_int8_const_view_t.rst + // Edits: + // - Added test_suite_debug_output() test. + // - Added unnecessary zero initializer to work around false positive compiler warning. + // (same as in bson_array_builder_append_vector_int8_elements) + { + bson_iter_t iter; + bson_vector_int8_const_view_t view; + + if (bson_iter_init_find (&iter, &doc, "vector") && bson_vector_int8_const_view_from_iter (&view, &iter)) { + size_t length = bson_vector_int8_const_view_length (view); + if (test_suite_debug_output ()) { + printf ("Elements in 'vector':\n"); + } + for (size_t i = 0; i < length; i++) { + int8_t element = 0; // Workaround + BSON_ASSERT (bson_vector_int8_const_view_read (view, &element, 1, i)); + if (test_suite_debug_output ()) { + printf (" [%d] = %d\n", (int) i, (int) element); + } + } + } + } + + bson_destroy (&doc); +} + +static void +test_bson_vector_example_int8_view (void) +{ + bson_t doc = BSON_INITIALIZER; + + // bson_vector_int8_view_t.rst + { + static const int8_t values[] = {1, 2, 3}; + const size_t values_count = sizeof values / sizeof values[0]; + + bson_vector_int8_view_t view; + BSON_ASSERT (BSON_APPEND_VECTOR_INT8 (&doc, "vector", values_count, &view)); + BSON_ASSERT (bson_vector_int8_view_write (view, values, values_count, 0)); + } + + bson_destroy (&doc); +} + +static void +test_bson_vector_example_float32_const_view (void) +{ + // setup: construct a sample document + bson_t doc = BSON_INITIALIZER; + { + static const float values[] = {5.0f, -1e10f, (float) INFINITY, (float) NAN, -1.0f}; + bson_vector_float32_view_t view; + BSON_ASSERT (BSON_APPEND_VECTOR_FLOAT32 (&doc, "vector", sizeof values / sizeof values[0], &view)); + BSON_ASSERT (bson_vector_float32_view_write (view, values, sizeof values / sizeof values[0], 0)); + } + + // bson_vector_float32_const_view_t.rst + // Edits: + // - Added test_suite_debug_output() test. + { + bson_iter_t iter; + bson_vector_float32_const_view_t view; + + if (bson_iter_init_find (&iter, &doc, "vector") && bson_vector_float32_const_view_from_iter (&view, &iter)) { + size_t length = bson_vector_float32_const_view_length (view); + if (test_suite_debug_output ()) { + printf ("Elements in 'vector':\n"); + } + for (size_t i = 0; i < length; i++) { + float element; + BSON_ASSERT (bson_vector_float32_const_view_read (view, &element, 1, i)); + if (test_suite_debug_output ()) { + printf (" [%d] = %f\n", (int) i, element); + } + } + } + } + + bson_destroy (&doc); +} + +static void +test_bson_vector_example_float32_view (void) +{ + bson_t doc = BSON_INITIALIZER; + + // bson_vector_float32_view_t.rst + { + static const float values[] = {1.0f, 2.0f, 3.0f}; + const size_t values_count = sizeof values / sizeof values[0]; + + bson_vector_float32_view_t view; + BSON_ASSERT (BSON_APPEND_VECTOR_FLOAT32 (&doc, "vector", values_count, &view)); + BSON_ASSERT (bson_vector_float32_view_write (view, values, values_count, 0)); + } + + bson_destroy (&doc); +} + +static void +test_bson_vector_example_packed_bits_const_view (void) +{ + // setup: construct a sample document + bson_t doc = BSON_INITIALIZER; + { + static const bool values[] = {true, false, true, true, false, true, false, true, true, false}; + bson_vector_packed_bits_view_t view; + BSON_ASSERT (BSON_APPEND_VECTOR_PACKED_BITS (&doc, "vector", sizeof values / sizeof values[0], &view)); + BSON_ASSERT (bson_vector_packed_bits_view_pack_bool (view, values, sizeof values / sizeof values[0], 0)); + } + + // bson_vector_packed_bits_const_view_t.rst + // Edits: + // - Added test_suite_debug_output() test. + // - Added unnecessary zero initializer to work around false positive compiler warning. + // (same as in bson_array_builder_append_vector_int8_elements) + { + bson_iter_t iter; + bson_vector_packed_bits_const_view_t view; + + if (bson_iter_init_find (&iter, &doc, "vector") && bson_vector_packed_bits_const_view_from_iter (&view, &iter)) { + size_t length = bson_vector_packed_bits_const_view_length (view); + size_t length_bytes = bson_vector_packed_bits_const_view_length_bytes (view); + size_t padding = bson_vector_packed_bits_const_view_padding (view); + + if (test_suite_debug_output ()) { + printf ("Elements in 'vector':\n"); + } + for (size_t i = 0; i < length; i++) { + bool element; + BSON_ASSERT (bson_vector_packed_bits_const_view_unpack_bool (view, &element, 1, i)); + if (test_suite_debug_output ()) { + printf (" elements[%d] = %d\n", (int) i, (int) element); + } + } + + if (test_suite_debug_output ()) { + printf ("Bytes in 'vector': (%d bits unused)\n", (int) padding); + } + for (size_t i = 0; i < length_bytes; i++) { + uint8_t packed_byte = 0; // Workaround + BSON_ASSERT (bson_vector_packed_bits_const_view_read_packed (view, &packed_byte, 1, i)); + if (test_suite_debug_output ()) { + printf (" bytes[%d] = 0x%02x\n", (int) i, (unsigned) packed_byte); + } + } + } + } + + bson_destroy (&doc); +} + +static void +test_bson_vector_example_packed_bits_view (void) +{ + bson_t doc = BSON_INITIALIZER; + + // bson_vector_packed_bits_view_t.rst + { + // Fill a new vector with individual boolean elements + { + static const bool bool_values[] = {true, false, true, true, false}; + const size_t bool_values_count = sizeof bool_values / sizeof bool_values[0]; + + bson_vector_packed_bits_view_t view; + BSON_ASSERT (BSON_APPEND_VECTOR_PACKED_BITS (&doc, "from_bool", bool_values_count, &view)); + BSON_ASSERT (bson_vector_packed_bits_view_pack_bool (view, bool_values, bool_values_count, 0)); + } + + // Fill another new vector with packed bytes + { + static const uint8_t packed_bytes[] = {0xb0}; + const size_t unused_bits_count = 3; + const size_t packed_values_count = sizeof packed_bytes * 8 - unused_bits_count; + + bson_vector_packed_bits_view_t view; + BSON_ASSERT (BSON_APPEND_VECTOR_PACKED_BITS (&doc, "from_packed", packed_values_count, &view)); + BSON_ASSERT (bson_vector_packed_bits_view_write_packed (view, packed_bytes, sizeof packed_bytes, 0)); + } + + // Compare both vectors. They match exactly. + { + bson_iter_t from_bool_iter, from_packed_iter; + BSON_ASSERT (bson_iter_init_find (&from_bool_iter, &doc, "from_bool")); + BSON_ASSERT (bson_iter_init_find (&from_packed_iter, &doc, "from_packed")); + BSON_ASSERT (bson_iter_binary_equal (&from_bool_iter, &from_packed_iter)); + } + } + + bson_destroy (&doc); +} + +void +test_bson_vector_install (TestSuite *suite) +{ + install_json_test_suite_with_check (suite, BSON_JSON_DIR, "bson_binary_vector", test_bson_vector_json_cb); + + TestSuite_Add (suite, "/bson_binary_vector/view_api/usage/int8", test_bson_vector_view_api_usage_int8); + TestSuite_Add (suite, "/bson_binary_vector/view_api/usage/float32", test_bson_vector_view_api_usage_float32); + TestSuite_Add (suite, "/bson_binary_vector/view_api/usage/packed_bits", test_bson_vector_view_api_usage_packed_bits); + + TestSuite_Add (suite, "/bson_binary_vector/view_api/fuzz/int8", test_bson_vector_view_api_fuzz_int8); + TestSuite_Add (suite, "/bson_binary_vector/view_api/fuzz/float32", test_bson_vector_view_api_fuzz_float32); + TestSuite_Add (suite, "/bson_binary_vector/view_api/fuzz/packed_bits", test_bson_vector_view_api_fuzz_packed_bits); + + TestSuite_Add (suite, "/bson_binary_vector/example/int8_const_view", test_bson_vector_example_int8_const_view); + TestSuite_Add (suite, "/bson_binary_vector/example/int8_view", test_bson_vector_example_int8_view); + TestSuite_Add (suite, "/bson_binary_vector/example/float32_const_view", test_bson_vector_example_float32_const_view); + TestSuite_Add (suite, "/bson_binary_vector/example/float32_view", test_bson_vector_example_float32_view); + TestSuite_Add ( + suite, "/bson_binary_vector/example/packed_bits_const_view", test_bson_vector_example_packed_bits_const_view); + TestSuite_Add (suite, "/bson_binary_vector/example/packed_bits_view", test_bson_vector_example_packed_bits_view); +} From c1ab6e930d85992d71f2c6cbd515e169ff393444 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Thu, 6 Feb 2025 14:34:41 -0800 Subject: [PATCH 05/51] Changes to integrate bson-binary-vector with libbson --- src/libbson/doc/api.rst | 1 + src/libbson/doc/bson_append_binary.rst | 4 + src/libbson/doc/bson_array_builder_t.rst | 6 + src/libbson/doc/bson_iter_binary.rst | 4 + src/libbson/doc/bson_iter_t.rst | 8 ++ src/libbson/doc/bson_subtype_t.rst | 1 + src/libbson/doc/bson_t.rst | 4 + src/libbson/src/bson/bson-endian.h | 35 ++++++ src/libbson/src/bson/bson-error.h | 1 + src/libbson/src/bson/bson-iter.c | 131 ++++++++++++++++++++++ src/libbson/src/bson/bson-iter.h | 18 +++ src/libbson/src/bson/bson-macros.h | 12 ++ src/libbson/src/bson/bson-types.h | 1 + src/libbson/src/bson/bson.c | 130 ++++++++++++++++++--- src/libbson/src/bson/bson.h | 49 +++++++- src/libmongoc/CMakeLists.txt | 2 +- src/libmongoc/tests/test-libmongoc-main.c | 1 + 17 files changed, 388 insertions(+), 20 deletions(-) diff --git a/src/libbson/doc/api.rst b/src/libbson/doc/api.rst index cc4365cae15..b85668154b4 100644 --- a/src/libbson/doc/api.rst +++ b/src/libbson/doc/api.rst @@ -25,5 +25,6 @@ API Reference bson_writer_t bson_get_monotonic_time bson_memory + binary_vector version legacy_extended_json diff --git a/src/libbson/doc/bson_append_binary.rst b/src/libbson/doc/bson_append_binary.rst index c3fce9081bb..f8a7f6728be 100644 --- a/src/libbson/doc/bson_append_binary.rst +++ b/src/libbson/doc/bson_append_binary.rst @@ -38,3 +38,7 @@ Returns ------- Returns ``true`` if the operation was applied successfully. The function will fail if appending ``binary`` grows ``bson`` larger than INT32_MAX. + +.. seealso:: + + | :symbol:`bson_append_binary_uninit` diff --git a/src/libbson/doc/bson_array_builder_t.rst b/src/libbson/doc/bson_array_builder_t.rst index 5baca2d7f4f..773738f5536 100644 --- a/src/libbson/doc/bson_array_builder_t.rst +++ b/src/libbson/doc/bson_array_builder_t.rst @@ -82,6 +82,12 @@ Appending values to an array const uint8_t *binary, uint32_t length); + bool + bson_array_builder_append_binary_uninit (bson_array_builder_t *bab, + bson_subtype_t subtype, + uint8_t **binary, + uint32_t length); + bool bson_array_builder_append_bool (bson_array_builder_t *bab, bool value); diff --git a/src/libbson/doc/bson_iter_binary.rst b/src/libbson/doc/bson_iter_binary.rst index b456bfbe62b..a0e408b2af2 100644 --- a/src/libbson/doc/bson_iter_binary.rst +++ b/src/libbson/doc/bson_iter_binary.rst @@ -32,3 +32,7 @@ This function shall return the binary data of a BSON_TYPE_BINARY element. It is The buffer that ``binary`` points to is only valid until the iterator's :symbol:`bson_t` is modified or freed. +.. seealso:: + + | :symbol:`bson_iter_binary_equal` + | :symbol:`bson_iter_binary_subtype` diff --git a/src/libbson/doc/bson_iter_t.rst b/src/libbson/doc/bson_iter_t.rst index 620388f7758..f636599c520 100644 --- a/src/libbson/doc/bson_iter_t.rst +++ b/src/libbson/doc/bson_iter_t.rst @@ -22,6 +22,11 @@ Synopsis #define BSON_ITER_HOLDS_BINARY(iter) /* ... */ + #define BSON_ITER_HOLDS_VECTOR(iter) /* ... */ + #define BSON_ITER_HOLDS_VECTOR_INT8(iter) /* ... */ + #define BSON_ITER_HOLDS_VECTOR_FLOAT32(iter) /* ... */ + #define BSON_ITER_HOLDS_VECTOR_PACKED_BITS(iter) /* ... */ + #define BSON_ITER_HOLDS_UNDEFINED(iter) /* ... */ #define BSON_ITER_HOLDS_OID(iter) /* ... */ @@ -88,6 +93,8 @@ The :symbol:`bson_t` *MUST* be valid for the lifetime of the iter and it is an e bson_iter_as_double bson_iter_as_int64 bson_iter_binary + bson_iter_binary_subtype + bson_iter_binary_equal bson_iter_bool bson_iter_code bson_iter_codewscope @@ -115,6 +122,7 @@ The :symbol:`bson_t` *MUST* be valid for the lifetime of the iter and it is an e bson_iter_offset bson_iter_oid bson_iter_overwrite_bool + bson_iter_overwrite_binary bson_iter_overwrite_date_time bson_iter_overwrite_decimal128 bson_iter_overwrite_double diff --git a/src/libbson/doc/bson_subtype_t.rst b/src/libbson/doc/bson_subtype_t.rst index 9c54a395c15..177c02203bc 100644 --- a/src/libbson/doc/bson_subtype_t.rst +++ b/src/libbson/doc/bson_subtype_t.rst @@ -22,6 +22,7 @@ Synopsis BSON_SUBTYPE_MD5 = 0x05, BSON_SUBTYPE_COLUMN = 0x07, BSON_SUBTYPE_SENSITIVE = 0x08, + BSON_SUBTYPE_VECTOR = 0x09, BSON_SUBTYPE_USER = 0x80, } bson_subtype_t; diff --git a/src/libbson/doc/bson_t.rst b/src/libbson/doc/bson_t.rst index 910698d639e..03cb80e1b04 100644 --- a/src/libbson/doc/bson_t.rst +++ b/src/libbson/doc/bson_t.rst @@ -56,6 +56,9 @@ Synopsis #define BSON_APPEND_BINARY(b, key, subtype, val, len) \ bson_append_binary (b, key, (int) strlen (key), subtype, val, len) + #define BSON_APPEND_BINARY_UNINIT(b, key, subtype, val, len) \ + bson_append_binary_uninit (b, key, (int) strlen (key), subtype, val, len) + #define BSON_APPEND_BOOL(b, key, val) \ bson_append_bool (b, key, (int) strlen (key), val) @@ -163,6 +166,7 @@ BSON document contains duplicate keys. bson_append_array_begin bson_append_array_end bson_append_binary + bson_append_binary_uninit bson_append_bool bson_append_code bson_append_code_with_scope diff --git a/src/libbson/src/bson/bson-endian.h b/src/libbson/src/bson/bson-endian.h index 9b6cf9ef531..8ea44153275 100644 --- a/src/libbson/src/bson/bson-endian.h +++ b/src/libbson/src/bson/bson-endian.h @@ -83,6 +83,8 @@ BSON_BEGIN_DECLS #define BSON_UINT64_TO_BE(v) BSON_UINT64_SWAP_LE_BE (v) #define BSON_DOUBLE_FROM_LE(v) ((double) v) #define BSON_DOUBLE_TO_LE(v) ((double) v) +#define BSON_FLOAT_FROM_LE(v) ((float) v) +#define BSON_FLOAT_TO_LE(v) ((float) v) #elif BSON_BYTE_ORDER == BSON_BIG_ENDIAN #define BSON_UINT16_FROM_LE(v) BSON_UINT16_SWAP_LE_BE (v) #define BSON_UINT16_TO_LE(v) BSON_UINT16_SWAP_LE_BE (v) @@ -98,6 +100,8 @@ BSON_BEGIN_DECLS #define BSON_UINT64_TO_BE(v) ((uint64_t) v) #define BSON_DOUBLE_FROM_LE(v) (__bson_double_swap_slow (v)) #define BSON_DOUBLE_TO_LE(v) (__bson_double_swap_slow (v)) +#define BSON_FLOAT_FROM_LE(v) (__bson_float_swap_slow (v)) +#define BSON_FLOAT_TO_LE(v) (__bson_float_swap_slow (v)) #else #error "The endianness of target architecture is unknown." #endif @@ -205,6 +209,37 @@ __bson_double_swap_slow (double v) /* IN */ return v; } + +/* + *-------------------------------------------------------------------------- + * + * __bson_float_swap_slow -- + * + * Fallback endianness conversion for single floating point. + * + * Returns: + * The endian swapped version. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +BSON_STATIC_ASSERT2 (sizeof_uint32_t, sizeof (float) == sizeof (uint32_t)); + +static BSON_INLINE float +__bson_float_swap_slow (float v) /* IN */ +{ + uint32_t uv; + + memcpy (&uv, &v, sizeof (v)); + uv = BSON_UINT32_SWAP_LE_BE (uv); + memcpy (&v, &uv, sizeof (v)); + + return v; +} + BSON_END_DECLS diff --git a/src/libbson/src/bson/bson-error.h b/src/libbson/src/bson/bson-error.h index 855af02bb19..154800f2a18 100644 --- a/src/libbson/src/bson/bson-error.h +++ b/src/libbson/src/bson/bson-error.h @@ -32,6 +32,7 @@ BSON_BEGIN_DECLS #define BSON_ERROR_JSON 1 #define BSON_ERROR_READER 2 #define BSON_ERROR_INVALID 3 +#define BSON_ERROR_VECTOR 4 BSON_EXPORT (void) diff --git a/src/libbson/src/bson/bson-iter.c b/src/libbson/src/bson/bson-iter.c index b5bac45e901..5c785730e5c 100644 --- a/src/libbson/src/bson/bson-iter.c +++ b/src/libbson/src/bson/bson-iter.c @@ -942,6 +942,137 @@ bson_iter_binary (const bson_iter_t *iter, /* IN */ } +/* + *-------------------------------------------------------------------------- + * + * bson_iter_overwrite_binary -- + * + * Obtain temporary mutable access to the contents of a BSON_TYPE_BINARY + * field. It may be modified in content only, without changing length + * or subtype, through a temporary pointer that's only valid until the + * underlying bson_t is modified or deleted. + * + * Parameters: + * @iter: A bson_iter_t + * @binary_len: A location for the length of @binary. + * @binary: A location for a pointer to the binary data. + * + * Returns: + * On success, returns a pointer in *binary and a length in *binary_len. + * The pointer is invalidated when the underlying bson_t is destroyed or modified. + * If the iter does not point to a binary item of the indicated subtype, + * returns NULL in *binary and 0 *binary_len. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +BSON_EXPORT (void) +bson_iter_overwrite_binary (bson_iter_t *iter, /* IN */ + bson_subtype_t subtype, /* IN */ + uint32_t *binary_len, /* OUT */ + uint8_t **binary) /* OUT */ +{ + BSON_ASSERT_PARAM (iter); + BSON_OPTIONAL_PARAM (binary_len); + BSON_OPTIONAL_PARAM (binary); + + bson_subtype_t iter_subtype; + uint32_t iter_binary_len; + const uint8_t *iter_binary; + bson_iter_binary (iter, &iter_subtype, &iter_binary_len, &iter_binary); + + if (iter_binary && iter_subtype == subtype) { + // All of bson_iter_overwrite_* work by casting away const from iter->raw. + if (binary) { + *binary = (void *) iter_binary; + } + if (binary_len) { + *binary_len = iter_binary_len; + } + return; + } + if (binary) { + *binary = NULL; + } + if (binary_len) { + *binary_len = 0; + } +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_iter_binary_subtype -- + * + * Retrieves the subtype of a BSON_TYPE_BINARY field. + * + * Parameters: + * @iter: A bson_iter_t + * + * Returns: + * Same as the @subtype OUT parameter from bson_iter_binary(). + * If the iterator is valid, returns the referenced subtype. Otherwise, + * returns BSON_SUBTYPE_BINARY as a fallback. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +BSON_EXPORT (bson_subtype_t) +bson_iter_binary_subtype (const bson_iter_t *iter) +{ + bson_subtype_t result; + bson_iter_binary (iter, &result, NULL, NULL); + return result; +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_iter_binary_equal -- + * + * Compare two BSON_TYPE_BINARY fields for equality. + * + * Parameters: + * @iter_a: First bson_iter_t to compare + * @iter_b: Second bson_iter_t to compare + * + * Returns: + * true if both iterators point to BSON_TYPE_BINARY fields with + * identical subtype and contents. false if there is any difference. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +BSON_EXPORT (bool) +bson_iter_binary_equal (const bson_iter_t *iter_a, const bson_iter_t *iter_b) +{ + BSON_ASSERT_PARAM (iter_a); + BSON_ASSERT_PARAM (iter_b); + + if (BSON_ITER_HOLDS_BINARY (iter_a) && BSON_ITER_HOLDS_BINARY (iter_b)) { + bson_subtype_t subtypes[2]; + uint32_t lengths[2]; + const uint8_t *data[2]; + bson_iter_binary (iter_a, &subtypes[0], &lengths[0], &data[0]); + bson_iter_binary (iter_b, &subtypes[1], &lengths[1], &data[1]); + return subtypes[0] == subtypes[1] && lengths[0] == lengths[1] && 0 == memcmp (data[0], data[1], lengths[0]); + } else { + return false; + } +} + + /* *-------------------------------------------------------------------------- * diff --git a/src/libbson/src/bson/bson-iter.h b/src/libbson/src/bson/bson-iter.h index 5431902c260..746a2f0c76a 100644 --- a/src/libbson/src/bson/bson-iter.h +++ b/src/libbson/src/bson/bson-iter.h @@ -40,6 +40,15 @@ BSON_BEGIN_DECLS #define BSON_ITER_HOLDS_BINARY(iter) (bson_iter_type ((iter)) == BSON_TYPE_BINARY) +#define BSON_ITER_HOLDS_VECTOR(iter) \ + (BSON_ITER_HOLDS_BINARY (iter) && bson_iter_binary_subtype (iter) == BSON_SUBTYPE_VECTOR) + +#define BSON_ITER_HOLDS_VECTOR_INT8(iter) (bson_vector_int8_const_view_from_iter (NULL, iter)) + +#define BSON_ITER_HOLDS_VECTOR_FLOAT32(iter) (bson_vector_float32_const_view_from_iter (NULL, iter)) + +#define BSON_ITER_HOLDS_VECTOR_PACKED_BITS(iter) (bson_vector_packed_bits_const_view_from_iter (NULL, iter)) + #define BSON_ITER_HOLDS_UNDEFINED(iter) (bson_iter_type ((iter)) == BSON_TYPE_UNDEFINED) #define BSON_ITER_HOLDS_OID(iter) (bson_iter_type ((iter)) == BSON_TYPE_OID) @@ -115,6 +124,15 @@ bson_iter_array (const bson_iter_t *iter, uint32_t *array_len, const uint8_t **a BSON_EXPORT (void) bson_iter_binary (const bson_iter_t *iter, bson_subtype_t *subtype, uint32_t *binary_len, const uint8_t **binary); +BSON_EXPORT (void) +bson_iter_overwrite_binary (bson_iter_t *iter, bson_subtype_t subtype, uint32_t *binary_len, uint8_t **binary); + +BSON_EXPORT (bson_subtype_t) +bson_iter_binary_subtype (const bson_iter_t *iter); + +BSON_EXPORT (bool) +bson_iter_binary_equal (const bson_iter_t *iter_a, const bson_iter_t *iter_b); + BSON_EXPORT (const char *) bson_iter_code (const bson_iter_t *iter, uint32_t *length); diff --git a/src/libbson/src/bson/bson-macros.h b/src/libbson/src/bson/bson-macros.h index a4c00aef92e..4675349b4b3 100644 --- a/src/libbson/src/bson/bson-macros.h +++ b/src/libbson/src/bson/bson-macros.h @@ -210,6 +210,18 @@ #endif +#if defined(__GNUC__) +#define BSON_RESTRICT __restrict__ +#elif defined(_MSC_VER) +#define BSON_RESTRICT __restrict +#elif !defined(__cplusplus) +// C99 (not C++) +#define BSON_RESTRICT restrict +#else +#define BSON_RESTRICT +#endif + + BSON_NORETURN static BSON_INLINE void _bson_assert_failed_on_line (const char *file, int line, const char *func, const char *test) { diff --git a/src/libbson/src/bson/bson-types.h b/src/libbson/src/bson/bson-types.h index 66407998a5e..4b1986f9bf7 100644 --- a/src/libbson/src/bson/bson-types.h +++ b/src/libbson/src/bson/bson-types.h @@ -274,6 +274,7 @@ typedef enum { BSON_SUBTYPE_ENCRYPTED = 0x06, BSON_SUBTYPE_COLUMN = 0x07, BSON_SUBTYPE_SENSITIVE = 0x08, + BSON_SUBTYPE_VECTOR = 0x09, BSON_SUBTYPE_USER = 0x80, } bson_subtype_t; diff --git a/src/libbson/src/bson/bson.c b/src/libbson/src/bson/bson.c index d76a1b2ceb4..36cbc4efa27 100644 --- a/src/libbson/src/bson/bson.c +++ b/src/libbson/src/bson/bson.c @@ -251,7 +251,7 @@ _bson_encode_length (bson_t *bson) /* IN */ typedef struct _bson_append_bytes_arg { - const uint8_t *bytes; // Not null. + const uint8_t *bytes; // Optional. uint32_t length; // > 0. } _bson_append_bytes_arg; @@ -319,7 +319,9 @@ BSON_STATIC_ASSERT2 (size_t_gte_uint32_t, SIZE_MAX >= UINT32_MAX); } else { \ uint8_t *data = _bson_data ((_bson)) + ((_bson)->len - 1u); \ for (const _bson_append_bytes_arg *arg = (_list).args; arg != (_list).current; ++arg) { \ - memcpy (data, arg->bytes, arg->length); \ + if (arg->bytes) { \ + memcpy (data, arg->bytes, arg->length); \ + } \ (_bson)->len += arg->length; \ data += arg->length; \ } \ @@ -694,15 +696,14 @@ bson_append_array (bson_t *bson, /* IN */ /* *-------------------------------------------------------------------------- * - * bson_append_binary -- + * _bson_append_binary -- * - * Append binary data to @bson. The field will have the - * BSON_TYPE_BINARY type. + * Append a BSON_TYPE_BINARY field, with or without data copied in. * * Parameters: * @subtype: the BSON Binary Subtype. See bsonspec.org for more * information. - * @binary: a pointer to the raw binary data. + * @binary: Optional pointer to the raw binary data. * @length: the size of @binary in bytes. * * Returns: @@ -714,23 +715,19 @@ bson_append_array (bson_t *bson, /* IN */ *-------------------------------------------------------------------------- */ -bool -bson_append_binary (bson_t *bson, /* IN */ - const char *key, /* IN */ - int key_length, /* IN */ - bson_subtype_t subtype, /* IN */ - const uint8_t *binary, /* IN */ - uint32_t length) /* IN */ +static bool +_bson_append_binary (bson_t *bson, /* IN */ + const char *key, /* IN */ + int key_length, /* IN */ + bson_subtype_t subtype, /* IN */ + const uint8_t *binary, /* IN */ + uint32_t length) /* IN */ { static const uint8_t type = BSON_TYPE_BINARY; BSON_ASSERT_PARAM (bson); BSON_ASSERT_PARAM (key); - if (!binary && length > 0u) { - return false; - } - BSON_APPEND_BYTES_LIST_DECLARE (args); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &type, sizeof (type)); @@ -770,6 +767,87 @@ bson_append_binary (bson_t *bson, /* IN */ } +/* + *-------------------------------------------------------------------------- + * + * bson_append_binary -- + * + * Append binary data to @bson. The field will have the + * BSON_TYPE_BINARY type. + * + * Parameters: + * @subtype: the BSON Binary Subtype. See bsonspec.org for more + * information. + * @binary: a pointer to the raw binary data. + * @length: the size of @binary in bytes. + * + * Returns: + * true if successful; otherwise false. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +bool +bson_append_binary (bson_t *bson, /* IN */ + const char *key, /* IN */ + int key_length, /* IN */ + bson_subtype_t subtype, /* IN */ + const uint8_t *binary, /* IN */ + uint32_t length) /* IN */ +{ + if (!binary && length > 0u) { + return false; + } + return _bson_append_binary (bson, key, key_length, subtype, binary, length); +} + + +/* + *-------------------------------------------------------------------------- + * + * bson_append_binary_uninit -- + * + * Append binary data to @bson by framing an uninitialized field to be written by the caller. + * The field will have the BSON_TYPE_BINARY type. On success, the caller MUST write to all + * bytes in the binary data field. The returned `*binary` pointer is only valid until the + * bson_t is modified or destroyed. + * + * Parameters: + * @subtype: the BSON Binary Subtype. See bsonspec.org for more + * information. + * @binary: Output parameter for a temporary pointer where the binary item's contents must be written. + * @length: the size of @binary in bytes. + * + * Returns: + * true if successful; otherwise false. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +bool +bson_append_binary_uninit (bson_t *bson, /* IN */ + const char *key, /* IN */ + int key_length, /* IN */ + bson_subtype_t subtype, /* IN */ + uint8_t **binary, /* IN */ + uint32_t length) /* IN */ +{ + BSON_ASSERT_PARAM (binary); + if (_bson_append_binary (bson, key, key_length, subtype, NULL, length)) { + *binary = _bson_data (bson) + bson->len - 1u - length; + return true; + } else { + return false; + } +} + + /* *-------------------------------------------------------------------------- * @@ -2725,6 +2803,7 @@ bson_array_builder_append_value (bson_array_builder_t *bab, const bson_value_t * bson_array_builder_append_impl (bson_append_value, value); } + bool bson_array_builder_append_array (bson_array_builder_t *bab, const bson_t *array) { @@ -2732,6 +2811,13 @@ bson_array_builder_append_array (bson_array_builder_t *bab, const bson_t *array) } +bool +bson_array_builder_append_array_from_vector (bson_array_builder_t *bab, const bson_iter_t *iter) +{ + bson_array_builder_append_impl (bson_append_array_from_vector, iter); +} + + bool bson_array_builder_append_binary (bson_array_builder_t *bab, bson_subtype_t subtype, @@ -2742,6 +2828,16 @@ bson_array_builder_append_binary (bson_array_builder_t *bab, } +bool +bson_array_builder_append_binary_uninit (bson_array_builder_t *bab, + bson_subtype_t subtype, + uint8_t **binary, + uint32_t length) +{ + bson_array_builder_append_impl (bson_append_binary_uninit, subtype, binary, length); +} + + bool bson_array_builder_append_bool (bson_array_builder_t *bab, bool value) { diff --git a/src/libbson/src/bson/bson.h b/src/libbson/src/bson/bson.h index 96a7337f153..cece721d603 100644 --- a/src/libbson/src/bson/bson.h +++ b/src/libbson/src/bson/bson.h @@ -44,6 +44,7 @@ #include #include #include +#include #include #include #include @@ -625,11 +626,31 @@ bson_append_array (bson_t *bson, const char *key, int key_length, const bson_t * BSON_EXPORT (bool) bson_array_builder_append_array (bson_array_builder_t *bab, const bson_t *array); +/** + * bson_append_array_from_vector: + * @bson: A bson_t that will be modified. + * @key: The key for the field. + * @iter: A bson_iter_t pointing to any supported vector in another bson_t. + * + * If @iter points to a supported vector type, converts the vector to a BSON array appended to @bson. + * + * Returns: true if successful; false if append would overflow max size or @iter does not point to a vector in a + * supported format. + */ +BSON_EXPORT (bool) +bson_append_array_from_vector (bson_t *bson, const char *key, int key_length, const bson_iter_t *iter); + +#define BSON_APPEND_ARRAY_FROM_VECTOR(b, key, iter) bson_append_array_from_vector (b, key, (int) strlen (key), iter) + +BSON_EXPORT (bool) +bson_array_builder_append_array_from_vector (bson_array_builder_t *bab, const bson_iter_t *iter); + /** * bson_append_binary: - * @bson: A bson_t to append. + * @bson: A bson_t. * @key: The key for the field. - * @subtype: The bson_subtype_t of the binary. + * @key_length: Optional length of 'key' in bytes, or -1 to use strlen(key). + * @subtype: The bson_subtype_t of the binary item. * @binary: The binary buffer to append. * @length: The length of @binary. * @@ -649,6 +670,30 @@ bson_array_builder_append_binary (bson_array_builder_t *bab, const uint8_t *binary, uint32_t length); +/** + * bson_append_binary_uninit: + * @bson: A bson_t. + * @key: The key for the field. + * @key_length: Optional length of 'key' in bytes, or -1 to use strlen(key). + * @binary: Output parameter, pointer for the binary data within bson_t to be written. + * @length: Length of the binary field to allocate, in bytes. + * + * Returns: true if successful; false if append would overflow max size. + */ + +BSON_EXPORT (bool) +bson_append_binary_uninit ( + bson_t *bson, const char *key, int key_length, bson_subtype_t subtype, uint8_t **binary, uint32_t length); + +#define BSON_APPEND_BINARY_UNINIT(b, key, subtype, val, len) \ + bson_append_binary_uninit (b, key, (int) strlen (key), subtype, val, len) + +BSON_EXPORT (bool) +bson_array_builder_append_binary_uninit (bson_array_builder_t *bab, + bson_subtype_t subtype, + uint8_t **binary, + uint32_t length); + /** * bson_append_bool: * @bson: A bson_t. diff --git a/src/libmongoc/CMakeLists.txt b/src/libmongoc/CMakeLists.txt index dc980840c0b..3cbd1a676f1 100644 --- a/src/libmongoc/CMakeLists.txt +++ b/src/libmongoc/CMakeLists.txt @@ -1040,13 +1040,13 @@ set (test-libmongoc-sources ${mongo-c-driver_SOURCE_DIR}/src/libbson/tests/corpus-test.h ${mongo-c-driver_SOURCE_DIR}/src/libbson/tests/test-atomic.c ${mongo-c-driver_SOURCE_DIR}/src/libbson/tests/test-b64.c - ${mongo-c-driver_SOURCE_DIR}/src/libbson/tests/test-bson.c ${mongo-c-driver_SOURCE_DIR}/src/libbson/tests/test-bcon-basic.c ${mongo-c-driver_SOURCE_DIR}/src/libbson/tests/test-bcon-extract.c ${mongo-c-driver_SOURCE_DIR}/src/libbson/tests/test-bson-cmp.c ${mongo-c-driver_SOURCE_DIR}/src/libbson/tests/test-bson-corpus.c ${mongo-c-driver_SOURCE_DIR}/src/libbson/tests/test-bson-error.c ${mongo-c-driver_SOURCE_DIR}/src/libbson/tests/test-bson-sync.c + ${mongo-c-driver_SOURCE_DIR}/src/libbson/tests/test-bson-vector.c ${mongo-c-driver_SOURCE_DIR}/src/libbson/tests/test-bson-version.c ${mongo-c-driver_SOURCE_DIR}/src/libbson/tests/test-bson.c ${mongo-c-driver_SOURCE_DIR}/src/libbson/tests/test-clock.c diff --git a/src/libmongoc/tests/test-libmongoc-main.c b/src/libmongoc/tests/test-libmongoc-main.c index fdee937cd8b..2d33639a83f 100644 --- a/src/libmongoc/tests/test-libmongoc-main.c +++ b/src/libmongoc/tests/test-libmongoc-main.c @@ -32,6 +32,7 @@ main (int argc, char *argv[]) TEST_INSTALL (test_bson_install); TEST_INSTALL (test_bson_sync_install); TEST_INSTALL (test_bson_version_install); + TEST_INSTALL (test_bson_vector_install); TEST_INSTALL (test_clock_install); TEST_INSTALL (test_decimal128_install); TEST_INSTALL (test_endian_install); From 6fe0d0a5108ad2cf4034fbdc74466ec19b26037e Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Tue, 18 Feb 2025 08:31:32 -0800 Subject: [PATCH 06/51] Note about the differing public and private API of bson_iter_binary and friends --- src/libbson/src/bson/bson-iter.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/libbson/src/bson/bson-iter.c b/src/libbson/src/bson/bson-iter.c index 5c785730e5c..bdc09755ac0 100644 --- a/src/libbson/src/bson/bson-iter.c +++ b/src/libbson/src/bson/bson-iter.c @@ -881,6 +881,12 @@ bson_iter_next (bson_iter_t *iter) /* INOUT */ * @binary should not be modified or freed and is only valid while * @iter's bson_t is valid and unmodified. * + * Note: Public constraints are tighter than private ones. + * API documentation says it's "a programming error to call this function + * when ``iter`` is not observing an element of type BSON_TYPE_BINARY.". + * Privately only, we do check the iterator type and we output NULL and + * BSON_SUBTYPE_BINARY when the type is incorrect. + * * Parameters: * @iter: A bson_iter_t * @subtype: A location for the binary subtype. @@ -952,6 +958,12 @@ bson_iter_binary (const bson_iter_t *iter, /* IN */ * or subtype, through a temporary pointer that's only valid until the * underlying bson_t is modified or deleted. * + * Note: Public constraints are tighter than private ones. + * API documentation says it's "a programming error to call this function + * when ``iter`` is not observing an element of type BSON_TYPE_BINARY.". + * Privately only, we do check the iterator type and we return NULL when + * the type is incorrect. + * * Parameters: * @iter: A bson_iter_t * @binary_len: A location for the length of @binary. @@ -1010,6 +1022,12 @@ bson_iter_overwrite_binary (bson_iter_t *iter, /* IN */ * * Retrieves the subtype of a BSON_TYPE_BINARY field. * + * Note: Public constraints are tighter than private ones. + * API documentation says it's "a programming error to call this function + * when ``iter`` is not observing an element of type BSON_TYPE_BINARY.". + * Privately only, we do check the iterator type and return + * BSON_SUBTYPE_BINARY when the type is incorrect. + * * Parameters: * @iter: A bson_iter_t * From 9263e89ea89452dd84be5fc9be73fdb3fd4141cf Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Tue, 18 Feb 2025 08:42:15 -0800 Subject: [PATCH 07/51] Public APIs for direct pointer access to int8 vectors --- .../bson_vector_int8_const_view_pointer.rst | 36 +++++++++++++++++++ .../doc/bson_vector_int8_const_view_t.rst | 1 + .../doc/bson_vector_int8_view_pointer.rst | 36 +++++++++++++++++++ src/libbson/doc/bson_vector_int8_view_t.rst | 1 + src/libbson/src/bson/bson-vector.h | 17 +++++++-- 5 files changed, 89 insertions(+), 2 deletions(-) create mode 100644 src/libbson/doc/bson_vector_int8_const_view_pointer.rst create mode 100644 src/libbson/doc/bson_vector_int8_view_pointer.rst diff --git a/src/libbson/doc/bson_vector_int8_const_view_pointer.rst b/src/libbson/doc/bson_vector_int8_const_view_pointer.rst new file mode 100644 index 00000000000..b2cd3f2ef2b --- /dev/null +++ b/src/libbson/doc/bson_vector_int8_const_view_pointer.rst @@ -0,0 +1,36 @@ +a``:man_page: bson_vector_int8_const_view_pointer + +bson_vector_int8_const_view_pointer() +===================================== + +Obtain a direct ``int8_t`` pointer to the Vector elements referenced by a :symbol:`bson_vector_int8_const_view_t`. + +Synopsis +-------- + +.. code-block:: c + + const int8_t * + bson_vector_int8_const_view_pointer (bson_vector_int8_const_view_t view); + +Parameters +---------- + +* ``view``: A valid :symbol:`bson_vector_int8_const_view_t`. + +Description +----------- + +Unwraps a vector view into a bare pointer. +The ``int8`` Vector elements use a serialized format that's fully compatible with a C ``int8_t``. + +Returns +------- + +A pointer derived from the pointer this View was created from. +Its lifetime matches that of the original pointer. +If the view was created from a :symbol:`bson_iter_t`, it will be valid until the underlying :symbol:`bson_t` is otherwise modified or destroyed. + +.. seealso:: + + | :symbol:`bson_vector_int8_view_pointer` diff --git a/src/libbson/doc/bson_vector_int8_const_view_t.rst b/src/libbson/doc/bson_vector_int8_const_view_t.rst index 81468f105bf..aa9a97085aa 100644 --- a/src/libbson/doc/bson_vector_int8_const_view_t.rst +++ b/src/libbson/doc/bson_vector_int8_const_view_t.rst @@ -38,6 +38,7 @@ The :symbol:`bson_t` *MUST* be valid for the lifetime of the view and it is an e bson_vector_int8_const_view_from_iter bson_vector_int8_const_view_length bson_vector_int8_const_view_read + bson_vector_int8_const_view_pointer Example ------- diff --git a/src/libbson/doc/bson_vector_int8_view_pointer.rst b/src/libbson/doc/bson_vector_int8_view_pointer.rst new file mode 100644 index 00000000000..0b9fa329107 --- /dev/null +++ b/src/libbson/doc/bson_vector_int8_view_pointer.rst @@ -0,0 +1,36 @@ +a``:man_page: bson_vector_int8_view_pointer + +bson_vector_int8_view_pointer() +=============================== + +Obtain a direct ``int8_t`` pointer to the Vector elements referenced by a :symbol:`bson_vector_int8_view_t`. + +Synopsis +-------- + +.. code-block:: c + + int8_t * + bson_vector_int8_view_pointer (bson_vector_int8_view_t view); + +Parameters +---------- + +* ``view``: A valid :symbol:`bson_vector_int8_view_t`. + +Description +----------- + +Unwraps a vector view into a bare pointer. +The ``int8`` Vector elements use a serialized format that's fully compatible with a C ``int8_t``. + +Returns +------- + +A pointer derived from the pointer this View was created from. +Its lifetime matches that of the original pointer. +If the view was created from a :symbol:`bson_iter_t`, it will be valid until the underlying :symbol:`bson_t` is otherwise modified or destroyed. + +.. seealso:: + + | :symbol:`bson_vector_int8_const_view_pointer` diff --git a/src/libbson/doc/bson_vector_int8_view_t.rst b/src/libbson/doc/bson_vector_int8_view_t.rst index f024651c917..2268ab38f3c 100644 --- a/src/libbson/doc/bson_vector_int8_view_t.rst +++ b/src/libbson/doc/bson_vector_int8_view_t.rst @@ -40,6 +40,7 @@ The :symbol:`bson_t` *MUST* be valid for the lifetime of the view and it is an e bson_vector_int8_view_length bson_vector_int8_view_read bson_vector_int8_view_write + bson_vector_int8_view_pointer Example ------- diff --git a/src/libbson/src/bson/bson-vector.h b/src/libbson/src/bson/bson-vector.h index 7f78d7f3b28..2684f160cc2 100644 --- a/src/libbson/src/bson/bson-vector.h +++ b/src/libbson/src/bson/bson-vector.h @@ -259,6 +259,19 @@ bson_append_array_from_vector_packed_bits (bson_t *bson, bson_append_array_from_vector_packed_bits (b, key, (int) strlen (key), view) +static const BSON_INLINE int8_t * +bson_vector_int8_const_view_pointer (bson_vector_int8_const_view_t view) +{ + return (const int8_t *) view.binary.data + BSON_VECTOR_HEADER_LEN; +} + +static BSON_INLINE int8_t * +bson_vector_int8_view_pointer (bson_vector_int8_view_t view) +{ + return (int8_t *) view.binary.data + BSON_VECTOR_HEADER_LEN; +} + + static BSON_INLINE uint32_t bson_vector_int8_binary_data_length (size_t element_count) { @@ -363,7 +376,7 @@ bson_vector_int8_const_view_read (bson_vector_int8_const_view_t view, { size_t length = bson_vector_int8_const_view_length (view); if (BSON_LIKELY (vector_offset_elements <= length && element_count <= length - vector_offset_elements)) { - memcpy (values_out, view.binary.data + BSON_VECTOR_HEADER_LEN + vector_offset_elements, element_count); + memcpy (values_out, bson_vector_int8_const_view_pointer (view) + vector_offset_elements, element_count); return true; } else { return false; @@ -388,7 +401,7 @@ bson_vector_int8_view_write (bson_vector_int8_view_t view, { size_t length = bson_vector_int8_view_length (view); if (BSON_LIKELY (vector_offset_elements <= length && element_count <= length - vector_offset_elements)) { - memcpy (view.binary.data + BSON_VECTOR_HEADER_LEN + vector_offset_elements, values, element_count); + memcpy (bson_vector_int8_view_pointer (view) + vector_offset_elements, values, element_count); return true; } else { return false; From ae91e0d1c8bbf4da096eb2a3a2a91ef80cdef497 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Tue, 18 Feb 2025 08:51:42 -0800 Subject: [PATCH 08/51] Trivial, fix inline placement --- src/libbson/src/bson/bson-vector.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libbson/src/bson/bson-vector.h b/src/libbson/src/bson/bson-vector.h index 2684f160cc2..36bd1944d06 100644 --- a/src/libbson/src/bson/bson-vector.h +++ b/src/libbson/src/bson/bson-vector.h @@ -259,7 +259,7 @@ bson_append_array_from_vector_packed_bits (bson_t *bson, bson_append_array_from_vector_packed_bits (b, key, (int) strlen (key), view) -static const BSON_INLINE int8_t * +static BSON_INLINE const int8_t * bson_vector_int8_const_view_pointer (bson_vector_int8_const_view_t view) { return (const int8_t *) view.binary.data + BSON_VECTOR_HEADER_LEN; From 75a09843eca5bd3029e0ca6eab0c26950ac7fe56 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Tue, 18 Feb 2025 09:02:42 -0800 Subject: [PATCH 09/51] Trivial, avoid temporarily viewing header bytes as int8_t --- src/libbson/src/bson/bson-vector.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libbson/src/bson/bson-vector.h b/src/libbson/src/bson/bson-vector.h index 36bd1944d06..c3eec4fe9b9 100644 --- a/src/libbson/src/bson/bson-vector.h +++ b/src/libbson/src/bson/bson-vector.h @@ -262,13 +262,13 @@ bson_append_array_from_vector_packed_bits (bson_t *bson, static BSON_INLINE const int8_t * bson_vector_int8_const_view_pointer (bson_vector_int8_const_view_t view) { - return (const int8_t *) view.binary.data + BSON_VECTOR_HEADER_LEN; + return (const int8_t *) (view.binary.data + BSON_VECTOR_HEADER_LEN); } static BSON_INLINE int8_t * bson_vector_int8_view_pointer (bson_vector_int8_view_t view) { - return (int8_t *) view.binary.data + BSON_VECTOR_HEADER_LEN; + return (int8_t *) (view.binary.data + BSON_VECTOR_HEADER_LEN); } From 6168cb20a8dd0d81b5349664ac865f9389f693b5 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Tue, 18 Feb 2025 15:46:14 -0800 Subject: [PATCH 10/51] Fix typo in man_page definition --- src/libbson/doc/bson_vector_int8_const_view_pointer.rst | 2 +- src/libbson/doc/bson_vector_int8_view_pointer.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libbson/doc/bson_vector_int8_const_view_pointer.rst b/src/libbson/doc/bson_vector_int8_const_view_pointer.rst index b2cd3f2ef2b..555cfbd8d6a 100644 --- a/src/libbson/doc/bson_vector_int8_const_view_pointer.rst +++ b/src/libbson/doc/bson_vector_int8_const_view_pointer.rst @@ -1,4 +1,4 @@ -a``:man_page: bson_vector_int8_const_view_pointer +:man_page: bson_vector_int8_const_view_pointer bson_vector_int8_const_view_pointer() ===================================== diff --git a/src/libbson/doc/bson_vector_int8_view_pointer.rst b/src/libbson/doc/bson_vector_int8_view_pointer.rst index 0b9fa329107..afaa4630597 100644 --- a/src/libbson/doc/bson_vector_int8_view_pointer.rst +++ b/src/libbson/doc/bson_vector_int8_view_pointer.rst @@ -1,4 +1,4 @@ -a``:man_page: bson_vector_int8_view_pointer +:man_page: bson_vector_int8_view_pointer bson_vector_int8_view_pointer() =============================== From 1a68f6aafcd82311a293bf752974451c9c0c7162 Mon Sep 17 00:00:00 2001 From: mdbmes Date: Tue, 25 Feb 2025 12:45:15 -0800 Subject: [PATCH 11/51] Update src/libbson/src/bson/bson.c Co-authored-by: Ezra Chung <88335979+eramongodb@users.noreply.github.com> --- src/libbson/src/bson/bson.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libbson/src/bson/bson.c b/src/libbson/src/bson/bson.c index 36cbc4efa27..97d8f8f2c06 100644 --- a/src/libbson/src/bson/bson.c +++ b/src/libbson/src/bson/bson.c @@ -727,6 +727,7 @@ _bson_append_binary (bson_t *bson, /* IN */ BSON_ASSERT_PARAM (bson); BSON_ASSERT_PARAM (key); + BSON_OPTIONAL_PARAM (binary); BSON_APPEND_BYTES_LIST_DECLARE (args); From 6270bc5c047ca47dff5bf86f20d793dc527eec98 Mon Sep 17 00:00:00 2001 From: mdbmes Date: Tue, 25 Feb 2025 12:45:25 -0800 Subject: [PATCH 12/51] Update src/libbson/src/bson/bson.c Co-authored-by: Ezra Chung <88335979+eramongodb@users.noreply.github.com> --- src/libbson/src/bson/bson.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libbson/src/bson/bson.c b/src/libbson/src/bson/bson.c index 97d8f8f2c06..f09cfec46be 100644 --- a/src/libbson/src/bson/bson.c +++ b/src/libbson/src/bson/bson.c @@ -698,7 +698,7 @@ bson_append_array (bson_t *bson, /* IN */ * * _bson_append_binary -- * - * Append a BSON_TYPE_BINARY field, with or without data copied in. + * Append a BSON_TYPE_BINARY field, optionally copying @binary into the field. * * Parameters: * @subtype: the BSON Binary Subtype. See bsonspec.org for more From 21c5054b44d44be6a29b720455063084dbbdb804 Mon Sep 17 00:00:00 2001 From: mdbmes Date: Tue, 25 Feb 2025 12:45:43 -0800 Subject: [PATCH 13/51] Update src/libbson/src/bson/bson.c Co-authored-by: Ezra Chung <88335979+eramongodb@users.noreply.github.com> --- src/libbson/src/bson/bson.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libbson/src/bson/bson.c b/src/libbson/src/bson/bson.c index f09cfec46be..e06ef90c950 100644 --- a/src/libbson/src/bson/bson.c +++ b/src/libbson/src/bson/bson.c @@ -704,7 +704,7 @@ bson_append_array (bson_t *bson, /* IN */ * @subtype: the BSON Binary Subtype. See bsonspec.org for more * information. * @binary: Optional pointer to the raw binary data. - * @length: the size of @binary in bytes. + * @length: the size of the field's binary data in bytes. * * Returns: * true if successful; otherwise false. From edc9b203f86b94296c2faa70ce9f5717cf90a52c Mon Sep 17 00:00:00 2001 From: mdbmes Date: Tue, 25 Feb 2025 12:45:55 -0800 Subject: [PATCH 14/51] Update src/libbson/src/bson/bson.c Co-authored-by: Ezra Chung <88335979+eramongodb@users.noreply.github.com> --- src/libbson/src/bson/bson.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libbson/src/bson/bson.c b/src/libbson/src/bson/bson.c index e06ef90c950..c32c8992aa1 100644 --- a/src/libbson/src/bson/bson.c +++ b/src/libbson/src/bson/bson.c @@ -813,8 +813,8 @@ bson_append_binary (bson_t *bson, /* IN */ * * Append binary data to @bson by framing an uninitialized field to be written by the caller. * The field will have the BSON_TYPE_BINARY type. On success, the caller MUST write to all - * bytes in the binary data field. The returned `*binary` pointer is only valid until the - * bson_t is modified or destroyed. + * bytes in the binary data field. The returned `*binary` pointer may be invalidated by + * subsequent modifications to @bson. * * Parameters: * @subtype: the BSON Binary Subtype. See bsonspec.org for more From fe491be79f91dc0bd43320a52cd3caa4bfebd0aa Mon Sep 17 00:00:00 2001 From: mdbmes Date: Tue, 25 Feb 2025 13:03:09 -0800 Subject: [PATCH 15/51] Update src/libbson/src/bson/bson-vector.c Co-authored-by: Ezra Chung <88335979+eramongodb@users.noreply.github.com> --- src/libbson/src/bson/bson-vector.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libbson/src/bson/bson-vector.c b/src/libbson/src/bson/bson-vector.c index c488d6f1c32..733b3f9b94d 100644 --- a/src/libbson/src/bson/bson-vector.c +++ b/src/libbson/src/bson/bson-vector.c @@ -63,7 +63,7 @@ bson_vector_packed_bits_validate (bson_vector_binary_header_impl_t header, } else { // We need to read the last byte of the binary block to validate that unused bits are zero. uint8_t last_data_byte = binary_data[binary_data_len - 1]; - uint8_t mask_of_unused_bits = (1 << padding) - 1; + uint8_t mask_of_unused_bits = (uint8_t) ((1u << padding) - 1u); return (last_data_byte & mask_of_unused_bits) == 0; } } else { From 217562c9da05217ae3daeb13de65c72affd29830 Mon Sep 17 00:00:00 2001 From: mdbmes Date: Tue, 25 Feb 2025 13:04:20 -0800 Subject: [PATCH 16/51] Update src/libbson/src/bson/bson-vector-private.h Co-authored-by: Ezra Chung <88335979+eramongodb@users.noreply.github.com> --- src/libbson/src/bson/bson-vector-private.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libbson/src/bson/bson-vector-private.h b/src/libbson/src/bson/bson-vector-private.h index 14867e1ed3f..0882dead92d 100644 --- a/src/libbson/src/bson/bson-vector-private.h +++ b/src/libbson/src/bson/bson-vector-private.h @@ -43,7 +43,7 @@ bson_vector_header_byte_0 (bson_vector_element_type_t element_type, bson_vector_ { BSON_ASSERT ((unsigned) element_type <= 0x0f); BSON_ASSERT ((unsigned) element_size <= 0x0f); - return (uint8_t) element_type << 4 | (uint8_t) element_size; + return (uint8_t) (((unsigned) element_type << 4) | (unsigned) element_size); } // See also `bson_vector_padding_from_header_byte_1` defined in for use by public inline functions. From f6b58c0663a47c239302fc28b998e85626f1da3a Mon Sep 17 00:00:00 2001 From: mdbmes Date: Tue, 25 Feb 2025 13:05:44 -0800 Subject: [PATCH 17/51] Update src/libbson/src/bson/bson-vector.h Co-authored-by: Ezra Chung <88335979+eramongodb@users.noreply.github.com> --- src/libbson/src/bson/bson-vector.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libbson/src/bson/bson-vector.h b/src/libbson/src/bson/bson-vector.h index c3eec4fe9b9..ba434798227 100644 --- a/src/libbson/src/bson/bson-vector.h +++ b/src/libbson/src/bson/bson-vector.h @@ -357,7 +357,7 @@ bson_vector_packed_bits_view_padding (bson_vector_packed_bits_view_t view) static BSON_INLINE size_t bson_vector_packed_bits_const_view_length (bson_vector_packed_bits_const_view_t view) { - return bson_vector_packed_bits_const_view_length_bytes (view) * (size_t) 8 - + return bson_vector_packed_bits_const_view_length_bytes (view) * 8u - bson_vector_packed_bits_const_view_padding (view); } From 3fa7c05b8104ea291f1c24ddb0698c1367b98625 Mon Sep 17 00:00:00 2001 From: mdbmes Date: Tue, 25 Feb 2025 13:06:14 -0800 Subject: [PATCH 18/51] Update src/libbson/src/bson/bson-vector.h Co-authored-by: Ezra Chung <88335979+eramongodb@users.noreply.github.com> --- src/libbson/src/bson/bson-vector.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libbson/src/bson/bson-vector.h b/src/libbson/src/bson/bson-vector.h index ba434798227..b2abd460e81 100644 --- a/src/libbson/src/bson/bson-vector.h +++ b/src/libbson/src/bson/bson-vector.h @@ -510,7 +510,7 @@ bson_vector_packed_bits_view_write_packed (bson_vector_packed_bits_view_t view, size_t other_bytes = byte_count - 1u; memcpy (view.binary.data + BSON_VECTOR_HEADER_LEN + vector_offset_bytes, packed_values, other_bytes); view.binary.data[BSON_VECTOR_HEADER_LEN + vector_offset_bytes + other_bytes] = - ((uint8_t) 0xFF << bson_vector_packed_bits_view_padding (view)) & packed_values[other_bytes]; + (UINT8_C (0xFF) << bson_vector_packed_bits_view_padding (view)) & packed_values[other_bytes]; } else { memcpy (view.binary.data + BSON_VECTOR_HEADER_LEN + vector_offset_bytes, packed_values, byte_count); } From 12e6edf6655a94e4c6bfe61a416964d3ab38102c Mon Sep 17 00:00:00 2001 From: mdbmes Date: Tue, 25 Feb 2025 13:07:16 -0800 Subject: [PATCH 19/51] Update src/libbson/tests/test-bson-vector.c Co-authored-by: Ezra Chung <88335979+eramongodb@users.noreply.github.com> --- src/libbson/tests/test-bson-vector.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libbson/tests/test-bson-vector.c b/src/libbson/tests/test-bson-vector.c index fc1b694d6b8..62ccf4cc2fd 100644 --- a/src/libbson/tests/test-bson-vector.c +++ b/src/libbson/tests/test-bson-vector.c @@ -156,7 +156,7 @@ append_vector_packed_bits_from_packed_array ( static void hex_str_to_bson (bson_t *bson_out, const char *hex_str) { - uint32_t size = strlen (hex_str) / 2; + uint32_t size = (uint32_t) strlen (hex_str) / 2u; uint8_t *buffer = bson_reserve_buffer (bson_out, size); for (uint32_t i = 0; i < size; i++) { unsigned int byte; From 41a7ebbf81817596d25a81eb4b3061978293bb5d Mon Sep 17 00:00:00 2001 From: mdbmes Date: Tue, 25 Feb 2025 13:08:55 -0800 Subject: [PATCH 20/51] Update src/libbson/tests/test-bson-vector.c Co-authored-by: Ezra Chung <88335979+eramongodb@users.noreply.github.com> --- src/libbson/tests/test-bson-vector.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libbson/tests/test-bson-vector.c b/src/libbson/tests/test-bson-vector.c index 62ccf4cc2fd..a14625b50a6 100644 --- a/src/libbson/tests/test-bson-vector.c +++ b/src/libbson/tests/test-bson-vector.c @@ -140,7 +140,7 @@ append_vector_packed_bits_from_packed_array ( } bson_vector_packed_bits_view_t view; - if (bson_append_vector_packed_bits (bson, key, key_length, byte_count * 8 - padding, &view)) { + if (bson_append_vector_packed_bits (bson, key, key_length, byte_count * 8u - (size_t) padding, &view)) { bson_iter_t copy_iter = *iter; for (size_t i = 0; i < byte_count; i++) { BSON_ASSERT (bson_iter_next (©_iter)); From 149d44102d14980886aec881a1ad8fb07604621a Mon Sep 17 00:00:00 2001 From: mdbmes Date: Tue, 25 Feb 2025 13:10:00 -0800 Subject: [PATCH 21/51] Update src/libbson/tests/test-bson-vector.c Co-authored-by: Ezra Chung <88335979+eramongodb@users.noreply.github.com> --- src/libbson/tests/test-bson-vector.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libbson/tests/test-bson-vector.c b/src/libbson/tests/test-bson-vector.c index a14625b50a6..1e6a7f2cad8 100644 --- a/src/libbson/tests/test-bson-vector.c +++ b/src/libbson/tests/test-bson-vector.c @@ -332,7 +332,7 @@ test_bson_vector_json_case (vector_json_test_case_t *test_case) if (actual_double != actual_double) { is_sorta_equal = true; } - } else if (expected_double == 0 || expected_double * 0 != 0) { + } else if (expected_double == 0.0 || expected_double * 0.0 != 0.0) { // Infinity or zero, equality comparison is fine. is_sorta_equal = expected_double == actual_double; } else { From 4b2d6f30e745d574565b2ddc679343cb1280666d Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Tue, 25 Feb 2025 17:57:20 -0800 Subject: [PATCH 22/51] Rename packed_bits to packed_bit * replace s/packed_bits/packed_bit/ * in filenames also * and fixup documentation headings and indents --- src/libbson/doc/binary_vector.rst | 22 +- .../doc/bson_append_array_from_vector.rst | 2 +- .../bson_append_array_from_vector_float32.rst | 2 +- .../bson_append_array_from_vector_int8.rst | 2 +- ...on_append_array_from_vector_packed_bit.rst | 40 +++ ...n_append_array_from_vector_packed_bits.rst | 40 --- .../doc/bson_append_vector_float32.rst | 2 +- .../bson_append_vector_float32_from_array.rst | 2 +- src/libbson/doc/bson_append_vector_int8.rst | 2 +- .../bson_append_vector_int8_from_array.rst | 2 +- ....rst => bson_append_vector_packed_bit.rst} | 24 +- ...n_append_vector_packed_bit_from_array.rst} | 22 +- ...n_array_builder_append_vector_elements.rst | 2 +- ...der_append_vector_packed_bit_elements.rst} | 12 +- src/libbson/doc/bson_iter_t.rst | 2 +- ..._vector_packed_bit_binary_data_length.rst} | 10 +- ...vector_packed_bit_const_view_from_iter.rst | 37 +++ ...bson_vector_packed_bit_const_view_init.rst | 39 +++ ...on_vector_packed_bit_const_view_length.rst | 33 +++ ...tor_packed_bit_const_view_length_bytes.rst | 34 +++ ..._vector_packed_bit_const_view_padding.rst} | 14 +- ...tor_packed_bit_const_view_read_packed.rst} | 22 +- .../bson_vector_packed_bit_const_view_t.rst | 75 ++++++ ...tor_packed_bit_const_view_unpack_bool.rst} | 20 +- .../bson_vector_packed_bit_view_as_const.rst | 29 +++ .../bson_vector_packed_bit_view_from_iter.rst | 33 +++ .../doc/bson_vector_packed_bit_view_init.rst | 35 +++ .../bson_vector_packed_bit_view_length.rst | 29 +++ ...n_vector_packed_bit_view_length_bytes.rst} | 12 +- ...bson_vector_packed_bit_view_pack_bool.rst} | 18 +- ...> bson_vector_packed_bit_view_padding.rst} | 14 +- ...on_vector_packed_bit_view_read_packed.rst} | 22 +- .../doc/bson_vector_packed_bit_view_t.rst | 85 +++++++ ...on_vector_packed_bit_view_unpack_bool.rst} | 20 +- ...n_vector_packed_bit_view_write_packed.rst} | 22 +- ...ector_packed_bits_const_view_from_iter.rst | 37 --- ...son_vector_packed_bits_const_view_init.rst | 39 --- ...n_vector_packed_bits_const_view_length.rst | 33 --- ...or_packed_bits_const_view_length_bytes.rst | 34 --- .../bson_vector_packed_bits_const_view_t.rst | 75 ------ .../bson_vector_packed_bits_view_as_const.rst | 29 --- ...bson_vector_packed_bits_view_from_iter.rst | 33 --- .../doc/bson_vector_packed_bits_view_init.rst | 35 --- .../bson_vector_packed_bits_view_length.rst | 29 --- .../doc/bson_vector_packed_bits_view_t.rst | 85 ------- src/libbson/src/bson/bson-iter.h | 2 +- src/libbson/src/bson/bson-vector.c | 76 +++--- src/libbson/src/bson/bson-vector.h | 153 ++++++------ src/libbson/tests/test-bson-vector.c | 234 +++++++++--------- 49 files changed, 837 insertions(+), 838 deletions(-) create mode 100644 src/libbson/doc/bson_append_array_from_vector_packed_bit.rst delete mode 100644 src/libbson/doc/bson_append_array_from_vector_packed_bits.rst rename src/libbson/doc/{bson_append_vector_packed_bits.rst => bson_append_vector_packed_bit.rst} (55%) rename src/libbson/doc/{bson_append_vector_packed_bits_from_array.rst => bson_append_vector_packed_bit_from_array.rst} (69%) rename src/libbson/doc/{bson_array_builder_append_vector_packed_bits_elements.rst => bson_array_builder_append_vector_packed_bit_elements.rst} (54%) rename src/libbson/doc/{bson_vector_packed_bits_binary_data_length.rst => bson_vector_packed_bit_binary_data_length.rst} (69%) create mode 100644 src/libbson/doc/bson_vector_packed_bit_const_view_from_iter.rst create mode 100644 src/libbson/doc/bson_vector_packed_bit_const_view_init.rst create mode 100644 src/libbson/doc/bson_vector_packed_bit_const_view_length.rst create mode 100644 src/libbson/doc/bson_vector_packed_bit_const_view_length_bytes.rst rename src/libbson/doc/{bson_vector_packed_bits_const_view_padding.rst => bson_vector_packed_bit_const_view_padding.rst} (53%) rename src/libbson/doc/{bson_vector_packed_bits_const_view_read_packed.rst => bson_vector_packed_bit_const_view_read_packed.rst} (57%) create mode 100644 src/libbson/doc/bson_vector_packed_bit_const_view_t.rst rename src/libbson/doc/{bson_vector_packed_bits_const_view_unpack_bool.rst => bson_vector_packed_bit_const_view_unpack_bool.rst} (54%) create mode 100644 src/libbson/doc/bson_vector_packed_bit_view_as_const.rst create mode 100644 src/libbson/doc/bson_vector_packed_bit_view_from_iter.rst create mode 100644 src/libbson/doc/bson_vector_packed_bit_view_init.rst create mode 100644 src/libbson/doc/bson_vector_packed_bit_view_length.rst rename src/libbson/doc/{bson_vector_packed_bits_view_length_bytes.rst => bson_vector_packed_bit_view_length_bytes.rst} (55%) rename src/libbson/doc/{bson_vector_packed_bits_view_pack_bool.rst => bson_vector_packed_bit_view_pack_bool.rst} (60%) rename src/libbson/doc/{bson_vector_packed_bits_view_padding.rst => bson_vector_packed_bit_view_padding.rst} (55%) rename src/libbson/doc/{bson_vector_packed_bits_view_read_packed.rst => bson_vector_packed_bit_view_read_packed.rst} (59%) create mode 100644 src/libbson/doc/bson_vector_packed_bit_view_t.rst rename src/libbson/doc/{bson_vector_packed_bits_view_unpack_bool.rst => bson_vector_packed_bit_view_unpack_bool.rst} (56%) rename src/libbson/doc/{bson_vector_packed_bits_view_write_packed.rst => bson_vector_packed_bit_view_write_packed.rst} (61%) delete mode 100644 src/libbson/doc/bson_vector_packed_bits_const_view_from_iter.rst delete mode 100644 src/libbson/doc/bson_vector_packed_bits_const_view_init.rst delete mode 100644 src/libbson/doc/bson_vector_packed_bits_const_view_length.rst delete mode 100644 src/libbson/doc/bson_vector_packed_bits_const_view_length_bytes.rst delete mode 100644 src/libbson/doc/bson_vector_packed_bits_const_view_t.rst delete mode 100644 src/libbson/doc/bson_vector_packed_bits_view_as_const.rst delete mode 100644 src/libbson/doc/bson_vector_packed_bits_view_from_iter.rst delete mode 100644 src/libbson/doc/bson_vector_packed_bits_view_init.rst delete mode 100644 src/libbson/doc/bson_vector_packed_bits_view_length.rst delete mode 100644 src/libbson/doc/bson_vector_packed_bits_view_t.rst diff --git a/src/libbson/doc/binary_vector.rst b/src/libbson/doc/binary_vector.rst index 249364232b9..a9c72ae8fee 100644 --- a/src/libbson/doc/binary_vector.rst +++ b/src/libbson/doc/binary_vector.rst @@ -15,7 +15,7 @@ The specification currently defines three element types, which Libbson interpret * ``int8``: signed integer elements, equivalent to C ``int8_t``. * ``float32``: IEEE 754 floating point, 32 bits per element, least-significant byte first. After alignment and byte swapping, elements are equivalent to C ``float``. -* ``packed_bits``: single-bit integer elements, packed most-significant bit first. Accessible in packed form as C ``uint8_t`` or as unpacked elements using C ``bool``. +* ``packed_bit``: single-bit integer elements, packed most-significant bit first. Accessible in packed form as C ``uint8_t`` or as unpacked elements using C ``bool``. Vector Views ------------ @@ -28,8 +28,8 @@ Vector Views bson_vector_int8_const_view_t bson_vector_float32_view_t bson_vector_float32_const_view_t - bson_vector_packed_bits_view_t - bson_vector_packed_bits_const_view_t + bson_vector_packed_bit_view_t + bson_vector_packed_bit_const_view_t Integration ----------- @@ -42,7 +42,7 @@ Integration bson_append_vector_int8 bson_append_vector_float32 - bson_append_vector_packed_bits + bson_append_vector_packed_bit * Accessing an existing Vector via :symbol:`bson_iter_t`: @@ -51,7 +51,7 @@ Integration #define BSON_ITER_HOLDS_VECTOR(iter) /* ... */ #define BSON_ITER_HOLDS_VECTOR_INT8(iter) /* ... */ #define BSON_ITER_HOLDS_VECTOR_FLOAT32(iter) /* ... */ - #define BSON_ITER_HOLDS_VECTOR_PACKED_BITS(iter) /* ... */ + #define BSON_ITER_HOLDS_VECTOR_PACKED_BIT(iter) /* ... */ .. toctree:: :titlesonly: @@ -61,8 +61,8 @@ Integration bson_vector_int8_const_view_from_iter bson_vector_float32_view_from_iter bson_vector_float32_const_view_from_iter - bson_vector_packed_bits_view_from_iter - bson_vector_packed_bits_const_view_from_iter + bson_vector_packed_bit_view_from_iter + bson_vector_packed_bit_const_view_from_iter Array Conversion ---------------- @@ -83,7 +83,7 @@ Array Conversion bson_append_array_from_vector_int8 bson_append_array_from_vector_float32 - bson_append_array_from_vector_packed_bits + bson_append_array_from_vector_packed_bit * Using :symbol:`bson_array_builder_t` for array-from-vector: @@ -93,7 +93,7 @@ Array Conversion bson_array_builder_append_vector_int8_elements bson_array_builder_append_vector_float32_elements - bson_array_builder_append_vector_packed_bits_elements + bson_array_builder_append_vector_packed_bit_elements bson_array_builder_append_vector_elements * Type specific vector-from-array: @@ -104,7 +104,7 @@ Array Conversion bson_append_vector_int8_from_array bson_append_vector_float32_from_array - bson_append_vector_packed_bits_from_array + bson_append_vector_packed_bit_from_array Additional Definitions ---------------------- @@ -133,7 +133,7 @@ Additional Definitions bson_vector_int8_binary_data_length bson_vector_float32_binary_data_length - bson_vector_packed_bits_binary_data_length + bson_vector_packed_bit_binary_data_length * Errors: diff --git a/src/libbson/doc/bson_append_array_from_vector.rst b/src/libbson/doc/bson_append_array_from_vector.rst index 8f65922180a..c247d889bcf 100644 --- a/src/libbson/doc/bson_append_array_from_vector.rst +++ b/src/libbson/doc/bson_append_array_from_vector.rst @@ -9,7 +9,7 @@ Synopsis .. code-block:: c #define BSON_APPEND_ARRAY_FROM_VECTOR(b, key, iter) \ - bson_append_array_from_vector (b, key, (int) strlen (key), iter) + bson_append_array_from_vector (b, key, (int) strlen (key), iter) bool bson_append_array_from_vector (bson_t *bson, diff --git a/src/libbson/doc/bson_append_array_from_vector_float32.rst b/src/libbson/doc/bson_append_array_from_vector_float32.rst index 5b012d5ecdd..376a95c0bab 100644 --- a/src/libbson/doc/bson_append_array_from_vector_float32.rst +++ b/src/libbson/doc/bson_append_array_from_vector_float32.rst @@ -9,7 +9,7 @@ Synopsis .. code-block:: c #define BSON_APPEND_ARRAY_FROM_VECTOR_FLOAT32(b, key, view) \ - bson_append_array_from_vector_float32 (b, key, (int) strlen (key), view) + bson_append_array_from_vector_float32 (b, key, (int) strlen (key), view) bool bson_append_array_from_vector_float32 (bson_t *bson, diff --git a/src/libbson/doc/bson_append_array_from_vector_int8.rst b/src/libbson/doc/bson_append_array_from_vector_int8.rst index cfd55726d37..d4f29b83463 100644 --- a/src/libbson/doc/bson_append_array_from_vector_int8.rst +++ b/src/libbson/doc/bson_append_array_from_vector_int8.rst @@ -9,7 +9,7 @@ Synopsis .. code-block:: c #define BSON_APPEND_ARRAY_FROM_VECTOR_INT8(b, key, view) \ - bson_append_array_from_vector_int8 (b, key, (int) strlen (key), view) + bson_append_array_from_vector_int8 (b, key, (int) strlen (key), view) bool bson_append_array_from_vector_int8 (bson_t *bson, diff --git a/src/libbson/doc/bson_append_array_from_vector_packed_bit.rst b/src/libbson/doc/bson_append_array_from_vector_packed_bit.rst new file mode 100644 index 00000000000..0f30355b020 --- /dev/null +++ b/src/libbson/doc/bson_append_array_from_vector_packed_bit.rst @@ -0,0 +1,40 @@ +:man_page: bson_append_array_from_vector_packed_bit + +bson_append_array_from_vector_packed_bit() +========================================== + +Synopsis +-------- + +.. code-block:: c + + #define BSON_APPEND_ARRAY_FROM_VECTOR_PACKED_BIT(b, key, view) \ + bson_append_array_from_vector_packed_bit (b, key, (int) strlen (key), view) + + bool + bson_append_array_from_vector_packed_bit (bson_t *bson, + const char *key, + int key_length, + bson_vector_packed_bit_const_view_t view); + +Parameters +---------- + +* ``bson``: A :symbol:`bson_t`. +* ``key``: An ASCII C string containing the name of the field. +* ``key_length``: The length of ``key`` in bytes, or -1 to determine the length with ``strlen()``. +* ``view``: A :symbol:`bson_vector_packed_bit_const_view_t` pointing to validated ``packed_bit`` :doc:`binary_vector` data. + +Description +----------- + +Converts the Vector pointed to by ``view`` into a plain BSON Array, written to ``bson`` under the name ``key``. + +Returns +------- + +Returns ``true`` if the operation was applied successfully. The function fails if appending the array grows ``bson`` larger than INT32_MAX. + +.. seealso:: + + | :symbol:`bson_array_builder_append_vector_packed_bit_elements` diff --git a/src/libbson/doc/bson_append_array_from_vector_packed_bits.rst b/src/libbson/doc/bson_append_array_from_vector_packed_bits.rst deleted file mode 100644 index dd4ecb5d5b9..00000000000 --- a/src/libbson/doc/bson_append_array_from_vector_packed_bits.rst +++ /dev/null @@ -1,40 +0,0 @@ -:man_page: bson_append_array_from_vector_packed_bits - -bson_append_array_from_vector_packed_bits() -=========================================== - -Synopsis --------- - -.. code-block:: c - - #define BSON_APPEND_ARRAY_FROM_VECTOR_PACKED_BITS(b, key, view) \ - bson_append_array_from_vector_packed_bits (b, key, (int) strlen (key), view) - - bool - bson_append_array_from_vector_packed_bits (bson_t *bson, - const char *key, - int key_length, - bson_vector_packed_bits_const_view_t view); - -Parameters ----------- - -* ``bson``: A :symbol:`bson_t`. -* ``key``: An ASCII C string containing the name of the field. -* ``key_length``: The length of ``key`` in bytes, or -1 to determine the length with ``strlen()``. -* ``view``: A :symbol:`bson_vector_packed_bits_const_view_t` pointing to validated ``packed_bits`` :doc:`binary_vector` data. - -Description ------------ - -Converts the Vector pointed to by ``view`` into a plain BSON Array, written to ``bson`` under the name ``key``. - -Returns -------- - -Returns ``true`` if the operation was applied successfully. The function fails if appending the array grows ``bson`` larger than INT32_MAX. - -.. seealso:: - - | :symbol:`bson_array_builder_append_vector_packed_bits_elements` diff --git a/src/libbson/doc/bson_append_vector_float32.rst b/src/libbson/doc/bson_append_vector_float32.rst index 22f85217e97..ecdbb5194f4 100644 --- a/src/libbson/doc/bson_append_vector_float32.rst +++ b/src/libbson/doc/bson_append_vector_float32.rst @@ -9,7 +9,7 @@ Synopsis .. code-block:: c #define BSON_APPEND_VECTOR_FLOAT32(b, key, count, view) \ - bson_append_vector_float32 (b, key, (int) strlen (key), count, view) + bson_append_vector_float32 (b, key, (int) strlen (key), count, view) bool bson_append_vector_float32 (bson_t *bson, diff --git a/src/libbson/doc/bson_append_vector_float32_from_array.rst b/src/libbson/doc/bson_append_vector_float32_from_array.rst index 5f230edddb6..76c991f84e1 100644 --- a/src/libbson/doc/bson_append_vector_float32_from_array.rst +++ b/src/libbson/doc/bson_append_vector_float32_from_array.rst @@ -9,7 +9,7 @@ Synopsis .. code-block:: c #define BSON_APPEND_VECTOR_FLOAT32_FROM_ARRAY(b, key, iter, err) \ - bson_append_vector_float32_from_array (b, key, (int) strlen (key), iter, err) + bson_append_vector_float32_from_array (b, key, (int) strlen (key), iter, err) bool bson_append_vector_float32_from_array (bson_t *bson, diff --git a/src/libbson/doc/bson_append_vector_int8.rst b/src/libbson/doc/bson_append_vector_int8.rst index 69ca769137f..ae71794aec9 100644 --- a/src/libbson/doc/bson_append_vector_int8.rst +++ b/src/libbson/doc/bson_append_vector_int8.rst @@ -9,7 +9,7 @@ Synopsis .. code-block:: c #define BSON_APPEND_VECTOR_INT8(b, key, count, view) \ - bson_append_vector_int8 (b, key, (int) strlen (key), count, view) + bson_append_vector_int8 (b, key, (int) strlen (key), count, view) bool bson_append_vector_int8 (bson_t *bson, diff --git a/src/libbson/doc/bson_append_vector_int8_from_array.rst b/src/libbson/doc/bson_append_vector_int8_from_array.rst index de58e09873f..76e9efcd6d3 100644 --- a/src/libbson/doc/bson_append_vector_int8_from_array.rst +++ b/src/libbson/doc/bson_append_vector_int8_from_array.rst @@ -9,7 +9,7 @@ Synopsis .. code-block:: c #define BSON_APPEND_VECTOR_INT8_FROM_ARRAY(b, key, iter, err) \ - bson_append_vector_int8_from_array (b, key, (int) strlen (key), iter, err) + bson_append_vector_int8_from_array (b, key, (int) strlen (key), iter, err) bool bson_append_vector_int8_from_array (bson_t *bson, diff --git a/src/libbson/doc/bson_append_vector_packed_bits.rst b/src/libbson/doc/bson_append_vector_packed_bit.rst similarity index 55% rename from src/libbson/doc/bson_append_vector_packed_bits.rst rename to src/libbson/doc/bson_append_vector_packed_bit.rst index 068788f9a44..7f57463c4c1 100644 --- a/src/libbson/doc/bson_append_vector_packed_bits.rst +++ b/src/libbson/doc/bson_append_vector_packed_bit.rst @@ -1,22 +1,22 @@ -:man_page: bson_append_vector_packed_bits +:man_page: bson_append_vector_packed_bit -bson_append_vector_packed_bits() -================================ +bson_append_vector_packed_bit() +=============================== Synopsis -------- .. code-block:: c - #define BSON_APPEND_VECTOR_PACKED_BITS(b, key, count, view) \ - bson_append_vector_packed_bits (b, key, (int) strlen (key), count, view) + #define BSON_APPEND_VECTOR_PACKED_BIT(b, key, count, view) \ + bson_append_vector_packed_bit (b, key, (int) strlen (key), count, view) bool - bson_append_vector_packed_bits (bson_t *bson, - const char *key, - int key_length, - size_t element_count, - bson_vector_packed_bits_view_t *view_out); + bson_append_vector_packed_bit (bson_t *bson, + const char *key, + int key_length, + size_t element_count, + bson_vector_packed_bit_view_t *view_out); Parameters ---------- @@ -25,12 +25,12 @@ Parameters * ``key``: An ASCII C string containing the name of the field. * ``key_length``: The length of ``key`` in bytes, or -1 to determine the length with ``strlen()``. * ``element_count``: Number of elements to allocate space for. -* ``view_out``: Receives a :symbol:`bson_vector_packed_bits_view_t` with uninitialized elements. +* ``view_out``: Receives a :symbol:`bson_vector_packed_bit_view_t` with uninitialized elements. Description ----------- -Appends a new field to ``bson`` by allocating a Vector with the indicated number of ``packed_bits`` elements. +Appends a new field to ``bson`` by allocating a Vector with the indicated number of ``packed_bit`` elements. The elements will be uninitialized. On success, the caller must write every element in the Vector if the resulting :symbol:`bson_t` is to be used. diff --git a/src/libbson/doc/bson_append_vector_packed_bits_from_array.rst b/src/libbson/doc/bson_append_vector_packed_bit_from_array.rst similarity index 69% rename from src/libbson/doc/bson_append_vector_packed_bits_from_array.rst rename to src/libbson/doc/bson_append_vector_packed_bit_from_array.rst index 5728fab286f..fc767243a4c 100644 --- a/src/libbson/doc/bson_append_vector_packed_bits_from_array.rst +++ b/src/libbson/doc/bson_append_vector_packed_bit_from_array.rst @@ -1,22 +1,22 @@ -:man_page: bson_append_vector_packed_bits_from_array +:man_page: bson_append_vector_packed_bit_from_array -bson_append_vector_packed_bits_from_array() -=========================================== +bson_append_vector_packed_bit_from_array() +========================================== Synopsis -------- .. code-block:: c - #define BSON_APPEND_VECTOR_PACKED_BITS_FROM_ARRAY(b, key, iter, err) \ - bson_append_vector_packed_bits_from_array (b, key, (int) strlen (key), iter, err) + #define BSON_APPEND_VECTOR_PACKED_BIT_FROM_ARRAY(b, key, iter, err) \ + bson_append_vector_packed_bit_from_array (b, key, (int) strlen (key), iter, err) bool - bson_append_vector_packed_bits_from_array (bson_t *bson, - const char *key, - int key_length, - const bson_iter_t *iter, - bson_error_t *error); + bson_append_vector_packed_bit_from_array (bson_t *bson, + const char *key, + int key_length, + const bson_iter_t *iter, + bson_error_t *error); Parameters ---------- @@ -30,7 +30,7 @@ Parameters Description ----------- -Appends a new field to ``bson`` by converting an Array to a Vector of ``packed_bits`` elements. +Appends a new field to ``bson`` by converting an Array to a Vector of ``packed_bit`` elements. For the conversion to succeed, every item in the Array must be either an integer (``BSON_TYPE_INT32`` or ``BSON_TYPE_INT64``) with the values ``0`` or ``1``, or boolean (``BSON_TYPE_BOOL``). If any element has an incorrect type or an out-of-range value, the conversion fails with an ``error`` message providing details, and no changes are made to ``bson``. diff --git a/src/libbson/doc/bson_array_builder_append_vector_elements.rst b/src/libbson/doc/bson_array_builder_append_vector_elements.rst index 1de13a7ccd7..101e24eca78 100644 --- a/src/libbson/doc/bson_array_builder_append_vector_elements.rst +++ b/src/libbson/doc/bson_array_builder_append_vector_elements.rst @@ -35,4 +35,4 @@ Returns ``true`` if the operation was applied successfully. The function fails i | :symbol:`bson_append_array_from_vector` | :symbol:`bson_array_builder_append_vector_int8_elements` | :symbol:`bson_array_builder_append_vector_float32_elements` - | :symbol:`bson_array_builder_append_vector_packed_bits_elements` + | :symbol:`bson_array_builder_append_vector_packed_bit_elements` diff --git a/src/libbson/doc/bson_array_builder_append_vector_packed_bits_elements.rst b/src/libbson/doc/bson_array_builder_append_vector_packed_bit_elements.rst similarity index 54% rename from src/libbson/doc/bson_array_builder_append_vector_packed_bits_elements.rst rename to src/libbson/doc/bson_array_builder_append_vector_packed_bit_elements.rst index 36b6afc1085..146fe53db6e 100644 --- a/src/libbson/doc/bson_array_builder_append_vector_packed_bits_elements.rst +++ b/src/libbson/doc/bson_array_builder_append_vector_packed_bit_elements.rst @@ -1,7 +1,7 @@ -:man_page: bson_array_builder_append_vector_packed_bits_elements +:man_page: bson_array_builder_append_vector_packed_bit_elements -bson_array_builder_append_vector_packed_bits_elements() -======================================================= +bson_array_builder_append_vector_packed_bit_elements() +====================================================== Synopsis -------- @@ -9,14 +9,14 @@ Synopsis .. code-block:: c bool - bson_array_builder_append_vector_packed_bits_elements (bson_array_builder_t *builder, - bson_vector_packed_bits_const_view_t view); + bson_array_builder_append_vector_packed_bit_elements (bson_array_builder_t *builder, + bson_vector_packed_bit_const_view_t view); Parameters ---------- * ``builder``: A valid :symbol:`bson_array_builder_t`. -* ``view``: A :symbol:`bson_vector_packed_bits_const_view_t` pointing to validated ``packed_bits`` :doc:`binary_vector` data. +* ``view``: A :symbol:`bson_vector_packed_bit_const_view_t` pointing to validated ``packed_bit`` :doc:`binary_vector` data. Description ----------- diff --git a/src/libbson/doc/bson_iter_t.rst b/src/libbson/doc/bson_iter_t.rst index f636599c520..dd43318f68d 100644 --- a/src/libbson/doc/bson_iter_t.rst +++ b/src/libbson/doc/bson_iter_t.rst @@ -25,7 +25,7 @@ Synopsis #define BSON_ITER_HOLDS_VECTOR(iter) /* ... */ #define BSON_ITER_HOLDS_VECTOR_INT8(iter) /* ... */ #define BSON_ITER_HOLDS_VECTOR_FLOAT32(iter) /* ... */ - #define BSON_ITER_HOLDS_VECTOR_PACKED_BITS(iter) /* ... */ + #define BSON_ITER_HOLDS_VECTOR_PACKED_BIT(iter) /* ... */ #define BSON_ITER_HOLDS_UNDEFINED(iter) /* ... */ diff --git a/src/libbson/doc/bson_vector_packed_bits_binary_data_length.rst b/src/libbson/doc/bson_vector_packed_bit_binary_data_length.rst similarity index 69% rename from src/libbson/doc/bson_vector_packed_bits_binary_data_length.rst rename to src/libbson/doc/bson_vector_packed_bit_binary_data_length.rst index 499f78441bb..0d073db4360 100644 --- a/src/libbson/doc/bson_vector_packed_bits_binary_data_length.rst +++ b/src/libbson/doc/bson_vector_packed_bit_binary_data_length.rst @@ -1,9 +1,9 @@ -:man_page: bson_vector_packed_bits_binary_data_length +:man_page: bson_vector_packed_bit_binary_data_length -bson_vector_packed_bits_binary_data_length() -============================================ +bson_vector_packed_bit_binary_data_length() +=========================================== -Calculate the size of a BSON Binary field that would be needed to store a Vector with the indicated number of ``packed_bits`` elements. +Calculate the size of a BSON Binary field that would be needed to store a Vector with the indicated number of ``packed_bit`` elements. Synopsis -------- @@ -11,7 +11,7 @@ Synopsis .. code-block:: c uint32_t - bson_vector_packed_bits_binary_data_length (size_t element_count); + bson_vector_packed_bit_binary_data_length (size_t element_count); Parameters ---------- diff --git a/src/libbson/doc/bson_vector_packed_bit_const_view_from_iter.rst b/src/libbson/doc/bson_vector_packed_bit_const_view_from_iter.rst new file mode 100644 index 00000000000..664438ec8b1 --- /dev/null +++ b/src/libbson/doc/bson_vector_packed_bit_const_view_from_iter.rst @@ -0,0 +1,37 @@ +:man_page: bson_vector_packed_bit_const_view_from_iter + +bson_vector_packed_bit_const_view_from_iter() +============================================= + +Initialize a :symbol:`bson_vector_packed_bit_const_view_t` from a :symbol:`bson_iter_t` pointing to a valid Vector of ``packed_bit`` element type. + +Synopsis +-------- + +.. code-block:: c + + bool + bson_vector_packed_bit_const_view_from_iter (bson_vector_packed_bit_const_view_t *view_out, + const bson_iter_t *iter); + +Parameters +---------- + +* ``view_out``: A :symbol:`bson_vector_packed_bit_const_view_t` is written here on success. +* ``iter``: A valid :symbol:`bson_iter_t`. + +Description +----------- + +The provided iterator, which must point to some kind of BSON item, will be checked for a valid Vector of ``packed_bit`` element type. +On success, a :symbol:`bson_vector_packed_bit_const_view_t` is set to point to the same underlying :symbol:`bson_t` buffer as the provided :symbol:`bson_iter_t`. +The view will only be valid until the containing document is destroyed or modified. + +Returns +------- + +Returns true if the view was successfully initialized. + +.. seealso:: + + | :symbol:`bson_vector_packed_bit_view_from_iter` diff --git a/src/libbson/doc/bson_vector_packed_bit_const_view_init.rst b/src/libbson/doc/bson_vector_packed_bit_const_view_init.rst new file mode 100644 index 00000000000..564283d3f95 --- /dev/null +++ b/src/libbson/doc/bson_vector_packed_bit_const_view_init.rst @@ -0,0 +1,39 @@ +:man_page: bson_vector_packed_bit_const_view_init + +bson_vector_packed_bit_const_view_init() +======================================== + +Initialize a :symbol:`bson_vector_packed_bit_const_view_t` from a const ``uint8_t`` buffer. + +Synopsis +-------- + +.. code-block:: c + + bool + bson_vector_packed_bit_const_view_init (bson_vector_packed_bit_const_view_t *view_out, + const uint8_t *binary_data, + uint32_t binary_data_len); + +Parameters +---------- + +* ``view_out``: A :symbol:`bson_vector_packed_bit_const_view_t` is written here on success. +* ``binary_data``: A pointer to the BSON Binary data block to be validated. +* ``binary_data_len``: Length of the binary data block, in bytes. + +Description +----------- + +The length, header, and trailing padding of the provided binary data block will be checked for a valid Vector of ``packed_bit`` element type. +On success, the pointer and length are packaged as a :symbol:`bson_vector_packed_bit_const_view_t` written to ``*view_out``. +The view will only be valid as long as ``binary_data`` is valid. + +Returns +------- + +Returns true if the view was successfully initialized. + +.. seealso:: + + | :symbol:`bson_vector_packed_bit_view_init` diff --git a/src/libbson/doc/bson_vector_packed_bit_const_view_length.rst b/src/libbson/doc/bson_vector_packed_bit_const_view_length.rst new file mode 100644 index 00000000000..b418614eb80 --- /dev/null +++ b/src/libbson/doc/bson_vector_packed_bit_const_view_length.rst @@ -0,0 +1,33 @@ +:man_page: bson_vector_packed_bit_const_view_length + +bson_vector_packed_bit_const_view_length() +========================================== + +Return the number of elements in a Vector referenced by a :symbol:`bson_vector_packed_bit_const_view_t`. + +Synopsis +-------- + +.. code-block:: c + + size_t + bson_vector_packed_bit_const_view_length (bson_vector_packed_bit_const_view_t view); + +Parameters +---------- + +* ``view``: A valid :symbol:`bson_vector_packed_bit_const_view_t`. + +Description +----------- + +An element count is calculated from information stored inside the `bson_vector_packed_bit_const_view_t` value. + +Returns +------- + +The number of elements, as a ``size_t``. + +.. seealso:: + + | :symbol:`bson_vector_packed_bit_view_length` diff --git a/src/libbson/doc/bson_vector_packed_bit_const_view_length_bytes.rst b/src/libbson/doc/bson_vector_packed_bit_const_view_length_bytes.rst new file mode 100644 index 00000000000..781beef6cc7 --- /dev/null +++ b/src/libbson/doc/bson_vector_packed_bit_const_view_length_bytes.rst @@ -0,0 +1,34 @@ +:man_page: bson_vector_packed_bit_const_view_length_bytes + +bson_vector_packed_bit_const_view_length_bytes() +================================================ + +Return the number of packed bytes in a Vector referenced by a :symbol:`bson_vector_packed_bit_const_view_t`. + +Synopsis +-------- + +.. code-block:: c + + size_t + bson_vector_packed_bit_const_view_length_bytes (bson_vector_packed_bit_const_view_t view); + +Parameters +---------- + +* ``view``: A valid :symbol:`bson_vector_packed_bit_const_view_t`. + +Description +----------- + +A byte count is calculated from the view's stored binary block length. +If the element count isn't a multiple of 8, the final byte will include bits that do not belong to any element. + +Returns +------- + +The number of bytes, as a ``size_t``. + +.. seealso:: + + | :symbol:`bson_vector_packed_bit_view_length_bytes` diff --git a/src/libbson/doc/bson_vector_packed_bits_const_view_padding.rst b/src/libbson/doc/bson_vector_packed_bit_const_view_padding.rst similarity index 53% rename from src/libbson/doc/bson_vector_packed_bits_const_view_padding.rst rename to src/libbson/doc/bson_vector_packed_bit_const_view_padding.rst index b3922a8d66f..8c34f5f0ab7 100644 --- a/src/libbson/doc/bson_vector_packed_bits_const_view_padding.rst +++ b/src/libbson/doc/bson_vector_packed_bit_const_view_padding.rst @@ -1,9 +1,9 @@ -:man_page: bson_vector_packed_bits_const_view_padding +:man_page: bson_vector_packed_bit_const_view_padding -bson_vector_packed_bits_const_view_padding() -============================================ +bson_vector_packed_bit_const_view_padding() +=========================================== -Returns the number of unused bits in a Vector referenced by a :symbol:`bson_vector_packed_bits_const_view_t`. +Returns the number of unused bits in a Vector referenced by a :symbol:`bson_vector_packed_bit_const_view_t`. Synopsis -------- @@ -11,12 +11,12 @@ Synopsis .. code-block:: c size_t - bson_vector_packed_bits_const_view_padding (bson_vector_packed_bits_const_view_t view); + bson_vector_packed_bit_const_view_padding (bson_vector_packed_bit_const_view_t view); Parameters ---------- -* ``view``: A valid :symbol:`bson_vector_packed_bits_const_view_t`. +* ``view``: A valid :symbol:`bson_vector_packed_bit_const_view_t`. Description ----------- @@ -31,4 +31,4 @@ Vector validation guarantees that empty Vectors have a ``padding`` of 0. .. seealso:: - | :symbol:`bson_vector_packed_bits_view_padding` + | :symbol:`bson_vector_packed_bit_view_padding` diff --git a/src/libbson/doc/bson_vector_packed_bits_const_view_read_packed.rst b/src/libbson/doc/bson_vector_packed_bit_const_view_read_packed.rst similarity index 57% rename from src/libbson/doc/bson_vector_packed_bits_const_view_read_packed.rst rename to src/libbson/doc/bson_vector_packed_bit_const_view_read_packed.rst index 01069904e2e..21ff00a3297 100644 --- a/src/libbson/doc/bson_vector_packed_bits_const_view_read_packed.rst +++ b/src/libbson/doc/bson_vector_packed_bit_const_view_read_packed.rst @@ -1,9 +1,9 @@ -:man_page: bson_vector_packed_bits_const_view_read_packed +:man_page: bson_vector_packed_bit_const_view_read_packed -bson_vector_packed_bits_const_view_read_packed() -================================================ +bson_vector_packed_bit_const_view_read_packed() +=============================================== -Copy a contiguous block of packed bytes out of a :symbol:`bson_vector_packed_bits_const_view_t`. +Copy a contiguous block of packed bytes out of a :symbol:`bson_vector_packed_bit_const_view_t`. Synopsis -------- @@ -11,15 +11,15 @@ Synopsis .. code-block:: c bool - bson_vector_packed_bits_const_view_read_packed (bson_vector_packed_bits_const_view_t view, - uint8_t *packed_values_out, - size_t byte_count, - size_t vector_offset_bytes); + bson_vector_packed_bit_const_view_read_packed (bson_vector_packed_bit_const_view_t view, + uint8_t *packed_values_out, + size_t byte_count, + size_t vector_offset_bytes); Parameters ---------- -* ``view``: A valid :symbol:`bson_vector_packed_bits_const_view_t`. +* ``view``: A valid :symbol:`bson_vector_packed_bit_const_view_t`. * ``packed_values_out``: Location where the packed bytes will be read to. * ``byte_count``: Number of bytes to read. * ``vector_offset_bytes``: The byte index of the first packed byte to read. @@ -41,5 +41,5 @@ On success, returns true and reads ``byte_count`` bytes into ``*packed_values_ou .. seealso:: - | :symbol:`bson_vector_packed_bits_view_read_packed` - | :symbol:`bson_vector_packed_bits_view_write_packed` + | :symbol:`bson_vector_packed_bit_view_read_packed` + | :symbol:`bson_vector_packed_bit_view_write_packed` diff --git a/src/libbson/doc/bson_vector_packed_bit_const_view_t.rst b/src/libbson/doc/bson_vector_packed_bit_const_view_t.rst new file mode 100644 index 00000000000..bcc9b50705e --- /dev/null +++ b/src/libbson/doc/bson_vector_packed_bit_const_view_t.rst @@ -0,0 +1,75 @@ +:man_page: bson_vector_packed_bit_const_view_t + +bson_vector_packed_bit_const_view_t +=================================== + +A reference to non-owned const BSON Binary data holding a valid Vector of ``packed_bit`` element type. + +Synopsis +-------- + +.. code-block:: c + + #include + + typedef struct bson_vector_packed_bit_const_view_t { + /*< private >*/ + } bson_vector_packed_bit_const_view_t; + +Description +----------- + +:symbol:`bson_vector_packed_bit_const_view_t` is a structure that acts as an opaque const reference to a block of memory that has been validated as a ``packed_bit`` vector. + +It is meant to be passed by value and can be discarded at any time. The contents of the structure should be considered private. + +The :symbol:`bson_t` *MUST* be valid for the lifetime of the view and it is an error to modify the :symbol:`bson_t` while using the view. + +.. only:: html + + Functions + --------- + + .. toctree:: + :titlesonly: + :maxdepth: 1 + + bson_vector_packed_bit_const_view_init + bson_vector_packed_bit_const_view_from_iter + bson_vector_packed_bit_const_view_length + bson_vector_packed_bit_const_view_length_bytes + bson_vector_packed_bit_const_view_padding + bson_vector_packed_bit_const_view_read_packed + bson_vector_packed_bit_const_view_unpack_bool + +Example +------- + +.. code-block:: c + + bson_iter_t iter; + bson_vector_packed_bit_const_view_t view; + + if (bson_iter_init_find (&iter, &doc, "vector") && bson_vector_packed_bit_const_view_from_iter (&view, &iter)) { + size_t length = bson_vector_packed_bit_const_view_length (view); + size_t length_bytes = bson_vector_packed_bit_const_view_length_bytes (view); + size_t padding = bson_vector_packed_bit_const_view_padding (view); + + printf ("Elements in 'vector':\n"); + for (size_t i = 0; i < length; i++) { + bool element; + BSON_ASSERT (bson_vector_packed_bit_const_view_unpack_bool (view, &element, 1, i)); + printf (" elements[%d] = %d\n", (int) i, (int) element); + } + + printf ("Bytes in 'vector': (%d bits unused)\n", (int) padding); + for (size_t i = 0; i < length_bytes; i++) { + uint8_t packed_byte; + BSON_ASSERT (bson_vector_packed_bit_const_view_read_packed (view, &packed_byte, 1, i)); + printf (" bytes[%d] = 0x%02x\n", (int) i, (unsigned) packed_byte); + } + } + +.. seealso:: + + | :symbol:`bson_vector_packed_bit_view_t` diff --git a/src/libbson/doc/bson_vector_packed_bits_const_view_unpack_bool.rst b/src/libbson/doc/bson_vector_packed_bit_const_view_unpack_bool.rst similarity index 54% rename from src/libbson/doc/bson_vector_packed_bits_const_view_unpack_bool.rst rename to src/libbson/doc/bson_vector_packed_bit_const_view_unpack_bool.rst index 41593315c4a..c459e56e4a9 100644 --- a/src/libbson/doc/bson_vector_packed_bits_const_view_unpack_bool.rst +++ b/src/libbson/doc/bson_vector_packed_bit_const_view_unpack_bool.rst @@ -1,9 +1,9 @@ -:man_page: bson_vector_packed_bits_const_view_unpack_bool +:man_page: bson_vector_packed_bit_const_view_unpack_bool -bson_vector_packed_bits_const_view_unpack_bool() -================================================ +bson_vector_packed_bit_const_view_unpack_bool() +=============================================== -Unpack a contiguous block of elements from a :symbol:`bson_vector_packed_bits_const_view_t` into a C array of ``bool``. +Unpack a contiguous block of elements from a :symbol:`bson_vector_packed_bit_const_view_t` into a C array of ``bool``. Synopsis -------- @@ -11,15 +11,15 @@ Synopsis .. code-block:: c bool - bson_vector_packed_bits_const_view_unpack_bool (bson_vector_packed_bits_const_view_t view, - bool *unpacked_values_out, - size_t element_count, - size_t vector_offset_elements); + bson_vector_packed_bit_const_view_unpack_bool (bson_vector_packed_bit_const_view_t view, + bool *unpacked_values_out, + size_t element_count, + size_t vector_offset_elements); Parameters ---------- -* ``view``: A valid :symbol:`bson_vector_packed_bits_const_view_t`. +* ``view``: A valid :symbol:`bson_vector_packed_bit_const_view_t`. * ``unpacked_values_out``: Location where the ``bool`` elements will be unpacked to. * ``element_count``: Number of elements to unpack. * ``vector_offset_elements``: The vector index of the first element to unpack. @@ -38,4 +38,4 @@ On success, returns true and unpacks ``element_count`` elements into ``*unpacked .. seealso:: - | :symbol:`bson_vector_packed_bits_view_unpack_bool` + | :symbol:`bson_vector_packed_bit_view_unpack_bool` diff --git a/src/libbson/doc/bson_vector_packed_bit_view_as_const.rst b/src/libbson/doc/bson_vector_packed_bit_view_as_const.rst new file mode 100644 index 00000000000..bd10d7ec633 --- /dev/null +++ b/src/libbson/doc/bson_vector_packed_bit_view_as_const.rst @@ -0,0 +1,29 @@ +:man_page: bson_vector_packed_bit_view_as_const + +bson_vector_packed_bit_view_as_const() +====================================== + +Convert a :symbol:`bson_vector_packed_bit_view_t` into a :symbol:`bson_vector_packed_bit_const_view_t`. + +Synopsis +-------- + +.. code-block:: c + + bson_vector_packed_bit_const_view_t + bson_vector_packed_bit_view_as_const (bson_vector_packed_bit_view_t view); + +Parameters +---------- + +* ``view``: A valid :symbol:`bson_vector_packed_bit_view_t`. + +Description +----------- + +This adds a ``const`` qualifier to the view without re-validating the underlying data. + +Returns +------- + +Always returns a :symbol:`bson_vector_packed_bit_const_view_t`. diff --git a/src/libbson/doc/bson_vector_packed_bit_view_from_iter.rst b/src/libbson/doc/bson_vector_packed_bit_view_from_iter.rst new file mode 100644 index 00000000000..05d40ad8e4e --- /dev/null +++ b/src/libbson/doc/bson_vector_packed_bit_view_from_iter.rst @@ -0,0 +1,33 @@ +:man_page: bson_vector_packed_bit_view_from_iter + +bson_vector_packed_bit_view_from_iter() +======================================= + +Initialize a :symbol:`bson_vector_packed_bit_view_t` from a :symbol:`bson_iter_t` pointing to a valid Vector of ``packed_bit`` element type. + +Synopsis +-------- + +.. code-block:: c + + bool + bson_vector_packed_bit_view_from_iter (bson_vector_packed_bit_view_t *view_out, + bson_iter_t *iter); + +Parameters +---------- + +* ``view_out``: A :symbol:`bson_vector_packed_bit_view_t` is written here on success. +* ``iter``: A valid :symbol:`bson_iter_t`. + +Description +----------- + +The provided iterator, which must point to some kind of BSON item, will be checked for a valid Vector of ``packed_bit`` element type. +On success, a :symbol:`bson_vector_packed_bit_view_t` is set to point to the same underlying :symbol:`bson_t` buffer as the provided :symbol:`bson_iter_t`. +The view will only be valid until the containing document is destroyed or otherwise modified. + +Returns +------- + +Returns true if the view was successfully initialized. diff --git a/src/libbson/doc/bson_vector_packed_bit_view_init.rst b/src/libbson/doc/bson_vector_packed_bit_view_init.rst new file mode 100644 index 00000000000..e3aaf5838e3 --- /dev/null +++ b/src/libbson/doc/bson_vector_packed_bit_view_init.rst @@ -0,0 +1,35 @@ +:man_page: bson_vector_packed_bit_view_init + +bson_vector_packed_bit_view_init() +================================== + +Initialize a :symbol:`bson_vector_packed_bit_view_t` from a mutable ``uint8_t`` buffer. + +Synopsis +-------- + +.. code-block:: c + + bool + bson_vector_packed_bit_view_init (bson_vector_packed_bit_view_t *view_out, + uint8_t *binary_data, + uint32_t binary_data_len); + +Parameters +---------- + +* ``view_out``: A :symbol:`bson_vector_packed_bit_view_t` is written here on success. +* ``binary_data``: A pointer to the BSON Binary data block to be validated. +* ``binary_data_len``: Length of the binary data block, in bytes. + +Description +----------- + +The length, header, and trailing padding of the provided binary data block will be checked for a valid Vector of ``packed_bit`` element type. +On success, the pointer and length are packaged as a :symbol:`bson_vector_packed_bit_view_t` written to ``*view_out``. +The view will only be valid as long as ``binary_data`` is valid. + +Returns +------- + +Returns true if the view was successfully initialized. diff --git a/src/libbson/doc/bson_vector_packed_bit_view_length.rst b/src/libbson/doc/bson_vector_packed_bit_view_length.rst new file mode 100644 index 00000000000..fde82ffde56 --- /dev/null +++ b/src/libbson/doc/bson_vector_packed_bit_view_length.rst @@ -0,0 +1,29 @@ +:man_page: bson_vector_packed_bit_view_length + +bson_vector_packed_bit_view_length() +==================================== + +Return the number of elements in a Vector referenced by a :symbol:`bson_vector_packed_bit_view_t`. + +Synopsis +-------- + +.. code-block:: c + + size_t + bson_vector_packed_bit_view_length (bson_vector_packed_bit_view_t view); + +Parameters +---------- + +* ``view``: A valid :symbol:`bson_vector_packed_bit_view_t`. + +Description +----------- + +An element count is calculated from information stored inside the `bson_vector_packed_bit_view_t` value. + +Returns +------- + +The number of elements, as a ``size_t``. diff --git a/src/libbson/doc/bson_vector_packed_bits_view_length_bytes.rst b/src/libbson/doc/bson_vector_packed_bit_view_length_bytes.rst similarity index 55% rename from src/libbson/doc/bson_vector_packed_bits_view_length_bytes.rst rename to src/libbson/doc/bson_vector_packed_bit_view_length_bytes.rst index c800d5ecd4d..7659f2e90ee 100644 --- a/src/libbson/doc/bson_vector_packed_bits_view_length_bytes.rst +++ b/src/libbson/doc/bson_vector_packed_bit_view_length_bytes.rst @@ -1,9 +1,9 @@ -:man_page: bson_vector_packed_bits_view_length_bytes +:man_page: bson_vector_packed_bit_view_length_bytes -bson_vector_packed_bits_view_length_bytes() -=========================================== +bson_vector_packed_bit_view_length_bytes() +========================================== -Return the number of packed bytes in a Vector referenced by a :symbol:`bson_vector_packed_bits_view_t`. +Return the number of packed bytes in a Vector referenced by a :symbol:`bson_vector_packed_bit_view_t`. Synopsis -------- @@ -11,12 +11,12 @@ Synopsis .. code-block:: c size_t - bson_vector_packed_bits_view_length_bytes (bson_vector_packed_bits_view_t view); + bson_vector_packed_bit_view_length_bytes (bson_vector_packed_bit_view_t view); Parameters ---------- -* ``view``: A valid :symbol:`bson_vector_packed_bits_view_t`. +* ``view``: A valid :symbol:`bson_vector_packed_bit_view_t`. Description ----------- diff --git a/src/libbson/doc/bson_vector_packed_bits_view_pack_bool.rst b/src/libbson/doc/bson_vector_packed_bit_view_pack_bool.rst similarity index 60% rename from src/libbson/doc/bson_vector_packed_bits_view_pack_bool.rst rename to src/libbson/doc/bson_vector_packed_bit_view_pack_bool.rst index 6310debd928..4f94b65ab8e 100644 --- a/src/libbson/doc/bson_vector_packed_bits_view_pack_bool.rst +++ b/src/libbson/doc/bson_vector_packed_bit_view_pack_bool.rst @@ -1,9 +1,9 @@ -:man_page: bson_vector_packed_bits_view_pack_bool +:man_page: bson_vector_packed_bit_view_pack_bool -bson_vector_packed_bits_view_pack_bool() -======================================== +bson_vector_packed_bit_view_pack_bool() +======================================= -Pack a contiguous block of elements from a C ``bool`` array into a :symbol:`bson_vector_packed_bits_view_t`. +Pack a contiguous block of elements from a C ``bool`` array into a :symbol:`bson_vector_packed_bit_view_t`. Synopsis -------- @@ -11,15 +11,15 @@ Synopsis .. code-block:: c bool - bson_vector_packed_bits_view_pack_bool (bson_vector_packed_bits_view_t view, - const bool *unpacked_values, - size_t element_count, - size_t vector_offset_elements) + bson_vector_packed_bit_view_pack_bool (bson_vector_packed_bit_view_t view, + const bool *unpacked_values, + size_t element_count, + size_t vector_offset_elements) Parameters ---------- -* ``view``: A valid :symbol:`bson_vector_packed_bits_view_t`. +* ``view``: A valid :symbol:`bson_vector_packed_bit_view_t`. * ``unpacked_values``: Location where the ``bool`` elements will be packed from. * ``element_count``: Number of elements to pack. * ``vector_offset_elements``: The vector index of the first element to pack. diff --git a/src/libbson/doc/bson_vector_packed_bits_view_padding.rst b/src/libbson/doc/bson_vector_packed_bit_view_padding.rst similarity index 55% rename from src/libbson/doc/bson_vector_packed_bits_view_padding.rst rename to src/libbson/doc/bson_vector_packed_bit_view_padding.rst index 0caf28ec6b2..c240602ec83 100644 --- a/src/libbson/doc/bson_vector_packed_bits_view_padding.rst +++ b/src/libbson/doc/bson_vector_packed_bit_view_padding.rst @@ -1,9 +1,9 @@ -:man_page: bson_vector_packed_bits_view_padding +:man_page: bson_vector_packed_bit_view_padding -bson_vector_packed_bits_view_padding() -====================================== +bson_vector_packed_bit_view_padding() +===================================== -Returns the number of unused bits in a Vector referenced by a :symbol:`bson_vector_packed_bits_view_t`. +Returns the number of unused bits in a Vector referenced by a :symbol:`bson_vector_packed_bit_view_t`. Synopsis -------- @@ -11,12 +11,12 @@ Synopsis .. code-block:: c size_t - bson_vector_packed_bits_view_padding (bson_vector_packed_bits_view_t view); + bson_vector_packed_bit_view_padding (bson_vector_packed_bit_view_t view); Parameters ---------- -* ``view``: A valid :symbol:`bson_vector_packed_bits_view_t`. +* ``view``: A valid :symbol:`bson_vector_packed_bit_view_t`. Description ----------- @@ -31,4 +31,4 @@ Vector validation guarantees that empty Vectors have a ``padding`` of 0. .. seealso:: - | :symbol:`bson_vector_packed_bits_const_view_padding` + | :symbol:`bson_vector_packed_bit_const_view_padding` diff --git a/src/libbson/doc/bson_vector_packed_bits_view_read_packed.rst b/src/libbson/doc/bson_vector_packed_bit_view_read_packed.rst similarity index 59% rename from src/libbson/doc/bson_vector_packed_bits_view_read_packed.rst rename to src/libbson/doc/bson_vector_packed_bit_view_read_packed.rst index 0b6f2d93598..8bb9ea6b046 100644 --- a/src/libbson/doc/bson_vector_packed_bits_view_read_packed.rst +++ b/src/libbson/doc/bson_vector_packed_bit_view_read_packed.rst @@ -1,9 +1,9 @@ -:man_page: bson_vector_packed_bits_view_read_packed +:man_page: bson_vector_packed_bit_view_read_packed -bson_vector_packed_bits_view_read_packed() -=========================================== +bson_vector_packed_bit_view_read_packed() +========================================= -Copy a contiguous block of packed bytes out of a :symbol:`bson_vector_packed_bits_view_t`. +Copy a contiguous block of packed bytes out of a :symbol:`bson_vector_packed_bit_view_t`. Synopsis -------- @@ -11,15 +11,15 @@ Synopsis .. code-block:: c bool - bson_vector_packed_bits_view_read_packed (bson_vector_packed_bits_view_t view, - uint8_t *packed_values_out, - size_t byte_count, - size_t vector_offset_bytes); + bson_vector_packed_bit_view_read_packed (bson_vector_packed_bit_view_t view, + uint8_t *packed_values_out, + size_t byte_count, + size_t vector_offset_bytes); Parameters ---------- -* ``view``: A valid :symbol:`bson_vector_packed_bits_view_t`. +* ``view``: A valid :symbol:`bson_vector_packed_bit_view_t`. * ``packed_values_out``: Location where the packed bytes will be read to. * ``byte_count``: Number of bytes to read. * ``vector_offset_bytes``: The byte index of the first packed byte to read. @@ -41,5 +41,5 @@ On success, returns true and reads ``byte_count`` bytes into ``*packed_values_ou .. seealso:: - | :symbol:`bson_vector_packed_bits_const_view_read_packed` - | :symbol:`bson_vector_packed_bits_view_write_packed` + | :symbol:`bson_vector_packed_bit_const_view_read_packed` + | :symbol:`bson_vector_packed_bit_view_write_packed` diff --git a/src/libbson/doc/bson_vector_packed_bit_view_t.rst b/src/libbson/doc/bson_vector_packed_bit_view_t.rst new file mode 100644 index 00000000000..601521b371a --- /dev/null +++ b/src/libbson/doc/bson_vector_packed_bit_view_t.rst @@ -0,0 +1,85 @@ +:man_page: bson_vector_packed_bit_view_t + +bson_vector_packed_bit_view_t +============================= + +A reference to mutable non-owned BSON Binary data holding a valid Vector of ``packed_bit`` element type. + +Synopsis +-------- + +.. code-block:: c + + #include + + typedef struct bson_vector_packed_bit_view_t { + /*< private >*/ + } bson_vector_packed_bit_view_t; + +Description +----------- + +:symbol:`bson_vector_packed_bit_view_t` is a structure that acts as an opaque reference to a block of memory that has been validated as a ``packed_bit`` vector. + +It is meant to be passed by value and can be discarded at any time. The contents of the structure should be considered private. + +The :symbol:`bson_t` *MUST* be valid for the lifetime of the view and it is an error to modify the :symbol:`bson_t` while using the view. + +.. only:: html + + Functions + --------- + + .. toctree:: + :titlesonly: + :maxdepth: 1 + + bson_vector_packed_bit_view_init + bson_vector_packed_bit_view_from_iter + bson_vector_packed_bit_view_as_const + bson_vector_packed_bit_view_length + bson_vector_packed_bit_view_length_bytes + bson_vector_packed_bit_view_padding + bson_vector_packed_bit_view_read_packed + bson_vector_packed_bit_view_write_packed + bson_vector_packed_bit_view_unpack_bool + bson_vector_packed_bit_view_pack_bool + +Example +------- + +.. code-block:: c + + // Fill a new vector with individual boolean elements + { + static const bool bool_values[] = {true, false, true, true, false}; + const size_t bool_values_count = sizeof bool_values / sizeof bool_values[0]; + + bson_vector_packed_bit_view_t view; + BSON_ASSERT (BSON_APPEND_VECTOR_PACKED_BIT (&doc, "from_bool", bool_values_count, &view)); + BSON_ASSERT (bson_vector_packed_bit_view_pack_bool (view, bool_values, bool_values_count, 0)); + } + + // Fill another new vector with packed bytes + { + static const uint8_t packed_bytes[] = {0xb0}; + const size_t unused_bits_count = 3; + const size_t packed_values_count = sizeof packed_bytes * 8 - unused_bits_count; + + bson_vector_packed_bit_view_t view; + BSON_ASSERT (BSON_APPEND_VECTOR_PACKED_BIT (&doc, "from_packed", packed_values_count, &view)); + BSON_ASSERT (bson_vector_packed_bit_view_write_packed (view, packed_bytes, sizeof packed_bytes, 0)); + } + + // Compare both vectors. They match exactly. + { + bson_iter_t from_bool_iter, from_packed_iter; + BSON_ASSERT (bson_iter_init_find (&from_bool_iter, &doc, "from_bool")); + BSON_ASSERT (bson_iter_init_find (&from_packed_iter, &doc, "from_packed")); + BSON_ASSERT (bson_iter_binary_equal (&from_bool_iter, &from_packed_iter)); + } + +.. seealso:: + + | :symbol:`bson_append_vector_packed_bit` + | :symbol:`bson_vector_packed_bit_const_view_t` diff --git a/src/libbson/doc/bson_vector_packed_bits_view_unpack_bool.rst b/src/libbson/doc/bson_vector_packed_bit_view_unpack_bool.rst similarity index 56% rename from src/libbson/doc/bson_vector_packed_bits_view_unpack_bool.rst rename to src/libbson/doc/bson_vector_packed_bit_view_unpack_bool.rst index 80c733d12f2..62339ecd5ec 100644 --- a/src/libbson/doc/bson_vector_packed_bits_view_unpack_bool.rst +++ b/src/libbson/doc/bson_vector_packed_bit_view_unpack_bool.rst @@ -1,9 +1,9 @@ -:man_page: bson_vector_packed_bits_view_unpack_bool +:man_page: bson_vector_packed_bit_view_unpack_bool -bson_vector_packed_bits_view_unpack_bool() -================================================ +bson_vector_packed_bit_view_unpack_bool() +========================================= -Unpack a contiguous block of elements from a :symbol:`bson_vector_packed_bits_view_t` into a C array of ``bool``. +Unpack a contiguous block of elements from a :symbol:`bson_vector_packed_bit_view_t` into a C array of ``bool``. Synopsis -------- @@ -11,15 +11,15 @@ Synopsis .. code-block:: c bool - bson_vector_packed_bits_view_unpack_bool (bson_vector_packed_bits_view_t view, - bool *unpacked_values_out, - size_t element_count, - size_t vector_offset_elements); + bson_vector_packed_bit_view_unpack_bool (bson_vector_packed_bit_view_t view, + bool *unpacked_values_out, + size_t element_count, + size_t vector_offset_elements); Parameters ---------- -* ``view``: A valid :symbol:`bson_vector_packed_bits_view_t`. +* ``view``: A valid :symbol:`bson_vector_packed_bit_view_t`. * ``unpacked_values_out``: Location where the ``bool`` elements will be unpacked to. * ``element_count``: Number of elements to unpack. * ``vector_offset_elements``: The vector index of the first element to unpack. @@ -38,4 +38,4 @@ On success, returns true and unpacks ``element_count`` elements into ``*unpacked .. seealso:: - | :symbol:`bson_vector_packed_bits_const_view_unpack_bool` + | :symbol:`bson_vector_packed_bit_const_view_unpack_bool` diff --git a/src/libbson/doc/bson_vector_packed_bits_view_write_packed.rst b/src/libbson/doc/bson_vector_packed_bit_view_write_packed.rst similarity index 61% rename from src/libbson/doc/bson_vector_packed_bits_view_write_packed.rst rename to src/libbson/doc/bson_vector_packed_bit_view_write_packed.rst index 684836dbc3c..7b0f1174039 100644 --- a/src/libbson/doc/bson_vector_packed_bits_view_write_packed.rst +++ b/src/libbson/doc/bson_vector_packed_bit_view_write_packed.rst @@ -1,9 +1,9 @@ -:man_page: bson_vector_packed_bits_view_write_packed +:man_page: bson_vector_packed_bit_view_write_packed -bson_vector_packed_bits_view_write_packed() -=========================================== +bson_vector_packed_bit_view_write_packed() +========================================== -Copy a contiguous block of packed bytes into a :symbol:`bson_vector_packed_bits_view_t`. +Copy a contiguous block of packed bytes into a :symbol:`bson_vector_packed_bit_view_t`. Synopsis -------- @@ -11,15 +11,15 @@ Synopsis .. code-block:: c bool - bson_vector_packed_bits_view_write_packed (bson_vector_packed_bits_view_t view, - const uint8_t *packed_values, - size_t byte_count, - size_t vector_offset_bytes); + bson_vector_packed_bit_view_write_packed (bson_vector_packed_bit_view_t view, + const uint8_t *packed_values, + size_t byte_count, + size_t vector_offset_bytes); Parameters ---------- -* ``view``: A valid :symbol:`bson_vector_packed_bits_view_t`. +* ``view``: A valid :symbol:`bson_vector_packed_bit_view_t`. * ``packed_values``: Location where the packed bytes will be copied from. * ``byte_count``: Number of bytes to write. * ``vector_offset_bytes``: The byte index of the first packed byte to write. @@ -41,5 +41,5 @@ On success, returns true and writes ``byte_count`` bytes from ``*packed_values`` .. seealso:: - | :symbol:`bson_vector_packed_bits_view_read_packed` - | :symbol:`bson_vector_packed_bits_const_view_read_packed` + | :symbol:`bson_vector_packed_bit_view_read_packed` + | :symbol:`bson_vector_packed_bit_const_view_read_packed` diff --git a/src/libbson/doc/bson_vector_packed_bits_const_view_from_iter.rst b/src/libbson/doc/bson_vector_packed_bits_const_view_from_iter.rst deleted file mode 100644 index 9187fc96073..00000000000 --- a/src/libbson/doc/bson_vector_packed_bits_const_view_from_iter.rst +++ /dev/null @@ -1,37 +0,0 @@ -:man_page: bson_vector_packed_bits_const_view_from_iter - -bson_vector_packed_bits_const_view_from_iter() -============================================== - -Initialize a :symbol:`bson_vector_packed_bits_const_view_t` from a :symbol:`bson_iter_t` pointing to a valid Vector of ``packed_bits`` element type. - -Synopsis --------- - -.. code-block:: c - - bool - bson_vector_packed_bits_const_view_from_iter (bson_vector_packed_bits_const_view_t *view_out, - const bson_iter_t *iter); - -Parameters ----------- - -* ``view_out``: A :symbol:`bson_vector_packed_bits_const_view_t` is written here on success. -* ``iter``: A valid :symbol:`bson_iter_t`. - -Description ------------ - -The provided iterator, which must point to some kind of BSON item, will be checked for a valid Vector of ``packed_bits`` element type. -On success, a :symbol:`bson_vector_packed_bits_const_view_t` is set to point to the same underlying :symbol:`bson_t` buffer as the provided :symbol:`bson_iter_t`. -The view will only be valid until the containing document is destroyed or modified. - -Returns -------- - -Returns true if the view was successfully initialized. - -.. seealso:: - - | :symbol:`bson_vector_packed_bits_view_from_iter` diff --git a/src/libbson/doc/bson_vector_packed_bits_const_view_init.rst b/src/libbson/doc/bson_vector_packed_bits_const_view_init.rst deleted file mode 100644 index 80ce23120fd..00000000000 --- a/src/libbson/doc/bson_vector_packed_bits_const_view_init.rst +++ /dev/null @@ -1,39 +0,0 @@ -:man_page: bson_vector_packed_bits_const_view_init - -bson_vector_packed_bits_const_view_init() -========================================= - -Initialize a :symbol:`bson_vector_packed_bits_const_view_t` from a const ``uint8_t`` buffer. - -Synopsis --------- - -.. code-block:: c - - bool - bson_vector_packed_bits_const_view_init (bson_vector_packed_bits_const_view_t *view_out, - const uint8_t *binary_data, - uint32_t binary_data_len); - -Parameters ----------- - -* ``view_out``: A :symbol:`bson_vector_packed_bits_const_view_t` is written here on success. -* ``binary_data``: A pointer to the BSON Binary data block to be validated. -* ``binary_data_len``: Length of the binary data block, in bytes. - -Description ------------ - -The length, header, and trailing padding of the provided binary data block will be checked for a valid Vector of ``packed_bits`` element type. -On success, the pointer and length are packaged as a :symbol:`bson_vector_packed_bits_const_view_t` written to ``*view_out``. -The view will only be valid as long as ``binary_data`` is valid. - -Returns -------- - -Returns true if the view was successfully initialized. - -.. seealso:: - - | :symbol:`bson_vector_packed_bits_view_init` diff --git a/src/libbson/doc/bson_vector_packed_bits_const_view_length.rst b/src/libbson/doc/bson_vector_packed_bits_const_view_length.rst deleted file mode 100644 index b590894874b..00000000000 --- a/src/libbson/doc/bson_vector_packed_bits_const_view_length.rst +++ /dev/null @@ -1,33 +0,0 @@ -:man_page: bson_vector_packed_bits_const_view_length - -bson_vector_packed_bits_const_view_length() -=========================================== - -Return the number of elements in a Vector referenced by a :symbol:`bson_vector_packed_bits_const_view_t`. - -Synopsis --------- - -.. code-block:: c - - size_t - bson_vector_packed_bits_const_view_length (bson_vector_packed_bits_const_view_t view); - -Parameters ----------- - -* ``view``: A valid :symbol:`bson_vector_packed_bits_const_view_t`. - -Description ------------ - -An element count is calculated from information stored inside the `bson_vector_packed_bits_const_view_t` value. - -Returns -------- - -The number of elements, as a ``size_t``. - -.. seealso:: - - | :symbol:`bson_vector_packed_bits_view_length` diff --git a/src/libbson/doc/bson_vector_packed_bits_const_view_length_bytes.rst b/src/libbson/doc/bson_vector_packed_bits_const_view_length_bytes.rst deleted file mode 100644 index 0a9d5db6ae0..00000000000 --- a/src/libbson/doc/bson_vector_packed_bits_const_view_length_bytes.rst +++ /dev/null @@ -1,34 +0,0 @@ -:man_page: bson_vector_packed_bits_const_view_length_bytes - -bson_vector_packed_bits_const_view_length_bytes() -================================================= - -Return the number of packed bytes in a Vector referenced by a :symbol:`bson_vector_packed_bits_const_view_t`. - -Synopsis --------- - -.. code-block:: c - - size_t - bson_vector_packed_bits_const_view_length_bytes (bson_vector_packed_bits_const_view_t view); - -Parameters ----------- - -* ``view``: A valid :symbol:`bson_vector_packed_bits_const_view_t`. - -Description ------------ - -A byte count is calculated from the view's stored binary block length. -If the element count isn't a multiple of 8, the final byte will include bits that do not belong to any element. - -Returns -------- - -The number of bytes, as a ``size_t``. - -.. seealso:: - - | :symbol:`bson_vector_packed_bits_view_length_bytes` diff --git a/src/libbson/doc/bson_vector_packed_bits_const_view_t.rst b/src/libbson/doc/bson_vector_packed_bits_const_view_t.rst deleted file mode 100644 index 01e72f7ff86..00000000000 --- a/src/libbson/doc/bson_vector_packed_bits_const_view_t.rst +++ /dev/null @@ -1,75 +0,0 @@ -:man_page: bson_vector_packed_bits_const_view_t - -bson_vector_packed_bits_const_view_t -==================================== - -A reference to non-owned const BSON Binary data holding a valid Vector of ``packed_bits`` element type. - -Synopsis --------- - -.. code-block:: c - - #include - - typedef struct bson_vector_packed_bits_const_view_t { - /*< private >*/ - } bson_vector_packed_bits_const_view_t; - -Description ------------ - -:symbol:`bson_vector_packed_bits_const_view_t` is a structure that acts as an opaque const reference to a block of memory that has been validated as a ``packed_bits`` vector. - -It is meant to be passed by value and can be discarded at any time. The contents of the structure should be considered private. - -The :symbol:`bson_t` *MUST* be valid for the lifetime of the view and it is an error to modify the :symbol:`bson_t` while using the view. - -.. only:: html - - Functions - --------- - - .. toctree:: - :titlesonly: - :maxdepth: 1 - - bson_vector_packed_bits_const_view_init - bson_vector_packed_bits_const_view_from_iter - bson_vector_packed_bits_const_view_length - bson_vector_packed_bits_const_view_length_bytes - bson_vector_packed_bits_const_view_padding - bson_vector_packed_bits_const_view_read_packed - bson_vector_packed_bits_const_view_unpack_bool - -Example -------- - -.. code-block:: c - - bson_iter_t iter; - bson_vector_packed_bits_const_view_t view; - - if (bson_iter_init_find (&iter, &doc, "vector") && bson_vector_packed_bits_const_view_from_iter (&view, &iter)) { - size_t length = bson_vector_packed_bits_const_view_length (view); - size_t length_bytes = bson_vector_packed_bits_const_view_length_bytes (view); - size_t padding = bson_vector_packed_bits_const_view_padding (view); - - printf ("Elements in 'vector':\n"); - for (size_t i = 0; i < length; i++) { - bool element; - BSON_ASSERT (bson_vector_packed_bits_const_view_unpack_bool (view, &element, 1, i)); - printf (" elements[%d] = %d\n", (int) i, (int) element); - } - - printf ("Bytes in 'vector': (%d bits unused)\n", (int) padding); - for (size_t i = 0; i < length_bytes; i++) { - uint8_t packed_byte; - BSON_ASSERT (bson_vector_packed_bits_const_view_read_packed (view, &packed_byte, 1, i)); - printf (" bytes[%d] = 0x%02x\n", (int) i, (unsigned) packed_byte); - } - } - -.. seealso:: - - | :symbol:`bson_vector_packed_bits_view_t` diff --git a/src/libbson/doc/bson_vector_packed_bits_view_as_const.rst b/src/libbson/doc/bson_vector_packed_bits_view_as_const.rst deleted file mode 100644 index 369fe9c97c6..00000000000 --- a/src/libbson/doc/bson_vector_packed_bits_view_as_const.rst +++ /dev/null @@ -1,29 +0,0 @@ -:man_page: bson_vector_packed_bits_view_as_const - -bson_vector_packed_bits_view_as_const() -======================================= - -Convert a :symbol:`bson_vector_packed_bits_view_t` into a :symbol:`bson_vector_packed_bits_const_view_t`. - -Synopsis --------- - -.. code-block:: c - - bson_vector_packed_bits_const_view_t - bson_vector_packed_bits_view_as_const (bson_vector_packed_bits_view_t view); - -Parameters ----------- - -* ``view``: A valid :symbol:`bson_vector_packed_bits_view_t`. - -Description ------------ - -This adds a ``const`` qualifier to the view without re-validating the underlying data. - -Returns -------- - -Always returns a :symbol:`bson_vector_packed_bits_const_view_t`. diff --git a/src/libbson/doc/bson_vector_packed_bits_view_from_iter.rst b/src/libbson/doc/bson_vector_packed_bits_view_from_iter.rst deleted file mode 100644 index be8c88f4e3d..00000000000 --- a/src/libbson/doc/bson_vector_packed_bits_view_from_iter.rst +++ /dev/null @@ -1,33 +0,0 @@ -:man_page: bson_vector_packed_bits_view_from_iter - -bson_vector_packed_bits_view_from_iter() -======================================== - -Initialize a :symbol:`bson_vector_packed_bits_view_t` from a :symbol:`bson_iter_t` pointing to a valid Vector of ``packed_bits`` element type. - -Synopsis --------- - -.. code-block:: c - - bool - bson_vector_packed_bits_view_from_iter (bson_vector_packed_bits_view_t *view_out, - bson_iter_t *iter); - -Parameters ----------- - -* ``view_out``: A :symbol:`bson_vector_packed_bits_view_t` is written here on success. -* ``iter``: A valid :symbol:`bson_iter_t`. - -Description ------------ - -The provided iterator, which must point to some kind of BSON item, will be checked for a valid Vector of ``packed_bits`` element type. -On success, a :symbol:`bson_vector_packed_bits_view_t` is set to point to the same underlying :symbol:`bson_t` buffer as the provided :symbol:`bson_iter_t`. -The view will only be valid until the containing document is destroyed or otherwise modified. - -Returns -------- - -Returns true if the view was successfully initialized. diff --git a/src/libbson/doc/bson_vector_packed_bits_view_init.rst b/src/libbson/doc/bson_vector_packed_bits_view_init.rst deleted file mode 100644 index b2c2622e08a..00000000000 --- a/src/libbson/doc/bson_vector_packed_bits_view_init.rst +++ /dev/null @@ -1,35 +0,0 @@ -:man_page: bson_vector_packed_bits_view_init - -bson_vector_packed_bits_view_init() -=================================== - -Initialize a :symbol:`bson_vector_packed_bits_view_t` from a mutable ``uint8_t`` buffer. - -Synopsis --------- - -.. code-block:: c - - bool - bson_vector_packed_bits_view_init (bson_vector_packed_bits_view_t *view_out, - uint8_t *binary_data, - uint32_t binary_data_len); - -Parameters ----------- - -* ``view_out``: A :symbol:`bson_vector_packed_bits_view_t` is written here on success. -* ``binary_data``: A pointer to the BSON Binary data block to be validated. -* ``binary_data_len``: Length of the binary data block, in bytes. - -Description ------------ - -The length, header, and trailing padding of the provided binary data block will be checked for a valid Vector of ``packed_bits`` element type. -On success, the pointer and length are packaged as a :symbol:`bson_vector_packed_bits_view_t` written to ``*view_out``. -The view will only be valid as long as ``binary_data`` is valid. - -Returns -------- - -Returns true if the view was successfully initialized. diff --git a/src/libbson/doc/bson_vector_packed_bits_view_length.rst b/src/libbson/doc/bson_vector_packed_bits_view_length.rst deleted file mode 100644 index 4f89f1b68c5..00000000000 --- a/src/libbson/doc/bson_vector_packed_bits_view_length.rst +++ /dev/null @@ -1,29 +0,0 @@ -:man_page: bson_vector_packed_bits_view_length - -bson_vector_packed_bits_view_length() -===================================== - -Return the number of elements in a Vector referenced by a :symbol:`bson_vector_packed_bits_view_t`. - -Synopsis --------- - -.. code-block:: c - - size_t - bson_vector_packed_bits_view_length (bson_vector_packed_bits_view_t view); - -Parameters ----------- - -* ``view``: A valid :symbol:`bson_vector_packed_bits_view_t`. - -Description ------------ - -An element count is calculated from information stored inside the `bson_vector_packed_bits_view_t` value. - -Returns -------- - -The number of elements, as a ``size_t``. diff --git a/src/libbson/doc/bson_vector_packed_bits_view_t.rst b/src/libbson/doc/bson_vector_packed_bits_view_t.rst deleted file mode 100644 index b9bc576279f..00000000000 --- a/src/libbson/doc/bson_vector_packed_bits_view_t.rst +++ /dev/null @@ -1,85 +0,0 @@ -:man_page: bson_vector_packed_bits_view_t - -bson_vector_packed_bits_view_t -============================== - -A reference to mutable non-owned BSON Binary data holding a valid Vector of ``packed_bits`` element type. - -Synopsis --------- - -.. code-block:: c - - #include - - typedef struct bson_vector_packed_bits_view_t { - /*< private >*/ - } bson_vector_packed_bits_view_t; - -Description ------------ - -:symbol:`bson_vector_packed_bits_view_t` is a structure that acts as an opaque reference to a block of memory that has been validated as a ``packed_bits`` vector. - -It is meant to be passed by value and can be discarded at any time. The contents of the structure should be considered private. - -The :symbol:`bson_t` *MUST* be valid for the lifetime of the view and it is an error to modify the :symbol:`bson_t` while using the view. - -.. only:: html - - Functions - --------- - - .. toctree:: - :titlesonly: - :maxdepth: 1 - - bson_vector_packed_bits_view_init - bson_vector_packed_bits_view_from_iter - bson_vector_packed_bits_view_as_const - bson_vector_packed_bits_view_length - bson_vector_packed_bits_view_length_bytes - bson_vector_packed_bits_view_padding - bson_vector_packed_bits_view_read_packed - bson_vector_packed_bits_view_write_packed - bson_vector_packed_bits_view_unpack_bool - bson_vector_packed_bits_view_pack_bool - -Example -------- - -.. code-block:: c - - // Fill a new vector with individual boolean elements - { - static const bool bool_values[] = {true, false, true, true, false}; - const size_t bool_values_count = sizeof bool_values / sizeof bool_values[0]; - - bson_vector_packed_bits_view_t view; - BSON_ASSERT (BSON_APPEND_VECTOR_PACKED_BITS (&doc, "from_bool", bool_values_count, &view)); - BSON_ASSERT (bson_vector_packed_bits_view_pack_bool (view, bool_values, bool_values_count, 0)); - } - - // Fill another new vector with packed bytes - { - static const uint8_t packed_bytes[] = {0xb0}; - const size_t unused_bits_count = 3; - const size_t packed_values_count = sizeof packed_bytes * 8 - unused_bits_count; - - bson_vector_packed_bits_view_t view; - BSON_ASSERT (BSON_APPEND_VECTOR_PACKED_BITS (&doc, "from_packed", packed_values_count, &view)); - BSON_ASSERT (bson_vector_packed_bits_view_write_packed (view, packed_bytes, sizeof packed_bytes, 0)); - } - - // Compare both vectors. They match exactly. - { - bson_iter_t from_bool_iter, from_packed_iter; - BSON_ASSERT (bson_iter_init_find (&from_bool_iter, &doc, "from_bool")); - BSON_ASSERT (bson_iter_init_find (&from_packed_iter, &doc, "from_packed")); - BSON_ASSERT (bson_iter_binary_equal (&from_bool_iter, &from_packed_iter)); - } - -.. seealso:: - - | :symbol:`bson_append_vector_packed_bits` - | :symbol:`bson_vector_packed_bits_const_view_t` diff --git a/src/libbson/src/bson/bson-iter.h b/src/libbson/src/bson/bson-iter.h index 746a2f0c76a..65b74594979 100644 --- a/src/libbson/src/bson/bson-iter.h +++ b/src/libbson/src/bson/bson-iter.h @@ -47,7 +47,7 @@ BSON_BEGIN_DECLS #define BSON_ITER_HOLDS_VECTOR_FLOAT32(iter) (bson_vector_float32_const_view_from_iter (NULL, iter)) -#define BSON_ITER_HOLDS_VECTOR_PACKED_BITS(iter) (bson_vector_packed_bits_const_view_from_iter (NULL, iter)) +#define BSON_ITER_HOLDS_VECTOR_PACKED_BIT(iter) (bson_vector_packed_bit_const_view_from_iter (NULL, iter)) #define BSON_ITER_HOLDS_UNDEFINED(iter) (bson_iter_type ((iter)) == BSON_TYPE_UNDEFINED) diff --git a/src/libbson/src/bson/bson-vector.c b/src/libbson/src/bson/bson-vector.c index 733b3f9b94d..a1d67be5a44 100644 --- a/src/libbson/src/bson/bson-vector.c +++ b/src/libbson/src/bson/bson-vector.c @@ -48,9 +48,9 @@ bson_vector_float32_validate (bson_vector_binary_header_impl_t header, uint32_t } static BSON_INLINE bool -bson_vector_packed_bits_validate (bson_vector_binary_header_impl_t header, - const uint8_t *binary_data, - uint32_t binary_data_len) +bson_vector_packed_bit_validate (bson_vector_binary_header_impl_t header, + const uint8_t *binary_data, + uint32_t binary_data_len) { if (header.bytes[0] == bson_vector_header_byte_0 (BSON_VECTOR_ELEMENT_UNSIGNED_INT, BSON_VECTOR_ELEMENT_1_BIT)) { size_t padding = bson_vector_padding_from_header_byte_1 (header.bytes[1]); @@ -149,17 +149,17 @@ bson_vector_float32_const_view_init (bson_vector_float32_const_view_t *view_out, } bool -bson_vector_packed_bits_view_init (bson_vector_packed_bits_view_t *view_out, - uint8_t *binary_data, - uint32_t binary_data_len) +bson_vector_packed_bit_view_init (bson_vector_packed_bit_view_t *view_out, + uint8_t *binary_data, + uint32_t binary_data_len) { BSON_OPTIONAL_PARAM (view_out); BSON_ASSERT_PARAM (binary_data); bson_vector_binary_header_impl_t header; if (bson_vector_binary_header_impl_init (&header, binary_data, binary_data_len) && - bson_vector_packed_bits_validate (header, binary_data, binary_data_len)) { + bson_vector_packed_bit_validate (header, binary_data, binary_data_len)) { if (view_out) { - *view_out = (bson_vector_packed_bits_view_t){ + *view_out = (bson_vector_packed_bit_view_t){ .binary.data = binary_data, .binary.data_len = binary_data_len, .binary.header_copy = header}; } return true; @@ -169,17 +169,17 @@ bson_vector_packed_bits_view_init (bson_vector_packed_bits_view_t *view_out, } bool -bson_vector_packed_bits_const_view_init (bson_vector_packed_bits_const_view_t *view_out, - const uint8_t *binary_data, - uint32_t binary_data_len) +bson_vector_packed_bit_const_view_init (bson_vector_packed_bit_const_view_t *view_out, + const uint8_t *binary_data, + uint32_t binary_data_len) { BSON_OPTIONAL_PARAM (view_out); BSON_ASSERT_PARAM (binary_data); bson_vector_binary_header_impl_t header; if (bson_vector_binary_header_impl_init (&header, binary_data, binary_data_len) && - bson_vector_packed_bits_validate (header, binary_data, binary_data_len)) { + bson_vector_packed_bit_validate (header, binary_data, binary_data_len)) { if (view_out) { - *view_out = (bson_vector_packed_bits_const_view_t){ + *view_out = (bson_vector_packed_bit_const_view_t){ .binary.data = binary_data, .binary.data_len = binary_data_len, .binary.header_copy = header}; } return true; @@ -254,7 +254,7 @@ bson_vector_float32_const_view_from_iter (bson_vector_float32_const_view_t *view } bool -bson_vector_packed_bits_view_from_iter (bson_vector_packed_bits_view_t *view_out, bson_iter_t *iter) +bson_vector_packed_bit_view_from_iter (bson_vector_packed_bit_view_t *view_out, bson_iter_t *iter) { BSON_OPTIONAL_PARAM (view_out); BSON_ASSERT_PARAM (iter); @@ -262,14 +262,14 @@ bson_vector_packed_bits_view_from_iter (bson_vector_packed_bits_view_t *view_out uint32_t binary_len; uint8_t *binary; bson_iter_overwrite_binary (iter, BSON_SUBTYPE_VECTOR, &binary_len, &binary); - return binary && bson_vector_packed_bits_view_init (view_out, binary, binary_len); + return binary && bson_vector_packed_bit_view_init (view_out, binary, binary_len); } else { return false; } } bool -bson_vector_packed_bits_const_view_from_iter (bson_vector_packed_bits_const_view_t *view_out, const bson_iter_t *iter) +bson_vector_packed_bit_const_view_from_iter (bson_vector_packed_bit_const_view_t *view_out, const bson_iter_t *iter) { BSON_OPTIONAL_PARAM (view_out); BSON_ASSERT_PARAM (iter); @@ -279,7 +279,7 @@ bson_vector_packed_bits_const_view_from_iter (bson_vector_packed_bits_const_view const uint8_t *binary; bson_iter_binary (iter, &subtype, &binary_len, &binary); return binary && subtype == BSON_SUBTYPE_VECTOR && - bson_vector_packed_bits_const_view_init (view_out, binary, binary_len); + bson_vector_packed_bit_const_view_init (view_out, binary, binary_len); } else { return false; } @@ -337,13 +337,13 @@ bson_append_vector_float32 ( } bool -bson_append_vector_packed_bits ( - bson_t *bson, const char *key, int key_length, size_t element_count, bson_vector_packed_bits_view_t *view_out) +bson_append_vector_packed_bit ( + bson_t *bson, const char *key, int key_length, size_t element_count, bson_vector_packed_bit_view_t *view_out) { BSON_ASSERT_PARAM (bson); BSON_ASSERT_PARAM (view_out); - uint32_t length = bson_vector_packed_bits_binary_data_length (element_count); + uint32_t length = bson_vector_packed_bit_binary_data_length (element_count); if (length < BSON_VECTOR_HEADER_LEN) { return false; } @@ -359,7 +359,7 @@ bson_append_vector_packed_bits ( // No reason to read-modify-write here, it's better to write the whole byte. binary[length - 1u] = 0u; } - *view_out = (bson_vector_packed_bits_view_t){ + *view_out = (bson_vector_packed_bit_view_t){ .binary.data = binary, .binary.data_len = length, .binary.header_copy = header}; return true; } else { @@ -488,7 +488,7 @@ bson_append_vector_float32_from_array ( } bool -bson_append_vector_packed_bits_from_array ( +bson_append_vector_packed_bit_from_array ( bson_t *bson, const char *key, int key_length, const bson_iter_t *iter, bson_error_t *error) { BSON_ASSERT_PARAM (bson); @@ -516,7 +516,7 @@ bson_append_vector_packed_bits_from_array ( bson_set_error (error, BSON_ERROR_VECTOR, BSON_VECTOR_ERROR_ARRAY_ELEMENT_VALUE, - "BSON array key '%s' value %" PRId64 " is out of range for vector of packed_bits", + "BSON array key '%s' value %" PRId64 " is out of range for vector of packed_bit", bson_iter_key (&validation_iter), element_as_int64); return false; @@ -525,8 +525,8 @@ bson_append_vector_packed_bits_from_array ( } } - bson_vector_packed_bits_view_t view; - if (!bson_append_vector_packed_bits (bson, key, key_length, element_count, &view)) { + bson_vector_packed_bit_view_t view; + if (!bson_append_vector_packed_bit (bson, key, key_length, element_count, &view)) { bson_vector_set_error_max_size (error); return false; } @@ -534,7 +534,7 @@ bson_append_vector_packed_bits_from_array ( for (size_t i = 0; i < element_count; i++) { BSON_ASSERT (bson_iter_next (©_iter)); bool element_as_bool = (bool) bson_iter_as_int64 (©_iter); - BSON_ASSERT (bson_vector_packed_bits_view_pack_bool (view, &element_as_bool, 1, i)); + BSON_ASSERT (bson_vector_packed_bit_view_pack_bool (view, &element_as_bool, 1, i)); } return true; } @@ -573,14 +573,14 @@ bson_array_builder_append_vector_float32_elements (bson_array_builder_t *builder } bool -bson_array_builder_append_vector_packed_bits_elements (bson_array_builder_t *builder, - bson_vector_packed_bits_const_view_t view) +bson_array_builder_append_vector_packed_bit_elements (bson_array_builder_t *builder, + bson_vector_packed_bit_const_view_t view) { BSON_ASSERT_PARAM (builder); - size_t length = bson_vector_packed_bits_const_view_length (view); + size_t length = bson_vector_packed_bit_const_view_length (view); for (size_t i = 0; i < length; i++) { bool element; - BSON_ASSERT (bson_vector_packed_bits_const_view_unpack_bool (view, &element, 1, i)); + BSON_ASSERT (bson_vector_packed_bit_const_view_unpack_bool (view, &element, 1, i)); if (!bson_array_builder_append_int32 (builder, element ? 1 : 0)) { return false; } @@ -607,9 +607,9 @@ bson_array_builder_append_vector_elements (bson_array_builder_t *builder, const } } { - bson_vector_packed_bits_const_view_t view; - if (bson_vector_packed_bits_const_view_from_iter (&view, iter)) { - return bson_array_builder_append_vector_packed_bits_elements (builder, view); + bson_vector_packed_bit_const_view_t view; + if (bson_vector_packed_bit_const_view_from_iter (&view, iter)) { + return bson_array_builder_append_vector_packed_bit_elements (builder, view); } } return false; @@ -648,16 +648,16 @@ bson_append_array_from_vector_float32 (bson_t *bson, } bool -bson_append_array_from_vector_packed_bits (bson_t *bson, - const char *key, - int key_length, - bson_vector_packed_bits_const_view_t view) +bson_append_array_from_vector_packed_bit (bson_t *bson, + const char *key, + int key_length, + bson_vector_packed_bit_const_view_t view) { BSON_ASSERT_PARAM (bson); BSON_ASSERT_PARAM (key); bson_array_builder_t *child; if (bson_append_array_builder_begin (bson, key, key_length, &child)) { - bool ok = bson_array_builder_append_vector_packed_bits_elements (child, view); + bool ok = bson_array_builder_append_vector_packed_bit_elements (child, view); return bson_append_array_builder_end (bson, child) && ok; } else { return false; diff --git a/src/libbson/src/bson/bson-vector.h b/src/libbson/src/bson/bson-vector.h index b2abd460e81..501f8e12c4d 100644 --- a/src/libbson/src/bson/bson-vector.h +++ b/src/libbson/src/bson/bson-vector.h @@ -92,15 +92,15 @@ typedef struct bson_vector_float32_const_view_t { bson_vector_binary_const_view_impl_t binary; } bson_vector_float32_const_view_t; -/** @brief A reference to non-owned BSON Binary data holding a valid Vector of packed_bits */ -typedef struct bson_vector_packed_bits_view_t { +/** @brief A reference to non-owned BSON Binary data holding a valid Vector of packed_bit */ +typedef struct bson_vector_packed_bit_view_t { bson_vector_binary_view_impl_t binary; -} bson_vector_packed_bits_view_t; +} bson_vector_packed_bit_view_t; -/** @brief A reference to non-owned const BSON Binary data holding a valid Vector of packed_bits */ -typedef struct bson_vector_packed_bits_const_view_t { +/** @brief A reference to non-owned const BSON Binary data holding a valid Vector of packed_bit */ +typedef struct bson_vector_packed_bit_const_view_t { bson_vector_binary_const_view_impl_t binary; -} bson_vector_packed_bits_const_view_t; +} bson_vector_packed_bit_const_view_t; static BSON_INLINE bson_vector_int8_const_view_t @@ -119,10 +119,10 @@ bson_vector_float32_view_as_const (bson_vector_float32_view_t view) return result; } -static BSON_INLINE bson_vector_packed_bits_const_view_t -bson_vector_packed_bits_view_as_const (bson_vector_packed_bits_view_t view) +static BSON_INLINE bson_vector_packed_bit_const_view_t +bson_vector_packed_bit_view_as_const (bson_vector_packed_bit_view_t view) { - bson_vector_packed_bits_const_view_t result; + bson_vector_packed_bit_const_view_t result; result.binary = bson_vector_binary_view_impl_as_const (view.binary); return result; } @@ -146,14 +146,14 @@ bson_vector_float32_const_view_init (bson_vector_float32_const_view_t *view_out, uint32_t binary_data_len); BSON_EXPORT (bool) -bson_vector_packed_bits_view_init (bson_vector_packed_bits_view_t *view_out, - uint8_t *binary_data, - uint32_t binary_data_len); +bson_vector_packed_bit_view_init (bson_vector_packed_bit_view_t *view_out, + uint8_t *binary_data, + uint32_t binary_data_len); BSON_EXPORT (bool) -bson_vector_packed_bits_const_view_init (bson_vector_packed_bits_const_view_t *view_out, - const uint8_t *binary_data, - uint32_t binary_data_len); +bson_vector_packed_bit_const_view_init (bson_vector_packed_bit_const_view_t *view_out, + const uint8_t *binary_data, + uint32_t binary_data_len); BSON_EXPORT (bool) @@ -169,10 +169,10 @@ BSON_EXPORT (bool) bson_vector_float32_const_view_from_iter (bson_vector_float32_const_view_t *view_out, const bson_iter_t *iter); BSON_EXPORT (bool) -bson_vector_packed_bits_view_from_iter (bson_vector_packed_bits_view_t *view_out, bson_iter_t *iter); +bson_vector_packed_bit_view_from_iter (bson_vector_packed_bit_view_t *view_out, bson_iter_t *iter); BSON_EXPORT (bool) -bson_vector_packed_bits_const_view_from_iter (bson_vector_packed_bits_const_view_t *view_out, const bson_iter_t *iter); +bson_vector_packed_bit_const_view_from_iter (bson_vector_packed_bit_const_view_t *view_out, const bson_iter_t *iter); BSON_EXPORT (bool) @@ -184,8 +184,8 @@ bson_array_builder_append_vector_float32_elements (struct _bson_array_builder_t bson_vector_float32_const_view_t view); BSON_EXPORT (bool) -bson_array_builder_append_vector_packed_bits_elements (struct _bson_array_builder_t *builder, - bson_vector_packed_bits_const_view_t view); +bson_array_builder_append_vector_packed_bit_elements (struct _bson_array_builder_t *builder, + bson_vector_packed_bit_const_view_t view); BSON_EXPORT (bool) bson_array_builder_append_vector_elements (struct _bson_array_builder_t *builder, const bson_iter_t *iter); @@ -205,11 +205,11 @@ bson_append_vector_float32 ( bson_append_vector_float32 (b, key, (int) strlen (key), count, view) BSON_EXPORT (bool) -bson_append_vector_packed_bits ( - bson_t *bson, const char *key, int key_length, size_t element_count, bson_vector_packed_bits_view_t *view_out); +bson_append_vector_packed_bit ( + bson_t *bson, const char *key, int key_length, size_t element_count, bson_vector_packed_bit_view_t *view_out); -#define BSON_APPEND_VECTOR_PACKED_BITS(b, key, count, view) \ - bson_append_vector_packed_bits (b, key, (int) strlen (key), count, view) +#define BSON_APPEND_VECTOR_PACKED_BIT(b, key, count, view) \ + bson_append_vector_packed_bit (b, key, (int) strlen (key), count, view) BSON_EXPORT (bool) @@ -227,11 +227,11 @@ bson_append_vector_float32_from_array ( bson_append_vector_float32_from_array (b, key, (int) strlen (key), iter, err) BSON_EXPORT (bool) -bson_append_vector_packed_bits_from_array ( +bson_append_vector_packed_bit_from_array ( bson_t *bson, const char *key, int key_length, const bson_iter_t *iter, bson_error_t *error); -#define BSON_APPEND_VECTOR_PACKED_BITS_FROM_ARRAY(b, key, iter, err) \ - bson_append_vector_packed_bits_from_array (b, key, (int) strlen (key), iter, err) +#define BSON_APPEND_VECTOR_PACKED_BIT_FROM_ARRAY(b, key, iter, err) \ + bson_append_vector_packed_bit_from_array (b, key, (int) strlen (key), iter, err) BSON_EXPORT (bool) @@ -250,13 +250,13 @@ bson_append_array_from_vector_float32 (bson_t *bson, bson_append_array_from_vector_float32 (b, key, (int) strlen (key), view) BSON_EXPORT (bool) -bson_append_array_from_vector_packed_bits (bson_t *bson, - const char *key, - int key_length, - bson_vector_packed_bits_const_view_t view); +bson_append_array_from_vector_packed_bit (bson_t *bson, + const char *key, + int key_length, + bson_vector_packed_bit_const_view_t view); -#define BSON_APPEND_ARRAY_FROM_VECTOR_PACKED_BITS(b, key, view) \ - bson_append_array_from_vector_packed_bits (b, key, (int) strlen (key), view) +#define BSON_APPEND_ARRAY_FROM_VECTOR_PACKED_BIT(b, key, view) \ + bson_append_array_from_vector_packed_bit (b, key, (int) strlen (key), view) static BSON_INLINE const int8_t * @@ -289,7 +289,7 @@ bson_vector_float32_binary_data_length (size_t element_count) } static BSON_INLINE uint32_t -bson_vector_packed_bits_binary_data_length (size_t element_count) +bson_vector_packed_bit_binary_data_length (size_t element_count) { const size_t max_representable = (size_t) BSON_MIN ( (uint64_t) SIZE_MAX, ((uint64_t) UINT32_MAX - (uint64_t) BSON_VECTOR_HEADER_LEN) * (uint64_t) 8); @@ -324,15 +324,15 @@ bson_vector_float32_view_length (bson_vector_float32_view_t view) } static BSON_INLINE size_t -bson_vector_packed_bits_const_view_length_bytes (bson_vector_packed_bits_const_view_t view) +bson_vector_packed_bit_const_view_length_bytes (bson_vector_packed_bit_const_view_t view) { return view.binary.data_len - (uint32_t) BSON_VECTOR_HEADER_LEN; } static BSON_INLINE size_t -bson_vector_packed_bits_view_length_bytes (bson_vector_packed_bits_view_t view) +bson_vector_packed_bit_view_length_bytes (bson_vector_packed_bit_view_t view) { - return bson_vector_packed_bits_const_view_length_bytes (bson_vector_packed_bits_view_as_const (view)); + return bson_vector_packed_bit_const_view_length_bytes (bson_vector_packed_bit_view_as_const (view)); } // Implementation detail, not part of documented API. @@ -343,28 +343,27 @@ bson_vector_padding_from_header_byte_1 (uint8_t byte_1) } static BSON_INLINE size_t -bson_vector_packed_bits_const_view_padding (bson_vector_packed_bits_const_view_t view) +bson_vector_packed_bit_const_view_padding (bson_vector_packed_bit_const_view_t view) { return bson_vector_padding_from_header_byte_1 (view.binary.header_copy.bytes[1]); } static BSON_INLINE size_t -bson_vector_packed_bits_view_padding (bson_vector_packed_bits_view_t view) +bson_vector_packed_bit_view_padding (bson_vector_packed_bit_view_t view) { - return bson_vector_packed_bits_const_view_padding (bson_vector_packed_bits_view_as_const (view)); + return bson_vector_packed_bit_const_view_padding (bson_vector_packed_bit_view_as_const (view)); } static BSON_INLINE size_t -bson_vector_packed_bits_const_view_length (bson_vector_packed_bits_const_view_t view) +bson_vector_packed_bit_const_view_length (bson_vector_packed_bit_const_view_t view) { - return bson_vector_packed_bits_const_view_length_bytes (view) * 8u - - bson_vector_packed_bits_const_view_padding (view); + return bson_vector_packed_bit_const_view_length_bytes (view) * 8u - bson_vector_packed_bit_const_view_padding (view); } static BSON_INLINE size_t -bson_vector_packed_bits_view_length (bson_vector_packed_bits_view_t view) +bson_vector_packed_bit_view_length (bson_vector_packed_bit_view_t view) { - return bson_vector_packed_bits_const_view_length (bson_vector_packed_bits_view_as_const (view)); + return bson_vector_packed_bit_const_view_length (bson_vector_packed_bit_view_as_const (view)); } @@ -472,12 +471,12 @@ bson_vector_float32_view_write (bson_vector_float32_view_t view, static BSON_INLINE bool -bson_vector_packed_bits_const_view_read_packed (bson_vector_packed_bits_const_view_t view, - uint8_t *BSON_RESTRICT packed_values_out, - size_t byte_count, - size_t vector_offset_bytes) +bson_vector_packed_bit_const_view_read_packed (bson_vector_packed_bit_const_view_t view, + uint8_t *BSON_RESTRICT packed_values_out, + size_t byte_count, + size_t vector_offset_bytes) { - size_t length_bytes = bson_vector_packed_bits_const_view_length_bytes (view); + size_t length_bytes = bson_vector_packed_bit_const_view_length_bytes (view); if (BSON_LIKELY (vector_offset_bytes <= length_bytes && byte_count <= length_bytes - vector_offset_bytes)) { memcpy (packed_values_out, view.binary.data + BSON_VECTOR_HEADER_LEN + vector_offset_bytes, byte_count); return true; @@ -487,22 +486,22 @@ bson_vector_packed_bits_const_view_read_packed (bson_vector_packed_bits_const_vi } static BSON_INLINE bool -bson_vector_packed_bits_view_read_packed (bson_vector_packed_bits_view_t view, - uint8_t *BSON_RESTRICT packed_values_out, - size_t byte_count, - size_t vector_offset_bytes) +bson_vector_packed_bit_view_read_packed (bson_vector_packed_bit_view_t view, + uint8_t *BSON_RESTRICT packed_values_out, + size_t byte_count, + size_t vector_offset_bytes) { - return bson_vector_packed_bits_const_view_read_packed ( - bson_vector_packed_bits_view_as_const (view), packed_values_out, byte_count, vector_offset_bytes); + return bson_vector_packed_bit_const_view_read_packed ( + bson_vector_packed_bit_view_as_const (view), packed_values_out, byte_count, vector_offset_bytes); } static BSON_INLINE bool -bson_vector_packed_bits_view_write_packed (bson_vector_packed_bits_view_t view, - const uint8_t *BSON_RESTRICT packed_values, - size_t byte_count, - size_t vector_offset_bytes) +bson_vector_packed_bit_view_write_packed (bson_vector_packed_bit_view_t view, + const uint8_t *BSON_RESTRICT packed_values, + size_t byte_count, + size_t vector_offset_bytes) { - size_t length_bytes = bson_vector_packed_bits_view_length_bytes (view); + size_t length_bytes = bson_vector_packed_bit_view_length_bytes (view); if (BSON_LIKELY (vector_offset_bytes <= length_bytes && byte_count <= length_bytes - vector_offset_bytes)) { if (byte_count == length_bytes - vector_offset_bytes && byte_count >= 1u) { // This write touches the last byte in the vector: @@ -510,7 +509,7 @@ bson_vector_packed_bits_view_write_packed (bson_vector_packed_bits_view_t view, size_t other_bytes = byte_count - 1u; memcpy (view.binary.data + BSON_VECTOR_HEADER_LEN + vector_offset_bytes, packed_values, other_bytes); view.binary.data[BSON_VECTOR_HEADER_LEN + vector_offset_bytes + other_bytes] = - (UINT8_C (0xFF) << bson_vector_packed_bits_view_padding (view)) & packed_values[other_bytes]; + (UINT8_C (0xFF) << bson_vector_packed_bit_view_padding (view)) & packed_values[other_bytes]; } else { memcpy (view.binary.data + BSON_VECTOR_HEADER_LEN + vector_offset_bytes, packed_values, byte_count); } @@ -522,12 +521,12 @@ bson_vector_packed_bits_view_write_packed (bson_vector_packed_bits_view_t view, static BSON_INLINE bool -bson_vector_packed_bits_const_view_unpack_bool (bson_vector_packed_bits_const_view_t view, - bool *BSON_RESTRICT unpacked_values_out, - size_t element_count, - size_t vector_offset_elements) +bson_vector_packed_bit_const_view_unpack_bool (bson_vector_packed_bit_const_view_t view, + bool *BSON_RESTRICT unpacked_values_out, + size_t element_count, + size_t vector_offset_elements) { - size_t length = bson_vector_packed_bits_const_view_length (view); + size_t length = bson_vector_packed_bit_const_view_length (view); if (BSON_LIKELY (vector_offset_elements <= length && element_count <= length - vector_offset_elements)) { size_t i; for (i = 0; i < element_count; i++) { @@ -542,22 +541,22 @@ bson_vector_packed_bits_const_view_unpack_bool (bson_vector_packed_bits_const_vi } static BSON_INLINE bool -bson_vector_packed_bits_view_unpack_bool (bson_vector_packed_bits_view_t view, - bool *BSON_RESTRICT unpacked_values_out, - size_t element_count, - size_t vector_offset_elements) +bson_vector_packed_bit_view_unpack_bool (bson_vector_packed_bit_view_t view, + bool *BSON_RESTRICT unpacked_values_out, + size_t element_count, + size_t vector_offset_elements) { - return bson_vector_packed_bits_const_view_unpack_bool ( - bson_vector_packed_bits_view_as_const (view), unpacked_values_out, element_count, vector_offset_elements); + return bson_vector_packed_bit_const_view_unpack_bool ( + bson_vector_packed_bit_view_as_const (view), unpacked_values_out, element_count, vector_offset_elements); } static BSON_INLINE bool -bson_vector_packed_bits_view_pack_bool (bson_vector_packed_bits_view_t view, - const bool *BSON_RESTRICT unpacked_values, - size_t element_count, - size_t vector_offset_elements) +bson_vector_packed_bit_view_pack_bool (bson_vector_packed_bit_view_t view, + const bool *BSON_RESTRICT unpacked_values, + size_t element_count, + size_t vector_offset_elements) { - size_t length = bson_vector_packed_bits_view_length (view); + size_t length = bson_vector_packed_bit_view_length (view); if (BSON_LIKELY (vector_offset_elements <= length && element_count <= length - vector_offset_elements)) { while (element_count > 0) { uint8_t *BSON_RESTRICT packed_byte = &view.binary.data[BSON_VECTOR_HEADER_LEN + (vector_offset_elements >> 3)]; diff --git a/src/libbson/tests/test-bson-vector.c b/src/libbson/tests/test-bson-vector.c index 1e6a7f2cad8..b500e10e61a 100644 --- a/src/libbson/tests/test-bson-vector.c +++ b/src/libbson/tests/test-bson-vector.c @@ -44,10 +44,10 @@ BSON_STATIC_ASSERT2 (sizeof_bson_vector_float32_const_view_t, sizeof (bson_vector_float32_const_view_t) == EXPECTED_VECTOR_VIEW_SIZE); BSON_STATIC_ASSERT2 (sizeof_bson_vector_float32_view_t, sizeof (bson_vector_float32_view_t) == EXPECTED_VECTOR_VIEW_SIZE); -BSON_STATIC_ASSERT2 (sizeof_bson_vector_packed_bits_const_view_t, - sizeof (bson_vector_packed_bits_const_view_t) == EXPECTED_VECTOR_VIEW_SIZE); -BSON_STATIC_ASSERT2 (sizeof_bson_vector_packed_bits_view_t, - sizeof (bson_vector_packed_bits_view_t) == EXPECTED_VECTOR_VIEW_SIZE); +BSON_STATIC_ASSERT2 (sizeof_bson_vector_packed_bit_const_view_t, + sizeof (bson_vector_packed_bit_const_view_t) == EXPECTED_VECTOR_VIEW_SIZE); +BSON_STATIC_ASSERT2 (sizeof_bson_vector_packed_bit_view_t, + sizeof (bson_vector_packed_bit_view_t) == EXPECTED_VECTOR_VIEW_SIZE); #undef EXPECTED_VECTOR_VIEW_SIZE typedef struct vector_json_test_case_t { @@ -82,12 +82,12 @@ translate_json_test_vector (bson_t *array_in, bson_t *array_out) } static bool -append_vector_packed_bits_from_packed_array ( +append_vector_packed_bit_from_packed_array ( bson_t *bson, const char *key, int key_length, const bson_iter_t *iter, int64_t padding, bson_error_t *error) { // (TODO for DRIVERS-3095, DRIVERS-3097) This implements something the test covers that our API doesn't. If the test // were modified to cover element-by-element conversion, this can be replaced with - // bson_append_vector_packed_bits_from_array. + // bson_append_vector_packed_bit_from_array. BSON_ASSERT_PARAM (bson); BSON_ASSERT_PARAM (key); @@ -125,7 +125,7 @@ append_vector_packed_bits_from_packed_array ( TEST_ERROR_DOMAIN, TEST_ERROR_CODE, "'padding' parameter (%" PRId64 - ") for append_vector_packed_bits_from_packed_array is out of range", + ") for append_vector_packed_bit_from_packed_array is out of range", padding); return false; } @@ -134,18 +134,18 @@ append_vector_packed_bits_from_packed_array ( TEST_ERROR_DOMAIN, TEST_ERROR_CODE, "nonzero 'padding' parameter (%" PRId64 - ") for zero-length append_vector_packed_bits_from_packed_array", + ") for zero-length append_vector_packed_bit_from_packed_array", padding); return false; } - bson_vector_packed_bits_view_t view; - if (bson_append_vector_packed_bits (bson, key, key_length, byte_count * 8u - (size_t) padding, &view)) { + bson_vector_packed_bit_view_t view; + if (bson_append_vector_packed_bit (bson, key, key_length, byte_count * 8u - (size_t) padding, &view)) { bson_iter_t copy_iter = *iter; for (size_t i = 0; i < byte_count; i++) { BSON_ASSERT (bson_iter_next (©_iter)); uint8_t packed_byte = (uint8_t) bson_iter_as_int64 (©_iter); - BSON_ASSERT (bson_vector_packed_bits_view_write_packed (view, &packed_byte, 1, i)); + BSON_ASSERT (bson_vector_packed_bit_view_write_packed (view, &packed_byte, 1, i)); } return true; } else { @@ -219,7 +219,7 @@ test_bson_vector_json_case (vector_json_test_case_t *test_case) } bson_destroy (&converted); } else if (0 == strcmp ("0x10", test_case->test_dtype_hex_str)) { - // packed_bits from packed bytes in an int array, with "padding" parameter supplied separately. + // packed_bit from packed bytes in an int array, with "padding" parameter supplied separately. // TODO for DRIVERS-3095, DRIVERS-3097: // - Array-to-Vector should be defined as an element-by-element conversion. This test shouldn't operate on packed // representations. @@ -230,12 +230,12 @@ test_bson_vector_json_case (vector_json_test_case_t *test_case) test_error ("test '%s' is missing required 'padding' field", test_case->test_description); } vector_from_array_ok = test_case->test_vector_array && bson_iter_init (&iter, test_case->test_vector_array) && - append_vector_packed_bits_from_packed_array (&vector_from_array, - test_case->scenario_test_key, - -1, - &iter, - *test_case->test_padding, - &vector_from_array_error); + append_vector_packed_bit_from_packed_array (&vector_from_array, + test_case->scenario_test_key, + -1, + &iter, + *test_case->test_padding, + &vector_from_array_error); } else { test_error ( "test '%s' has unsupported dtype_hex format '%s'", test_case->test_description, test_case->test_dtype_hex_str); @@ -287,7 +287,7 @@ test_bson_vector_json_case (vector_json_test_case_t *test_case) } // (TODO for DRIVERS-3095, DRIVERS-3097) Due to loosely defined element types and rounding behavior in the test - // vectors, this comparison can't be exact. Temporary special cases are needed for float32 and packed_bits. + // vectors, this comparison can't be exact. Temporary special cases are needed for float32 and packed_bit. if (BSON_ITER_HOLDS_VECTOR_FLOAT32 (&iter)) { // float32 special case: We need to handle the nonstandard "inf" and "-inf" forms, and @@ -352,16 +352,16 @@ test_bson_vector_json_case (vector_json_test_case_t *test_case) } } - } else if (BSON_ITER_HOLDS_VECTOR_PACKED_BITS (&iter)) { - // packed_bits special case: The tests for packed_bits aren't actually testing vector-to-array conversion as we + } else if (BSON_ITER_HOLDS_VECTOR_PACKED_BIT (&iter)) { + // packed_bit special case: The tests for packed_bit aren't actually testing vector-to-array conversion as we // understand it, they're operating on bytes rather than elements. This is the inverse of - // append_vector_packed_bits_from_packed_array() above, and it bypasses the vector-to-array conversion. + // append_vector_packed_bit_from_packed_array() above, and it bypasses the vector-to-array conversion. // 'array_from_vector' is ignored on this path. bson_iter_t expected_iter; BSON_ASSERT (bson_iter_init (&expected_iter, test_case->test_vector_array)); - bson_vector_packed_bits_const_view_t actual_view; - BSON_ASSERT (bson_vector_packed_bits_const_view_from_iter (&actual_view, &iter)); + bson_vector_packed_bit_const_view_t actual_view; + BSON_ASSERT (bson_vector_packed_bit_const_view_from_iter (&actual_view, &iter)); size_t byte_count = 0; while (bson_iter_next (&expected_iter)) { @@ -376,24 +376,24 @@ test_bson_vector_json_case (vector_json_test_case_t *test_case) // tests allow padding bits to take on undefined values. Modify the expected values to keep padding bits // zeroed. if (0 == strcmp ("PACKED_BIT with padding", test_case->test_description) && - byte_count == bson_vector_packed_bits_const_view_length_bytes (actual_view) - 1u) { + byte_count == bson_vector_packed_bit_const_view_length_bytes (actual_view) - 1u) { expected_byte &= ((int64_t) 0xFF << *test_case->test_padding) & 0xFF; } // Note, the zero initializer is only needed due to a false positive -Wmaybe-uninitialized warning in // uncommon configurations where the compiler does not have visibility into memcpy(). uint8_t actual_byte = 0; - BSON_ASSERT (bson_vector_packed_bits_const_view_read_packed (actual_view, &actual_byte, 1, byte_count)); + BSON_ASSERT (bson_vector_packed_bit_const_view_read_packed (actual_view, &actual_byte, 1, byte_count)); if (expected_byte != (int64_t) actual_byte) { - test_error ("failed to match packed byte %d of packed_bits test-vector. Actual: 0x%02x Expected: 0x%02x", + test_error ("failed to match packed byte %d of packed_bit test-vector. Actual: 0x%02x Expected: 0x%02x", (int) byte_count, (unsigned) actual_byte, (unsigned) expected_byte); } byte_count++; } - ASSERT_CMPSIZE_T (byte_count, ==, bson_vector_packed_bits_const_view_length_bytes (actual_view)); + ASSERT_CMPSIZE_T (byte_count, ==, bson_vector_packed_bit_const_view_length_bytes (actual_view)); } else { // No special case, expect an exact match. (Used for int8 vectors) @@ -550,7 +550,7 @@ test_bson_vector_view_api_usage_int8 (void) ASSERT (BSON_ITER_HOLDS_VECTOR (&iter)); ASSERT (BSON_ITER_HOLDS_VECTOR_INT8 (&iter)); ASSERT (!BSON_ITER_HOLDS_VECTOR_FLOAT32 (&iter)); - ASSERT (!BSON_ITER_HOLDS_VECTOR_PACKED_BITS (&iter)); + ASSERT (!BSON_ITER_HOLDS_VECTOR_PACKED_BIT (&iter)); bson_vector_int8_const_view_t view; ASSERT (bson_vector_int8_const_view_from_iter (&view, &iter)); ASSERT (bson_vector_int8_const_view_length (view) == 25); @@ -665,7 +665,7 @@ test_bson_vector_view_api_usage_float32 (void) ASSERT (BSON_ITER_HOLDS_VECTOR (&iter)); ASSERT (!BSON_ITER_HOLDS_VECTOR_INT8 (&iter)); ASSERT (BSON_ITER_HOLDS_VECTOR_FLOAT32 (&iter)); - ASSERT (!BSON_ITER_HOLDS_VECTOR_PACKED_BITS (&iter)); + ASSERT (!BSON_ITER_HOLDS_VECTOR_PACKED_BIT (&iter)); bson_vector_float32_const_view_t view; ASSERT (bson_vector_float32_const_view_from_iter (&view, &iter)); ASSERT (bson_vector_float32_const_view_length (view) == 5); @@ -732,18 +732,18 @@ test_bson_vector_view_api_usage_float32 (void) } static void -test_bson_vector_view_api_usage_packed_bits (void) +test_bson_vector_view_api_usage_packed_bit (void) { bson_t doc = BSON_INITIALIZER; // Construct a small vector by packing individual elements from a 'bool' source { - bson_vector_packed_bits_view_t view; + bson_vector_packed_bit_view_t view; const size_t length = 123; - ASSERT (BSON_APPEND_VECTOR_PACKED_BITS (&doc, "vector", length, &view)); + ASSERT (BSON_APPEND_VECTOR_PACKED_BIT (&doc, "vector", length, &view)); for (size_t i = 0; i < length; i++) { bool v = (i & 1) != 0; - bson_vector_packed_bits_view_pack_bool (view, &v, 1, i); + bson_vector_packed_bit_view_pack_bool (view, &v, 1, i); } } @@ -752,12 +752,12 @@ test_bson_vector_view_api_usage_packed_bits (void) // Construct a longer vector by packing individual elements from a 'bool' source { - bson_vector_packed_bits_view_t view; + bson_vector_packed_bit_view_t view; const size_t length = 100002; - ASSERT (bson_append_vector_packed_bits (&doc, "longer_vector", -1, length, &view)); + ASSERT (bson_append_vector_packed_bit (&doc, "longer_vector", -1, length, &view)); for (size_t i = 0; i < length; i++) { bool v = (i & 3) != 0; - bson_vector_packed_bits_view_pack_bool (view, &v, 1, i); + bson_vector_packed_bit_view_pack_bool (view, &v, 1, i); } } @@ -776,16 +776,16 @@ test_bson_vector_view_api_usage_packed_bits (void) ASSERT (BSON_ITER_HOLDS_VECTOR (&iter)); ASSERT (!BSON_ITER_HOLDS_VECTOR_INT8 (&iter)); ASSERT (!BSON_ITER_HOLDS_VECTOR_FLOAT32 (&iter)); - ASSERT (BSON_ITER_HOLDS_VECTOR_PACKED_BITS (&iter)); - bson_vector_packed_bits_const_view_t view; - ASSERT (bson_vector_packed_bits_const_view_from_iter (&view, &iter)); - ASSERT (bson_vector_packed_bits_const_view_length (view) == 123); + ASSERT (BSON_ITER_HOLDS_VECTOR_PACKED_BIT (&iter)); + bson_vector_packed_bit_const_view_t view; + ASSERT (bson_vector_packed_bit_const_view_from_iter (&view, &iter)); + ASSERT (bson_vector_packed_bit_const_view_length (view) == 123); bool values[123]; bool expected_values[123]; for (size_t i = 0; i < sizeof expected_values / sizeof expected_values[0]; i++) { expected_values[i] = (i & 1) != 0; } - ASSERT (bson_vector_packed_bits_const_view_unpack_bool (view, values, sizeof values / sizeof values[0], 0)); + ASSERT (bson_vector_packed_bit_const_view_unpack_bool (view, values, sizeof values / sizeof values[0], 0)); ASSERT_MEMCMP (values, expected_values, (int) sizeof expected_values); } @@ -793,13 +793,13 @@ test_bson_vector_view_api_usage_packed_bits (void) { bson_iter_t iter; ASSERT (bson_iter_init_find (&iter, &doc, "vector")); - bson_vector_packed_bits_const_view_t view; - ASSERT (bson_vector_packed_bits_const_view_from_iter (&view, &iter)); - ASSERT (bson_vector_packed_bits_const_view_length (view) == 123); + bson_vector_packed_bit_const_view_t view; + ASSERT (bson_vector_packed_bit_const_view_from_iter (&view, &iter)); + ASSERT (bson_vector_packed_bit_const_view_length (view) == 123); uint8_t packed[16]; static const uint8_t expected_packed[16] = { 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x40}; - ASSERT (bson_vector_packed_bits_const_view_read_packed (view, packed, sizeof packed, 0)); + ASSERT (bson_vector_packed_bit_const_view_read_packed (view, packed, sizeof packed, 0)); ASSERT_MEMCMP (packed, expected_packed, (int) sizeof expected_packed); } @@ -807,21 +807,21 @@ test_bson_vector_view_api_usage_packed_bits (void) { bson_iter_t iter; ASSERT (bson_iter_init_find (&iter, &doc, "vector")); - bson_vector_packed_bits_view_t view; - ASSERT (bson_vector_packed_bits_view_from_iter (&view, &iter)); + bson_vector_packed_bit_view_t view; + ASSERT (bson_vector_packed_bit_view_from_iter (&view, &iter)); uint8_t packed[2] = {0x12, 0x34}; - ASSERT (bson_vector_packed_bits_view_write_packed (view, packed, sizeof packed, 12)); + ASSERT (bson_vector_packed_bit_view_write_packed (view, packed, sizeof packed, 12)); } // Partial read of the packed representation { bson_iter_t iter; ASSERT (bson_iter_init_find (&iter, &doc, "vector")); - bson_vector_packed_bits_const_view_t view; - ASSERT (bson_vector_packed_bits_const_view_from_iter (&view, &iter)); + bson_vector_packed_bit_const_view_t view; + ASSERT (bson_vector_packed_bit_const_view_from_iter (&view, &iter)); uint8_t packed[5]; static const uint8_t expected_packed[5] = {0x55, 0x12, 0x34, 0x55, 0x40}; - ASSERT (bson_vector_packed_bits_const_view_read_packed (view, packed, sizeof packed, 11)); + ASSERT (bson_vector_packed_bit_const_view_read_packed (view, packed, sizeof packed, 11)); ASSERT_MEMCMP (packed, expected_packed, (int) sizeof expected_packed); } @@ -829,13 +829,13 @@ test_bson_vector_view_api_usage_packed_bits (void) { bson_iter_t iter; ASSERT (bson_iter_init_find (&iter, &doc, "vector")); - bson_vector_packed_bits_view_t view; - ASSERT (bson_vector_packed_bits_view_from_iter (&view, &iter)); + bson_vector_packed_bit_view_t view; + ASSERT (bson_vector_packed_bit_view_from_iter (&view, &iter)); bool values[24] = { false, false, false, true, false, false, false, true, true, true, false, true, true, false, false, false, false, true, false, false, false, false, false, true, }; - ASSERT (bson_vector_packed_bits_view_pack_bool (view, values, sizeof values / sizeof values[0], 3)); + ASSERT (bson_vector_packed_bit_view_pack_bool (view, values, sizeof values / sizeof values[0], 3)); } // Convert the small vector to a BSON Array, and check the resulting canonical extended JSON. @@ -885,7 +885,7 @@ test_bson_vector_view_api_usage_packed_bits (void) ASSERT (bson_iter_init_find (&iter, &converted, "array")); ASSERT (BSON_ITER_HOLDS_ARRAY (&iter)); ASSERT (bson_iter_recurse (&iter, &iter)); - ASSERT (BSON_APPEND_VECTOR_PACKED_BITS_FROM_ARRAY (&doc, "round_trip", &iter, NULL)); + ASSERT (BSON_APPEND_VECTOR_PACKED_BIT_FROM_ARRAY (&doc, "round_trip", &iter, NULL)); bson_destroy (&converted); } @@ -907,7 +907,7 @@ test_bson_vector_view_api_usage_packed_bits (void) ASSERT (bson_iter_init_find (&iter, &converted, "array")); ASSERT (BSON_ITER_HOLDS_ARRAY (&iter)); ASSERT (bson_iter_recurse (&iter, &iter)); - ASSERT (BSON_APPEND_VECTOR_PACKED_BITS_FROM_ARRAY (&doc, "longer_round_trip", &iter, NULL)); + ASSERT (BSON_APPEND_VECTOR_PACKED_BIT_FROM_ARRAY (&doc, "longer_round_trip", &iter, NULL)); bson_destroy (&converted); } { @@ -917,36 +917,36 @@ test_bson_vector_view_api_usage_packed_bits (void) ASSERT (bson_iter_binary_equal (&a, &b)); } - // Padding bits will be initialized to zero when a packed_bits vector is first allocated by - // bson_append_vector_packed_bits + // Padding bits will be initialized to zero when a packed_bit vector is first allocated by + // bson_append_vector_packed_bit { // Set the uninitialized part of 'doc' to a known value static const uint32_t reserve_len = 512; memset (bson_reserve_buffer (&doc, doc.len + reserve_len) + doc.len, 0xdd, reserve_len); - bson_vector_packed_bits_view_t view; - ASSERT (BSON_APPEND_VECTOR_PACKED_BITS (&doc, "padding_init_test", 12, &view)); - ASSERT (bson_vector_packed_bits_view_length_bytes (view) == 2); - ASSERT (bson_vector_packed_bits_view_padding (view) == 4); + bson_vector_packed_bit_view_t view; + ASSERT (BSON_APPEND_VECTOR_PACKED_BIT (&doc, "padding_init_test", 12, &view)); + ASSERT (bson_vector_packed_bit_view_length_bytes (view) == 2); + ASSERT (bson_vector_packed_bit_view_padding (view) == 4); // BSON validity only requires the low 4 bits to be zero, but the entire last // byte will be zeroed by our implementation. uint8_t bytes[2]; - ASSERT (bson_vector_packed_bits_view_read_packed (view, bytes, sizeof bytes, 0)); + ASSERT (bson_vector_packed_bit_view_read_packed (view, bytes, sizeof bytes, 0)); ASSERT_CMPUINT ((unsigned) bytes[0], ==, 0xdd); ASSERT_CMPUINT ((unsigned) bytes[1], ==, 0x00); } - // Padding bits can't be forcibly given nonzero values using bson_vector_packed_bits_view_write_packed + // Padding bits can't be forcibly given nonzero values using bson_vector_packed_bit_view_write_packed { - bson_vector_packed_bits_view_t view; - ASSERT (BSON_APPEND_VECTOR_PACKED_BITS (&doc, "padding_mask_test", 13, &view)); - ASSERT (bson_vector_packed_bits_view_length_bytes (view) == 2); - ASSERT (bson_vector_packed_bits_view_padding (view) == 3); + bson_vector_packed_bit_view_t view; + ASSERT (BSON_APPEND_VECTOR_PACKED_BIT (&doc, "padding_mask_test", 13, &view)); + ASSERT (bson_vector_packed_bit_view_length_bytes (view) == 2); + ASSERT (bson_vector_packed_bit_view_padding (view) == 3); uint8_t bytes[2] = {0xff, 0xff}; - ASSERT (bson_vector_packed_bits_view_write_packed (view, bytes, sizeof bytes, 0)); - ASSERT (bson_vector_packed_bits_view_read_packed (view, bytes, sizeof bytes, 0)); + ASSERT (bson_vector_packed_bit_view_write_packed (view, bytes, sizeof bytes, 0)); + ASSERT (bson_vector_packed_bit_view_read_packed (view, bytes, sizeof bytes, 0)); ASSERT_CMPUINT ((unsigned) bytes[0], ==, 0xff); ASSERT_CMPUINT ((unsigned) bytes[1], ==, 0xf8); } @@ -1070,7 +1070,7 @@ test_bson_vector_view_api_fuzz_float32 (void) } static void -test_bson_vector_view_api_fuzz_packed_bits (void) +test_bson_vector_view_api_fuzz_packed_bit (void) { size_t current_length = 0; bson_t vector_doc = BSON_INITIALIZER; @@ -1086,12 +1086,12 @@ test_bson_vector_view_api_fuzz_packed_bits (void) // Resize and fill from unpacked bool source size_t new_length = (size_t) r_param % MAX_TESTED_VECTOR_LENGTH; bson_reinit (&vector_doc); - bson_vector_packed_bits_view_t view; - BSON_ASSERT (BSON_APPEND_VECTOR_PACKED_BITS (&vector_doc, "vector", new_length, &view)); + bson_vector_packed_bit_view_t view; + BSON_ASSERT (BSON_APPEND_VECTOR_PACKED_BIT (&vector_doc, "vector", new_length, &view)); for (size_t i = 0; i < new_length; i++) { expected_elements[i] = (rand () & 1) != 0; } - BSON_ASSERT (bson_vector_packed_bits_view_pack_bool (view, expected_elements, new_length, 0)); + BSON_ASSERT (bson_vector_packed_bit_view_pack_bool (view, expected_elements, new_length, 0)); current_length = new_length; } else if (r_operation < 7) { @@ -1103,13 +1103,13 @@ test_bson_vector_view_api_fuzz_packed_bits (void) for (size_t i = 0; i < element_count; i++) { expected_elements[offset + i] = (rand () & 1) != 0; } - bson_vector_packed_bits_view_t view; + bson_vector_packed_bit_view_t view; bson_iter_t iter; BSON_ASSERT (bson_iter_init_find (&iter, &vector_doc, "vector")); - BSON_ASSERT (bson_vector_packed_bits_view_from_iter (&view, &iter)); - BSON_ASSERT (bson_vector_packed_bits_view_length (view) == current_length); + BSON_ASSERT (bson_vector_packed_bit_view_from_iter (&view, &iter)); + BSON_ASSERT (bson_vector_packed_bit_view_length (view) == current_length); BSON_ASSERT ( - bson_vector_packed_bits_view_pack_bool (view, expected_elements + offset, element_count, offset)); + bson_vector_packed_bit_view_pack_bool (view, expected_elements + offset, element_count, offset)); } else { // Partial write of packed bytes size_t current_length_bytes = (current_length + 7) / 8; @@ -1122,13 +1122,13 @@ test_bson_vector_view_api_fuzz_packed_bits (void) expected_elements[(byte_offset + i) * 8 + bit] = (packed_byte & (0x80 >> bit)) != 0; } } - bson_vector_packed_bits_view_t view; + bson_vector_packed_bit_view_t view; bson_iter_t iter; BSON_ASSERT (bson_iter_init_find (&iter, &vector_doc, "vector")); - BSON_ASSERT (bson_vector_packed_bits_view_from_iter (&view, &iter)); - BSON_ASSERT (bson_vector_packed_bits_view_length (view) == current_length); - BSON_ASSERT (bson_vector_packed_bits_view_length_bytes (view) == current_length_bytes); - BSON_ASSERT (bson_vector_packed_bits_view_write_packed (view, packed_buffer, byte_count, byte_offset)); + BSON_ASSERT (bson_vector_packed_bit_view_from_iter (&view, &iter)); + BSON_ASSERT (bson_vector_packed_bit_view_length (view) == current_length); + BSON_ASSERT (bson_vector_packed_bit_view_length_bytes (view) == current_length_bytes); + BSON_ASSERT (bson_vector_packed_bit_view_write_packed (view, packed_buffer, byte_count, byte_offset)); } } else { // Partial read @@ -1136,12 +1136,12 @@ test_bson_vector_view_api_fuzz_packed_bits (void) // Partial read to unpacked bool destination size_t element_count = r_param % current_length; size_t offset = rand () % (current_length - element_count); - bson_vector_packed_bits_const_view_t view; + bson_vector_packed_bit_const_view_t view; bson_iter_t iter; BSON_ASSERT (bson_iter_init_find (&iter, &vector_doc, "vector")); - BSON_ASSERT (bson_vector_packed_bits_const_view_from_iter (&view, &iter)); - BSON_ASSERT (bson_vector_packed_bits_const_view_length (view) == current_length); - BSON_ASSERT (bson_vector_packed_bits_const_view_unpack_bool (view, actual_elements, element_count, offset)); + BSON_ASSERT (bson_vector_packed_bit_const_view_from_iter (&view, &iter)); + BSON_ASSERT (bson_vector_packed_bit_const_view_length (view) == current_length); + BSON_ASSERT (bson_vector_packed_bit_const_view_unpack_bool (view, actual_elements, element_count, offset)); for (size_t i = 0; i < element_count; i++) { BSON_ASSERT (actual_elements[i] == expected_elements[i + offset]); } @@ -1150,13 +1150,13 @@ test_bson_vector_view_api_fuzz_packed_bits (void) size_t current_length_bytes = (current_length + 7) / 8; size_t byte_count = r_param % current_length_bytes; size_t byte_offset = rand () % (current_length_bytes - byte_count); - bson_vector_packed_bits_const_view_t view; + bson_vector_packed_bit_const_view_t view; bson_iter_t iter; BSON_ASSERT (bson_iter_init_find (&iter, &vector_doc, "vector")); - BSON_ASSERT (bson_vector_packed_bits_const_view_from_iter (&view, &iter)); - BSON_ASSERT (bson_vector_packed_bits_const_view_length (view) == current_length); - BSON_ASSERT (bson_vector_packed_bits_const_view_length_bytes (view) == current_length_bytes); - BSON_ASSERT (bson_vector_packed_bits_const_view_read_packed (view, packed_buffer, byte_count, byte_offset)); + BSON_ASSERT (bson_vector_packed_bit_const_view_from_iter (&view, &iter)); + BSON_ASSERT (bson_vector_packed_bit_const_view_length (view) == current_length); + BSON_ASSERT (bson_vector_packed_bit_const_view_length_bytes (view) == current_length_bytes); + BSON_ASSERT (bson_vector_packed_bit_const_view_read_packed (view, packed_buffer, byte_count, byte_offset)); for (size_t i = 0; i < byte_count; i++) { uint8_t packed_byte = packed_buffer[i]; for (unsigned bit = 0; bit < 8; bit++) { @@ -1285,37 +1285,37 @@ test_bson_vector_example_float32_view (void) } static void -test_bson_vector_example_packed_bits_const_view (void) +test_bson_vector_example_packed_bit_const_view (void) { // setup: construct a sample document bson_t doc = BSON_INITIALIZER; { static const bool values[] = {true, false, true, true, false, true, false, true, true, false}; - bson_vector_packed_bits_view_t view; - BSON_ASSERT (BSON_APPEND_VECTOR_PACKED_BITS (&doc, "vector", sizeof values / sizeof values[0], &view)); - BSON_ASSERT (bson_vector_packed_bits_view_pack_bool (view, values, sizeof values / sizeof values[0], 0)); + bson_vector_packed_bit_view_t view; + BSON_ASSERT (BSON_APPEND_VECTOR_PACKED_BIT (&doc, "vector", sizeof values / sizeof values[0], &view)); + BSON_ASSERT (bson_vector_packed_bit_view_pack_bool (view, values, sizeof values / sizeof values[0], 0)); } - // bson_vector_packed_bits_const_view_t.rst + // bson_vector_packed_bit_const_view_t.rst // Edits: // - Added test_suite_debug_output() test. // - Added unnecessary zero initializer to work around false positive compiler warning. // (same as in bson_array_builder_append_vector_int8_elements) { bson_iter_t iter; - bson_vector_packed_bits_const_view_t view; + bson_vector_packed_bit_const_view_t view; - if (bson_iter_init_find (&iter, &doc, "vector") && bson_vector_packed_bits_const_view_from_iter (&view, &iter)) { - size_t length = bson_vector_packed_bits_const_view_length (view); - size_t length_bytes = bson_vector_packed_bits_const_view_length_bytes (view); - size_t padding = bson_vector_packed_bits_const_view_padding (view); + if (bson_iter_init_find (&iter, &doc, "vector") && bson_vector_packed_bit_const_view_from_iter (&view, &iter)) { + size_t length = bson_vector_packed_bit_const_view_length (view); + size_t length_bytes = bson_vector_packed_bit_const_view_length_bytes (view); + size_t padding = bson_vector_packed_bit_const_view_padding (view); if (test_suite_debug_output ()) { printf ("Elements in 'vector':\n"); } for (size_t i = 0; i < length; i++) { bool element; - BSON_ASSERT (bson_vector_packed_bits_const_view_unpack_bool (view, &element, 1, i)); + BSON_ASSERT (bson_vector_packed_bit_const_view_unpack_bool (view, &element, 1, i)); if (test_suite_debug_output ()) { printf (" elements[%d] = %d\n", (int) i, (int) element); } @@ -1326,7 +1326,7 @@ test_bson_vector_example_packed_bits_const_view (void) } for (size_t i = 0; i < length_bytes; i++) { uint8_t packed_byte = 0; // Workaround - BSON_ASSERT (bson_vector_packed_bits_const_view_read_packed (view, &packed_byte, 1, i)); + BSON_ASSERT (bson_vector_packed_bit_const_view_read_packed (view, &packed_byte, 1, i)); if (test_suite_debug_output ()) { printf (" bytes[%d] = 0x%02x\n", (int) i, (unsigned) packed_byte); } @@ -1338,20 +1338,20 @@ test_bson_vector_example_packed_bits_const_view (void) } static void -test_bson_vector_example_packed_bits_view (void) +test_bson_vector_example_packed_bit_view (void) { bson_t doc = BSON_INITIALIZER; - // bson_vector_packed_bits_view_t.rst + // bson_vector_packed_bit_view_t.rst { // Fill a new vector with individual boolean elements { static const bool bool_values[] = {true, false, true, true, false}; const size_t bool_values_count = sizeof bool_values / sizeof bool_values[0]; - bson_vector_packed_bits_view_t view; - BSON_ASSERT (BSON_APPEND_VECTOR_PACKED_BITS (&doc, "from_bool", bool_values_count, &view)); - BSON_ASSERT (bson_vector_packed_bits_view_pack_bool (view, bool_values, bool_values_count, 0)); + bson_vector_packed_bit_view_t view; + BSON_ASSERT (BSON_APPEND_VECTOR_PACKED_BIT (&doc, "from_bool", bool_values_count, &view)); + BSON_ASSERT (bson_vector_packed_bit_view_pack_bool (view, bool_values, bool_values_count, 0)); } // Fill another new vector with packed bytes @@ -1360,9 +1360,9 @@ test_bson_vector_example_packed_bits_view (void) const size_t unused_bits_count = 3; const size_t packed_values_count = sizeof packed_bytes * 8 - unused_bits_count; - bson_vector_packed_bits_view_t view; - BSON_ASSERT (BSON_APPEND_VECTOR_PACKED_BITS (&doc, "from_packed", packed_values_count, &view)); - BSON_ASSERT (bson_vector_packed_bits_view_write_packed (view, packed_bytes, sizeof packed_bytes, 0)); + bson_vector_packed_bit_view_t view; + BSON_ASSERT (BSON_APPEND_VECTOR_PACKED_BIT (&doc, "from_packed", packed_values_count, &view)); + BSON_ASSERT (bson_vector_packed_bit_view_write_packed (view, packed_bytes, sizeof packed_bytes, 0)); } // Compare both vectors. They match exactly. @@ -1384,17 +1384,17 @@ test_bson_vector_install (TestSuite *suite) TestSuite_Add (suite, "/bson_binary_vector/view_api/usage/int8", test_bson_vector_view_api_usage_int8); TestSuite_Add (suite, "/bson_binary_vector/view_api/usage/float32", test_bson_vector_view_api_usage_float32); - TestSuite_Add (suite, "/bson_binary_vector/view_api/usage/packed_bits", test_bson_vector_view_api_usage_packed_bits); + TestSuite_Add (suite, "/bson_binary_vector/view_api/usage/packed_bit", test_bson_vector_view_api_usage_packed_bit); TestSuite_Add (suite, "/bson_binary_vector/view_api/fuzz/int8", test_bson_vector_view_api_fuzz_int8); TestSuite_Add (suite, "/bson_binary_vector/view_api/fuzz/float32", test_bson_vector_view_api_fuzz_float32); - TestSuite_Add (suite, "/bson_binary_vector/view_api/fuzz/packed_bits", test_bson_vector_view_api_fuzz_packed_bits); + TestSuite_Add (suite, "/bson_binary_vector/view_api/fuzz/packed_bit", test_bson_vector_view_api_fuzz_packed_bit); TestSuite_Add (suite, "/bson_binary_vector/example/int8_const_view", test_bson_vector_example_int8_const_view); TestSuite_Add (suite, "/bson_binary_vector/example/int8_view", test_bson_vector_example_int8_view); TestSuite_Add (suite, "/bson_binary_vector/example/float32_const_view", test_bson_vector_example_float32_const_view); TestSuite_Add (suite, "/bson_binary_vector/example/float32_view", test_bson_vector_example_float32_view); TestSuite_Add ( - suite, "/bson_binary_vector/example/packed_bits_const_view", test_bson_vector_example_packed_bits_const_view); - TestSuite_Add (suite, "/bson_binary_vector/example/packed_bits_view", test_bson_vector_example_packed_bits_view); + suite, "/bson_binary_vector/example/packed_bit_const_view", test_bson_vector_example_packed_bit_const_view); + TestSuite_Add (suite, "/bson_binary_vector/example/packed_bit_view", test_bson_vector_example_packed_bit_view); } From a17e71621648d9be2502b5acc1a429a89b632759 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Wed, 26 Feb 2025 11:52:36 -0800 Subject: [PATCH 23/51] Represent array keys with uint32_t not size_t --- src/libbson/src/bson/bson-vector.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/libbson/src/bson/bson-vector.c b/src/libbson/src/bson/bson-vector.c index a1d67be5a44..82263245402 100644 --- a/src/libbson/src/bson/bson-vector.c +++ b/src/libbson/src/bson/bson-vector.c @@ -368,7 +368,7 @@ bson_append_vector_packed_bit ( } static bool -bson_vector_from_array_expect_key (const bson_iter_t *iter, size_t numeric_key, bson_error_t *error) +bson_vector_from_array_expect_key (const bson_iter_t *iter, uint32_t numeric_key, bson_error_t *error) { char buffer[16]; const char *key; @@ -401,7 +401,7 @@ bson_append_vector_int8_from_array ( BSON_ASSERT_PARAM (key); BSON_ASSERT_PARAM (iter); - size_t element_count = 0; + uint32_t element_count = 0; { bson_iter_t validation_iter = *iter; while (bson_iter_next (&validation_iter)) { @@ -437,7 +437,7 @@ bson_append_vector_int8_from_array ( return false; } bson_iter_t copy_iter = *iter; - for (size_t i = 0; i < element_count; i++) { + for (uint32_t i = 0; i < element_count; i++) { BSON_ASSERT (bson_iter_next (©_iter)); int8_t element = (int8_t) bson_iter_as_int64 (©_iter); BSON_ASSERT (bson_vector_int8_view_write (view, &element, 1, i)); @@ -453,7 +453,7 @@ bson_append_vector_float32_from_array ( BSON_ASSERT_PARAM (key); BSON_ASSERT_PARAM (iter); - size_t element_count = 0; + uint32_t element_count = 0; { bson_iter_t validation_iter = *iter; while (bson_iter_next (&validation_iter)) { @@ -479,7 +479,7 @@ bson_append_vector_float32_from_array ( return false; } bson_iter_t copy_iter = *iter; - for (size_t i = 0; i < element_count; i++) { + for (uint32_t i = 0; i < element_count; i++) { BSON_ASSERT (bson_iter_next (©_iter)); float element = (float) bson_iter_double (©_iter); BSON_ASSERT (bson_vector_float32_view_write (view, &element, 1, i)); @@ -495,7 +495,7 @@ bson_append_vector_packed_bit_from_array ( BSON_ASSERT_PARAM (key); BSON_ASSERT_PARAM (iter); - size_t element_count = 0; + uint32_t element_count = 0; { bson_iter_t validation_iter = *iter; while (bson_iter_next (&validation_iter)) { @@ -531,7 +531,7 @@ bson_append_vector_packed_bit_from_array ( return false; } bson_iter_t copy_iter = *iter; - for (size_t i = 0; i < element_count; i++) { + for (uint32_t i = 0; i < element_count; i++) { BSON_ASSERT (bson_iter_next (©_iter)); bool element_as_bool = (bool) bson_iter_as_int64 (©_iter); BSON_ASSERT (bson_vector_packed_bit_view_pack_bool (view, &element_as_bool, 1, i)); From f3527ec195c3c0425aaa1aefcde409bfc120dc61 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Wed, 26 Feb 2025 16:18:18 -0800 Subject: [PATCH 24/51] In public headers, disable pointer arithmetic warnings from -Weverything --- src/libbson/src/bson/bson-vector.h | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/libbson/src/bson/bson-vector.h b/src/libbson/src/bson/bson-vector.h index 501f8e12c4d..564cfff7fca 100644 --- a/src/libbson/src/bson/bson-vector.h +++ b/src/libbson/src/bson/bson-vector.h @@ -262,13 +262,17 @@ bson_append_array_from_vector_packed_bit (bson_t *bson, static BSON_INLINE const int8_t * bson_vector_int8_const_view_pointer (bson_vector_int8_const_view_t view) { + BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_BEGIN return (const int8_t *) (view.binary.data + BSON_VECTOR_HEADER_LEN); + BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_END } static BSON_INLINE int8_t * bson_vector_int8_view_pointer (bson_vector_int8_view_t view) { + BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_BEGIN return (int8_t *) (view.binary.data + BSON_VECTOR_HEADER_LEN); + BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_END } @@ -345,7 +349,9 @@ bson_vector_padding_from_header_byte_1 (uint8_t byte_1) static BSON_INLINE size_t bson_vector_packed_bit_const_view_padding (bson_vector_packed_bit_const_view_t view) { + BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_BEGIN return bson_vector_padding_from_header_byte_1 (view.binary.header_copy.bytes[1]); + BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_END } static BSON_INLINE size_t @@ -375,7 +381,9 @@ bson_vector_int8_const_view_read (bson_vector_int8_const_view_t view, { size_t length = bson_vector_int8_const_view_length (view); if (BSON_LIKELY (vector_offset_elements <= length && element_count <= length - vector_offset_elements)) { + BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_BEGIN memcpy (values_out, bson_vector_int8_const_view_pointer (view) + vector_offset_elements, element_count); + BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_END return true; } else { return false; @@ -400,7 +408,9 @@ bson_vector_int8_view_write (bson_vector_int8_view_t view, { size_t length = bson_vector_int8_view_length (view); if (BSON_LIKELY (vector_offset_elements <= length && element_count <= length - vector_offset_elements)) { + BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_BEGIN memcpy (bson_vector_int8_view_pointer (view) + vector_offset_elements, values, element_count); + BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_END return true; } else { return false; @@ -419,6 +429,7 @@ bson_vector_float32_const_view_read (bson_vector_float32_const_view_t view, size_t length = bson_vector_float32_const_view_length (view); if (BSON_LIKELY (vector_offset_elements <= length && element_count <= length - vector_offset_elements)) { size_t byte_offset = BSON_VECTOR_HEADER_LEN + vector_offset_elements * 4; + BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_BEGIN #if BSON_BYTE_ORDER == BSON_LITTLE_ENDIAN memcpy (values_out, view.binary.data + byte_offset, element_count * 4); #else @@ -429,6 +440,7 @@ bson_vector_float32_const_view_read (bson_vector_float32_const_view_t view, values_out[i] = BSON_FLOAT_FROM_LE (aligned_tmp); } #endif + BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_END return true; } else { return false; @@ -454,6 +466,7 @@ bson_vector_float32_view_write (bson_vector_float32_view_t view, size_t length = bson_vector_float32_view_length (view); if (BSON_LIKELY (vector_offset_elements <= length && element_count <= length - vector_offset_elements)) { size_t byte_offset = BSON_VECTOR_HEADER_LEN + vector_offset_elements * 4; + BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_BEGIN #if BSON_BYTE_ORDER == BSON_LITTLE_ENDIAN memcpy (view.binary.data + byte_offset, values, element_count * 4); #else @@ -463,6 +476,7 @@ bson_vector_float32_view_write (bson_vector_float32_view_t view, memcpy (view.binary.data + byte_offset + i * 4, &aligned_tmp, 4); } #endif + BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_END return true; } else { return false; @@ -478,7 +492,9 @@ bson_vector_packed_bit_const_view_read_packed (bson_vector_packed_bit_const_view { size_t length_bytes = bson_vector_packed_bit_const_view_length_bytes (view); if (BSON_LIKELY (vector_offset_bytes <= length_bytes && byte_count <= length_bytes - vector_offset_bytes)) { + BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_BEGIN memcpy (packed_values_out, view.binary.data + BSON_VECTOR_HEADER_LEN + vector_offset_bytes, byte_count); + BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_END return true; } else { return false; @@ -503,6 +519,7 @@ bson_vector_packed_bit_view_write_packed (bson_vector_packed_bit_view_t view, { size_t length_bytes = bson_vector_packed_bit_view_length_bytes (view); if (BSON_LIKELY (vector_offset_bytes <= length_bytes && byte_count <= length_bytes - vector_offset_bytes)) { + BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_BEGIN if (byte_count == length_bytes - vector_offset_bytes && byte_count >= 1u) { // This write touches the last byte in the vector: // special-case that byte so we can ensure unused bits remain set to zero. @@ -513,6 +530,7 @@ bson_vector_packed_bit_view_write_packed (bson_vector_packed_bit_view_t view, } else { memcpy (view.binary.data + BSON_VECTOR_HEADER_LEN + vector_offset_bytes, packed_values, byte_count); } + BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_END return true; } else { return false; @@ -531,8 +549,10 @@ bson_vector_packed_bit_const_view_unpack_bool (bson_vector_packed_bit_const_view size_t i; for (i = 0; i < element_count; i++) { size_t element_index = vector_offset_elements + i; + BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_BEGIN uint8_t packed_byte = view.binary.data[BSON_VECTOR_HEADER_LEN + (element_index >> 3)]; unpacked_values_out[i] = 0 != (packed_byte & ((uint8_t) 0x80 >> (element_index & 7))); + BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_END } return true; } else { @@ -559,6 +579,7 @@ bson_vector_packed_bit_view_pack_bool (bson_vector_packed_bit_view_t view, size_t length = bson_vector_packed_bit_view_length (view); if (BSON_LIKELY (vector_offset_elements <= length && element_count <= length - vector_offset_elements)) { while (element_count > 0) { + BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_BEGIN uint8_t *BSON_RESTRICT packed_byte = &view.binary.data[BSON_VECTOR_HEADER_LEN + (vector_offset_elements >> 3)]; if (element_count >= 8 && (vector_offset_elements & 7) == 0) { uint8_t complete_byte = 0; @@ -577,6 +598,7 @@ bson_vector_packed_bit_view_pack_bool (bson_vector_packed_bit_view_t view, vector_offset_elements++; element_count--; } + BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_END } return true; } else { From dc9d22f05025f07070b9b1d69bd2fb1c487e4d13 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Wed, 26 Feb 2025 16:20:08 -0800 Subject: [PATCH 25/51] Style change, prefer to write element address calculation as plain addition rather than address of subscript --- src/libbson/src/bson/bson-vector.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libbson/src/bson/bson-vector.h b/src/libbson/src/bson/bson-vector.h index 564cfff7fca..48fb0158b21 100644 --- a/src/libbson/src/bson/bson-vector.h +++ b/src/libbson/src/bson/bson-vector.h @@ -580,7 +580,7 @@ bson_vector_packed_bit_view_pack_bool (bson_vector_packed_bit_view_t view, if (BSON_LIKELY (vector_offset_elements <= length && element_count <= length - vector_offset_elements)) { while (element_count > 0) { BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_BEGIN - uint8_t *BSON_RESTRICT packed_byte = &view.binary.data[BSON_VECTOR_HEADER_LEN + (vector_offset_elements >> 3)]; + uint8_t *BSON_RESTRICT packed_byte = BSON_VECTOR_HEADER_LEN + (vector_offset_elements >> 3) + view.binary.data; if (element_count >= 8 && (vector_offset_elements & 7) == 0) { uint8_t complete_byte = 0; unsigned i; From 150d9c2bcbaad8d54105fd25539b79ce82ae59f4 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Wed, 26 Feb 2025 16:58:46 -0800 Subject: [PATCH 26/51] Add _uninit suffix to allocators for uninitialized vectors --- src/libbson/doc/binary_vector.rst | 6 +-- ... => bson_append_vector_float32_uninit.rst} | 22 ++++----- ...rst => bson_append_vector_int8_uninit.rst} | 22 ++++----- ... bson_append_vector_packed_bit_uninit.rst} | 20 ++++---- .../doc/bson_vector_float32_view_t.rst | 4 +- src/libbson/doc/bson_vector_int8_view_t.rst | 4 +- .../doc/bson_vector_packed_bit_view_t.rst | 6 +-- src/libbson/src/bson/bson-vector.c | 12 ++--- src/libbson/src/bson/bson-vector.h | 16 +++---- src/libbson/tests/test-bson-vector.c | 46 +++++++++---------- 10 files changed, 79 insertions(+), 79 deletions(-) rename src/libbson/doc/{bson_append_vector_float32.rst => bson_append_vector_float32_uninit.rst} (56%) rename src/libbson/doc/{bson_append_vector_int8.rst => bson_append_vector_int8_uninit.rst} (57%) rename src/libbson/doc/{bson_append_vector_packed_bit.rst => bson_append_vector_packed_bit_uninit.rst} (58%) diff --git a/src/libbson/doc/binary_vector.rst b/src/libbson/doc/binary_vector.rst index a9c72ae8fee..5891f3a029a 100644 --- a/src/libbson/doc/binary_vector.rst +++ b/src/libbson/doc/binary_vector.rst @@ -40,9 +40,9 @@ Integration :titlesonly: :maxdepth: 1 - bson_append_vector_int8 - bson_append_vector_float32 - bson_append_vector_packed_bit + bson_append_vector_int8_uninit + bson_append_vector_float32_uninit + bson_append_vector_packed_bit_uninit * Accessing an existing Vector via :symbol:`bson_iter_t`: diff --git a/src/libbson/doc/bson_append_vector_float32.rst b/src/libbson/doc/bson_append_vector_float32_uninit.rst similarity index 56% rename from src/libbson/doc/bson_append_vector_float32.rst rename to src/libbson/doc/bson_append_vector_float32_uninit.rst index ecdbb5194f4..2a1989100e6 100644 --- a/src/libbson/doc/bson_append_vector_float32.rst +++ b/src/libbson/doc/bson_append_vector_float32_uninit.rst @@ -1,22 +1,22 @@ -:man_page: bson_append_vector_float32 +:man_page: bson_append_vector_float32_uninit -bson_append_vector_float32() -============================ +bson_append_vector_float32_uninit() +=================================== Synopsis -------- .. code-block:: c - #define BSON_APPEND_VECTOR_FLOAT32(b, key, count, view) \ - bson_append_vector_float32 (b, key, (int) strlen (key), count, view) + #define BSON_APPEND_VECTOR_FLOAT32_UNINIT(b, key, count, view) \ + bson_append_vector_float32_uninit (b, key, (int) strlen (key), count, view) bool - bson_append_vector_float32 (bson_t *bson, - const char *key, - int key_length, - size_t element_count, - bson_vector_float32_view_t *view_out); + bson_append_vector_float32_uninit (bson_t *bson, + const char *key, + int key_length, + size_t element_count, + bson_vector_float32_view_t *view_out); Parameters ---------- @@ -34,7 +34,7 @@ Appends a new field to ``bson`` by allocating a Vector with the indicated number The elements will be uninitialized. On success, the caller must write every element in the Vector if the resulting :symbol:`bson_t` is to be used. -The pointer written to ``*view_out`` is only valid until ``bson`` is otherwise modified or freed. +The view written to ``*view_out`` is only valid until ``bson`` is otherwise modified or freed. Returns ------- diff --git a/src/libbson/doc/bson_append_vector_int8.rst b/src/libbson/doc/bson_append_vector_int8_uninit.rst similarity index 57% rename from src/libbson/doc/bson_append_vector_int8.rst rename to src/libbson/doc/bson_append_vector_int8_uninit.rst index ae71794aec9..62234f5c632 100644 --- a/src/libbson/doc/bson_append_vector_int8.rst +++ b/src/libbson/doc/bson_append_vector_int8_uninit.rst @@ -1,22 +1,22 @@ -:man_page: bson_append_vector_int8 +:man_page: bson_append_vector_int8_uninit -bson_append_vector_int8() -========================= +bson_append_vector_int8_uninit() +================================ Synopsis -------- .. code-block:: c - #define BSON_APPEND_VECTOR_INT8(b, key, count, view) \ - bson_append_vector_int8 (b, key, (int) strlen (key), count, view) + #define BSON_APPEND_VECTOR_INT8_UNINIT(b, key, count, view) \ + bson_append_vector_int8_uninit (b, key, (int) strlen (key), count, view) bool - bson_append_vector_int8 (bson_t *bson, - const char *key, - int key_length, - size_t element_count, - bson_vector_int8_view_t *view_out); + bson_append_vector_int8_uninit (bson_t *bson, + const char *key, + int key_length, + size_t element_count, + bson_vector_int8_view_t *view_out); Parameters ---------- @@ -34,7 +34,7 @@ Appends a new field to ``bson`` by allocating a Vector with the indicated number The elements will be uninitialized. On success, the caller must write every element in the Vector if the resulting :symbol:`bson_t` is to be used. -The pointer written to ``*view_out`` is only valid until ``bson`` is otherwise modified or freed. +The view written to ``*view_out`` is only valid until ``bson`` is otherwise modified or freed. Returns ------- diff --git a/src/libbson/doc/bson_append_vector_packed_bit.rst b/src/libbson/doc/bson_append_vector_packed_bit_uninit.rst similarity index 58% rename from src/libbson/doc/bson_append_vector_packed_bit.rst rename to src/libbson/doc/bson_append_vector_packed_bit_uninit.rst index 7f57463c4c1..8aaff981e92 100644 --- a/src/libbson/doc/bson_append_vector_packed_bit.rst +++ b/src/libbson/doc/bson_append_vector_packed_bit_uninit.rst @@ -1,6 +1,6 @@ -:man_page: bson_append_vector_packed_bit +:man_page: bson_append_vector_packed_bit_uninit -bson_append_vector_packed_bit() +bson_append_vector_packed_bit_uninit() =============================== Synopsis @@ -8,15 +8,15 @@ Synopsis .. code-block:: c - #define BSON_APPEND_VECTOR_PACKED_BIT(b, key, count, view) \ - bson_append_vector_packed_bit (b, key, (int) strlen (key), count, view) + #define BSON_APPEND_VECTOR_PACKED_BIT_UNINIT(b, key, count, view) \ + bson_append_vector_packed_bit_uninit (b, key, (int) strlen (key), count, view) bool - bson_append_vector_packed_bit (bson_t *bson, - const char *key, - int key_length, - size_t element_count, - bson_vector_packed_bit_view_t *view_out); + bson_append_vector_packed_bit_uninit (bson_t *bson, + const char *key, + int key_length, + size_t element_count, + bson_vector_packed_bit_view_t *view_out); Parameters ---------- @@ -34,7 +34,7 @@ Appends a new field to ``bson`` by allocating a Vector with the indicated number The elements will be uninitialized. On success, the caller must write every element in the Vector if the resulting :symbol:`bson_t` is to be used. -The pointer written to ``*view_out`` is only valid until ``bson`` is otherwise modified or freed. +The view written to ``*view_out`` is only valid until ``bson`` is otherwise modified or freed. Returns ------- diff --git a/src/libbson/doc/bson_vector_float32_view_t.rst b/src/libbson/doc/bson_vector_float32_view_t.rst index 7dabfc8d5ba..bdd7fa5b217 100644 --- a/src/libbson/doc/bson_vector_float32_view_t.rst +++ b/src/libbson/doc/bson_vector_float32_view_t.rst @@ -50,10 +50,10 @@ Example const size_t values_count = sizeof values / sizeof values[0]; bson_vector_float32_view_t view; - BSON_ASSERT (BSON_APPEND_VECTOR_FLOAT32 (&doc, "vector", values_count, &view)); + BSON_ASSERT (BSON_APPEND_VECTOR_FLOAT32_UNINIT (&doc, "vector", values_count, &view)); BSON_ASSERT (bson_vector_float32_view_write (view, values, values_count, 0)); .. seealso:: - | :symbol:`bson_append_vector_float32` + | :symbol:`bson_append_vector_float32_uninit` | :symbol:`bson_vector_float32_const_view_t` diff --git a/src/libbson/doc/bson_vector_int8_view_t.rst b/src/libbson/doc/bson_vector_int8_view_t.rst index 2268ab38f3c..663b184203d 100644 --- a/src/libbson/doc/bson_vector_int8_view_t.rst +++ b/src/libbson/doc/bson_vector_int8_view_t.rst @@ -51,10 +51,10 @@ Example const size_t values_count = sizeof values / sizeof values[0]; bson_vector_int8_view_t view; - BSON_ASSERT (BSON_APPEND_VECTOR_INT8 (&doc, "vector", values_count, &view)); + BSON_ASSERT (BSON_APPEND_VECTOR_INT8_UNINIT (&doc, "vector", values_count, &view)); BSON_ASSERT (bson_vector_int8_view_write (view, values, values_count, 0)); .. seealso:: - | :symbol:`bson_append_vector_int8` + | :symbol:`bson_append_vector_int8_uninit` | :symbol:`bson_vector_int8_const_view_t` diff --git a/src/libbson/doc/bson_vector_packed_bit_view_t.rst b/src/libbson/doc/bson_vector_packed_bit_view_t.rst index 601521b371a..0d747a5b63c 100644 --- a/src/libbson/doc/bson_vector_packed_bit_view_t.rst +++ b/src/libbson/doc/bson_vector_packed_bit_view_t.rst @@ -56,7 +56,7 @@ Example const size_t bool_values_count = sizeof bool_values / sizeof bool_values[0]; bson_vector_packed_bit_view_t view; - BSON_ASSERT (BSON_APPEND_VECTOR_PACKED_BIT (&doc, "from_bool", bool_values_count, &view)); + BSON_ASSERT (BSON_APPEND_VECTOR_PACKED_BIT_UNINIT (&doc, "from_bool", bool_values_count, &view)); BSON_ASSERT (bson_vector_packed_bit_view_pack_bool (view, bool_values, bool_values_count, 0)); } @@ -67,7 +67,7 @@ Example const size_t packed_values_count = sizeof packed_bytes * 8 - unused_bits_count; bson_vector_packed_bit_view_t view; - BSON_ASSERT (BSON_APPEND_VECTOR_PACKED_BIT (&doc, "from_packed", packed_values_count, &view)); + BSON_ASSERT (BSON_APPEND_VECTOR_PACKED_BIT_UNINIT (&doc, "from_packed", packed_values_count, &view)); BSON_ASSERT (bson_vector_packed_bit_view_write_packed (view, packed_bytes, sizeof packed_bytes, 0)); } @@ -81,5 +81,5 @@ Example .. seealso:: - | :symbol:`bson_append_vector_packed_bit` + | :symbol:`bson_append_vector_packed_bit_uninit` | :symbol:`bson_vector_packed_bit_const_view_t` diff --git a/src/libbson/src/bson/bson-vector.c b/src/libbson/src/bson/bson-vector.c index 82263245402..dc3e8d61596 100644 --- a/src/libbson/src/bson/bson-vector.c +++ b/src/libbson/src/bson/bson-vector.c @@ -287,7 +287,7 @@ bson_vector_packed_bit_const_view_from_iter (bson_vector_packed_bit_const_view_t bool -bson_append_vector_int8 ( +bson_append_vector_int8_uninit ( bson_t *bson, const char *key, int key_length, size_t element_count, bson_vector_int8_view_t *view_out) { BSON_ASSERT_PARAM (bson); @@ -312,7 +312,7 @@ bson_append_vector_int8 ( } bool -bson_append_vector_float32 ( +bson_append_vector_float32_uninit ( bson_t *bson, const char *key, int key_length, size_t element_count, bson_vector_float32_view_t *view_out) { BSON_ASSERT_PARAM (bson); @@ -337,7 +337,7 @@ bson_append_vector_float32 ( } bool -bson_append_vector_packed_bit ( +bson_append_vector_packed_bit_uninit ( bson_t *bson, const char *key, int key_length, size_t element_count, bson_vector_packed_bit_view_t *view_out) { BSON_ASSERT_PARAM (bson); @@ -432,7 +432,7 @@ bson_append_vector_int8_from_array ( } bson_vector_int8_view_t view; - if (!bson_append_vector_int8 (bson, key, key_length, element_count, &view)) { + if (!bson_append_vector_int8_uninit (bson, key, key_length, element_count, &view)) { bson_vector_set_error_max_size (error); return false; } @@ -474,7 +474,7 @@ bson_append_vector_float32_from_array ( } bson_vector_float32_view_t view; - if (!bson_append_vector_float32 (bson, key, key_length, element_count, &view)) { + if (!bson_append_vector_float32_uninit (bson, key, key_length, element_count, &view)) { bson_vector_set_error_max_size (error); return false; } @@ -526,7 +526,7 @@ bson_append_vector_packed_bit_from_array ( } bson_vector_packed_bit_view_t view; - if (!bson_append_vector_packed_bit (bson, key, key_length, element_count, &view)) { + if (!bson_append_vector_packed_bit_uninit (bson, key, key_length, element_count, &view)) { bson_vector_set_error_max_size (error); return false; } diff --git a/src/libbson/src/bson/bson-vector.h b/src/libbson/src/bson/bson-vector.h index 48fb0158b21..44562e118d7 100644 --- a/src/libbson/src/bson/bson-vector.h +++ b/src/libbson/src/bson/bson-vector.h @@ -192,24 +192,24 @@ bson_array_builder_append_vector_elements (struct _bson_array_builder_t *builder BSON_EXPORT (bool) -bson_append_vector_int8 ( +bson_append_vector_int8_uninit ( bson_t *bson, const char *key, int key_length, size_t element_count, bson_vector_int8_view_t *view_out); -#define BSON_APPEND_VECTOR_INT8(b, key, count, view) bson_append_vector_int8 (b, key, (int) strlen (key), count, view) +#define BSON_APPEND_VECTOR_INT8_UNINIT(b, key, count, view) bson_append_vector_int8_uninit (b, key, (int) strlen (key), count, view) BSON_EXPORT (bool) -bson_append_vector_float32 ( +bson_append_vector_float32_uninit ( bson_t *bson, const char *key, int key_length, size_t element_count, bson_vector_float32_view_t *view_out); -#define BSON_APPEND_VECTOR_FLOAT32(b, key, count, view) \ - bson_append_vector_float32 (b, key, (int) strlen (key), count, view) +#define BSON_APPEND_VECTOR_FLOAT32_UNINIT(b, key, count, view) \ + bson_append_vector_float32_uninit (b, key, (int) strlen (key), count, view) BSON_EXPORT (bool) -bson_append_vector_packed_bit ( +bson_append_vector_packed_bit_uninit ( bson_t *bson, const char *key, int key_length, size_t element_count, bson_vector_packed_bit_view_t *view_out); -#define BSON_APPEND_VECTOR_PACKED_BIT(b, key, count, view) \ - bson_append_vector_packed_bit (b, key, (int) strlen (key), count, view) +#define BSON_APPEND_VECTOR_PACKED_BIT_UNINIT(b, key, count, view) \ + bson_append_vector_packed_bit_uninit (b, key, (int) strlen (key), count, view) BSON_EXPORT (bool) diff --git a/src/libbson/tests/test-bson-vector.c b/src/libbson/tests/test-bson-vector.c index b500e10e61a..d4f194e1d30 100644 --- a/src/libbson/tests/test-bson-vector.c +++ b/src/libbson/tests/test-bson-vector.c @@ -140,7 +140,7 @@ append_vector_packed_bit_from_packed_array ( } bson_vector_packed_bit_view_t view; - if (bson_append_vector_packed_bit (bson, key, key_length, byte_count * 8u - (size_t) padding, &view)) { + if (bson_append_vector_packed_bit_uninit (bson, key, key_length, byte_count * 8u - (size_t) padding, &view)) { bson_iter_t copy_iter = *iter; for (size_t i = 0; i < byte_count; i++) { BSON_ASSERT (bson_iter_next (©_iter)); @@ -502,7 +502,7 @@ test_bson_vector_view_api_usage_int8 (void) { bson_vector_int8_view_t view; const size_t length = 25; - ASSERT (BSON_APPEND_VECTOR_INT8 (&doc, "vector", length, &view)); + ASSERT (BSON_APPEND_VECTOR_INT8_UNINIT (&doc, "vector", length, &view)); for (size_t i = 0; i < length; i++) { int8_t v = (int8_t) i - 9; bson_vector_int8_view_write (view, &v, 1, i); @@ -517,7 +517,7 @@ test_bson_vector_view_api_usage_int8 (void) { bson_vector_int8_view_t view; const size_t length = 50000; - ASSERT (bson_append_vector_int8 (&doc, "longer_vector", -1, length, &view)); + ASSERT (bson_append_vector_int8_uninit (&doc, "longer_vector", -1, length, &view)); for (size_t i = 0; i < length; i++) { int8_t v = (int8_t) (uint8_t) i; bson_vector_int8_view_write (view, &v, 1, i); @@ -528,7 +528,7 @@ test_bson_vector_view_api_usage_int8 (void) { bson_vector_int8_view_t view; const size_t length = UINT32_MAX - 1; - ASSERT (!bson_append_vector_int8 (&doc, "overlong_vector", -1, length, &view)); + ASSERT (!bson_append_vector_int8_uninit (&doc, "overlong_vector", -1, length, &view)); } // Use a mutable view to partially overwrite "vector" @@ -628,7 +628,7 @@ test_bson_vector_view_api_usage_float32 (void) { bson_vector_float32_view_t view; const size_t length = 5; - ASSERT (BSON_APPEND_VECTOR_FLOAT32 (&doc, "vector", length, &view)); + ASSERT (BSON_APPEND_VECTOR_FLOAT32_UNINIT (&doc, "vector", length, &view)); for (size_t i = 0; i < length; i++) { float v = 1.0f + 0.25f * (float) i; bson_vector_float32_view_write (view, &v, 1, i); @@ -643,7 +643,7 @@ test_bson_vector_view_api_usage_float32 (void) { bson_vector_float32_view_t view; const size_t length = 10000; - ASSERT (bson_append_vector_float32 (&doc, "longer_vector", -1, length, &view)); + ASSERT (bson_append_vector_float32_uninit (&doc, "longer_vector", -1, length, &view)); for (size_t i = 0; i < length; i++) { float v = (float) i; bson_vector_float32_view_write (view, &v, 1, i); @@ -654,7 +654,7 @@ test_bson_vector_view_api_usage_float32 (void) { bson_vector_float32_view_t view; const size_t length = (UINT32_MAX - 1) / 4; - ASSERT (!bson_append_vector_float32 (&doc, "overlong_vector", -1, length, &view)); + ASSERT (!bson_append_vector_float32_uninit (&doc, "overlong_vector", -1, length, &view)); } // Read the small vector into a float array @@ -740,7 +740,7 @@ test_bson_vector_view_api_usage_packed_bit (void) { bson_vector_packed_bit_view_t view; const size_t length = 123; - ASSERT (BSON_APPEND_VECTOR_PACKED_BIT (&doc, "vector", length, &view)); + ASSERT (BSON_APPEND_VECTOR_PACKED_BIT_UNINIT (&doc, "vector", length, &view)); for (size_t i = 0; i < length; i++) { bool v = (i & 1) != 0; bson_vector_packed_bit_view_pack_bool (view, &v, 1, i); @@ -754,7 +754,7 @@ test_bson_vector_view_api_usage_packed_bit (void) { bson_vector_packed_bit_view_t view; const size_t length = 100002; - ASSERT (bson_append_vector_packed_bit (&doc, "longer_vector", -1, length, &view)); + ASSERT (bson_append_vector_packed_bit_uninit (&doc, "longer_vector", -1, length, &view)); for (size_t i = 0; i < length; i++) { bool v = (i & 3) != 0; bson_vector_packed_bit_view_pack_bool (view, &v, 1, i); @@ -765,7 +765,7 @@ test_bson_vector_view_api_usage_packed_bit (void) { bson_vector_int8_view_t view; const size_t length = (UINT32_MAX - 1) * (size_t) 8; - ASSERT (!bson_append_vector_int8 (&doc, "overlong_vector", -1, length, &view)); + ASSERT (!bson_append_vector_int8_uninit (&doc, "overlong_vector", -1, length, &view)); } // Unpack the small vector into a bool array @@ -918,14 +918,14 @@ test_bson_vector_view_api_usage_packed_bit (void) } // Padding bits will be initialized to zero when a packed_bit vector is first allocated by - // bson_append_vector_packed_bit + // bson_append_vector_packed_bit_uninit { // Set the uninitialized part of 'doc' to a known value static const uint32_t reserve_len = 512; memset (bson_reserve_buffer (&doc, doc.len + reserve_len) + doc.len, 0xdd, reserve_len); bson_vector_packed_bit_view_t view; - ASSERT (BSON_APPEND_VECTOR_PACKED_BIT (&doc, "padding_init_test", 12, &view)); + ASSERT (BSON_APPEND_VECTOR_PACKED_BIT_UNINIT (&doc, "padding_init_test", 12, &view)); ASSERT (bson_vector_packed_bit_view_length_bytes (view) == 2); ASSERT (bson_vector_packed_bit_view_padding (view) == 4); @@ -940,7 +940,7 @@ test_bson_vector_view_api_usage_packed_bit (void) // Padding bits can't be forcibly given nonzero values using bson_vector_packed_bit_view_write_packed { bson_vector_packed_bit_view_t view; - ASSERT (BSON_APPEND_VECTOR_PACKED_BIT (&doc, "padding_mask_test", 13, &view)); + ASSERT (BSON_APPEND_VECTOR_PACKED_BIT_UNINIT (&doc, "padding_mask_test", 13, &view)); ASSERT (bson_vector_packed_bit_view_length_bytes (view) == 2); ASSERT (bson_vector_packed_bit_view_padding (view) == 3); @@ -974,7 +974,7 @@ test_bson_vector_view_api_fuzz_int8 (void) size_t new_length = (size_t) r_param % MAX_TESTED_VECTOR_LENGTH; bson_reinit (&vector_doc); bson_vector_int8_view_t view; - BSON_ASSERT (BSON_APPEND_VECTOR_INT8 (&vector_doc, "vector", new_length, &view)); + BSON_ASSERT (BSON_APPEND_VECTOR_INT8_UNINIT (&vector_doc, "vector", new_length, &view)); for (size_t i = 0; i < new_length; i++) { expected_elements[i] = (int8_t) (uint8_t) rand (); } @@ -1030,7 +1030,7 @@ test_bson_vector_view_api_fuzz_float32 (void) size_t new_length = (size_t) r_param % MAX_TESTED_VECTOR_LENGTH; bson_reinit (&vector_doc); bson_vector_float32_view_t view; - BSON_ASSERT (BSON_APPEND_VECTOR_FLOAT32 (&vector_doc, "vector", new_length, &view)); + BSON_ASSERT (BSON_APPEND_VECTOR_FLOAT32_UNINIT (&vector_doc, "vector", new_length, &view)); for (size_t i = 0; i < new_length; i++) { expected_elements[i] = (float) rand (); } @@ -1087,7 +1087,7 @@ test_bson_vector_view_api_fuzz_packed_bit (void) size_t new_length = (size_t) r_param % MAX_TESTED_VECTOR_LENGTH; bson_reinit (&vector_doc); bson_vector_packed_bit_view_t view; - BSON_ASSERT (BSON_APPEND_VECTOR_PACKED_BIT (&vector_doc, "vector", new_length, &view)); + BSON_ASSERT (BSON_APPEND_VECTOR_PACKED_BIT_UNINIT (&vector_doc, "vector", new_length, &view)); for (size_t i = 0; i < new_length; i++) { expected_elements[i] = (rand () & 1) != 0; } @@ -1180,7 +1180,7 @@ test_bson_vector_example_int8_const_view (void) { static const int8_t values[] = {12, 34, -56}; bson_vector_int8_view_t view; - BSON_ASSERT (BSON_APPEND_VECTOR_INT8 (&doc, "vector", sizeof values / sizeof values[0], &view)); + BSON_ASSERT (BSON_APPEND_VECTOR_INT8_UNINIT (&doc, "vector", sizeof values / sizeof values[0], &view)); BSON_ASSERT (bson_vector_int8_view_write (view, values, sizeof values / sizeof values[0], 0)); } @@ -1222,7 +1222,7 @@ test_bson_vector_example_int8_view (void) const size_t values_count = sizeof values / sizeof values[0]; bson_vector_int8_view_t view; - BSON_ASSERT (BSON_APPEND_VECTOR_INT8 (&doc, "vector", values_count, &view)); + BSON_ASSERT (BSON_APPEND_VECTOR_INT8_UNINIT (&doc, "vector", values_count, &view)); BSON_ASSERT (bson_vector_int8_view_write (view, values, values_count, 0)); } @@ -1237,7 +1237,7 @@ test_bson_vector_example_float32_const_view (void) { static const float values[] = {5.0f, -1e10f, (float) INFINITY, (float) NAN, -1.0f}; bson_vector_float32_view_t view; - BSON_ASSERT (BSON_APPEND_VECTOR_FLOAT32 (&doc, "vector", sizeof values / sizeof values[0], &view)); + BSON_ASSERT (BSON_APPEND_VECTOR_FLOAT32_UNINIT (&doc, "vector", sizeof values / sizeof values[0], &view)); BSON_ASSERT (bson_vector_float32_view_write (view, values, sizeof values / sizeof values[0], 0)); } @@ -1277,7 +1277,7 @@ test_bson_vector_example_float32_view (void) const size_t values_count = sizeof values / sizeof values[0]; bson_vector_float32_view_t view; - BSON_ASSERT (BSON_APPEND_VECTOR_FLOAT32 (&doc, "vector", values_count, &view)); + BSON_ASSERT (BSON_APPEND_VECTOR_FLOAT32_UNINIT (&doc, "vector", values_count, &view)); BSON_ASSERT (bson_vector_float32_view_write (view, values, values_count, 0)); } @@ -1292,7 +1292,7 @@ test_bson_vector_example_packed_bit_const_view (void) { static const bool values[] = {true, false, true, true, false, true, false, true, true, false}; bson_vector_packed_bit_view_t view; - BSON_ASSERT (BSON_APPEND_VECTOR_PACKED_BIT (&doc, "vector", sizeof values / sizeof values[0], &view)); + BSON_ASSERT (BSON_APPEND_VECTOR_PACKED_BIT_UNINIT (&doc, "vector", sizeof values / sizeof values[0], &view)); BSON_ASSERT (bson_vector_packed_bit_view_pack_bool (view, values, sizeof values / sizeof values[0], 0)); } @@ -1350,7 +1350,7 @@ test_bson_vector_example_packed_bit_view (void) const size_t bool_values_count = sizeof bool_values / sizeof bool_values[0]; bson_vector_packed_bit_view_t view; - BSON_ASSERT (BSON_APPEND_VECTOR_PACKED_BIT (&doc, "from_bool", bool_values_count, &view)); + BSON_ASSERT (BSON_APPEND_VECTOR_PACKED_BIT_UNINIT (&doc, "from_bool", bool_values_count, &view)); BSON_ASSERT (bson_vector_packed_bit_view_pack_bool (view, bool_values, bool_values_count, 0)); } @@ -1361,7 +1361,7 @@ test_bson_vector_example_packed_bit_view (void) const size_t packed_values_count = sizeof packed_bytes * 8 - unused_bits_count; bson_vector_packed_bit_view_t view; - BSON_ASSERT (BSON_APPEND_VECTOR_PACKED_BIT (&doc, "from_packed", packed_values_count, &view)); + BSON_ASSERT (BSON_APPEND_VECTOR_PACKED_BIT_UNINIT (&doc, "from_packed", packed_values_count, &view)); BSON_ASSERT (bson_vector_packed_bit_view_write_packed (view, packed_bytes, sizeof packed_bytes, 0)); } From 758856a17196d26092b9557fe5395d7b015ba112 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Wed, 26 Feb 2025 17:14:02 -0800 Subject: [PATCH 27/51] Use INFINITY and NAN for float but not double --- src/libbson/src/bson/bson-vector.h | 3 ++- src/libbson/tests/test-bson-vector.c | 16 +++++++++++----- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/libbson/src/bson/bson-vector.h b/src/libbson/src/bson/bson-vector.h index 44562e118d7..69b90308bcb 100644 --- a/src/libbson/src/bson/bson-vector.h +++ b/src/libbson/src/bson/bson-vector.h @@ -195,7 +195,8 @@ BSON_EXPORT (bool) bson_append_vector_int8_uninit ( bson_t *bson, const char *key, int key_length, size_t element_count, bson_vector_int8_view_t *view_out); -#define BSON_APPEND_VECTOR_INT8_UNINIT(b, key, count, view) bson_append_vector_int8_uninit (b, key, (int) strlen (key), count, view) +#define BSON_APPEND_VECTOR_INT8_UNINIT(b, key, count, view) \ + bson_append_vector_int8_uninit (b, key, (int) strlen (key), count, view) BSON_EXPORT (bool) bson_append_vector_float32_uninit ( diff --git a/src/libbson/tests/test-bson-vector.c b/src/libbson/tests/test-bson-vector.c index d4f194e1d30..f8959fa7f53 100644 --- a/src/libbson/tests/test-bson-vector.c +++ b/src/libbson/tests/test-bson-vector.c @@ -58,6 +58,12 @@ typedef struct vector_json_test_case_t { bool *test_valid; } vector_json_test_case_t; +static BSON_INLINE double +double_inf (void) +{ + return 1.0 / 0.0; +} + static void translate_json_test_vector (bson_t *array_in, bson_t *array_out) { @@ -70,9 +76,9 @@ translate_json_test_vector (bson_t *array_in, bson_t *array_out) bson_array_builder_t *builder = bson_array_builder_new (); while (bson_iter_next (&iter_in)) { if (BSON_ITER_HOLDS_UTF8 (&iter_in) && 0 == strcmp ("inf", bson_iter_utf8 (&iter_in, NULL))) { - BSON_ASSERT (bson_array_builder_append_double (builder, INFINITY)); + BSON_ASSERT (bson_array_builder_append_double (builder, double_inf ())); } else if (BSON_ITER_HOLDS_UTF8 (&iter_in) && 0 == strcmp ("-inf", bson_iter_utf8 (&iter_in, NULL))) { - BSON_ASSERT (bson_array_builder_append_double (builder, -INFINITY)); + BSON_ASSERT (bson_array_builder_append_double (builder, -double_inf ())); } else { BSON_ASSERT (bson_array_builder_append_iter (builder, &iter_in)); } @@ -315,10 +321,10 @@ test_bson_vector_json_case (vector_json_test_case_t *test_case) double expected_double; if (BSON_ITER_HOLDS_UTF8 (&expected_iter) && 0 == strcmp ("inf", bson_iter_utf8 (&expected_iter, NULL))) { - expected_double = INFINITY; + expected_double = double_inf (); } else if (BSON_ITER_HOLDS_UTF8 (&expected_iter) && 0 == strcmp ("-inf", bson_iter_utf8 (&expected_iter, NULL))) { - expected_double = -INFINITY; + expected_double = -double_inf (); } else if (BSON_ITER_HOLDS_DOUBLE (&expected_iter)) { expected_double = bson_iter_double (&expected_iter); } else { @@ -1235,7 +1241,7 @@ test_bson_vector_example_float32_const_view (void) // setup: construct a sample document bson_t doc = BSON_INITIALIZER; { - static const float values[] = {5.0f, -1e10f, (float) INFINITY, (float) NAN, -1.0f}; + static const float values[] = {5.0f, -1e10f, INFINITY, NAN, -1.0f}; bson_vector_float32_view_t view; BSON_ASSERT (BSON_APPEND_VECTOR_FLOAT32_UNINIT (&doc, "vector", sizeof values / sizeof values[0], &view)); BSON_ASSERT (bson_vector_float32_view_write (view, values, sizeof values / sizeof values[0], 0)); From e93b66c16cc0eb0c0e82652dd4fc11160f5bd508 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Wed, 26 Feb 2025 18:59:18 -0800 Subject: [PATCH 28/51] Note about low RAND_MAX on windows --- src/libbson/tests/test-bson-vector.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libbson/tests/test-bson-vector.c b/src/libbson/tests/test-bson-vector.c index f8959fa7f53..cb4bedd310e 100644 --- a/src/libbson/tests/test-bson-vector.c +++ b/src/libbson/tests/test-bson-vector.c @@ -960,6 +960,7 @@ test_bson_vector_view_api_usage_packed_bit (void) bson_destroy (&doc); } +// Note: The effective MAX_TESTED_VECTOR_LENGTH is limited to 2047 on Windows due to RAND_MAX==0x7fff #define MAX_TESTED_VECTOR_LENGTH 10000 #define FUZZ_TEST_ITERS 5000 From aea2bef2827672ff064dc596a8a6ad980a4612d3 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Wed, 26 Feb 2025 19:06:19 -0800 Subject: [PATCH 29/51] Adjust type for fuzzer random inputs --- src/libbson/tests/test-bson-vector.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/libbson/tests/test-bson-vector.c b/src/libbson/tests/test-bson-vector.c index cb4bedd310e..1df408a0c50 100644 --- a/src/libbson/tests/test-bson-vector.c +++ b/src/libbson/tests/test-bson-vector.c @@ -972,9 +972,9 @@ test_bson_vector_view_api_fuzz_int8 (void) int8_t *expected_elements = bson_malloc (MAX_TESTED_VECTOR_LENGTH * sizeof *expected_elements); int8_t *actual_elements = bson_malloc (MAX_TESTED_VECTOR_LENGTH * sizeof *actual_elements); for (int fuzz_iter = 0; fuzz_iter < FUZZ_TEST_ITERS; fuzz_iter++) { - int r = rand (); - int r_operation = r & 0xF; - int r_param = r >> 4; + unsigned r = (unsigned) rand (); + unsigned r_operation = r & 0xFu; + size_t r_param = r >> 4; if (current_length == 0 || r_operation == 15) { // Resize and fill @@ -1028,9 +1028,9 @@ test_bson_vector_view_api_fuzz_float32 (void) float *expected_elements = bson_malloc (MAX_TESTED_VECTOR_LENGTH * sizeof *expected_elements); float *actual_elements = bson_malloc (MAX_TESTED_VECTOR_LENGTH * sizeof *actual_elements); for (int fuzz_iter = 0; fuzz_iter < FUZZ_TEST_ITERS; fuzz_iter++) { - int r = rand (); - int r_operation = r & 0xF; - int r_param = r >> 4; + unsigned r = (unsigned) rand (); + unsigned r_operation = r & 0xFu; + size_t r_param = r >> 4; if (current_length == 0 || r_operation == 15) { // Resize and fill @@ -1085,9 +1085,9 @@ test_bson_vector_view_api_fuzz_packed_bit (void) bool *actual_elements = bson_malloc (MAX_TESTED_VECTOR_LENGTH * sizeof *actual_elements); uint8_t *packed_buffer = bson_malloc ((MAX_TESTED_VECTOR_LENGTH + 7) / 8); for (int fuzz_iter = 0; fuzz_iter < FUZZ_TEST_ITERS; fuzz_iter++) { - int r = rand (); - int r_operation = r & 0xF; - int r_param = r >> 4; + unsigned r = (unsigned) rand (); + unsigned r_operation = r & 0xFu; + size_t r_param = r >> 4; if (current_length == 0 || r_operation == 15) { // Resize and fill from unpacked bool source From 6f732fcc6226508f52a6c8e8afe70beec99e370c Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Wed, 26 Feb 2025 20:34:23 -0800 Subject: [PATCH 30/51] libbson bugfix, allow allocating max size documents The power-of-two rounding was exceeding MAX_SIZE on any allocation attempts above about MAX_SIZE/2. --- src/libbson/src/bson/bson.c | 42 +++++++++++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/src/libbson/src/bson/bson.c b/src/libbson/src/bson/bson.c index c32c8992aa1..be581c8863e 100644 --- a/src/libbson/src/bson/bson.c +++ b/src/libbson/src/bson/bson.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -60,6 +61,31 @@ typedef struct { */ static const uint8_t gZero; +/* + *-------------------------------------------------------------------------- + * + * _bson_next_power_of_two_for_alloc -- + * + * Given a potential allocation length no greater than BSON_MAX_SIZE, + * round it up to the next power of two without exceeding BSON_MAX_SIZE. + * + * Returns: + * A value >= the input size and <= BSON_MAX_SIZE. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +static BSON_INLINE size_t +_bson_next_power_of_two_for_alloc (size_t size) +{ + MONGOC_DEBUG_ASSERT (size <= BSON_MAX_SIZE); + size_t power_of_two = bson_next_power_of_two (size); + return BSON_MIN (power_of_two, BSON_MAX_SIZE); +} + /* *-------------------------------------------------------------------------- * @@ -90,7 +116,7 @@ _bson_impl_inline_grow (bson_impl_inline_t *impl, /* IN */ return true; } - req = bson_next_power_of_two (impl->len + size); + req = _bson_next_power_of_two_for_alloc (impl->len + size); if (req <= BSON_MAX_SIZE) { data = bson_malloc (req); @@ -150,7 +176,7 @@ _bson_impl_alloc_grow (bson_impl_alloc_t *impl, /* IN */ return true; } - req = bson_next_power_of_two (req); + req = _bson_next_power_of_two_for_alloc (req); if ((req <= BSON_MAX_SIZE) && impl->realloc) { *impl->buf = impl->realloc (*impl->buf, req, impl->realloc_func_ctx); @@ -168,7 +194,8 @@ _bson_impl_alloc_grow (bson_impl_alloc_t *impl, /* IN */ * _bson_grow -- * * Grows the bson_t structure to be large enough to contain @size - * bytes. + * bytes in addition to its current content. The caller is responsible + * for ensuring the new summed size is <= BSON_MAX_SIZE. * * Returns: * true if successful, false if the size would overflow. @@ -183,6 +210,9 @@ static bool _bson_grow (bson_t *bson, /* IN */ uint32_t size) /* IN */ { + // Already checked by caller in all build types + MONGOC_DEBUG_ASSERT ((size_t) bson->len <= BSON_MAX_SIZE && (size_t) size <= BSON_MAX_SIZE - (size_t) bson->len); + if ((bson->flags & BSON_FLAG_INLINE)) { return _bson_impl_inline_grow ((bson_impl_inline_t *) bson, size); } @@ -2097,7 +2127,7 @@ bson_copy_to (const bson_t *src, bson_t *dst) } data = _bson_data (src); - len = bson_next_power_of_two ((size_t) src->len); + len = _bson_next_power_of_two_for_alloc ((size_t) src->len); adst = (bson_impl_alloc_t *) dst; adst->flags = BSON_FLAG_STATIC; @@ -2219,6 +2249,10 @@ bson_reserve_buffer (bson_t *bson, uint32_t size) return NULL; } + MONGOC_DEBUG_ASSERT ((size_t) bson->len <= BSON_MAX_SIZE); + if ((size_t) size > BSON_MAX_SIZE - (size_t) bson->len) { + return NULL; + } if (!_bson_grow (bson, size)) { return NULL; } From 3969826eac8998f1e46d8d95ce96eff6eeb9f062 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Wed, 26 Feb 2025 21:29:55 -0800 Subject: [PATCH 31/51] Edge case tests for sizing, allocation, and accessors --- src/libbson/tests/test-bson-vector.c | 211 +++++++++++++++++++++++++++ 1 file changed, 211 insertions(+) diff --git a/src/libbson/tests/test-bson-vector.c b/src/libbson/tests/test-bson-vector.c index 1df408a0c50..cea61558016 100644 --- a/src/libbson/tests/test-bson-vector.c +++ b/src/libbson/tests/test-bson-vector.c @@ -1384,6 +1384,213 @@ test_bson_vector_example_packed_bit_view (void) bson_destroy (&doc); } +static void +test_bson_vector_edge_cases_int8 (void) +{ + size_t max_representable_elements = (size_t) UINT32_MAX - BSON_VECTOR_HEADER_LEN; + + // Test binary_data_length (uint32_t) edge cases, without any allocation. + { + ASSERT_CMPUINT32 (bson_vector_int8_binary_data_length (max_representable_elements - 1u), ==, UINT32_MAX - 1u); + ASSERT_CMPUINT32 (bson_vector_int8_binary_data_length (max_representable_elements), ==, UINT32_MAX); + ASSERT_CMPUINT32 (bson_vector_int8_binary_data_length (max_representable_elements + 1u), ==, 0); + } + + // Needs little real memory because most bytes are never accessed, + // but we do need a virtual address space larger than 32 bits. +#if BSON_WORD_SIZE > 32 + + size_t expected_bson_overhead = + 5 /* empty bson document */ + 3 /* "v" element header */ + 5 /* binary item header */; + size_t max_alloc_elements = (size_t) BSON_MAX_SIZE - expected_bson_overhead - BSON_VECTOR_HEADER_LEN; + + bson_t doc = BSON_INITIALIZER; + bson_vector_int8_view_t view; + + // Test allocation (BSON_MAX_SIZE + uint32_t) edge cases. + { + ASSERT (!BSON_APPEND_VECTOR_INT8_UNINIT (&doc, "v", max_representable_elements, &view)); + ASSERT (!BSON_APPEND_VECTOR_INT8_UNINIT (&doc, "v", max_representable_elements + 1u, &view)); + ASSERT (!BSON_APPEND_VECTOR_INT8_UNINIT (&doc, "v", max_alloc_elements + 1u, &view)); + ASSERT (BSON_APPEND_VECTOR_INT8_UNINIT (&doc, "v", max_alloc_elements, &view)); + } + + // Test some read and write boundaries. + { + int8_t values[] = {1, 2, 3, 4, 5}; + size_t values_size = sizeof values / sizeof values[0]; + ASSERT (bson_vector_int8_view_write (view, values, values_size, 0)); + ASSERT (bson_vector_int8_view_read (view, values, values_size, 0)); + ASSERT (!bson_vector_int8_view_write (view, values, max_alloc_elements + 1u, 0)); + ASSERT (!bson_vector_int8_view_read (view, values, max_alloc_elements + 1u, 0)); + ASSERT (bson_vector_int8_view_write (view, values, values_size, max_alloc_elements - values_size)); + ASSERT (bson_vector_int8_view_read (view, values, values_size, max_alloc_elements - values_size)); + ASSERT (!bson_vector_int8_view_write (view, values, values_size, max_alloc_elements - values_size + 1u)); + ASSERT (!bson_vector_int8_view_read (view, values, values_size, max_alloc_elements - values_size + 1u)); + ASSERT (!bson_vector_int8_view_write (view, values, values_size + 1u, max_alloc_elements - values_size)); + ASSERT (!bson_vector_int8_view_read (view, values, values_size + 1u, max_alloc_elements - values_size)); + ASSERT (!bson_vector_int8_view_write (view, values, SIZE_MAX, max_alloc_elements - values_size)); + ASSERT (!bson_vector_int8_view_read (view, values, SIZE_MAX, max_alloc_elements - values_size)); + ASSERT (!bson_vector_int8_view_write (view, values, SIZE_MAX, max_alloc_elements - values_size + 1u)); + ASSERT (!bson_vector_int8_view_read (view, values, SIZE_MAX, max_alloc_elements - values_size + 1u)); + } + + bson_destroy (&doc); +#endif // BSON_WORD_SIZE > 32 +} + +static void +test_bson_vector_edge_cases_float32 (void) +{ + size_t max_representable_elements = ((size_t) UINT32_MAX - BSON_VECTOR_HEADER_LEN) / sizeof (float); + + // Test binary_data_length (uint32_t) edge cases, without any allocation. + // Note that the longest possible multiple of a complete element is 1 byte short of UINT32_MAX. + { + ASSERT_CMPUINT32 ( + bson_vector_float32_binary_data_length (max_representable_elements - 1u), ==, UINT32_MAX - 1u - 4u); + ASSERT_CMPUINT32 (bson_vector_float32_binary_data_length (max_representable_elements), ==, UINT32_MAX - 1u); + ASSERT_CMPUINT32 (bson_vector_float32_binary_data_length (max_representable_elements + 1u), ==, 0); + } + + // Needs little real memory because most bytes are never accessed, + // but we do need a virtual address space larger than 32 bits. +#if BSON_WORD_SIZE > 32 + + size_t expected_bson_overhead = + 5 /* empty bson document */ + 3 /* "v" element header */ + 5 /* binary item header */; + size_t max_alloc_elements = + ((size_t) BSON_MAX_SIZE - expected_bson_overhead - BSON_VECTOR_HEADER_LEN) / sizeof (float); + + bson_t doc = BSON_INITIALIZER; + bson_vector_float32_view_t view; + + // Test allocation (BSON_MAX_SIZE + uint32_t) edge cases. + { + ASSERT (!BSON_APPEND_VECTOR_FLOAT32_UNINIT (&doc, "v", max_representable_elements, &view)); + ASSERT (!BSON_APPEND_VECTOR_FLOAT32_UNINIT (&doc, "v", max_representable_elements + 1u, &view)); + ASSERT (!BSON_APPEND_VECTOR_FLOAT32_UNINIT (&doc, "v", max_alloc_elements + 1u, &view)); + ASSERT (BSON_APPEND_VECTOR_FLOAT32_UNINIT (&doc, "v", max_alloc_elements, &view)); + } + + // Test some read and write boundaries. + { + float values[] = {1.f, 2.f, 3.f, 4.f, 5.f}; + size_t values_size = sizeof values / sizeof values[0]; + ASSERT (bson_vector_float32_view_write (view, values, values_size, 0)); + ASSERT (bson_vector_float32_view_read (view, values, values_size, 0)); + ASSERT (!bson_vector_float32_view_write (view, values, max_alloc_elements + 1u, 0)); + ASSERT (!bson_vector_float32_view_read (view, values, max_alloc_elements + 1u, 0)); + ASSERT (bson_vector_float32_view_write (view, values, values_size, max_alloc_elements - values_size)); + ASSERT (bson_vector_float32_view_read (view, values, values_size, max_alloc_elements - values_size)); + ASSERT (!bson_vector_float32_view_write (view, values, values_size, max_alloc_elements - values_size + 1u)); + ASSERT (!bson_vector_float32_view_read (view, values, values_size, max_alloc_elements - values_size + 1u)); + ASSERT (!bson_vector_float32_view_write (view, values, values_size + 1u, max_alloc_elements - values_size)); + ASSERT (!bson_vector_float32_view_read (view, values, values_size + 1u, max_alloc_elements - values_size)); + ASSERT (!bson_vector_float32_view_write (view, values, SIZE_MAX, max_alloc_elements - values_size)); + ASSERT (!bson_vector_float32_view_read (view, values, SIZE_MAX, max_alloc_elements - values_size)); + ASSERT (!bson_vector_float32_view_write (view, values, SIZE_MAX, max_alloc_elements - values_size + 1u)); + ASSERT (!bson_vector_float32_view_read (view, values, SIZE_MAX, max_alloc_elements - values_size + 1u)); + } + + bson_destroy (&doc); +#endif // BSON_WORD_SIZE > 32 +} + +static void +test_bson_vector_edge_cases_packed_bit (void) +{ + size_t max_representable_elements = ((size_t) UINT32_MAX - BSON_VECTOR_HEADER_LEN) * 8u; + + // Test binary_data_length (uint32_t) edge cases, without any allocation. + { + ASSERT_CMPUINT32 ( + bson_vector_packed_bit_binary_data_length (max_representable_elements - 8u), ==, UINT32_MAX - 1u); + ASSERT_CMPUINT32 (bson_vector_packed_bit_binary_data_length (max_representable_elements - 7u), ==, UINT32_MAX); + ASSERT_CMPUINT32 (bson_vector_packed_bit_binary_data_length (max_representable_elements), ==, UINT32_MAX); + ASSERT_CMPUINT32 (bson_vector_packed_bit_binary_data_length (max_representable_elements + 1u), ==, 0); + } + + // Needs little real memory because most bytes are never accessed, + // but we do need a virtual address space larger than 32 bits. +#if BSON_WORD_SIZE > 32 + + size_t expected_bson_overhead = + 5 /* empty bson document */ + 3 /* "v" element header */ + 5 /* binary item header */; + size_t max_alloc_bytes = (size_t) BSON_MAX_SIZE - expected_bson_overhead - BSON_VECTOR_HEADER_LEN; + size_t max_alloc_elements = max_alloc_bytes * 8u; + + bson_t doc = BSON_INITIALIZER; + bson_vector_packed_bit_view_t view; + + // Test allocation (BSON_MAX_SIZE + uint32_t) edge cases. + { + ASSERT (!BSON_APPEND_VECTOR_PACKED_BIT_UNINIT (&doc, "v", max_representable_elements, &view)); + ASSERT (!BSON_APPEND_VECTOR_PACKED_BIT_UNINIT (&doc, "v", max_representable_elements + 1u, &view)); + ASSERT (!BSON_APPEND_VECTOR_PACKED_BIT_UNINIT (&doc, "v", max_alloc_elements + 1u, &view)); + ASSERT (BSON_APPEND_VECTOR_PACKED_BIT_UNINIT (&doc, "v", max_alloc_elements, &view)); + } + + // Test some pack and unpack boundaries, similar to the read/write tests for non-packed element types. + // Only tests one length, but it's chosen to be greater than 8 and not a multiple of 8. + { + bool values[190]; + size_t values_size = sizeof values / sizeof values[0]; + for (size_t i = 0; i < values_size; i++) { + values[i] = (i & 3) == 3; + } + ASSERT (bson_vector_packed_bit_view_pack_bool (view, values, values_size, 0)); + ASSERT (bson_vector_packed_bit_view_unpack_bool (view, values, values_size, 0)); + ASSERT (!bson_vector_packed_bit_view_pack_bool (view, values, max_alloc_elements + 1u, 0)); + ASSERT (!bson_vector_packed_bit_view_unpack_bool (view, values, max_alloc_elements + 1u, 0)); + ASSERT (bson_vector_packed_bit_view_pack_bool (view, values, values_size, max_alloc_elements - values_size)); + ASSERT (bson_vector_packed_bit_view_unpack_bool (view, values, values_size, max_alloc_elements - values_size)); + ASSERT ( + !bson_vector_packed_bit_view_pack_bool (view, values, values_size, max_alloc_elements - values_size + 1u)); + ASSERT ( + !bson_vector_packed_bit_view_unpack_bool (view, values, values_size, max_alloc_elements - values_size + 1u)); + ASSERT ( + !bson_vector_packed_bit_view_pack_bool (view, values, values_size + 1u, max_alloc_elements - values_size)); + ASSERT ( + !bson_vector_packed_bit_view_unpack_bool (view, values, values_size + 1u, max_alloc_elements - values_size)); + ASSERT (!bson_vector_packed_bit_view_pack_bool (view, values, SIZE_MAX, max_alloc_elements - values_size)); + ASSERT (!bson_vector_packed_bit_view_unpack_bool (view, values, SIZE_MAX, max_alloc_elements - values_size)); + ASSERT (!bson_vector_packed_bit_view_pack_bool (view, values, SIZE_MAX, max_alloc_elements - values_size + 1u)); + ASSERT (!bson_vector_packed_bit_view_unpack_bool (view, values, SIZE_MAX, max_alloc_elements - values_size + 1u)); + } + + // Test some read and write boundaries on packed bytes. + { + uint8_t packed[] = {0x12, 0x34, 0x56, 0x78, 0x9A}; + ASSERT (bson_vector_packed_bit_view_write_packed (view, packed, sizeof packed, 0)); + ASSERT (bson_vector_packed_bit_view_read_packed (view, packed, sizeof packed, 0)); + ASSERT (!bson_vector_packed_bit_view_write_packed (view, packed, max_alloc_bytes + 1u, 0)); + ASSERT (!bson_vector_packed_bit_view_read_packed (view, packed, max_alloc_bytes + 1u, 0)); + ASSERT ( + bson_vector_packed_bit_view_write_packed (view, packed, sizeof packed, max_alloc_bytes - sizeof packed)); + ASSERT ( + bson_vector_packed_bit_view_read_packed (view, packed, sizeof packed, max_alloc_bytes - sizeof packed)); + ASSERT (!bson_vector_packed_bit_view_write_packed ( + view, packed, sizeof packed, max_alloc_bytes - sizeof packed + 1u)); + ASSERT (!bson_vector_packed_bit_view_read_packed ( + view, packed, sizeof packed, max_alloc_bytes - sizeof packed + 1u)); + ASSERT (!bson_vector_packed_bit_view_write_packed ( + view, packed, sizeof packed + 1u, max_alloc_bytes - sizeof packed)); + ASSERT (!bson_vector_packed_bit_view_read_packed ( + view, packed, sizeof packed + 1u, max_alloc_bytes - sizeof packed)); + ASSERT ( + !bson_vector_packed_bit_view_write_packed (view, packed, SIZE_MAX, max_alloc_bytes - sizeof packed)); + ASSERT (!bson_vector_packed_bit_view_read_packed (view, packed, SIZE_MAX, max_alloc_bytes - sizeof packed)); + ASSERT (!bson_vector_packed_bit_view_write_packed ( + view, packed, SIZE_MAX, max_alloc_bytes - sizeof packed + 1u)); + ASSERT ( + !bson_vector_packed_bit_view_read_packed (view, packed, SIZE_MAX, max_alloc_bytes - sizeof packed + 1u)); + } + + bson_destroy (&doc); +#endif // BSON_WORD_SIZE > 32 +} + void test_bson_vector_install (TestSuite *suite) { @@ -1404,4 +1611,8 @@ test_bson_vector_install (TestSuite *suite) TestSuite_Add ( suite, "/bson_binary_vector/example/packed_bit_const_view", test_bson_vector_example_packed_bit_const_view); TestSuite_Add (suite, "/bson_binary_vector/example/packed_bit_view", test_bson_vector_example_packed_bit_view); + + TestSuite_Add (suite, "/bson_binary_vector/edge_cases/int8", test_bson_vector_edge_cases_int8); + TestSuite_Add (suite, "/bson_binary_vector/edge_cases/float32", test_bson_vector_edge_cases_float32); + TestSuite_Add (suite, "/bson_binary_vector/edge_cases/packed_bit", test_bson_vector_edge_cases_packed_bit); } From 57a2a0d161e8cc394d353d0035c4776e63575a53 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Thu, 27 Feb 2025 09:37:56 -0800 Subject: [PATCH 32/51] Move read/write edge case tests to macros --- src/libbson/tests/test-bson-vector.c | 119 ++++++++++----------------- 1 file changed, 43 insertions(+), 76 deletions(-) diff --git a/src/libbson/tests/test-bson-vector.c b/src/libbson/tests/test-bson-vector.c index cea61558016..cdccd31fcea 100644 --- a/src/libbson/tests/test-bson-vector.c +++ b/src/libbson/tests/test-bson-vector.c @@ -1384,6 +1384,26 @@ test_bson_vector_example_packed_bit_view (void) bson_destroy (&doc); } +// Shared edge case tests that apply to all reader/writer functions. +#define TEST_BSON_VECTOR_RW(_expected, _view, _v, _count, _offset, _read, _write) \ + if (true) { \ + ASSERT ((_expected) == (_write) ((_view), (_v), (_count), (_offset))); \ + ASSERT ((_expected) == (_read) ((_view), (_v), (_count), (_offset))); \ + } else { \ + } + +#define TEST_BSON_VECTOR_EDGE_CASES_RW_COMMON(_view, _alloc_size, _v, _v_size, _read, _write) \ + if (true) { \ + TEST_BSON_VECTOR_RW (false, (_view), (_v), (_alloc_size) + 1u, 0, (_read), (_write)); \ + TEST_BSON_VECTOR_RW (true, (_view), (_v), (_v_size), (_alloc_size) - (_v_size), (_read), (_write)); \ + TEST_BSON_VECTOR_RW (false, (_view), (_v), (_v_size), (_alloc_size) - (_v_size) + 1u, (_read), (_write)); \ + TEST_BSON_VECTOR_RW (false, (_view), (_v), (_v_size) + 1u, (_alloc_size) - (_v_size), (_read), (_write)); \ + TEST_BSON_VECTOR_RW (false, (_view), (_v), SIZE_MAX, (_alloc_size) - (_v_size), (_read), (_write)); \ + TEST_BSON_VECTOR_RW (false, (_view), (_v), SIZE_MAX, (_alloc_size) - (_v_size) + 1u, (_read), (_write)); \ + TEST_BSON_VECTOR_RW (true, (_view), (_v), (_v_size), 0, (_read), (_write)); \ + } else { \ + } + static void test_bson_vector_edge_cases_int8 (void) { @@ -1397,7 +1417,7 @@ test_bson_vector_edge_cases_int8 (void) } // Needs little real memory because most bytes are never accessed, - // but we do need a virtual address space larger than 32 bits. + // but we should require a virtual address space larger than 32 bits. #if BSON_WORD_SIZE > 32 size_t expected_bson_overhead = @@ -1419,20 +1439,8 @@ test_bson_vector_edge_cases_int8 (void) { int8_t values[] = {1, 2, 3, 4, 5}; size_t values_size = sizeof values / sizeof values[0]; - ASSERT (bson_vector_int8_view_write (view, values, values_size, 0)); - ASSERT (bson_vector_int8_view_read (view, values, values_size, 0)); - ASSERT (!bson_vector_int8_view_write (view, values, max_alloc_elements + 1u, 0)); - ASSERT (!bson_vector_int8_view_read (view, values, max_alloc_elements + 1u, 0)); - ASSERT (bson_vector_int8_view_write (view, values, values_size, max_alloc_elements - values_size)); - ASSERT (bson_vector_int8_view_read (view, values, values_size, max_alloc_elements - values_size)); - ASSERT (!bson_vector_int8_view_write (view, values, values_size, max_alloc_elements - values_size + 1u)); - ASSERT (!bson_vector_int8_view_read (view, values, values_size, max_alloc_elements - values_size + 1u)); - ASSERT (!bson_vector_int8_view_write (view, values, values_size + 1u, max_alloc_elements - values_size)); - ASSERT (!bson_vector_int8_view_read (view, values, values_size + 1u, max_alloc_elements - values_size)); - ASSERT (!bson_vector_int8_view_write (view, values, SIZE_MAX, max_alloc_elements - values_size)); - ASSERT (!bson_vector_int8_view_read (view, values, SIZE_MAX, max_alloc_elements - values_size)); - ASSERT (!bson_vector_int8_view_write (view, values, SIZE_MAX, max_alloc_elements - values_size + 1u)); - ASSERT (!bson_vector_int8_view_read (view, values, SIZE_MAX, max_alloc_elements - values_size + 1u)); + TEST_BSON_VECTOR_EDGE_CASES_RW_COMMON ( + view, max_alloc_elements, values, values_size, bson_vector_int8_view_read, bson_vector_int8_view_write); } bson_destroy (&doc); @@ -1454,7 +1462,7 @@ test_bson_vector_edge_cases_float32 (void) } // Needs little real memory because most bytes are never accessed, - // but we do need a virtual address space larger than 32 bits. + // but we should require a virtual address space larger than 32 bits. #if BSON_WORD_SIZE > 32 size_t expected_bson_overhead = @@ -1477,20 +1485,8 @@ test_bson_vector_edge_cases_float32 (void) { float values[] = {1.f, 2.f, 3.f, 4.f, 5.f}; size_t values_size = sizeof values / sizeof values[0]; - ASSERT (bson_vector_float32_view_write (view, values, values_size, 0)); - ASSERT (bson_vector_float32_view_read (view, values, values_size, 0)); - ASSERT (!bson_vector_float32_view_write (view, values, max_alloc_elements + 1u, 0)); - ASSERT (!bson_vector_float32_view_read (view, values, max_alloc_elements + 1u, 0)); - ASSERT (bson_vector_float32_view_write (view, values, values_size, max_alloc_elements - values_size)); - ASSERT (bson_vector_float32_view_read (view, values, values_size, max_alloc_elements - values_size)); - ASSERT (!bson_vector_float32_view_write (view, values, values_size, max_alloc_elements - values_size + 1u)); - ASSERT (!bson_vector_float32_view_read (view, values, values_size, max_alloc_elements - values_size + 1u)); - ASSERT (!bson_vector_float32_view_write (view, values, values_size + 1u, max_alloc_elements - values_size)); - ASSERT (!bson_vector_float32_view_read (view, values, values_size + 1u, max_alloc_elements - values_size)); - ASSERT (!bson_vector_float32_view_write (view, values, SIZE_MAX, max_alloc_elements - values_size)); - ASSERT (!bson_vector_float32_view_read (view, values, SIZE_MAX, max_alloc_elements - values_size)); - ASSERT (!bson_vector_float32_view_write (view, values, SIZE_MAX, max_alloc_elements - values_size + 1u)); - ASSERT (!bson_vector_float32_view_read (view, values, SIZE_MAX, max_alloc_elements - values_size + 1u)); + TEST_BSON_VECTOR_EDGE_CASES_RW_COMMON ( + view, max_alloc_elements, values, values_size, bson_vector_float32_view_read, bson_vector_float32_view_write); } bson_destroy (&doc); @@ -1512,7 +1508,7 @@ test_bson_vector_edge_cases_packed_bit (void) } // Needs little real memory because most bytes are never accessed, - // but we do need a virtual address space larger than 32 bits. + // but we should require a virtual address space larger than 32 bits. #if BSON_WORD_SIZE > 32 size_t expected_bson_overhead = @@ -1531,7 +1527,7 @@ test_bson_vector_edge_cases_packed_bit (void) ASSERT (BSON_APPEND_VECTOR_PACKED_BIT_UNINIT (&doc, "v", max_alloc_elements, &view)); } - // Test some pack and unpack boundaries, similar to the read/write tests for non-packed element types. + // Test pack and unpack boundaries with the same tests used for read/write of non-packed element types. // Only tests one length, but it's chosen to be greater than 8 and not a multiple of 8. { bool values[190]; @@ -1539,52 +1535,23 @@ test_bson_vector_edge_cases_packed_bit (void) for (size_t i = 0; i < values_size; i++) { values[i] = (i & 3) == 3; } - ASSERT (bson_vector_packed_bit_view_pack_bool (view, values, values_size, 0)); - ASSERT (bson_vector_packed_bit_view_unpack_bool (view, values, values_size, 0)); - ASSERT (!bson_vector_packed_bit_view_pack_bool (view, values, max_alloc_elements + 1u, 0)); - ASSERT (!bson_vector_packed_bit_view_unpack_bool (view, values, max_alloc_elements + 1u, 0)); - ASSERT (bson_vector_packed_bit_view_pack_bool (view, values, values_size, max_alloc_elements - values_size)); - ASSERT (bson_vector_packed_bit_view_unpack_bool (view, values, values_size, max_alloc_elements - values_size)); - ASSERT ( - !bson_vector_packed_bit_view_pack_bool (view, values, values_size, max_alloc_elements - values_size + 1u)); - ASSERT ( - !bson_vector_packed_bit_view_unpack_bool (view, values, values_size, max_alloc_elements - values_size + 1u)); - ASSERT ( - !bson_vector_packed_bit_view_pack_bool (view, values, values_size + 1u, max_alloc_elements - values_size)); - ASSERT ( - !bson_vector_packed_bit_view_unpack_bool (view, values, values_size + 1u, max_alloc_elements - values_size)); - ASSERT (!bson_vector_packed_bit_view_pack_bool (view, values, SIZE_MAX, max_alloc_elements - values_size)); - ASSERT (!bson_vector_packed_bit_view_unpack_bool (view, values, SIZE_MAX, max_alloc_elements - values_size)); - ASSERT (!bson_vector_packed_bit_view_pack_bool (view, values, SIZE_MAX, max_alloc_elements - values_size + 1u)); - ASSERT (!bson_vector_packed_bit_view_unpack_bool (view, values, SIZE_MAX, max_alloc_elements - values_size + 1u)); - } - - // Test some read and write boundaries on packed bytes. + TEST_BSON_VECTOR_EDGE_CASES_RW_COMMON (view, + max_alloc_elements, + values, + values_size, + bson_vector_packed_bit_view_unpack_bool, + bson_vector_packed_bit_view_pack_bool); + } + + // Test read and write boundaries on packed bytes. { uint8_t packed[] = {0x12, 0x34, 0x56, 0x78, 0x9A}; - ASSERT (bson_vector_packed_bit_view_write_packed (view, packed, sizeof packed, 0)); - ASSERT (bson_vector_packed_bit_view_read_packed (view, packed, sizeof packed, 0)); - ASSERT (!bson_vector_packed_bit_view_write_packed (view, packed, max_alloc_bytes + 1u, 0)); - ASSERT (!bson_vector_packed_bit_view_read_packed (view, packed, max_alloc_bytes + 1u, 0)); - ASSERT ( - bson_vector_packed_bit_view_write_packed (view, packed, sizeof packed, max_alloc_bytes - sizeof packed)); - ASSERT ( - bson_vector_packed_bit_view_read_packed (view, packed, sizeof packed, max_alloc_bytes - sizeof packed)); - ASSERT (!bson_vector_packed_bit_view_write_packed ( - view, packed, sizeof packed, max_alloc_bytes - sizeof packed + 1u)); - ASSERT (!bson_vector_packed_bit_view_read_packed ( - view, packed, sizeof packed, max_alloc_bytes - sizeof packed + 1u)); - ASSERT (!bson_vector_packed_bit_view_write_packed ( - view, packed, sizeof packed + 1u, max_alloc_bytes - sizeof packed)); - ASSERT (!bson_vector_packed_bit_view_read_packed ( - view, packed, sizeof packed + 1u, max_alloc_bytes - sizeof packed)); - ASSERT ( - !bson_vector_packed_bit_view_write_packed (view, packed, SIZE_MAX, max_alloc_bytes - sizeof packed)); - ASSERT (!bson_vector_packed_bit_view_read_packed (view, packed, SIZE_MAX, max_alloc_bytes - sizeof packed)); - ASSERT (!bson_vector_packed_bit_view_write_packed ( - view, packed, SIZE_MAX, max_alloc_bytes - sizeof packed + 1u)); - ASSERT ( - !bson_vector_packed_bit_view_read_packed (view, packed, SIZE_MAX, max_alloc_bytes - sizeof packed + 1u)); + TEST_BSON_VECTOR_EDGE_CASES_RW_COMMON (view, + max_alloc_bytes, + packed, + sizeof packed, + bson_vector_packed_bit_view_read_packed, + bson_vector_packed_bit_view_write_packed); } bson_destroy (&doc); From 05bd56afc125ee2e7f97d6ecd0ec4780d0adfe28 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Thu, 27 Feb 2025 09:49:18 -0800 Subject: [PATCH 33/51] bugfix for test_bson_reserve_buffer_errors The earlier fix for a bug in allocating bson_t near the max size revealed a flawed test that was only succeeding because of the allocation bug. This fixes the test to identify both sides of the boundary: we fail to allocate a bson_t that's one byte too large, and on 64-bit platforms we allocate a max-sized bson_t. --- src/libbson/tests/test-bson.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/libbson/tests/test-bson.c b/src/libbson/tests/test-bson.c index ecd288317ee..49c2b2c0318 100644 --- a/src/libbson/tests/test-bson.c +++ b/src/libbson/tests/test-bson.c @@ -1886,7 +1886,11 @@ test_bson_reserve_buffer_errors (void) uint32_t len_le; /* too big */ - ASSERT (!bson_reserve_buffer (&bson, (uint32_t) (INT32_MAX - bson.len - 1))); + ASSERT (!bson_reserve_buffer (&bson, (uint32_t) (BSON_MAX_SIZE - bson.len + 1u))); + /* exactly the maximum size */ +#if BSON_WORD_SIZE > 32 + ASSERT (bson_reserve_buffer (&bson, (uint32_t) (BSON_MAX_SIZE - bson.len))); +#endif /* make a static bson, it refuses bson_reserve_buffer since it's read-only */ bson_destroy (&bson); From d1b35d015e3673e31b4d48a75c3c306d43cc5e0c Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Thu, 27 Feb 2025 12:08:39 -0800 Subject: [PATCH 34/51] Revert "libbson bugfix, allow allocating max size documents" This reverts commit 6f732fcc6226508f52a6c8e8afe70beec99e370c. (Moved to CDRIVER-5915) --- src/libbson/src/bson/bson.c | 42 ++++--------------------------------- 1 file changed, 4 insertions(+), 38 deletions(-) diff --git a/src/libbson/src/bson/bson.c b/src/libbson/src/bson/bson.c index be581c8863e..c32c8992aa1 100644 --- a/src/libbson/src/bson/bson.c +++ b/src/libbson/src/bson/bson.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include @@ -61,31 +60,6 @@ typedef struct { */ static const uint8_t gZero; -/* - *-------------------------------------------------------------------------- - * - * _bson_next_power_of_two_for_alloc -- - * - * Given a potential allocation length no greater than BSON_MAX_SIZE, - * round it up to the next power of two without exceeding BSON_MAX_SIZE. - * - * Returns: - * A value >= the input size and <= BSON_MAX_SIZE. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -static BSON_INLINE size_t -_bson_next_power_of_two_for_alloc (size_t size) -{ - MONGOC_DEBUG_ASSERT (size <= BSON_MAX_SIZE); - size_t power_of_two = bson_next_power_of_two (size); - return BSON_MIN (power_of_two, BSON_MAX_SIZE); -} - /* *-------------------------------------------------------------------------- * @@ -116,7 +90,7 @@ _bson_impl_inline_grow (bson_impl_inline_t *impl, /* IN */ return true; } - req = _bson_next_power_of_two_for_alloc (impl->len + size); + req = bson_next_power_of_two (impl->len + size); if (req <= BSON_MAX_SIZE) { data = bson_malloc (req); @@ -176,7 +150,7 @@ _bson_impl_alloc_grow (bson_impl_alloc_t *impl, /* IN */ return true; } - req = _bson_next_power_of_two_for_alloc (req); + req = bson_next_power_of_two (req); if ((req <= BSON_MAX_SIZE) && impl->realloc) { *impl->buf = impl->realloc (*impl->buf, req, impl->realloc_func_ctx); @@ -194,8 +168,7 @@ _bson_impl_alloc_grow (bson_impl_alloc_t *impl, /* IN */ * _bson_grow -- * * Grows the bson_t structure to be large enough to contain @size - * bytes in addition to its current content. The caller is responsible - * for ensuring the new summed size is <= BSON_MAX_SIZE. + * bytes. * * Returns: * true if successful, false if the size would overflow. @@ -210,9 +183,6 @@ static bool _bson_grow (bson_t *bson, /* IN */ uint32_t size) /* IN */ { - // Already checked by caller in all build types - MONGOC_DEBUG_ASSERT ((size_t) bson->len <= BSON_MAX_SIZE && (size_t) size <= BSON_MAX_SIZE - (size_t) bson->len); - if ((bson->flags & BSON_FLAG_INLINE)) { return _bson_impl_inline_grow ((bson_impl_inline_t *) bson, size); } @@ -2127,7 +2097,7 @@ bson_copy_to (const bson_t *src, bson_t *dst) } data = _bson_data (src); - len = _bson_next_power_of_two_for_alloc ((size_t) src->len); + len = bson_next_power_of_two ((size_t) src->len); adst = (bson_impl_alloc_t *) dst; adst->flags = BSON_FLAG_STATIC; @@ -2249,10 +2219,6 @@ bson_reserve_buffer (bson_t *bson, uint32_t size) return NULL; } - MONGOC_DEBUG_ASSERT ((size_t) bson->len <= BSON_MAX_SIZE); - if ((size_t) size > BSON_MAX_SIZE - (size_t) bson->len) { - return NULL; - } if (!_bson_grow (bson, size)) { return NULL; } From 91adb2ae43116d80fded35af22a8d6ebc805db9a Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Thu, 27 Feb 2025 12:09:35 -0800 Subject: [PATCH 35/51] Revert "bugfix for test_bson_reserve_buffer_errors" This reverts commit 05bd56afc125ee2e7f97d6ecd0ec4780d0adfe28. (Moved to CDRIVER-5915) --- src/libbson/tests/test-bson.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/libbson/tests/test-bson.c b/src/libbson/tests/test-bson.c index 49c2b2c0318..ecd288317ee 100644 --- a/src/libbson/tests/test-bson.c +++ b/src/libbson/tests/test-bson.c @@ -1886,11 +1886,7 @@ test_bson_reserve_buffer_errors (void) uint32_t len_le; /* too big */ - ASSERT (!bson_reserve_buffer (&bson, (uint32_t) (BSON_MAX_SIZE - bson.len + 1u))); - /* exactly the maximum size */ -#if BSON_WORD_SIZE > 32 - ASSERT (bson_reserve_buffer (&bson, (uint32_t) (BSON_MAX_SIZE - bson.len))); -#endif + ASSERT (!bson_reserve_buffer (&bson, (uint32_t) (INT32_MAX - bson.len - 1))); /* make a static bson, it refuses bson_reserve_buffer since it's read-only */ bson_destroy (&bson); From f2bb3183eb913dccf8c73ec5d87142b97e96dbbd Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Wed, 26 Feb 2025 20:34:23 -0800 Subject: [PATCH 36/51] CDRIVER-5915: Fix for allocation of bson_t larger than half max size --- src/libbson/src/bson/bson.c | 68 +++++++++++++++++++++++++++++------ src/libbson/tests/test-bson.c | 9 +++-- 2 files changed, 65 insertions(+), 12 deletions(-) diff --git a/src/libbson/src/bson/bson.c b/src/libbson/src/bson/bson.c index c32c8992aa1..0c807591c0f 100644 --- a/src/libbson/src/bson/bson.c +++ b/src/libbson/src/bson/bson.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -60,6 +61,36 @@ typedef struct { */ static const uint8_t gZero; +/* + *-------------------------------------------------------------------------- + * + * _bson_next_power_of_two_for_alloc -- + * + * Given a potential allocation length in bytes, round up to the + * next power of two without exceeding BSON_MAX_SIZE. + * + * Returns: + * If the input is <= BSON_MAX_SIZE, returns a value >= the input + * and still <= BSON_MAX_SIZE. If the input was greater than + * BSON_MAX_SIZE, it is returned unmodified. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +static BSON_INLINE size_t +_bson_next_power_of_two_for_alloc (size_t size) +{ + if (size <= BSON_MAX_SIZE) { + size_t power_of_two = bson_next_power_of_two (size); + return BSON_MIN (power_of_two, BSON_MAX_SIZE); + } else { + return size; + } +} + /* *-------------------------------------------------------------------------- * @@ -90,7 +121,7 @@ _bson_impl_inline_grow (bson_impl_inline_t *impl, /* IN */ return true; } - req = bson_next_power_of_two (impl->len + size); + req = _bson_next_power_of_two_for_alloc (impl->len + size); if (req <= BSON_MAX_SIZE) { data = bson_malloc (req); @@ -122,11 +153,12 @@ _bson_impl_inline_grow (bson_impl_inline_t *impl, /* IN */ * * _bson_impl_alloc_grow -- * - * Document growth implementation for documents containing malloc - * based buffers. + * Document growth implementation for non-inline documents, possibly + * containing a reallocatable buffer. * * Returns: - * true if successful; otherwise false indicating BSON_MAX_SIZE overflow. + * true if successful; otherwise false indicating BSON_MAX_SIZE overflow + * or an attempt to grow a buffer with no realloc implementation. * * Side effects: * None. @@ -143,6 +175,12 @@ _bson_impl_alloc_grow (bson_impl_alloc_t *impl, /* IN */ /* * Determine how many bytes we need for this document in the buffer * including necessary trailing bytes for parent documents. + * + * Note that the buffer offset and nesting depth are not available + * outside bson_impl_alloc_t, meaning it's not possible for callers to + * fully rule out BSON_MAX_SIZE overflow before _bson_grow(). + * Some earlier checks against BSON_MAX_SIZE serve to prevent intermediate + * overflows rather than to validate the final allocation size. */ req = (impl->offset + impl->len + size + impl->depth); @@ -150,7 +188,7 @@ _bson_impl_alloc_grow (bson_impl_alloc_t *impl, /* IN */ return true; } - req = bson_next_power_of_two (req); + req = _bson_next_power_of_two_for_alloc (req); if ((req <= BSON_MAX_SIZE) && impl->realloc) { *impl->buf = impl->realloc (*impl->buf, req, impl->realloc_func_ctx); @@ -168,10 +206,11 @@ _bson_impl_alloc_grow (bson_impl_alloc_t *impl, /* IN */ * _bson_grow -- * * Grows the bson_t structure to be large enough to contain @size - * bytes. + * bytes in addition to its current content. * * Returns: - * true if successful, false if the size would overflow. + * true if successful, false if the size would overflow or the buffer + * needs to grow but does not support reallocation. * * Side effects: * None. @@ -2097,7 +2136,7 @@ bson_copy_to (const bson_t *src, bson_t *dst) } data = _bson_data (src); - len = bson_next_power_of_two ((size_t) src->len); + len = _bson_next_power_of_two_for_alloc ((size_t) src->len); adst = (bson_impl_alloc_t *) dst; adst->flags = BSON_FLAG_STATIC; @@ -2219,15 +2258,24 @@ bson_reserve_buffer (bson_t *bson, uint32_t size) return NULL; } - if (!_bson_grow (bson, size)) { + /* The caller wants a total document size of "size". + * Note that the bson_t can also include space for parent or sibling documents (offset) and for trailing bytes + * (depth). These sizes will be considered by _bson_grow() but we can assume they are zero in documents without + * BSON_FLAG_CHILD or BSON_FLAG_IN_CHILD. If this is called on a document that's part of a bson_writer_t, it is + * correct to ignore offset: we set the size of the current document, leaving previous documents alone. */ + if (size > bson->len && !_bson_grow (bson, size - bson->len)) { + // Will fail due to overflow or when reallocation is needed on a buffer that does not support it. return NULL; } if (bson->flags & BSON_FLAG_INLINE) { /* bson_grow didn't spill over */ ((bson_impl_inline_t *) bson)->len = size; + BSON_ASSERT (size <= BSON_INLINE_DATA_SIZE); } else { - ((bson_impl_alloc_t *) bson)->len = size; + bson_impl_alloc_t *impl = (bson_impl_alloc_t *) bson; + impl->len = size; + BSON_ASSERT (impl->offset <= *impl->buflen && *impl->buflen - impl->offset >= (size_t) size); } return _bson_data (bson); diff --git a/src/libbson/tests/test-bson.c b/src/libbson/tests/test-bson.c index ecd288317ee..7300dddc846 100644 --- a/src/libbson/tests/test-bson.c +++ b/src/libbson/tests/test-bson.c @@ -1886,10 +1886,15 @@ test_bson_reserve_buffer_errors (void) uint32_t len_le; /* too big */ - ASSERT (!bson_reserve_buffer (&bson, (uint32_t) (INT32_MAX - bson.len - 1))); + ASSERT (!bson_reserve_buffer (&bson, (uint32_t) (BSON_MAX_SIZE + 1u))); + /* exactly the maximum size */ +#if BSON_WORD_SIZE > 32 + ASSERT (bson_reserve_buffer (&bson, (uint32_t) BSON_MAX_SIZE)); + ASSERT_CMPUINT32 (bson.len, ==, BSON_MAX_SIZE); +#endif + bson_destroy (&bson); /* make a static bson, it refuses bson_reserve_buffer since it's read-only */ - bson_destroy (&bson); len_le = BSON_UINT32_TO_LE (5); memcpy (data, &len_le, sizeof (len_le)); ASSERT (bson_init_static (&bson, data, sizeof data)); From c1363b09ceb7c57b6453919cfad236a850707924 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Thu, 27 Feb 2025 12:25:19 -0800 Subject: [PATCH 37/51] Revert "Use INFINITY and NAN for float but not double" This reverts commit 758856a17196d26092b9557fe5395d7b015ba112. --- src/libbson/src/bson/bson-vector.h | 3 +-- src/libbson/tests/test-bson-vector.c | 16 +++++----------- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/src/libbson/src/bson/bson-vector.h b/src/libbson/src/bson/bson-vector.h index 69b90308bcb..44562e118d7 100644 --- a/src/libbson/src/bson/bson-vector.h +++ b/src/libbson/src/bson/bson-vector.h @@ -195,8 +195,7 @@ BSON_EXPORT (bool) bson_append_vector_int8_uninit ( bson_t *bson, const char *key, int key_length, size_t element_count, bson_vector_int8_view_t *view_out); -#define BSON_APPEND_VECTOR_INT8_UNINIT(b, key, count, view) \ - bson_append_vector_int8_uninit (b, key, (int) strlen (key), count, view) +#define BSON_APPEND_VECTOR_INT8_UNINIT(b, key, count, view) bson_append_vector_int8_uninit (b, key, (int) strlen (key), count, view) BSON_EXPORT (bool) bson_append_vector_float32_uninit ( diff --git a/src/libbson/tests/test-bson-vector.c b/src/libbson/tests/test-bson-vector.c index cdccd31fcea..f70b471cc7d 100644 --- a/src/libbson/tests/test-bson-vector.c +++ b/src/libbson/tests/test-bson-vector.c @@ -58,12 +58,6 @@ typedef struct vector_json_test_case_t { bool *test_valid; } vector_json_test_case_t; -static BSON_INLINE double -double_inf (void) -{ - return 1.0 / 0.0; -} - static void translate_json_test_vector (bson_t *array_in, bson_t *array_out) { @@ -76,9 +70,9 @@ translate_json_test_vector (bson_t *array_in, bson_t *array_out) bson_array_builder_t *builder = bson_array_builder_new (); while (bson_iter_next (&iter_in)) { if (BSON_ITER_HOLDS_UTF8 (&iter_in) && 0 == strcmp ("inf", bson_iter_utf8 (&iter_in, NULL))) { - BSON_ASSERT (bson_array_builder_append_double (builder, double_inf ())); + BSON_ASSERT (bson_array_builder_append_double (builder, INFINITY)); } else if (BSON_ITER_HOLDS_UTF8 (&iter_in) && 0 == strcmp ("-inf", bson_iter_utf8 (&iter_in, NULL))) { - BSON_ASSERT (bson_array_builder_append_double (builder, -double_inf ())); + BSON_ASSERT (bson_array_builder_append_double (builder, -INFINITY)); } else { BSON_ASSERT (bson_array_builder_append_iter (builder, &iter_in)); } @@ -321,10 +315,10 @@ test_bson_vector_json_case (vector_json_test_case_t *test_case) double expected_double; if (BSON_ITER_HOLDS_UTF8 (&expected_iter) && 0 == strcmp ("inf", bson_iter_utf8 (&expected_iter, NULL))) { - expected_double = double_inf (); + expected_double = INFINITY; } else if (BSON_ITER_HOLDS_UTF8 (&expected_iter) && 0 == strcmp ("-inf", bson_iter_utf8 (&expected_iter, NULL))) { - expected_double = -double_inf (); + expected_double = -INFINITY; } else if (BSON_ITER_HOLDS_DOUBLE (&expected_iter)) { expected_double = bson_iter_double (&expected_iter); } else { @@ -1242,7 +1236,7 @@ test_bson_vector_example_float32_const_view (void) // setup: construct a sample document bson_t doc = BSON_INITIALIZER; { - static const float values[] = {5.0f, -1e10f, INFINITY, NAN, -1.0f}; + static const float values[] = {5.0f, -1e10f, (float) INFINITY, (float) NAN, -1.0f}; bson_vector_float32_view_t view; BSON_ASSERT (BSON_APPEND_VECTOR_FLOAT32_UNINIT (&doc, "vector", sizeof values / sizeof values[0], &view)); BSON_ASSERT (bson_vector_float32_view_write (view, values, sizeof values / sizeof values[0], 0)); From 277dda071468100939b0fe09ba32d3e0a92021e7 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Thu, 27 Feb 2025 12:27:09 -0800 Subject: [PATCH 38/51] clang-format --- src/libbson/src/bson/bson-vector.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libbson/src/bson/bson-vector.h b/src/libbson/src/bson/bson-vector.h index 44562e118d7..69b90308bcb 100644 --- a/src/libbson/src/bson/bson-vector.h +++ b/src/libbson/src/bson/bson-vector.h @@ -195,7 +195,8 @@ BSON_EXPORT (bool) bson_append_vector_int8_uninit ( bson_t *bson, const char *key, int key_length, size_t element_count, bson_vector_int8_view_t *view_out); -#define BSON_APPEND_VECTOR_INT8_UNINIT(b, key, count, view) bson_append_vector_int8_uninit (b, key, (int) strlen (key), count, view) +#define BSON_APPEND_VECTOR_INT8_UNINIT(b, key, count, view) \ + bson_append_vector_int8_uninit (b, key, (int) strlen (key), count, view) BSON_EXPORT (bool) bson_append_vector_float32_uninit ( From f8a349799fe785985aedd44abcc0572ac193f6d4 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Thu, 27 Feb 2025 12:27:14 -0800 Subject: [PATCH 39/51] Explicitly cast INFINITY to double --- src/libbson/tests/test-bson-vector.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libbson/tests/test-bson-vector.c b/src/libbson/tests/test-bson-vector.c index f70b471cc7d..6e242616e0b 100644 --- a/src/libbson/tests/test-bson-vector.c +++ b/src/libbson/tests/test-bson-vector.c @@ -70,9 +70,9 @@ translate_json_test_vector (bson_t *array_in, bson_t *array_out) bson_array_builder_t *builder = bson_array_builder_new (); while (bson_iter_next (&iter_in)) { if (BSON_ITER_HOLDS_UTF8 (&iter_in) && 0 == strcmp ("inf", bson_iter_utf8 (&iter_in, NULL))) { - BSON_ASSERT (bson_array_builder_append_double (builder, INFINITY)); + BSON_ASSERT (bson_array_builder_append_double (builder, (double) INFINITY)); } else if (BSON_ITER_HOLDS_UTF8 (&iter_in) && 0 == strcmp ("-inf", bson_iter_utf8 (&iter_in, NULL))) { - BSON_ASSERT (bson_array_builder_append_double (builder, -INFINITY)); + BSON_ASSERT (bson_array_builder_append_double (builder, (double) -INFINITY)); } else { BSON_ASSERT (bson_array_builder_append_iter (builder, &iter_in)); } @@ -315,10 +315,10 @@ test_bson_vector_json_case (vector_json_test_case_t *test_case) double expected_double; if (BSON_ITER_HOLDS_UTF8 (&expected_iter) && 0 == strcmp ("inf", bson_iter_utf8 (&expected_iter, NULL))) { - expected_double = INFINITY; + expected_double = (double) INFINITY; } else if (BSON_ITER_HOLDS_UTF8 (&expected_iter) && 0 == strcmp ("-inf", bson_iter_utf8 (&expected_iter, NULL))) { - expected_double = -INFINITY; + expected_double = (double) -INFINITY; } else if (BSON_ITER_HOLDS_DOUBLE (&expected_iter)) { expected_double = bson_iter_double (&expected_iter); } else { @@ -1236,7 +1236,7 @@ test_bson_vector_example_float32_const_view (void) // setup: construct a sample document bson_t doc = BSON_INITIALIZER; { - static const float values[] = {5.0f, -1e10f, (float) INFINITY, (float) NAN, -1.0f}; + static const float values[] = {5.0f, -1e10f, INFINITY, NAN, -1.0f}; bson_vector_float32_view_t view; BSON_ASSERT (BSON_APPEND_VECTOR_FLOAT32_UNINIT (&doc, "vector", sizeof values / sizeof values[0], &view)); BSON_ASSERT (bson_vector_float32_view_write (view, values, sizeof values / sizeof values[0], 0)); From fc7772da36b5ceaf52bdab0e028d5ef2a3d069e1 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Thu, 27 Feb 2025 12:31:36 -0800 Subject: [PATCH 40/51] Fix missing underline from earlier _uninit change --- src/libbson/doc/bson_append_vector_packed_bit_uninit.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libbson/doc/bson_append_vector_packed_bit_uninit.rst b/src/libbson/doc/bson_append_vector_packed_bit_uninit.rst index 8aaff981e92..40ef02ecc50 100644 --- a/src/libbson/doc/bson_append_vector_packed_bit_uninit.rst +++ b/src/libbson/doc/bson_append_vector_packed_bit_uninit.rst @@ -1,7 +1,7 @@ :man_page: bson_append_vector_packed_bit_uninit bson_append_vector_packed_bit_uninit() -=============================== +====================================== Synopsis -------- From 3e4ec4bb176f434aed16a014e5d9cd5e5120ce87 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Thu, 27 Feb 2025 13:18:44 -0800 Subject: [PATCH 41/51] test-bson-vector read/write edge cases use malloc'ed value buffers The main reason for this change is to avoid an unhelpful implementation of -Warray-bounds in gcc 11 which notices that the memcpy in these tests can be out-of-range, but doesn't notice that the out-of-range memcpy will never be executed. The easiest fix was to dynamically allocate the value buffers, to prevent gcc from associating range info with these pointers. This replaces some arbitrary nonzero test values with zeroes, out of convenience. --- src/libbson/tests/test-bson-vector.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/libbson/tests/test-bson-vector.c b/src/libbson/tests/test-bson-vector.c index 6e242616e0b..208ae7e6651 100644 --- a/src/libbson/tests/test-bson-vector.c +++ b/src/libbson/tests/test-bson-vector.c @@ -1431,10 +1431,11 @@ test_bson_vector_edge_cases_int8 (void) // Test some read and write boundaries. { - int8_t values[] = {1, 2, 3, 4, 5}; - size_t values_size = sizeof values / sizeof values[0]; + size_t values_size = 100; + int8_t *values = bson_malloc0 (values_size * sizeof *values); TEST_BSON_VECTOR_EDGE_CASES_RW_COMMON ( view, max_alloc_elements, values, values_size, bson_vector_int8_view_read, bson_vector_int8_view_write); + bson_free (values); } bson_destroy (&doc); @@ -1477,10 +1478,11 @@ test_bson_vector_edge_cases_float32 (void) // Test some read and write boundaries. { - float values[] = {1.f, 2.f, 3.f, 4.f, 5.f}; - size_t values_size = sizeof values / sizeof values[0]; + size_t values_size = 100; + float *values = bson_malloc0 (values_size * sizeof *values); TEST_BSON_VECTOR_EDGE_CASES_RW_COMMON ( view, max_alloc_elements, values, values_size, bson_vector_float32_view_read, bson_vector_float32_view_write); + bson_free (values); } bson_destroy (&doc); @@ -1524,28 +1526,28 @@ test_bson_vector_edge_cases_packed_bit (void) // Test pack and unpack boundaries with the same tests used for read/write of non-packed element types. // Only tests one length, but it's chosen to be greater than 8 and not a multiple of 8. { - bool values[190]; - size_t values_size = sizeof values / sizeof values[0]; - for (size_t i = 0; i < values_size; i++) { - values[i] = (i & 3) == 3; - } + size_t values_size = 190; + bool *values = bson_malloc0 (values_size * sizeof *values); TEST_BSON_VECTOR_EDGE_CASES_RW_COMMON (view, max_alloc_elements, values, values_size, bson_vector_packed_bit_view_unpack_bool, bson_vector_packed_bit_view_pack_bool); + bson_free (values); } // Test read and write boundaries on packed bytes. { - uint8_t packed[] = {0x12, 0x34, 0x56, 0x78, 0x9A}; + size_t packed_size = 50; + uint8_t *packed = bson_malloc0 (packed_size); TEST_BSON_VECTOR_EDGE_CASES_RW_COMMON (view, max_alloc_bytes, packed, - sizeof packed, + packed_size, bson_vector_packed_bit_view_read_packed, bson_vector_packed_bit_view_write_packed); + bson_free (packed); } bson_destroy (&doc); From 35b0b31e9bae124fdafaa3b4dd308edf4a718491 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Thu, 27 Feb 2025 14:41:05 -0800 Subject: [PATCH 42/51] Reconsider function name (_bson_round_up_alloc_size) The new name doesn't misleadingly imply that the result is always a power of two. --- src/libbson/src/bson/bson.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libbson/src/bson/bson.c b/src/libbson/src/bson/bson.c index 0c807591c0f..f5f48efed23 100644 --- a/src/libbson/src/bson/bson.c +++ b/src/libbson/src/bson/bson.c @@ -64,7 +64,7 @@ static const uint8_t gZero; /* *-------------------------------------------------------------------------- * - * _bson_next_power_of_two_for_alloc -- + * _bson_round_up_alloc_size -- * * Given a potential allocation length in bytes, round up to the * next power of two without exceeding BSON_MAX_SIZE. @@ -81,7 +81,7 @@ static const uint8_t gZero; */ static BSON_INLINE size_t -_bson_next_power_of_two_for_alloc (size_t size) +_bson_round_up_alloc_size (size_t size) { if (size <= BSON_MAX_SIZE) { size_t power_of_two = bson_next_power_of_two (size); @@ -121,7 +121,7 @@ _bson_impl_inline_grow (bson_impl_inline_t *impl, /* IN */ return true; } - req = _bson_next_power_of_two_for_alloc (impl->len + size); + req = _bson_round_up_alloc_size (impl->len + size); if (req <= BSON_MAX_SIZE) { data = bson_malloc (req); @@ -188,7 +188,7 @@ _bson_impl_alloc_grow (bson_impl_alloc_t *impl, /* IN */ return true; } - req = _bson_next_power_of_two_for_alloc (req); + req = _bson_round_up_alloc_size (req); if ((req <= BSON_MAX_SIZE) && impl->realloc) { *impl->buf = impl->realloc (*impl->buf, req, impl->realloc_func_ctx); @@ -2136,7 +2136,7 @@ bson_copy_to (const bson_t *src, bson_t *dst) } data = _bson_data (src); - len = _bson_next_power_of_two_for_alloc ((size_t) src->len); + len = _bson_round_up_alloc_size ((size_t) src->len); adst = (bson_impl_alloc_t *) dst; adst->flags = BSON_FLAG_STATIC; From 7b2c32481b76b32af2f274f1e760ae790906f1c0 Mon Sep 17 00:00:00 2001 From: mdbmes Date: Fri, 28 Feb 2025 15:08:46 -0800 Subject: [PATCH 43/51] Update src/libbson/tests/test-bson-vector.c Co-authored-by: Ezra Chung <88335979+eramongodb@users.noreply.github.com> --- src/libbson/tests/test-bson-vector.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libbson/tests/test-bson-vector.c b/src/libbson/tests/test-bson-vector.c index 208ae7e6651..ff4f8f34aa0 100644 --- a/src/libbson/tests/test-bson-vector.c +++ b/src/libbson/tests/test-bson-vector.c @@ -985,7 +985,7 @@ test_bson_vector_view_api_fuzz_int8 (void) } else if (r_operation < 7) { // Partial write size_t element_count = r_param % current_length; - size_t offset = rand () % (current_length - element_count); + size_t offset = (size_t) rand () % (current_length - element_count); for (size_t i = 0; i < element_count; i++) { expected_elements[offset + i] = (int8_t) (uint8_t) rand (); } From 4337a3d6c774e9c8b8e699124db205e0cbb73d64 Mon Sep 17 00:00:00 2001 From: mdbmes Date: Fri, 28 Feb 2025 15:17:01 -0800 Subject: [PATCH 44/51] Update src/libbson/tests/test-bson-vector.c Co-authored-by: Ezra Chung <88335979+eramongodb@users.noreply.github.com> --- src/libbson/tests/test-bson-vector.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libbson/tests/test-bson-vector.c b/src/libbson/tests/test-bson-vector.c index ff4f8f34aa0..2eb4e8aa345 100644 --- a/src/libbson/tests/test-bson-vector.c +++ b/src/libbson/tests/test-bson-vector.c @@ -975,7 +975,7 @@ test_bson_vector_view_api_fuzz_int8 (void) size_t new_length = (size_t) r_param % MAX_TESTED_VECTOR_LENGTH; bson_reinit (&vector_doc); bson_vector_int8_view_t view; - BSON_ASSERT (BSON_APPEND_VECTOR_INT8_UNINIT (&vector_doc, "vector", new_length, &view)); + ASSERT (BSON_APPEND_VECTOR_INT8_UNINIT (&vector_doc, "vector", new_length, &view)); for (size_t i = 0; i < new_length; i++) { expected_elements[i] = (int8_t) (uint8_t) rand (); } From f89c255c8d88768ea13fe985c4cf01eef3c2988b Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Fri, 28 Feb 2025 15:31:36 -0800 Subject: [PATCH 45/51] End statement-like macros with a statement that requires a semicolon --- src/libbson/tests/test-bson-vector.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libbson/tests/test-bson-vector.c b/src/libbson/tests/test-bson-vector.c index 2eb4e8aa345..a2c0073fb38 100644 --- a/src/libbson/tests/test-bson-vector.c +++ b/src/libbson/tests/test-bson-vector.c @@ -1383,8 +1383,8 @@ test_bson_vector_example_packed_bit_view (void) if (true) { \ ASSERT ((_expected) == (_write) ((_view), (_v), (_count), (_offset))); \ ASSERT ((_expected) == (_read) ((_view), (_v), (_count), (_offset))); \ - } else { \ - } + } else \ + ((void) 0) #define TEST_BSON_VECTOR_EDGE_CASES_RW_COMMON(_view, _alloc_size, _v, _v_size, _read, _write) \ if (true) { \ @@ -1395,8 +1395,8 @@ test_bson_vector_example_packed_bit_view (void) TEST_BSON_VECTOR_RW (false, (_view), (_v), SIZE_MAX, (_alloc_size) - (_v_size), (_read), (_write)); \ TEST_BSON_VECTOR_RW (false, (_view), (_v), SIZE_MAX, (_alloc_size) - (_v_size) + 1u, (_read), (_write)); \ TEST_BSON_VECTOR_RW (true, (_view), (_v), (_v_size), 0, (_read), (_write)); \ - } else { \ - } + } else \ + ((void) 0) static void test_bson_vector_edge_cases_int8 (void) From 66104f733faa9ae606928519f13a5399f2e321a2 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Fri, 28 Feb 2025 15:35:07 -0800 Subject: [PATCH 46/51] Replace BSON_ASSERT with ASSERT in test-bson-vector --- src/libbson/tests/test-bson-vector.c | 163 +++++++++++++-------------- 1 file changed, 81 insertions(+), 82 deletions(-) diff --git a/src/libbson/tests/test-bson-vector.c b/src/libbson/tests/test-bson-vector.c index a2c0073fb38..bec708d6c2d 100644 --- a/src/libbson/tests/test-bson-vector.c +++ b/src/libbson/tests/test-bson-vector.c @@ -66,18 +66,18 @@ translate_json_test_vector (bson_t *array_in, bson_t *array_out) // - convert "-inf" to a double -Infinity bson_iter_t iter_in; - BSON_ASSERT (bson_iter_init (&iter_in, array_in)); + ASSERT (bson_iter_init (&iter_in, array_in)); bson_array_builder_t *builder = bson_array_builder_new (); while (bson_iter_next (&iter_in)) { if (BSON_ITER_HOLDS_UTF8 (&iter_in) && 0 == strcmp ("inf", bson_iter_utf8 (&iter_in, NULL))) { - BSON_ASSERT (bson_array_builder_append_double (builder, (double) INFINITY)); + ASSERT (bson_array_builder_append_double (builder, (double) INFINITY)); } else if (BSON_ITER_HOLDS_UTF8 (&iter_in) && 0 == strcmp ("-inf", bson_iter_utf8 (&iter_in, NULL))) { - BSON_ASSERT (bson_array_builder_append_double (builder, (double) -INFINITY)); + ASSERT (bson_array_builder_append_double (builder, (double) -INFINITY)); } else { - BSON_ASSERT (bson_array_builder_append_iter (builder, &iter_in)); + ASSERT (bson_array_builder_append_iter (builder, &iter_in)); } } - BSON_ASSERT (bson_array_builder_build (builder, array_out)); + ASSERT (bson_array_builder_build (builder, array_out)); bson_array_builder_destroy (builder); } @@ -143,9 +143,9 @@ append_vector_packed_bit_from_packed_array ( if (bson_append_vector_packed_bit_uninit (bson, key, key_length, byte_count * 8u - (size_t) padding, &view)) { bson_iter_t copy_iter = *iter; for (size_t i = 0; i < byte_count; i++) { - BSON_ASSERT (bson_iter_next (©_iter)); + ASSERT (bson_iter_next (©_iter)); uint8_t packed_byte = (uint8_t) bson_iter_as_int64 (©_iter); - BSON_ASSERT (bson_vector_packed_bit_view_write_packed (view, &packed_byte, 1, i)); + ASSERT (bson_vector_packed_bit_view_write_packed (view, &packed_byte, 1, i)); } return true; } else { @@ -160,7 +160,7 @@ hex_str_to_bson (bson_t *bson_out, const char *hex_str) uint8_t *buffer = bson_reserve_buffer (bson_out, size); for (uint32_t i = 0; i < size; i++) { unsigned int byte; - BSON_ASSERT (SSCANF (&hex_str[i * 2], "%2x", &byte) == 1); + ASSERT (SSCANF (&hex_str[i * 2], "%2x", &byte) == 1); buffer[i] = (uint8_t) byte; } } @@ -174,9 +174,9 @@ test_bson_vector_json_case (vector_json_test_case_t *test_case) hex_str_to_bson (&expected_bson, test_case->test_canonical_bson_str); } - BSON_ASSERT (test_case->test_valid); - BSON_ASSERT (test_case->test_dtype_hex_str); - BSON_ASSERT (test_case->scenario_test_key); + ASSERT (test_case->test_valid); + ASSERT (test_case->test_dtype_hex_str); + ASSERT (test_case->scenario_test_key); bson_t vector_from_array = BSON_INITIALIZER; bson_error_t vector_from_array_error; @@ -185,11 +185,11 @@ test_bson_vector_json_case (vector_json_test_case_t *test_case) // (TODO for DRIVERS-3095, DRIVERS-3097) Patch test cases that have unused bits set to '1' when '0' is required. if (0 == strcmp ("PACKED_BIT with padding", test_case->test_description)) { bson_iter_t iter; - BSON_ASSERT (bson_iter_init_find (&iter, &expected_bson, test_case->scenario_test_key)); + ASSERT (bson_iter_init_find (&iter, &expected_bson, test_case->scenario_test_key)); uint32_t binary_len; uint8_t *binary; bson_iter_overwrite_binary (&iter, BSON_SUBTYPE_VECTOR, &binary_len, &binary); - BSON_ASSERT (binary_len > BSON_VECTOR_HEADER_LEN); + ASSERT (binary_len > BSON_VECTOR_HEADER_LEN); binary[binary_len - 1] &= (uint8_t) 0xFF << bson_vector_padding_from_header_byte_1 (binary[1]); } @@ -273,7 +273,7 @@ test_bson_vector_json_case (vector_json_test_case_t *test_case) // Perform an array-from-vector and check it ("decode") bson_iter_t iter; - BSON_ASSERT (bson_iter_init_find (&iter, &expected_bson, test_case->scenario_test_key)); + ASSERT (bson_iter_init_find (&iter, &expected_bson, test_case->scenario_test_key)); bson_t array_from_vector = BSON_INITIALIZER; { @@ -282,7 +282,7 @@ test_bson_vector_json_case (vector_json_test_case_t *test_case) test_error ("test '%s' should be valid but failed array-from-vector conversion", test_case->test_description); } - BSON_ASSERT (bson_array_builder_build (array_builder, &array_from_vector)); + ASSERT (bson_array_builder_build (array_builder, &array_from_vector)); bson_array_builder_destroy (array_builder); } @@ -294,8 +294,8 @@ test_bson_vector_json_case (vector_json_test_case_t *test_case) // due to underspecified rounding and conversion rules we compare value inexactly. bson_iter_t actual_iter, expected_iter; - BSON_ASSERT (bson_iter_init (&actual_iter, &array_from_vector)); - BSON_ASSERT (bson_iter_init (&expected_iter, test_case->test_vector_array)); + ASSERT (bson_iter_init (&actual_iter, &array_from_vector)); + ASSERT (bson_iter_init (&expected_iter, test_case->test_vector_array)); for (size_t i = 0;; i++) { bool actual_next = bson_iter_next (&actual_iter); @@ -359,9 +359,9 @@ test_bson_vector_json_case (vector_json_test_case_t *test_case) // 'array_from_vector' is ignored on this path. bson_iter_t expected_iter; - BSON_ASSERT (bson_iter_init (&expected_iter, test_case->test_vector_array)); + ASSERT (bson_iter_init (&expected_iter, test_case->test_vector_array)); bson_vector_packed_bit_const_view_t actual_view; - BSON_ASSERT (bson_vector_packed_bit_const_view_from_iter (&actual_view, &iter)); + ASSERT (bson_vector_packed_bit_const_view_from_iter (&actual_view, &iter)); size_t byte_count = 0; while (bson_iter_next (&expected_iter)) { @@ -383,7 +383,7 @@ test_bson_vector_json_case (vector_json_test_case_t *test_case) // Note, the zero initializer is only needed due to a false positive -Wmaybe-uninitialized warning in // uncommon configurations where the compiler does not have visibility into memcpy(). uint8_t actual_byte = 0; - BSON_ASSERT (bson_vector_packed_bit_const_view_read_packed (actual_view, &actual_byte, 1, byte_count)); + ASSERT (bson_vector_packed_bit_const_view_read_packed (actual_view, &actual_byte, 1, byte_count)); if (expected_byte != (int64_t) actual_byte) { test_error ("failed to match packed byte %d of packed_bit test-vector. Actual: 0x%02x Expected: 0x%02x", @@ -429,7 +429,7 @@ test_bson_vector_json_case (vector_json_test_case_t *test_case) if (test_case->test_canonical_bson_str) { bson_t array_from_vector = BSON_INITIALIZER; bson_iter_t iter; - BSON_ASSERT (bson_iter_init_find (&iter, &expected_bson, test_case->scenario_test_key)); + ASSERT (bson_iter_init_find (&iter, &expected_bson, test_case->scenario_test_key)); if (BSON_APPEND_ARRAY_FROM_VECTOR (&array_from_vector, "should_fail", &iter)) { test_error ("bson_binary_vector JSON scenario '%s' test '%s' should be invalid but array-from-vector " "succeeded with result: %s", @@ -979,7 +979,7 @@ test_bson_vector_view_api_fuzz_int8 (void) for (size_t i = 0; i < new_length; i++) { expected_elements[i] = (int8_t) (uint8_t) rand (); } - BSON_ASSERT (bson_vector_int8_view_write (view, expected_elements, new_length, 0)); + ASSERT (bson_vector_int8_view_write (view, expected_elements, new_length, 0)); current_length = new_length; } else if (r_operation < 7) { @@ -991,9 +991,9 @@ test_bson_vector_view_api_fuzz_int8 (void) } bson_vector_int8_view_t view; bson_iter_t iter; - BSON_ASSERT (bson_iter_init_find (&iter, &vector_doc, "vector")); - BSON_ASSERT (bson_vector_int8_view_from_iter (&view, &iter)); - BSON_ASSERT (bson_vector_int8_view_write (view, expected_elements + offset, element_count, offset)); + ASSERT (bson_iter_init_find (&iter, &vector_doc, "vector")); + ASSERT (bson_vector_int8_view_from_iter (&view, &iter)); + ASSERT (bson_vector_int8_view_write (view, expected_elements + offset, element_count, offset)); } else { // Partial read @@ -1001,11 +1001,11 @@ test_bson_vector_view_api_fuzz_int8 (void) size_t offset = rand () % (current_length - element_count); bson_vector_int8_const_view_t view; bson_iter_t iter; - BSON_ASSERT (bson_iter_init_find (&iter, &vector_doc, "vector")); - BSON_ASSERT (bson_vector_int8_const_view_from_iter (&view, &iter)); - BSON_ASSERT (bson_vector_int8_const_view_read (view, actual_elements, element_count, offset)); + ASSERT (bson_iter_init_find (&iter, &vector_doc, "vector")); + ASSERT (bson_vector_int8_const_view_from_iter (&view, &iter)); + ASSERT (bson_vector_int8_const_view_read (view, actual_elements, element_count, offset)); for (size_t i = 0; i < element_count; i++) { - BSON_ASSERT (actual_elements[i] == expected_elements[i + offset]); + ASSERT (actual_elements[i] == expected_elements[i + offset]); } } } @@ -1031,11 +1031,11 @@ test_bson_vector_view_api_fuzz_float32 (void) size_t new_length = (size_t) r_param % MAX_TESTED_VECTOR_LENGTH; bson_reinit (&vector_doc); bson_vector_float32_view_t view; - BSON_ASSERT (BSON_APPEND_VECTOR_FLOAT32_UNINIT (&vector_doc, "vector", new_length, &view)); + ASSERT (BSON_APPEND_VECTOR_FLOAT32_UNINIT (&vector_doc, "vector", new_length, &view)); for (size_t i = 0; i < new_length; i++) { expected_elements[i] = (float) rand (); } - BSON_ASSERT (bson_vector_float32_view_write (view, expected_elements, new_length, 0)); + ASSERT (bson_vector_float32_view_write (view, expected_elements, new_length, 0)); current_length = new_length; } else if (r_operation < 7) { @@ -1047,9 +1047,9 @@ test_bson_vector_view_api_fuzz_float32 (void) } bson_vector_float32_view_t view; bson_iter_t iter; - BSON_ASSERT (bson_iter_init_find (&iter, &vector_doc, "vector")); - BSON_ASSERT (bson_vector_float32_view_from_iter (&view, &iter)); - BSON_ASSERT (bson_vector_float32_view_write (view, expected_elements + offset, element_count, offset)); + ASSERT (bson_iter_init_find (&iter, &vector_doc, "vector")); + ASSERT (bson_vector_float32_view_from_iter (&view, &iter)); + ASSERT (bson_vector_float32_view_write (view, expected_elements + offset, element_count, offset)); } else { // Partial read @@ -1057,11 +1057,11 @@ test_bson_vector_view_api_fuzz_float32 (void) size_t offset = rand () % (current_length - element_count); bson_vector_float32_const_view_t view; bson_iter_t iter; - BSON_ASSERT (bson_iter_init_find (&iter, &vector_doc, "vector")); - BSON_ASSERT (bson_vector_float32_const_view_from_iter (&view, &iter)); - BSON_ASSERT (bson_vector_float32_const_view_read (view, actual_elements, element_count, offset)); + ASSERT (bson_iter_init_find (&iter, &vector_doc, "vector")); + ASSERT (bson_vector_float32_const_view_from_iter (&view, &iter)); + ASSERT (bson_vector_float32_const_view_read (view, actual_elements, element_count, offset)); for (size_t i = 0; i < element_count; i++) { - BSON_ASSERT (actual_elements[i] == expected_elements[i + offset]); + ASSERT (actual_elements[i] == expected_elements[i + offset]); } } } @@ -1088,11 +1088,11 @@ test_bson_vector_view_api_fuzz_packed_bit (void) size_t new_length = (size_t) r_param % MAX_TESTED_VECTOR_LENGTH; bson_reinit (&vector_doc); bson_vector_packed_bit_view_t view; - BSON_ASSERT (BSON_APPEND_VECTOR_PACKED_BIT_UNINIT (&vector_doc, "vector", new_length, &view)); + ASSERT (BSON_APPEND_VECTOR_PACKED_BIT_UNINIT (&vector_doc, "vector", new_length, &view)); for (size_t i = 0; i < new_length; i++) { expected_elements[i] = (rand () & 1) != 0; } - BSON_ASSERT (bson_vector_packed_bit_view_pack_bool (view, expected_elements, new_length, 0)); + ASSERT (bson_vector_packed_bit_view_pack_bool (view, expected_elements, new_length, 0)); current_length = new_length; } else if (r_operation < 7) { @@ -1106,11 +1106,10 @@ test_bson_vector_view_api_fuzz_packed_bit (void) } bson_vector_packed_bit_view_t view; bson_iter_t iter; - BSON_ASSERT (bson_iter_init_find (&iter, &vector_doc, "vector")); - BSON_ASSERT (bson_vector_packed_bit_view_from_iter (&view, &iter)); - BSON_ASSERT (bson_vector_packed_bit_view_length (view) == current_length); - BSON_ASSERT ( - bson_vector_packed_bit_view_pack_bool (view, expected_elements + offset, element_count, offset)); + ASSERT (bson_iter_init_find (&iter, &vector_doc, "vector")); + ASSERT (bson_vector_packed_bit_view_from_iter (&view, &iter)); + ASSERT (bson_vector_packed_bit_view_length (view) == current_length); + ASSERT (bson_vector_packed_bit_view_pack_bool (view, expected_elements + offset, element_count, offset)); } else { // Partial write of packed bytes size_t current_length_bytes = (current_length + 7) / 8; @@ -1125,11 +1124,11 @@ test_bson_vector_view_api_fuzz_packed_bit (void) } bson_vector_packed_bit_view_t view; bson_iter_t iter; - BSON_ASSERT (bson_iter_init_find (&iter, &vector_doc, "vector")); - BSON_ASSERT (bson_vector_packed_bit_view_from_iter (&view, &iter)); - BSON_ASSERT (bson_vector_packed_bit_view_length (view) == current_length); - BSON_ASSERT (bson_vector_packed_bit_view_length_bytes (view) == current_length_bytes); - BSON_ASSERT (bson_vector_packed_bit_view_write_packed (view, packed_buffer, byte_count, byte_offset)); + ASSERT (bson_iter_init_find (&iter, &vector_doc, "vector")); + ASSERT (bson_vector_packed_bit_view_from_iter (&view, &iter)); + ASSERT (bson_vector_packed_bit_view_length (view) == current_length); + ASSERT (bson_vector_packed_bit_view_length_bytes (view) == current_length_bytes); + ASSERT (bson_vector_packed_bit_view_write_packed (view, packed_buffer, byte_count, byte_offset)); } } else { // Partial read @@ -1139,12 +1138,12 @@ test_bson_vector_view_api_fuzz_packed_bit (void) size_t offset = rand () % (current_length - element_count); bson_vector_packed_bit_const_view_t view; bson_iter_t iter; - BSON_ASSERT (bson_iter_init_find (&iter, &vector_doc, "vector")); - BSON_ASSERT (bson_vector_packed_bit_const_view_from_iter (&view, &iter)); - BSON_ASSERT (bson_vector_packed_bit_const_view_length (view) == current_length); - BSON_ASSERT (bson_vector_packed_bit_const_view_unpack_bool (view, actual_elements, element_count, offset)); + ASSERT (bson_iter_init_find (&iter, &vector_doc, "vector")); + ASSERT (bson_vector_packed_bit_const_view_from_iter (&view, &iter)); + ASSERT (bson_vector_packed_bit_const_view_length (view) == current_length); + ASSERT (bson_vector_packed_bit_const_view_unpack_bool (view, actual_elements, element_count, offset)); for (size_t i = 0; i < element_count; i++) { - BSON_ASSERT (actual_elements[i] == expected_elements[i + offset]); + ASSERT (actual_elements[i] == expected_elements[i + offset]); } } else { // Partial read of packed bytes @@ -1153,15 +1152,15 @@ test_bson_vector_view_api_fuzz_packed_bit (void) size_t byte_offset = rand () % (current_length_bytes - byte_count); bson_vector_packed_bit_const_view_t view; bson_iter_t iter; - BSON_ASSERT (bson_iter_init_find (&iter, &vector_doc, "vector")); - BSON_ASSERT (bson_vector_packed_bit_const_view_from_iter (&view, &iter)); - BSON_ASSERT (bson_vector_packed_bit_const_view_length (view) == current_length); - BSON_ASSERT (bson_vector_packed_bit_const_view_length_bytes (view) == current_length_bytes); - BSON_ASSERT (bson_vector_packed_bit_const_view_read_packed (view, packed_buffer, byte_count, byte_offset)); + ASSERT (bson_iter_init_find (&iter, &vector_doc, "vector")); + ASSERT (bson_vector_packed_bit_const_view_from_iter (&view, &iter)); + ASSERT (bson_vector_packed_bit_const_view_length (view) == current_length); + ASSERT (bson_vector_packed_bit_const_view_length_bytes (view) == current_length_bytes); + ASSERT (bson_vector_packed_bit_const_view_read_packed (view, packed_buffer, byte_count, byte_offset)); for (size_t i = 0; i < byte_count; i++) { uint8_t packed_byte = packed_buffer[i]; for (unsigned bit = 0; bit < 8; bit++) { - BSON_ASSERT (expected_elements[(byte_offset + i) * 8 + bit] == ((packed_byte & (0x80 >> bit)) != 0)); + ASSERT (expected_elements[(byte_offset + i) * 8 + bit] == ((packed_byte & (0x80 >> bit)) != 0)); } } } @@ -1181,8 +1180,8 @@ test_bson_vector_example_int8_const_view (void) { static const int8_t values[] = {12, 34, -56}; bson_vector_int8_view_t view; - BSON_ASSERT (BSON_APPEND_VECTOR_INT8_UNINIT (&doc, "vector", sizeof values / sizeof values[0], &view)); - BSON_ASSERT (bson_vector_int8_view_write (view, values, sizeof values / sizeof values[0], 0)); + ASSERT (BSON_APPEND_VECTOR_INT8_UNINIT (&doc, "vector", sizeof values / sizeof values[0], &view)); + ASSERT (bson_vector_int8_view_write (view, values, sizeof values / sizeof values[0], 0)); } // bson_vector_int8_const_view_t.rst @@ -1201,7 +1200,7 @@ test_bson_vector_example_int8_const_view (void) } for (size_t i = 0; i < length; i++) { int8_t element = 0; // Workaround - BSON_ASSERT (bson_vector_int8_const_view_read (view, &element, 1, i)); + ASSERT (bson_vector_int8_const_view_read (view, &element, 1, i)); if (test_suite_debug_output ()) { printf (" [%d] = %d\n", (int) i, (int) element); } @@ -1223,8 +1222,8 @@ test_bson_vector_example_int8_view (void) const size_t values_count = sizeof values / sizeof values[0]; bson_vector_int8_view_t view; - BSON_ASSERT (BSON_APPEND_VECTOR_INT8_UNINIT (&doc, "vector", values_count, &view)); - BSON_ASSERT (bson_vector_int8_view_write (view, values, values_count, 0)); + ASSERT (BSON_APPEND_VECTOR_INT8_UNINIT (&doc, "vector", values_count, &view)); + ASSERT (bson_vector_int8_view_write (view, values, values_count, 0)); } bson_destroy (&doc); @@ -1238,8 +1237,8 @@ test_bson_vector_example_float32_const_view (void) { static const float values[] = {5.0f, -1e10f, INFINITY, NAN, -1.0f}; bson_vector_float32_view_t view; - BSON_ASSERT (BSON_APPEND_VECTOR_FLOAT32_UNINIT (&doc, "vector", sizeof values / sizeof values[0], &view)); - BSON_ASSERT (bson_vector_float32_view_write (view, values, sizeof values / sizeof values[0], 0)); + ASSERT (BSON_APPEND_VECTOR_FLOAT32_UNINIT (&doc, "vector", sizeof values / sizeof values[0], &view)); + ASSERT (bson_vector_float32_view_write (view, values, sizeof values / sizeof values[0], 0)); } // bson_vector_float32_const_view_t.rst @@ -1256,7 +1255,7 @@ test_bson_vector_example_float32_const_view (void) } for (size_t i = 0; i < length; i++) { float element; - BSON_ASSERT (bson_vector_float32_const_view_read (view, &element, 1, i)); + ASSERT (bson_vector_float32_const_view_read (view, &element, 1, i)); if (test_suite_debug_output ()) { printf (" [%d] = %f\n", (int) i, element); } @@ -1278,8 +1277,8 @@ test_bson_vector_example_float32_view (void) const size_t values_count = sizeof values / sizeof values[0]; bson_vector_float32_view_t view; - BSON_ASSERT (BSON_APPEND_VECTOR_FLOAT32_UNINIT (&doc, "vector", values_count, &view)); - BSON_ASSERT (bson_vector_float32_view_write (view, values, values_count, 0)); + ASSERT (BSON_APPEND_VECTOR_FLOAT32_UNINIT (&doc, "vector", values_count, &view)); + ASSERT (bson_vector_float32_view_write (view, values, values_count, 0)); } bson_destroy (&doc); @@ -1293,8 +1292,8 @@ test_bson_vector_example_packed_bit_const_view (void) { static const bool values[] = {true, false, true, true, false, true, false, true, true, false}; bson_vector_packed_bit_view_t view; - BSON_ASSERT (BSON_APPEND_VECTOR_PACKED_BIT_UNINIT (&doc, "vector", sizeof values / sizeof values[0], &view)); - BSON_ASSERT (bson_vector_packed_bit_view_pack_bool (view, values, sizeof values / sizeof values[0], 0)); + ASSERT (BSON_APPEND_VECTOR_PACKED_BIT_UNINIT (&doc, "vector", sizeof values / sizeof values[0], &view)); + ASSERT (bson_vector_packed_bit_view_pack_bool (view, values, sizeof values / sizeof values[0], 0)); } // bson_vector_packed_bit_const_view_t.rst @@ -1316,7 +1315,7 @@ test_bson_vector_example_packed_bit_const_view (void) } for (size_t i = 0; i < length; i++) { bool element; - BSON_ASSERT (bson_vector_packed_bit_const_view_unpack_bool (view, &element, 1, i)); + ASSERT (bson_vector_packed_bit_const_view_unpack_bool (view, &element, 1, i)); if (test_suite_debug_output ()) { printf (" elements[%d] = %d\n", (int) i, (int) element); } @@ -1327,7 +1326,7 @@ test_bson_vector_example_packed_bit_const_view (void) } for (size_t i = 0; i < length_bytes; i++) { uint8_t packed_byte = 0; // Workaround - BSON_ASSERT (bson_vector_packed_bit_const_view_read_packed (view, &packed_byte, 1, i)); + ASSERT (bson_vector_packed_bit_const_view_read_packed (view, &packed_byte, 1, i)); if (test_suite_debug_output ()) { printf (" bytes[%d] = 0x%02x\n", (int) i, (unsigned) packed_byte); } @@ -1351,8 +1350,8 @@ test_bson_vector_example_packed_bit_view (void) const size_t bool_values_count = sizeof bool_values / sizeof bool_values[0]; bson_vector_packed_bit_view_t view; - BSON_ASSERT (BSON_APPEND_VECTOR_PACKED_BIT_UNINIT (&doc, "from_bool", bool_values_count, &view)); - BSON_ASSERT (bson_vector_packed_bit_view_pack_bool (view, bool_values, bool_values_count, 0)); + ASSERT (BSON_APPEND_VECTOR_PACKED_BIT_UNINIT (&doc, "from_bool", bool_values_count, &view)); + ASSERT (bson_vector_packed_bit_view_pack_bool (view, bool_values, bool_values_count, 0)); } // Fill another new vector with packed bytes @@ -1362,16 +1361,16 @@ test_bson_vector_example_packed_bit_view (void) const size_t packed_values_count = sizeof packed_bytes * 8 - unused_bits_count; bson_vector_packed_bit_view_t view; - BSON_ASSERT (BSON_APPEND_VECTOR_PACKED_BIT_UNINIT (&doc, "from_packed", packed_values_count, &view)); - BSON_ASSERT (bson_vector_packed_bit_view_write_packed (view, packed_bytes, sizeof packed_bytes, 0)); + ASSERT (BSON_APPEND_VECTOR_PACKED_BIT_UNINIT (&doc, "from_packed", packed_values_count, &view)); + ASSERT (bson_vector_packed_bit_view_write_packed (view, packed_bytes, sizeof packed_bytes, 0)); } // Compare both vectors. They match exactly. { bson_iter_t from_bool_iter, from_packed_iter; - BSON_ASSERT (bson_iter_init_find (&from_bool_iter, &doc, "from_bool")); - BSON_ASSERT (bson_iter_init_find (&from_packed_iter, &doc, "from_packed")); - BSON_ASSERT (bson_iter_binary_equal (&from_bool_iter, &from_packed_iter)); + ASSERT (bson_iter_init_find (&from_bool_iter, &doc, "from_bool")); + ASSERT (bson_iter_init_find (&from_packed_iter, &doc, "from_packed")); + ASSERT (bson_iter_binary_equal (&from_bool_iter, &from_packed_iter)); } } From 36f544dfe5d7a2739c18dabd92375630cd3fab55 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Fri, 28 Feb 2025 15:40:00 -0800 Subject: [PATCH 47/51] Explicit casts for all rand() calls in test-bson-vector --- src/libbson/tests/test-bson-vector.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/libbson/tests/test-bson-vector.c b/src/libbson/tests/test-bson-vector.c index bec708d6c2d..bcbc9c993ef 100644 --- a/src/libbson/tests/test-bson-vector.c +++ b/src/libbson/tests/test-bson-vector.c @@ -998,7 +998,7 @@ test_bson_vector_view_api_fuzz_int8 (void) } else { // Partial read size_t element_count = r_param % current_length; - size_t offset = rand () % (current_length - element_count); + size_t offset = (size_t) rand () % (current_length - element_count); bson_vector_int8_const_view_t view; bson_iter_t iter; ASSERT (bson_iter_init_find (&iter, &vector_doc, "vector")); @@ -1041,7 +1041,7 @@ test_bson_vector_view_api_fuzz_float32 (void) } else if (r_operation < 7) { // Partial write size_t element_count = r_param % current_length; - size_t offset = rand () % (current_length - element_count); + size_t offset = (size_t) rand () % (current_length - element_count); for (size_t i = 0; i < element_count; i++) { expected_elements[offset + i] = (float) rand (); } @@ -1054,7 +1054,7 @@ test_bson_vector_view_api_fuzz_float32 (void) } else { // Partial read size_t element_count = r_param % current_length; - size_t offset = rand () % (current_length - element_count); + size_t offset = (size_t) rand () % (current_length - element_count); bson_vector_float32_const_view_t view; bson_iter_t iter; ASSERT (bson_iter_init_find (&iter, &vector_doc, "vector")); @@ -1090,7 +1090,7 @@ test_bson_vector_view_api_fuzz_packed_bit (void) bson_vector_packed_bit_view_t view; ASSERT (BSON_APPEND_VECTOR_PACKED_BIT_UNINIT (&vector_doc, "vector", new_length, &view)); for (size_t i = 0; i < new_length; i++) { - expected_elements[i] = (rand () & 1) != 0; + expected_elements[i] = ((unsigned) rand () & 1u) != 0u; } ASSERT (bson_vector_packed_bit_view_pack_bool (view, expected_elements, new_length, 0)); current_length = new_length; @@ -1100,9 +1100,9 @@ test_bson_vector_view_api_fuzz_packed_bit (void) if (r_operation & 1) { // Partial write from unpacked bool source size_t element_count = r_param % current_length; - size_t offset = rand () % (current_length - element_count); + size_t offset = (size_t) rand () % (current_length - element_count); for (size_t i = 0; i < element_count; i++) { - expected_elements[offset + i] = (rand () & 1) != 0; + expected_elements[offset + i] = ((unsigned) rand () & 1u) != 0u; } bson_vector_packed_bit_view_t view; bson_iter_t iter; @@ -1114,7 +1114,7 @@ test_bson_vector_view_api_fuzz_packed_bit (void) // Partial write of packed bytes size_t current_length_bytes = (current_length + 7) / 8; size_t byte_count = r_param % current_length_bytes; - size_t byte_offset = rand () % (current_length_bytes - byte_count); + size_t byte_offset = (size_t) rand () % (current_length_bytes - byte_count); for (size_t i = 0; i < byte_count; i++) { uint8_t packed_byte = (uint8_t) rand (); packed_buffer[i] = packed_byte; @@ -1135,7 +1135,7 @@ test_bson_vector_view_api_fuzz_packed_bit (void) if (r_operation & 1) { // Partial read to unpacked bool destination size_t element_count = r_param % current_length; - size_t offset = rand () % (current_length - element_count); + size_t offset = (size_t) rand () % (current_length - element_count); bson_vector_packed_bit_const_view_t view; bson_iter_t iter; ASSERT (bson_iter_init_find (&iter, &vector_doc, "vector")); @@ -1149,7 +1149,7 @@ test_bson_vector_view_api_fuzz_packed_bit (void) // Partial read of packed bytes size_t current_length_bytes = (current_length + 7) / 8; size_t byte_count = r_param % current_length_bytes; - size_t byte_offset = rand () % (current_length_bytes - byte_count); + size_t byte_offset = (size_t) rand () % (current_length_bytes - byte_count); bson_vector_packed_bit_const_view_t view; bson_iter_t iter; ASSERT (bson_iter_init_find (&iter, &vector_doc, "vector")); From ca5171dec1cc71fd8314692a6e20bd415bc659f0 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Fri, 28 Feb 2025 16:17:28 -0800 Subject: [PATCH 48/51] Improve ASSERT_MEMCMP somewhat * evaluate inputs once, inside parenthesis * show errors with a hex dump instead of assuming the data is printable * include error location in the output --- src/libmongoc/tests/TestSuite.h | 36 ++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/src/libmongoc/tests/TestSuite.h b/src/libmongoc/tests/TestSuite.h index 635f4e3ff24..4d9a4ab3fb0 100644 --- a/src/libmongoc/tests/TestSuite.h +++ b/src/libmongoc/tests/TestSuite.h @@ -120,6 +120,20 @@ bson_open (const char *filename, int flags, ...) } else \ ((void) 0) +#define MONGOC_STDERR_HEXDUMP(pointer, length) \ + if (1) { \ + const uint8_t *_pointer = (const uint8_t *) (pointer); \ + const size_t _length = (length); \ + fflush (stdout); \ + putc ('<', stderr); \ + for (size_t _i = 0; _i < _length; _i++) { \ + fprintf (stderr, "%s%02x", _i ? " " : "", _pointer[_i]); \ + } \ + putc ('>', stderr); \ + fflush (stderr); \ + } else \ + ((void) 0) + #define ASSERT(Cond) \ do { \ if (!(Cond)) { \ @@ -260,15 +274,23 @@ _test_error (const char *format, ...) BSON_GNUC_PRINTF (1, 2); #define ASSERT_CMPDOUBLE(a, eq, b) ASSERT_CMPINT_HELPER (a, eq, b, "f", double) #define ASSERT_CMPVOID(a, eq, b) ASSERT_CMPINT_HELPER (a, eq, b, "p", void *) -#define ASSERT_MEMCMP(a, b, n) \ - do { \ - if (0 != memcmp (a, b, n)) { \ - MONGOC_STDERR_PRINTF ("Failed comparing %d bytes: \"%.*s\" != \"%.*s\"", n, n, (char *) a, n, (char *) b); \ - abort (); \ - } \ +#define ASSERT_MEMCMP(a, b, n) \ + do { \ + const void *_a = (a); \ + const void *_b = (b); \ + const size_t _n = (n); \ + if (0 != memcmp (_a, _b, _n)) { \ + MONGOC_STDERR_PRINTF ("FAIL\n\nAssert Failure: Expected an exact match of %" PRIu64 " bytes:\n ", \ + (uint64_t) _n); \ + MONGOC_STDERR_HEXDUMP (_a, _n); \ + fprintf (stderr, " !=\n "); \ + MONGOC_STDERR_HEXDUMP (_b, _n); \ + MONGOC_STDERR_PRINTF ("\n %s:%d %s()\n", __FILE__, (int) (__LINE__), BSON_FUNC); \ + fflush (stderr); \ + abort (); \ + } \ } while (0) - #ifdef ASSERT_ALMOST_EQUAL #undef ASSERT_ALMOST_EQUAL #endif From 1702a2a5a2d91a8f63d5252d75b002cedc34f9eb Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Fri, 28 Feb 2025 16:21:10 -0800 Subject: [PATCH 49/51] Use ASSERT_MEMCMP for exact comparison of float32 and other bulk elements --- src/libbson/tests/test-bson-vector.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/libbson/tests/test-bson-vector.c b/src/libbson/tests/test-bson-vector.c index bcbc9c993ef..98115178280 100644 --- a/src/libbson/tests/test-bson-vector.c +++ b/src/libbson/tests/test-bson-vector.c @@ -1004,9 +1004,7 @@ test_bson_vector_view_api_fuzz_int8 (void) ASSERT (bson_iter_init_find (&iter, &vector_doc, "vector")); ASSERT (bson_vector_int8_const_view_from_iter (&view, &iter)); ASSERT (bson_vector_int8_const_view_read (view, actual_elements, element_count, offset)); - for (size_t i = 0; i < element_count; i++) { - ASSERT (actual_elements[i] == expected_elements[i + offset]); - } + ASSERT_MEMCMP (actual_elements, expected_elements + offset, element_count * sizeof *actual_elements); } } bson_destroy (&vector_doc); @@ -1060,9 +1058,7 @@ test_bson_vector_view_api_fuzz_float32 (void) ASSERT (bson_iter_init_find (&iter, &vector_doc, "vector")); ASSERT (bson_vector_float32_const_view_from_iter (&view, &iter)); ASSERT (bson_vector_float32_const_view_read (view, actual_elements, element_count, offset)); - for (size_t i = 0; i < element_count; i++) { - ASSERT (actual_elements[i] == expected_elements[i + offset]); - } + ASSERT_MEMCMP (actual_elements, expected_elements + offset, element_count * sizeof *actual_elements); } } bson_destroy (&vector_doc); @@ -1142,9 +1138,7 @@ test_bson_vector_view_api_fuzz_packed_bit (void) ASSERT (bson_vector_packed_bit_const_view_from_iter (&view, &iter)); ASSERT (bson_vector_packed_bit_const_view_length (view) == current_length); ASSERT (bson_vector_packed_bit_const_view_unpack_bool (view, actual_elements, element_count, offset)); - for (size_t i = 0; i < element_count; i++) { - ASSERT (actual_elements[i] == expected_elements[i + offset]); - } + ASSERT_MEMCMP (actual_elements, expected_elements + offset, element_count * sizeof *actual_elements); } else { // Partial read of packed bytes size_t current_length_bytes = (current_length + 7) / 8; From 3e3d4db7b2afb3fea3535e3816ab7e1245f61137 Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Mon, 3 Mar 2025 08:40:07 -0800 Subject: [PATCH 50/51] Revert "Reconsider function name (_bson_round_up_alloc_size)" This reverts commit 35b0b31e9bae124fdafaa3b4dd308edf4a718491. --- src/libbson/src/bson/bson.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libbson/src/bson/bson.c b/src/libbson/src/bson/bson.c index f5f48efed23..0c807591c0f 100644 --- a/src/libbson/src/bson/bson.c +++ b/src/libbson/src/bson/bson.c @@ -64,7 +64,7 @@ static const uint8_t gZero; /* *-------------------------------------------------------------------------- * - * _bson_round_up_alloc_size -- + * _bson_next_power_of_two_for_alloc -- * * Given a potential allocation length in bytes, round up to the * next power of two without exceeding BSON_MAX_SIZE. @@ -81,7 +81,7 @@ static const uint8_t gZero; */ static BSON_INLINE size_t -_bson_round_up_alloc_size (size_t size) +_bson_next_power_of_two_for_alloc (size_t size) { if (size <= BSON_MAX_SIZE) { size_t power_of_two = bson_next_power_of_two (size); @@ -121,7 +121,7 @@ _bson_impl_inline_grow (bson_impl_inline_t *impl, /* IN */ return true; } - req = _bson_round_up_alloc_size (impl->len + size); + req = _bson_next_power_of_two_for_alloc (impl->len + size); if (req <= BSON_MAX_SIZE) { data = bson_malloc (req); @@ -188,7 +188,7 @@ _bson_impl_alloc_grow (bson_impl_alloc_t *impl, /* IN */ return true; } - req = _bson_round_up_alloc_size (req); + req = _bson_next_power_of_two_for_alloc (req); if ((req <= BSON_MAX_SIZE) && impl->realloc) { *impl->buf = impl->realloc (*impl->buf, req, impl->realloc_func_ctx); @@ -2136,7 +2136,7 @@ bson_copy_to (const bson_t *src, bson_t *dst) } data = _bson_data (src); - len = _bson_round_up_alloc_size ((size_t) src->len); + len = _bson_next_power_of_two_for_alloc ((size_t) src->len); adst = (bson_impl_alloc_t *) dst; adst->flags = BSON_FLAG_STATIC; From bcb2b87690aa94cc39ed971019a5289ee1a7b78c Mon Sep 17 00:00:00 2001 From: Micah Scott Date: Mon, 3 Mar 2025 08:41:00 -0800 Subject: [PATCH 51/51] Revert "CDRIVER-5915: Fix for allocation of bson_t larger than half max size" This reverts commit f2bb3183eb913dccf8c73ec5d87142b97e96dbbd. --- src/libbson/src/bson/bson.c | 68 ++++++----------------------------- src/libbson/tests/test-bson.c | 9 ++--- 2 files changed, 12 insertions(+), 65 deletions(-) diff --git a/src/libbson/src/bson/bson.c b/src/libbson/src/bson/bson.c index 0c807591c0f..c32c8992aa1 100644 --- a/src/libbson/src/bson/bson.c +++ b/src/libbson/src/bson/bson.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include @@ -61,36 +60,6 @@ typedef struct { */ static const uint8_t gZero; -/* - *-------------------------------------------------------------------------- - * - * _bson_next_power_of_two_for_alloc -- - * - * Given a potential allocation length in bytes, round up to the - * next power of two without exceeding BSON_MAX_SIZE. - * - * Returns: - * If the input is <= BSON_MAX_SIZE, returns a value >= the input - * and still <= BSON_MAX_SIZE. If the input was greater than - * BSON_MAX_SIZE, it is returned unmodified. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -static BSON_INLINE size_t -_bson_next_power_of_two_for_alloc (size_t size) -{ - if (size <= BSON_MAX_SIZE) { - size_t power_of_two = bson_next_power_of_two (size); - return BSON_MIN (power_of_two, BSON_MAX_SIZE); - } else { - return size; - } -} - /* *-------------------------------------------------------------------------- * @@ -121,7 +90,7 @@ _bson_impl_inline_grow (bson_impl_inline_t *impl, /* IN */ return true; } - req = _bson_next_power_of_two_for_alloc (impl->len + size); + req = bson_next_power_of_two (impl->len + size); if (req <= BSON_MAX_SIZE) { data = bson_malloc (req); @@ -153,12 +122,11 @@ _bson_impl_inline_grow (bson_impl_inline_t *impl, /* IN */ * * _bson_impl_alloc_grow -- * - * Document growth implementation for non-inline documents, possibly - * containing a reallocatable buffer. + * Document growth implementation for documents containing malloc + * based buffers. * * Returns: - * true if successful; otherwise false indicating BSON_MAX_SIZE overflow - * or an attempt to grow a buffer with no realloc implementation. + * true if successful; otherwise false indicating BSON_MAX_SIZE overflow. * * Side effects: * None. @@ -175,12 +143,6 @@ _bson_impl_alloc_grow (bson_impl_alloc_t *impl, /* IN */ /* * Determine how many bytes we need for this document in the buffer * including necessary trailing bytes for parent documents. - * - * Note that the buffer offset and nesting depth are not available - * outside bson_impl_alloc_t, meaning it's not possible for callers to - * fully rule out BSON_MAX_SIZE overflow before _bson_grow(). - * Some earlier checks against BSON_MAX_SIZE serve to prevent intermediate - * overflows rather than to validate the final allocation size. */ req = (impl->offset + impl->len + size + impl->depth); @@ -188,7 +150,7 @@ _bson_impl_alloc_grow (bson_impl_alloc_t *impl, /* IN */ return true; } - req = _bson_next_power_of_two_for_alloc (req); + req = bson_next_power_of_two (req); if ((req <= BSON_MAX_SIZE) && impl->realloc) { *impl->buf = impl->realloc (*impl->buf, req, impl->realloc_func_ctx); @@ -206,11 +168,10 @@ _bson_impl_alloc_grow (bson_impl_alloc_t *impl, /* IN */ * _bson_grow -- * * Grows the bson_t structure to be large enough to contain @size - * bytes in addition to its current content. + * bytes. * * Returns: - * true if successful, false if the size would overflow or the buffer - * needs to grow but does not support reallocation. + * true if successful, false if the size would overflow. * * Side effects: * None. @@ -2136,7 +2097,7 @@ bson_copy_to (const bson_t *src, bson_t *dst) } data = _bson_data (src); - len = _bson_next_power_of_two_for_alloc ((size_t) src->len); + len = bson_next_power_of_two ((size_t) src->len); adst = (bson_impl_alloc_t *) dst; adst->flags = BSON_FLAG_STATIC; @@ -2258,24 +2219,15 @@ bson_reserve_buffer (bson_t *bson, uint32_t size) return NULL; } - /* The caller wants a total document size of "size". - * Note that the bson_t can also include space for parent or sibling documents (offset) and for trailing bytes - * (depth). These sizes will be considered by _bson_grow() but we can assume they are zero in documents without - * BSON_FLAG_CHILD or BSON_FLAG_IN_CHILD. If this is called on a document that's part of a bson_writer_t, it is - * correct to ignore offset: we set the size of the current document, leaving previous documents alone. */ - if (size > bson->len && !_bson_grow (bson, size - bson->len)) { - // Will fail due to overflow or when reallocation is needed on a buffer that does not support it. + if (!_bson_grow (bson, size)) { return NULL; } if (bson->flags & BSON_FLAG_INLINE) { /* bson_grow didn't spill over */ ((bson_impl_inline_t *) bson)->len = size; - BSON_ASSERT (size <= BSON_INLINE_DATA_SIZE); } else { - bson_impl_alloc_t *impl = (bson_impl_alloc_t *) bson; - impl->len = size; - BSON_ASSERT (impl->offset <= *impl->buflen && *impl->buflen - impl->offset >= (size_t) size); + ((bson_impl_alloc_t *) bson)->len = size; } return _bson_data (bson); diff --git a/src/libbson/tests/test-bson.c b/src/libbson/tests/test-bson.c index 7300dddc846..ecd288317ee 100644 --- a/src/libbson/tests/test-bson.c +++ b/src/libbson/tests/test-bson.c @@ -1886,15 +1886,10 @@ test_bson_reserve_buffer_errors (void) uint32_t len_le; /* too big */ - ASSERT (!bson_reserve_buffer (&bson, (uint32_t) (BSON_MAX_SIZE + 1u))); - /* exactly the maximum size */ -#if BSON_WORD_SIZE > 32 - ASSERT (bson_reserve_buffer (&bson, (uint32_t) BSON_MAX_SIZE)); - ASSERT_CMPUINT32 (bson.len, ==, BSON_MAX_SIZE); -#endif - bson_destroy (&bson); + ASSERT (!bson_reserve_buffer (&bson, (uint32_t) (INT32_MAX - bson.len - 1))); /* make a static bson, it refuses bson_reserve_buffer since it's read-only */ + bson_destroy (&bson); len_le = BSON_UINT32_TO_LE (5); memcpy (data, &len_le, sizeof (len_le)); ASSERT (bson_init_static (&bson, data, sizeof data));