diff options
| author | Richard Qin <richard.qin.x@gmail.com> | 2026-11-04 01:30:57 +0800 |
|---|---|---|
| committer | Richard Qin <richard.qin.x@gmail.com> | 2026-11-04 01:30:57 +0800 |
| commit | b66474ea45515d495366c4afe3ede647a30c7390 (patch) | |
| tree | a82370f6849ceaaea433ba4d3a57d06ab786c8d0 /libbase/include/core/memory/Alignment.h | |
| parent | 19ce3dbf1682dcac869580b39e4ccb420649d33a (diff) | |
| download | rcc-project-b66474ea45515d495366c4afe3ede647a30c7390.tar.gz rcc-project-b66474ea45515d495366c4afe3ede647a30c7390.tar.xz | |
Signed-off-by: Richard Qin <richard.qin.x@gmail.com>
Diffstat (limited to 'libbase/include/core/memory/Alignment.h')
| -rw-r--r-- | libbase/include/core/memory/Alignment.h | 407 |
1 files changed, 281 insertions, 126 deletions
diff --git a/libbase/include/core/memory/Alignment.h b/libbase/include/core/memory/Alignment.h index 4078cd6..1391e06 100644 --- a/libbase/include/core/memory/Alignment.h +++ b/libbase/include/core/memory/Alignment.h @@ -49,50 +49,65 @@ #include <string> #endif // NDEBUG -namespace libbase { +namespace libbase +{ #define ALIGN_CHECK_ISPOSITIVE(decl) \ - assert(decl > 0 && (#decl " should be defined")) + assert (decl > 0 && (#decl " should be defined")) /// This struct is a compact representation of a valid (non-zero power of two) /// alignment. /// It is suitable for use as static global constants. -struct Align { +struct Align +{ private: uint8_t ShiftValue = 0; /// The log2 of the required alignment. /// ShiftValue is less than 64 by construction. friend struct MaybeAlign; - friend unsigned Log2(Align); - friend bool operator==(Align Lhs, Align Rhs); - friend bool operator!=(Align Lhs, Align Rhs); - friend bool operator<=(Align Lhs, Align Rhs); - friend bool operator>=(Align Lhs, Align Rhs); - friend bool operator<(Align Lhs, Align Rhs); - friend bool operator>(Align Lhs, Align Rhs); - friend unsigned encode(struct MaybeAlign A); - friend struct MaybeAlign decodeMaybeAlign(unsigned Value); + friend unsigned Log2 (Align); + friend bool + operator== (Align Lhs, Align Rhs); + friend bool + operator!= (Align Lhs, Align Rhs); + friend bool + operator<= (Align Lhs, Align Rhs); + friend bool + operator>= (Align Lhs, Align Rhs); + friend bool + operator< (Align Lhs, Align Rhs); + friend bool + operator> (Align Lhs, Align Rhs); + friend unsigned + encode (struct MaybeAlign A); + friend struct MaybeAlign + decodeMaybeAlign (unsigned Value); public: /// Default is byte-aligned. - constexpr Align() = default; + constexpr Align () = default; /// Do not perform checks in case of copy/move construct/assign, because the /// checks have been performed when building `Other`. - constexpr Align(const Align &Other) = default; - constexpr Align(Align &&Other) = default; - constexpr Align &operator=(const Align &Other) = default; - constexpr Align &operator=(Align &&Other) = default; - - explicit Align(uint64_t Value) { - assert(Value > 0 && "Value must not be 0"); - assert(libbase::isPowerOf2_64(Value) && "Alignment is not a power of 2"); - ShiftValue = Log2_64(Value); - assert(ShiftValue < 64 && "Broken invariant"); + constexpr Align (const Align &Other) = default; + constexpr Align (Align &&Other) = default; + constexpr Align & + operator= (const Align &Other) = default; + constexpr Align & + operator= (Align &&Other) = default; + + explicit Align (uint64_t Value) + { + assert (Value > 0 && "Value must not be 0"); + assert (libbase::isPowerOf2_64 (Value) && "Alignment is not a power of 2"); + ShiftValue = Log2_64 (Value); + assert (ShiftValue < 64 && "Broken invariant"); } /// Returns an alignment of `1 << Log2Value` bytes. - constexpr static Align fromLog2(unsigned Log2Value) { - assert(Log2Value < 64 && "Alignment exponent is too large"); + constexpr static Align + fromLog2 (unsigned Log2Value) + { + assert (Log2Value < 64 && "Alignment exponent is too large"); Align Out; Out.ShiftValue = Log2Value; return Out; @@ -100,75 +115,109 @@ public: /// This is a hole in the type system and should not be abused. /// Needed to interact with C for instance. - constexpr uint64_t value() const { return uint64_t(1) << ShiftValue; } + constexpr uint64_t + value () const + { + return uint64_t (1) << ShiftValue; + } // Returns the previous alignment. - Align previous() const { - assert(ShiftValue != 0 && "Undefined operation"); + Align + previous () const + { + assert (ShiftValue != 0 && "Undefined operation"); Align Out; Out.ShiftValue = ShiftValue - 1; return Out; } /// Allow constructions of constexpr Align. - template <size_t kValue> constexpr static Align Constant() { - return fromLog2(ConstantLog2<kValue>()); + template <size_t kValue> + constexpr static Align + Constant () + { + return fromLog2 (ConstantLog2<kValue> ()); } /// Allow constructions of constexpr Align from types. /// Compile time equivalent to Align(alignof(T)). - template <typename T> constexpr static Align Of() { - return Constant<std::alignment_of_v<T>>(); + template <typename T> + constexpr static Align + Of () + { + return Constant<std::alignment_of_v<T>> (); } }; /// Treats the value 0 as a 1, so Align is always at least 1. -inline Align assumeAligned(uint64_t Value) { - return Value ? Align(Value) : Align(); +inline Align +assumeAligned (uint64_t Value) +{ + return Value ? Align (Value) : Align (); } /// This struct is a compact representation of a valid (power of two) or /// undefined (0) alignment. -struct MaybeAlign : std::optional<Align> { +struct MaybeAlign : std::optional<Align> +{ private: using UP = std::optional<Align>; public: /// Default is undefined. - MaybeAlign() = default; + MaybeAlign () = default; /// Do not perform checks in case of copy/move construct/assign, because the /// checks have been performed when building `Other`. - MaybeAlign(const MaybeAlign &Other) = default; - MaybeAlign &operator=(const MaybeAlign &Other) = default; - MaybeAlign(MaybeAlign &&Other) = default; - MaybeAlign &operator=(MaybeAlign &&Other) = default; - - constexpr MaybeAlign(std::nullopt_t None) : UP(None) {} - constexpr MaybeAlign(Align Value) : UP(Value) {} - explicit MaybeAlign(uint64_t Value) { - assert((Value == 0 || libbase::isPowerOf2_64(Value)) && - "Alignment is neither 0 nor a power of 2"); + MaybeAlign (const MaybeAlign &Other) = default; + MaybeAlign & + operator= (const MaybeAlign &Other) = default; + MaybeAlign (MaybeAlign &&Other) = default; + MaybeAlign & + operator= (MaybeAlign &&Other) = default; + + constexpr MaybeAlign (std::nullopt_t None) : UP (None) + { + } + constexpr MaybeAlign (Align Value) : UP (Value) + { + } + explicit MaybeAlign (uint64_t Value) + { + assert ((Value == 0 || libbase::isPowerOf2_64 (Value)) && + "Alignment is neither 0 nor a power of 2"); if (Value) - emplace(Value); + { + emplace (Value); + } } /// For convenience, returns a valid alignment or 1 if undefined. - Align valueOrOne() const { return value_or(Align()); } + Align + valueOrOne () const + { + return value_or (Align ()); + } }; /// Checks that SizeInBytes is a multiple of the alignment. -inline bool isAligned(Align Lhs, uint64_t SizeInBytes) { - return SizeInBytes % Lhs.value() == 0; +inline bool +isAligned (Align Lhs, uint64_t SizeInBytes) +{ + return SizeInBytes % Lhs.value () == 0; } /// Checks that Addr is a multiple of the alignment. -inline bool isAddrAligned(Align Lhs, const void *Addr) { - return isAligned(Lhs, reinterpret_cast<uintptr_t>(Addr)); +inline bool +isAddrAligned (Align Lhs, const void *Addr) +{ + return isAligned (Lhs, reinterpret_cast<uintptr_t> (Addr)); } /// Returns a multiple of A needed to store `Size` bytes. -constexpr inline uint64_t alignTo(uint64_t Size, Align A) { - const uint64_t Value = A.value(); +constexpr inline uint64_t +alignTo (uint64_t Size, Align A) +{ + const uint64_t Value = A.value (); // The following line is equivalent to `(Size + Value - 1) / Value * Value`. // The division followed by a multiplication can be thought of as a right @@ -192,49 +241,71 @@ constexpr inline uint64_t alignTo(uint64_t Size, Align A) { /// alignTo(17, Align(8), 1) = 17 /// alignTo(~0LL, Align(8), 3) = 3 /// \endcode -inline uint64_t alignTo(uint64_t Size, Align A, uint64_t Skew) { - const uint64_t Value = A.value(); +inline uint64_t +alignTo (uint64_t Size, Align A, uint64_t Skew) +{ + const uint64_t Value = A.value (); Skew %= Value; - return alignTo(Size - Skew, A) + Skew; + return alignTo (Size - Skew, A) + Skew; } /// Aligns `Addr` to `Alignment` bytes, rounding up. -inline uintptr_t alignAddr(const void *Addr, Align Alignment) { - uintptr_t ArithAddr = reinterpret_cast<uintptr_t>(Addr); - assert(static_cast<uintptr_t>(ArithAddr + Alignment.value() - 1) >= - ArithAddr && - "Overflow"); - return alignTo(ArithAddr, Alignment); +inline uintptr_t +alignAddr (const void *Addr, Align Alignment) +{ + uintptr_t ArithAddr = reinterpret_cast<uintptr_t> (Addr); + assert (static_cast<uintptr_t> (ArithAddr + Alignment.value () - 1) >= + ArithAddr && + "Overflow"); + return alignTo (ArithAddr, Alignment); } /// Returns the offset to the next integer (mod 2**64) that is greater than /// or equal to \p Value and is a multiple of \p Align. -inline uint64_t offsetToAlignment(uint64_t Value, Align Alignment) { - return alignTo(Value, Alignment) - Value; +inline uint64_t +offsetToAlignment (uint64_t Value, Align Alignment) +{ + return alignTo (Value, Alignment) - Value; } /// Returns the necessary adjustment for aligning `Addr` to `Alignment` /// bytes, rounding up. -inline uint64_t offsetToAlignedAddr(const void *Addr, Align Alignment) { - return offsetToAlignment(reinterpret_cast<uintptr_t>(Addr), Alignment); +inline uint64_t +offsetToAlignedAddr (const void *Addr, Align Alignment) +{ + return offsetToAlignment (reinterpret_cast<uintptr_t> (Addr), Alignment); } /// Returns the log2 of the alignment. -inline unsigned Log2(Align A) { return A.ShiftValue; } +inline unsigned +Log2 (Align A) +{ + return A.ShiftValue; +} /// Returns the alignment that satisfies both alignments. /// Same semantic as MinAlign. -inline Align commonAlignment(Align A, uint64_t Offset) { - return Align(MinAlign(A.value(), Offset)); +inline Align +commonAlignment (Align A, uint64_t Offset) +{ + return Align (MinAlign (A.value (), Offset)); } /// Returns a representation of the alignment that encodes undefined as 0. -inline unsigned encode(MaybeAlign A) { return A ? A->ShiftValue + 1 : 0; } +inline unsigned +encode (MaybeAlign A) +{ + return A ? A->ShiftValue + 1 : 0; +} /// Dual operation of the encode function above. -inline MaybeAlign decodeMaybeAlign(unsigned Value) { +inline MaybeAlign +decodeMaybeAlign (unsigned Value) +{ if (Value == 0) - return MaybeAlign(); + { + return MaybeAlign (); + } Align Out; Out.ShiftValue = Value - 1; return Out; @@ -242,95 +313,179 @@ inline MaybeAlign decodeMaybeAlign(unsigned Value) { /// Returns a representation of the alignment, the encoded value is positive by /// definition. -inline unsigned encode(Align A) { return encode(MaybeAlign(A)); } +inline unsigned +encode (Align A) +{ + return encode (MaybeAlign (A)); +} /// Comparisons between Align and scalars. Rhs must be positive. -inline bool operator==(Align Lhs, uint64_t Rhs) { - ALIGN_CHECK_ISPOSITIVE(Rhs); - return Lhs.value() == Rhs; +inline bool +operator== (Align Lhs, uint64_t Rhs) +{ + ALIGN_CHECK_ISPOSITIVE (Rhs); + return Lhs.value () == Rhs; } -inline bool operator!=(Align Lhs, uint64_t Rhs) { - ALIGN_CHECK_ISPOSITIVE(Rhs); - return Lhs.value() != Rhs; +inline bool +operator!= (Align Lhs, uint64_t Rhs) +{ + ALIGN_CHECK_ISPOSITIVE (Rhs); + return Lhs.value () != Rhs; } -inline bool operator<=(Align Lhs, uint64_t Rhs) { - ALIGN_CHECK_ISPOSITIVE(Rhs); - return Lhs.value() <= Rhs; +inline bool +operator<= (Align Lhs, uint64_t Rhs) +{ + ALIGN_CHECK_ISPOSITIVE (Rhs); + return Lhs.value () <= Rhs; } -inline bool operator>=(Align Lhs, uint64_t Rhs) { - ALIGN_CHECK_ISPOSITIVE(Rhs); - return Lhs.value() >= Rhs; +inline bool +operator>= (Align Lhs, uint64_t Rhs) +{ + ALIGN_CHECK_ISPOSITIVE (Rhs); + return Lhs.value () >= Rhs; } -inline bool operator<(Align Lhs, uint64_t Rhs) { - ALIGN_CHECK_ISPOSITIVE(Rhs); - return Lhs.value() < Rhs; +inline bool +operator< (Align Lhs, uint64_t Rhs) +{ + ALIGN_CHECK_ISPOSITIVE (Rhs); + return Lhs.value () < Rhs; } -inline bool operator>(Align Lhs, uint64_t Rhs) { - ALIGN_CHECK_ISPOSITIVE(Rhs); - return Lhs.value() > Rhs; +inline bool +operator> (Align Lhs, uint64_t Rhs) +{ + ALIGN_CHECK_ISPOSITIVE (Rhs); + return Lhs.value () > Rhs; } /// Comparisons operators between Align. -inline bool operator==(Align Lhs, Align Rhs) { +inline bool +operator== (Align Lhs, Align Rhs) +{ return Lhs.ShiftValue == Rhs.ShiftValue; } -inline bool operator!=(Align Lhs, Align Rhs) { +inline bool +operator!= (Align Lhs, Align Rhs) +{ return Lhs.ShiftValue != Rhs.ShiftValue; } -inline bool operator<=(Align Lhs, Align Rhs) { +inline bool +operator<= (Align Lhs, Align Rhs) +{ return Lhs.ShiftValue <= Rhs.ShiftValue; } -inline bool operator>=(Align Lhs, Align Rhs) { +inline bool +operator>= (Align Lhs, Align Rhs) +{ return Lhs.ShiftValue >= Rhs.ShiftValue; } -inline bool operator<(Align Lhs, Align Rhs) { +inline bool +operator< (Align Lhs, Align Rhs) +{ return Lhs.ShiftValue < Rhs.ShiftValue; } -inline bool operator>(Align Lhs, Align Rhs) { +inline bool +operator> (Align Lhs, Align Rhs) +{ return Lhs.ShiftValue > Rhs.ShiftValue; } // Don't allow relational comparisons with MaybeAlign. -bool operator<=(Align Lhs, MaybeAlign Rhs) = delete; -bool operator>=(Align Lhs, MaybeAlign Rhs) = delete; -bool operator<(Align Lhs, MaybeAlign Rhs) = delete; -bool operator>(Align Lhs, MaybeAlign Rhs) = delete; - -bool operator<=(MaybeAlign Lhs, Align Rhs) = delete; -bool operator>=(MaybeAlign Lhs, Align Rhs) = delete; -bool operator<(MaybeAlign Lhs, Align Rhs) = delete; -bool operator>(MaybeAlign Lhs, Align Rhs) = delete; - -bool operator<=(MaybeAlign Lhs, MaybeAlign Rhs) = delete; -bool operator>=(MaybeAlign Lhs, MaybeAlign Rhs) = delete; -bool operator<(MaybeAlign Lhs, MaybeAlign Rhs) = delete; -bool operator>(MaybeAlign Lhs, MaybeAlign Rhs) = delete; +bool +operator<= (Align Lhs, MaybeAlign Rhs) = delete; +bool +operator>= (Align Lhs, MaybeAlign Rhs) = delete; +bool +operator< (Align Lhs, MaybeAlign Rhs) = delete; +bool +operator> (Align Lhs, MaybeAlign Rhs) = delete; + +bool +operator<= (MaybeAlign Lhs, Align Rhs) = delete; +bool +operator>= (MaybeAlign Lhs, Align Rhs) = delete; +bool +operator< (MaybeAlign Lhs, Align Rhs) = delete; +bool +operator> (MaybeAlign Lhs, Align Rhs) = delete; + +bool +operator<= (MaybeAlign Lhs, MaybeAlign Rhs) = delete; +bool +operator>= (MaybeAlign Lhs, MaybeAlign Rhs) = delete; +bool +operator< (MaybeAlign Lhs, MaybeAlign Rhs) = delete; +bool +operator> (MaybeAlign Lhs, MaybeAlign Rhs) = delete; // Allow equality comparisons between Align and MaybeAlign. -inline bool operator==(MaybeAlign Lhs, Align Rhs) { return Lhs && *Lhs == Rhs; } -inline bool operator!=(MaybeAlign Lhs, Align Rhs) { return !(Lhs == Rhs); } -inline bool operator==(Align Lhs, MaybeAlign Rhs) { return Rhs == Lhs; } -inline bool operator!=(Align Lhs, MaybeAlign Rhs) { return !(Rhs == Lhs); } +inline bool +operator== (MaybeAlign Lhs, Align Rhs) +{ + return Lhs && *Lhs == Rhs; +} +inline bool +operator!= (MaybeAlign Lhs, Align Rhs) +{ + return !(Lhs == Rhs); +} +inline bool +operator== (Align Lhs, MaybeAlign Rhs) +{ + return Rhs == Lhs; +} +inline bool +operator!= (Align Lhs, MaybeAlign Rhs) +{ + return !(Rhs == Lhs); +} // Allow equality comparisons with MaybeAlign. -inline bool operator==(MaybeAlign Lhs, MaybeAlign Rhs) { +inline bool +operator== (MaybeAlign Lhs, MaybeAlign Rhs) +{ return (Lhs && Rhs && (*Lhs == *Rhs)) || (!Lhs && !Rhs); } -inline bool operator!=(MaybeAlign Lhs, MaybeAlign Rhs) { return !(Lhs == Rhs); } +inline bool +operator!= (MaybeAlign Lhs, MaybeAlign Rhs) +{ + return !(Lhs == Rhs); +} // Allow equality comparisons with std::nullopt. -inline bool operator==(MaybeAlign Lhs, std::nullopt_t) { return !bool(Lhs); } -inline bool operator!=(MaybeAlign Lhs, std::nullopt_t) { return bool(Lhs); } -inline bool operator==(std::nullopt_t, MaybeAlign Rhs) { return !bool(Rhs); } -inline bool operator!=(std::nullopt_t, MaybeAlign Rhs) { return bool(Rhs); } +inline bool +operator== (MaybeAlign Lhs, std::nullopt_t) +{ + return !bool (Lhs); +} +inline bool +operator!= (MaybeAlign Lhs, std::nullopt_t) +{ + return bool (Lhs); +} +inline bool +operator== (std::nullopt_t, MaybeAlign Rhs) +{ + return !bool (Rhs); +} +inline bool +operator!= (std::nullopt_t, MaybeAlign Rhs) +{ + return bool (Rhs); +} #ifndef NDEBUG // For usage in LLVM_DEBUG macros. -inline std::string DebugStr(const Align &A) { - return std::to_string(A.value()); +inline std::string +DebugStr (const Align &A) +{ + return std::to_string (A.value ()); } // For usage in LLVM_DEBUG macros. -inline std::string DebugStr(const MaybeAlign &MA) { +inline std::string +DebugStr (const MaybeAlign &MA) +{ if (MA) - return std::to_string(MA->value()); + { + return std::to_string (MA->value ()); + } return "None"; } #endif // NDEBUG |
