Skip to content

Commit ebfc852

Browse files
authored
Merge pull request #585 from evoskuil/master
Add sieve class and tests and remove test implementation.
2 parents 8b9dabe + 7705b6f commit ebfc852

3 files changed

Lines changed: 1188 additions & 1121 deletions

File tree

include/bitcoin/database/impl/primitives/sieve.ipp

Lines changed: 107 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,39 +22,135 @@
2222
#include <bitcoin/system.hpp>
2323
#include <bitcoin/database/define.hpp>
2424

25-
// [-------------------screen----------][--------------link--------------]
26-
// [[selector][--------masks----------]][--------------link--------------]
25+
// [--------------------sieve-----------][--------------link--------------]
26+
// [[selector][--------screens---------]][--------------link--------------]
2727

28-
// [[111][1111111111111111111111111111]] terminal sentinal (empty/default)
28+
// [[111][1111111111111111111111111111]] empty/default
2929
// [[000][1111111111111111111111111111]] 1 screen
3030
// [[001][2222222222222211111111111111]] 2 screens
3131
// [[010][3333333333222222222111111111]] 3 screens
3232
// [[011][4444444333333322222221111111]] 4 screens
3333
// [[100][5555554444443333332222211111]] 5 screens
3434
// [[101][6666655555444443333322221111]] 6 screens
3535
// [[110][7777666655554444333322221111]] 7 screens
36-
// [[111][-777766665555444433332222111]] 8 screens (partial)
37-
// [[111][1000000000000000000000000000]] overflow sentinal
36+
// [[111][-888777766665555444333222111]] 8 screens (high order sentinel bit)
37+
// [[111][1000000000000000000000000000]] saturated
3838

39-
// To minimize masking and shifting in alignment, the sieve is defined as a two
40-
// dimensional matrix of precomputed. One dimension is determined by the
41-
// screen selector the other is used to iterate through maskes for that screen.
39+
// To minimize computation in alignment the sieve is defined as two dimensional
40+
// matrix of precomputed masks. One dimension is determined by the screen
41+
// selector and other is used to iterate through masks for the selected screen.
4242
// A single screen requires one mask, a double two, and so on. The max selector
4343
// value indicates that the first bit of the screen is a sentinel. This is set
4444
// for either terminal (all other bits set) or overflow (no other bits set).
4545
// If the sentinel is unset then the max screen is in used on remaining bits.
4646
// The seive should be terminal if and only if the link is terminal, and when
4747
// overflowed implies that the bucket is saturated, rendering it unscreened.
4848

