2323#include < cstring>
2424#include < exception>
2525#include < limits>
26+ #include < map>
2627#include < string_view>
2728#include < utility>
2829#include < vector>
@@ -51,34 +52,20 @@ int64_t ToPosition(int32_t key, uint32_t pos32) {
5152 return (int64_t {key} << 32 ) | int64_t {pos32};
5253}
5354
54- Status ValidatePosition (int64_t pos) {
55- if (pos < 0 || pos > RoaringPositionBitmap::kMaxPosition ) {
56- return InvalidArgument (" Bitmap supports positions that are >= 0 and <= {}: {}" ,
57- RoaringPositionBitmap::kMaxPosition , pos);
58- }
59- return {};
60- }
61-
62- void WriteBitmaps (const std::vector<roaring::Roaring>& bitmaps, uint8_t * buf) {
55+ void WriteBitmaps (const std::map<int32_t , roaring::Roaring>& bitmaps, uint8_t * buf) {
6356 WriteLittleEndian (static_cast <int64_t >(bitmaps.size ()), buf);
6457 buf += kBitmapCountSizeBytes ;
65- for (int32_t key = 0 ; std::cmp_less (key, bitmaps. size ()); ++key ) {
58+ for (const auto & [ key, bitmap] : bitmaps) {
6659 WriteLittleEndian (key, buf);
6760 buf += kBitmapKeySizeBytes ;
68- buf += bitmaps[key] .write (reinterpret_cast <char *>(buf), /* portable=*/ true );
61+ buf += bitmap .write (reinterpret_cast <char *>(buf), /* portable=*/ true );
6962 }
7063}
7164
7265} // namespace
7366
7467struct RoaringPositionBitmap ::Impl {
75- std::vector<roaring::Roaring> bitmaps;
76-
77- void AllocateBitmapsIfNeeded (int32_t required_length) {
78- if (std::cmp_less (bitmaps.size (), required_length)) {
79- bitmaps.resize (static_cast <size_t >(required_length));
80- }
81- }
68+ std::map<int32_t , roaring::Roaring> bitmaps;
8269};
8370
8471RoaringPositionBitmap::RoaringPositionBitmap () : impl_(std::make_unique<Impl>()) {}
@@ -108,86 +95,85 @@ RoaringPositionBitmap::RoaringPositionBitmap(std::unique_ptr<Impl> impl)
10895 : impl_(std::move(impl)) {}
10996
11097void RoaringPositionBitmap::Add (int64_t pos) {
111- if (pos < 0 || pos > kMaxPosition ) {
98+ if (pos < 0 ) {
11299 return ; // Silently ignore invalid positions
113100 }
114101 int32_t key = Key (pos);
115102 uint32_t pos32 = Pos32Bits (pos);
116- impl_->AllocateBitmapsIfNeeded (key + 1 );
117103 impl_->bitmaps [key].add (pos32);
118104}
119105
120106void RoaringPositionBitmap::AddManyForKey (int32_t key,
121107 std::span<const uint32_t > positions) {
122- impl_->AllocateBitmapsIfNeeded (key + 1 );
108+ if (key < 0 || positions.empty ()) {
109+ return ;
110+ }
123111 impl_->bitmaps [key].addMany (positions.size (), positions.data ());
124112}
125113
126114void RoaringPositionBitmap::AddRange (int64_t pos_start, int64_t pos_end) {
127115 pos_start = std::max (pos_start, int64_t {0 });
128- pos_end = std::min (pos_end, kMaxPosition + 1 );
129116 if (pos_start >= pos_end) {
130117 return ;
131118 }
132119
133120 int64_t pos_last = pos_end - 1 ;
134121 int32_t start_key = Key (pos_start);
135122 int32_t end_key = Key (pos_last);
136- impl_->AllocateBitmapsIfNeeded (end_key + 1 );
137123
138- for (int32_t key = start_key; key <= end_key; ++key) {
124+ for (int64_t key = start_key; key <= end_key; ++key) {
139125 uint64_t low_start = (key == start_key) ? Pos32Bits (pos_start) : uint64_t {0 };
140126 uint64_t low_end = (key == end_key) ? static_cast <uint64_t >(Pos32Bits (pos_last)) + 1
141127 : (uint64_t {1 } << 32 );
142- impl_->bitmaps [key].addRange (low_start, low_end);
128+ impl_->bitmaps [static_cast < int32_t >( key) ].addRange (low_start, low_end);
143129 }
144130}
145131
146132bool RoaringPositionBitmap::Contains (int64_t pos) const {
147- if (pos < 0 || pos > kMaxPosition ) {
133+ if (pos < 0 ) {
148134 return false ; // Invalid positions are not contained
149135 }
150136 int32_t key = Key (pos);
151137 uint32_t pos32 = Pos32Bits (pos);
152- return std::cmp_less (key, impl_->bitmaps .size ()) && impl_->bitmaps [key].contains (pos32);
138+ auto it = impl_->bitmaps .find (key);
139+ return it != impl_->bitmaps .end () && it->second .contains (pos32);
153140}
154141
155142bool RoaringPositionBitmap::IsEmpty () const { return Cardinality () == 0 ; }
156143
157144size_t RoaringPositionBitmap::Cardinality () const {
158145 size_t total = 0 ;
159- for (const auto & bitmap : impl_->bitmaps ) {
146+ for (const auto & [_, bitmap] : impl_->bitmaps ) {
160147 total += bitmap.cardinality ();
161148 }
162149 return total;
163150}
164151
165152void RoaringPositionBitmap::Or (const RoaringPositionBitmap& other) {
166- impl_->AllocateBitmapsIfNeeded (static_cast <int32_t >(other.impl_ ->bitmaps .size ()));
167- for (size_t key = 0 ; key < other.impl_ ->bitmaps .size (); ++key) {
168- impl_->bitmaps [key] |= other.impl_ ->bitmaps [key];
153+ for (const auto & [key, bitmap] : other.impl_ ->bitmaps ) {
154+ impl_->bitmaps [key] |= bitmap;
169155 }
170156}
171157
172158bool RoaringPositionBitmap::Optimize () {
173159 bool changed = false ;
174- for (auto & bitmap : impl_->bitmaps ) {
160+ for (auto & [_, bitmap] : impl_->bitmaps ) {
175161 changed |= bitmap.runOptimize ();
176162 }
177163 return changed;
178164}
179165
180166void RoaringPositionBitmap::ForEach (const std::function<void (int64_t )>& fn) const {
181- for (size_t key = 0 ; key < impl_->bitmaps . size (); ++key ) {
182- for (uint32_t pos32 : impl_-> bitmaps [key] ) {
183- fn (ToPosition (static_cast < int32_t >( key) , pos32));
167+ for (const auto & [ key, bitmap] : impl_->bitmaps ) {
168+ for (uint32_t pos32 : bitmap ) {
169+ fn (ToPosition (key, pos32));
184170 }
185171 }
186172}
187173
188174size_t RoaringPositionBitmap::SerializedSizeInBytes () const {
189175 size_t size = kBitmapCountSizeBytes ;
190- for (const auto & bitmap : impl_->bitmaps ) {
176+ for (const auto & [_, bitmap] : impl_->bitmaps ) {
191177 size += kBitmapKeySizeBytes + bitmap.getSizeInBytes (/* portable=*/ true );
192178 }
193179 return size;
@@ -238,18 +224,10 @@ Result<RoaringPositionBitmap> RoaringPositionBitmap::Deserialize(std::string_vie
238224 remaining -= kBitmapKeySizeBytes ;
239225
240226 ICEBERG_PRECHECK (key >= 0 , " Invalid unsigned key: {}" , key);
241- ICEBERG_PRECHECK (key < std::numeric_limits<int32_t >::max (), " Key is too large: {}" ,
242- key);
243227 ICEBERG_PRECHECK (key > last_key,
244228 " Keys must be sorted in ascending order, got key {} after {}" , key,
245229 last_key);
246230
247- // Fill gaps with empty bitmaps
248- while (last_key < key - 1 ) {
249- impl->bitmaps .emplace_back ();
250- ++last_key;
251- }
252-
253231 // Read bitmap using portable safe deserialization.
254232 // CRoaring's readSafe may throw on corrupted data.
255233 roaring::Roaring bitmap;
@@ -266,7 +244,9 @@ Result<RoaringPositionBitmap> RoaringPositionBitmap::Deserialize(std::string_vie
266244 buf += bitmap_size;
267245 remaining -= bitmap_size;
268246
269- impl->bitmaps .emplace_back (std::move (bitmap));
247+ if (!bitmap.isEmpty ()) {
248+ impl->bitmaps .emplace (key, std::move (bitmap));
249+ }
270250 last_key = key;
271251 --remaining_count;
272252 }
0 commit comments