diff --git a/funreg.hpp b/funreg.hpp index accdb9d..dc646aa 100644 --- a/funreg.hpp +++ b/funreg.hpp @@ -86,20 +86,18 @@ requires IsAccess struct Register; template -concept IsRegister = requires { - requires IsAccess; - requires std::same_as>; -}; +concept IsRegister = + IsAccess && + std::same_as>; #else template requires(std::unsigned_integral) class Register; template -concept IsRegister = requires { - requires std::unsigned_integral; - requires IsAccess; -}; +concept IsRegister = + std::unsigned_integral && + IsAccess; #endif template @@ -107,10 +105,21 @@ requires IsRegister struct RegisterMask; template -concept IsRegisterMask = requires { - requires IsRegister; - requires std::same_as>; -}; +concept IsRegisterMask = + IsRegister && + std::same_as>; + +template +concept UsesRegister = + IsRegisterMask && + IsRegister && + std::same_as; + +template +concept UsesSomeRegister = + IsRegisterMask && + (IsRegister, ...) && + (std::same_as || ...); /** * @struct Register @@ -156,7 +165,8 @@ public: * Sets register bits to '1' according to the given RegisterMasks. */ template - requires(IsRegisterMask, ...) + requires((IsRegisterMask, ...) && + (UsesRegister>, ...)) static void set() { apply([](auto r, auto m) { return r | m; }); } @@ -172,7 +182,8 @@ public: * Clears register bits to '0' according to the given RegisterMasks. */ template - requires(IsRegisterMask, ...) + requires((IsRegisterMask, ...) && + (UsesRegister>, ...)) static void clear() { apply([](auto r, auto m) { return r & ~m; }); } @@ -188,7 +199,8 @@ public: * Toggles bits in the register according to the given RegisterMasks. */ template - requires(IsRegisterMask, ...) + requires((IsRegisterMask, ...) && + (UsesRegister>, ...)) static void toggle() { apply([](auto r, auto m) { return r ^m; }); } @@ -206,7 +218,8 @@ public: * If no masks are given, all register bits are returned. */ template - requires(IsRegisterMask, ...) + requires((IsRegisterMask, ...) && + (UsesRegister>, ...)) static auto read() { if constexpr (sizeof...(Masks) > 0) return read() & mergeMasks(); @@ -219,7 +232,8 @@ public: * If no masks are given, tests if the register has a non-zero value. */ template - requires(IsRegisterMask, ...) + requires((IsRegisterMask, ...) && + (UsesRegister>, ...)) static bool test() { if constexpr (sizeof...(Masks) > 0) { auto mask = mergeMasks(); @@ -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 - requires(IsRegisterMask, ...) - static void apply(auto fn) { + constexpr static void apply(auto fn) { if constexpr (sizeof...(Masks) > 0) { - auto mask = mergeMasks(); + constexpr auto mask = mergeMasks(); 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 - requires(IsRegisterMask, ...) - static auto mergeMasks() { + constexpr static auto mergeMasks() { if constexpr (sizeof...(Masks) > 0) { if constexpr ((isThis | ...)) { auto mask = @@ -482,7 +496,8 @@ public: * only written once. */ template - requires(IsRegisterMask, ...) + requires((IsRegisterMask, ...) && + (UsesSomeRegister, ...)) static void set() { apply([](auto r, auto m) { return r | m; }); } @@ -493,7 +508,8 @@ public: * Only reads and writes each register once; see set(). */ template - requires(IsRegisterMask, ...) + requires((IsRegisterMask, ...) && + (UsesSomeRegister, ...)) static void clear() { apply([](auto r, auto m) { return r & ~m; }); } @@ -504,7 +520,8 @@ public: * Only reads and writes each register once; see set(). */ template - requires(IsRegisterMask, ...) + requires((IsRegisterMask, ...) && + (UsesSomeRegister, ...)) static void toggle() { apply([](auto r, auto m) { return r ^ m; }); } @@ -523,6 +540,8 @@ public: private: template + requires((IsRegisterMask, ...) && + (UsesSomeRegister, ...)) static void apply(auto fn) { (Registers::template apply(fn), ...); }