BloomFilter.h 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. /*
  2. This file is part of cpp-ethereum.
  3. cpp-ethereum is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation, either version 3 of the License, or
  6. (at your option) any later version.
  7. cpp-ethereum is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
  13. */
  14. /** @file BloomFilter.h
  15. * @author Vladislav Gluhovsky <vlad@ethdev.com>
  16. * @date June 2015
  17. */
  18. #pragma once
  19. #include "Common.h"
  20. namespace dev
  21. {
  22. namespace shh
  23. {
  24. template <unsigned N>
  25. class TopicBloomFilterBase: public FixedHash<N>
  26. {
  27. public:
  28. TopicBloomFilterBase() { init(); }
  29. TopicBloomFilterBase(FixedHash<N> const& _h): FixedHash<N>(_h) { init(); }
  30. void addBloom(AbridgedTopic const& _h) { addRaw(bloom(_h)); }
  31. void removeBloom(AbridgedTopic const& _h) { removeRaw(bloom(_h)); }
  32. bool containsBloom(AbridgedTopic const& _h) const { return this->contains(bloom(_h)); }
  33. void addRaw(FixedHash<N> const& _h);
  34. void removeRaw(FixedHash<N> const& _h);
  35. bool containsRaw(FixedHash<N> const& _h) const { return this->contains(_h); }
  36. static FixedHash<N> bloom(AbridgedTopic const& _h);
  37. static void setBit(FixedHash<N>& _h, unsigned index);
  38. static bool isBitSet(FixedHash<N> const& _h, unsigned _index);
  39. private:
  40. void init() { for (unsigned i = 0; i < CounterSize; ++i) m_refCounter[i] = 0; }
  41. static const unsigned CounterSize = N * 8;
  42. std::array<uint16_t, CounterSize> m_refCounter;
  43. };
  44. static unsigned const c_powerOfTwoBitMmask[8] = { 1, 2, 4, 8, 16, 32, 64, 128 };
  45. template <unsigned N>
  46. void TopicBloomFilterBase<N>::addRaw(FixedHash<N> const& _h)
  47. {
  48. *this |= _h;
  49. for (unsigned i = 0; i < CounterSize; ++i)
  50. if (isBitSet(_h, i))
  51. {
  52. if (m_refCounter[i] != std::numeric_limits<uint16_t>::max())
  53. m_refCounter[i]++;
  54. else
  55. BOOST_THROW_EXCEPTION(Overflow());
  56. }
  57. }
  58. template <unsigned N>
  59. void TopicBloomFilterBase<N>::removeRaw(FixedHash<N> const& _h)
  60. {
  61. for (unsigned i = 0; i < CounterSize; ++i)
  62. if (isBitSet(_h, i))
  63. {
  64. if (m_refCounter[i])
  65. m_refCounter[i]--;
  66. if (!m_refCounter[i])
  67. (*this)[i / 8] &= ~c_powerOfTwoBitMmask[i % 8];
  68. }
  69. }
  70. template <unsigned N>
  71. bool TopicBloomFilterBase<N>::isBitSet(FixedHash<N> const& _h, unsigned _index)
  72. {
  73. unsigned iByte = _index / 8;
  74. unsigned iBit = _index % 8;
  75. return (_h[iByte] & c_powerOfTwoBitMmask[iBit]) != 0;
  76. }
  77. template <unsigned N>
  78. void TopicBloomFilterBase<N>::setBit(FixedHash<N>& _h, unsigned _index)
  79. {
  80. unsigned iByte = _index / 8;
  81. unsigned iBit = _index % 8;
  82. _h[iByte] |= c_powerOfTwoBitMmask[iBit];
  83. }
  84. template <unsigned N>
  85. FixedHash<N> TopicBloomFilterBase<N>::bloom(AbridgedTopic const& _h)
  86. {
  87. // The size of AbridgedTopic is 32 bits, and 27 of them participate in this algorithm.
  88. // We need to review the algorithm if any of the following constants will be changed.
  89. static_assert(4 == AbridgedTopic::size, "wrong template parameter in TopicBloomFilterBase<N>::bloom()");
  90. static_assert(3 == BitsPerBloom, "wrong template parameter in TopicBloomFilterBase<N>::bloom()");
  91. FixedHash<N> ret;
  92. if (TopicBloomFilterSize == N)
  93. for (unsigned i = 0; i < BitsPerBloom; ++i)
  94. {
  95. unsigned x = _h[i];
  96. if (_h[BitsPerBloom] & c_powerOfTwoBitMmask[i])
  97. x += 256;
  98. setBit(ret, x);
  99. }
  100. else
  101. for (unsigned i = 0; i < BitsPerBloom; ++i)
  102. {
  103. unsigned x = unsigned(_h[i]) + unsigned(_h[i + 1]);
  104. x %= N * 8;
  105. setBit(ret, x);
  106. }
  107. return ret;
  108. }
  109. using TopicBloomFilter = TopicBloomFilterBase<TopicBloomFilterSize>;
  110. }
  111. }