Skip to content

Commit 5b83bd4

Browse files
authored
Use ByteString instead of std::vector in the BloomFilter (#11038)
1 parent 0745252 commit 5b83bd4

File tree

6 files changed

+51
-54
lines changed

6 files changed

+51
-54
lines changed

Firestore/Example/Tests/SpecTests/FSTSpecTests.mm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,7 @@ - (SnapshotVersion)parseVersion:(NSNumber *_Nullable)version {
342342
NSString *bitmapEncoded = bitsData[@"bitmap"];
343343
std::string bitmapDecoded;
344344
absl::Base64Unescape([bitmapEncoded cStringUsingEncoding:NSASCIIStringEncoding], &bitmapDecoded);
345-
std::vector<uint8_t> bitmap(bitmapDecoded.begin(), bitmapDecoded.end());
345+
ByteString bitmap(bitmapDecoded);
346346

347347
// If not specified in proto, default padding and hashCount to 0.
348348
int32_t padding = [bitsData[@"padding"] intValue];

Firestore/core/src/remote/bloom_filter.cc

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ namespace firebase {
2626
namespace firestore {
2727
namespace remote {
2828

29+
using nanopb::ByteString;
2930
using util::Status;
3031
using util::StatusOr;
3132

@@ -38,9 +39,9 @@ bool HasSameBits(const BloomFilter& lhs, const BloomFilter& rhs) {
3839
return true;
3940
}
4041

41-
const std::vector<uint8_t>& bitmap1 = lhs.bitmap();
42-
const std::vector<uint8_t>& bitmap2 = rhs.bitmap();
43-
const auto byte_count = static_cast<int32_t>(bitmap1.size());
42+
const auto byte_count = static_cast<int32_t>(lhs.bitmap().size());
43+
const uint8_t* bitmap1 = lhs.bitmap().data();
44+
const uint8_t* bitmap2 = rhs.bitmap().data();
4445

4546
// Compare all bytes from the bitmap, except for the last byte.
4647
for (int32_t i = 0; i < byte_count - 1; ++i) {
@@ -81,14 +82,12 @@ int32_t BloomFilter::GetBitIndex(const Hash& hash, int32_t hash_index) const {
8182
}
8283

8384
bool BloomFilter::IsBitSet(int32_t index) const {
84-
uint8_t byte_at_index = bitmap_[index / 8];
85+
uint8_t byte_at_index = bitmap_.data()[index / 8];
8586
int32_t offset = index % 8;
8687
return (byte_at_index & (static_cast<uint8_t>(0x01) << offset)) != 0;
8788
}
8889

89-
BloomFilter::BloomFilter(std::vector<uint8_t> bitmap,
90-
int32_t padding,
91-
int32_t hash_count)
90+
BloomFilter::BloomFilter(ByteString bitmap, int32_t padding, int32_t hash_count)
9291
: bit_count_(static_cast<int32_t>(bitmap.size()) * 8 - padding),
9392
hash_count_(hash_count),
9493
bitmap_(std::move(bitmap)) {
@@ -101,7 +100,7 @@ BloomFilter::BloomFilter(std::vector<uint8_t> bitmap,
101100
HARD_ASSERT(bit_count_ >= 0);
102101
}
103102

104-
StatusOr<BloomFilter> BloomFilter::Create(std::vector<uint8_t> bitmap,
103+
StatusOr<BloomFilter> BloomFilter::Create(ByteString bitmap,
105104
int32_t padding,
106105
int32_t hash_count) {
107106
if (padding < 0 || padding >= 8) {

Firestore/core/src/remote/bloom_filter.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
#define FIRESTORE_CORE_SRC_REMOTE_BLOOM_FILTER_H_
1919

2020
#include <string>
21-
#include <vector>
21+
#include "Firestore/core/src/nanopb/byte_string.h"
2222
#include "Firestore/core/src/util/statusor.h"
2323
#include "absl/strings/string_view.h"
2424

@@ -28,7 +28,7 @@ namespace remote {
2828

2929
class BloomFilter final {
3030
public:
31-
BloomFilter(std::vector<uint8_t> bitmap, int32_t padding, int32_t hash_count);
31+
BloomFilter(nanopb::ByteString bitmap, int32_t padding, int32_t hash_count);
3232

3333
// Copyable & movable.
3434
BloomFilter(const BloomFilter&) = default;
@@ -42,7 +42,7 @@ class BloomFilter final {
4242
* @return a new BloomFilter if the inputs are valid, otherwise returns a not
4343
* `ok()` status.
4444
*/
45-
static util::StatusOr<BloomFilter> Create(std::vector<uint8_t> bitmap,
45+
static util::StatusOr<BloomFilter> Create(nanopb::ByteString bitmap,
4646
int32_t padding,
4747
int32_t hash_count);
4848

@@ -75,7 +75,7 @@ class BloomFilter final {
7575
}
7676

7777
/** Bloom filter's bitmap. */
78-
const std::vector<uint8_t>& bitmap() const {
78+
const nanopb::ByteString& bitmap() const {
7979
return bitmap_;
8080
}
8181

@@ -108,7 +108,7 @@ class BloomFilter final {
108108

109109
int32_t hash_count_ = 0;
110110

111-
std::vector<uint8_t> bitmap_;
111+
nanopb::ByteString bitmap_;
112112
};
113113

114114
bool operator==(const BloomFilter& lhs, const BloomFilter& rhs);

Firestore/core/src/remote/existence_filter.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,16 @@
1818
#define FIRESTORE_CORE_SRC_REMOTE_EXISTENCE_FILTER_H_
1919

2020
#include <utility>
21-
#include <vector>
2221

22+
#include "Firestore/core/src/nanopb/byte_string.h"
2323
#include "Firestore/core/src/remote/bloom_filter.h"
2424

2525
namespace firebase {
2626
namespace firestore {
2727
namespace remote {
2828

2929
struct BloomFilterParameters {
30-
std::vector<uint8_t> bitmap;
30+
nanopb::ByteString bitmap;
3131
int32_t padding;
3232
int32_t hash_count;
3333
};

Firestore/core/src/remote/serializer.cc

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1456,15 +1456,13 @@ ExistenceFilter Serializer::DecodeExistenceFilter(
14561456

14571457
int32_t hash_count = filter.unchanged_names.hash_count;
14581458
int32_t padding = 0;
1459-
std::vector<uint8_t> bitmap;
1459+
ByteString bitmap;
14601460
if (filter.unchanged_names.has_bits) {
14611461
padding = filter.unchanged_names.bits.padding;
1462-
1463-
pb_bytes_array_t* bitmap_ptr = filter.unchanged_names.bits.bitmap;
1464-
if (bitmap_ptr != nullptr) {
1465-
bitmap = std::vector<uint8_t>(bitmap_ptr->bytes,
1466-
bitmap_ptr->bytes + bitmap_ptr->size);
1467-
}
1462+
// TODO(b/274668697) Steal the bytes using ByteString::Take() instead of
1463+
// copying them. To do this, the `filter` argument will need to be
1464+
// non-const, which will affect the caller(s), and their caller(s), etc.
1465+
bitmap = ByteString(filter.unchanged_names.bits.bitmap);
14681466
}
14691467
return {filter.count,
14701468
BloomFilterParameters{std::move(bitmap), padding, hash_count}};

Firestore/core/test/unit/remote/bloom_filter_test.cc

Lines changed: 31 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818

1919
#include <fstream>
2020
#include <iostream>
21-
#include <vector>
2221

2322
#include "Firestore/core/src/util/hard_assert.h"
2423
#include "Firestore/core/src/util/json_reader.h"
@@ -31,39 +30,40 @@ namespace firestore {
3130
namespace remote {
3231
namespace {
3332

33+
using nanopb::ByteString;
3434
using nlohmann::json;
3535
using util::JsonReader;
3636
using util::Path;
3737
using util::Status;
3838
using util::StatusOr;
3939

4040
TEST(BloomFilterUnitTest, CanInstantiateEmptyBloomFilter) {
41-
BloomFilter bloom_filter(std::vector<uint8_t>{}, 0, 0);
41+
BloomFilter bloom_filter(ByteString{}, 0, 0);
4242
EXPECT_EQ(bloom_filter.bit_count(), 0);
4343
}
4444

4545
TEST(BloomFilterUnitTest, CanInstantiateNonEmptyBloomFilter) {
4646
{
47-
BloomFilter bloom_filter(std::vector<uint8_t>{1}, 0, 1);
47+
BloomFilter bloom_filter(ByteString{1}, 0, 1);
4848
EXPECT_EQ(bloom_filter.bit_count(), 8);
4949
}
5050
{
51-
BloomFilter bloom_filter(std::vector<uint8_t>{1}, 7, 1);
51+
BloomFilter bloom_filter(ByteString{1}, 7, 1);
5252
EXPECT_EQ(bloom_filter.bit_count(), 1);
5353
}
5454
}
5555

5656
TEST(BloomFilterUnitTest, CreateShouldReturnBloomFilterOnValidInputs) {
5757
StatusOr<BloomFilter> maybe_bloom_filter =
58-
BloomFilter::Create(std::vector<uint8_t>{1}, 1, 1);
58+
BloomFilter::Create(ByteString{1}, 1, 1);
5959
ASSERT_TRUE(maybe_bloom_filter.ok());
6060
BloomFilter bloom_filter = maybe_bloom_filter.ValueOrDie();
6161
EXPECT_EQ(bloom_filter.bit_count(), 7);
6262
}
6363

6464
TEST(BloomFilterUnitTest, CreateShouldBeAbleToCreatEmptyBloomFilter) {
6565
StatusOr<BloomFilter> maybe_bloom_filter =
66-
BloomFilter::Create(std::vector<uint8_t>{}, 0, 0);
66+
BloomFilter::Create(ByteString{}, 0, 0);
6767
ASSERT_TRUE(maybe_bloom_filter.ok());
6868
BloomFilter bloom_filter = maybe_bloom_filter.ValueOrDie();
6969
EXPECT_EQ(bloom_filter.bit_count(), 0);
@@ -72,14 +72,14 @@ TEST(BloomFilterUnitTest, CreateShouldBeAbleToCreatEmptyBloomFilter) {
7272
TEST(BloomFilterUnitTest, CreateShouldReturnNotOKStatusOnNegativePadding) {
7373
{
7474
StatusOr<BloomFilter> maybe_bloom_filter =
75-
BloomFilter::Create(std::vector<uint8_t>{}, -1, 0);
75+
BloomFilter::Create(ByteString{}, -1, 0);
7676
ASSERT_FALSE(maybe_bloom_filter.ok());
7777
EXPECT_EQ(maybe_bloom_filter.status().error_message(),
7878
"Invalid padding: -1");
7979
}
8080
{
8181
StatusOr<BloomFilter> maybe_bloom_filter =
82-
BloomFilter::Create(std::vector<uint8_t>{1}, -1, 1);
82+
BloomFilter::Create(ByteString{1}, -1, 1);
8383
ASSERT_FALSE(maybe_bloom_filter.ok());
8484
EXPECT_EQ(maybe_bloom_filter.status().error_message(),
8585
"Invalid padding: -1");
@@ -89,14 +89,14 @@ TEST(BloomFilterUnitTest, CreateShouldReturnNotOKStatusOnNegativePadding) {
8989
TEST(BloomFilterUnitTest, CreateShouldReturnNotOKStatusOnNegativeHashCount) {
9090
{
9191
StatusOr<BloomFilter> maybe_bloom_filter =
92-
BloomFilter::Create(std::vector<uint8_t>{}, 0, -1);
92+
BloomFilter::Create(ByteString{}, 0, -1);
9393
ASSERT_FALSE(maybe_bloom_filter.ok());
9494
EXPECT_EQ(maybe_bloom_filter.status().error_message(),
9595
"Invalid hash count: -1");
9696
}
9797
{
9898
StatusOr<BloomFilter> maybe_bloom_filter =
99-
BloomFilter::Create(std::vector<uint8_t>{1}, 1, -1);
99+
BloomFilter::Create(ByteString{1}, 1, -1);
100100
ASSERT_FALSE(maybe_bloom_filter.ok());
101101
EXPECT_EQ(maybe_bloom_filter.status().error_message(),
102102
"Invalid hash count: -1");
@@ -105,51 +105,51 @@ TEST(BloomFilterUnitTest, CreateShouldReturnNotOKStatusOnNegativeHashCount) {
105105

106106
TEST(BloomFilterUnitTest, CreateShouldReturnNotOKStatusOnZeroHashCount) {
107107
StatusOr<BloomFilter> maybe_bloom_filter =
108-
BloomFilter::Create(std::vector<uint8_t>{1}, 1, 0);
108+
BloomFilter::Create(ByteString{1}, 1, 0);
109109
ASSERT_FALSE(maybe_bloom_filter.ok());
110110
EXPECT_EQ(maybe_bloom_filter.status().error_message(),
111111
"Invalid hash count: 0");
112112
}
113113

114114
TEST(BloomFilterUnitTest, CreateShouldReturnNotOKStatusIfPaddingIsTooLarge) {
115115
StatusOr<BloomFilter> maybe_bloom_filter =
116-
BloomFilter::Create(std::vector<uint8_t>{1}, 8, 1);
116+
BloomFilter::Create(ByteString{1}, 8, 1);
117117
ASSERT_FALSE(maybe_bloom_filter.ok());
118118
EXPECT_EQ(maybe_bloom_filter.status().error_message(), "Invalid padding: 8");
119119
}
120120

121121
TEST(BloomFilterTest, CheckBloomFiltersEqualityWithSameInput) {
122-
BloomFilter bloom_filter1(std::vector<uint8_t>{1}, 1, 1);
123-
BloomFilter bloom_filter2(std::vector<uint8_t>{1}, 1, 1);
122+
BloomFilter bloom_filter1(ByteString{1}, 1, 1);
123+
BloomFilter bloom_filter2(ByteString{1}, 1, 1);
124124
EXPECT_TRUE(bloom_filter1 == bloom_filter2);
125125
EXPECT_FALSE(bloom_filter1 != bloom_filter2);
126126
}
127127

128128
TEST(BloomFilterTest, CheckBloomFiltersEqualityWithDifferentBitmap) {
129129
{
130-
BloomFilter bloom_filter1(std::vector<uint8_t>{1}, 1, 1);
131-
BloomFilter bloom_filter2(std::vector<uint8_t>{2}, 1, 1);
130+
BloomFilter bloom_filter1(ByteString{1}, 1, 1);
131+
BloomFilter bloom_filter2(ByteString{2}, 1, 1);
132132
EXPECT_FALSE(bloom_filter1 == bloom_filter2);
133133
EXPECT_TRUE(bloom_filter1 != bloom_filter2);
134134
}
135135
{
136-
BloomFilter bloom_filter1(std::vector<uint8_t>{1}, 1, 1);
137-
BloomFilter bloom_filter2(std::vector<uint8_t>{1, 1}, 1, 1);
136+
BloomFilter bloom_filter1(ByteString{1}, 1, 1);
137+
BloomFilter bloom_filter2(ByteString{1, 1}, 1, 1);
138138
EXPECT_FALSE(bloom_filter1 == bloom_filter2);
139139
EXPECT_TRUE(bloom_filter1 != bloom_filter2);
140140
}
141141
}
142142

143143
TEST(BloomFilterTest, CheckBloomFiltersEqualityWithDifferentPadding) {
144-
BloomFilter bloom_filter1(std::vector<uint8_t>{1}, 1, 1);
145-
BloomFilter bloom_filter2(std::vector<uint8_t>{1}, 2, 1);
144+
BloomFilter bloom_filter1(ByteString{1}, 1, 1);
145+
BloomFilter bloom_filter2(ByteString{1}, 2, 1);
146146
EXPECT_FALSE(bloom_filter1 == bloom_filter2);
147147
EXPECT_TRUE(bloom_filter1 != bloom_filter2);
148148
}
149149

150150
TEST(BloomFilterTest, CheckBloomFiltersEqualityWithDifferentHashCount) {
151-
BloomFilter bloom_filter1(std::vector<uint8_t>{1}, 1, 1);
152-
BloomFilter bloom_filter2(std::vector<uint8_t>{1}, 1, 2);
151+
BloomFilter bloom_filter1(ByteString{1}, 1, 1);
152+
BloomFilter bloom_filter2(ByteString{1}, 1, 2);
153153
EXPECT_FALSE(bloom_filter1 == bloom_filter2);
154154
EXPECT_TRUE(bloom_filter1 != bloom_filter2);
155155
}
@@ -159,17 +159,17 @@ TEST(BloomFilterTest,
159159
// In BloomFilter bitmap, padding is guaranteed to be less than 8, and
160160
// starts counting from the leftmost indexes of the last byte.
161161
{
162-
BloomFilter bloom_filter1(std::vector<uint8_t>{255, 127}, 1,
162+
BloomFilter bloom_filter1(ByteString{255, 127}, 1,
163163
1); // bitmap -> 11111111 01111111
164-
BloomFilter bloom_filter2(std::vector<uint8_t>{255, 255}, 1,
164+
BloomFilter bloom_filter2(ByteString{255, 255}, 1,
165165
1); // bitmap -> 11111111 11111111
166166
EXPECT_TRUE(bloom_filter1 == bloom_filter2);
167167
EXPECT_FALSE(bloom_filter1 != bloom_filter2);
168168
}
169169
{
170-
BloomFilter bloom_filter1(std::vector<uint8_t>{255, 207}, 4,
170+
BloomFilter bloom_filter1(ByteString{255, 207}, 4,
171171
1); // bitmap -> 11111111 11001111
172-
BloomFilter bloom_filter2(std::vector<uint8_t>{255, 255}, 4,
172+
BloomFilter bloom_filter2(ByteString{255, 255}, 4,
173173
1); // bitmap -> 11111111 11111111
174174
EXPECT_TRUE(bloom_filter1 == bloom_filter2);
175175
EXPECT_FALSE(bloom_filter1 != bloom_filter2);
@@ -178,25 +178,25 @@ TEST(BloomFilterTest,
178178

179179
TEST(BloomFilterTest, MightContainCanProcessNonStandardCharacters) {
180180
// A non-empty BloomFilter object with 1 insertion : "ÀÒ∑"
181-
BloomFilter bloom_filter(std::vector<uint8_t>{237, 5}, 5, 8);
181+
BloomFilter bloom_filter(ByteString{237, 5}, 5, 8);
182182
EXPECT_TRUE(bloom_filter.MightContain("ÀÒ∑"));
183183
EXPECT_FALSE(bloom_filter.MightContain("Ò∑À"));
184184
}
185185

186186
TEST(BloomFilterUnitTest, MightContainOnEmptyBloomFilterShouldReturnFalse) {
187-
BloomFilter bloom_filter(std::vector<uint8_t>{}, 0, 0);
187+
BloomFilter bloom_filter(ByteString{}, 0, 0);
188188
EXPECT_FALSE(bloom_filter.MightContain(""));
189189
EXPECT_FALSE(bloom_filter.MightContain("a"));
190190
}
191191

192192
TEST(BloomFilterUnitTest,
193193
MightContainWithEmptyStringMightReturnFalsePositiveResult) {
194194
{
195-
BloomFilter bloom_filter(std::vector<uint8_t>{1}, 1, 1);
195+
BloomFilter bloom_filter(ByteString{1}, 1, 1);
196196
EXPECT_FALSE(bloom_filter.MightContain(""));
197197
}
198198
{
199-
BloomFilter bloom_filter(std::vector<uint8_t>{255}, 0, 16);
199+
BloomFilter bloom_filter(ByteString{255}, 0, 16);
200200
EXPECT_TRUE(bloom_filter.MightContain(""));
201201
}
202202
}
@@ -241,7 +241,7 @@ class BloomFilterGoldenTest : public ::testing::Test {
241241
int hash_count = reader.OptionalInt("hashCount", test_file, 0);
242242
std::string decoded;
243243
absl::Base64Unescape(bitmap, &decoded);
244-
std::vector<uint8_t> decoded_map(decoded.begin(), decoded.end());
244+
ByteString decoded_map(decoded);
245245

246246
StatusOr<BloomFilter> maybe_bloom_filter =
247247
BloomFilter::Create(std::move(decoded_map), padding, hash_count);

0 commit comments

Comments
 (0)