duckstation

duckstation, but archived from the revision just before upstream changed it to a proprietary software project, this version is the libre one
git clone https://git.neptards.moe/u3shit/duckstation.git
Log | Files | Refs | README | LICENSE

align.h (4228B)


      1 // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
      2 // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
      3 
      4 #pragma once
      5 
      6 #include "types.h"
      7 
      8 #include <cstdlib>
      9 #include <memory>
     10 #include <type_traits>
     11 
     12 #ifdef _MSC_VER
     13 #include <malloc.h>
     14 #endif
     15 
     16 namespace Common {
     17 template<typename T>
     18 constexpr bool IsAligned(T value, unsigned int alignment)
     19 {
     20   return (value % static_cast<T>(alignment)) == 0;
     21 }
     22 template<typename T>
     23 constexpr T AlignUp(T value, unsigned int alignment)
     24 {
     25   return (value + static_cast<T>(alignment - 1)) / static_cast<T>(alignment) * static_cast<T>(alignment);
     26 }
     27 template<typename T>
     28 constexpr T AlignDown(T value, unsigned int alignment)
     29 {
     30   return value / static_cast<T>(alignment) * static_cast<T>(alignment);
     31 }
     32 template<typename T>
     33 constexpr bool IsAlignedPow2(T value, unsigned int alignment)
     34 {
     35   return (value & static_cast<T>(alignment - 1)) == 0;
     36 }
     37 template<typename T>
     38 constexpr T AlignUpPow2(T value, unsigned int alignment)
     39 {
     40   return (value + static_cast<T>(alignment - 1)) & static_cast<T>(~static_cast<T>(alignment - 1));
     41 }
     42 template<typename T>
     43 constexpr T AlignDownPow2(T value, unsigned int alignment)
     44 {
     45   return value & static_cast<T>(~static_cast<T>(alignment - 1));
     46 }
     47 template<typename T>
     48 constexpr bool IsPow2(T value)
     49 {
     50   return (value & (value - 1)) == 0;
     51 }
     52 template<typename T>
     53 constexpr T PreviousPow2(T value)
     54 {
     55   if (value == static_cast<T>(0))
     56     return 0;
     57 
     58   value |= (value >> 1);
     59   value |= (value >> 2);
     60   value |= (value >> 4);
     61   if constexpr (sizeof(T) >= 16)
     62     value |= (value >> 8);
     63   if constexpr (sizeof(T) >= 32)
     64     value |= (value >> 16);
     65   if constexpr (sizeof(T) >= 64)
     66     value |= (value >> 32);
     67   return value - (value >> 1);
     68 }
     69 template<typename T>
     70 constexpr T NextPow2(T value)
     71 {
     72   // https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
     73   if (value == static_cast<T>(0))
     74     return 0;
     75 
     76   value--;
     77   value |= (value >> 1);
     78   value |= (value >> 2);
     79   value |= (value >> 4);
     80   if constexpr (sizeof(T) >= 16)
     81     value |= (value >> 8);
     82   if constexpr (sizeof(T) >= 32)
     83     value |= (value >> 16);
     84   if constexpr (sizeof(T) >= 64)
     85     value |= (value >> 32);
     86   value++;
     87   return value;
     88 }
     89 
     90 ALWAYS_INLINE static void* AlignedMalloc(size_t size, size_t alignment)
     91 {
     92 #ifdef _MSC_VER
     93   return _aligned_malloc(size, alignment);
     94 #else
     95   // Unaligned sizes are slow on macOS.
     96 #ifdef __APPLE__
     97   if (IsPow2(alignment))
     98     size = (size + alignment - 1) & ~(alignment - 1);
     99 #endif
    100   void* ret = nullptr;
    101   return (posix_memalign(&ret, alignment, size) == 0) ? ret : nullptr;
    102 #endif
    103 }
    104 
    105 ALWAYS_INLINE static void AlignedFree(void* ptr)
    106 {
    107 #ifdef _MSC_VER
    108   _aligned_free(ptr);
    109 #else
    110   free(ptr);
    111 #endif
    112 }
    113 
    114 namespace detail {
    115 template<class T>
    116 struct unique_aligned_ptr_deleter
    117 {
    118   ALWAYS_INLINE void operator()(T* ptr) { Common::AlignedFree(ptr); }
    119 };
    120 
    121 template<class>
    122 constexpr bool is_unbounded_array_v = false;
    123 template<class T>
    124 constexpr bool is_unbounded_array_v<T[]> = true;
    125 
    126 template<class>
    127 constexpr bool is_bounded_array_v = false;
    128 template<class T, std::size_t N>
    129 constexpr bool is_bounded_array_v<T[N]> = true;
    130 } // namespace detail
    131 
    132 template<class T>
    133 using unique_aligned_ptr = std::unique_ptr<T, detail::unique_aligned_ptr_deleter<std::remove_extent_t<T>>>;
    134 
    135 template<class T, class... Args>
    136   requires(std::is_unbounded_array_v<T>, std::is_trivially_default_constructible_v<std::remove_extent_t<T>>,
    137            std::is_trivially_destructible_v<std::remove_extent_t<T>>)
    138 unique_aligned_ptr<T> make_unique_aligned(size_t alignment, size_t n)
    139 {
    140   unique_aligned_ptr<T> ptr(
    141     static_cast<std::remove_extent_t<T>*>(AlignedMalloc(sizeof(std::remove_extent_t<T>) * n, alignment)));
    142   if (ptr)
    143     new (ptr.get()) std::remove_extent_t<T>[ n ]();
    144   return ptr;
    145 }
    146 
    147 template<class T, class... Args>
    148   requires(std::is_unbounded_array_v<T>, std::is_trivially_default_constructible_v<std::remove_extent_t<T>>,
    149            std::is_trivially_destructible_v<std::remove_extent_t<T>>)
    150 unique_aligned_ptr<T> make_unique_aligned_for_overwrite(size_t alignment, size_t n)
    151 {
    152   return unique_aligned_ptr<T>(
    153     static_cast<std::remove_extent_t<T>*>(AlignedMalloc(sizeof(std::remove_extent_t<T>) * n, alignment)));
    154 }
    155 
    156 } // namespace Common