diff options
author | Clyne <clyne@bitgloo.com> | 2022-08-11 08:10:34 -0400 |
---|---|---|
committer | Clyne <clyne@bitgloo.com> | 2022-08-11 08:10:34 -0400 |
commit | 2e6001946fd4b8b450e8023662e2192a94972f25 (patch) | |
tree | 1a345cd9cbdeca9debc4cd07a832d9394b75ed61 | |
parent | 922489447fda4a0975aefcc1045cfaac744be598 (diff) |
Verify register and mask parameterserror-checking
-rw-r--r-- | funreg.hpp | 75 |
1 files changed, 47 insertions, 28 deletions
@@ -86,20 +86,18 @@ requires IsAccess<Access> struct Register; template<typename T> -concept IsRegister = requires { - requires IsAccess<typename T::access>; - requires std::same_as<T, Register<typename T::access>>; -}; +concept IsRegister = + IsAccess<typename T::access> && + std::same_as<T, Register<typename T::access>>; #else template<typename T, uintptr_t Addr> requires(std::unsigned_integral<T>) class Register; template<typename T> -concept IsRegister = requires { - requires std::unsigned_integral<typename T::type>; - requires IsAccess<typename T::Access>; -}; +concept IsRegister = + std::unsigned_integral<typename T::type> && + IsAccess<typename T::Access>; #endif template<typename Reg, typename Reg::type Mask> @@ -107,10 +105,21 @@ requires IsRegister<Reg> struct RegisterMask; template<typename T> -concept IsRegisterMask = requires { - requires IsRegister<typename T::reg>; - requires std::same_as<T, RegisterMask<typename T::reg, T::mask>>; -}; +concept IsRegisterMask = + IsRegister<typename T::reg> && + std::same_as<T, RegisterMask<typename T::reg, T::mask>>; + +template<typename M, typename R> +concept UsesRegister = + IsRegisterMask<M> && + IsRegister<R> && + std::same_as<typename M::reg, R>; + +template<typename M, typename... Rs> +concept UsesSomeRegister = + IsRegisterMask<M> && + (IsRegister<Rs>, ...) && + (std::same_as<typename M::reg, Rs> || ...); /** * @struct Register @@ -156,7 +165,8 @@ public: * Sets register bits to '1' according to the given RegisterMasks. */ template<typename... Masks> - requires(IsRegisterMask<Masks>, ...) + requires((IsRegisterMask<Masks>, ...) && + (UsesRegister<Masks, Register<Access>>, ...)) static void set() { apply<Masks...>([](auto r, auto m) { return r | m; }); } @@ -172,7 +182,8 @@ public: * Clears register bits to '0' according to the given RegisterMasks. */ template<typename... Masks> - requires(IsRegisterMask<Masks>, ...) + requires((IsRegisterMask<Masks>, ...) && + (UsesRegister<Masks, Register<Access>>, ...)) static void clear() { apply<Masks...>([](auto r, auto m) { return r & ~m; }); } @@ -188,7 +199,8 @@ public: * Toggles bits in the register according to the given RegisterMasks. */ template<typename... Masks> - requires(IsRegisterMask<Masks>, ...) + requires((IsRegisterMask<Masks>, ...) && + (UsesRegister<Masks, Register<Access>>, ...)) static void toggle() { apply<Masks...>([](auto r, auto m) { return r ^m; }); } @@ -206,7 +218,8 @@ public: * If no masks are given, all register bits are returned. */ template<typename... Masks> - requires(IsRegisterMask<Masks>, ...) + requires((IsRegisterMask<Masks>, ...) && + (UsesRegister<Masks, Register<Access>>, ...)) static auto read() { if constexpr (sizeof...(Masks) > 0) return read() & mergeMasks<Masks...>(); @@ -219,7 +232,8 @@ public: * If no masks are given, tests if the register has a non-zero value. */ template<typename... Masks> - requires(IsRegisterMask<Masks>, ...) + requires((IsRegisterMask<Masks>, ...) && + (UsesRegister<Masks, Register<Access>>, ...)) static bool test() { if constexpr (sizeof...(Masks) > 0) { auto mask = mergeMasks<Masks...>(); @@ -248,16 +262,16 @@ public: } } -private: + // Internal use only. // Applies bit-masks to the register through the provided function. - // The provided function receives a pointer to the register's data and a - // bit-mask created by merging all provided bit-masks. + // All masks meant for this register are merged together; then, `fn` + // will receive the register's current value and the mask to carry out + // the operation. The result is written back to the register. // If no masks are given, a mask selecting all bits is used. template<typename... Masks> - requires(IsRegisterMask<Masks>, ...) - static void apply(auto fn) { + constexpr static void apply(auto fn) { if constexpr (sizeof...(Masks) > 0) { - auto mask = mergeMasks<Masks...>(); + constexpr auto mask = mergeMasks<Masks...>(); if constexpr (mask) write(fn(read(), mask)); } else { @@ -265,11 +279,11 @@ private: } } +private: // Takes a list of bit-masks, and returns a merged mask of those which are // meant for this register. template<typename... Masks> - requires(IsRegisterMask<Masks>, ...) - static auto mergeMasks() { + constexpr static auto mergeMasks() { if constexpr (sizeof...(Masks) > 0) { if constexpr ((isThis<typename Masks::reg> | ...)) { auto mask = @@ -482,7 +496,8 @@ public: * only written once. */ template<typename... Masks> - requires(IsRegisterMask<Masks>, ...) + requires((IsRegisterMask<Masks>, ...) && + (UsesSomeRegister<Masks, Registers...>, ...)) static void set() { apply<Masks...>([](auto r, auto m) { return r | m; }); } @@ -493,7 +508,8 @@ public: * Only reads and writes each register once; see set(). */ template<typename... Masks> - requires(IsRegisterMask<Masks>, ...) + requires((IsRegisterMask<Masks>, ...) && + (UsesSomeRegister<Masks, Registers...>, ...)) static void clear() { apply<Masks...>([](auto r, auto m) { return r & ~m; }); } @@ -504,7 +520,8 @@ public: * Only reads and writes each register once; see set(). */ template<typename... Masks> - requires(IsRegisterMask<Masks>, ...) + requires((IsRegisterMask<Masks>, ...) && + (UsesSomeRegister<Masks, Registers...>, ...)) static void toggle() { apply<Masks...>([](auto r, auto m) { return r ^ m; }); } @@ -523,6 +540,8 @@ public: private: template<typename... Masks> + requires((IsRegisterMask<Masks>, ...) && + (UsesSomeRegister<Masks, Registers...>, ...)) static void apply(auto fn) { (Registers::template apply<Masks...>(fn), ...); } |