#pragma once #include #include #include #include #include namespace gp { 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; } }; 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]; } }; template 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: 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); } } }; }