|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
|
|
#include <initializer_list>
|
|
|
|
|
#include <memory>
|
|
|
|
|
#include <utility>
|
|
|
|
|
|
|
|
|
|
#include "appfat.h"
|
|
|
|
|
#include "utils/stdcompat/cstddef.hpp"
|
|
|
|
|
|
|
|
|
|
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:
|
|
|
|
|
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]] const T *end() const
|
|
|
|
|
{
|
|
|
|
|
return begin() + size_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] size_t size() const
|
|
|
|
|
{
|
|
|
|
|
return size_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] T &back()
|
|
|
|
|
{
|
|
|
|
|
return (*this)[size_ - 1];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] const T &back() const
|
|
|
|
|
{
|
|
|
|
|
return (*this)[size_ - 1];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename... Args>
|
|
|
|
|
T &emplace_back(Args &&...args) // NOLINT(readability-identifier-naming)
|
|
|
|
|
{
|
|
|
|
|
assert(size_ < N);
|
|
|
|
|
return *::new (&data_[size_++]) T(std::forward<Args>(args)...);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
T &operator[](std::size_t pos)
|
|
|
|
|
{
|
|
|
|
|
return *data_[pos].ptr();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const T &operator[](std::size_t pos) const
|
|
|
|
|
{
|
|
|
|
|
return *data_[pos].ptr();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
~StaticVector()
|
|
|
|
|
{
|
|
|
|
|
for (std::size_t pos = 0; pos < size_; ++pos) {
|
|
|
|
|
#if __cplusplus >= 201703L
|
|
|
|
|
std::destroy_at(data_[pos].ptr());
|
|
|
|
|
#else
|
|
|
|
|
data_[pos].ptr()->~T();
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
struct AlignedStorage {
|
|
|
|
|
alignas(alignof(T)) byte data[sizeof(T)];
|
|
|
|
|
|
|
|
|
|
const T *ptr() const
|
|
|
|
|
{
|
|
|
|
|
#if __cplusplus >= 201703L
|
|
|
|
|
return std::launder(reinterpret_cast<const T *>(data));
|
|
|
|
|
#else
|
|
|
|
|
return reinterpret_cast<const T *>(data);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
T *ptr()
|
|
|
|
|
{
|
|
|
|
|
#if __cplusplus >= 201703L
|
|
|
|
|
return std::launder(reinterpret_cast<T *>(data));
|
|
|
|
|
#else
|
|
|
|
|
return reinterpret_cast<T *>(data);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
AlignedStorage data_[N];
|
|
|
|
|
std::size_t size_ = 0;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
} // namespace devilution
|