Commit 09d75f08 authored by Yedidya Feldblum's avatar Yedidya Feldblum Committed by Facebook Github Bot

constexpr_find_first_set, constexpr_find_last_set

Summary: [Folly] `constexpr_find_first_set`, `constexpr_find_last_set`; with an application into `F14Table`.

Reviewed By: nbronson

Differential Revision: D8529579

fbshipit-source-id: 90d02215001abf1ffb3f04550eda22021263bbb1
parent fd346480
......@@ -180,6 +180,39 @@ constexpr T constexpr_pow(T base, std::size_t exp) {
(exp % 2 ? base : T(1));
}
/// constexpr_find_last_set
///
/// Return the 1-based index of the most significant bit which is set.
/// For x > 0, constexpr_find_last_set(x) == 1 + floor(log2(x)).
template <typename T>
constexpr std::size_t constexpr_find_last_set(T const t) {
using U = std::make_unsigned_t<T>;
return t == T(0) ? 0 : 1 + constexpr_log2(static_cast<U>(t));
}
namespace detail {
template <typename U>
constexpr std::size_t
constexpr_find_first_set_(std::size_t s, std::size_t a, U const u) {
return s == 0 ? a
: constexpr_find_first_set_(
s / 2, a + s * bool((u >> a) % (U(1) << s) == U(0)), u);
}
} // namespace detail
/// constexpr_find_first_set
///
/// Return the 1-based index of the least significant bit which is set.
/// For x > 0, the exponent in the largest power of two which does not divide x.
template <typename T>
constexpr std::size_t constexpr_find_first_set(T t) {
using U = std::make_unsigned_t<T>;
using size = std::integral_constant<std::size_t, sizeof(T) * 4>;
return t == T(0)
? 0
: 1 + detail::constexpr_find_first_set_(size{}, 0, static_cast<U>(t));
}
template <typename T>
constexpr T constexpr_add_overflow_clamped(T a, T b) {
using L = std::numeric_limits<T>;
......
......@@ -30,6 +30,7 @@
#include <vector>
#include <folly/Bits.h>
#include <folly/ConstexprMath.h>
#include <folly/Likely.h>
#include <folly/Portability.h>
#include <folly/ScopeGuard.h>
......@@ -726,11 +727,10 @@ class PackedChunkItemPtr<T*> {
static constexpr uintptr_t kIndexBits = 4;
static constexpr uintptr_t kIndexMask = (uintptr_t{1} << kIndexBits) - 1;
static constexpr uintptr_t kAlignBits = (sizeof(T) % 16) == 0
? 4
: (sizeof(T) % 8) == 0
? 3
: (sizeof(T) % 4) == 0 ? 2 : (sizeof(T) % 2) == 0 ? 1 : 0;
static constexpr uintptr_t kAlignBits = constexpr_min(
uintptr_t{4},
constexpr_find_first_set(uintptr_t{sizeof(T)}) - 1);
static constexpr uintptr_t kAlignMask = (uintptr_t{1} << kAlignBits) - 1;
static constexpr uintptr_t kModulus = uintptr_t{1}
......
......@@ -16,10 +16,12 @@
#include <folly/ConstexprMath.h>
#include <folly/portability/GTest.h>
#include <limits>
#include <type_traits>
#include <folly/lang/Bits.h>
#include <folly/portability/GTest.h>
namespace {
class ConstexprMathTest : public testing::Test {};
} // namespace
......@@ -195,6 +197,73 @@ TEST_F(ConstexprMathTest, constexpr_pow) {
}
}
TEST_F(ConstexprMathTest, constexpr_find_last_set_examples) {
{
constexpr auto a = folly::constexpr_find_last_set(int64_t(0));
EXPECT_EQ(0, a);
}
{
constexpr auto a = folly::constexpr_find_last_set(int64_t(2));
EXPECT_EQ(2, a);
}
{
constexpr auto a = folly::constexpr_find_last_set(int64_t(4096 + 64));
EXPECT_EQ(13, a);
}
}
TEST_F(ConstexprMathTest, constexpr_find_last_set_all_64_adjacents) {
using type = uint64_t;
constexpr auto const bits = std::numeric_limits<type>::digits;
EXPECT_EQ(0, folly::constexpr_find_last_set(type(0)));
for (size_t i = 0; i < bits; ++i) {
type const v = type(1) << i;
EXPECT_EQ(i + 1, folly::constexpr_find_last_set(v));
EXPECT_EQ(i, folly::constexpr_find_last_set((v - 1)));
}
}
TEST_F(ConstexprMathTest, constexpr_find_last_set_all_8_reference) {
using type = char;
for (size_t i = 0; i < 256u; ++i) {
auto const expected = folly::findLastSet(type(i));
EXPECT_EQ(expected, folly::constexpr_find_last_set(type(i)));
}
}
TEST_F(ConstexprMathTest, constexpr_find_first_set_examples) {
{
constexpr auto a = folly::constexpr_find_first_set(int64_t(0));
EXPECT_EQ(0, a);
}
{
constexpr auto a = folly::constexpr_find_first_set(int64_t(2));
EXPECT_EQ(2, a);
}
{
constexpr auto a = folly::constexpr_find_first_set(int64_t(4096 + 64));
EXPECT_EQ(7, a);
}
}
TEST_F(ConstexprMathTest, constexpr_find_first_set_all_64_adjacent) {
using type = uint64_t;
constexpr auto const bits = std::numeric_limits<type>::digits;
EXPECT_EQ(0, folly::constexpr_find_first_set(type(0)));
for (size_t i = 0; i < bits; ++i) {
type const v = (type(1) << (bits - 1)) | (type(1) << i);
EXPECT_EQ(i + 1, folly::constexpr_find_first_set(v));
}
}
TEST_F(ConstexprMathTest, constexpr_find_first_set_all_8_reference) {
using type = char;
for (size_t i = 0; i < 256u; ++i) {
auto const expected = folly::findFirstSet(type(i));
EXPECT_EQ(expected, folly::constexpr_find_first_set(type(i)));
}
}
constexpr auto kInt64Max = std::numeric_limits<int64_t>::max();
constexpr auto kInt64Min = std::numeric_limits<int64_t>::min();
constexpr auto kUInt64Max = std::numeric_limits<uint64_t>::max();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment