Skip to content

Commit 0511d27

Browse files
authored
Merge pull request #587 from evoskuil/master
Add consteval mask table generation to sieve class.
2 parents 6f63b80 + f05fc16 commit 0511d27

5 files changed

Lines changed: 291 additions & 196 deletions

File tree

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

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
// [[111][1000000000000000000000000000]] saturated
3838

3939
// To minimize computation in alignment the sieve is defined as two dimensional
40-
// matrix of precomputed masks. One dimension is determined by the screen
40+
// table of precomputed masks. One dimension is determined by the screen
4141
// 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
@@ -73,6 +73,17 @@ constexpr CLASS::operator CLASS::sieve_t() const NOEXCEPT
7373
return sieve_;
7474
}
7575

76+
// protected
77+
TEMPLATE
78+
constexpr CLASS::sieve_t CLASS::masks(size_t row, size_t column) const NOEXCEPT
79+
{
80+
BC_ASSERT(column <= row);
81+
82+
// Read/write member compressed array as if it was a two-dimesional array.
83+
constexpr auto get_offset = generate_offsets();
84+
return masks_[get_offset[row] + column];
85+
}
86+
7687
TEMPLATE
7788
constexpr bool CLASS::screened(sieve_t fingerprint) const NOEXCEPT
7889
{
@@ -153,6 +164,72 @@ constexpr bool CLASS::screen(sieve_t fingerprint) NOEXCEPT
153164
return true;
154165
}
155166

167+
// protected/static
168+
TEMPLATE
169+
CONSTEVAL CLASS::offsets_t CLASS::generate_offsets() NOEXCEPT
170+
{
171+
using namespace system;
172+
173+
// Generate compression offsets at compile, generally 16 or 32 elements.
174+
offsets_t offsets{};
175+
for (size_t index{}; index < screens; ++index)
176+
offsets[index] = to_half(ceilinged_multiply(index, add1(index)));
177+
178+
return offsets;
179+
}
180+
181+
// protected/static
182+
TEMPLATE
183+
CONSTEVAL CLASS::masks_t CLASS::generate_masks() NOEXCEPT
184+
{
185+
using namespace system;
186+
masks_t out{};
187+
188+
// Read/write compressed array as if it was a two-dimesional array.
189+
const auto masks = [&out](auto row, auto column) NOEXCEPT -> sieve_t&
190+
{
191+
BC_ASSERT(column <= row);
192+
constexpr auto get_offset = generate_offsets();
193+
return out[get_offset[row] + column];
194+
};
195+
196+
// Determine the count of mask bits for a given table element.
197+
const auto mask_bits = [](auto row, auto column) NOEXCEPT -> size_t
198+
{
199+
BC_ASSERT(column <= row);
200+
const auto div = floored_divide(screen_bits, add1(row));
201+
const auto mod = floored_modulo(screen_bits, add1(row));
202+
return div + to_int(column < mod);
203+
};
204+
205+
masks(0, 0) = first_mask;
206+
for (sieve_t row = 1; row < screens; ++row)
207+
{
208+
for (sieve_t col = 0; col < row; ++col)
209+
masks(row, col) = masks(sub1(row), col);
210+
211+
for (auto mask = row; !is_zero(mask); --mask)
212+
{
213+
const auto col = sub1(mask);
214+
auto excess = floored_subtract(ones_count(masks(row, col)),
215+
mask_bits(row, col));
216+
217+
while (!is_zero(excess))
218+
{
219+
const auto bit = right_zeros(masks(row, col));
220+
if (bit < screen_bits)
221+
{
222+
set_right_into(masks(row, col), bit, false);
223+
set_right_into(masks(row, row), bit, true);
224+
--excess;
225+
}
226+
}
227+
}
228+
}
229+
230+
return out;
231+
}
232+
156233
} // namespace database
157234
} // namespace libbitcoin
158235

include/bitcoin/database/impl/query/objects.ipp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,8 @@ bool CLASS::populate(const transaction& tx) const NOEXCEPT
322322
return std::all_of(ins->begin(), ins->end(),
323323
[this](const auto& in) NOEXCEPT
324324
{
325-
return populate(*in);
325+
// Work around bogus clang warning.
326+
return this->populate(*in);
326327
});
327328
}
328329

@@ -336,7 +337,8 @@ bool CLASS::populate(const block& block) const NOEXCEPT
336337
return std::all_of(std::next(txs->begin()), txs->end(),
337338
[this](const auto& tx) NOEXCEPT
338339
{
339-
return populate(*tx);
340+
// Work around bogus clang warning.
341+
return this->populate(*tx);
340342
});
341343
}
342344

include/bitcoin/database/primitives/sieve.hpp

Lines changed: 14 additions & 191 deletions
Original file line numberDiff line numberDiff line change
@@ -58,206 +58,29 @@ class sieve
5858
static constexpr auto screen_bits = sieve_bits - selector_bits;
5959

