text: #include <vector_smart_pointer.hpp>
  
  template <typename T>
  VectorSmartPointer<T>::VectorSmartPointer()
  {
      m_size = 0;
      m_capacity = 0;
      m_data = nullptr;
  };
  
  template <typename T>
  VectorSmartPointer<T>::~VectorSmartPointer()
  {
      m_data.reset();
  };
  
  template <typename T>
  VectorSmartPointer<T>::VectorSmartPointer(const uint32_t size)
  {
      std::cout << "C'tor with Size" << std::endl;
      m_capacity = size;
      m_size = size;
      m_data = std::make_unique<T[]>(size);
  }
  
  template <typename T>
  VectorSmartPointer<T>::VectorSmartPointer(const uint32_t size, const T& initial)
  {
      std::cout << "C'tor with Size and Init" << std::endl;
      m_capacity = size;
      m_size = size;
      m_data = std::make_unique<T[]>(size);
      std::fill(this->begin(), this->end(), initial);
  }
  
  template <typename T>
  VectorSmartPointer<T>::VectorSmartPointer(const std::initializer_list<T>& rhs)
  {
      std::cout << "C'tor with Init List" << std::endl;
      m_size = rhs.size();
      m_capacity = rhs.size();
      m_data = std::make_unique<T[]>(m_size);
      std::copy(rhs.begin(), rhs.end(), this->begin());
  }
  
  template <typename T>
  VectorSmartPointer<T>::VectorSmartPointer(const VectorSmartPointer<T>& rhs)
  {
      std::cout << "Copy C'tor" << std::endl;
      m_size = rhs.size();
      m_capacity = rhs.capacity();
      m_data = std::make_unique<T[]>(m_size);
      std::copy(rhs.begin(), rhs.end(), this->begin());
  }
  
  template <typename T>
  VectorSmartPointer<T>::VectorSmartPointer(VectorSmartPointer<T>&& rhs) noexcept
  {
      // m_size = rhs.size();
      // m_capacity = rhs.capacity();
      // m_data = std::make_unique<T[]>(m_size);
      // std::copy(rhs.begin(), rhs.end(), this->begin());
      std::cout << "Move C'tor" << std::endl;
      m_size = rhs.size();
      m_capacity = rhs.capacity();
      m_data = std::make_unique<T[]>(m_size);
      std::copy(rhs.begin(), rhs.end(), this->begin());
  }
  
  // https://en.cppreference.com/w/cpp/language/copy_assignment
  template <typename T>
  VectorSmartPointer<T> & VectorSmartPointer<T>::operator=(const VectorSmartPointer<T> & rhs)
  {
      std::cout << "Copy Assignment" << std::endl;
      if (&rhs != this) 
      {
          if(m_size != rhs.size())
          {
              m_size = rhs.size();
              m_capacity = rhs.capacity();
              m_data.reset(new T[m_size]);
          }
          std::copy(rhs.begin(), rhs.end(), this->begin());
      }
      return *this;
  }
  
  template <typename T>
  VectorSmartPointer<T> & VectorSmartPointer<T>::operator=(VectorSmartPointer<T> && rhs) noexcept
  {
      std::cout << "Move Assignment" << std::endl;
      if (&rhs != this) 
      {
          // m_data.reset();
          // m_size = std::swap(rhs.size());
          // m_capacity = std::swap(rhs.capacity());
          // m_size = rhs.size();
          // m_capacity = rhs.capacity();
          // m_data = std::exchange
          // m_data = std::move(rhs.data());
          // m_data = std::make_unique<T[]>(m_size);
  
          if(m_size != rhs.size())
          {
              m_size = rhs.size();
              m_capacity = rhs.capacity();
              m_data.reset(new T[m_size]);
          }
          std::copy(rhs.begin(), rhs.end(), this->begin());
      }
      return *this;
  }
  
  template <typename T>
  T& VectorSmartPointer<T>::operator[] (const uint32_t index)
  {
      return m_data.get()[index];
  }
  
  template <typename T>
  T& VectorSmartPointer<T>::operator() (const uint32_t index)
  {
      return m_data.get()[index];
  }
  
  template <typename T>
  const T& VectorSmartPointer<T>::operator[] (const uint32_t index) const
  {
      return m_data.get()[index];
  }
  
  template <typename T>
  const T& VectorSmartPointer<T>::operator() (const uint32_t index) const
  {
      return m_data.get()[index];
  }
  
  template <typename T>
  uint32_t VectorSmartPointer<T>::size() const
  {
      return m_size;
  }
  
  template <typename T>
  uint32_t VectorSmartPointer<T>::capacity() const
  {
      return m_capacity;
  }
  
  template <typename T>
  bool VectorSmartPointer<T>::empty() const
  {
      return m_size > 0 ? false : true;
  }
  
  template <typename T>
  typename VectorSmartPointer<T>::iterator VectorSmartPointer<T>::begin()
  {
      return m_data.get();
  }
  
  template <typename T>
  typename VectorSmartPointer<T>::iterator VectorSmartPointer<T>::end()
  {
      return m_data.get() + m_size;
  }
  
  template <typename T>
  typename VectorSmartPointer<T>::const_iterator VectorSmartPointer<T>::begin() const
  {
      return m_data.get();
  }
  
  template <typename T>
  typename VectorSmartPointer<T>::const_iterator VectorSmartPointer<T>::end() const 
  {
      return m_data.get() + m_size;
  }
  
  // template <typename T>
  // std::unique_ptr<T[]> VectorSmartPointer<T>::data()
  // {
  //     return std::move(m_data);
  // }
  
  template <typename T>
  T& VectorSmartPointer<T>::front()
  {
      return m_data.get()[0];
  }
  
  template <typename T>
  T& VectorSmartPointer<T>::back()
  {
      return m_data.get()[m_size-1];
  }
  
  template <typename T>
  void VectorSmartPointer<T>::push_back(const T& value)
  {
      if (m_size >= m_capacity)
          reserve(m_capacity+5);
      m_data[m_size++] = value;
  }
  
  template <typename T>
  void VectorSmartPointer<T>::emplace_back(const T&& value)
  {
      if (m_size >= m_capacity)
          reserve(m_capacity+5);
      m_data[m_size++] = value;
  }
  
  template <typename T>
  void VectorSmartPointer<T>::pop_back()
  {
      m_size --;
  }
  
  template <typename T>
  void VectorSmartPointer<T>::reserve(const uint32_t capacity)
  {
      if (m_data == nullptr)
      {
          m_size = 0;
          m_capacity = 0;
      }
      std::unique_ptr temp_data = std::make_unique<T[]>(capacity);
  
      const uint32_t lSize = capacity < m_size ? capacity : m_size;
  
      std::copy(this->begin(), this->begin() + lSize, temp_data.get());
  
      m_capacity = capacity;
      m_data = std::move(temp_data);
  }
  
  template <typename T>
  void VectorSmartPointer<T>::resize(const uint32_t size)
  {
      reserve(size);
      m_size = size;
  }
  
  template <typename T>
  void VectorSmartPointer<T>::clear()
  {
      m_capacity = 0;
      m_size = 0;
      m_data = nullptr;
  }
  
  template class VectorSmartPointer<int>;