#ifndef ARRAY_HPP
#define ARRAY_HPP
#include <algorithm>
#include <cassert>
#include <cstdlib>
#include <initializer_list>
#include <iterator>
#include <new>
#include <utility>
template<typename T>
class Array {
private:
using Tag = enum {AllocateStorage};
Array(Tag tag, std::size_t size) :
size(size),
data(size > 0?
static_cast<T*>(operator new(sizeof(T) * size))
:
nullptr) {
}
public:
Array() noexcept : size(0), data(nullptr) {
}
Array(std::size_t size) : Array(AllocateStorage, size) {
for (std::size_t index = 0; index < size; ++index) {
new (data + index) T();
}
}
Array(std::size_t size, const T& t) : Array(AllocateStorage, size) {
for (std::size_t index = 0; index < size; ++index) {
new (data + index) T(t);
}
}
template<typename Iterator>
Array(Iterator it1, Iterator it2) :
Array(AllocateStorage, std::distance(it1, it2)) {
std::size_t index = 0;
while (it1 != it2 && index < size) {
new (data + index++) T(*it1++);
}
size = index;
}
Array(std::initializer_list<T> elements) :
Array(elements.begin(), elements.end()) {
}
Array(const Array& other) : Array(AllocateStorage, other.size) {
for (std::size_t index = 0; index < size; ++index) {
new (data + index) T(other.data[index]);
}
}
friend void swap(Array& a1, Array& a2) noexcept {
using std::swap;
swap(a1.size, a2.size);
swap(a1.data, a2.data);
}
Array(Array&& other) noexcept : Array() {
swap(*this, other);
}
~Array() {
for (std::size_t index = 0; index < size; ++index) {
data[index].~T();
}
operator delete(data);
}
Array& operator=(Array other) noexcept {
swap(*this, other);
return *this;
}
std::size_t get_size() const noexcept {
return size;
}
T& operator()(std::size_t index) {
assert(index < size);
return data[index];
}
const T& operator()(std::size_t index) const {
assert(index < size);
return data[index];
}
T* begin() noexcept {
return data;
}
const T* begin() const noexcept {
return data;
}
T* end() noexcept {
return data + size;
}
const T* end() const noexcept {
return data + size;
}
private:
std::size_t size;
T* data;
};
#endif