/* This file is part of Jellyfish.
Jellyfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Jellyfish is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Jellyfish. If not, see .
*/
#ifndef __BLOOM_COUNTER2_HPP__
#define __BLOOM_COUNTER2_HPP__
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifdef HAVE_CONFIG_H
#include
#endif
namespace jellyfish {
/* Bloom counter with 3 values: 0, 1 or 2. It is thread safe and lock free.
*/
template, typename atomic_t = ::atomic::gcc>
class bloom_counter2_base : public bloom_base, HashPair> {
typedef bloom_base, HashPair> super;
atomic_t atomic_;
protected:
static size_t nb_bytes__(size_t l) {
return l / 5 + (l % 5 != 0);
}
public:
bloom_counter2_base(size_t m, unsigned long k, unsigned char* ptr, const HashPair& fns = HashPair()) :
super(m, k, ptr, fns)
{ }
bloom_counter2_base(bloom_counter2_base&& rhs) :
super(std::move(rhs))
{ }
size_t nb_bytes() const {
return nb_bytes__(super::d_.d());
}
// Insert key with given hashes
unsigned int insert__(const uint64_t* hashes) {
// Prefetch memory locations
static_assert(std::is_pod::value, "prefetch_info must be a POD");
typename super::prefetch_info pinfo[super::k_];
const size_t base = super::d_.remainder(hashes[0]);
const size_t inc = super::d_.remainder(hashes[1]);
for(unsigned long i = 0; i < super::k_; ++i) {
const size_t p = super::d_.remainder(base + i * inc);
const size_t off = p / 5;
pinfo[i].boff = p % 5;
pinfo[i].pos = super::data_ + off;
// prefetch_write_no(pinfo[i].pos);
__builtin_prefetch(pinfo[i].pos, 1, 0);
}
// Insert element
unsigned char res = 2;
for(unsigned long i = 0; i < super::k_; ++i) {
size_t boff = pinfo[i].boff;
unsigned char v = jflib::a_load(pinfo[i].pos);
while(true) {
unsigned char w = v;
switch(boff) {
case 0: break;
case 1: w /= 3; break;
case 2: w /= 9; break;
case 3: w /= 27; break;
case 4: w /= 81; break;
}
w = w % 3;
if(w == 2) break;
unsigned char nv = v;
switch(boff) {
case 0: nv += 1; break;
case 1: nv += 3; break;
case 2: nv += 9; break;
case 3: nv += 27; break;
case 4: nv += 81; break;
}
unsigned char cv = atomic_.cas(pinfo[i].pos, v, nv);
if(cv == v) {
if(w < res)
res = w;
break;
}
v = cv;
}
}
return res;
}
unsigned int check__(uint64_t *hashes) const {
// Prefetch memory locations
static_assert(std::is_pod::value, "prefetch_info must be a POD");
typename super::prefetch_info pinfo[super::k_];
const size_t base = super::d_.remainder(hashes[0]);
const size_t inc = super::d_.remainder(hashes[1]);
for(unsigned long i = 0; i < super::k_; ++i) {
const size_t p = super::d_.remainder(base + i * inc);
const size_t off = p / 5;
pinfo[i].boff = p % 5;
pinfo[i].pos = super::data_ + off;
// prefetch_read_no(pinfo[i].pos);
__builtin_prefetch(pinfo[i].pos, 0, 0);
}
// Check element
unsigned char res = 2;
for(unsigned long i = 0; i < super::k_; ++i) {
size_t boff = pinfo[i].boff;
unsigned char w = jflib::a_load(pinfo[i].pos);
switch(boff) {
case 0: break;
case 1: w /= 3; break;
case 2: w /= 9; break;
case 3: w /= 27; break;
case 4: w /= 81; break;
}
w = w % 3;
if(w < res)
res = w;
}
return res;
}
};
template, typename atomic_t = ::atomic::gcc,
typename mem_block_t = allocators::mmap>
class bloom_counter2:
protected mem_block_t,
public bloom_counter2_base
{
typedef bloom_counter2_base super;
public:
typedef typename super::key_type key_type;
bloom_counter2(const double fp, const size_t n, const HashPair& fns = HashPair()) :
mem_block_t(super::nb_bytes__(super::opt_m(fp, n))),
super(super::opt_m(fp, n), super::opt_k(fp), (unsigned char*)mem_block_t::get_ptr(), fns)
{
if(!mem_block_t::get_ptr())
throw std::runtime_error(err::msg() << "Failed to allocate " << super::nb_bytes__(super::opt_m(fp, n))
<< " bytes of memory for bloom_counter");
}
bloom_counter2(size_t m, unsigned long k, const HashPair& fns = HashPair()) :
mem_block_t(super::nb_bytes__(m)),
super(m, k, (unsigned char*)mem_block_t::get_ptr(), fns)
{
if(!mem_block_t::get_ptr())
throw std::runtime_error(err::msg() << "Failed to allocate " << super::nb_bytes__(m) << " bytes of memory for bloom_counter");
}
bloom_counter2(size_t m, unsigned long k, std::istream& is, const HashPair& fns = HashPair()) :
mem_block_t(super::nb_bytes__(m)),
super(m, k, (unsigned char*)mem_block_t::get_ptr(), fns)
{
if(!mem_block_t::get_ptr())
throw std::runtime_error(err::msg() << "Failed to allocate " << super::nb_bytes__(m) << " bytes of memory for bloom_counter");
is.read((char*)mem_block_t::get_ptr(), mem_block_t::get_size());
}
bloom_counter2(const bloom_counter2& rhs) = delete;
bloom_counter2(bloom_counter2&& rhs) :
mem_block_t(std::move(rhs)),
super(std::move(rhs))
{ }
};
template, typename atomic_t = ::atomic::gcc>
class bloom_counter2_file :
protected mapped_file,
public bloom_counter2_base
{
typedef bloom_counter2_base super;
public:
typedef typename super::key_type key_type;
bloom_counter2_file(size_t m, unsigned long k, const char* path, const HashPair& fns = HashPair(), off_t offset = 0) :
mapped_file(path),
super(m, k, (unsigned char*)mapped_file::base() + offset, fns)
{ }
bloom_counter2_file(const bloom_counter2_file& rhs) = delete;
bloom_counter2_file(bloom_counter2_file&& rhs) :
mapped_file(std::move(rhs)),
super(std::move(rhs))
{ }
};
} // namespace jellyfish {
#endif // __BLOOM_COUNTER2_HPP__