Skip to content

Instantly share code, notes, and snippets.

@Bigcheese
Last active December 17, 2015 01:38
Show Gist options
  • Save Bigcheese/5529530 to your computer and use it in GitHub Desktop.
Save Bigcheese/5529530 to your computer and use it in GitHub Desktop.
Bit hacks library API design.
#include <algorithm>
#include <cstdint>
#include <cstring>
#include <limits>
enum class zero_behaivor {
undefined,
max,
width
};
template <typename T>
std::size_t count_trailing_zeros_recurse(T val) {
return val ? 1 + count_trailing_zeros_recurse(val >> 1)
: 0;
}
template <typename T>
std::size_t count_leading_zeros(T val, zero_behaivor zb = zero_behaivor::width) noexcept {
return std::numeric_limits<T>::digits - count_trailing_zeros_recurse(val);
}
template <>
std::size_t count_leading_zeros(std::uint32_t val, zero_behaivor zb) noexcept {
return zb == zero_behaivor::width ? val == 0 ? std::numeric_limits<std::uint32_t>::digits
: __builtin_clz(val)
: __builtin_clz(val);
}
template <>
std::size_t count_leading_zeros(std::uint64_t val, zero_behaivor zb) noexcept {
return zb == zero_behaivor::width ? val == 0 ? std::numeric_limits<std::uint32_t>::digits
: __builtin_clzll(val)
: __builtin_clzll(val);
}
template <typename T>
std::size_t count_trailing_zeros(T val, zero_behaivor zb = zero_behaivor::width) noexcept {
return count_trailing_zeros_recurse(val);
}
template <>
std::size_t count_trailing_zeros(std::uint32_t val, zero_behaivor zb) noexcept {
return zb == zero_behaivor::width ? val == 0 ? std::numeric_limits<std::uint32_t>::digits
: __builtin_ctz(val)
: __builtin_ctz(val);
}
template <>
std::size_t count_trailing_zeros(std::uint64_t val, zero_behaivor zb) noexcept {
return zb == zero_behaivor::width ? val == 0 ? std::numeric_limits<std::uint32_t>::digits
: __builtin_ctzll(val)
: __builtin_ctzll(val);
}
// T must be unsigned or of user defined type.
// User defined overloads may take val as const T &.
template <typename T>
std::size_t find_first_set(T val, zero_behaivor zb = zero_behaivor::max) noexcept {
return zb == zero_behaivor::max ? val == 0 ? std::numeric_limits<T>::max()
: count_trailing_zeros(val, zero_behaivor::undefined)
: count_trailing_zeros(val, zero_behaivor::undefined);
}
template <typename T>
std::size_t find_last_set(T val, zero_behaivor zb = zero_behaivor::max) noexcept {
return zb == zero_behaivor::max ? val == 0 ? std::numeric_limits<T>::max()
: count_leading_zeros(val, zero_behaivor::undefined) ^ (std::numeric_limits<T>::digits - 1)
: count_leading_zeros(val, zero_behaivor::undefined) ^ (std::numeric_limits<T>::digits - 1);
}
template <typename T>
T reverse_bytes(T val) {
char buf[sizeof(T)];
std::memcpy(buf, &val, sizeof(T));
std::reverse(buf, buf + sizeof(T));
std::memcpy(&val, buf, sizeof(T));
return val;
}
template <>
std::uint32_t reverse_bytes(std::uint32_t val) {
return __builtin_bswap32(val);
}
template <typename T>
T reverse_bits(T val) {
return 0;
}
unsigned fls(unsigned a) {
return find_last_set(a, zero_behaivor::undefined);
}
unsigned clz(unsigned a) {
return count_leading_zeros(a);
}
unsigned clz16(std::uint16_t a) {
return count_leading_zeros(a);
}
unsigned ffs(unsigned a) {
return find_first_set(a, zero_behaivor::undefined);
}
unsigned ffs16(std::uint16_t a) {
return find_first_set(a, zero_behaivor::undefined);
}
unsigned rby(unsigned a) {
return reverse_bytes(a);
}
int main() {
int size = find_last_set<std::uint64_t>(2+4+1);
return size;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment