2026-09-24 14:08:32 -06:00
|
|
|
/// @file dpf/packed_lane.hpp
|
2026-09-28 05:59:19 -06:00
|
|
|
/// @brief Extract and deposit one sub-byte lane in a leaf node.
|
|
|
|
|
/// Lane 0 is the low bits of the first byte. Widths are 1
|
|
|
|
|
/// (`dpf::bit`, `dpf::gf2`), 2 (`dpf::twobit`, `dpf::gf22`), or 4
|
|
|
|
|
/// (`dpf::nyble`, `dpf::gf24`).
|
2026-09-24 14:08:32 -06:00
|
|
|
|
|
|
|
|
#ifndef LIBDPF_INCLUDE_DPF_PACKED_LANE_HPP__
|
|
|
|
|
#define LIBDPF_INCLUDE_DPF_PACKED_LANE_HPP__
|
|
|
|
|
|
|
|
|
|
#include <cassert>
|
|
|
|
|
#include <cstddef>
|
|
|
|
|
#include <cstdint>
|
2026-09-28 05:59:19 -06:00
|
|
|
#include <type_traits>
|
2026-09-24 14:08:32 -06:00
|
|
|
|
|
|
|
|
#include "hedley/hedley.h"
|
|
|
|
|
|
|
|
|
|
#include "dpf/bit.hpp"
|
|
|
|
|
#include "dpf/nyble.hpp"
|
|
|
|
|
#include "dpf/twobit.hpp"
|
|
|
|
|
|
|
|
|
|
namespace dpf
|
|
|
|
|
{
|
|
|
|
|
namespace packed
|
|
|
|
|
{
|
|
|
|
|
|
2026-09-28 05:59:19 -06:00
|
|
|
/// @brief Low bits of one lane as an unsigned integer.
|
|
|
|
|
/// @details Enums convert directly. Class lanes such as `gf2n` expose
|
|
|
|
|
/// `integral_type` and an explicit conversion to it.
|
|
|
|
|
template <typename LaneT>
|
|
|
|
|
HEDLEY_ALWAYS_INLINE
|
|
|
|
|
HEDLEY_NO_THROW
|
|
|
|
|
HEDLEY_PURE
|
|
|
|
|
constexpr unsigned lane_unsigned(LaneT value) noexcept
|
|
|
|
|
{
|
|
|
|
|
if constexpr (std::is_enum_v<LaneT> || std::is_integral_v<LaneT>)
|
|
|
|
|
return static_cast<unsigned>(value);
|
|
|
|
|
else
|
|
|
|
|
return static_cast<unsigned>(static_cast<typename LaneT::integral_type>(value));
|
|
|
|
|
}
|
|
|
|
|
|
2026-09-24 14:08:32 -06:00
|
|
|
template <typename LaneT, typename LeafT>
|
|
|
|
|
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<LaneT>;
|
|
|
|
|
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<const unsigned char *>(
|
|
|
|
|
std::addressof(leaf));
|
|
|
|
|
const std::size_t bit = lane * bits;
|
|
|
|
|
assert(bit / 8u < sizeof(LeafT));
|
|
|
|
|
const unsigned shift = static_cast<unsigned>(bit % 8u);
|
|
|
|
|
const unsigned val = (bytes[bit / 8u] >> shift) & mask;
|
|
|
|
|
return static_cast<LaneT>(val);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// @brief zero `out` is the caller's job; this writes one lane and leaves
|
|
|
|
|
/// every other lane untouched.
|
2026-09-24 23:18:10 -06:00
|
|
|
/// @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
|
2026-09-24 14:08:32 -06:00
|
|
|
template <typename LaneT, typename LeafT>
|
|
|
|
|
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<LaneT>;
|
|
|
|
|
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<unsigned char *>(std::addressof(leaf));
|
|
|
|
|
const std::size_t bit = lane * bits;
|
|
|
|
|
assert(bit / 8u < sizeof(LeafT));
|
|
|
|
|
const unsigned shift = static_cast<unsigned>(bit % 8u);
|
2026-09-28 05:59:19 -06:00
|
|
|
const unsigned val = lane_unsigned(value) & mask;
|
2026-09-24 14:08:32 -06:00
|
|
|
unsigned char & cell = bytes[bit / 8u];
|
|
|
|
|
cell = static_cast<unsigned char>((cell & ~(mask << shift)) | (val << shift));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename NodeT, typename LaneT>
|
|
|
|
|
HEDLEY_ALWAYS_INLINE
|
|
|
|
|
HEDLEY_NO_THROW
|
|
|
|
|
NodeT make_lane_node(std::size_t lane, LaneT value) noexcept
|
|
|
|
|
{
|
|
|
|
|
NodeT node{};
|
|
|
|
|
deposit_lane<LaneT>(node, lane, value);
|
|
|
|
|
return node;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace packed
|
|
|
|
|
} // namespace dpf
|
|
|
|
|
|
|
|
|
|
#endif // LIBDPF_INCLUDE_DPF_PACKED_LANE_HPP__
|