style: use tab replace spaces
every one could change the length of tab but not of space
This commit is contained in:
@ -1,50 +1,50 @@
|
||||
#pragma once
|
||||
#include "concept.h"
|
||||
#include "debug.h"
|
||||
#include <version>
|
||||
#include <climits>
|
||||
#include <concepts>
|
||||
#include <version>
|
||||
|
||||
namespace dark {
|
||||
|
||||
template <std::size_t _Nm>
|
||||
template<std::size_t _Nm>
|
||||
struct Bit {
|
||||
private:
|
||||
static_assert(0 < _Nm && _Nm <= kMaxLength,
|
||||
"Bit: _Nm out of range. Should be in [1, kMaxLength]");
|
||||
|
||||
max_size_t _M_data : _Nm; // Real storage
|
||||
private:
|
||||
static_assert(0 < _Nm && _Nm <= kMaxLength,
|
||||
"Bit: _Nm out of range. Should be in [1, kMaxLength]");
|
||||
|
||||
template <std::size_t _Hi, std::size_t _Lo>
|
||||
static constexpr void _M_range_check();
|
||||
max_size_t _M_data : _Nm; // Real storage
|
||||
|
||||
public:
|
||||
static constexpr std::size_t _Bit_Len = _Nm;
|
||||
template<std::size_t _Hi, std::size_t _Lo>
|
||||
static constexpr void _M_range_check();
|
||||
|
||||
constexpr Bit(max_size_t data = 0) : _M_data(data) {}
|
||||
public:
|
||||
static constexpr std::size_t _Bit_Len = _Nm;
|
||||
|
||||
constexpr explicit operator max_size_t() const { return this->_M_data; }
|
||||
constexpr Bit(max_size_t data = 0) : _M_data(data) {}
|
||||
|
||||
template <concepts::bit_type ..._Tp>
|
||||
requires ((_Tp::_Bit_Len + ...) == _Nm)
|
||||
constexpr Bit(const _Tp &...args);
|
||||
constexpr explicit operator max_size_t() const { return this->_M_data; }
|
||||
|
||||
template <concepts::bit_convertible <_Nm> _Tp>
|
||||
constexpr Bit &operator=(const _Tp &val);
|
||||
template<concepts::bit_type... _Tp>
|
||||
requires((_Tp::_Bit_Len + ...) == _Nm)
|
||||
constexpr Bit(const _Tp &...args);
|
||||
|
||||
template <std::size_t _Hi, std::size_t _Lo = _Hi, concepts::bit_convertible <_Nm> _Tp>
|
||||
constexpr void set(const _Tp &val);
|
||||
template<concepts::bit_convertible<_Nm> _Tp>
|
||||
constexpr Bit &operator=(const _Tp &val);
|
||||
|
||||
template <std::size_t _Hi, std::size_t _Lo = _Hi>
|
||||
constexpr auto range() const -> Bit <_Hi - _Lo + 1>;
|
||||
template<std::size_t _Hi, std::size_t _Lo = _Hi, concepts::bit_convertible<_Nm> _Tp>
|
||||
constexpr void set(const _Tp &val);
|
||||
|
||||
template <std::size_t _Len = 1>
|
||||
constexpr auto slice(std::size_t pos) const -> Bit <_Len>;
|
||||
template<std::size_t _Hi, std::size_t _Lo = _Hi>
|
||||
constexpr auto range() const -> Bit<_Hi - _Lo + 1>;
|
||||
|
||||
constexpr Bit <1> operator [](std::size_t pos) const { return this->slice(pos); }
|
||||
template<std::size_t _Len = 1>
|
||||
constexpr auto slice(std::size_t pos) const -> Bit<_Len>;
|
||||
|
||||
constexpr Bit<1> operator[](std::size_t pos) const { return this->slice(pos); }
|
||||
};
|
||||
|
||||
template <concepts::bit_type ..._Tp>
|
||||
template<concepts::bit_type... _Tp>
|
||||
Bit(_Tp...) -> Bit<(_Tp::_Bit_Len + ...)>;
|
||||
|
||||
} // namespace dark
|
||||
|
@ -3,84 +3,87 @@
|
||||
|
||||
namespace dark {
|
||||
|
||||
template <int _First>
|
||||
template<int _First>
|
||||
constexpr auto int_concat(max_size_t arg) { return arg; }
|
||||
|
||||
template <int _First, int ..._Lens>
|
||||
constexpr auto int_concat(max_size_t arg, auto ...args) {
|
||||
return (arg << (_Lens + ...)) | int_concat<_Lens...>(args...);
|
||||
template<int _First, int... _Lens>
|
||||
constexpr auto int_concat(max_size_t arg, auto... args) {
|
||||
return (arg << (_Lens + ...)) | int_concat<_Lens...>(args...);
|
||||
}
|
||||
|
||||
template <std::size_t _Old, std::size_t _New = kMaxLength>
|
||||
template<std::size_t _Old, std::size_t _New = kMaxLength>
|
||||
constexpr auto sign_extend(max_size_t val) {
|
||||
static_assert(_Old < _New, "sign_extend: _Old should be less than _New");
|
||||
struct { max_ssize_t _M_data : _Old; } tmp;
|
||||
return Bit<_New>(tmp._M_data = val);
|
||||
static_assert(_Old < _New, "sign_extend: _Old should be less than _New");
|
||||
struct {
|
||||
max_ssize_t _M_data : _Old;
|
||||
} tmp;
|
||||
return Bit<_New>(tmp._M_data = val);
|
||||
}
|
||||
|
||||
template <std::size_t _New = kMaxLength, concepts::bit_type _Tp>
|
||||
constexpr auto sign_extend(const _Tp & val) {
|
||||
return sign_extend<_Tp::_Bit_Len, _New>(static_cast<max_size_t>(val));
|
||||
template<std::size_t _New = kMaxLength, concepts::bit_type _Tp>
|
||||
constexpr auto sign_extend(const _Tp &val) {
|
||||
return sign_extend<_Tp::_Bit_Len, _New>(static_cast<max_size_t>(val));
|
||||
}
|
||||
|
||||
template <std::size_t _Old, std::size_t _New = kMaxLength>
|
||||
template<std::size_t _Old, std::size_t _New = kMaxLength>
|
||||
constexpr auto zero_extend(max_size_t val) {
|
||||
static_assert(_Old < _New, "zero_extend: _Old should be less than _New");
|
||||
struct { max_size_t _M_data : _Old; } tmp;
|
||||
return Bit<_New>(tmp._M_data = val);
|
||||
static_assert(_Old < _New, "zero_extend: _Old should be less than _New");
|
||||
struct {
|
||||
max_size_t _M_data : _Old;
|
||||
} tmp;
|
||||
return Bit<_New>(tmp._M_data = val);
|
||||
}
|
||||
|
||||
template <std::size_t _New = kMaxLength, concepts::bit_type _Tp>
|
||||
template<std::size_t _New = kMaxLength, concepts::bit_type _Tp>
|
||||
constexpr auto zero_extend(const _Tp &val) {
|
||||
return zero_extend<_Tp::_Bit_Len, _New>(static_cast<max_size_t>(val));
|
||||
return zero_extend<_Tp::_Bit_Len, _New>(static_cast<max_size_t>(val));
|
||||
}
|
||||
|
||||
template <std::size_t _Nm>
|
||||
template <concepts::bit_type ..._Tp>
|
||||
requires ((_Tp::_Bit_Len + ...) == _Nm)
|
||||
template<std::size_t _Nm>
|
||||
template<concepts::bit_type... _Tp>
|
||||
requires((_Tp::_Bit_Len + ...) == _Nm)
|
||||
constexpr Bit<_Nm>::Bit(const _Tp &...args)
|
||||
: _M_data(int_concat<_Tp::_Bit_Len...>(static_cast<max_size_t>(args)...)) {}
|
||||
: _M_data(int_concat<_Tp::_Bit_Len...>(static_cast<max_size_t>(args)...)) {}
|
||||
|
||||
template <std::size_t _Nm>
|
||||
template <concepts::bit_convertible <_Nm> _Tp>
|
||||
template<std::size_t _Nm>
|
||||
template<concepts::bit_convertible<_Nm> _Tp>
|
||||
constexpr Bit<_Nm> &Bit<_Nm>::operator=(const _Tp &val) {
|
||||
this->_M_data = static_cast<max_size_t>(val);
|
||||
return *this;
|
||||
this->_M_data = static_cast<max_size_t>(val);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <std::size_t _Nm>
|
||||
template <std::size_t _Hi, std::size_t _Lo>
|
||||
template<std::size_t _Nm>
|
||||
template<std::size_t _Hi, std::size_t _Lo>
|
||||
constexpr void Bit<_Nm>::_M_range_check() {
|
||||
static_assert(_Lo <= _Hi, "Bit::range_check: _Lo should be no greater than _Hi");
|
||||
static_assert(_Hi < _Nm, "Bit::range_check: _Hi should be less than _Nm");
|
||||
static_assert(_Lo <= _Hi, "Bit::range_check: _Lo should be no greater than _Hi");
|
||||
static_assert(_Hi < _Nm, "Bit::range_check: _Hi should be less than _Nm");
|
||||
}
|
||||
|
||||
template <std::size_t _Nm>
|
||||
template <std::size_t _Hi, std::size_t _Lo, concepts::bit_convertible <_Nm> _Tp>
|
||||
template<std::size_t _Nm>
|
||||
template<std::size_t _Hi, std::size_t _Lo, concepts::bit_convertible<_Nm> _Tp>
|
||||
constexpr void Bit<_Nm>::set(const _Tp &val) {
|
||||
this->_M_range_check<_Hi, _Lo>();
|
||||
auto data = static_cast<max_size_t>(val);
|
||||
constexpr auto _Length = _Hi - _Lo + 1;
|
||||
auto mask = make_mask<_Length> << _Lo;
|
||||
this->_M_data = (this->_M_data & ~mask) | ((data << _Lo) & mask);
|
||||
this->_M_range_check<_Hi, _Lo>();
|
||||
auto data = static_cast<max_size_t>(val);
|
||||
constexpr auto _Length = _Hi - _Lo + 1;
|
||||
auto mask = make_mask<_Length> << _Lo;
|
||||
this->_M_data = (this->_M_data & ~mask) | ((data << _Lo) & mask);
|
||||
}
|
||||
|
||||
template <std::size_t _Nm>
|
||||
template <std::size_t _Hi, std::size_t _Lo>
|
||||
constexpr auto Bit<_Nm>::range() const -> Bit <_Hi - _Lo + 1> {
|
||||
this->_M_range_check<_Hi, _Lo>();
|
||||
constexpr auto _Length = _Hi - _Lo + 1;
|
||||
return Bit<_Length>(this->_M_data >> _Lo);
|
||||
template<std::size_t _Nm>
|
||||
template<std::size_t _Hi, std::size_t _Lo>
|
||||
constexpr auto Bit<_Nm>::range() const -> Bit<_Hi - _Lo + 1> {
|
||||
this->_M_range_check<_Hi, _Lo>();
|
||||
constexpr auto _Length = _Hi - _Lo + 1;
|
||||
return Bit<_Length>(this->_M_data >> _Lo);
|
||||
}
|
||||
|
||||
template <std::size_t _Nm>
|
||||
template <std::size_t _Len>
|
||||
constexpr auto Bit<_Nm>::slice(std::size_t pos) const -> Bit <_Len> {
|
||||
static_assert(_Len <= _Nm, "Bit::slice: _Len should be no greater than _Nm");
|
||||
debug::assert(pos <= _Nm - _Len, "Bit::slice: pos should be less than _Nm - _Len");
|
||||
return Bit<_Len>(this->_M_data >> pos);
|
||||
template<std::size_t _Nm>
|
||||
template<std::size_t _Len>
|
||||
constexpr auto Bit<_Nm>::slice(std::size_t pos) const -> Bit<_Len> {
|
||||
static_assert(_Len <= _Nm, "Bit::slice: _Len should be no greater than _Nm");
|
||||
debug::assert(pos <= _Nm - _Len, "Bit::slice: pos should be less than _Nm - _Len");
|
||||
return Bit<_Len>(this->_M_data >> pos);
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace dark
|
||||
|
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
#include <limits>
|
||||
#include <cstdint>
|
||||
#include <concepts>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
|
||||
namespace dark {
|
||||
|
||||
@ -10,45 +10,43 @@ using max_ssize_t = std::int32_t;
|
||||
|
||||
static constexpr std::size_t kMaxLength = std::numeric_limits<max_size_t>::digits;
|
||||
|
||||
template <std::size_t _Len>
|
||||
template<std::size_t _Len>
|
||||
consteval max_size_t make_mask() {
|
||||
static_assert(_Len <= kMaxLength, "Mask length out of range");
|
||||
return _Len == kMaxLength ? ~max_size_t(0) : (max_size_t(1) << _Len) - 1;
|
||||
static_assert(_Len <= kMaxLength, "Mask length out of range");
|
||||
return _Len == kMaxLength ? ~max_size_t(0) : (max_size_t(1) << _Len) - 1;
|
||||
}
|
||||
|
||||
} // namespace dark
|
||||
|
||||
namespace dark::concepts {
|
||||
|
||||
template <typename _Tp>
|
||||
using func_t = void(*)(_Tp);
|
||||
template<typename _Tp>
|
||||
using func_t = void (*)(_Tp);
|
||||
|
||||
template <typename _From, typename _To>
|
||||
concept implicit_convertible_to = requires(_From &a, func_t <_To> b) {
|
||||
b(a); // Can implicitly convert
|
||||
template<typename _From, typename _To>
|
||||
concept implicit_convertible_to = requires(_From &a, func_t<_To> b) {
|
||||
b(a); // Can implicitly convert
|
||||
};
|
||||
|
||||
template <typename _From, typename _To>
|
||||
template<typename _From, typename _To>
|
||||
concept explicit_convertible_to =
|
||||
!implicit_convertible_to <_From, _To>
|
||||
&& std::constructible_from <_To, _From>;
|
||||
!implicit_convertible_to<_From, _To> && std::constructible_from<_To, _From>;
|
||||
|
||||
template <typename _Tp>
|
||||
template<typename _Tp>
|
||||
concept has_length = requires { { +_Tp::_Bit_Len } -> std::same_as <std::size_t>; };
|
||||
|
||||
template <typename _Tp>
|
||||
concept bit_type = has_length <_Tp> && explicit_convertible_to <_Tp, max_size_t>;
|
||||
template<typename _Tp>
|
||||
concept bit_type = has_length<_Tp> && explicit_convertible_to<_Tp, max_size_t>;
|
||||
|
||||
template <typename _Tp>
|
||||
concept int_type = !has_length <_Tp> && implicit_convertible_to <_Tp, max_size_t>;
|
||||
template<typename _Tp>
|
||||
concept int_type = !has_length<_Tp> && implicit_convertible_to<_Tp, max_size_t>;
|
||||
|
||||
template <typename _Lhs, typename _Rhs>
|
||||
template<typename _Lhs, typename _Rhs>
|
||||
concept bit_match =
|
||||
(bit_type <_Lhs> && bit_type <_Rhs> && _Lhs::_Bit_Len == _Rhs::_Bit_Len)
|
||||
|| (int_type <_Lhs> || int_type <_Rhs>);
|
||||
(bit_type<_Lhs> && bit_type<_Rhs> && _Lhs::_Bit_Len == _Rhs::_Bit_Len) || (int_type<_Lhs> || int_type<_Rhs>);
|
||||
|
||||
template <typename _Tp, std::size_t _Len>
|
||||
template<typename _Tp, std::size_t _Len>
|
||||
concept bit_convertible =
|
||||
(bit_type <_Tp> && _Tp::_Bit_Len == _Len) || int_type <_Tp>;
|
||||
(bit_type<_Tp> && _Tp::_Bit_Len == _Len) || int_type<_Tp>;
|
||||
|
||||
} // namespace dark::concepts
|
||||
|
@ -48,4 +48,4 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
}// namespace dark
|
||||
} // namespace dark
|
||||
|
@ -8,60 +8,64 @@
|
||||
namespace dark::debug {
|
||||
|
||||
/**
|
||||
* Copied from https://en.cppreference.com/w/cpp/utility/unreachable
|
||||
* Copied from https://en.cppreference.com/w/cpp/utility/unreachable
|
||||
* If compiled under C++23, just use std::unreachable() instead.
|
||||
*/
|
||||
[[noreturn]] inline void unreachable() {
|
||||
#if __cplusplus > 202002L
|
||||
std::unreachable();
|
||||
std::unreachable();
|
||||
#elif defined(_MSC_VER) && !defined(__clang__) // MSVC
|
||||
// Uses compiler specific extensions if possible.
|
||||
// Even if no extension is used, undefined behavior is still raised by
|
||||
// an empty function body and the noreturn attribute.
|
||||
__assume(false);
|
||||
#else // GCC, Clang
|
||||
__builtin_unreachable();
|
||||
// Uses compiler specific extensions if possible.
|
||||
// Even if no extension is used, undefined behavior is still raised by
|
||||
// an empty function body and the noreturn attribute.
|
||||
__assume(false);
|
||||
#else // GCC, Clang
|
||||
__builtin_unreachable();
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename _Tp, typename... _Args>
|
||||
template<typename _Tp, typename... _Args>
|
||||
struct assert {
|
||||
#ifdef _DEBUG
|
||||
explicit assert(_Tp &&condition, _Args &&...args,
|
||||
std::source_location location = std::source_location::current()) {
|
||||
if (condition) return;
|
||||
std::cerr << "Assertion failed at: "
|
||||
<< location.file_name() << ":" << location.line() << "\n";
|
||||
if constexpr (sizeof...(args) != 0) {
|
||||
std::cerr << "Message: ";
|
||||
((std::cerr << args), ...) << std::endl;
|
||||
}
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
explicit assert(_Tp &&condition, _Args &&...args,
|
||||
std::source_location location = std::source_location::current()) {
|
||||
if (condition) return;
|
||||
std::cerr << "Assertion failed at: "
|
||||
<< location.file_name() << ":" << location.line() << "\n";
|
||||
if constexpr (sizeof...(args) != 0) {
|
||||
std::cerr << "Message: ";
|
||||
((std::cerr << args), ...) << std::endl;
|
||||
}
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
#else
|
||||
explicit assert(_Tp &&, _Args &&...) {}
|
||||
explicit assert(_Tp &&, _Args &&...) {}
|
||||
#endif
|
||||
};
|
||||
|
||||
template <typename _Tp, typename... _Args>
|
||||
template<typename _Tp, typename... _Args>
|
||||
assert(_Tp &&, _Args &&...) -> assert<_Tp, _Args...>;
|
||||
|
||||
template <typename _Tp, _Tp _Default>
|
||||
template<typename _Tp, _Tp _Default>
|
||||
struct DebugValue {
|
||||
#ifdef _DEBUG
|
||||
private:
|
||||
_Tp _M_value = _Default;
|
||||
public:
|
||||
auto get_value() const { return this->_M_value; }
|
||||
auto set_value(_Tp value) { this->_M_value = value; }
|
||||
private:
|
||||
_Tp _M_value = _Default;
|
||||
|
||||
public:
|
||||
auto get_value() const { return this->_M_value; }
|
||||
auto set_value(_Tp value) { this->_M_value = value; }
|
||||
#else
|
||||
public:
|
||||
auto get_value() const { return _Default; }
|
||||
auto set_value(_Tp) { /* do nothing */ }
|
||||
public:
|
||||
auto get_value() const { return _Default; }
|
||||
auto set_value(_Tp) { /* do nothing */ }
|
||||
#endif
|
||||
public:
|
||||
explicit operator _Tp() const { return this->get_value(); }
|
||||
DebugValue &operator=(_Tp value) { this->set_value(value); return *this; }
|
||||
public:
|
||||
explicit operator _Tp() const { return this->get_value(); }
|
||||
DebugValue &operator=(_Tp value) {
|
||||
this->set_value(value);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace dark::debug
|
||||
|
@ -16,4 +16,4 @@ struct Module : public ModuleBase, public _Tinput, public _Toutput, protected _T
|
||||
}
|
||||
};
|
||||
|
||||
}// namespace dark
|
||||
} // namespace dark
|
||||
|
@ -3,127 +3,128 @@
|
||||
|
||||
namespace dark {
|
||||
|
||||
using dark::concepts::bit_match;
|
||||
using dark::concepts::bit_type;
|
||||
using dark::concepts::int_type;
|
||||
using dark::concepts::bit_match;
|
||||
|
||||
template <typename _Tp>
|
||||
constexpr auto cast(const _Tp& value) {
|
||||
return static_cast <max_size_t> (value);
|
||||
template<typename _Tp>
|
||||
constexpr auto cast(const _Tp &value) {
|
||||
return static_cast<max_size_t>(value);
|
||||
}
|
||||
|
||||
template <typename _Tp, typename _Up>
|
||||
template<typename _Tp, typename _Up>
|
||||
consteval auto get_common_length() -> std::size_t {
|
||||
static_assert(bit_match <_Tp, _Up>);
|
||||
if constexpr (bit_type <_Tp>) {
|
||||
return _Tp::_Bit_Len;
|
||||
} else {
|
||||
static_assert(bit_type <_Up>, "Invalid common length");
|
||||
return _Up::_Bit_Len;
|
||||
}
|
||||
static_assert(bit_match<_Tp, _Up>);
|
||||
if constexpr (bit_type<_Tp>) {
|
||||
return _Tp::_Bit_Len;
|
||||
}
|
||||
else {
|
||||
static_assert(bit_type<_Up>, "Invalid common length");
|
||||
return _Up::_Bit_Len;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <typename _Tp, typename _Up>
|
||||
requires bit_match <_Tp, _Up>
|
||||
constexpr auto operator + (const _Tp &lhs, const _Up &rhs) {
|
||||
constexpr auto _Len = get_common_length <_Tp, _Up>();
|
||||
return Bit <_Len> (cast(lhs) + cast(rhs));
|
||||
template<typename _Tp, typename _Up>
|
||||
requires bit_match<_Tp, _Up>
|
||||
constexpr auto operator+(const _Tp &lhs, const _Up &rhs) {
|
||||
constexpr auto _Len = get_common_length<_Tp, _Up>();
|
||||
return Bit<_Len>(cast(lhs) + cast(rhs));
|
||||
}
|
||||
|
||||
template <typename _Tp, typename _Up>
|
||||
requires bit_match <_Tp, _Up>
|
||||
constexpr auto operator - (const _Tp &lhs, const _Up &rhs) {
|
||||
constexpr auto _Len = get_common_length <_Tp, _Up>();
|
||||
return Bit <_Len> (cast(lhs) - cast(rhs));
|
||||
template<typename _Tp, typename _Up>
|
||||
requires bit_match<_Tp, _Up>
|
||||
constexpr auto operator-(const _Tp &lhs, const _Up &rhs) {
|
||||
constexpr auto _Len = get_common_length<_Tp, _Up>();
|
||||
return Bit<_Len>(cast(lhs) - cast(rhs));
|
||||
}
|
||||
|
||||
template <typename _Tp, typename _Up>
|
||||
requires bit_match <_Tp, _Up>
|
||||
constexpr auto operator * (const _Tp &lhs, const _Up &rhs) {
|
||||
constexpr auto _Len = get_common_length <_Tp, _Up>();
|
||||
return Bit <_Len> (cast(lhs) * cast(rhs));
|
||||
template<typename _Tp, typename _Up>
|
||||
requires bit_match<_Tp, _Up>
|
||||
constexpr auto operator*(const _Tp &lhs, const _Up &rhs) {
|
||||
constexpr auto _Len = get_common_length<_Tp, _Up>();
|
||||
return Bit<_Len>(cast(lhs) * cast(rhs));
|
||||
}
|
||||
|
||||
template <typename _Tp, typename _Up>
|
||||
requires bit_match <_Tp, _Up>
|
||||
constexpr auto operator / (const _Tp &lhs, const _Up &rhs) {
|
||||
constexpr auto _Len = get_common_length <_Tp, _Up>();
|
||||
return Bit <_Len> (cast(lhs) / cast(rhs));
|
||||
template<typename _Tp, typename _Up>
|
||||
requires bit_match<_Tp, _Up>
|
||||
constexpr auto operator/(const _Tp &lhs, const _Up &rhs) {
|
||||
constexpr auto _Len = get_common_length<_Tp, _Up>();
|
||||
return Bit<_Len>(cast(lhs) / cast(rhs));
|
||||
}
|
||||
|
||||
template <typename _Tp, typename _Up>
|
||||
requires bit_match <_Tp, _Up>
|
||||
constexpr auto operator & (const _Tp &lhs, const _Up &rhs) {
|
||||
constexpr auto _Len = get_common_length <_Tp, _Up>();
|
||||
return Bit <_Len> (cast(lhs) & cast(rhs));
|
||||
template<typename _Tp, typename _Up>
|
||||
requires bit_match<_Tp, _Up>
|
||||
constexpr auto operator&(const _Tp &lhs, const _Up &rhs) {
|
||||
constexpr auto _Len = get_common_length<_Tp, _Up>();
|
||||
return Bit<_Len>(cast(lhs) & cast(rhs));
|
||||
}
|
||||
|
||||
template <typename _Tp, typename _Up>
|
||||
requires bit_match <_Tp, _Up>
|
||||
constexpr auto operator | (const _Tp &lhs, const _Up &rhs) {
|
||||
constexpr auto _Len = get_common_length <_Tp, _Up>();
|
||||
return Bit <_Len> (cast(lhs) | cast(rhs));
|
||||
template<typename _Tp, typename _Up>
|
||||
requires bit_match<_Tp, _Up>
|
||||
constexpr auto operator|(const _Tp &lhs, const _Up &rhs) {
|
||||
constexpr auto _Len = get_common_length<_Tp, _Up>();
|
||||
return Bit<_Len>(cast(lhs) | cast(rhs));
|
||||
}
|
||||
|
||||
template <typename _Tp, typename _Up>
|
||||
requires bit_match <_Tp, _Up>
|
||||
constexpr auto operator ^ (const _Tp &lhs, const _Up &rhs) {
|
||||
constexpr auto _Len = get_common_length <_Tp, _Up>();
|
||||
return Bit <_Len> (cast(lhs) ^ cast(rhs));
|
||||
template<typename _Tp, typename _Up>
|
||||
requires bit_match<_Tp, _Up>
|
||||
constexpr auto operator^(const _Tp &lhs, const _Up &rhs) {
|
||||
constexpr auto _Len = get_common_length<_Tp, _Up>();
|
||||
return Bit<_Len>(cast(lhs) ^ cast(rhs));
|
||||
}
|
||||
|
||||
template <typename _Tp>
|
||||
concept int_or_bit = int_type <_Tp> || bit_type <_Tp>;
|
||||
template<typename _Tp>
|
||||
concept int_or_bit = int_type<_Tp> || bit_type<_Tp>;
|
||||
|
||||
template <bit_type _Tp, int_or_bit _Up>
|
||||
constexpr auto operator << (const _Tp &lhs, const _Up &rhs) {
|
||||
return Bit <_Tp::_Bit_Len> (cast(lhs) << (cast(rhs) & kMaxLength));
|
||||
template<bit_type _Tp, int_or_bit _Up>
|
||||
constexpr auto operator<<(const _Tp &lhs, const _Up &rhs) {
|
||||
return Bit<_Tp::_Bit_Len>(cast(lhs) << (cast(rhs) & kMaxLength));
|
||||
}
|
||||
|
||||
template <bit_type _Tp, int_or_bit _Up>
|
||||
constexpr auto operator >> (const _Tp &lhs, const _Up &rhs) {
|
||||
return Bit <_Tp::_Bit_Len> (cast(lhs) >> (cast(rhs) & kMaxLength));
|
||||
template<bit_type _Tp, int_or_bit _Up>
|
||||
constexpr auto operator>>(const _Tp &lhs, const _Up &rhs) {
|
||||
return Bit<_Tp::_Bit_Len>(cast(lhs) >> (cast(rhs) & kMaxLength));
|
||||
}
|
||||
|
||||
template <bit_type _Tp>
|
||||
constexpr auto operator ~ (const _Tp &value) {
|
||||
return Bit <_Tp::_Bit_Len> (~cast(value));
|
||||
template<bit_type _Tp>
|
||||
constexpr auto operator~(const _Tp &value) {
|
||||
return Bit<_Tp::_Bit_Len>(~cast(value));
|
||||
}
|
||||
|
||||
template <bit_type _Tp>
|
||||
constexpr auto operator ! (const _Tp &value) {
|
||||
return ~value;
|
||||
template<bit_type _Tp>
|
||||
constexpr auto operator!(const _Tp &value) {
|
||||
return ~value;
|
||||
}
|
||||
|
||||
template <bit_type _Tp>
|
||||
constexpr auto operator + (const _Tp &value) {
|
||||
return Bit <_Tp::_Bit_Len> (+cast(value));
|
||||
template<bit_type _Tp>
|
||||
constexpr auto operator+(const _Tp &value) {
|
||||
return Bit<_Tp::_Bit_Len>(+cast(value));
|
||||
}
|
||||
|
||||
template <bit_type _Tp>
|
||||
constexpr auto operator - (const _Tp &value) {
|
||||
return Bit <_Tp::_Bit_Len> (-cast(value));
|
||||
template<bit_type _Tp>
|
||||
constexpr auto operator-(const _Tp &value) {
|
||||
return Bit<_Tp::_Bit_Len>(-cast(value));
|
||||
}
|
||||
|
||||
template <int_or_bit _Tp, int_or_bit _Up>
|
||||
constexpr bool operator && (const _Tp &lhs, const _Up &rhs) {
|
||||
return cast(lhs) && cast(rhs);
|
||||
template<int_or_bit _Tp, int_or_bit _Up>
|
||||
constexpr bool operator&&(const _Tp &lhs, const _Up &rhs) {
|
||||
return cast(lhs) && cast(rhs);
|
||||
}
|
||||
|
||||
template <int_or_bit _Tp, int_or_bit _Up>
|
||||
constexpr bool operator || (const _Tp &lhs, const _Up &rhs) {
|
||||
return cast(lhs) || cast(rhs);
|
||||
template<int_or_bit _Tp, int_or_bit _Up>
|
||||
constexpr bool operator||(const _Tp &lhs, const _Up &rhs) {
|
||||
return cast(lhs) || cast(rhs);
|
||||
}
|
||||
|
||||
template <int_or_bit _Tp, int_or_bit _Up>
|
||||
constexpr bool operator == (const _Tp &lhs, const _Up &rhs) {
|
||||
return cast(lhs) == cast(rhs);
|
||||
template<int_or_bit _Tp, int_or_bit _Up>
|
||||
constexpr bool operator==(const _Tp &lhs, const _Up &rhs) {
|
||||
return cast(lhs) == cast(rhs);
|
||||
}
|
||||
|
||||
template <int_or_bit _Tp, int_or_bit _Up>
|
||||
constexpr auto operator <=> (const _Tp &lhs, const _Up &rhs) {
|
||||
return cast(lhs) <=> cast(rhs);
|
||||
template<int_or_bit _Tp, int_or_bit _Up>
|
||||
constexpr auto operator<=>(const _Tp &lhs, const _Up &rhs) {
|
||||
return cast(lhs) <=> cast(rhs);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,81 +1,104 @@
|
||||
#pragma once
|
||||
#include <tuple>
|
||||
#include <concepts>
|
||||
#include <tuple>
|
||||
|
||||
namespace dark::reflect {
|
||||
|
||||
/* A init helper to get the size of a struct. */
|
||||
struct init_helper { template <typename _Tp> operator _Tp(); };
|
||||
struct init_helper {
|
||||
template<typename _Tp>
|
||||
operator _Tp();
|
||||
};
|
||||
|
||||
/* A size helper to get the size of a struct. */
|
||||
template <typename _Tp> requires std::is_aggregate_v <_Tp>
|
||||
template<typename _Tp>
|
||||
requires std::is_aggregate_v<_Tp>
|
||||
inline consteval auto member_size_aux(auto &&...args) -> std::size_t {
|
||||
constexpr std::size_t size = sizeof...(args);
|
||||
constexpr std::size_t maximum = 114;
|
||||
if constexpr (size > maximum) {
|
||||
static_assert (sizeof(_Tp) == 0, "The struct has too many members.");
|
||||
} else if constexpr (!requires {_Tp { args... }; }) {
|
||||
return size - 1;
|
||||
} else {
|
||||
return member_size_aux <_Tp> (args..., init_helper {});
|
||||
}
|
||||
constexpr std::size_t size = sizeof...(args);
|
||||
constexpr std::size_t maximum = 114;
|
||||
if constexpr (size > maximum) {
|
||||
static_assert(sizeof(_Tp) == 0, "The struct has too many members.");
|
||||
}
|
||||
else if constexpr (!requires { _Tp{args...}; }) {
|
||||
return size - 1;
|
||||
}
|
||||
else {
|
||||
return member_size_aux<_Tp>(args..., init_helper{});
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the member size for a aggregate type without base. */
|
||||
template <typename _Tp> requires std::is_aggregate_v <_Tp>
|
||||
inline consteval auto member_size(_Tp &) -> std::size_t { return member_size_aux <_Tp> (); }
|
||||
template<typename _Tp>
|
||||
requires std::is_aggregate_v<_Tp>
|
||||
inline consteval auto member_size(_Tp &) -> std::size_t { return member_size_aux<_Tp>(); }
|
||||
|
||||
template <typename _Tp> requires std::is_aggregate_v <_Tp>
|
||||
inline consteval auto member_size() -> std::size_t { return member_size_aux <_Tp> (); }
|
||||
template<typename _Tp>
|
||||
requires std::is_aggregate_v<_Tp>
|
||||
inline consteval auto member_size() -> std::size_t { return member_size_aux<_Tp>(); }
|
||||
|
||||
template <typename _Tp> requires std::is_aggregate_v <_Tp>
|
||||
template<typename _Tp>
|
||||
requires std::is_aggregate_v<_Tp>
|
||||
auto tuplify(_Tp &value) {
|
||||
constexpr auto size = member_size <_Tp> ();
|
||||
if constexpr (size == 1) {
|
||||
auto &[x0] = value;
|
||||
return std::forward_as_tuple(x0);
|
||||
} else if constexpr (size == 2) {
|
||||
auto &[x0, x1] = value;
|
||||
return std::forward_as_tuple(x0, x1);
|
||||
} else if constexpr (size == 3) {
|
||||
auto &[x0, x1, x2] = value;
|
||||
return std::forward_as_tuple(x0, x1, x2);
|
||||
} else if constexpr (size == 4) {
|
||||
auto &[x0, x1, x2, x3] = value;
|
||||
return std::forward_as_tuple(x0, x1, x2, x3);
|
||||
} else if constexpr (size == 5) {
|
||||
auto &[x0, x1, x2, x3, x4] = value;
|
||||
return std::forward_as_tuple(x0, x1, x2, x3, x4);
|
||||
} else if constexpr (size == 6) {
|
||||
auto &[x0, x1, x2, x3, x4, x5] = value;
|
||||
return std::forward_as_tuple(x0, x1, x2, x3, x4, x5);
|
||||
} else if constexpr (size == 7) {
|
||||
auto &[x0, x1, x2, x3, x4, x5, x6] = value;
|
||||
return std::forward_as_tuple(x0, x1, x2, x3, x4, x5, x6);
|
||||
} else if constexpr (size == 8) {
|
||||
auto &[x0, x1, x2, x3, x4, x5, x6, x7] = value;
|
||||
return std::forward_as_tuple(x0, x1, x2, x3, x4, x5, x6, x7);
|
||||
} else if constexpr (size == 9) {
|
||||
auto &[x0, x1, x2, x3, x4, x5, x6, x7, x8] = value;
|
||||
return std::forward_as_tuple(x0, x1, x2, x3, x4, x5, x6, x7, x8);
|
||||
} else if constexpr (size == 10) {
|
||||
auto &[x0, x1, x2, x3, x4, x5, x6, x7, x8, x9] = value;
|
||||
return std::forward_as_tuple(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9);
|
||||
} else if constexpr (size == 11) {
|
||||
auto &[x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10] = value;
|
||||
return std::forward_as_tuple(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10);
|
||||
} else if constexpr (size == 12) {
|
||||
auto &[x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11] = value;
|
||||
return std::forward_as_tuple(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11);
|
||||
} else if constexpr (size == 13) {
|
||||
auto &[x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12] = value;
|
||||
return std::forward_as_tuple(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12);
|
||||
} else if constexpr (size == 14) {
|
||||
auto &[x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13] = value;
|
||||
return std::forward_as_tuple(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13);
|
||||
} else {
|
||||
static_assert (sizeof(_Tp) == 0, "The struct has too many members.");
|
||||
}
|
||||
constexpr auto size = member_size<_Tp>();
|
||||
if constexpr (size == 1) {
|
||||
auto &[x0] = value;
|
||||
return std::forward_as_tuple(x0);
|
||||
}
|
||||
else if constexpr (size == 2) {
|
||||
auto &[x0, x1] = value;
|
||||
return std::forward_as_tuple(x0, x1);
|
||||
}
|
||||
else if constexpr (size == 3) {
|
||||
auto &[x0, x1, x2] = value;
|
||||
return std::forward_as_tuple(x0, x1, x2);
|
||||
}
|
||||
else if constexpr (size == 4) {
|
||||
auto &[x0, x1, x2, x3] = value;
|
||||
return std::forward_as_tuple(x0, x1, x2, x3);
|
||||
}
|
||||
else if constexpr (size == 5) {
|
||||
auto &[x0, x1, x2, x3, x4] = value;
|
||||
return std::forward_as_tuple(x0, x1, x2, x3, x4);
|
||||
}
|
||||
else if constexpr (size == 6) {
|
||||
auto &[x0, x1, x2, x3, x4, x5] = value;
|
||||
return std::forward_as_tuple(x0, x1, x2, x3, x4, x5);
|
||||
}
|
||||
else if constexpr (size == 7) {
|
||||
auto &[x0, x1, x2, x3, x4, x5, x6] = value;
|
||||
return std::forward_as_tuple(x0, x1, x2, x3, x4, x5, x6);
|
||||
}
|
||||
else if constexpr (size == 8) {
|
||||
auto &[x0, x1, x2, x3, x4, x5, x6, x7] = value;
|
||||
return std::forward_as_tuple(x0, x1, x2, x3, x4, x5, x6, x7);
|
||||
}
|
||||
else if constexpr (size == 9) {
|
||||
auto &[x0, x1, x2, x3, x4, x5, x6, x7, x8] = value;
|
||||
return std::forward_as_tuple(x0, x1, x2, x3, x4, x5, x6, x7, x8);
|
||||
}
|
||||
else if constexpr (size == 10) {
|
||||
auto &[x0, x1, x2, x3, x4, x5, x6, x7, x8, x9] = value;
|
||||
return std::forward_as_tuple(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9);
|
||||
}
|
||||
else if constexpr (size == 11) {
|
||||
auto &[x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10] = value;
|
||||
return std::forward_as_tuple(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10);
|
||||
}
|
||||
else if constexpr (size == 12) {
|
||||
auto &[x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11] = value;
|
||||
return std::forward_as_tuple(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11);
|
||||
}
|
||||
else if constexpr (size == 13) {
|
||||
auto &[x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12] = value;
|
||||
return std::forward_as_tuple(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12);
|
||||
}
|
||||
else if constexpr (size == 14) {
|
||||
auto &[x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13] = value;
|
||||
return std::forward_as_tuple(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13);
|
||||
}
|
||||
else {
|
||||
static_assert(sizeof(_Tp) == 0, "The struct has too many members.");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace dark::reflect
|
||||
|
@ -1,46 +1,46 @@
|
||||
#pragma once
|
||||
#include "debug.h"
|
||||
#include "concept.h"
|
||||
#include "debug.h"
|
||||
|
||||
namespace dark {
|
||||
|
||||
template <std::size_t _Len>
|
||||
template<std::size_t _Len>
|
||||
struct Register {
|
||||
private:
|
||||
static_assert(0 < _Len && _Len <= kMaxLength,
|
||||
"Register: _Len must be in range [1, kMaxLength].");
|
||||
private:
|
||||
static_assert(0 < _Len && _Len <= kMaxLength,
|
||||
"Register: _Len must be in range [1, kMaxLength].");
|
||||
|
||||
friend class Visitor;
|
||||
friend class Visitor;
|
||||
|
||||
max_size_t _M_old : _Len;
|
||||
max_size_t _M_new : _Len;
|
||||
max_size_t _M_old : _Len;
|
||||
max_size_t _M_new : _Len;
|
||||
|
||||
[[no_unique_address]]
|
||||
debug::DebugValue <bool, false> _M_assigned;
|
||||
[[no_unique_address]]
|
||||
debug::DebugValue<bool, false> _M_assigned;
|
||||
|
||||
void sync() {
|
||||
this->_M_assigned = false;
|
||||
this->_M_old = this->_M_new;
|
||||
}
|
||||
void sync() {
|
||||
this->_M_assigned = false;
|
||||
this->_M_old = this->_M_new;
|
||||
}
|
||||
|
||||
public:
|
||||
static constexpr std::size_t _Bit_Len = _Len;
|
||||
public:
|
||||
static constexpr std::size_t _Bit_Len = _Len;
|
||||
|
||||
Register() : _M_old(), _M_new(), _M_assigned() {}
|
||||
Register() : _M_old(), _M_new(), _M_assigned() {}
|
||||
|
||||
Register(Register &&) = delete;
|
||||
Register(const Register &) = delete;
|
||||
Register &operator=(Register &&) = delete;
|
||||
Register &operator=(const Register &rhs) = delete;
|
||||
Register(Register &&) = delete;
|
||||
Register(const Register &) = delete;
|
||||
Register &operator=(Register &&) = delete;
|
||||
Register &operator=(const Register &rhs) = delete;
|
||||
|
||||
template <concepts::bit_convertible <_Len> _Tp>
|
||||
void operator <= (const _Tp &value) {
|
||||
debug::assert(!this->_M_assigned, "Register is double assigned in this cycle.");
|
||||
this->_M_assigned = true;
|
||||
this->_M_new = static_cast <max_size_t> (value);
|
||||
}
|
||||
template<concepts::bit_convertible<_Len> _Tp>
|
||||
void operator<=(const _Tp &value) {
|
||||
debug::assert(!this->_M_assigned, "Register is double assigned in this cycle.");
|
||||
this->_M_assigned = true;
|
||||
this->_M_new = static_cast<max_size_t>(value);
|
||||
}
|
||||
|
||||
explicit operator max_size_t() const { return this->_M_old; }
|
||||
explicit operator max_size_t() const { return this->_M_old; }
|
||||
};
|
||||
|
||||
} // namespace dark
|
||||
|
@ -5,56 +5,62 @@
|
||||
namespace dark {
|
||||
|
||||
struct Visitor {
|
||||
template <typename _Tp>
|
||||
static constexpr bool is_syncable_v =
|
||||
requires(_Tp &val) { { val.sync() } -> std::same_as<void>; };
|
||||
template<typename _Tp>
|
||||
static constexpr bool is_syncable_v =
|
||||
requires(_Tp &val) { { val.sync() } -> std::same_as<void>; };
|
||||
|
||||
template <typename _Tp> requires is_syncable_v<_Tp>
|
||||
static void sync(_Tp &val) { val.sync(); }
|
||||
template<typename _Tp>
|
||||
requires is_syncable_v<_Tp>
|
||||
static void sync(_Tp &val) { val.sync(); }
|
||||
|
||||
template <typename _Tp, typename _Base>
|
||||
static _Base &cast(_Tp &value) { return static_cast<_Base &>(value); }
|
||||
template<typename _Tp, typename _Base>
|
||||
static _Base &cast(_Tp &value) { return static_cast<_Base &>(value); }
|
||||
};
|
||||
|
||||
template <typename ..._Base>
|
||||
template<typename... _Base>
|
||||
struct SyncTags {};
|
||||
|
||||
template <typename _Tp>
|
||||
template<typename _Tp>
|
||||
static constexpr bool is_valid_tag_v = false;
|
||||
template <typename ..._Base>
|
||||
template<typename... _Base>
|
||||
static constexpr bool is_valid_tag_v<SyncTags<_Base...>> = true;
|
||||
template <typename _Tp>
|
||||
template<typename _Tp>
|
||||
concept has_valid_tag = is_valid_tag_v<typename _Tp::Tags>;
|
||||
|
||||
template <typename _Tp>
|
||||
template<typename _Tp>
|
||||
static constexpr bool is_std_array_v = std::is_array_v<_Tp>;
|
||||
template <typename _Tp, std::size_t _Nm>
|
||||
template<typename _Tp, std::size_t _Nm>
|
||||
static constexpr bool is_std_array_v<std::array<_Tp, _Nm>> = true;
|
||||
|
||||
template <typename _Tp>
|
||||
template<typename _Tp>
|
||||
inline void sync_member(_Tp &value);
|
||||
|
||||
template <typename _Tp, typename ..._Base>
|
||||
template<typename _Tp, typename... _Base>
|
||||
inline void sync_by_tag(_Tp &value, SyncTags<_Base...>) {
|
||||
(sync_member(Visitor::cast<_Tp, _Base>(value)), ...);
|
||||
(sync_member(Visitor::cast<_Tp, _Base>(value)), ...);
|
||||
}
|
||||
|
||||
template <typename _Tp>
|
||||
template<typename _Tp>
|
||||
inline void sync_member(_Tp &value) {
|
||||
if constexpr (std::is_const_v <_Tp>) {
|
||||
/* Do nothing! Constant members need no synchronization! */
|
||||
} else if constexpr (is_std_array_v<_Tp>) {
|
||||
for (auto &member : value) sync_member(member);
|
||||
} else if constexpr (Visitor::is_syncable_v<_Tp>) {
|
||||
Visitor::sync(value);
|
||||
} else if constexpr (has_valid_tag<_Tp>) {
|
||||
sync_by_tag(value, typename _Tp::Tags {});
|
||||
} else if constexpr (std::is_aggregate_v<_Tp>) {
|
||||
auto &&tuple = reflect::tuplify(value);
|
||||
std::apply([](auto &...members) { (sync_member(members), ...); }, tuple);
|
||||
} else {
|
||||
static_assert(sizeof(_Tp) == 0, "This type is not syncable.");
|
||||
}
|
||||
if constexpr (std::is_const_v<_Tp>) {
|
||||
/* Do nothing! Constant members need no synchronization! */
|
||||
}
|
||||
else if constexpr (is_std_array_v<_Tp>) {
|
||||
for (auto &member: value) sync_member(member);
|
||||
}
|
||||
else if constexpr (Visitor::is_syncable_v<_Tp>) {
|
||||
Visitor::sync(value);
|
||||
}
|
||||
else if constexpr (has_valid_tag<_Tp>) {
|
||||
sync_by_tag(value, typename _Tp::Tags{});
|
||||
}
|
||||
else if constexpr (std::is_aggregate_v<_Tp>) {
|
||||
auto &&tuple = reflect::tuplify(value);
|
||||
std::apply([](auto &...members) { (sync_member(members), ...); }, tuple);
|
||||
}
|
||||
else {
|
||||
static_assert(sizeof(_Tp) == 0, "This type is not syncable.");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace dark::hardware
|
||||
} // namespace dark
|
||||
|
@ -1,31 +1,31 @@
|
||||
#pragma once
|
||||
#include "bit.h"
|
||||
#include "bit_impl.h"
|
||||
#include "wire.h"
|
||||
#include "operator.h"
|
||||
#include "register.h"
|
||||
#include "synchronize.h"
|
||||
#include "operator.h"
|
||||
#include "wire.h"
|
||||
|
||||
using dark::Bit;
|
||||
using dark::sign_extend;
|
||||
using dark::zero_extend;
|
||||
|
||||
using dark::Wire;
|
||||
using dark::Register;
|
||||
using dark::Wire;
|
||||
|
||||
using dark::SyncTags;
|
||||
using dark::sync_member;
|
||||
using dark::SyncTags;
|
||||
using dark::Visitor;
|
||||
|
||||
using dark::max_size_t;
|
||||
using dark::max_ssize_t;
|
||||
|
||||
template <dark::concepts::bit_type _Tp>
|
||||
template<dark::concepts::bit_type _Tp>
|
||||
constexpr auto to_unsigned(const _Tp &x) {
|
||||
return static_cast<dark::max_size_t>(x);
|
||||
return static_cast<dark::max_size_t>(x);
|
||||
}
|
||||
|
||||
template <dark::concepts::bit_type _Tp>
|
||||
template<dark::concepts::bit_type _Tp>
|
||||
constexpr auto to_signed(const _Tp &x) {
|
||||
return static_cast<dark::max_ssize_t>(to_unsigned(x));
|
||||
return static_cast<dark::max_ssize_t>(to_unsigned(x));
|
||||
}
|
||||
|
153
include/wire.h
153
include/wire.h
@ -1,113 +1,112 @@
|
||||
#pragma once
|
||||
#include "debug.h"
|
||||
#include "concept.h"
|
||||
#include "debug.h"
|
||||
#include <memory>
|
||||
|
||||
namespace dark {
|
||||
|
||||
namespace details {
|
||||
|
||||
template <typename _Fn, std::size_t _Len>
|
||||
concept WireFunction =
|
||||
concepts::bit_convertible <std::decay_t <std::invoke_result_t <_Fn>>, _Len>;
|
||||
template<typename _Fn, std::size_t _Len>
|
||||
concept WireFunction =
|
||||
concepts::bit_convertible<std::decay_t<std::invoke_result_t<_Fn>>, _Len>;
|
||||
|
||||
struct FuncBase {
|
||||
using _Ret_t = max_size_t;
|
||||
using _Cpy_t = FuncBase *;
|
||||
virtual _Ret_t call() const = 0;
|
||||
virtual _Cpy_t copy() const = 0;
|
||||
virtual ~FuncBase() = default;
|
||||
};
|
||||
struct FuncBase {
|
||||
using _Ret_t = max_size_t;
|
||||
using _Cpy_t = FuncBase *;
|
||||
virtual _Ret_t call() const = 0;
|
||||
virtual _Cpy_t copy() const = 0;
|
||||
virtual ~FuncBase() = default;
|
||||
};
|
||||
|
||||
template <std::size_t _Len, WireFunction <_Len> _Fn>
|
||||
struct FuncImpl final : FuncBase {
|
||||
_Fn _M_lambda;
|
||||
template<std::size_t _Len, WireFunction<_Len> _Fn>
|
||||
struct FuncImpl final : FuncBase {
|
||||
_Fn _M_lambda;
|
||||
|
||||
template <typename _Tp>
|
||||
FuncImpl(_Tp &&fn) : _M_lambda(std::forward <_Tp> (fn)) {}
|
||||
template<typename _Tp>
|
||||
FuncImpl(_Tp &&fn) : _M_lambda(std::forward<_Tp>(fn)) {}
|
||||
|
||||
_Ret_t call() const override { return static_cast <_Ret_t> (this->_M_lambda()); }
|
||||
_Cpy_t copy() const override { return new FuncImpl(*this); }
|
||||
};
|
||||
_Ret_t call() const override { return static_cast<_Ret_t>(this->_M_lambda()); }
|
||||
_Cpy_t copy() const override { return new FuncImpl(*this); }
|
||||
};
|
||||
|
||||
struct EmptyWire final : FuncBase {
|
||||
_Ret_t call() const override {
|
||||
debug::assert(false, "Empty wire is called.");
|
||||
debug::unreachable();
|
||||
}
|
||||
_Cpy_t copy() const override { return new EmptyWire; }
|
||||
};
|
||||
struct EmptyWire final : FuncBase {
|
||||
_Ret_t call() const override {
|
||||
debug::assert(false, "Empty wire is called.");
|
||||
debug::unreachable();
|
||||
}
|
||||
_Cpy_t copy() const override { return new EmptyWire; }
|
||||
};
|
||||
|
||||
} // namespace details
|
||||
|
||||
|
||||
template <std::size_t _Len>
|
||||
template<std::size_t _Len>
|
||||
struct Wire {
|
||||
private:
|
||||
static_assert(0 < _Len && _Len <= kMaxLength,
|
||||
"Wire: _Len must be in range [1, kMaxLength].");
|
||||
private:
|
||||
static_assert(0 < _Len && _Len <= kMaxLength,
|
||||
"Wire: _Len must be in range [1, kMaxLength].");
|
||||
|
||||
friend class Visitor;
|
||||
friend class Visitor;
|
||||
|
||||
using _Manage_t = std::unique_ptr <details::FuncBase>;
|
||||
using _Manage_t = std::unique_ptr<details::FuncBase>;
|
||||
|
||||
_Manage_t _M_func;
|
||||
_Manage_t _M_func;
|
||||
|
||||
mutable max_size_t _M_cache : _Len;
|
||||
mutable bool _M_holds;
|
||||
mutable max_size_t _M_cache : _Len;
|
||||
mutable bool _M_holds;
|
||||
|
||||
[[no_unique_address]]
|
||||
debug::DebugValue <bool, false> _M_assigned;
|
||||
[[no_unique_address]]
|
||||
debug::DebugValue<bool, false> _M_assigned;
|
||||
|
||||
void sync() { this->_M_holds = false; }
|
||||
private:
|
||||
void sync() { this->_M_holds = false; }
|
||||
|
||||
template <details::WireFunction <_Len> _Fn>
|
||||
static auto _M_new_func(_Fn &&fn) {
|
||||
using _Decay_t = std::decay_t <_Fn>;
|
||||
return new details::FuncImpl <_Len, _Decay_t> {std::forward <_Fn>(fn)};
|
||||
}
|
||||
template<details::WireFunction<_Len> _Fn>
|
||||
static auto _M_new_func(_Fn &&fn) {
|
||||
using _Decay_t = std::decay_t<_Fn>;
|
||||
return new details::FuncImpl<_Len, _Decay_t>{std::forward<_Fn>(fn)};
|
||||
}
|
||||
|
||||
void _M_checked_assign() {
|
||||
debug::assert(!this->_M_assigned, "Wire is assigned twice.");
|
||||
this->_M_assigned = true;
|
||||
}
|
||||
void _M_checked_assign() {
|
||||
debug::assert(!this->_M_assigned, "Wire is assigned twice.");
|
||||
this->_M_assigned = true;
|
||||
}
|
||||
|
||||
public:
|
||||
static constexpr std::size_t _Bit_Len = _Len;
|
||||
public:
|
||||
static constexpr std::size_t _Bit_Len = _Len;
|
||||
|
||||
Wire() :
|
||||
_M_func(new details::EmptyWire),
|
||||
_M_cache(), _M_holds(), _M_assigned() {}
|
||||
Wire() : _M_func(new details::EmptyWire),
|
||||
_M_cache(), _M_holds(), _M_assigned() {}
|
||||
|
||||
explicit operator max_size_t() const {
|
||||
if (this->_M_holds == false) {
|
||||
this->_M_holds = true;
|
||||
this->_M_cache = this->_M_func->call();
|
||||
}
|
||||
return this->_M_cache;
|
||||
}
|
||||
explicit operator max_size_t() const {
|
||||
if (this->_M_holds == false) {
|
||||
this->_M_holds = true;
|
||||
this->_M_cache = this->_M_func->call();
|
||||
}
|
||||
return this->_M_cache;
|
||||
}
|
||||
|
||||
Wire(Wire &&) = delete;
|
||||
Wire(const Wire &) = delete;
|
||||
Wire &operator=(Wire &&) = delete;
|
||||
Wire &operator=(const Wire &rhs) = delete;
|
||||
Wire(Wire &&) = delete;
|
||||
Wire(const Wire &) = delete;
|
||||
Wire &operator=(Wire &&) = delete;
|
||||
Wire &operator=(const Wire &rhs) = delete;
|
||||
|
||||
template <details::WireFunction <_Len> _Fn>
|
||||
Wire(_Fn &&fn) :
|
||||
_M_func(_M_new_func(std::forward <_Fn> (fn))),
|
||||
_M_cache(), _M_holds(), _M_assigned() {}
|
||||
template<details::WireFunction<_Len> _Fn>
|
||||
Wire(_Fn &&fn) : _M_func(_M_new_func(std::forward<_Fn>(fn))),
|
||||
_M_cache(), _M_holds(), _M_assigned() {}
|
||||
|
||||
template <details::WireFunction <_Len> _Fn>
|
||||
Wire &operator=(_Fn &&fn) {
|
||||
return this->assign(std::forward <_Fn> (fn)), *this;
|
||||
}
|
||||
template<details::WireFunction<_Len> _Fn>
|
||||
Wire &operator=(_Fn &&fn) {
|
||||
return this->assign(std::forward<_Fn>(fn)), *this;
|
||||
}
|
||||
|
||||
template <details::WireFunction <_Len> _Fn>
|
||||
void assign(_Fn &&fn) {
|
||||
this->_M_checked_assign();
|
||||
this->_M_func.reset(_M_new_func(std::forward <_Fn> (fn)));
|
||||
this->sync();
|
||||
}
|
||||
template<details::WireFunction<_Len> _Fn>
|
||||
void assign(_Fn &&fn) {
|
||||
this->_M_checked_assign();
|
||||
this->_M_func.reset(_M_new_func(std::forward<_Fn>(fn)));
|
||||
this->sync();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user