Skip to content

Commit 4df9280

Browse files
committed
Port filters from database library.
1 parent d672a74 commit 4df9280

6 files changed

Lines changed: 2673 additions & 9 deletions

File tree

include/bitcoin/system/filter/bloom.hpp

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,67 @@
2020
#define LIBBITCOIN_SYSTEM_FILTER_BLOOM_HPP
2121

2222
#include <bitcoin/system/define.hpp>
23+
#include <bitcoin/system/math/math.hpp>
2324

2425
namespace libbitcoin {
2526
namespace system {
2627

28+
/// Bloom is limited to integral types.
29+
template <size_t M, size_t K,
30+
if_not_greater<K, M> = true,
31+
if_not_greater<M, bits<uint64_t>> = true>
32+
class bloom
33+
{
34+
public:
35+
/// This produces size_t when disabled.
36+
using type = unsigned_type<to_ceilinged_bytes(M)>;
37+
38+
/// Bloom is bypassed.
39+
static constexpr bool disabled = is_zero(M) || is_zero(K);
40+
41+
/// Did fingerprint collide.
42+
static constexpr bool is_collision(type previous, type next) NOEXCEPT;
43+
44+
/// Is potential collision.
45+
static constexpr bool is_screened(type value, uint64_t entropy) NOEXCEPT;
46+
47+
/// Add fingerprint to bloom.
48+
static constexpr type screen(type value, uint64_t entropy) NOEXCEPT;
49+
50+
protected:
51+
/// Effectively sentinel values.
52+
static constexpr type saturated = 0;
53+
static constexpr type empty = unmask_right<type>(M);
54+
55+
/// 2^select must be >= M to address all bits in M (modulo if over).
56+
static constexpr size_t select = ceilinged_log2(M);
57+
58+
/// For each K, select unique bits of entropy are required.
59+
static constexpr size_t min_entropy = safe_multiply(select, K);
60+
static_assert(min_entropy <= bits<uint64_t>);
61+
62+
/// Return the k bit selection for the entropy.
63+
static constexpr size_t get_bit(size_t k, uint64_t entropy) NOEXCEPT;
64+
65+
/// Is sentinel value for empty filter.
66+
static constexpr bool is_empty(type value) NOEXCEPT;
67+
68+
/// Is sentinel value for saturated filter.
69+
static constexpr bool is_saturated(type value) NOEXCEPT;
70+
};
71+
2772
} // namespace system
2873
} // namespace libbitcoin
2974

75+
#define TEMPLATE template <size_t M, size_t K, \
76+
if_not_greater<K, M> If1, \
77+
if_not_greater<M, bits<uint64_t>> If2>
78+
79+
#define CLASS bloom<M, K, If1, If2>
80+
3081
#include <bitcoin/system/impl/filter/bloom.ipp>
3182

83+
#undef CLASS
84+
#undef TEMPLATE
85+
3286
#endif

include/bitcoin/system/filter/sieve.hpp

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,83 @@
2020
#define LIBBITCOIN_SYSTEM_FILTER_SIEVE_HPP
2121

2222
#include <bitcoin/system/define.hpp>
23+
#include <bitcoin/system/math/math.hpp>
2324

2425
namespace libbitcoin {
2526
namespace system {
2627

28+
/// Sieve is limited to integral types.
29+
/// There are no false negatives, with the goal of minimizing false positives.
30+
template <size_t SieveBits, size_t SelectBits,
31+
if_not_greater<SelectBits, SieveBits> = true,
32+
if_not_greater<SieveBits, bits<uint64_t>> = true>
33+
class sieve
34+
{
35+
public:
36+
/// This produces size_t when disabled.
37+
using type = unsigned_type<to_ceilinged_bytes(SieveBits)>;
38+
39+
/// Sieve is bypassed.
40+
static constexpr bool disabled = is_zero(SieveBits) || is_zero(SelectBits);
41+
42+
/// Is sieve saturated did fingerprint collide with it.
43+
static constexpr bool is_collision(type previous, type next) NOEXCEPT;
44+
45+
/// Is potential duplicate (saturated or screened).
46+
static constexpr bool is_screened(type value, uint64_t entropy) NOEXCEPT;
47+
48+
/// Add fingerprint to sieve. Changes determined by return/value.
49+
/// Only "value added to sieve" implies a negative result.
50+
/// All other results imply a positive result (potential existence).
51+
/// return == value && return == saturated: sieve was saturated.
52+
/// return != value && return == saturated: sieve now saturated
53+
/// return == value && return != saturated: value was screened.
54+
/// return != value && return != saturated: value added to sieve.
55+
static constexpr type screen(type value, uint64_t entropy) NOEXCEPT;
56+
57+
protected:
58+
static constexpr auto screen_bits = SieveBits - SelectBits;
59+
static constexpr auto screens = power2(SelectBits);
60+
static constexpr auto limit = sub1(screens);
61+
static constexpr auto sentinel = sub1(screen_bits);
62+
static constexpr auto empty = unmask_right<type>(SieveBits);
63+
static constexpr auto saturated = mask_right(empty, sentinel);
64+
static constexpr auto first_mask = unmask_right<type>(screen_bits);
65+
static constexpr auto select_mask = first_mask;
66+
static constexpr auto mask_count = to_half(safe_multiply(screens,
67+
add1(screens)));
68+
69+
using masks_t = std_array<type, mask_count>;
70+
using offsets_t = std_array<type, screens>;
71+
72+
/// Generate compression offsets at compile time.
73+
static CONSTEVAL offsets_t generate_offsets() NOEXCEPT;
74+
75+
/// Generate compressed mask table at compile time.
76+
static CONSTEVAL masks_t generate_masks() NOEXCEPT;
77+
78+
/// Read member compressed mask array as if it was a two-dimesional array.
79+
static constexpr type masks(size_t row, size_t column) NOEXCEPT;
80+
81+
/// Is sentinel value for empty filter.
82+
static constexpr bool is_empty(type value) NOEXCEPT;
83+
84+
/// Is sentinel value for saturated filter.
85+
static constexpr bool is_saturated(type value) NOEXCEPT;
86+
};
87+
2788
} // namespace system
2889
} // namespace libbitcoin
2990