6060
static constexpr auto empty = system::unmask_right<sieve_t>(sieve_bits);
61-
static constexpr auto selector_mask = system::unmask_right<sieve_t>(screen_bits);
6261
static constexpr auto saturated = system::mask_right(empty, sub1(screen_bits));
62+
static constexpr auto first_mask = system::unmask_right<sieve_t>(screen_bits);
63+
static constexpr auto selector_mask = first_mask;
6364

6465
static constexpr auto screens = system::power2(selector_bits);
65-
static constexpr auto matrix = to_half(screens * add1(screens));
66+
static constexpr auto mask_count = to_half(screens * add1(screens));
6667
static constexpr auto limit = sub1(screens);
67-
using masks_t = std_array<sieve_t, matrix>;
68+
using masks_t = std_array<sieve_t, mask_count>;
69+
using offsets_t = std_array<size_t, screens>;
6870

69-
// Generate compression offsets at compile, generally 16 or 32 elements.
70-
template <size_t Size>
71-
static CONSTEVAL auto offsets() NOEXCEPT
72-
{
73-
std_array<uint16_t, Size> offset{};
74-
for (auto index = zero; index < Size; ++index)
75-
offset[index] = to_half(index * add1(index));
76-
return offset;
77-
}
71+
/// Generate compression offsets at compile.
72+
static CONSTEVAL offsets_t generate_offsets() NOEXCEPT;
7873

79-
// Access compressed array as if it was a two-dimesional array.
80-
static constexpr auto masks(auto screen, auto segment) NOEXCEPT
81-
{
82-
constexpr auto offset = offsets<screens>();
83-
return masks_[offset[screen] + segment];
84-
}
74+
/// Compile-time mask table generator.
75+
static CONSTEVAL masks_t generate_masks() NOEXCEPT;
76+
77+
/// Read member compressed mask array as if it was a two-dimesional array.
78+
constexpr sieve_t masks(size_t row, size_t column) const NOEXCEPT;
8579

