// Copyright 2018-2022 David Robillard // Copyright 2006-2007 Chris Hamilton // SPDX-License-Identifier: GPL-2.0-or-later #ifndef CHILBERT_DETAIL_OPERATIONS_HPP #define CHILBERT_DETAIL_OPERATIONS_HPP #include "chilbert/detail/traits.hpp" #include "chilbert/operators.hpp" #ifdef _MSC_VER # include # include #endif #include #include #include #include #include namespace chilbert { namespace detail { /// Reset all bits in `field` template std::enable_if_t::value> reset_bits(T& field) { field = static_cast(0); } /// Reset all bits in `field` template std::enable_if_t> reset_bits(T& field) { field.reset(); } /// Return the `index`th bit in `field` template std::enable_if_t::value, bool> test_bit(const T& field, const size_t index) { assert(size_t(index) < sizeof(field) * CHAR_BIT); return field & (T{1} << index); } /// Return the `index`th bit in `field` template std::enable_if_t, bool> test_bit(const T& field, const size_t index) { return field.test(index); } /// Set the `index`th bit in `field` template std::enable_if_t::value> set_bit(T& field, const size_t index) { assert(size_t(index) < sizeof(field) * CHAR_BIT); field |= (T{1} << index); assert(test_bit(field, index)); } /// Set the `index`th bit in `field` to `value` template std::enable_if_t::value> set_bit(T& field, const size_t index, const bool value) { assert(size_t(index) < sizeof(field) * CHAR_BIT); field ^= (-T{value} ^ field) & (T{1U} << index); assert(test_bit(field, index) == value); } /// Set the `index`th bit in `field` template std::enable_if_t> set_bit(T& field, const size_t index) { field.set(index); } /// Set the `index`th bit in `field` to `value` template std::enable_if_t> set_bit(T& field, const size_t index, const bool value) { field.set(index, value); } #ifdef _MSC_VER inline uint32_t pop_count(const uint32_t field) { return __popcnt(field); } inline uint64_t pop_count(const uint64_t field) { return __popcnt64(field); } #else /// Return 1 + the index of the least significant 1-bit of `field`, or zero template inline int pop_count(const T field); template<> inline int pop_count(const unsigned long field) { return __builtin_popcountl(field); } template<> inline int pop_count(const unsigned long long field) { return __builtin_popcountll(field); } #endif #ifdef _MSC_VER inline uint32_t find_first(const uint32_t field) { return field ? 1U + _tzcnt_u32(field) : 0U; } inline uint64_t find_first(const uint64_t field) { return field ? 1U + _tzcnt_u64(field) : 0U; } #else /// Return 1 + the index of the least significant 1-bit of `field`, or zero template inline int find_first(T field); template<> inline int find_first(const unsigned long field) { return __builtin_ffsl(static_cast(field)); } template<> inline int find_first(const unsigned long long field) { return __builtin_ffsll(static_cast(field)); } #endif /// Calculates the Gray Code of `value` in place template std::enable_if_t> gray_code(T& value); /// Implementation of grayCode for any integral type template std::enable_if_t::value> gray_code(T& value) { value ^= (value >> 1U); } /// Calculates the inverse Gray Code of `value` in place template std::enable_if_t> gray_code_inv(T& value); /// Implementation of gray_code_inv for any integral type template std::enable_if_t::value> gray_code_inv(T& value) { constexpr T shift_end = sizeof(T) * CHAR_BIT; for (T shift = 1U; shift < shift_end; shift <<= 1U) { value ^= (value >> shift); } } } // namespace detail } // namespace chilbert #endif