91+
#define TEMPLATE template <size_t SieveBits, size_t SelectBits, \
92+
if_not_greater<SelectBits, SieveBits> If1, \
93+
if_not_greater<SieveBits, bits<uint64_t>> If2>
94+
95+
#define CLASS sieve<SieveBits, SelectBits, If1, If2>
96+
3097
#include <bitcoin/system/impl/filter/sieve.ipp>
3198

99+
#undef CLASS
100+
#undef TEMPLATE
101+
32102
#endif

include/bitcoin/system/impl/filter/bloom.ipp

Lines changed: 80 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,89 @@
1919
#ifndef LIBBITCOIN_SYSTEM_FILTER_BLOOM_IPP
2020
#define LIBBITCOIN_SYSTEM_FILTER_BLOOM_IPP
2121

22-
#include <bitcoin/system/define.hpp>
23-
2422
namespace libbitcoin {
2523
namespace system {
2624

25+
TEMPLATE
26+
constexpr bool CLASS::is_collision(type previous, type next) NOEXCEPT
27+
{
28+
return next == previous;
29+
}
30+
31+
TEMPLATE
32+
constexpr bool CLASS::is_screened(type value, uint64_t entropy) NOEXCEPT
33+
{
34+
if constexpr (disabled)
35+
{
36+
return true;
37+
}
38+
else
39+
{
40+
if (is_empty(value))
41+
return false;
42+
43+
for (auto k = zero; k < K; ++k)
44+
if (get_right(value, get_bit(k, entropy)))
45+
return false;
46+
47+
// All selected bits are set (to zero, default is one).
48+
return true;
49+
}
50+
}
51+
52+
TEMPLATE
53+
constexpr CLASS::type CLASS::screen(type value, uint64_t entropy) NOEXCEPT
54+
{
55+
if constexpr (disabled)
56+
{
57+
return value;
58+
}
59+
else
60+
{
61+
if (is_saturated(value))
62+
return value;
63+
64+
for (auto k = zero; k < K; ++k)
65+
set_right_into(value, get_bit(k, entropy), false);
66+
67+
// All selected bits have been set (to zero, default is one).
68+
return value;
69+
}
70+
}
71+
72+
// protected
73+
// ----------------------------------------------------------------------------
74+
75+
TEMPLATE
76+
constexpr bool CLASS::is_empty(type value) NOEXCEPT
77+
{
78+
return value == empty;
79+
}
80+
81+
TEMPLATE
82+
constexpr bool CLASS::is_saturated(type value) NOEXCEPT
83+
{
84+
return value == saturated;
85+
}
86+
87+
TEMPLATE
88+
constexpr size_t CLASS::get_bit(size_t k, uint64_t entropy) NOEXCEPT
89+
{
90+
constexpr auto mask = unmask_right<type>(select);
91+
const auto shifted = shift_right(entropy, k * select);
92+
const auto bit = bit_and(possible_narrow_cast<type>(shifted), mask);
93+
94+
// When 2^clog2(M) > M must modulo selection to remain within M.
95+
if constexpr (mask >= M)
96+
{
97+
return bit % M;
98+
}
99+
else
100+
{
101+
return bit;
102+
}
103+
}
104+
27105
} // namespace system
28106
} // namespace libbitcoin
29107

0 commit comments

Comments
 (0)