/// @file dpf/offset_wrapper.hpp /// @brief /// @details /// @author Ryan Henry /// @copyright Copyright (c) 2019-2024 Ryan Henry and [others](@ref authors) /// @license Released under a GNU General Public v2.0 (GPLv2) license; /// see [LICENSE.md](@ref license) for details. #ifndef LIBDPF_INCLUDE_DPF_OFFSET_WRAPPER_HPP__ #define LIBDPF_INCLUDE_DPF_OFFSET_WRAPPER_HPP__ #include "hedley/hedley.h" namespace dpf { template struct offset_wrapper final { public: using input_type = dpf::concrete_type_t; offset_wrapper(input_type = input_type{}) : offset_{} { } template HEDLEY_ALWAYS_INLINE HEDLEY_PURE HEDLEY_NO_THROW constexpr auto operator()(InputType && x) const noexcept { static_assert(std::is_convertible_v); return input_type(std::forward(x)); } HEDLEY_ALWAYS_INLINE HEDLEY_PURE HEDLEY_NO_THROW constexpr bool is_ready() const noexcept { return true; } HEDLEY_ALWAYS_INLINE HEDLEY_PURE HEDLEY_NO_THROW static constexpr bool is_wildcard() noexcept { return false; } private: input_type offset_; // waste an `input_type` to make `sizeof` match up }; template struct offset_wrapper> { public: using input_type = ConcreteInputT; offset_wrapper(input_type x) : offset_{x}, offset_state_{offset_status::notset} { } template HEDLEY_INLINE input_type operator()(InputType && x) const { static_assert(std::is_convertible_v); if (HEDLEY_UNLIKELY(offset_state_ != offset_status::ready)) { throw std::runtime_error("offset not set"); } return input_type(x) + offset_; } template const input_type & compute_and_get_share(InputType && input_share) { static_assert(std::is_convertible_v); begin_transition(offset_status::notset); offset_ -= input_share; offset_state_ = offset_status::waiting; return offset_; } template const input_type & reconstruct(InputType && other_share) { static_assert(std::is_convertible_v); begin_transition(offset_status::waiting); offset_ += other_share; offset_state_ = offset_status::ready; return offset_; } template const input_type & set(InputType && offset) { static_assert(std::is_convertible_v); begin_transition(offset_status::notset); offset_ += offset; offset_state_ = offset_status::ready; return offset_; } HEDLEY_ALWAYS_INLINE HEDLEY_NO_THROW bool is_ready() const noexcept { return offset_state_ == offset_status::ready; } HEDLEY_ALWAYS_INLINE HEDLEY_PURE HEDLEY_NO_THROW static constexpr bool is_wildcard() noexcept { return true; } private: enum class offset_status : psnip_uint8_t { ready = 0, waiting = 1, computing = 2, notset = 3 }; void begin_transition(offset_status expected) { if (HEDLEY_UNLIKELY(offset_state_ != expected)) { throw std::runtime_error("invalid state transition"); } offset_state_ = offset_status::computing; } input_type offset_; offset_status offset_state_; }; } // namespace dpf #endif // LIBDPF_INCLUDE_DPF_OFFSET_WRAPPER_HPP__