Commit 33b7fa2d authored by Yedidya Feldblum's avatar Yedidya Feldblum Committed by Facebook Github Bot

Smaller implementations for findFirstSet, findLastSet

Summary: [Folly] Smaller implementations for `findFirstSet`, `findLastSet`.

Reviewed By: nbronson

Differential Revision: D8471816

fbshipit-source-id: 699af98d404e6dd76df02e344d09c850abc1c32f
parent e0122b40
......@@ -60,159 +60,118 @@
#include <limits>
#include <type_traits>
#include <folly/ConstexprMath.h>
#include <folly/Portability.h>
#include <folly/Utility.h>
#include <folly/lang/Assume.h>
#include <folly/portability/Builtins.h>
namespace folly {
// Generate overloads for findFirstSet as wrappers around
// appropriate ffs, ffsl, ffsll gcc builtins
template <class T>
inline FOLLY_INTRINSIC_CONSTEXPR
typename std::enable_if<
(std::is_integral<T>::value &&
std::is_unsigned<T>::value &&
sizeof(T) <= sizeof(unsigned int)),
unsigned int>::type
findFirstSet(T x) {
return static_cast<unsigned int>(__builtin_ffs(static_cast<int>(x)));
}
template <class T>
inline FOLLY_INTRINSIC_CONSTEXPR
typename std::enable_if<
(std::is_integral<T>::value &&
std::is_unsigned<T>::value &&
sizeof(T) > sizeof(unsigned int) &&
sizeof(T) <= sizeof(unsigned long)),
unsigned int>::type
findFirstSet(T x) {
return static_cast<unsigned int>(__builtin_ffsl(static_cast<long>(x)));
}
template <class T>
inline FOLLY_INTRINSIC_CONSTEXPR
typename std::enable_if<
(std::is_integral<T>::value &&
std::is_unsigned<T>::value &&
sizeof(T) > sizeof(unsigned long) &&
sizeof(T) <= sizeof(unsigned long long)),
unsigned int>::type
findFirstSet(T x) {
return static_cast<unsigned int>(__builtin_ffsll(static_cast<long long>(x)));
namespace detail {
template <typename Dst, typename Src>
constexpr std::make_signed_t<Dst> bits_to_signed(Src const s) {
static_assert(std::is_signed<Dst>::value, "unsigned type");
return to_signed(static_cast<std::make_unsigned_t<Dst>>(to_unsigned(s)));
}
template <class T>
inline FOLLY_INTRINSIC_CONSTEXPR
typename std::enable_if<
(std::is_integral<T>::value && std::is_signed<T>::value),
unsigned int>::type
findFirstSet(T x) {
// Note that conversion from a signed type to the corresponding unsigned
// type is technically implementation-defined, but will likely work
// on any impementation that uses two's complement.
return findFirstSet(static_cast<typename std::make_unsigned<T>::type>(x));
}
// findLastSet: return the 1-based index of the highest bit set
// for x > 0, findLastSet(x) == 1 + floor(log2(x))
template <class T>
inline FOLLY_INTRINSIC_CONSTEXPR
typename std::enable_if<
(std::is_integral<T>::value &&
std::is_unsigned<T>::value &&
sizeof(T) <= sizeof(unsigned int)),
unsigned int>::type
findLastSet(T x) {
// If X is a power of two X - Y = ((X - 1) ^ Y) + 1. Doing this transformation
// allows GCC to remove its own xor that it adds to implement clz using bsr
return x ? ((8 * sizeof(unsigned int) - 1) ^ __builtin_clz(x)) + 1 : 0;
template <typename Dst, typename Src>
constexpr std::make_unsigned_t<Dst> bits_to_unsigned(Src const s) {
static_assert(std::is_unsigned<Dst>::value, "signed type");
return static_cast<Dst>(to_unsigned(s));
}
} // namespace detail
template <class T>
inline FOLLY_INTRINSIC_CONSTEXPR
typename std::enable_if<
(std::is_integral<T>::value &&
std::is_unsigned<T>::value &&
sizeof(T) > sizeof(unsigned int) &&
sizeof(T) <= sizeof(unsigned long)),
unsigned int>::type
findLastSet(T x) {
return x ? ((8 * sizeof(unsigned long) - 1) ^ __builtin_clzl(x)) + 1 : 0;
/// findFirstSet
///
/// 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>
inline FOLLY_INTRINSIC_CONSTEXPR unsigned int findFirstSet(T const v) {
using S0 = int;
using S1 = long int;
using S2 = long long int;
using detail::bits_to_signed;
static_assert(sizeof(T) <= sizeof(S2), "over-sized type");
static_assert(std::is_integral<T>::value, "non-integral type");
static_assert(!std::is_same<T, bool>::value, "bool type");
// clang-format off
return static_cast<unsigned int>(
sizeof(T) <= sizeof(S0) ? __builtin_ffs(bits_to_signed<S0>(v)) :
sizeof(T) <= sizeof(S1) ? __builtin_ffsl(bits_to_signed<S1>(v)) :
sizeof(T) <= sizeof(S2) ? __builtin_ffsll(bits_to_signed<S2>(v)) :
0);
// clang-format on
}
template <class T>
inline FOLLY_INTRINSIC_CONSTEXPR
typename std::enable_if<
(std::is_integral<T>::value &&
std::is_unsigned<T>::value &&
sizeof(T) > sizeof(unsigned long) &&
sizeof(T) <= sizeof(unsigned long long)),
unsigned int>::type
findLastSet(T x) {
return x ? ((8 * sizeof(unsigned long long) - 1) ^ __builtin_clzll(x)) + 1
: 0;
/// findLastSet
///
/// Return the 1-based index of the most significant bit which is set.
/// For x > 0, findLastSet(x) == 1 + floor(log2(x)).
template <typename T>
inline FOLLY_INTRINSIC_CONSTEXPR unsigned int findLastSet(T const v) {
using U0 = unsigned int;
using U1 = unsigned long int;
using U2 = unsigned long long int;
using detail::bits_to_unsigned;
static_assert(sizeof(T) <= sizeof(U2), "over-sized type");
static_assert(std::is_integral<T>::value, "non-integral type");
static_assert(!std::is_same<T, bool>::value, "bool type");
// If X is a power of two X - Y = 1 + ((X - 1) ^ Y). Doing this transformation
// allows GCC to remove its own xor that it adds to implement clz using bsr.
// clang-format off
using size = index_constant<constexpr_max(sizeof(T), sizeof(U0))>;
return v ? 1u + ((8u * size{} - 1u) ^ static_cast<unsigned int>(
sizeof(T) <= sizeof(U0) ? __builtin_clz(bits_to_unsigned<U1>(v)) :
sizeof(T) <= sizeof(U1) ? __builtin_clzl(bits_to_unsigned<U1>(v)) :
sizeof(T) <= sizeof(U2) ? __builtin_clzll(bits_to_unsigned<U2>(v)) :
0)) : 0u;
// clang-format on
}
template <class T>
inline FOLLY_INTRINSIC_CONSTEXPR
typename std::enable_if<
(std::is_integral<T>::value &&
std::is_signed<T>::value),
unsigned int>::type
findLastSet(T x) {
return findLastSet(static_cast<typename std::make_unsigned<T>::type>(x));
/// popcount
///
/// Returns the number of bits which are set.
template <typename T>
inline FOLLY_INTRINSIC_CONSTEXPR unsigned int popcount(T const v) {
using U0 = unsigned int;
using U1 = unsigned long int;
using U2 = unsigned long long int;
using detail::bits_to_unsigned;
static_assert(sizeof(T) <= sizeof(U2), "over-sized type");
static_assert(std::is_integral<T>::value, "non-integral type");
static_assert(!std::is_same<T, bool>::value, "bool type");
// clang-format off
return static_cast<unsigned int>(
sizeof(T) <= sizeof(U0) ? __builtin_popcount(bits_to_unsigned<U1>(v)) :
sizeof(T) <= sizeof(U1) ? __builtin_popcountl(bits_to_unsigned<U1>(v)) :
sizeof(T) <= sizeof(U2) ? __builtin_popcountll(bits_to_unsigned<U2>(v)) :
0);
// clang-format on
}
template <class T>
inline FOLLY_INTRINSIC_CONSTEXPR
typename std::enable_if<
std::is_integral<T>::value && std::is_unsigned<T>::value,
T>::type
nextPowTwo(T v) {
return v ? (T(1) << findLastSet(v - 1)) : 1;
inline FOLLY_INTRINSIC_CONSTEXPR T nextPowTwo(T const v) {
static_assert(std::is_unsigned<T>::value, "signed type");
return v ? (T(1) << findLastSet(v - 1)) : T(1);
}
template <class T>
inline FOLLY_INTRINSIC_CONSTEXPR typename std::
enable_if<std::is_integral<T>::value && std::is_unsigned<T>::value, T>::type
prevPowTwo(T v) {
return v ? (T(1) << (findLastSet(v) - 1)) : 0;
inline FOLLY_INTRINSIC_CONSTEXPR T prevPowTwo(T const v) {
static_assert(std::is_unsigned<T>::value, "signed type");
return v ? (T(1) << (findLastSet(v) - 1)) : T(0);
}
template <class T>
inline constexpr typename std::enable_if<
std::is_integral<T>::value && std::is_unsigned<T>::value,
bool>::type
isPowTwo(T v) {
inline constexpr bool isPowTwo(T const v) {
static_assert(std::is_integral<T>::value, "non-integral type");
static_assert(std::is_unsigned<T>::value, "signed type");
static_assert(!std::is_same<T, bool>::value, "bool type");
return (v != 0) && !(v & (v - 1));
}
/**
* Population count
*/
template <class T>
inline typename std::enable_if<
(std::is_integral<T>::value &&
std::is_unsigned<T>::value &&
sizeof(T) <= sizeof(unsigned int)),
size_t>::type
popcount(T x) {
return size_t(__builtin_popcount(x));
}
template <class T>
inline typename std::enable_if<
(std::is_integral<T>::value &&
std::is_unsigned<T>::value &&
sizeof(T) > sizeof(unsigned int) &&
sizeof(T) <= sizeof(unsigned long long)),
size_t>::type
popcount(T x) {
return size_t(__builtin_popcountll(x));
}
/**
* Endianness detection and manipulation primitives.
*/
......
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