Last active
December 17, 2015 01:38
-
-
Save Bigcheese/5529530 to your computer and use it in GitHub Desktop.
Bit hacks library API design.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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