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
#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

View File

@ -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

View File

@ -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

View File

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

View File

@ -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

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 {
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);
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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));
}

View File

@ -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();
}
};