Files
OpenVulkano/openVulkanoCpp/Data/Containers/Array.hpp
2023-10-03 19:52:23 +02:00

306 lines
5.6 KiB
C++

/*
* 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 <algorithm>
#include <iterator>
#include <initializer_list>
#include <cstddef>
#include <vector>
namespace OpenVulkano
{
/**
* Heap allocated array. For all these times you need a fixed size data structure, but don't know the size at compile time.
* @tparam T The type to be used
*/
template<typename T>
class Array
{
size_t size;
T* data;
public:
using iterator = T*;
using const_iterator = const T*;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
Array() noexcept: size(0), data(nullptr)
{}
explicit Array(size_t size) : size(size), data(new T[size]())
{}
Array(const std::initializer_list<T>& list) : size(list.size()), data(static_cast<T*>(::operator new(sizeof(T) * list.Size())))
{
std::copy(list.begin(), list.end(), Begin());
}
Array(const Array<T>& other) : size(other.Size()), data(static_cast<T*>(::operator new(sizeof(T) * other.Size())))
{
std::copy(other.begin(), other.end(), Begin());
}
Array(Array<T>&& other) noexcept:
size(other.size), data(other.data)
{
other.data = nullptr;
other.size = 0;
}
explicit Array(const std::vector<T>& vector) : size(vector.size()), data(static_cast<T*>(::operator new(sizeof(T) * size)))
{
std::copy(vector.begin(), vector.end(), Begin());
}
Array(size_t size, const T& defaultValue) : size(size), data(static_cast<T*>(::operator new(sizeof(T) * size)))
{
Fill(defaultValue);
}
~Array() noexcept
{
delete[] data;
}
Array& operator=(const Array<T>& rhs)
{
if (this == &rhs) return *this;
Resize(rhs.size());
std::copy(rhs.begin(), rhs.end(), Begin());
return *this;
}
Array& operator=(const std::initializer_list<T>& list)
{
Resize(list.size());
std::copy(list.begin(), list.end(), Begin());
return *this;
}
Array& operator=(Array<T>&& rhs) noexcept
{
if (this != &rhs)
{
Array(std::move(rhs)).Swap(*this);
}
return *this;
}
T& operator[](size_t n)
{
return data[n];
}
const T& operator[](size_t n) const
{
return data[n];
}
operator bool() const noexcept
{
return data;
}
iterator Begin() noexcept
{
return data;
}
const_iterator Begin() const noexcept
{
return data;
}
iterator begin() noexcept
{
return data;
}
const_iterator begin() const noexcept
{
return data;
}
iterator End() noexcept
{
return Begin() + Size();
}
const_iterator End() const noexcept
{
return Begin() + Size();
}
iterator end() noexcept
{
return Begin() + Size();
}
const_iterator end() const noexcept
{
return Begin() + Size();
}
reverse_iterator ReverseBegin() noexcept
{
return reverse_iterator(End());
}
const_reverse_iterator ReverseBegin() const noexcept
{
return const_reverse_iterator(End());
}
reverse_iterator ReverseEnd() noexcept
{
return reverse_iterator(Begin());
}
const_reverse_iterator ReverseEnd() const noexcept
{
return const_reverse_iterator(Begin());
}
const_iterator ConstBegin() const noexcept
{
return Begin();
}
const_iterator ConstEnd() const noexcept
{
return End();
}
const_reverse_iterator ConstReverseBegin() const noexcept
{
return ReverseBegin();
}
const_reverse_iterator ConstReverseEnd() const noexcept
{
return ReverseEnd();
}
[[nodiscard]] size_t Size() const noexcept
{
return size;
}
[[nodiscard]] size_t MaxSize() const noexcept
{
return size;
}
[[nodiscard]] bool Empty() const noexcept
{
return Size() == 0;
}
T& At(size_t n)
{
if (n >= Size()) throw std::out_of_range("Index " + std::to_string(n) + " is out of bounds.");
return data[n];
}
const T& At(size_t n) const
{
return const_cast<Array*>(this)->At(n);
}
T& Front() noexcept
{
return *Begin();
}
const T& Front() const noexcept
{
return *ConstBegin();
}
T& Back() noexcept
{
return *(End() - 1);
}
const T& Back() const noexcept
{
return *(ConstEnd() - 1);
}
T* Data() noexcept
{
return data;
}
const T* Data() const noexcept
{
return data;
}
void Fill(const T& value) noexcept(noexcept(std::fill(Begin(), End(), value)))
{
std::fill(Begin(), End(), value);
}
void Swap(Array<T>& other) noexcept
{
std::swap(data, other.data);
std::swap(size, other.size);
}
private:
void Resize(size_t newSize)
{
if (Size() != newSize)
{
size = 0;
delete[] data;
data = nullptr;
data = new T[newSize];
size = newSize;
}
}
};
template<typename T>
inline bool operator==(const Array<T>& lhs, const Array<T>& rhs)
{
return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin());
}
template<typename T>
inline bool operator!=(const Array<T>& lhs, const Array<T>& rhs)
{
return !(lhs == rhs);
}
template<typename T>
inline bool operator<(const Array<T>& lhs, const Array<T>& rhs)
{
return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
}
template<typename T>
inline bool operator>(const Array<T>& lhs, const Array<T>& rhs)
{
return rhs < lhs;
}
template<typename T>
inline bool operator>=(const Array<T>& lhs, const Array<T>& rhs)
{
return !(lhs < rhs);
}
template<typename T>
inline bool operator<=(const Array<T>& lhs, const Array<T>& rhs)
{
return !(rhs < lhs);
}
}