Files
nostalgia/deps/ox/src/ox/std/array.hpp

212 lines
5.4 KiB
C++

/*
* Copyright 2015 - 2025 gary@drinkingtea.net
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "bit.hpp"
#include "def.hpp"
#include "error.hpp"
#include "initializerlist.hpp"
#include "iterator.hpp"
#include "math.hpp"
#include "new.hpp"
#include "types.hpp"
#include "utility.hpp"
OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage)
namespace ox {
template<typename T, std::size_t ArraySize>
class Array {
public:
using value_type = T;
using size_type = std::size_t;
template<typename RefType = T&, typename PtrType = T*, bool reverse = false>
using iterator = SpanIterator<T, RefType, PtrType, reverse>;
private:
T m_items[ArraySize]{};
public:
constexpr Array() noexcept = default;
template<typename ...Args>
constexpr Array(Args ...list) noexcept: m_items{std::move(list)...} {
}
constexpr Array(std::initializer_list<T> list) noexcept;
constexpr Array(const Array &other);
constexpr Array(Array &&other) noexcept;
constexpr ~Array() = default;
constexpr iterator<> begin() noexcept {
return iterator<>(&m_items[0], 0, ArraySize);
}
constexpr iterator<> end() noexcept {
return iterator<>(&m_items[0], ArraySize, ArraySize);
}
constexpr iterator<const T&, const T*> begin() const noexcept {
return iterator<const T&, const T*>(&m_items[0], 0, ArraySize);
}
constexpr iterator<const T&, const T*> end() const noexcept {
return iterator<const T&, const T*>(&m_items[0], ArraySize, ArraySize);
}
constexpr iterator<T&, T*, true> rbegin() noexcept {
return iterator<T&, T*, true>(&m_items[0], ArraySize - 1, ArraySize);
}
constexpr iterator<T&, T*, true> rend() noexcept {
return iterator<T&, T*, true>(&m_items[0], MaxValue<size_type>, ArraySize);
}
constexpr iterator<const T&, const T*, true> rbegin() const noexcept {
return iterator<const T&, const T*, true>(m_items, ArraySize - 1, ArraySize);
}
constexpr iterator<const T&, const T*, true> rend() const noexcept {
return iterator<const T&, const T*, true>(m_items, MaxValue<size_type>, ArraySize);
}
constexpr bool operator==(const Array &other) const;
constexpr Array &operator=(const Array &other);
constexpr Array &operator=(Array &&other) noexcept;
[[nodiscard]]
constexpr T &operator[](std::size_t i) noexcept;
[[nodiscard]]
constexpr const T &operator[](std::size_t i) const noexcept;
[[nodiscard]]
constexpr std::size_t size() const noexcept;
[[nodiscard]]
constexpr T *data() noexcept {
return m_items;
}
[[nodiscard]]
constexpr const T *data() const noexcept {
return m_items;
}
[[nodiscard]]
constexpr bool contains(const T&) const;
};
template<typename T, std::size_t ArraySize, typename RefType, bool reverse>
using ArrayIt = typename Array<T, ArraySize>::template iterator<RefType, reverse>;
template<typename T, std::size_t ArraySize, typename RefType, bool reverse>
constexpr ArrayIt<T, ArraySize, RefType, reverse> operator+(std::size_t n, const ArrayIt<T, ArraySize, RefType, reverse> &a) {
return a + n;
}
template<typename T, std::size_t ArraySize>
constexpr Array<T, ArraySize>::Array(std::initializer_list<T> list) noexcept {
for (auto i = 0ul; auto &item : list) {
this->operator[](i) = item;
++i;
}
}
template<typename T, std::size_t ArraySize>
constexpr Array<T, ArraySize>::Array(const Array &other) {
for (std::size_t i = 0; i < ArraySize; ++i) {
m_items[i] = T(other.m_items[i]);
}
}
template<typename T, std::size_t ArraySize>
constexpr Array<T, ArraySize>::Array(Array &&other) noexcept {
if (this != &other) {
for (std::size_t i = 0; i < ArraySize; ++i) {
m_items[i] = T(std::move(other.m_items[i]));
}
}
}
template<typename T, std::size_t ArraySize>
constexpr bool Array<T, ArraySize>::operator==(const Array &other) const {
if (std::is_constant_evaluated()) {
for (std::size_t i = 0; i < ArraySize; i++) {
if (!(m_items[i] == other.m_items[i])) {
return false;
}
}
return true;
} else {
return memcmp(this, &other, sizeof(*this)) == 0;
}
}
template<typename T, std::size_t ArraySize>
constexpr Array<T, ArraySize> &Array<T, ArraySize>::operator=(const Array &other) {
if (this != &other) {
for (std::size_t i = 0; i < ArraySize; ++i) {
m_items[i] = other.m_items[i];
}
}
return *this;
return *this;
}
template<typename T, std::size_t ArraySize>
constexpr Array<T, ArraySize> &Array<T, ArraySize>::operator=(Array &&other) noexcept {
if (this != &other) {
for (std::size_t i = 0; i < ArraySize; ++i) {
m_items[i] = std::move(other.m_items[i]);
}
}
return *this;
}
template<typename T, std::size_t ArraySize>
constexpr T &Array<T, ArraySize>::operator[](std::size_t i) noexcept {
boundsCheck(__FILE__, __LINE__, i, size(), "Array access overflow");
return m_items[i];
}
template<typename T, std::size_t ArraySize>
constexpr const T &Array<T, ArraySize>::operator[](std::size_t i) const noexcept {
boundsCheck(__FILE__, __LINE__, i, size(), "Array access overflow");
return m_items[i];
}
template<typename T, std::size_t ArraySize>
constexpr std::size_t Array<T, ArraySize>::size() const noexcept {
return ArraySize;
}
template<typename T, std::size_t ArraySize>
constexpr bool Array<T, ArraySize>::contains(const T &v) const {
for (std::size_t i = 0; i < ArraySize; i++) {
if (m_items[i] == v) {
return true;
}
}
return false;
}
}
OX_CLANG_NOWARN_END