@@ -988,6 +988,12 @@ class VlqHexDecoder {
988
988
}
989
989
class RoaringBitmap {
990
990
constructor ( str ) {
991
+ // https://github.com/RoaringBitmap/RoaringFormatSpec
992
+ //
993
+ // Roaring bitmaps are used for flags that can be kept in their
994
+ // compressed form, even when loaded into memory. This decoder
995
+ // turns the containers into objects, but uses byte array
996
+ // slices of the original format for the data payload.
991
997
const strdecoded = atob ( str ) ;
992
998
const u8array = new Uint8Array ( strdecoded . length ) ;
993
999
for ( let j = 0 ; j < strdecoded . length ; ++ j ) {
@@ -1053,9 +1059,24 @@ class RoaringBitmap {
1053
1059
contains ( keyvalue ) {
1054
1060
const key = keyvalue >> 16 ;
1055
1061
const value = keyvalue & 0xFFFF ;
1056
- for ( let i = 0 ; i < this . keys . length ; ++ i ) {
1057
- if ( this . keys [ i ] === key ) {
1058
- return this . containers [ i ] . contains ( value ) ;
1062
+ // Binary search algorithm copied from
1063
+ // https://en.wikipedia.org/wiki/Binary_search#Procedure
1064
+ //
1065
+ // Format is required by specification to be sorted.
1066
+ // Because keys are 16 bits and unique, length can't be
1067
+ // bigger than 2**16, and because we have 32 bits of safe int,
1068
+ // left + right can't overflow.
1069
+ let left = 0 ;
1070
+ let right = this . keys . length - 1 ;
1071
+ while ( left <= right ) {
1072
+ const mid = Math . floor ( ( left + right ) / 2 ) ;
1073
+ const x = this . keys [ mid ] ;
1074
+ if ( x < key ) {
1075
+ left = mid + 1 ;
1076
+ } else if ( x > key ) {
1077
+ right = mid - 1 ;
1078
+ } else {
1079
+ return this . containers [ mid ] . contains ( value ) ;
1059
1080
}
1060
1081
}
1061
1082
return false ;
@@ -1068,11 +1089,23 @@ class RoaringBitmapRun {
1068
1089
this . array = array ;
1069
1090
}
1070
1091
contains ( value ) {
1071
- const l = this . runcount * 4 ;
1072
- for ( let i = 0 ; i < l ; i += 4 ) {
1092
+ // Binary search algorithm copied from
1093
+ // https://en.wikipedia.org/wiki/Binary_search#Procedure
1094
+ //
1095
+ // Since runcount is stored as 16 bits, left + right
1096
+ // can't overflow.
1097
+ let left = 0 ;
1098
+ let right = this . runcount - 1 ;
1099
+ while ( left <= right ) {
1100
+ const mid = Math . floor ( ( left + right ) / 2 ) ;
1101
+ const i = mid * 4 ;
1073
1102
const start = this . array [ i ] | ( this . array [ i + 1 ] << 8 ) ;
1074
1103
const lenm1 = this . array [ i + 2 ] | ( this . array [ i + 3 ] << 8 ) ;
1075
- if ( value >= start && value <= ( start + lenm1 ) ) {
1104
+ if ( ( start + lenm1 ) < value ) {
1105
+ left = mid + 1 ;
1106
+ } else if ( start > value ) {
1107
+ right = mid - 1 ;
1108
+ } else {
1076
1109
return true ;
1077
1110
}
1078
1111
}
@@ -1085,10 +1118,22 @@ class RoaringBitmapArray {
1085
1118
this . array = array ;
1086
1119
}
1087
1120
contains ( value ) {
1088
- const l = this . cardinality * 2 ;
1089
- for ( let i = 0 ; i < l ; i += 2 ) {
1090
- const start = this . array [ i ] | ( this . array [ i + 1 ] << 8 ) ;
1091
- if ( value === start ) {
1121
+ // Binary search algorithm copied from
1122
+ // https://en.wikipedia.org/wiki/Binary_search#Procedure
1123
+ //
1124
+ // Since cardinality can't be higher than 4096, left + right
1125
+ // cannot overflow.
1126
+ let left = 0 ;
1127
+ let right = this . cardinality - 1 ;
1128
+ while ( left <= right ) {
1129
+ const mid = Math . floor ( ( left + right ) / 2 ) ;
1130
+ const i = mid * 2 ;
1131
+ const x = this . array [ i ] | ( this . array [ i + 1 ] << 8 ) ;
1132
+ if ( x < value ) {
1133
+ left = mid + 1 ;
1134
+ } else if ( x > value ) {
1135
+ right = mid - 1 ;
1136
+ } else {
1092
1137
return true ;
1093
1138
}
1094
1139
}
0 commit comments