#ifndef ROW_HPP
#define ROW_HPP

#include <iostream>
#include <cstdint>
#include <stdexcept>
#include "sort_algorithms.hpp"

template<typename T>
class row {
private:
	T* p;
	uint32_t n;
public:
	//Constructor
	row(T* data, uint32_t size) : n(size) {
		p = new T[n];
		for (uint32_t i=0;i<n;i++) p[i] = data[i];
	}

	//Destructor
	~row() { delete[] p;}

	//Copy constructor
	row(const row& other) : n(other.n) {
		p = new T[n];
		for (uint32_t i=0;i<n;i++) p[i]=other.p[i];
	}

	//Assignment operator (Deep copy)
	row& operator=(const row& other) {
		if (this != &other) {
			delete[] p;
			n=other.n;
			n=new T[n];
			for (uint32_t i=0;i<n;i++) p[i]=other.p[i];
		}
		return *this;
	}

	//operator[]
	T& operator[](uint32_t index) { return p[index]; }
	const T& operator[](uint32_t index) const { return p[index]; }

	//operator at
	T& at(uint32_t index) {
		if (index >= n) throw std::out_of_range("Index out of bounds");
		return p[index];
	}
	const T& at(uint32_t index) const {
		if (index >= n) throw std::out_of_range("Index out of bounds");
		return p[index];
	}

	//size() (Απαραίτητο για τους αλγόριθμους ταξινόμησης)
	uint32_t size() const { return n; }

	//operator <<
	friend std::ostream& operator<<(std::ostream& os, const row& r) {
		os << "[";
		for (uint32_t i=0;i<r.n;i++) os <<r.p[i]<<(i<r.n-1? "," : "");
		os << "]";
		return os;
	}

	//operator >>
	friend std::istream& operator>>(std::istream& is, row& r) {
		for (uint32_t i=0;i<r.n;i++) is >> r.p[i];
		return is;
	}
};

#endif
