#ifndef ROW_CPP
#define ROW_CPP

#include "row.hpp"

template <typename T>
Row<T>::Row(uint32_t size) {
    n = size;
    if(n > 0) {
        p = new T[n];
    } else {
        p = nullptr;
    }
}

template <typename T>
Row<T>::Row(T* arr, uint32_t size) {
    n = size;
    p = new T[n];
    for (uint32_t i = 0; i < n; i++) {
        p[i] = arr[i];
    }
}

template <typename T>
Row<T>::~Row() {
    if (p != nullptr) {
        delete[] p;
        p = nullptr;
    }
}

template <typename T>
Row<T>::Row(const Row<T>& other) {
    n = other.n;
    if (n > 0) {
        p = new T[n];
        for (uint32_t i = 0; i < n; i++) {
            p[i] = other.p[i];
        }
    } else {
        p = nullptr;
    }
}

template <typename T>
Row<T>& Row<T>::operator=(const Row<T>& other) {

    if (this == &other) {
        return *this;
    }
    
    delete[] p;
    
    n = other.n; 

    if(n > 0) {
        p = new T[n];
        for (uint32_t i = 0; i < n; i++) {
            p[i] = other.p[i];
        }
    } else {
        p = nullptr;
    }
    return *this;
}

template <typename T>
T& Row<T>::operator[](uint32_t idx) {
    return p[idx];
}

template <typename T>
const T& Row<T>::operator[](uint32_t idx) const {
    return p[idx];
}

template <typename T>
T& Row<T>::at(uint32_t idx) {
    if (idx >= n) {
        throw std::out_of_range("εκτος οριων");
    }
    return p[idx];
}

template <typename T>
const T& Row<T>::at(uint32_t idx) const {
    if (idx >= n) {
        throw std::out_of_range("εκτος οριων");
    }
    return p[idx];
}

template <typename T>
uint32_t Row<T>::size() const {
    return n;
}

#endif
