|
|
- #pragma once
-
- #include <gp/algorithm/foreach.hpp>
- #include <gp/algorithm/tmp_manip.hpp>
- #include <gp/array.hpp>
- #include <gp/exception.hpp>
-
- #include <atomic>
-
- #include <stdint.h>
-
- namespace gp {
-
- // TODO: Specify the concept of a skipstone
-
- /**
- * @brief An abstraction for exploring and picking in a list sequencially
- */
- struct linear_skipstone {
- constexpr static size_t ccbits = 1;
- constexpr static size_t cclast = 1;
- size_t ret = 0;
- void next() {
- ++ret;
- }
- operator size_t() {
- return ret;
- }
- };
-
- /**
- * @brief An abstraction for exploring and picking in a list in a non sequencial but still relatively cache friendly way
- */
- struct stepcache_skipstone {
- constexpr static size_t ccbits = 7;
- constexpr static size_t cclast = 127;
-
- constexpr static size_t list[128] = {
- 0, 1, 2, 3,
- 8, 9, 10, 11,
- 20, 21, 22, 23,
- 36, 37, 38, 39,
- 56, 57, 58, 59,
- 80, 81, 82, 83,
- 108, 109, 110, 111,
- 140, 141, 142, 143,
- 176, 177, 178, 179,
- 216, 217, 218, 219,
- 260, 261, 262, 263,
- 308, 309, 310, 311,
- 360, 361, 362, 363,
- 416, 417, 418, 419,
- 476, 477, 478, 479,
- 540, 541, 542, 543,
- 608, 609, 610, 611,
- 680, 681, 682, 683,
- 756, 757, 758, 759,
- 836, 837, 838, 839,
- 920, 921, 922, 923,
- 1008, 1009, 1010, 1011,
- 1100, 1101, 1102, 1103,
- 1196, 1197, 1198, 1199,
- 1296, 1297, 1298, 1299,
- 1400, 1401, 1402, 1403,
- 1508, 1509, 1510, 1511,
- 1736, 1737, 1738, 1739,
- 1856, 1857, 1858, 1859,
- 1980, 1981, 1982, 1983,
- 2108, 2109, 2110, 2111,
- 2240, 2241, 2242, 2243
- };
- size_t ret = 0;
- void next() {
- ++ret;
- }
- operator size_t() {
- [[unlikely]] if ( ret >= 128 )
- return ret+list[127];
- return list[ret];
- }
- };
-
- /**
- * @brief A datastructure to accurately check belonging in a set in a probabilistic way.
- * More precise than a bloomfilter, less space efficient, can allow deletion (handle with care)
- *
- * @tparam hash_type the type of hash storage type
- * @tparam magnitude the size of the filter as a power of 2
- * @tparam remainder the number of bits of remainder of the quotient \f$\frac{h}{m}\f$ where \f$h\f$ is a hash and \f$m\f$ the magnitude of the set, can throw away bits
- * @tparam skipstone_t the type of sequence exploration to perform
- */
- template<typename hash_type = uint32_t, uint8_t magnitude = 20, uint8_t remainder = (8*sizeof(hash_type))-magnitude, typename skipstone_t = linear_skipstone>
- class quotient_filter {
- constexpr static size_t phys_size = (1 << magnitude) / 32;
- using rem_t = typename gp::either<(remainder<=16), uint16_t, uint32_t>::type;
- struct node{
- //rem_t ccount : skipstone_t::ccbits;
- rem_t is_occupied : 1;
- rem_t is_deleted : 1;
- rem_t r : remainder;
- };
-
- gp::array<
- node,
- 1 << magnitude
- > data;
-
- void skipstone_killswitch(size_t q, size_t skip)
- {
- if(q == (q+skip)%data.size())
- {
- if constexpr (gp_config::has_exceptions)
- {
- throw gp::runtime_error("infinite skiploop detected");
- }
- else
- {
- exit((int)gp_errorcodes::infinite_skipstone);
- }
- }
- }
-
- public:
- quotient_filter() {
- gp::fill(data, node{0,0,0});
- }
-
- void set_hash(hash_type v)
- {
- const size_t q = v & ((1 << magnitude)-1);
- const size_t r = (v >> magnitude) & ((1 << remainder)-1);
- skipstone_t skip;
-
- for(;;)
- {
- auto& slot = data[(q+skip)%data.size()];
- if(slot.is_occupied)
- {
- if(slot.is_deleted)
- {
- slot.r = r;
- slot.is_deleted = false;
- for(;;)
- {
- skip.next();
- slot = data[(q+skip)%data.size()];
- if(!slot.is_occupied)
- {
- return;
- }
- else if(slot.r == r)
- {
- slot.is_deleted = true;
- }
- skipstone_killswitch(q, skip);
- }
- }
- if(slot.r == r)
- {
- return;
- }
- skip.next();
- }
- else
- {
- slot.r = r;
- slot.is_occupied = true;
- slot.is_deleted = false;
- return;
- }
- skipstone_killswitch(q, skip);
- }
- }
-
- bool test_hash(hash_type v)
- {
- const size_t q = v & ((1 << magnitude)-1);
- const size_t r = (v >> magnitude) & ((1 << remainder)-1);
- skipstone_t skip;
-
- for(;;)
- {
- auto& slot = data[(q+skip)%data.size()];
- if(slot.is_occupied)
- {
- if(!slot.is_deleted)
- {
- if(slot.r == r)
- {
- return true;
- }
- }
- skip.next();
- }
- else
- {
- return false;
- }
- skipstone_killswitch(q, skip);
- }
- }
-
- void remove_hash(hash_type v)
- {
- const size_t q = v & ((1 << magnitude)-1);
- const size_t r = (v >> magnitude) & ((1 << remainder)-1);
- skipstone_t skip;
-
- for(;;)
- {
- auto& slot = data[(q+skip)%data.size()];
- if(slot.is_occupied)
- {
- if(!slot.is_deleted)
- {
- if(slot.r == r)
- {
- slot.is_deleted = true;
- slot.is_occupied = false;
- }
- }
- skip.next();
- }
- else
- {
- return;
- }
- skipstone_killswitch(q, skip);
- }
- }
- };
- }
|