You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
127 lines
3.0 KiB
127 lines
3.0 KiB
#pragma once |
|
|
|
#include <cstddef> |
|
#include <initializer_list> |
|
#include <memory> |
|
#include <utility> |
|
|
|
#include "appfat.h" |
|
#include "utils/attributes.h" |
|
|
|
namespace devilution { |
|
|
|
/** |
|
* @brief A stack-allocated vector with a fixed capacity. |
|
* |
|
* @tparam T element type. |
|
* @tparam N capacity. |
|
*/ |
|
template <class T, size_t N> |
|
class StaticVector { |
|
public: |
|
using value_type = T; |
|
using reference = T &; |
|
using const_reference = const T &; |
|
using pointer = T *; |
|
using const_pointer = const T *; |
|
using size_type = size_t; |
|
using iterator = T *; |
|
using const_iterator = const T *; |
|
using difference_type = std::ptrdiff_t; |
|
|
|
StaticVector() = default; |
|
|
|
template <typename U> |
|
StaticVector(std::initializer_list<U> elements) |
|
{ |
|
for (auto &&element : elements) { |
|
emplace_back(element); |
|
} |
|
} |
|
|
|
[[nodiscard]] const T *begin() const { return &(*this)[0]; } |
|
[[nodiscard]] T *begin() { return &(*this)[0]; } |
|
|
|
[[nodiscard]] const T *end() const { return begin() + size_; } |
|
[[nodiscard]] T *end() { return begin() + size_; } |
|
|
|
[[nodiscard]] size_t size() const { return size_; } |
|
|
|
[[nodiscard]] bool empty() const DVL_PURE { return size_ == 0; } |
|
|
|
[[nodiscard]] const T &front() const { return (*this)[0]; } |
|
[[nodiscard]] T &front() { return (*this)[0]; } |
|
|
|
[[nodiscard]] const T &back() const { return (*this)[size_ - 1]; } |
|
[[nodiscard]] T &back() { return (*this)[size_ - 1]; } |
|
|
|
[[nodiscard]] const T *data() const { return data_[0].ptr(); } |
|
[[nodiscard]] T *data() { return data_[0].ptr(); } |
|
|
|
template <typename... Args> |
|
void push_back(Args &&...args) // NOLINT(readability-identifier-naming) |
|
{ |
|
emplace_back(std::forward<Args>(args)...); |
|
} |
|
|
|
template <typename... Args> |
|
T &emplace_back(Args &&...args) // NOLINT(readability-identifier-naming) |
|
{ |
|
assert(size_ < N); |
|
return *::new (&data_[size_++]) T(std::forward<Args>(args)...); |
|
} |
|
|
|
const T &operator[](std::size_t pos) const { return *data_[pos].ptr(); } |
|
T &operator[](std::size_t pos) { return *data_[pos].ptr(); } |
|
|
|
void erase(const T *first, const T *last) |
|
{ |
|
if (last == first) return; |
|
assert(first >= begin() && last <= end() && first <= last); |
|
const auto count = last - first; |
|
auto tail = std::move(const_cast<T *>(last), end(), const_cast<T *>(first)); |
|
std::destroy(tail, end()); |
|
size_ -= count; |
|
} |
|
|
|
void erase(const T *element) |
|
{ |
|
assert(element >= begin() && element < end()); |
|
erase(element, element + 1); |
|
} |
|
|
|
void pop_back() // NOLINT(readability-identifier-naming) |
|
{ |
|
std::destroy_at(&back()); |
|
--size_; |
|
} |
|
|
|
void clear() |
|
{ |
|
erase(begin(), end()); |
|
} |
|
|
|
~StaticVector() |
|
{ |
|
std::destroy_n(data(), size_); |
|
} |
|
|
|
private: |
|
struct AlignedStorage { |
|
alignas(alignof(T)) std::byte data[sizeof(T)]; |
|
|
|
const T *ptr() const |
|
{ |
|
return std::launder(reinterpret_cast<const T *>(data)); |
|
} |
|
|
|
T *ptr() |
|
{ |
|
return std::launder(reinterpret_cast<T *>(data)); |
|
} |
|
}; |
|
AlignedStorage data_[N]; |
|
std::size_t size_ = 0; |
|
}; |
|
|
|
} // namespace devilution
|
|
|