| |
| |
|
|
| #pragma once |
|
|
| #include <bit> |
| #include <cstddef> |
| #include <new> |
| #include <type_traits> |
|
|
| namespace Common { |
|
|
| template <typename T> |
| requires std::is_integral_v<T> |
| [[nodiscard]] constexpr T AlignUp(T value_, size_t size) { |
| using U = typename std::make_unsigned_t<T>; |
| auto value{static_cast<U>(value_)}; |
| auto mod{static_cast<T>(value % size)}; |
| value -= mod; |
| return static_cast<T>(mod == T{0} ? value : value + size); |
| } |
|
|
| template <typename T> |
| requires std::is_unsigned_v<T> |
| [[nodiscard]] constexpr T AlignUpLog2(T value, size_t align_log2) { |
| return static_cast<T>((value + ((1ULL << align_log2) - 1)) >> align_log2 << align_log2); |
| } |
|
|
| template <typename T> |
| requires std::is_integral_v<T> |
| [[nodiscard]] constexpr T AlignDown(T value_, size_t size) { |
| using U = typename std::make_unsigned_t<T>; |
| const auto value{static_cast<U>(value_)}; |
| return static_cast<T>(value - value % size); |
| } |
|
|
| template <typename T> |
| requires std::is_unsigned_v<T> |
| [[nodiscard]] constexpr bool Is4KBAligned(T value) { |
| return (value & 0xFFF) == 0; |
| } |
|
|
| template <typename T> |
| requires std::is_unsigned_v<T> |
| [[nodiscard]] constexpr bool IsWordAligned(T value) { |
| return (value & 0b11) == 0; |
| } |
|
|
| template <typename T> |
| requires std::is_integral_v<T> |
| [[nodiscard]] constexpr bool IsAligned(T value, size_t alignment) { |
| using U = typename std::make_unsigned_t<T>; |
| const U mask = static_cast<U>(alignment - 1); |
| return (value & mask) == 0; |
| } |
|
|
| template <typename T, typename U> |
| requires std::is_integral_v<T> |
| [[nodiscard]] constexpr T DivideUp(T x, U y) { |
| return (x + (y - 1)) / y; |
| } |
|
|
| template <typename T> |
| requires std::is_integral_v<T> |
| [[nodiscard]] constexpr T LeastSignificantOneBit(T x) { |
| return x & ~(x - 1); |
| } |
|
|
| template <typename T> |
| requires std::is_integral_v<T> |
| [[nodiscard]] constexpr T ResetLeastSignificantOneBit(T x) { |
| return x & (x - 1); |
| } |
|
|
| template <typename T> |
| requires std::is_integral_v<T> |
| [[nodiscard]] constexpr bool IsPowerOfTwo(T x) { |
| return x > 0 && ResetLeastSignificantOneBit(x) == 0; |
| } |
|
|
| template <typename T> |
| requires std::is_integral_v<T> |
| [[nodiscard]] constexpr T FloorPowerOfTwo(T x) { |
| return T{1} << (sizeof(T) * 8 - std::countl_zero(x) - 1); |
| } |
|
|
| template <typename T, size_t Align = 16> |
| class AlignmentAllocator { |
| public: |
| using value_type = T; |
| using size_type = size_t; |
| using difference_type = ptrdiff_t; |
|
|
| using propagate_on_container_copy_assignment = std::true_type; |
| using propagate_on_container_move_assignment = std::true_type; |
| using propagate_on_container_swap = std::true_type; |
| using is_always_equal = std::false_type; |
|
|
| constexpr AlignmentAllocator() noexcept = default; |
|
|
| template <typename T2> |
| constexpr AlignmentAllocator(const AlignmentAllocator<T2, Align>&) noexcept {} |
|
|
| [[nodiscard]] T* allocate(size_type n) { |
| return static_cast<T*>(::operator new(n * sizeof(T), std::align_val_t{Align})); |
| } |
|
|
| void deallocate(T* p, size_type n) { |
| ::operator delete(p, n * sizeof(T), std::align_val_t{Align}); |
| } |
|
|
| template <typename T2> |
| struct rebind { |
| using other = AlignmentAllocator<T2, Align>; |
| }; |
|
|
| template <typename T2, size_t Align2> |
| constexpr bool operator==(const AlignmentAllocator<T2, Align2>&) const noexcept { |
| return std::is_same_v<T, T2> && Align == Align2; |
| } |
| }; |
|
|
| } |
|
|