8680
private:
87-
// Logically this is sparse 16 x 16 = 256 matrix of uint32_t (1024 bytes).
81+
// Logically sparse, e.g. 16 x 16 = 256 table of uint32_t (1024 bytes).
8882
// Compressed to one-dimensional 136 element array of uint32_t (544 bytes).
89-
static constexpr std_array<sieve_t, matrix> masks_
90-
{
91-
// 1
92-
0b0000'1111111111111111111111111111,
93-
94-
// 2
95-
0b0000'1111111111111100000000000000,
96-
0b0000'0000000000000011111111111111,
97-
98-
// 3
99-
0b0000'1111111111000000000000000000,
100-
0b0000'0000000000000011111111100000,
101-
0b0000'0000000000111100000000011111,
102-
103-
// 4
104-
0b0000'1111111000000000000000000000,
105-
0b0000'0000000000000011111110000000,
106-
0b0000'0000000000111100000000011100,
107-
0b0000'0000000111000000000001100011,
108-
109-
// 5
110-
0b0000'1111110000000000000000000000,
111-
0b0000'0000000000000011111100000000,
112-
0b0000'0000000000111100000000011000,
113-
0b0000'0000000111000000000001100000,
114-
0b0000'0000001000000000000010000111,
115-
116-
// 6
117-
0b0000'1111100000000000000000000000,
118-
0b0000'0000000000000011111000000000,
119-
0b0000'0000000000111100000000010000,
120-
0b0000'0000000111000000000001100000,
121-
0b0000'0000001000000000000010000110,
122-
0b0000'0000010000000000000100001001,
123-
124-
// 7
125-
0b0000'1111000000000000000000000000,
126-
0b0000'0000000000000011110000000000,
127-
0b0000'0000000000111100000000000000,
128-
0b0000'0000000111000000000001000000,
129-
0b0000'0000001000000000000010000110,
130-
0b0000'0000010000000000000100001001,
131-
0b0000'0000100000000000001000110000,
132-
133-
// 8
134-
0b0000'1111000000000000000000000000,
135-
0b0000'0000000000000011110000000000,
136-
0b0000'0000000000111100000000000000,
137-
0b0000'0000000111000000000001000000,
138-
0b0000'0000001000000000000010000100,
139-
0b0000'0000010000000000000100001000,
140-
0b0000'0000100000000000001000100000,
141-
0b0000'0000000000000000000000010011,
142-
143-
// 9
144-
0b0000'1111000000000000000000000000,
145-
0b0000'0000000000000011100000000000,
146-
0b0000'0000000000111000000000000000,
147-
0b0000'0000000111000000000000000000,
148-
0b0000'0000001000000000000010000100,
149-
0b0000'0000010000000000000100001000,
150-
0b0000'0000100000000000001000100000,
151-
0b0000'0000000000000000000000010011,
152-
0b0000'0000000000000100010001000000,
153-
154-
// 10
155-
0b0000'1110000000000000000000000000,
156-
0b0000'0000000000000011100000000000,
157-
0b0000'0000000000111000000000000000,
158-
0b0000'0000000111000000000000000000,
159-
0b0000'0000001000000000000010000100,
160-
0b0000'0000010000000000000100001000,
161-
0b0000'0000100000000000001000100000,
162-
0b0000'0000000000000000000000010011,
163-
0b0000'0000000000000100010000000000,
164-
0b0000'0001000000000000000001000000,
165-
166-
// 11
167-
0b0000'1110000000000000000000000000,
168-
0b0000'0000000000000011100000000000,
169-
0b0000'0000000000111000000000000000,
170-
0b0000'0000000111000000000000000000,
171-
0b0000'0000001000000000000010000100,
172-
0b0000'0000010000000000000100001000,
173-
0b0000'0000100000000000001000000000,
174-
0b0000'0000000000000000000000010010,
175-
0b0000'0000000000000100010000000000,
176-
0b0000'0001000000000000000001000000,
177-
0b0000'0000000000000000000000100001,
178-
179-
// 12
180-
0b0000'1110000000000000000000000000,
181-
0b0000'0000000000000011100000000000,
182-
0b0000'0000000000111000000000000000,
183-
0b0000'0000000111000000000000000000,
184-
0b0000'0000001000000000000010000000,
185-
0b0000'0000010000000000000100000000,
186-
0b0000'0000100000000000001000000000,
187-
0b0000'0000000000000000000000010010,
188-
0b0000'0000000000000100010000000000,
189-
0b0000'0001000000000000000001000000,
190-
0b0000'0000000000000000000000100001,
191-
0b0000'0000000000000000000000001100,
192-
193-
// 13
194-
0b0000'1110000000000000000000000000,
195-
0b0000'0000000000000011100000000000,
196-
0b0000'0000000000110000000000000000,
197-
0b0000'0000000110000000000000000000,
198-
0b0000'0000001000000000000010000000,
199-
0b0000'0000010000000000000100000000,
200-
0b0000'0000100000000000001000000000,
201-
0b0000'0000000000000000000000010010,
202-
0b0000'0000000000000100010000000000,
203-
0b0000'0001000000000000000001000000,
204-
0b0000'0000000000000000000000100001,
205-
0b0000'0000000000000000000000001100,
206-
0b0000'0000000001001000000000000000,
207-
208-
// 14
209-
0b0000'1100000000000000000000000000,
210-
0b0000'0000000000000011000000000000,
211-
0b0000'0000000000110000000000000000,
212-
0b0000'0000000110000000000000000000,
213-
0b0000'0000001000000000000010000000,
214-
0b0000'0000010000000000000100000000,
215-
0b0000'0000100000000000001000000000,
216-
0b0000'0000000000000000000000010010,
217-
0b0000'0000000000000100010000000000,
218-
0b0000'0001000000000000000001000000,
219-
0b0000'0000000000000000000000100001,
220-
0b0000'0000000000000000000000001100,
221-
0b0000'0000000001001000000000000000,
222-
0b0000'0010000000000000100000000000,
223-
224-
// 15
225-
0b0000'1100000000000000000000000000,
226-
0b0000'0000000000000011000000000000,
227-
0b0000'0000000000110000000000000000,
228-
0b0000'0000000110000000000000000000,
229-
0b0000'0000001000000000000010000000,
230-
0b0000'0000010000000000000100000000,
231-
0b0000'0000100000000000001000000000,
232-
0b0000'0000000000000000000000010010,
233-
0b0000'0000000000000100010000000000,
234-
0b0000'0001000000000000000001000000,
235-
0b0000'0000000000000000000000100001,
236-
0b0000'0000000000000000000000001100,
237-
0b0000'0000000001001000000000000000,
238-
0b0000'0010000000000000000000000000,
239-
0b0000'0000000000000000100000000000,
240-
241-
// 16
242-
// first row first bit sacrificed for sentinel.
243-
0b0000'0'100000000000000000000000000,
244-
0b0000'0000000000000011000000000000,
245-
0b0000'0000000000110000000000000000,
246-
0b0000'0000000110000000000000000000,
247-
0b0000'0000001000000000000010000000,
248-
0b0000'0000010000000000000100000000,
249-
0b0000'0000100000000000001000000000,
250-
0b0000'0000000000000000000000010010,
251-
0b0000'0000000000000100010000000000,
252-
0b0000'0001000000000000000001000000,
253-
0b0000'0000000000000000000000100001,
254-
0b0000'0000000000000000000000001100,
255-
0b0000'0000000001000000000000000000,
256-
0b0000'0010000000000000000000000000,
257-
0b0000'0000000000000000100000000000,
258-
0b0000'0000000000001000000000000000
259-
};
260-
83+
static constexpr masks_t masks_ = generate_masks();
26184
sieve_t sieve_;
26285
};
26386

test/primitives/nomap.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -530,7 +530,6 @@ BOOST_AUTO_TEST_CASE(nomap__record_get__excess__false)
530530
test::chunk_storage body_store{ body_file };
531531
const nomap<link5, record_excess::size> instance{ head_store, body_store };
532532

533-
record_excess record{};
534533
BC_DEBUG_ONLY(BOOST_REQUIRE(!instance.get(zero, record));)
535534
BOOST_REQUIRE(!instance.get_fault());
536535
}

0 commit comments

Comments
 (0)