#include "row.h"

/* =========================
   CONSTRUCTORS
      ========================= */

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

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

                                      template<typename T>
                                      row<T>& row<T>::operator=(const row& other)
                                      {
                                          if (this == &other)
                                                  return *this;

                                                      delete[] p;
                                                          n = other.n;

                                                              p = new T[n];
                                                                  for (uint32_t i = 0; i < n; ++i)
                                                                          p[i] = other.p[i];

                                                                              return *this;
                                                                              }

                                                                              template<typename T>
                                                                              row<T>::~row()
                                                                              {
                                                                                  delete[] p;
                                                                                  }

                                                                                  /* =========================
                                                                                     MEMBER FUNCTIONS
                                                                                        ========================= */

                                                                                        template<typename T>
                                                                                        uint32_t row<T>::size() const
                                                                                        {
                                                                                            return n;
                                                                                            }

                                                                                            template<typename T>
                                                                                            T& row<T>::operator[](uint32_t index)
                                                                                            {
                                                                                                if (index >= n) {
                                                                                                        std::cerr << "Index out of bounds\n";
                                                                                                                std::abort();
                                                                                                                    }
                                                                                                                        return p[index];
                                                                                                                        }

                                                                                                                        template<typename T>
                                                                                                                        const T& row<T>::operator[](uint32_t index) const
                                                                                                                        {
                                                                                                                            if (index >= n) {
                                                                                                                                    std::cerr << "Index out of bounds\n";
                                                                                                                                            std::abort();
                                                                                                                                                }
                                                                                                                                                    return p[index];
                                                                                                                                                    }

                                                                                                                                                    template<typename T>
                                                                                                                                                    T& row<T>::at(uint32_t index)
                                                                                                                                                    {
                                                                                                                                                        if (index >= n) {
                                                                                                                                                                std::cerr << "Index out of bounds in at()\n";
                                                                                                                                                                        std::abort();
                                                                                                                                                                            }
                                                                                                                                                                                return p[index];
                                                                                                                                                                                }

                                                                                                                                                                                template<typename T>
                                                                                                                                                                                const T& row<T>::at(uint32_t index) const
                                                                                                                                                                                {
                                                                                                                                                                                    if (index >= n) {
                                                                                                                                                                                            std::cerr << "Index out of bounds in at()\n";
                                                                                                                                                                                                    std::abort();
                                                                                                                                                                                                        }
                                                                                                                                                                                                            return p[index];
                                                                                                                                                                                                            }

                                                                                                                                                                                                            /* =========================
                                                                                                                                                                                                               STREAM OPERATORS
                                                                                                                                                                                                                  ========================= */

                                                                                                                                                                                                                  template<typename T>
                                                                                                                                                                                                                  std::ostream& operator<<(std::ostream& os, const row<T>& obj)
                                                                                                                                                                                                                  {
                                                                                                                                                                                                                      for (uint32_t i = 0; i < obj.n; ++i)
                                                                                                                                                                                                                              os << obj.p[i] << " ";
                                                                                                                                                                                                                                  return os;
                                                                                                                                                                                                                                  }

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


                                                                                                                                                                                                                                                  /* =========================
                                                                                                                                                                                                                                                     EXPLICIT INSTANTIATION Needed for templates because are instantiated in runtime
                                                                                                                                                                                                                                                        ========================= */

                                                                                                                                                                                                                                                        // Add the types you want to support
                                                                                                                                                                                                                                                        //g++ main.cpp row.cpp -o main
                                                                                                                                                                                                                                                        template class row<int>;
                                                                                                                                                                                                                                                        template class row<long int>;
                                                                                                                                                                                                                                                        template class row<double>;
                                                                                                                                                                                                                                                        template class row<float>;
                                                                                                                                                                                                                                                        template class row<uint8_t>;

                                                                                                                                                                                                                                                        template std::ostream& operator<<(std::ostream&, const row<int>&);
                                                                                                                                                                                                                                                        template std::ostream& operator<<(std::ostream&, const row<long int>&);
                                                                                                                                                                                                                                                        template std::ostream& operator<<(std::ostream&, const row<float>&);
                                                                                                                                                                                                                                                        template std::ostream& operator<<(std::ostream&, const row<double>&);
                                                                                                                                                                                                                                                        template std::ostream& operator<<(std::ostream&, const row<uint8_t>&);

                                                                                                                                                                                                                                                        template std::istream& operator>>(std::istream&, row<int>&);
                                                                                                                                                                                                                                                        template std::istream& operator>>(std::istream&, row<long int>&);
                                                                                                                                                                                                                                                        template std::istream& operator>>(std::istream&, row<float>&);
                                                                                                                                                                                                                                                        template std::istream& operator>>(std::istream&, row<double>&);
                                                                                                                                                                                                                                                        template std::istream& operator>>(std::istream&, row<uint8_t>&);
