#ifndef UNINITIALIZEDARRAY_H
#define UNINITIALIZEDARRAY_H

#include <new>
#include <utility>
#include <vector>

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

public:
    UninitializedArray() = default;
    UninitializedArray(const UninitializedArray&) = delete;
    UninitializedArray(UninitializedArray&&) = delete;
    UninitializedArray& operator=(const UninitializedArray&) = delete;
    UninitializedArray& operator=(UninitializedArray&&) = delete;

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

    T* end() {
        return begin() + N;
    }

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

    const T* end() const {
        return begin() + N;
    }

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

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

    void init(int index, const T& t) {
        new(begin() + index) T(t);
    }

    void init(int index, T&& t) {
        new(begin() + index) T(std::move(t));
    }

    template<typename... Args>
    void init(int index, Args&&... args) {
        new(begin() + index) T(std::forward<Args>(args)...);
    }

    void destroy(int index) {
        begin()[index].~T();
    }
};

#endif