#ifndef LIST_H
#define LIST_H

#include <utility>

template<typename T, int N>
class List final {
    char data[sizeof (T) * N];
    int index = 0;

    void copy(const List& other) {
        for(int i = 0; i < other.index; i++) {
            add(other[i]);
        }
    }

    void move(List&& other) {
        for(int i = 0; i < other.index; i++) {
            add(std::move(other[i]));
        }
    }

public:
    List() = default;

    void clear() {
        for(int i = 0; i < index; i++) {
            (*this)[i].~T();
        }
        index = 0;
    }

    ~List() {
        clear();
    }

    List(const List& other) : index(0) {
        copy(other);
    }

    List& operator=(const List& other) {
        if(&other != this) {
            clear();
            copy(other);
        }
        return *this;
    }

    List(List&& other) : index(0) {
        move(std::move(other));
        other.clear();
    }

    List& operator=(List&& other) {
        if(&other != this) {
            clear();
            move(std::move(other));
            other.clear();
        }
        return *this;
    }

    T* begin() {
        return reinterpret_cast<T*> (data);
    }

    T* end() {
        return reinterpret_cast<T*> (data) + index;
    }

    const T* begin() const {
        return reinterpret_cast<const T*> (data);
    }

    const T* end() const {
        return reinterpret_cast<const T*> (data) + index;
    }

    void add(const T& t) {
        if(index >= N) {
            return;
        }
        new (end()) T(t);
        index++;
    }

    void add(T&& t) {
        if(index >= N) {
            return;
        }
        new (end()) T(std::move(t));
        index++;
    }

    template<typename... Args>
    void add(Args&&... args) {
        if(index >= N) {
            return;
        }
        new (end()) T(args...);
        index++;
    }

    T& operator[](int index) {
        return begin()[index];
    }

    const T& operator[](int index) const {
        return begin()[index];
    }

    int getLength() const {
        return index;
    }
};

#endif