diff --git a/libwhisper/BloomFilter.cpp b/libwhisper/BloomFilter.cpp index cff69c664..554274011 100644 --- a/libwhisper/BloomFilter.cpp +++ b/libwhisper/BloomFilter.cpp @@ -25,40 +25,4 @@ using namespace std; using namespace dev; using namespace dev::shh; -static unsigned const c_mask[] = { 1, 2, 4, 8, 16, 32, 64, 128 }; - -void TopicBloomFilter::addRaw(AbridgedTopic const& _h) -{ - *this |= _h; - for (unsigned i = 0; i < CounterSize; ++i) - if (isBitSet(_h, i)) - { - if (m_refCounter[i] != numeric_limits::max()) - m_refCounter[i]++; - else - BOOST_THROW_EXCEPTION(Overflow()); - } -} - -void TopicBloomFilter::removeRaw(AbridgedTopic 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_mask[i % 8]; - } -} - -bool TopicBloomFilter::isBitSet(AbridgedTopic const& _h, unsigned _index) -{ - unsigned iByte = _index / 8; - unsigned iBit = _index % 8; - return (_h[iByte] & c_mask[iBit]) != 0; -} - - diff --git a/libwhisper/BloomFilter.h b/libwhisper/BloomFilter.h index 0ca460805..157f4b011 100644 --- a/libwhisper/BloomFilter.h +++ b/libwhisper/BloomFilter.h @@ -28,30 +28,71 @@ namespace dev namespace shh { -class TopicBloomFilter: public AbridgedTopic +template +class TopicBloomFilterBase: public FixedHash { public: - TopicBloomFilter() { init(); } - TopicBloomFilter(AbridgedTopic const& _h): AbridgedTopic(_h) { init(); } + TopicBloomFilterBase() { init(); } + TopicBloomFilterBase(FixedHash const& _h): FixedHash(_h) { init(); } - void addBloom(AbridgedTopic const& _h) { addRaw(_h.template bloomPart()); } - void removeBloom(AbridgedTopic const& _h) { removeRaw(_h.template bloomPart()); } - bool containsBloom(AbridgedTopic const& _h) const { return contains(_h.template bloomPart()); } + void addBloom(dev::shh::AbridgedTopic const& _h) { addRaw(_h.template bloomPart()); } + void removeBloom(dev::shh::AbridgedTopic const& _h) { removeRaw(_h.template bloomPart()); } + bool containsBloom(dev::shh::AbridgedTopic const& _h) const { return this->contains(_h.template bloomPart()); } - void addRaw(AbridgedTopic const& _h); - void removeRaw(AbridgedTopic const& _h); - bool containsRaw(AbridgedTopic const& _h) const { return contains(_h); } + void addRaw(FixedHash const& _h); + void removeRaw(FixedHash const& _h); + bool containsRaw(FixedHash const& _h) const { return this->contains(_h); } enum { BitsPerBloom = 3 }; private: void init() { for (unsigned i = 0; i < CounterSize; ++i) m_refCounter[i] = 0; } - static bool isBitSet(AbridgedTopic const& _h, unsigned _index); + static bool isBitSet(FixedHash const& _h, unsigned _index); - enum { CounterSize = 8 * TopicBloomFilter::size }; + enum { CounterSize = 8 * TopicBloomFilterBase::size }; 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 % 8; + return (_h[iByte] & c_powerOfTwoBitMmask[iBit]) != 0; +} + +using TopicBloomFilter = TopicBloomFilterBase; + } } diff --git a/libwhisper/Common.cpp b/libwhisper/Common.cpp index 7f5b8ed06..32acbdd8e 100644 --- a/libwhisper/Common.cpp +++ b/libwhisper/Common.cpp @@ -95,9 +95,9 @@ TopicFilter::TopicFilter(RLP const& _r) } } -AbridgedTopic TopicFilter::exportBloom() const +FixedHash TopicFilter::exportBloom() const { - AbridgedTopic ret; + FixedHash ret; for (TopicMask const& t: m_topicMasks) for (auto const& i: t) ret |= i.first.template bloomPart(); diff --git a/libwhisper/Common.h b/libwhisper/Common.h index 07c5b3317..71435603e 100644 --- a/libwhisper/Common.h +++ b/libwhisper/Common.h @@ -59,6 +59,8 @@ enum WhisperPacket PacketCount }; +enum { TopicBloomFilterSize = 8 }; + using AbridgedTopic = FixedHash<4>; using Topic = h256; @@ -105,7 +107,7 @@ public: void streamRLP(RLPStream& _s) const { _s << m_topicMasks; } h256 sha3() const; bool matches(Envelope const& _m) const; - AbridgedTopic exportBloom() const; + FixedHash exportBloom() const; private: TopicMasks m_topicMasks; diff --git a/test/libwhisper/bloomFilter.cpp b/test/libwhisper/bloomFilter.cpp index 799c4caf6..e49473bdc 100644 --- a/test/libwhisper/bloomFilter.cpp +++ b/test/libwhisper/bloomFilter.cpp @@ -27,35 +27,39 @@ using namespace std; using namespace dev; using namespace dev::shh; -void testAddNonExisting(TopicBloomFilter& _f, AbridgedTopic const& _h) +using TopicBloomFilterShort = TopicBloomFilterBase<4>; +using TopicBloomFilterLong = TopicBloomFilterBase<8>; +using TopicBloomFilterTest = TopicBloomFilterLong; + +void testAddNonExisting(TopicBloomFilterShort& _f, AbridgedTopic const& _h) { BOOST_REQUIRE(!_f.containsRaw(_h)); _f.addRaw(_h); BOOST_REQUIRE(_f.containsRaw(_h)); } -void testRemoveExisting(TopicBloomFilter& _f, AbridgedTopic const& _h) +void testRemoveExisting(TopicBloomFilterShort& _f, AbridgedTopic const& _h) { BOOST_REQUIRE(_f.containsRaw(_h)); _f.removeRaw(_h); BOOST_REQUIRE(!_f.containsRaw(_h)); } -void testAddNonExistingBloom(TopicBloomFilter& _f, AbridgedTopic const& _h) +void testAddNonExistingBloom(TopicBloomFilterShort& _f, AbridgedTopic const& _h) { BOOST_REQUIRE(!_f.containsBloom(_h)); _f.addBloom(_h); BOOST_REQUIRE(_f.containsBloom(_h)); } -void testRemoveExistingBloom(TopicBloomFilter& _f, AbridgedTopic const& _h) +void testRemoveExistingBloom(TopicBloomFilterShort& _f, AbridgedTopic const& _h) { BOOST_REQUIRE(_f.containsBloom(_h)); _f.removeBloom(_h); BOOST_REQUIRE(!_f.containsBloom(_h)); } -int calculateExpected(TopicBloomFilter const& f, int const n) +int calculateExpected(TopicBloomFilterTest const& f, int const n) { int const m = f.size * 8; // number of bits in the bloom int const k = f.BitsPerBloom; // number of hash functions (e.g. bits set to 1 in every bloom) @@ -76,7 +80,7 @@ int calculateExpected(TopicBloomFilter const& f, int const n) return static_cast(kBitsSet * 100 + 0.5); // in percents, rounded up } -void testFalsePositiveRate(TopicBloomFilter const& f, int const inserted, Topic& x) +void testFalsePositiveRate(TopicBloomFilterTest const& f, int const inserted, Topic& x) { int const c_sampleSize = 1000; int falsePositive = 0; @@ -104,8 +108,8 @@ BOOST_AUTO_TEST_CASE(falsePositiveRate) VerbosityHolder setTemporaryLevel(10); cnote << "Testing Bloom Filter False Positive Rate..."; - TopicBloomFilter f; - Topic x(0xABCDEF); // deterministic pseudorandom value + TopicBloomFilterTest f; + Topic x(0xC0DEFEED); // deterministic pseudorandom value for (int i = 1; i < 21; ++i) { @@ -120,7 +124,7 @@ BOOST_AUTO_TEST_CASE(bloomFilterRandom) VerbosityHolder setTemporaryLevel(10); cnote << "Testing Bloom Filter matching..."; - TopicBloomFilter f; + TopicBloomFilterShort f; vector vec; Topic x(0xDEADBEEF); int const c_rounds = 4; @@ -146,7 +150,7 @@ BOOST_AUTO_TEST_CASE(bloomFilterRaw) VerbosityHolder setTemporaryLevel(10); cnote << "Testing Raw Bloom matching..."; - TopicBloomFilter f; + TopicBloomFilterShort f; AbridgedTopic b00000001(0x01); AbridgedTopic b00010000(0x10);