49-
// A 28 bit sieve requires 28 bits from each hashmap key, independent of both
50-
// the hashmap hash function and each other. The mask is
51-
5249
namespace libbitcoin {
5350
namespace database {
5451

5552
TEMPLATE
5653
constexpr CLASS::sieve() NOEXCEPT
54+
: sieve(empty)
55+
{
56+
}
57+
58+
TEMPLATE
59+
constexpr CLASS::sieve(sieve_t value) NOEXCEPT
60+
: sieve_{ value }
61+
{
62+
}
63+
64+
TEMPLATE
65+
constexpr CLASS::sieve_t CLASS::value() const NOEXCEPT
5766
{
67+
return sieve_;
68+
}
69+
70+
TEMPLATE
71+
constexpr CLASS::operator CLASS::sieve_t() const NOEXCEPT
72+
{
73+
return sieve_;
74+
}
75+
76+
TEMPLATE
77+
constexpr bool CLASS::screened(sieve_t fingerprint) const NOEXCEPT
78+
{
79+
using namespace system;
80+
const auto row = shift_right(sieve_, screen_bits);
81+
if (row == limit)
82+
{
83+
if (sieve_ == empty)
84+
return false;
85+
86+
if (sieve_ == saturated)
87+
return true;
88+
}
89+
90+
// Compare masked fingerprint to masked sieve, for all masks of the screen.
91+
for (sieve_t segment{}; segment <= row; ++segment)
92+
{
93+
const auto mask = matrix_[row][segment];
94+
if (bit_and(fingerprint, mask) == bit_and(sieve_, mask))
95+
return true;
96+
}
97+
98+
// Not empty, not saturated, not aligned with active screen (full if max).
99+
return false;
100+
}
101+
102+
TEMPLATE
103+
constexpr bool CLASS::screen(sieve_t fingerprint) NOEXCEPT
104+
{
105+
using namespace system;
106+
auto row = shift_right(sieve_, screen_bits);
107+
if (row == limit)
108+
{
109+
if (sieve_ == empty)
110+
{
111+
// Reset empty sentinel (not screened) for first screen.
112+
zeroize(row);
113+
}
114+
else
115+
{
116+
// Sieve was full, now saturated (all screened).
117+
sieve_ = saturated;
118+
return false;
119+
}
120+
}
121+
else
122+
{
123+
if (screened(fingerprint))
124+
{
125+
// Screened, bucket may contain element.
126+
return false;
127+
}
128+
else
129+
{
130+
// Not screened, empty, or full - add screen.
131+
++row;
132+
}
133+
}
134+
135+
// Both indexes are screen selector, as each new screen adds one mask.
136+
const auto mask = matrix_[row][row];
137+
138+
// Merge incremented selector, current sieve, and new fingerprint.
139+
sieve_ = bit_or
140+
(
141+
shift_left(row, screen_bits),
142+
bit_and
143+
(
144+
selector_mask,
145+
bit_or
146+
(
147+
bit_and(fingerprint, mask),
148+
bit_and(sieve_, bit_not(mask))
149+
)
150+
)
151+
);
152+
153+
return true;
58154
}
59155

60156
} // namespace database

include/bitcoin/database/primitives/sieve.hpp

Lines changed: 234 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,247 @@
2525
namespace libbitcoin {
2626
namespace database {
2727

28-
template <size_t Size>
29-
struct sieve
28+
/// Sieve is limited to integral types.
29+
template <size_t SieveBits, size_t SelectorBits,
30+
if_not_greater<SelectorBits, SieveBits> = true,
31+
if_not_greater<SieveBits, bits<uint64_t>> = true>
32+
class sieve
3033
{
34+
public:
35+
using sieve_t = unsigned_type<system::to_ceilinged_bytes(SieveBits)>;
36+
37+
/// Initialize empty sieve.
3138
constexpr sieve() NOEXCEPT;
39+
40+
/// Initialize existing sieve.
41+
constexpr sieve(sieve_t value) NOEXCEPT;
42+
43+
/// The fingerprint value.
44+
constexpr sieve_t value() const NOEXCEPT;
45+
46+
/// True if fingerprint aligns with sieve screen(s), bucket may contain.
47+
constexpr bool screened(sieve_t fingerprint) const NOEXCEPT;
48+
49+
/// Add fingerprint to sieve, false if already screened.
50+
constexpr bool screen(sieve_t fingerprint) NOEXCEPT;
51+
52+
/// The fingerprint value.
53+
constexpr operator sieve_t() const NOEXCEPT;
54+
55+
protected:
56+
static constexpr auto sieve_bits = SieveBits;
57+
static constexpr auto selector_bits = SelectorBits;
58+
static constexpr auto screen_bits = sieve_bits - selector_bits;
59+
static constexpr auto screens = system::power2(selector_bits);
60+
static constexpr auto limit = sub1(screens);
61+
static constexpr auto empty = system::unmask_right<sieve_t>(sieve_bits);
62+
static constexpr auto saturated = system::mask_right(empty, sub1(screen_bits));
63+
static constexpr auto selector_mask = system::mask_left<sieve_t>(selector_bits);
64+
65+
static_assert(is_same_type<sieve_t, uint32_t>);
66+
using screen_t = std_array<sieve_t, screens>;
67+
using matrix_t = std_array<screen_t, screens>;
68+
static constexpr matrix_t matrix_
69+
{
70+
screen_t
71+
{
72+
// 1
73+
0b0000'1111111111111111111111111111
74+
},
75+
{
76+
// 2
77+
0b0000'1111111111111100000000000000,
78+
0b0000'0000000000000011111111111111
79+
},
80+
{
81+
// 3
82+
0b0000'1111111111000000000000000000,
83+
0b0000'0000000000000011111111100000,
84+
0b0000'0000000000111100000000011111
85+
},
86+
{
87+
// 4
88+
0b0000'1111111000000000000000000000,
89+
0b0000'0000000000000011111110000000,
90+
0b0000'0000000000111100000000011100,
91+
0b0000'0000000111000000000001100011
92+
},
93+
{
94+
// 5
95+
0b0000'1111110000000000000000000000,
96+
0b0000'0000000000000011111100000000,
97+
0b0000'0000000000111100000000011000,
98+
0b0000'0000000111000000000001100000,
99+
0b0000'0000001000000000000010000111
100+
},
101+
{
102+
// 6
103+
0b0000'1111100000000000000000000000,
104+
0b0000'0000000000000011111000000000,
105+
0b0000'0000000000111100000000010000,
106+
0b0000'0000000111000000000001100000,
107+
0b0000'0000001000000000000010000110,
108+
0b0000'0000010000000000000100001001
109+
},
110+
{
111+
// 7
112+
0b0000'1111000000000000000000000000,
113+
0b0000'0000000000000011110000000000,
114+
0b0000'0000000000111100000000000000,
115+
0b0000'0000000111000000000001000000,
116+
0b0000'0000001000000000000010000110,
117+
0b0000'0000010000000000000100001001,
118+
0b0000'0000100000000000001000110000
119+
},
120+
{
121+
// 8
122+
0b0000'1111000000000000000000000000,
123+
0b0000'0000000000000011110000000000,
124+
0b0000'0000000000111100000000000000,
125+
0b0000'0000000111000000000001000000,
126+
0b0000'0000001000000000000010000100,
127+
0b0000'0000010000000000000100001000,
128+
0b0000'0000100000000000001000100000,
129+
0b0000'0000000000000000000000010011
130+
},
131+
{
132+
// 9
133+
0b0000'1111000000000000000000000000,
134+
0b0000'0000000000000011100000000000,
135+
0b0000'0000000000111000000000000000,
136+
0b0000'0000000111000000000000000000,
137+
0b0000'0000001000000000000010000100,
138+
0b0000'0000010000000000000100001000,
139+
0b0000'0000100000000000001000100000,
140+
0b0000'0000000000000000000000010011,
141+
0b0000'0000000000000100010001000000
142+
},
143+
{
144+
// 10
145+
0b0000'1110000000000000000000000000,
146+
0b0000'0000000000000011100000000000,
147+
0b0000'0000000000111000000000000000,
148+
0b0000'0000000111000000000000000000,
149+
0b0000'0000001000000000000010000100,
150+
0b0000'0000010000000000000100001000,
151+
0b0000'0000100000000000001000100000,
152+
0b0000'0000000000000000000000010011,
153+
0b0000'0000000000000100010000000000,
154+
0b0000'0001000000000000000001000000
155+
},
156+
{
157+
// 11
158+
0b0000'1110000000000000000000000000,
159+
0b0000'0000000000000011100000000000,
160+
0b0000'0000000000111000000000000000,
161+
0b0000'0000000111000000000000000000,
162+
0b0000'0000001000000000000010000100,
163+
0b0000'0000010000000000000100001000,
164+
0b0000'0000100000000000001000000000,
165+
0b0000'0000000000000000000000010010,
166+
0b0000'0000000000000100010000000000,
167+
0b0000'0001000000000000000001000000,
168+
0b0000'0000000000000000000000100001
169+
},
170+
{
171+
// 12
172+
0b0000'1110000000000000000000000000,
173+
0b0000'0000000000000011100000000000,
174+
0b0000'0000000000111000000000000000,
175+
0b0000'0000000111000000000000000000,
176+
0b0000'0000001000000000000010000000,
177+
0b0000'0000010000000000000100000000,
178+
0b0000'0000100000000000001000000000,
179+
0b0000'0000000000000000000000010010,
180+
0b0000'0000000000000100010000000000,
181+
0b0000'0001000000000000000001000000,
182+
0b0000'0000000000000000000000100001,
183+
0b0000'0000000000000000000000001100
184+
},
185+
{
186+
// 13
187+
0b0000'1110000000000000000000000000,
188+
0b0000'0000000000000011100000000000,
189+
0b0000'0000000000110000000000000000,
190+
0b0000'0000000110000000000000000000,
191+
0b0000'0000001000000000000010000000,
192+
0b0000'0000010000000000000100000000,
193+
0b0000'0000100000000000001000000000,
194+
0b0000'0000000000000000000000010010,
195+
0b0000'0000000000000100010000000000,
196+
0b0000'0001000000000000000001000000,
197+
0b0000'0000000000000000000000100001,
198+
0b0000'0000000000000000000000001100,
199+
0b0000'0000000001001000000000000000
200+
},
201+
{
202+
// 14
203+
0b0000'1100000000000000000000000000,
204+
0b0000'0000000000000011000000000000,
205+
0b0000'0000000000110000000000000000,
206+
0b0000'0000000110000000000000000000,
207+
0b0000'0000001000000000000010000000,
208+
0b0000'0000010000000000000100000000,
209+
0b0000'0000100000000000001000000000,
210+
0b0000'0000000000000000000000010010,
211+
0b0000'0000000000000100010000000000,
212+
0b0000'0001000000000000000001000000,
213+
0b0000'0000000000000000000000100001,
214+
0b0000'0000000000000000000000001100,
215+
0b0000'0000000001001000000000000000,
216+
0b0000'0010000000000000100000000000
217+
},
218+
{
219+
// 15
220+
0b0000'1100000000000000000000000000,
221+
0b0000'0000000000000011000000000000,
222+
0b0000'0000000000110000000000000000,
223+
0b0000'0000000110000000000000000000,
224+
0b0000'0000001000000000000010000000,
225+
0b0000'0000010000000000000100000000,
226+
0b0000'0000100000000000001000000000,
227+
0b0000'0000000000000000000000010010,
228+
0b0000'0000000000000100010000000000,
229+
0b0000'0001000000000000000001000000,
230+
0b0000'0000000000000000000000100001,
231+
0b0000'0000000000000000000000001100,
232+
0b0000'0000000001001000000000000000,
233+
0b0000'0010000000000000000000000000,
234+
0b0000'0000000000000000100000000000
235+
},
236+
{
237+
// 16
238+
0b0000'0'100000000000000000000000000, // first bit sacrificed for sentinel
239+
0b0000'0000000000000011000000000000,
240+
0b0000'0000000000110000000000000000,
241+
0b0000'0000000110000000000000000000,
242+
0b0000'0000001000000000000010000000,
243+
0b0000'0000010000000000000100000000,
244+
0b0000'0000100000000000001000000000,
245+
0b0000'0000000000000000000000010010,
246+
0b0000'0000000000000100010000000000,
247+
0b0000'0001000000000000000001000000,
248+
0b0000'0000000000000000000000100001,
249+
0b0000'0000000000000000000000001100,
250+
0b0000'0000000001000000000000000000,
251+
0b0000'0010000000000000000000000000,
252+
0b0000'0000000000000000100000000000,
253+
0b0000'0000000000001000000000000000
254+
}
255+
};
256+
257+
private:
258+
sieve_t sieve_;
32259
};
33260

34261
} // namespace database
35262
} // namespace libbitcoin
36263

37-
#define TEMPLATE template <size_t Size>
38-
#define CLASS sieve<Size>
264+
#define TEMPLATE template <size_t SieveBits, size_t SelectorBits, \
265+
if_not_greater<SelectorBits, SieveBits> If1, \
266+
if_not_greater<SieveBits, bits<uint64_t>> If2>
267+
268+
#define CLASS sieve<SieveBits, SelectorBits, If1, If2>
39269

40270
#include <bitcoin/database/impl/primitives/sieve.ipp>
41271

0 commit comments

Comments
 (0)