2026-09-24 14:08:32 -06:00
|
|
|
/// @file dpf/twobit.hpp
|
|
|
|
|
/// @brief `dpf::twobit`, a 2-bit output lane in the ring Z/4Z.
|
|
|
|
|
/// @details Values are `0..3`. Scalar `+` and `-` wrap mod 4. A leaf node
|
|
|
|
|
/// packs one lane every two bits, low lane in the low bits of the
|
|
|
|
|
/// first byte, matching `dpf::bit`. Leaf addition is not XOR: a
|
|
|
|
|
/// carry stays inside the 2-bit lane. See `packed_lane_arithmetic.hpp`.
|
2026-09-24 23:18:10 -06:00
|
|
|
/// @see packed_lane_arithmetic.hpp
|
2026-09-24 14:08:32 -06:00
|
|
|
|
|
|
|
|
#ifndef LIBDPF_INCLUDE_DPF_TWOBIT_HPP__
|
|
|
|
|
#define LIBDPF_INCLUDE_DPF_TWOBIT_HPP__
|
|
|
|
|
|
|
|
|
|
#include <cstddef>
|
|
|
|
|
#include <cstdint>
|
|
|
|
|
#include <istream>
|
|
|
|
|
#include <limits>
|
|
|
|
|
#include <ostream>
|
|
|
|
|
#include <stdexcept>
|
|
|
|
|
#include <string>
|
|
|
|
|
#include <type_traits>
|
|
|
|
|
|
|
|
|
|
#include "hedley/hedley.h"
|
|
|
|
|
|
|
|
|
|
#include "dpf/utils.hpp"
|
|
|
|
|
|
|
|
|
|
namespace dpf
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
/// @brief 2-bit unsigned ring element, packed two bits per lane
|
|
|
|
|
enum class twobit : std::uint8_t
|
|
|
|
|
{
|
|
|
|
|
zero = 0,
|
|
|
|
|
one = 1,
|
|
|
|
|
two = 2,
|
|
|
|
|
three = 3
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
HEDLEY_CONST
|
|
|
|
|
HEDLEY_NO_THROW
|
|
|
|
|
HEDLEY_ALWAYS_INLINE
|
|
|
|
|
static constexpr dpf::twobit to_twobit(unsigned value) noexcept
|
|
|
|
|
{
|
|
|
|
|
return static_cast<dpf::twobit>(value & 3u);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HEDLEY_CONST
|
|
|
|
|
HEDLEY_NO_THROW
|
|
|
|
|
HEDLEY_ALWAYS_INLINE
|
|
|
|
|
static constexpr dpf::twobit to_twobit(unsigned long long value) noexcept
|
|
|
|
|
{
|
|
|
|
|
return static_cast<dpf::twobit>(value & 3ull);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// @brief parse one character as a 2-bit digit
|
2026-09-24 23:18:10 -06:00
|
|
|
/// @tparam CharT character type
|
2026-09-24 14:08:32 -06:00
|
|
|
/// @param zero character for 0 (default `'0'`)
|
2026-09-24 23:18:10 -06:00
|
|
|
/// @param value the value to convert or store
|
|
|
|
|
/// @return the returned `dpf::twobit`
|
2026-09-24 14:08:32 -06:00
|
|
|
/// @throws std::domain_error if `value` is not one of the four digits
|
|
|
|
|
template <typename CharT>
|
|
|
|
|
HEDLEY_ALWAYS_INLINE
|
|
|
|
|
static constexpr dpf::twobit to_twobit(CharT value, CharT zero = CharT('0'))
|
|
|
|
|
{
|
|
|
|
|
auto delta = static_cast<unsigned>(value) - static_cast<unsigned>(zero);
|
|
|
|
|
if (delta > 3u)
|
|
|
|
|
{
|
|
|
|
|
throw std::domain_error("Unrecognized twobit character");
|
|
|
|
|
}
|
|
|
|
|
return static_cast<dpf::twobit>(delta);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline std::string to_string(dpf::twobit value)
|
|
|
|
|
{
|
|
|
|
|
return std::string(1, static_cast<char>('0' + static_cast<unsigned>(value)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename CharT, typename Traits>
|
|
|
|
|
std::basic_ostream<CharT, Traits> &
|
|
|
|
|
operator<<(std::basic_ostream<CharT, Traits> & os, dpf::twobit value)
|
|
|
|
|
{
|
|
|
|
|
return os << static_cast<char>('0' + static_cast<unsigned>(value));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename CharT, typename Traits>
|
|
|
|
|
std::basic_istream<CharT, Traits> &
|
|
|
|
|
operator>>(std::basic_istream<CharT, Traits> & is, dpf::twobit & value)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
value = to_twobit<CharT>(is.get(), is.widen('0'));
|
|
|
|
|
}
|
|
|
|
|
catch (const std::exception &)
|
|
|
|
|
{
|
|
|
|
|
is.setstate(std::ios::failbit);
|
|
|
|
|
}
|
|
|
|
|
return is;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// @brief addition in Z/4Z
|
2026-09-24 23:18:10 -06:00
|
|
|
/// @param lhs the left-hand operand
|
|
|
|
|
/// @param rhs the right-hand operand
|
|
|
|
|
/// @return addition in Z/4Z
|
2026-09-24 14:08:32 -06:00
|
|
|
HEDLEY_CONST
|
|
|
|
|
HEDLEY_NO_THROW
|
|
|
|
|
HEDLEY_ALWAYS_INLINE
|
|
|
|
|
constexpr dpf::twobit operator+(dpf::twobit lhs, dpf::twobit rhs) noexcept
|
|
|
|
|
{
|
|
|
|
|
return static_cast<dpf::twobit>(
|
|
|
|
|
(static_cast<unsigned>(lhs) + static_cast<unsigned>(rhs)) & 3u);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// @brief subtraction in Z/4Z
|
2026-09-24 23:18:10 -06:00
|
|
|
/// @param lhs the left-hand operand
|
|
|
|
|
/// @param rhs the right-hand operand
|
|
|
|
|
/// @return subtraction in Z/4Z
|
2026-09-24 14:08:32 -06:00
|
|
|
HEDLEY_CONST
|
|
|
|
|
HEDLEY_NO_THROW
|
|
|
|
|
HEDLEY_ALWAYS_INLINE
|
|
|
|
|
constexpr dpf::twobit operator-(dpf::twobit lhs, dpf::twobit rhs) noexcept
|
|
|
|
|
{
|
|
|
|
|
return static_cast<dpf::twobit>(
|
|
|
|
|
(static_cast<unsigned>(lhs) - static_cast<unsigned>(rhs)) & 3u);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// @brief additive inverse in Z/4Z
|
2026-09-24 23:18:10 -06:00
|
|
|
/// @param value the value to convert or store
|
|
|
|
|
/// @return additive inverse in Z/4Z
|
2026-09-24 14:08:32 -06:00
|
|
|
HEDLEY_CONST
|
|
|
|
|
HEDLEY_NO_THROW
|
|
|
|
|
HEDLEY_ALWAYS_INLINE
|
|
|
|
|
constexpr dpf::twobit operator-(dpf::twobit value) noexcept
|
|
|
|
|
{
|
|
|
|
|
return static_cast<dpf::twobit>((0u - static_cast<unsigned>(value)) & 3u);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// @brief multiplication in Z/4Z
|
2026-09-24 23:18:10 -06:00
|
|
|
/// @param lhs the left-hand operand
|
|
|
|
|
/// @param rhs the right-hand operand
|
|
|
|
|
/// @return multiplication in Z/4Z
|
2026-09-24 14:08:32 -06:00
|
|
|
HEDLEY_CONST
|
|
|
|
|
HEDLEY_NO_THROW
|
|
|
|
|
HEDLEY_ALWAYS_INLINE
|
|
|
|
|
constexpr dpf::twobit operator*(dpf::twobit lhs, dpf::twobit rhs) noexcept
|
|
|
|
|
{
|
|
|
|
|
return static_cast<dpf::twobit>(
|
|
|
|
|
(static_cast<unsigned>(lhs) * static_cast<unsigned>(rhs)) & 3u);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
namespace utils
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
template <>
|
|
|
|
|
struct bitlength_of<dpf::twobit>
|
|
|
|
|
: public std::integral_constant<std::size_t, 2> {};
|
|
|
|
|
|
|
|
|
|
template <typename NodeT>
|
|
|
|
|
struct bitlength_of_output<dpf::twobit, NodeT>
|
|
|
|
|
: public std::integral_constant<std::size_t, 2> {};
|
|
|
|
|
|
|
|
|
|
template <>
|
|
|
|
|
struct is_packed_subbyte<dpf::twobit> : std::true_type {};
|
|
|
|
|
|
|
|
|
|
template <>
|
|
|
|
|
struct packed_lane_bits<dpf::twobit>
|
|
|
|
|
: public std::integral_constant<std::size_t, 2> {};
|
|
|
|
|
|
|
|
|
|
template <>
|
|
|
|
|
struct make_from_integral_value<dpf::twobit>
|
|
|
|
|
{
|
|
|
|
|
using integral_type = std::uint8_t;
|
2026-09-24 20:44:07 -06:00
|
|
|
HEDLEY_NO_THROW
|
2026-09-24 14:08:32 -06:00
|
|
|
constexpr dpf::twobit operator()(integral_type val) const noexcept
|
|
|
|
|
{
|
|
|
|
|
return dpf::to_twobit(val);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
} // namespace utils
|
|
|
|
|
|
|
|
|
|
namespace literals
|
|
|
|
|
{
|
|
|
|
|
namespace twobit
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
constexpr dpf::twobit operator""_twobit(unsigned long long x)
|
|
|
|
|
{
|
|
|
|
|
return dpf::to_twobit(x);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace twobit
|
|
|
|
|
} // namespace literals
|
|
|
|
|
|
|
|
|
|
} // namespace dpf
|
|
|
|
|
|
|
|
|
|
namespace std
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
template <>
|
|
|
|
|
class numeric_limits<dpf::twobit> : public numeric_limits<std::uint8_t>
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
static constexpr int digits = 2;
|
|
|
|
|
static constexpr int digits10 = 0;
|
2026-09-24 20:44:07 -06:00
|
|
|
HEDLEY_NO_THROW
|
2026-09-24 14:08:32 -06:00
|
|
|
static constexpr dpf::twobit min() noexcept { return dpf::twobit::zero; }
|
2026-09-24 20:44:07 -06:00
|
|
|
HEDLEY_NO_THROW
|
2026-09-24 14:08:32 -06:00
|
|
|
static constexpr dpf::twobit max() noexcept { return dpf::twobit::three; }
|
2026-09-24 20:44:07 -06:00
|
|
|
HEDLEY_NO_THROW
|
2026-09-24 14:08:32 -06:00
|
|
|
static constexpr dpf::twobit lowest() noexcept { return min(); }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template <>
|
|
|
|
|
class numeric_limits<dpf::twobit const> : public numeric_limits<dpf::twobit> {};
|
|
|
|
|
|
|
|
|
|
template <>
|
|
|
|
|
class numeric_limits<dpf::twobit volatile> : public numeric_limits<dpf::twobit> {};
|
|
|
|
|
|
|
|
|
|
template <>
|
|
|
|
|
class numeric_limits<dpf::twobit const volatile>
|
|
|
|
|
: public numeric_limits<dpf::twobit> {};
|
|
|
|
|
|
|
|
|
|
} // namespace std
|
|
|
|
|
|
|
|
|
|
#endif // LIBDPF_INCLUDE_DPF_TWOBIT_HPP__
|