//============================================================================
//
// This file is part of the Shapes Generative Model Library (SGML) project.
//
// Copyright (c) 2010-2014 - Evangelos Kalogerakis, Siddhartha Chaudhuri (authors of the code) / Stanford University, UMass-Amherst
//
// SGML is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// SGML is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with SGML.  If not, see <http://www.gnu.org/licenses/>.
//
//============================================================================

#ifndef __SNL_S12_StackVector_hpp__
#define __SNL_S12_StackVector_hpp__

#include <boost/array.hpp>
#include <algorithm>
#include <vector>

namespace SNL {
namespace S12 {

#define STACK_VECTOR_DEFAULT_CAPACITY 20

template <typename T, std::size_t N = STACK_VECTOR_DEFAULT_CAPACITY> class StackVector
: public boost::array<T, N>
{
  private:
    typedef boost::array<T, N> BaseType;

  public:
    StackVector() : nelems(0) {}
    explicit StackVector(std::size_t n) : nelems(n) {}
    StackVector(std::size_t n, T const & c) : nelems(0) { BaseType::assign(c); }
    StackVector(StackVector const & other) : nelems(other.nelems) { BaseType::operator=(other); }
    explicit StackVector(SNL_VECTOR(T) const & src) : nelems(0) { copyFrom(src); }

    StackVector & operator=(StackVector const & other)
    {
      BaseType::operator=(other);
      nelems = other.nelems;
      return *this;
    }

    void resize(std::size_t sz) { nelems = sz; }
    void resize(std::size_t sz, T const & c) { nelems = sz; this->assign(c); }
    void reserve(std::size_t sz) {}
    void clear() { nelems = 0; }

    void push_back(T const & t) { (*this)[nelems++] = t; }
    void pop_back() { if (nelems > 0) nelems--; }

    template <typename InputIterator> void insert(typename BaseType::iterator pos, InputIterator b, InputIterator e)
    {
      std::size_t n = std::distance(b, e);
      std::copy_backward(pos, end(), pos + n);
      std::copy(b, e, pos);
    }

    typename BaseType::const_iterator end() const { return &(*this)[0] + nelems; }
    typename BaseType::iterator end() { return &(*this)[0] + nelems; }
    typename BaseType::const_reverse_iterator rbegin() const { return typename BaseType::const_reverse_iterator(end()); }
    typename BaseType::reverse_iterator rbegin() { return typename BaseType::reverse_iterator(end()); }

    std::size_t size() const { return nelems; }
    bool empty() const { return (nelems <= 0); }

    typename BaseType::const_reference back() const { return (*this)[nelems - 1]; }
    typename BaseType::reference back() { return (*this)[nelems - 1]; }

    void copyTo(std::SNL_VECTOR(T) & v) const
    {
      v.resize(nelems);
      for (size_t i = 0; i < nelems; ++i)
        v[i] = (*this)[i];
    }

    void copyFrom(std::SNL_VECTOR(T) const & v)
    {
      resize(v.size());
      for (size_t i = 0; i < v.size(); ++i)
        (*this)[i] = v[i];
    }

  private:
    std::size_t nelems;

}; // class StackVector

template <typename T>
bool operator==(StackVector<T> const & x, StackVector<T> const & y)
{
  return std::equal(x.begin(), x.end(), y.begin());
}

template <typename T>
bool operator!=(StackVector<T> const & x, StackVector<T> const & y)
{
  return !(x == y);
}

template <typename T>
bool operator<(StackVector<T> const & x, StackVector<T> const & y)
{
  return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end());
}

template <typename T>
bool operator>(StackVector<T> const & x, StackVector<T> const & y)
{
  return y < x;
}

template <typename T>
bool operator<=(StackVector<T> const & x, StackVector<T> const & y)
{
  return !(y < x);
}

template <typename T>
bool operator>=(StackVector<T> const & x, StackVector<T> const & y)
{
  return !(x < y);
}

} // namespace S12
} // namespace SNL

#endif
