style: use tab replace spaces

every one could change the length of tab but not of space
This commit is contained in:
Wankupi
2024-07-23 18:46:21 +08:00
parent 9038750dbe
commit 80ff0d5682
12 changed files with 455 additions and 421 deletions

View File

@ -1,50 +1,50 @@
#pragma once #pragma once
#include "concept.h" #include "concept.h"
#include "debug.h" #include "debug.h"
#include <version>
#include <climits> #include <climits>
#include <concepts> #include <concepts>
#include <version>
namespace dark { namespace dark {
template <std::size_t _Nm> template<std::size_t _Nm>
struct Bit { struct Bit {
private: private:
static_assert(0 < _Nm && _Nm <= kMaxLength, static_assert(0 < _Nm && _Nm <= kMaxLength,
"Bit: _Nm out of range. Should be in [1, kMaxLength]"); "Bit: _Nm out of range. Should be in [1, kMaxLength]");
max_size_t _M_data : _Nm; // Real storage
template <std::size_t _Hi, std::size_t _Lo> max_size_t _M_data : _Nm; // Real storage
static constexpr void _M_range_check();
public: template<std::size_t _Hi, std::size_t _Lo>
static constexpr std::size_t _Bit_Len = _Nm; 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> constexpr explicit operator max_size_t() const { return this->_M_data; }
requires ((_Tp::_Bit_Len + ...) == _Nm)
constexpr Bit(const _Tp &...args);
template <concepts::bit_convertible <_Nm> _Tp> template<concepts::bit_type... _Tp>
constexpr Bit &operator=(const _Tp &val); 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> template<concepts::bit_convertible<_Nm> _Tp>
constexpr void set(const _Tp &val); constexpr Bit &operator=(const _Tp &val);
template <std::size_t _Hi, std::size_t _Lo = _Hi> template<std::size_t _Hi, std::size_t _Lo = _Hi, concepts::bit_convertible<_Nm> _Tp>
constexpr auto range() const -> Bit <_Hi - _Lo + 1>; constexpr void set(const _Tp &val);
template <std::size_t _Len = 1> template<std::size_t _Hi, std::size_t _Lo = _Hi>
constexpr auto slice(std::size_t pos) const -> Bit <_Len>; 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 + ...)>; Bit(_Tp...) -> Bit<(_Tp::_Bit_Len + ...)>;
} // namespace dark } // namespace dark

View File

@ -3,84 +3,87 @@
namespace dark { namespace dark {
template <int _First> template<int _First>
constexpr auto int_concat(max_size_t arg) { return arg; } constexpr auto int_concat(max_size_t arg) { return arg; }
template <int _First, int ..._Lens> template<int _First, int... _Lens>
constexpr auto int_concat(max_size_t arg, auto ...args) { constexpr auto int_concat(max_size_t arg, auto... args) {
return (arg << (_Lens + ...)) | int_concat<_Lens...>(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) { constexpr auto sign_extend(max_size_t val) {
static_assert(_Old < _New, "sign_extend: _Old should be less than _New"); static_assert(_Old < _New, "sign_extend: _Old should be less than _New");
struct { max_ssize_t _M_data : _Old; } tmp; struct {
return Bit<_New>(tmp._M_data = val); max_ssize_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 sign_extend(const _Tp & val) { constexpr auto sign_extend(const _Tp &val) {
return sign_extend<_Tp::_Bit_Len, _New>(static_cast<max_size_t>(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) { constexpr auto zero_extend(max_size_t val) {
static_assert(_Old < _New, "zero_extend: _Old should be less than _New"); static_assert(_Old < _New, "zero_extend: _Old should be less than _New");
struct { max_size_t _M_data : _Old; } tmp; struct {
return Bit<_New>(tmp._M_data = val); 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) { 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<std::size_t _Nm>
template <concepts::bit_type ..._Tp> template<concepts::bit_type... _Tp>
requires ((_Tp::_Bit_Len + ...) == _Nm) requires((_Tp::_Bit_Len + ...) == _Nm)
constexpr Bit<_Nm>::Bit(const _Tp &...args) 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<std::size_t _Nm>
template <concepts::bit_convertible <_Nm> _Tp> template<concepts::bit_convertible<_Nm> _Tp>
constexpr Bit<_Nm> &Bit<_Nm>::operator=(const _Tp &val) { constexpr Bit<_Nm> &Bit<_Nm>::operator=(const _Tp &val) {
this->_M_data = static_cast<max_size_t>(val); this->_M_data = static_cast<max_size_t>(val);
return *this; return *this;
} }
template <std::size_t _Nm> template<std::size_t _Nm>
template <std::size_t _Hi, std::size_t _Lo> template<std::size_t _Hi, std::size_t _Lo>
constexpr void Bit<_Nm>::_M_range_check() { constexpr void Bit<_Nm>::_M_range_check() {
static_assert(_Lo <= _Hi, "Bit::range_check: _Lo should be no greater than _Hi"); 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(_Hi < _Nm, "Bit::range_check: _Hi should be less than _Nm");
} }
template <std::size_t _Nm> template<std::size_t _Nm>
template <std::size_t _Hi, std::size_t _Lo, concepts::bit_convertible <_Nm> _Tp> template<std::size_t _Hi, std::size_t _Lo, concepts::bit_convertible<_Nm> _Tp>
constexpr void Bit<_Nm>::set(const _Tp &val) { constexpr void Bit<_Nm>::set(const _Tp &val) {
this->_M_range_check<_Hi, _Lo>(); this->_M_range_check<_Hi, _Lo>();
auto data = static_cast<max_size_t>(val); auto data = static_cast<max_size_t>(val);
constexpr auto _Length = _Hi - _Lo + 1; constexpr auto _Length = _Hi - _Lo + 1;
auto mask = make_mask<_Length> << _Lo; auto mask = make_mask<_Length> << _Lo;
this->_M_data = (this->_M_data & ~mask) | ((data << _Lo) & mask); this->_M_data = (this->_M_data & ~mask) | ((data << _Lo) & mask);
} }
template <std::size_t _Nm> template<std::size_t _Nm>
template <std::size_t _Hi, std::size_t _Lo> template<std::size_t _Hi, std::size_t _Lo>
constexpr auto Bit<_Nm>::range() const -> Bit <_Hi - _Lo + 1> { constexpr auto Bit<_Nm>::range() const -> Bit<_Hi - _Lo + 1> {
this->_M_range_check<_Hi, _Lo>(); this->_M_range_check<_Hi, _Lo>();
constexpr auto _Length = _Hi - _Lo + 1; constexpr auto _Length = _Hi - _Lo + 1;
return Bit<_Length>(this->_M_data >> _Lo); return Bit<_Length>(this->_M_data >> _Lo);
} }
template <std::size_t _Nm> template<std::size_t _Nm>
template <std::size_t _Len> template<std::size_t _Len>
constexpr auto Bit<_Nm>::slice(std::size_t pos) const -> Bit <_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"); 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"); debug::assert(pos <= _Nm - _Len, "Bit::slice: pos should be less than _Nm - _Len");
return Bit<_Len>(this->_M_data >> pos); return Bit<_Len>(this->_M_data >> pos);
} }
} // namespace dark } // namespace dark

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
#include <limits>
#include <cstdint>
#include <concepts> #include <concepts>
#include <cstdint>
#include <limits>
namespace dark { 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; 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() { consteval max_size_t make_mask() {
static_assert(_Len <= kMaxLength, "Mask length out of range"); static_assert(_Len <= kMaxLength, "Mask length out of range");
return _Len == kMaxLength ? ~max_size_t(0) : (max_size_t(1) << _Len) - 1; return _Len == kMaxLength ? ~max_size_t(0) : (max_size_t(1) << _Len) - 1;
} }
} // namespace dark } // namespace dark
namespace dark::concepts { namespace dark::concepts {
template <typename _Tp> template<typename _Tp>
using func_t = void(*)(_Tp); using func_t = void (*)(_Tp);
template <typename _From, typename _To> template<typename _From, typename _To>
concept implicit_convertible_to = requires(_From &a, func_t <_To> b) { concept implicit_convertible_to = requires(_From &a, func_t<_To> b) {
b(a); // Can implicitly convert b(a); // Can implicitly convert
}; };
template <typename _From, typename _To> template<typename _From, typename _To>
concept explicit_convertible_to = concept explicit_convertible_to =
!implicit_convertible_to <_From, _To> !implicit_convertible_to<_From, _To> && std::constructible_from<_To, _From>;
&& std::constructible_from <_To, _From>;
template <typename _Tp> template<typename _Tp>
concept has_length = requires { { +_Tp::_Bit_Len } -> std::same_as <std::size_t>; }; concept has_length = requires { { +_Tp::_Bit_Len } -> std::same_as <std::size_t>; };
template <typename _Tp> template<typename _Tp>
concept bit_type = has_length <_Tp> && explicit_convertible_to <_Tp, max_size_t>; concept bit_type = has_length<_Tp> && explicit_convertible_to<_Tp, max_size_t>;
template <typename _Tp> template<typename _Tp>
concept int_type = !has_length <_Tp> && implicit_convertible_to <_Tp, max_size_t>; 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 = concept bit_match =
(bit_type <_Lhs> && bit_type <_Rhs> && _Lhs::_Bit_Len == _Rhs::_Bit_Len) (bit_type<_Lhs> && bit_type<_Rhs> && _Lhs::_Bit_Len == _Rhs::_Bit_Len) || (int_type<_Lhs> || int_type<_Rhs>);
|| (int_type <_Lhs> || int_type <_Rhs>);
template <typename _Tp, std::size_t _Len> template<typename _Tp, std::size_t _Len>
concept bit_convertible = 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 } // namespace dark::concepts

View File

@ -48,4 +48,4 @@ public:
} }
}; };
}// namespace dark } // namespace dark

View File

@ -8,60 +8,64 @@
namespace dark::debug { 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. * If compiled under C++23, just use std::unreachable() instead.
*/ */
[[noreturn]] inline void unreachable() { [[noreturn]] inline void unreachable() {
#if __cplusplus > 202002L #if __cplusplus > 202002L
std::unreachable(); std::unreachable();
#elif defined(_MSC_VER) && !defined(__clang__) // MSVC #elif defined(_MSC_VER) && !defined(__clang__) // MSVC
// Uses compiler specific extensions if possible. // Uses compiler specific extensions if possible.
// Even if no extension is used, undefined behavior is still raised by // Even if no extension is used, undefined behavior is still raised by
// an empty function body and the noreturn attribute. // an empty function body and the noreturn attribute.
__assume(false); __assume(false);
#else // GCC, Clang #else // GCC, Clang
__builtin_unreachable(); __builtin_unreachable();
#endif #endif
} }
template <typename _Tp, typename... _Args> template<typename _Tp, typename... _Args>
struct assert { struct assert {
#ifdef _DEBUG #ifdef _DEBUG
explicit assert(_Tp &&condition, _Args &&...args, explicit assert(_Tp &&condition, _Args &&...args,
std::source_location location = std::source_location::current()) { std::source_location location = std::source_location::current()) {
if (condition) return; if (condition) return;
std::cerr << "Assertion failed at: " std::cerr << "Assertion failed at: "
<< location.file_name() << ":" << location.line() << "\n"; << location.file_name() << ":" << location.line() << "\n";
if constexpr (sizeof...(args) != 0) { if constexpr (sizeof...(args) != 0) {
std::cerr << "Message: "; std::cerr << "Message: ";
((std::cerr << args), ...) << std::endl; ((std::cerr << args), ...) << std::endl;
} }
std::exit(EXIT_FAILURE); std::exit(EXIT_FAILURE);
} }
#else #else
explicit assert(_Tp &&, _Args &&...) {} explicit assert(_Tp &&, _Args &&...) {}
#endif #endif
}; };
template <typename _Tp, typename... _Args> template<typename _Tp, typename... _Args>
assert(_Tp &&, _Args &&...) -> assert<_Tp, _Args...>; assert(_Tp &&, _Args &&...) -> assert<_Tp, _Args...>;
template <typename _Tp, _Tp _Default> template<typename _Tp, _Tp _Default>
struct DebugValue { struct DebugValue {
#ifdef _DEBUG #ifdef _DEBUG
private: private:
_Tp _M_value = _Default; _Tp _M_value = _Default;
public:
auto get_value() const { return this->_M_value; } public:
auto set_value(_Tp value) { this->_M_value = value; } auto get_value() const { return this->_M_value; }
auto set_value(_Tp value) { this->_M_value = value; }
#else #else
public: public:
auto get_value() const { return _Default; } auto get_value() const { return _Default; }
auto set_value(_Tp) { /* do nothing */ } auto set_value(_Tp) { /* do nothing */ }
#endif #endif
public: public:
explicit operator _Tp() const { return this->get_value(); } explicit operator _Tp() const { return this->get_value(); }
DebugValue &operator=(_Tp value) { this->set_value(value); return *this; } DebugValue &operator=(_Tp value) {
this->set_value(value);
return *this;
}
}; };
} // namespace dark::debug } // namespace dark::debug

View File

@ -16,4 +16,4 @@ struct Module : public ModuleBase, public _Tinput, public _Toutput, protected _T
} }
}; };
}// namespace dark } // namespace dark

View File

@ -3,127 +3,128 @@
namespace dark { namespace dark {
using dark::concepts::bit_match;
using dark::concepts::bit_type; using dark::concepts::bit_type;
using dark::concepts::int_type; using dark::concepts::int_type;
using dark::concepts::bit_match;
template <typename _Tp> template<typename _Tp>
constexpr auto cast(const _Tp& value) { constexpr auto cast(const _Tp &value) {
return static_cast <max_size_t> (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 { consteval auto get_common_length() -> std::size_t {
static_assert(bit_match <_Tp, _Up>); static_assert(bit_match<_Tp, _Up>);
if constexpr (bit_type <_Tp>) { if constexpr (bit_type<_Tp>) {
return _Tp::_Bit_Len; return _Tp::_Bit_Len;
} else { }
static_assert(bit_type <_Up>, "Invalid common length"); else {
return _Up::_Bit_Len; static_assert(bit_type<_Up>, "Invalid common length");
} return _Up::_Bit_Len;
}
} }
template <typename _Tp, typename _Up> template<typename _Tp, typename _Up>
requires bit_match <_Tp, _Up> requires bit_match<_Tp, _Up>
constexpr auto operator + (const _Tp &lhs, const _Up &rhs) { constexpr auto operator+(const _Tp &lhs, const _Up &rhs) {
constexpr auto _Len = get_common_length <_Tp, _Up>(); constexpr auto _Len = get_common_length<_Tp, _Up>();
return Bit <_Len> (cast(lhs) + cast(rhs)); return Bit<_Len>(cast(lhs) + cast(rhs));
} }
template <typename _Tp, typename _Up> template<typename _Tp, typename _Up>
requires bit_match <_Tp, _Up> requires bit_match<_Tp, _Up>
constexpr auto operator - (const _Tp &lhs, const _Up &rhs) { constexpr auto operator-(const _Tp &lhs, const _Up &rhs) {
constexpr auto _Len = get_common_length <_Tp, _Up>(); constexpr auto _Len = get_common_length<_Tp, _Up>();
return Bit <_Len> (cast(lhs) - cast(rhs)); return Bit<_Len>(cast(lhs) - cast(rhs));
} }
template <typename _Tp, typename _Up> template<typename _Tp, typename _Up>
requires bit_match <_Tp, _Up> requires bit_match<_Tp, _Up>
constexpr auto operator * (const _Tp &lhs, const _Up &rhs) { constexpr auto operator*(const _Tp &lhs, const _Up &rhs) {
constexpr auto _Len = get_common_length <_Tp, _Up>(); constexpr auto _Len = get_common_length<_Tp, _Up>();
return Bit <_Len> (cast(lhs) * cast(rhs)); return Bit<_Len>(cast(lhs) * cast(rhs));
} }
template <typename _Tp, typename _Up> template<typename _Tp, typename _Up>
requires bit_match <_Tp, _Up> requires bit_match<_Tp, _Up>
constexpr auto operator / (const _Tp &lhs, const _Up &rhs) { constexpr auto operator/(const _Tp &lhs, const _Up &rhs) {
constexpr auto _Len = get_common_length <_Tp, _Up>(); constexpr auto _Len = get_common_length<_Tp, _Up>();
return Bit <_Len> (cast(lhs) / cast(rhs)); return Bit<_Len>(cast(lhs) / cast(rhs));
} }
template <typename _Tp, typename _Up> template<typename _Tp, typename _Up>
requires bit_match <_Tp, _Up> requires bit_match<_Tp, _Up>
constexpr auto operator & (const _Tp &lhs, const _Up &rhs) { constexpr auto operator&(const _Tp &lhs, const _Up &rhs) {
constexpr auto _Len = get_common_length <_Tp, _Up>(); constexpr auto _Len = get_common_length<_Tp, _Up>();
return Bit <_Len> (cast(lhs) & cast(rhs)); return Bit<_Len>(cast(lhs) & cast(rhs));
} }
template <typename _Tp, typename _Up> template<typename _Tp, typename _Up>
requires bit_match <_Tp, _Up> requires bit_match<_Tp, _Up>
constexpr auto operator | (const _Tp &lhs, const _Up &rhs) { constexpr auto operator|(const _Tp &lhs, const _Up &rhs) {
constexpr auto _Len = get_common_length <_Tp, _Up>(); constexpr auto _Len = get_common_length<_Tp, _Up>();
return Bit <_Len> (cast(lhs) | cast(rhs)); return Bit<_Len>(cast(lhs) | cast(rhs));
} }
template <typename _Tp, typename _Up> template<typename _Tp, typename _Up>
requires bit_match <_Tp, _Up> requires bit_match<_Tp, _Up>
constexpr auto operator ^ (const _Tp &lhs, const _Up &rhs) { constexpr auto operator^(const _Tp &lhs, const _Up &rhs) {
constexpr auto _Len = get_common_length <_Tp, _Up>(); constexpr auto _Len = get_common_length<_Tp, _Up>();
return Bit <_Len> (cast(lhs) ^ cast(rhs)); return Bit<_Len>(cast(lhs) ^ cast(rhs));
} }
template <typename _Tp> template<typename _Tp>
concept int_or_bit = int_type <_Tp> || bit_type <_Tp>; concept int_or_bit = int_type<_Tp> || bit_type<_Tp>;
template <bit_type _Tp, int_or_bit _Up> template<bit_type _Tp, int_or_bit _Up>
constexpr auto operator << (const _Tp &lhs, const _Up &rhs) { constexpr auto operator<<(const _Tp &lhs, const _Up &rhs) {
return Bit <_Tp::_Bit_Len> (cast(lhs) << (cast(rhs) & kMaxLength)); return Bit<_Tp::_Bit_Len>(cast(lhs) << (cast(rhs) & kMaxLength));
} }
template <bit_type _Tp, int_or_bit _Up> template<bit_type _Tp, int_or_bit _Up>
constexpr auto operator >> (const _Tp &lhs, const _Up &rhs) { constexpr auto operator>>(const _Tp &lhs, const _Up &rhs) {
return Bit <_Tp::_Bit_Len> (cast(lhs) >> (cast(rhs) & kMaxLength)); return Bit<_Tp::_Bit_Len>(cast(lhs) >> (cast(rhs) & kMaxLength));
} }
template <bit_type _Tp> template<bit_type _Tp>
constexpr auto operator ~ (const _Tp &value) { constexpr auto operator~(const _Tp &value) {
return Bit <_Tp::_Bit_Len> (~cast(value)); return Bit<_Tp::_Bit_Len>(~cast(value));
} }
template <bit_type _Tp> template<bit_type _Tp>
constexpr auto operator ! (const _Tp &value) { constexpr auto operator!(const _Tp &value) {
return ~value; return ~value;
} }
template <bit_type _Tp> template<bit_type _Tp>
constexpr auto operator + (const _Tp &value) { constexpr auto operator+(const _Tp &value) {
return Bit <_Tp::_Bit_Len> (+cast(value)); return Bit<_Tp::_Bit_Len>(+cast(value));
} }
template <bit_type _Tp> template<bit_type _Tp>
constexpr auto operator - (const _Tp &value) { constexpr auto operator-(const _Tp &value) {
return Bit <_Tp::_Bit_Len> (-cast(value)); return Bit<_Tp::_Bit_Len>(-cast(value));
} }
template <int_or_bit _Tp, int_or_bit _Up> template<int_or_bit _Tp, int_or_bit _Up>
constexpr bool operator && (const _Tp &lhs, const _Up &rhs) { constexpr bool operator&&(const _Tp &lhs, const _Up &rhs) {
return cast(lhs) && cast(rhs); return cast(lhs) && cast(rhs);
} }
template <int_or_bit _Tp, int_or_bit _Up> template<int_or_bit _Tp, int_or_bit _Up>
constexpr bool operator || (const _Tp &lhs, const _Up &rhs) { constexpr bool operator||(const _Tp &lhs, const _Up &rhs) {
return cast(lhs) || cast(rhs); return cast(lhs) || cast(rhs);
} }
template <int_or_bit _Tp, int_or_bit _Up> template<int_or_bit _Tp, int_or_bit _Up>
constexpr bool operator == (const _Tp &lhs, const _Up &rhs) { constexpr bool operator==(const _Tp &lhs, const _Up &rhs) {
return cast(lhs) == cast(rhs); return cast(lhs) == cast(rhs);
} }
template <int_or_bit _Tp, int_or_bit _Up> template<int_or_bit _Tp, int_or_bit _Up>
constexpr auto operator <=> (const _Tp &lhs, const _Up &rhs) { constexpr auto operator<=>(const _Tp &lhs, const _Up &rhs) {
return cast(lhs) <=> cast(rhs); return cast(lhs) <=> cast(rhs);
} }

View File

@ -1,81 +1,104 @@
#pragma once #pragma once
#include <tuple>
#include <concepts> #include <concepts>
#include <tuple>
namespace dark::reflect { namespace dark::reflect {
/* A init helper to get the size of a struct. */ /* 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. */ /* 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 { inline consteval auto member_size_aux(auto &&...args) -> std::size_t {
constexpr std::size_t size = sizeof...(args); constexpr std::size_t size = sizeof...(args);
constexpr std::size_t maximum = 114; constexpr std::size_t maximum = 114;
if constexpr (size > maximum) { if constexpr (size > maximum) {
static_assert (sizeof(_Tp) == 0, "The struct has too many members."); static_assert(sizeof(_Tp) == 0, "The struct has too many members.");
} else if constexpr (!requires {_Tp { args... }; }) { }
return size - 1; else if constexpr (!requires { _Tp{args...}; }) {
} else { return size - 1;
return member_size_aux <_Tp> (args..., init_helper {}); }
} else {
return member_size_aux<_Tp>(args..., init_helper{});
}
} }
/* Return the member size for a aggregate type without base. */ /* Return the member size for a aggregate type without base. */
template <typename _Tp> requires std::is_aggregate_v <_Tp> template<typename _Tp>
inline consteval auto member_size(_Tp &) -> std::size_t { return member_size_aux <_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> template<typename _Tp>
inline consteval auto member_size() -> std::size_t { return member_size_aux <_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) { auto tuplify(_Tp &value) {
constexpr auto size = member_size <_Tp> (); constexpr auto size = member_size<_Tp>();
if constexpr (size == 1) { if constexpr (size == 1) {
auto &[x0] = value; auto &[x0] = value;
return std::forward_as_tuple(x0); return std::forward_as_tuple(x0);
} else if constexpr (size == 2) { }
auto &[x0, x1] = value; else if constexpr (size == 2) {
return std::forward_as_tuple(x0, x1); auto &[x0, x1] = value;
} else if constexpr (size == 3) { return std::forward_as_tuple(x0, x1);
auto &[x0, x1, x2] = value; }
return std::forward_as_tuple(x0, x1, x2); else if constexpr (size == 3) {
} else if constexpr (size == 4) { auto &[x0, x1, x2] = value;
auto &[x0, x1, x2, x3] = value; return std::forward_as_tuple(x0, x1, x2);
return std::forward_as_tuple(x0, x1, x2, x3); }
} else if constexpr (size == 5) { else if constexpr (size == 4) {
auto &[x0, x1, x2, x3, x4] = value; auto &[x0, x1, x2, x3] = value;
return std::forward_as_tuple(x0, x1, x2, x3, x4); return std::forward_as_tuple(x0, x1, x2, x3);
} else if constexpr (size == 6) { }
auto &[x0, x1, x2, x3, x4, x5] = value; else if constexpr (size == 5) {
return std::forward_as_tuple(x0, x1, x2, x3, x4, x5); auto &[x0, x1, x2, x3, x4] = value;
} else if constexpr (size == 7) { return std::forward_as_tuple(x0, x1, x2, x3, x4);
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 == 6) {
} else if constexpr (size == 8) { auto &[x0, x1, x2, x3, x4, x5] = value;
auto &[x0, x1, x2, x3, x4, x5, x6, x7] = value; return std::forward_as_tuple(x0, x1, x2, x3, x4, x5);
return std::forward_as_tuple(x0, x1, x2, x3, x4, x5, x6, x7); }
} else if constexpr (size == 9) { else if constexpr (size == 7) {
auto &[x0, x1, x2, x3, x4, x5, x6, x7, x8] = value; auto &[x0, x1, x2, x3, x4, x5, x6] = value;
return std::forward_as_tuple(x0, x1, x2, x3, x4, x5, x6, x7, x8); return std::forward_as_tuple(x0, x1, x2, x3, x4, x5, x6);
} else if constexpr (size == 10) { }
auto &[x0, x1, x2, x3, x4, x5, x6, x7, x8, x9] = value; else if constexpr (size == 8) {
return std::forward_as_tuple(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9); auto &[x0, x1, x2, x3, x4, x5, x6, x7] = value;
} else if constexpr (size == 11) { return std::forward_as_tuple(x0, x1, x2, x3, x4, x5, x6, x7);
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 == 9) {
} else if constexpr (size == 12) { auto &[x0, x1, x2, x3, x4, x5, x6, x7, x8] = value;
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);
return std::forward_as_tuple(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11); }
} else if constexpr (size == 13) { else if constexpr (size == 10) {
auto &[x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12] = value; 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, x10, x11, x12); return std::forward_as_tuple(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9);
} else if constexpr (size == 14) { }
auto &[x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13] = value; else if constexpr (size == 11) {
return std::forward_as_tuple(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13); auto &[x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10] = value;
} else { return std::forward_as_tuple(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10);
static_assert (sizeof(_Tp) == 0, "The struct has too many members."); }
} 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 } // namespace dark::reflect

View File

@ -1,46 +1,46 @@
#pragma once #pragma once
#include "debug.h"
#include "concept.h" #include "concept.h"
#include "debug.h"
namespace dark { namespace dark {
template <std::size_t _Len> template<std::size_t _Len>
struct Register { struct Register {
private: private:
static_assert(0 < _Len && _Len <= kMaxLength, static_assert(0 < _Len && _Len <= kMaxLength,
"Register: _Len must be in range [1, 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_old : _Len;
max_size_t _M_new : _Len; max_size_t _M_new : _Len;
[[no_unique_address]] [[no_unique_address]]
debug::DebugValue <bool, false> _M_assigned; debug::DebugValue<bool, false> _M_assigned;
void sync() { void sync() {
this->_M_assigned = false; this->_M_assigned = false;
this->_M_old = this->_M_new; this->_M_old = this->_M_new;
} }
public: public:
static constexpr std::size_t _Bit_Len = _Len; 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(Register &&) = delete;
Register(const Register &) = delete; Register(const Register &) = delete;
Register &operator=(Register &&) = delete; Register &operator=(Register &&) = delete;
Register &operator=(const Register &rhs) = delete; Register &operator=(const Register &rhs) = delete;
template <concepts::bit_convertible <_Len> _Tp> template<concepts::bit_convertible<_Len> _Tp>
void operator <= (const _Tp &value) { void operator<=(const _Tp &value) {
debug::assert(!this->_M_assigned, "Register is double assigned in this cycle."); debug::assert(!this->_M_assigned, "Register is double assigned in this cycle.");
this->_M_assigned = true; this->_M_assigned = true;
this->_M_new = static_cast <max_size_t> (value); 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 } // namespace dark

View File

@ -5,56 +5,62 @@
namespace dark { namespace dark {
struct Visitor { struct Visitor {
template <typename _Tp> template<typename _Tp>
static constexpr bool is_syncable_v = static constexpr bool is_syncable_v =
requires(_Tp &val) { { val.sync() } -> std::same_as<void>; }; requires(_Tp &val) { { val.sync() } -> std::same_as<void>; };
template <typename _Tp> requires is_syncable_v<_Tp> template<typename _Tp>
static void sync(_Tp &val) { val.sync(); } requires is_syncable_v<_Tp>
static void sync(_Tp &val) { val.sync(); }
template <typename _Tp, typename _Base> template<typename _Tp, typename _Base>
static _Base &cast(_Tp &value) { return static_cast<_Base &>(value); } static _Base &cast(_Tp &value) { return static_cast<_Base &>(value); }
}; };
template <typename ..._Base> template<typename... _Base>
struct SyncTags {}; struct SyncTags {};
template <typename _Tp> template<typename _Tp>
static constexpr bool is_valid_tag_v = false; static constexpr bool is_valid_tag_v = false;
template <typename ..._Base> template<typename... _Base>
static constexpr bool is_valid_tag_v<SyncTags<_Base...>> = true; 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>; 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>; 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; static constexpr bool is_std_array_v<std::array<_Tp, _Nm>> = true;
template <typename _Tp> template<typename _Tp>
inline void sync_member(_Tp &value); 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...>) { 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) { inline void sync_member(_Tp &value) {
if constexpr (std::is_const_v <_Tp>) { if constexpr (std::is_const_v<_Tp>) {
/* Do nothing! Constant members need no synchronization! */ /* 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 (is_std_array_v<_Tp>) {
} else if constexpr (Visitor::is_syncable_v<_Tp>) { for (auto &member: value) sync_member(member);
Visitor::sync(value); }
} else if constexpr (has_valid_tag<_Tp>) { else if constexpr (Visitor::is_syncable_v<_Tp>) {
sync_by_tag(value, typename _Tp::Tags {}); Visitor::sync(value);
} else if constexpr (std::is_aggregate_v<_Tp>) { }
auto &&tuple = reflect::tuplify(value); else if constexpr (has_valid_tag<_Tp>) {
std::apply([](auto &...members) { (sync_member(members), ...); }, tuple); sync_by_tag(value, typename _Tp::Tags{});
} else { }
static_assert(sizeof(_Tp) == 0, "This type is not syncable."); 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

View File

@ -1,31 +1,31 @@
#pragma once #pragma once
#include "bit.h" #include "bit.h"
#include "bit_impl.h" #include "bit_impl.h"
#include "wire.h" #include "operator.h"
#include "register.h" #include "register.h"
#include "synchronize.h" #include "synchronize.h"
#include "operator.h" #include "wire.h"
using dark::Bit; using dark::Bit;
using dark::sign_extend; using dark::sign_extend;
using dark::zero_extend; using dark::zero_extend;
using dark::Wire;
using dark::Register; using dark::Register;
using dark::Wire;
using dark::SyncTags;
using dark::sync_member; using dark::sync_member;
using dark::SyncTags;
using dark::Visitor; using dark::Visitor;
using dark::max_size_t; using dark::max_size_t;
using dark::max_ssize_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) { 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) { 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));
} }

View File

@ -1,113 +1,112 @@
#pragma once #pragma once
#include "debug.h"
#include "concept.h" #include "concept.h"
#include "debug.h"
#include <memory> #include <memory>
namespace dark { namespace dark {
namespace details { namespace details {
template <typename _Fn, std::size_t _Len> template<typename _Fn, std::size_t _Len>
concept WireFunction = concept WireFunction =
concepts::bit_convertible <std::decay_t <std::invoke_result_t <_Fn>>, _Len>; concepts::bit_convertible<std::decay_t<std::invoke_result_t<_Fn>>, _Len>;
struct FuncBase { struct FuncBase {
using _Ret_t = max_size_t; using _Ret_t = max_size_t;
using _Cpy_t = FuncBase *; using _Cpy_t = FuncBase *;
virtual _Ret_t call() const = 0; virtual _Ret_t call() const = 0;
virtual _Cpy_t copy() const = 0; virtual _Cpy_t copy() const = 0;
virtual ~FuncBase() = default; virtual ~FuncBase() = default;
}; };
template <std::size_t _Len, WireFunction <_Len> _Fn> template<std::size_t _Len, WireFunction<_Len> _Fn>
struct FuncImpl final : FuncBase { struct FuncImpl final : FuncBase {
_Fn _M_lambda; _Fn _M_lambda;
template <typename _Tp> template<typename _Tp>
FuncImpl(_Tp &&fn) : _M_lambda(std::forward <_Tp> (fn)) {} FuncImpl(_Tp &&fn) : _M_lambda(std::forward<_Tp>(fn)) {}
_Ret_t call() const override { return static_cast <_Ret_t> (this->_M_lambda()); } _Ret_t call() const override { return static_cast<_Ret_t>(this->_M_lambda()); }
_Cpy_t copy() const override { return new FuncImpl(*this); } _Cpy_t copy() const override { return new FuncImpl(*this); }
}; };
struct EmptyWire final : FuncBase { struct EmptyWire final : FuncBase {
_Ret_t call() const override { _Ret_t call() const override {
debug::assert(false, "Empty wire is called."); debug::assert(false, "Empty wire is called.");
debug::unreachable(); debug::unreachable();
} }
_Cpy_t copy() const override { return new EmptyWire; } _Cpy_t copy() const override { return new EmptyWire; }
}; };
} // namespace details } // namespace details
template <std::size_t _Len> template<std::size_t _Len>
struct Wire { struct Wire {
private: private:
static_assert(0 < _Len && _Len <= kMaxLength, static_assert(0 < _Len && _Len <= kMaxLength,
"Wire: _Len must be in range [1, 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 max_size_t _M_cache : _Len;
mutable bool _M_holds; mutable bool _M_holds;
[[no_unique_address]] [[no_unique_address]]
debug::DebugValue <bool, false> _M_assigned; debug::DebugValue<bool, false> _M_assigned;
void sync() { this->_M_holds = false; } private:
void sync() { this->_M_holds = false; }
template <details::WireFunction <_Len> _Fn> template<details::WireFunction<_Len> _Fn>
static auto _M_new_func(_Fn &&fn) { static auto _M_new_func(_Fn &&fn) {
using _Decay_t = std::decay_t <_Fn>; using _Decay_t = std::decay_t<_Fn>;
return new details::FuncImpl <_Len, _Decay_t> {std::forward <_Fn>(fn)}; return new details::FuncImpl<_Len, _Decay_t>{std::forward<_Fn>(fn)};
} }
void _M_checked_assign() { void _M_checked_assign() {
debug::assert(!this->_M_assigned, "Wire is assigned twice."); debug::assert(!this->_M_assigned, "Wire is assigned twice.");
this->_M_assigned = true; this->_M_assigned = true;
} }
public: public:
static constexpr std::size_t _Bit_Len = _Len; static constexpr std::size_t _Bit_Len = _Len;
Wire() : Wire() : _M_func(new details::EmptyWire),
_M_func(new details::EmptyWire), _M_cache(), _M_holds(), _M_assigned() {}
_M_cache(), _M_holds(), _M_assigned() {}
explicit operator max_size_t() const { explicit operator max_size_t() const {
if (this->_M_holds == false) { if (this->_M_holds == false) {
this->_M_holds = true; this->_M_holds = true;
this->_M_cache = this->_M_func->call(); this->_M_cache = this->_M_func->call();
} }
return this->_M_cache; return this->_M_cache;
} }
Wire(Wire &&) = delete; Wire(Wire &&) = delete;
Wire(const Wire &) = delete; Wire(const Wire &) = delete;
Wire &operator=(Wire &&) = delete; Wire &operator=(Wire &&) = delete;
Wire &operator=(const Wire &rhs) = delete; Wire &operator=(const Wire &rhs) = delete;
template <details::WireFunction <_Len> _Fn> template<details::WireFunction<_Len> _Fn>
Wire(_Fn &&fn) : Wire(_Fn &&fn) : _M_func(_M_new_func(std::forward<_Fn>(fn))),
_M_func(_M_new_func(std::forward <_Fn> (fn))), _M_cache(), _M_holds(), _M_assigned() {}
_M_cache(), _M_holds(), _M_assigned() {}
template <details::WireFunction <_Len> _Fn> template<details::WireFunction<_Len> _Fn>
Wire &operator=(_Fn &&fn) { Wire &operator=(_Fn &&fn) {
return this->assign(std::forward <_Fn> (fn)), *this; return this->assign(std::forward<_Fn>(fn)), *this;
} }
template <details::WireFunction <_Len> _Fn> template<details::WireFunction<_Len> _Fn>
void assign(_Fn &&fn) { void assign(_Fn &&fn) {
this->_M_checked_assign(); this->_M_checked_assign();
this->_M_func.reset(_M_new_func(std::forward <_Fn> (fn))); this->_M_func.reset(_M_new_func(std::forward<_Fn>(fn)));
this->sync(); this->sync();
} }
}; };