refactor: use C++20 function std::popcount (#4389)

- Replace custom popcnt16 implementation with std::popcount from C++20
- Maintain compatibility with older compilers and MacOS by providing a
  conditional compilation fallback to __builtin_popcount and a lookup
  table method
- Move and inline related functions within SHAMapInnerNode for
  performance and readability

Signed-off-by: Manoj Doshi <mdoshi@ripple.com>
This commit is contained in:
Alphonse N. Mousse
2023-07-02 15:52:04 +00:00
committed by tequ
parent 913866afb2
commit e40a97100b
4 changed files with 44 additions and 38 deletions

View File

@@ -28,6 +28,7 @@
#include <ripple/shamap/impl/TaggedPointer.h>
#include <atomic>
#include <bit>
#include <bitset>
#include <cstdint>
#include <limits>
@@ -194,12 +195,24 @@ public:
makeCompressedInner(Slice data);
};
inline bool
SHAMapInnerNode::isEmpty() const
{
return isBranch_ == 0;
}
inline bool
SHAMapInnerNode::isEmptyBranch(int m) const
{
return (isBranch_ & (1 << m)) == 0;
}
inline int
SHAMapInnerNode::getBranchCount() const
{
return popcnt16(isBranch_);
}
inline bool
SHAMapInnerNode::isFullBelow(std::uint32_t generation) const
{

View File

@@ -256,18 +256,6 @@ SHAMapInnerNode::serializeWithPrefix(Serializer& s) const
[&](SHAMapHash const& hh) { s.addBitString(hh.as_uint256()); });
}
bool
SHAMapInnerNode::isEmpty() const
{
return isBranch_ == 0;
}
int
SHAMapInnerNode::getBranchCount() const
{
return popcnt16(isBranch_);
}
std::string
SHAMapInnerNode::getString(const SHAMapNodeID& id) const
{
@@ -292,9 +280,9 @@ SHAMapInnerNode::setChild(int m, std::shared_ptr<SHAMapTreeNode> child)
auto const dstIsBranch = [&] {
if (child)
return isBranch_ | (1 << m);
return isBranch_ | (1u << m);
else
return isBranch_ & ~(1 << m);
return isBranch_ & ~(1u << m);
}();
auto const dstToAllocate = popcnt16(dstIsBranch);

View File

@@ -22,6 +22,8 @@
#include <ripple/shamap/SHAMapTreeNode.h>
#include <array>
#include <bit>
#include <cstdint>
#include <optional>
@@ -217,6 +219,31 @@ public:
getChildIndex(std::uint16_t isBranch, int i) const;
};
[[nodiscard]] inline int
popcnt16(std::uint16_t a)
{
#if __cpp_lib_bitops
return std::popcount(a);
#elif defined(__clang__) || defined(__GNUC__)
return __builtin_popcount(a);
#else
// fallback to table lookup
static auto constexpr const tbl = []() {
std::array<std::uint8_t, 256> ret{};
for (int i = 0; i != 256; ++i)
{
for (int j = 0; j != 8; ++j)
{
if (i & (1 << j))
ret[i]++;
}
}
return ret;
}();
return tbl[a & 0xff] + tbl[a >> 8];
#endif
}
} // namespace ripple
#endif

View File

@@ -22,6 +22,7 @@
#include <ripple/shamap/impl/TaggedPointer.h>
#include <array>
#include <bit>
#include <boost/pool/pool_alloc.hpp>
@@ -159,29 +160,6 @@ deallocateArrays(std::uint8_t boundaryIndex, void* p)
freeArrayFuns[boundaryIndex](p);
}
[[nodiscard]] inline int
popcnt16(std::uint16_t a)
{
#if defined(__clang__) || defined(__GNUC__)
return __builtin_popcount(a);
#else
// fallback to table lookup
static auto constexpr const tbl = []() {
std::array<std::uint8_t, 256> ret{};
for (int i = 0; i != 256; ++i)
{
for (int j = 0; j != 8; ++j)
{
if (i & (1 << j))
ret[i]++;
}
}
return ret;
}();
return tbl[a & 0xff] + tbl[a >> 8];
#endif
}
// Used in `iterChildren` and elsewhere as the hash value for sparse arrays when
// the hash isn't actually stored in the array.
static SHAMapHash const zeroSHAMapHash;
@@ -285,7 +263,7 @@ TaggedPointer::getChildIndex(std::uint16_t isBranch, int i) const
// mask sets all the bits >=i to zero and all the bits <i to
// one.
auto const mask = (1 << i) - 1;
auto const mask = (1u << i) - 1;
return popcnt16(isBranch & mask);
}