flexarray.h 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. #ifndef AL_FLEXARRAY_H
  2. #define AL_FLEXARRAY_H
  3. #include <algorithm>
  4. #include <cstddef>
  5. #include <iterator>
  6. #include <memory>
  7. #include <new>
  8. #include <type_traits>
  9. #include "almalloc.h"
  10. #include "alspan.h"
  11. namespace al {
  12. /* Storage for flexible array data. This is trivially destructible if type T is
  13. * trivially destructible.
  14. */
  15. template<typename T, size_t alignment, bool = std::is_trivially_destructible<T>::value>
  16. struct alignas(alignment) FlexArrayStorage : al::span<T> {
  17. /* NOLINTBEGIN(bugprone-sizeof-expression) clang-tidy warns about the
  18. * sizeof(T) being suspicious when T is a pointer type, which it will be
  19. * for flexible arrays of pointers.
  20. */
  21. static constexpr size_t Sizeof(size_t count, size_t base=0u) noexcept
  22. { return sizeof(FlexArrayStorage) + sizeof(T)*count + base; }
  23. /* NOLINTEND(bugprone-sizeof-expression) */
  24. /* NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) Flexible
  25. * arrays store their payloads after the end of the object, which must be
  26. * the last in the whole parent chain.
  27. */
  28. FlexArrayStorage(size_t size) noexcept(std::is_nothrow_constructible_v<T>)
  29. : al::span<T>{::new(static_cast<void*>(this+1)) T[size], size}
  30. { }
  31. /* NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic) */
  32. ~FlexArrayStorage() = default;
  33. FlexArrayStorage(const FlexArrayStorage&) = delete;
  34. FlexArrayStorage& operator=(const FlexArrayStorage&) = delete;
  35. };
  36. template<typename T, size_t alignment>
  37. struct alignas(alignment) FlexArrayStorage<T,alignment,false> : al::span<T> {
  38. static constexpr size_t Sizeof(size_t count, size_t base=0u) noexcept
  39. { return sizeof(FlexArrayStorage) + sizeof(T)*count + base; }
  40. /* NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) */
  41. FlexArrayStorage(size_t size) noexcept(std::is_nothrow_constructible_v<T>)
  42. : al::span<T>{::new(static_cast<void*>(this+1)) T[size], size}
  43. { }
  44. /* NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic) */
  45. ~FlexArrayStorage() { std::destroy(this->begin(), this->end()); }
  46. FlexArrayStorage(const FlexArrayStorage&) = delete;
  47. FlexArrayStorage& operator=(const FlexArrayStorage&) = delete;
  48. };
  49. /* A flexible array type. Used either standalone or at the end of a parent
  50. * struct, to have a run-time-sized array that's embedded with its size. Should
  51. * be used delicately, ensuring there's no additional data after the FlexArray
  52. * member.
  53. */
  54. template<typename T, size_t Align=alignof(T)>
  55. struct FlexArray {
  56. using element_type = T;
  57. using value_type = std::remove_cv_t<T>;
  58. using index_type = size_t;
  59. using difference_type = ptrdiff_t;
  60. using pointer = T*;
  61. using const_pointer = const T*;
  62. using reference = T&;
  63. using const_reference = const T&;
  64. static constexpr std::size_t StorageAlign{std::max(alignof(T), Align)};
  65. using Storage_t_ = FlexArrayStorage<element_type,std::max(alignof(al::span<T>), StorageAlign)>;
  66. using iterator = typename Storage_t_::iterator;
  67. using const_iterator = typename Storage_t_::const_iterator;
  68. using reverse_iterator = typename Storage_t_::reverse_iterator;
  69. using const_reverse_iterator = typename Storage_t_::const_reverse_iterator;
  70. const Storage_t_ mStore;
  71. static constexpr index_type Sizeof(index_type count, index_type base=0u) noexcept
  72. { return Storage_t_::Sizeof(count, base); }
  73. static std::unique_ptr<FlexArray> Create(index_type count)
  74. { return std::unique_ptr<FlexArray>{new(FamCount{count}) FlexArray{count}}; }
  75. FlexArray(index_type size) noexcept(std::is_nothrow_constructible_v<Storage_t_,index_type>)
  76. : mStore{size}
  77. { }
  78. ~FlexArray() = default;
  79. [[nodiscard]] auto size() const noexcept -> index_type { return mStore.size(); }
  80. [[nodiscard]] auto empty() const noexcept -> bool { return mStore.empty(); }
  81. [[nodiscard]] auto data() noexcept -> pointer { return mStore.data(); }
  82. [[nodiscard]] auto data() const noexcept -> const_pointer { return mStore.data(); }
  83. [[nodiscard]] auto operator[](index_type i) noexcept -> reference { return mStore[i]; }
  84. [[nodiscard]] auto operator[](index_type i) const noexcept -> const_reference { return mStore[i]; }
  85. [[nodiscard]] auto front() noexcept -> reference { return mStore.front(); }
  86. [[nodiscard]] auto front() const noexcept -> const_reference { return mStore.front(); }
  87. [[nodiscard]] auto back() noexcept -> reference { return mStore.back(); }
  88. [[nodiscard]] auto back() const noexcept -> const_reference { return mStore.back(); }
  89. [[nodiscard]] auto begin() noexcept -> iterator { return mStore.begin(); }
  90. [[nodiscard]] auto begin() const noexcept -> const_iterator { return mStore.cbegin(); }
  91. [[nodiscard]] auto cbegin() const noexcept -> const_iterator { return mStore.cbegin(); }
  92. [[nodiscard]] auto end() noexcept -> iterator { return mStore.end(); }
  93. [[nodiscard]] auto end() const noexcept -> const_iterator { return mStore.cend(); }
  94. [[nodiscard]] auto cend() const noexcept -> const_iterator { return mStore.cend(); }
  95. [[nodiscard]] auto rbegin() noexcept -> reverse_iterator { return mStore.rbegin(); }
  96. [[nodiscard]] auto rbegin() const noexcept -> const_reverse_iterator { return mStore.crbegin(); }
  97. [[nodiscard]] auto crbegin() const noexcept -> const_reverse_iterator { return mStore.crbegin(); }
  98. [[nodiscard]] auto rend() noexcept -> reverse_iterator { return mStore.rend(); }
  99. [[nodiscard]] auto rend() const noexcept -> const_reverse_iterator { return mStore.crend(); }
  100. [[nodiscard]] auto crend() const noexcept -> const_reverse_iterator { return mStore.crend(); }
  101. gsl::owner<void*> operator new(size_t, FamCount count)
  102. { return ::operator new[](Sizeof(count), std::align_val_t{alignof(FlexArray)}); }
  103. void operator delete(gsl::owner<void*> block, FamCount) noexcept
  104. { ::operator delete[](block, std::align_val_t{alignof(FlexArray)}); }
  105. void operator delete(gsl::owner<void*> block) noexcept
  106. { ::operator delete[](block, std::align_val_t{alignof(FlexArray)}); }
  107. void *operator new(size_t size) = delete;
  108. void *operator new[](size_t size) = delete;
  109. void operator delete[](void *block) = delete;
  110. };
  111. } // namespace al
  112. #endif /* AL_FLEXARRAY_H */