#pragma once
#include <utility>
#include <cstddef>
#include <stdexcept>
#include <iostream>
template <typename T>
class ArrayList {
private:
std::size_t m_length;
T* m_data;
public:
ArrayList() : m_length(0), m_data(static_cast<T*>(::operator new(0))) {}
explicit ArrayList(std::size_t capacity) : m_length(0), m_data(static_cast<T*>(::operator new(sizeof(T) * capacity))) {}
ArrayList(const ArrayList& rhs)
: m_length(rhs.size())
, m_data(static_cast<T*>(::operator new(sizeof(T) * m_length))) {
for (std::size_t i = 0; i < rhs.size(); i++) {
m_data[i] = rhs[i];
}
}
~ArrayList() {
destruct_current();
::operator delete(m_data);
}
ArrayList& operator=(const ArrayList& rhs) {
if (&rhs == this)
return *this;
destruct_current();
::operator delete(m_data);
m_length = rhs.size();
m_data = static_cast<T*>(::operator new(sizeof(T) * m_length));
for (std::size_t i = 0; i < m_length; i++) {
m_data[i] = rhs[i];
}
return *this;
}
T& operator[](std::size_t index) {
if (index < 0 || index >= m_length) {
throw std::out_of_range("index out of range");
}
return m_data[index];
}
const T& operator[](std::size_t index) const {
if (index < 0 || index >= m_length) {
throw std::out_of_range("index out of range");
}
return m_data[index];
}
T* items() const {
return m_data;
}
std::size_t size() const {
return m_length;
}
void insert(std::size_t index, const T& item) {
if (index < 0 || index > m_length) {
throw std::out_of_range("index is out of range");
}
T* temp = static_cast<T*>(::operator new(sizeof(T) * (m_length + 1)));
for (std::size_t i = 0; i < index; i++) {
temp[i] = std::move(m_data[i]);
}
temp[index] = item;
for (std::size_t i = index; i < m_length; i++) {
temp[i + 1] = std::move(m_data[i]);
}
m_length++;
destruct_current();
::operator delete(m_data);
m_data = temp;
}
void remove(std::size_t index) {
if (m_length == 0 || index < 0 || index >= m_length) {
throw std::out_of_range("index is out of range");
}
T* temp = static_cast<T*>(::operator new(sizeof(T) * m_length - 1));
for (std::size_t i = 0; i < index; i++) {
temp[i] = std::move(m_data[i]);
}
for (std::size_t i = index + 1; i < m_length; i++) {
temp[i - 1] = std::move(m_data[i]);
}
destruct_current();
::operator delete(m_data);
m_data = temp;
m_length--;
}
void destruct_current() {
for (std::size_t i = 0; i < m_length; i++) {
m_data[i].~T();
}
}
void print() const {
for (std::size_t i = 0; i < m_length; i++) {
std::cout << m_data[i] << " ";
}
std::cout << "\n";
}
};