#ifndef AL_FLEXARRAY_H #define AL_FLEXARRAY_H #include #include #include #include #include "almalloc.h" #include "alspan.h" namespace al { /* Storage for flexible array data. This is trivially destructible if type T is * trivially destructible. */ template::value> struct alignas(std::max(alignment, alignof(al::span))) FlexArrayStorage : al::span { static constexpr size_t Sizeof(size_t count, size_t base=0u) noexcept { return sizeof(FlexArrayStorage) + sizeof(T)*count + base; } FlexArrayStorage(size_t size) noexcept(std::is_nothrow_constructible_v) : al::span{::new(static_cast(this+1)) T[size], size} { } ~FlexArrayStorage() = default; FlexArrayStorage(const FlexArrayStorage&) = delete; FlexArrayStorage& operator=(const FlexArrayStorage&) = delete; }; template struct alignas(std::max(alignment, alignof(al::span))) FlexArrayStorage : al::span { static constexpr size_t Sizeof(size_t count, size_t base=0u) noexcept { return sizeof(FlexArrayStorage) + sizeof(T)*count + base; } FlexArrayStorage(size_t size) noexcept(std::is_nothrow_constructible_v) : al::span{::new(static_cast(this+1)) T[size], size} { } ~FlexArrayStorage() { std::destroy(this->begin(), this->end()); } FlexArrayStorage(const FlexArrayStorage&) = delete; FlexArrayStorage& operator=(const FlexArrayStorage&) = delete; }; /* A flexible array type. Used either standalone or at the end of a parent * struct, to have a run-time-sized array that's embedded with its size. Should * be used delicately, ensuring there's no additional data after the FlexArray * member. */ template struct FlexArray { using element_type = T; using value_type = std::remove_cv_t; using index_type = size_t; using difference_type = ptrdiff_t; using pointer = T*; using const_pointer = const T*; using reference = T&; using const_reference = const T&; using iterator = pointer; using const_iterator = const_pointer; using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; static constexpr size_t alignment{std::max(alignof(T), Align)}; using Storage_t_ = FlexArrayStorage; const Storage_t_ mStore; static constexpr index_type Sizeof(index_type count, index_type base=0u) noexcept { return Storage_t_::Sizeof(count, base); } static std::unique_ptr Create(index_type count) { return std::unique_ptr{new(FamCount{count}) FlexArray{count}}; } FlexArray(index_type size) noexcept(std::is_nothrow_constructible_v) : mStore{size} { } ~FlexArray() = default; [[nodiscard]] auto size() const noexcept -> index_type { return mStore.size(); } [[nodiscard]] auto empty() const noexcept -> bool { return mStore.empty(); } [[nodiscard]] auto data() noexcept -> pointer { return mStore.data(); } [[nodiscard]] auto data() const noexcept -> const_pointer { return mStore.data(); } [[nodiscard]] auto operator[](index_type i) noexcept -> reference { return mStore[i]; } [[nodiscard]] auto operator[](index_type i) const noexcept -> const_reference { return mStore[i]; } [[nodiscard]] auto front() noexcept -> reference { return mStore.front(); } [[nodiscard]] auto front() const noexcept -> const_reference { return mStore.front(); } [[nodiscard]] auto back() noexcept -> reference { return mStore.back(); } [[nodiscard]] auto back() const noexcept -> const_reference { return mStore.back(); } [[nodiscard]] auto begin() noexcept -> iterator { return mStore.begin(); } [[nodiscard]] auto begin() const noexcept -> const_iterator { return mStore.cbegin(); } [[nodiscard]] auto cbegin() const noexcept -> const_iterator { return mStore.cbegin(); } [[nodiscard]] auto end() noexcept -> iterator { return mStore.end(); } [[nodiscard]] auto end() const noexcept -> const_iterator { return mStore.cend(); } [[nodiscard]] auto cend() const noexcept -> const_iterator { return mStore.cend(); } [[nodiscard]] auto rbegin() noexcept -> reverse_iterator { return end(); } [[nodiscard]] auto rbegin() const noexcept -> const_reverse_iterator { return cend(); } [[nodiscard]] auto crbegin() const noexcept -> const_reverse_iterator { return cend(); } [[nodiscard]] auto rend() noexcept -> reverse_iterator { return begin(); } [[nodiscard]] auto rend() const noexcept -> const_reverse_iterator { return cbegin(); } [[nodiscard]] auto crend() const noexcept -> const_reverse_iterator { return cbegin(); } gsl::owner operator new(size_t, FamCount count) { return ::operator new[](Sizeof(count), std::align_val_t{alignof(FlexArray)}); } void operator delete(gsl::owner block, FamCount) noexcept { ::operator delete[](block, std::align_val_t{alignof(FlexArray)}); } void operator delete(gsl::owner block) noexcept { ::operator delete[](block, std::align_val_t{alignof(FlexArray)}); } void *operator new(size_t size) = delete; void *operator new[](size_t size) = delete; void operator delete[](void *block) = delete; }; } // namespace al #endif /* AL_FLEXARRAY_H */