General Purpose library for Freestanding C++ and POSIX systems
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

210 lines
4.0 KiB

#pragma once
#include <gp/algorithm/tmp_manip.hpp>
#include <gp/array.hpp>
#include <gp/exception.hpp>
#include <atomic>
#include <stdint.h>
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<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:
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);
}
}
};
}