Clean up some variable initialization
[openal-soft.git] / common / flexarray.h
blobacfdd26971898abb49542705aa2a2fe072e05764
1 #ifndef AL_FLEXARRAY_H
2 #define AL_FLEXARRAY_H
4 #include <algorithm>
5 #include <cstddef>
6 #include <stdexcept>
7 #include <type_traits>
9 #include "almalloc.h"
10 #include "alspan.h"
12 namespace al {
14 /* Storage for flexible array data. This is trivially destructible if type T is
15 * trivially destructible.
17 template<typename T, size_t alignment, bool = std::is_trivially_destructible<T>::value>
18 struct alignas(std::max(alignment, alignof(al::span<T>))) FlexArrayStorage : al::span<T> {
19 /* NOLINTBEGIN(bugprone-sizeof-expression) clang-tidy warns about the
20 * sizeof(T) being suspicious when T is a pointer type, which it will be
21 * for flexible arrays of pointers.
23 static constexpr size_t Sizeof(size_t count, size_t base=0u) noexcept
24 { return sizeof(FlexArrayStorage) + sizeof(T)*count + base; }
25 /* NOLINTEND(bugprone-sizeof-expression) */
27 FlexArrayStorage(size_t size) noexcept(std::is_nothrow_constructible_v<T>)
28 : al::span<T>{::new(static_cast<void*>(this+1)) T[size], size}
29 { }
30 ~FlexArrayStorage() = default;
32 FlexArrayStorage(const FlexArrayStorage&) = delete;
33 FlexArrayStorage& operator=(const FlexArrayStorage&) = delete;
36 template<typename T, size_t alignment>
37 struct alignas(std::max(alignment, alignof(al::span<T>))) 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; }
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 ~FlexArrayStorage() { std::destroy(this->begin(), this->end()); }
46 FlexArrayStorage(const FlexArrayStorage&) = delete;
47 FlexArrayStorage& operator=(const FlexArrayStorage&) = delete;
50 /* A flexible array type. Used either standalone or at the end of a parent
51 * struct, to have a run-time-sized array that's embedded with its size. Should
52 * be used delicately, ensuring there's no additional data after the FlexArray
53 * member.
55 template<typename T, size_t Align=alignof(T)>
56 struct FlexArray {
57 using element_type = T;
58 using value_type = std::remove_cv_t<T>;
59 using index_type = size_t;
60 using difference_type = ptrdiff_t;
62 using pointer = T*;
63 using const_pointer = const T*;
64 using reference = T&;
65 using const_reference = const T&;
67 using iterator = pointer;
68 using const_iterator = const_pointer;
69 using reverse_iterator = std::reverse_iterator<iterator>;
70 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
72 static constexpr size_t alignment{std::max(alignof(T), Align)};
73 using Storage_t_ = FlexArrayStorage<element_type,alignment>;
75 const Storage_t_ mStore;
77 static constexpr index_type Sizeof(index_type count, index_type base=0u) noexcept
78 { return Storage_t_::Sizeof(count, base); }
79 static std::unique_ptr<FlexArray> Create(index_type count)
80 { return std::unique_ptr<FlexArray>{new(FamCount{count}) FlexArray{count}}; }
82 FlexArray(index_type size) noexcept(std::is_nothrow_constructible_v<Storage_t_,index_type>)
83 : mStore{size}
84 { }
85 ~FlexArray() = default;
87 [[nodiscard]] auto size() const noexcept -> index_type { return mStore.size(); }
88 [[nodiscard]] auto empty() const noexcept -> bool { return mStore.empty(); }
90 [[nodiscard]] auto data() noexcept -> pointer { return mStore.data(); }
91 [[nodiscard]] auto data() const noexcept -> const_pointer { return mStore.data(); }
93 [[nodiscard]] auto operator[](index_type i) noexcept -> reference { return mStore[i]; }
94 [[nodiscard]] auto operator[](index_type i) const noexcept -> const_reference { return mStore[i]; }
96 [[nodiscard]] auto front() noexcept -> reference { return mStore.front(); }
97 [[nodiscard]] auto front() const noexcept -> const_reference { return mStore.front(); }
99 [[nodiscard]] auto back() noexcept -> reference { return mStore.back(); }
100 [[nodiscard]] auto back() const noexcept -> const_reference { return mStore.back(); }
102 [[nodiscard]] auto begin() noexcept -> iterator { return mStore.begin(); }
103 [[nodiscard]] auto begin() const noexcept -> const_iterator { return mStore.cbegin(); }
104 [[nodiscard]] auto cbegin() const noexcept -> const_iterator { return mStore.cbegin(); }
105 [[nodiscard]] auto end() noexcept -> iterator { return mStore.end(); }
106 [[nodiscard]] auto end() const noexcept -> const_iterator { return mStore.cend(); }
107 [[nodiscard]] auto cend() const noexcept -> const_iterator { return mStore.cend(); }
109 [[nodiscard]] auto rbegin() noexcept -> reverse_iterator { return end(); }
110 [[nodiscard]] auto rbegin() const noexcept -> const_reverse_iterator { return cend(); }
111 [[nodiscard]] auto crbegin() const noexcept -> const_reverse_iterator { return cend(); }
112 [[nodiscard]] auto rend() noexcept -> reverse_iterator { return begin(); }
113 [[nodiscard]] auto rend() const noexcept -> const_reverse_iterator { return cbegin(); }
114 [[nodiscard]] auto crend() const noexcept -> const_reverse_iterator { return cbegin(); }
116 gsl::owner<void*> operator new(size_t, FamCount count)
117 { return ::operator new[](Sizeof(count), std::align_val_t{alignof(FlexArray)}); }
118 void operator delete(gsl::owner<void*> block, FamCount) noexcept
119 { ::operator delete[](block, std::align_val_t{alignof(FlexArray)}); }
120 void operator delete(gsl::owner<void*> block) noexcept
121 { ::operator delete[](block, std::align_val_t{alignof(FlexArray)}); }
123 void *operator new(size_t size) = delete;
124 void *operator new[](size_t size) = delete;
125 void operator delete[](void *block) = delete;
128 } // namespace al
130 #endif /* AL_FLEXARRAY_H */