diff --git a/CMakeLists.txt b/CMakeLists.txt index 067059477..6dcccd2c4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -658,6 +658,7 @@ set(TEST_SRC test/test_llarp_router.cpp test/util/test_llarp_util_aligned.cpp test/util/test_llarp_util_bencode.cpp + test/util/test_llarp_util_bits.cpp test/util/test_llarp_util_encode.cpp test/util/test_llarp_util_ini.cpp test/util/test_llarp_util_queue_manager.cpp @@ -765,7 +766,7 @@ else() target_link_libraries(${STATIC_LIB} ${CRYPTOGRAPHY_LIB} ${LIBS} ${UTIL_LIB} ${PLATFORM_LIB}) target_link_libraries(${EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} ${UTIL_LIB} ${PLATFORM_LIB}) - target_link_libraries(${TEST_EXE} ${STATIC_LINK_LIBS} gmock gtest ${STATIC_LIB} ${UTIL_LIB} ${PLATFORM_LIB}) + target_link_libraries(${TEST_EXE} ${STATIC_LINK_LIBS} gmock gtest absl::variant ${STATIC_LIB} ${UTIL_LIB} ${PLATFORM_LIB}) if (WIN32) target_link_libraries(${EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} ${UTIL_LIB} ${PLATFORM_LIB} ws2_32 iphlpapi) target_link_libraries(${TEST_EXE} ${STATIC_LINK_LIBS} gmock gtest ${STATIC_LIB} ${UTIL_LIB} ${PLATFORM_LIB} ws2_32 iphlpapi) diff --git a/llarp/net/exit_info.cpp b/llarp/net/exit_info.cpp index 89d6f1798..967829cf3 100644 --- a/llarp/net/exit_info.cpp +++ b/llarp/net/exit_info.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -82,4 +83,23 @@ namespace llarp return read; } + std::ostream& + operator<<(std::ostream& out, const ExitInfo& xi) + { + char tmp[128] = {0}; + if(inet_ntop(AF_INET6, (void*)&xi.address, tmp, sizeof(tmp))) + out << std::string(tmp); + else + return out; + out << std::string("/"); +#if defined(ANDROID) || defined(RPI) + snprintf(tmp, sizeof(tmp), "%zu", + llarp::bits::count_array_bits(xi.netmask.s6_addr)); + return out << tmp; +#else + return out << std::to_string( + llarp::bits::count_array_bits(xi.netmask.s6_addr)); +#endif + } + } // namespace llarp diff --git a/llarp/net/exit_info.hpp b/llarp/net/exit_info.hpp index 51a6a59e5..cef472dab 100644 --- a/llarp/net/exit_info.hpp +++ b/llarp/net/exit_info.hpp @@ -4,9 +4,8 @@ #include #include #include -#include -#include +#include /** * exit_info.h @@ -54,26 +53,10 @@ namespace llarp ExitInfo & operator=(const ExitInfo &other); - - friend std::ostream & - operator<<(std::ostream &out, const ExitInfo &xi) - { - char tmp[128] = {0}; - if(inet_ntop(AF_INET6, (void *)&xi.address, tmp, sizeof(tmp))) - out << std::string(tmp); - else - return out; - out << std::string("/"); -#if defined(ANDROID) || defined(RPI) - snprintf(tmp, sizeof(tmp), "%zu", - llarp::bits::count_array_bits(xi.netmask.s6_addr)); - return out << tmp; -#else - return out << std::to_string( - llarp::bits::count_array_bits(xi.netmask.s6_addr)); -#endif - } }; + + std::ostream & + operator<<(std::ostream &out, const ExitInfo &xi); } // namespace llarp #endif diff --git a/llarp/util/bits.hpp b/llarp/util/bits.hpp index afac00a1c..c2b5991f4 100644 --- a/llarp/util/bits.hpp +++ b/llarp/util/bits.hpp @@ -1,7 +1,10 @@ #ifndef LLARP_BITS_HPP #define LLARP_BITS_HPP +#include #include +#include +#include namespace llarp { @@ -9,27 +12,29 @@ namespace llarp { template < typename Int_t > constexpr std::size_t - count_bits(const Int_t& i) + count_bits(Int_t i) { - return i == 0 ? 0 - : ((i & 0x01) == 0x01) ? 1UL + count_bits(i >> 1) - : count_bits(i >> 1); + static_assert(std::is_integral< Int_t >::value, + "Int_t should be an integer"); + static_assert(std::is_unsigned< Int_t >::value, + "Int_t should be unsigned"); + return std::bitset< std::numeric_limits< Int_t >::digits >(i).count(); } - template < typename T > + template < typename InputIt > constexpr std::size_t - __count_array_bits(const T& array, std::size_t idx) + __count_array_bits(InputIt begin, InputIt end) { - return idx < sizeof(T) - ? count_bits(array[idx]) + __count_array_bits(array, idx + 1) - : 0; + return std::accumulate(begin, end, 0, [](auto acc, auto val) { + return acc + count_bits(val); + }); } template < typename T > constexpr std::size_t count_array_bits(const T& array) { - return __count_array_bits(array, 0); + return __count_array_bits(std::begin(array), std::end(array)); } } // namespace bits } // namespace llarp diff --git a/test/util/test_llarp_util_bits.cpp b/test/util/test_llarp_util_bits.cpp new file mode 100644 index 000000000..ba6b08a92 --- /dev/null +++ b/test/util/test_llarp_util_bits.cpp @@ -0,0 +1,66 @@ +#include +#include +#include + +#include + +using ArrayUC1 = std::array< unsigned char, 1 >; +using ArrayUC20 = std::array< unsigned char, 20 >; +using ArrayU1 = std::array< unsigned int, 1 >; +using ArrayULL1 = std::array< unsigned long long, 1 >; + +using TestType = absl::variant< ArrayUC1, ArrayUC20, ArrayU1, ArrayULL1 >; + +struct InputData +{ + TestType data; + size_t result; +}; + +struct TestBits : public ::testing::TestWithParam< InputData > +{ +}; + +TEST_P(TestBits, bitcount) +{ + auto d = GetParam(); + ASSERT_EQ(d.result, + absl::visit( + [](const auto& v) { return llarp::bits::count_array_bits(v); }, + d.data)); +} + +// clang-format off +static const InputData inputData[] = { + {ArrayUC1{0b00000000}, 0}, + {ArrayUC1{0b00000001}, 1}, + {ArrayUC1{0b00000010}, 1}, + {ArrayUC1{0b00000100}, 1}, + {ArrayUC1{0b00001000}, 1}, + {ArrayUC1{0b00010000}, 1}, + {ArrayUC1{0b00100000}, 1}, + {ArrayUC1{0b01000000}, 1}, + {ArrayUC1{0b10000000}, 1}, + {ArrayUC1{0b11111111}, 8}, + {ArrayUC20{0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, + 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, + 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, + 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000}, 0}, + {ArrayUC20{0b11111111, 0b00000100, 0b00000100, 0b00000100, 0b00000100, + 0b11111111, 0b00000100, 0b00000100, 0b00000100, 0b00000100, + 0b11111111, 0b00000100, 0b00000100, 0b00000100, 0b00000100, + 0b11111111, 0b00000100, 0b00000100, 0b00000100, 0b00000100}, 48}, + {ArrayU1{0b00000000000000000000000000000000}, 0}, + {ArrayU1{0b00101010101010101010101010101010}, 15}, + {ArrayU1{0b10101010101010101010101010101010}, 16}, + {ArrayU1{0b01010101010101010101010101010101}, 16}, + {ArrayU1{0b11111111111111111111111111111111}, 32}, + {ArrayULL1{0b0000000000000000000000000000000000000000000000000000000000000000}, 0}, + {ArrayULL1{0b0010101010101010101010101010101000101010101010101010101010101010}, 30}, + {ArrayULL1{0b1010101010101010101010101010101010101010101010101010101010101010}, 32}, + {ArrayULL1{0b0101010101010101010101010101010101010101010101010101010101010101}, 32}, + {ArrayULL1{0b1111111111111111111111111111111111111111111111111111111111111111}, 64}, +}; +// clang-format on + +INSTANTIATE_TEST_CASE_P(TestBits, TestBits, ::testing::ValuesIn(inputData));