/*
This file is part of cpp-ethereum.
cpp-ethereum 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.
cpp-ethereum 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 cpp-ethereum. If not, see .
*/
/** @file BloomFilter.h
* @author Vladislav Gluhovsky
* @date June 2015
*/
#pragma once
#include "Common.h"
namespace dev
{
namespace shh
{
template
class TopicBloomFilterBase: public FixedHash
{
public:
TopicBloomFilterBase() { init(); }
TopicBloomFilterBase(FixedHash const& _h): FixedHash(_h) { init(); }
void addBloom(AbridgedTopic const& _h) { addRaw(bloom(_h)); }
void removeBloom(AbridgedTopic const& _h) { removeRaw(bloom(_h)); }
bool containsBloom(AbridgedTopic const& _h) const { return this->contains(bloom(_h)); }
void addRaw(FixedHash const& _h);
void removeRaw(FixedHash const& _h);
bool containsRaw(FixedHash const& _h) const { return this->contains(_h); }
static FixedHash bloom(AbridgedTopic const& _h);
static void setBit(FixedHash& _h, unsigned index);
static bool isBitSet(FixedHash const& _h, unsigned _index);
private:
void init() { for (unsigned i = 0; i < CounterSize; ++i) m_refCounter[i] = 0; }
static const unsigned CounterSize = N * 8;
std::array m_refCounter;
};
static unsigned const c_powerOfTwoBitMmask[8] = { 1, 2, 4, 8, 16, 32, 64, 128 };
template
void TopicBloomFilterBase::addRaw(FixedHash const& _h)
{
*this |= _h;
for (unsigned i = 0; i < CounterSize; ++i)
if (isBitSet(_h, i))
{
if (m_refCounter[i] != std::numeric_limits::max())
m_refCounter[i]++;
else
BOOST_THROW_EXCEPTION(Overflow());
}
}
template
void TopicBloomFilterBase::removeRaw(FixedHash const& _h)
{
for (unsigned i = 0; i < CounterSize; ++i)
if (isBitSet(_h, i))
{
if (m_refCounter[i])
m_refCounter[i]--;
if (!m_refCounter[i])
(*this)[i / 8] &= ~c_powerOfTwoBitMmask[i % 8];
}
}
template
bool TopicBloomFilterBase::isBitSet(FixedHash const& _h, unsigned _index)
{
unsigned iByte = _index / 8;
unsigned iBit = _index & 0x7;
return (_h[iByte] & c_powerOfTwoBitMmask[iBit]) != 0;
}
template
void TopicBloomFilterBase::setBit(FixedHash& _h, unsigned _index)
{
unsigned iByte = _index / 8;
unsigned iBit = _index & 0x7;
_h[iByte] |= c_powerOfTwoBitMmask[iBit];
}
template
FixedHash TopicBloomFilterBase::bloom(AbridgedTopic const& _h)
{
// The size of AbridgedTopic is 32 bits, and 27 of them participate in this algorithm.
// We need to review the algorithm if any of the following constants will be changed.
static_assert(4 == AbridgedTopic::size, "wrong template parameter in TopicBloomFilterBase::bloom()");
static_assert(3 == BitsPerBloom, "wrong template parameter in TopicBloomFilterBase::bloom()");
FixedHash ret;
if (TopicBloomFilterSize == N)
for (unsigned i = 0; i < BitsPerBloom; ++i)
{
unsigned x = _h[i];
if (_h[BitsPerBloom] & c_powerOfTwoBitMmask[i])
x += 256;
setBit(ret, x);
}
else
for (unsigned i = 0; i < BitsPerBloom; ++i)
{
unsigned x = unsigned(_h[i]) + unsigned(_h[i + 1]);
x %= N * 8;
setBit(ret, x);
}
return ret;
}
using TopicBloomFilter = TopicBloomFilterBase;
}
}