#ifndef ROW_HPP
#define ROW_HPP

#include <iostream>
#include <cstdint>
#include <stdexcept>

template<typename T>
class row {
private:
	T* p;
	uint32_t n;

public:
	row() : p(nullptr), n(0) {}

	row(T* arr, uint32_t size): n(size) {
		p = new T[n];
		for (uint32_t i = 0;i < n; i++) {
			p[i] = arr[i];
		}
	}

	row(uint32_t size) : n(size) {
		p = new T[n];
	}

	~row() {
		delete[] p;
	}

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

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

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

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

	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];
	}

	uint32_t size() const {
		return n;
	}

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

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

#include "sort_algorithms.hpp"

#endif
