/// @file dpf/packed_lane.hpp /// @brief Extract and deposit one `dpf::bit`, `dpf::twobit`, or `dpf::nyble` /// lane in a leaf node. Lane 0 is the low bits of the first byte. #ifndef LIBDPF_INCLUDE_DPF_PACKED_LANE_HPP__ #define LIBDPF_INCLUDE_DPF_PACKED_LANE_HPP__ #include #include #include #include "hedley/hedley.h" #include "dpf/bit.hpp" #include "dpf/nyble.hpp" #include "dpf/twobit.hpp" namespace dpf { namespace packed { template HEDLEY_ALWAYS_INLINE HEDLEY_NO_THROW HEDLEY_PURE LaneT extract_lane(const LeafT & leaf, std::size_t lane) noexcept { constexpr unsigned bits = utils::packed_lane_bits_v; static_assert(bits == 1 || bits == 2 || bits == 4, "packed lane width must be 1, 2, or 4"); constexpr unsigned mask = (1u << bits) - 1u; const auto * bytes = reinterpret_cast( std::addressof(leaf)); const std::size_t bit = lane * bits; assert(bit / 8u < sizeof(LeafT)); const unsigned shift = static_cast(bit % 8u); const unsigned val = (bytes[bit / 8u] >> shift) & mask; return static_cast(val); } /// @brief zero `out` is the caller's job; this writes one lane and leaves /// every other lane untouched. /// @tparam LaneT lane type /// @tparam LeafT leaf type /// @param leaf the leaf value /// @param lane the lane index or lane value /// @param value the value to convert or store template HEDLEY_ALWAYS_INLINE HEDLEY_NO_THROW void deposit_lane(LeafT & leaf, std::size_t lane, LaneT value) noexcept { constexpr unsigned bits = utils::packed_lane_bits_v; static_assert(bits == 1 || bits == 2 || bits == 4, "packed lane width must be 1, 2, or 4"); constexpr unsigned mask = (1u << bits) - 1u; auto * bytes = reinterpret_cast(std::addressof(leaf)); const std::size_t bit = lane * bits; assert(bit / 8u < sizeof(LeafT)); const unsigned shift = static_cast(bit % 8u); const unsigned val = static_cast(value) & mask; unsigned char & cell = bytes[bit / 8u]; cell = static_cast((cell & ~(mask << shift)) | (val << shift)); } template HEDLEY_ALWAYS_INLINE HEDLEY_NO_THROW NodeT make_lane_node(std::size_t lane, LaneT value) noexcept { NodeT node{}; deposit_lane(node, lane, value); return node; } } // namespace packed } // namespace dpf #endif // LIBDPF_INCLUDE_DPF_PACKED_LANE_HPP__