
/*

  KLayout Layout Viewer
  Copyright (C) 2006-2020 Matthias Koefferlein

  This program 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 2 of the License, or
  (at your option) any later version.

  This program 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 this program; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

*/



#ifndef HDR_tlStableVector
#define HDR_tlStableVector

#include <stddef.h>
#include <vector>
#include <iterator>

namespace tl 
{

/**
 *  @brief A stable vector class
 *
 *  Unlike the normal vector, the stable vector guarantees that the  
 *  objects stored within are not relocated to other memory locations
 *  even if the vector reallocates memory.
 *  The stable vector does this by maintaining pointers rather than
 *  objects itself.
 *  This way, this container is able to store objects that do not have
 *  a copy semantics.
 *  
 *  The stable vector offers two iterators: a usual one and a stable one.
 *  While the usual iterator is invalidated if the vector reallocates
 *  (the iterator gets invalid, not the location of the objects them-
 *  selves), the stable iterator stays valid even if the container 
 *  reallocates. The stable iterator is a pointer to the container plus
 *  an index.
 */

template <class X>
class stable_vector
{
public:
  typedef X value_type;

  class iterator;

  class const_iterator 
  {
  public:
    typedef std::random_access_iterator_tag iterator_category;
    typedef ptrdiff_t difference_type;
    typedef X value_type;
    typedef const X &reference;
    typedef const X *pointer;

    const_iterator ()
      : m_iter ()
    {
      //  .. nothing yet ..
    }

    const_iterator (const const_iterator &d)
      : m_iter (d.m_iter)
    {
      //  .. nothing yet ..
    }

    const_iterator (const iterator &d)
      : m_iter (d.m_iter)
    {
      //  .. nothing yet ..
    }

    const_iterator (typename std::vector<X *>::const_iterator d)
      : m_iter (d)
    {
      //  .. nothing yet ..
    }

    const_iterator &operator= (const_iterator d) 
    {
      m_iter = d.m_iter;
      return *this;
    }

    const iterator &operator= (iterator d) 
    {
      m_iter = d.m_iter;
      return *this;
    }

    bool operator== (const_iterator d) const
    {
      return m_iter == d.m_iter;
    }

    bool operator!= (const_iterator d) const
    {
      return m_iter != d.m_iter;
    }

    bool operator< (const_iterator d) const
    {
      return m_iter < d.m_iter;
    }

    ptrdiff_t operator- (const_iterator d) const
    {
      return m_iter - d.m_iter;
    }

    const_iterator operator- (ptrdiff_t n) const
    {
      return m_iter - n;
    }

    const_iterator operator+ (ptrdiff_t n) const
    {
      return m_iter + n;
    }

    const_iterator &operator+= (ptrdiff_t n) 
    {
      m_iter += n;
      return *this;
    }

    const_iterator &operator-= (ptrdiff_t n)
    {
      m_iter -= n;
      return *this;
    }

    const_iterator &operator++ ()
    {
      ++m_iter;
      return *this;
    }

    const_iterator operator++ (int)
    {
      const_iterator i = *this;
      ++m_iter;
      return i;
    }

    const_iterator &operator-- ()
    {
      --m_iter;
      return *this;
    }

    const_iterator operator-- (int)
    {
      const_iterator i = *this;
      --m_iter;
      return i;
    }

    const X &operator[] (ptrdiff_t n) const
    {
      return *m_iter [n];
    }

    const X &operator* () const
    {
      return **m_iter;
    }

    const X *operator-> () const
    {
      return *m_iter;
    }

  private:
    typename std::vector<X *>::const_iterator m_iter;
  };

  class iterator 
  {
  public:
    typedef std::random_access_iterator_tag iterator_category;
    typedef ptrdiff_t difference_type;
    typedef X value_type;
    typedef X &reference;
    typedef X *pointer;

    iterator ()
      : m_iter ()
    {
      //  .. nothing yet ..
    }

    iterator (const iterator &d)
      : m_iter (d.m_iter)
    {
      //  .. nothing yet ..
    }

    iterator (typename std::vector<X *>::iterator d)
      : m_iter (d)
    {
      //  .. nothing yet ..
    }

    iterator &operator= (iterator d) 
    {
      m_iter = d.m_iter;
      return *this;
    }

    bool operator== (iterator d) const
    {
      return m_iter == d.m_iter;
    }

    bool operator!= (iterator d) const
    {
      return m_iter != d.m_iter;
    }

    bool operator< (iterator d) const
    {
      return m_iter < d.m_iter;
    }

    ptrdiff_t operator- (iterator d) const
    {
      return m_iter - d.m_iter;
    }

    iterator operator- (ptrdiff_t n) const
    {
      return m_iter - n;
    }

    iterator operator+ (ptrdiff_t n) const
    {
      return m_iter + n;
    }

    iterator &operator+= (ptrdiff_t n) 
    {
      m_iter += n;
      return *this;
    }

    iterator &operator-= (ptrdiff_t n)
    {
      m_iter -= n;
      return *this;
    }

    iterator &operator++ ()
    {
      ++m_iter;
      return *this;
    }

    iterator operator++ (int)
    {
      iterator i = *this;
      ++m_iter;
      return i;
    }

    iterator &operator-- ()
    {
      --m_iter;
      return *this;
    }

    iterator operator-- (int)
    {
      iterator i = *this;
      --m_iter;
      return i;
    }

    X &operator[] (ptrdiff_t n) const
    {
      return *m_iter [n];
    }

    X &operator* () const
    {
      return **m_iter;
    }

    X *operator-> () const
    {
      return *m_iter;
    }

  private:
    typename std::vector<X *>::iterator m_iter;
    friend class stable_vector::const_iterator;
  };

  class stable_iterator;

  class stable_const_iterator 
  {
  public:
    typedef std::random_access_iterator_tag iterator_category;
    typedef ptrdiff_t difference_type;
    typedef X value_type;
    typedef const X &reference;
    typedef const X *pointer;

    stable_const_iterator ()
      : mp_vector (0), m_index (0)
    {
      //  .. nothing yet ..
    }

    stable_const_iterator (const stable_const_iterator &d)
      : mp_vector (d.mp_vector), m_index (d.m_index)
    {
      //  .. nothing yet ..
    }

    stable_const_iterator (const stable_iterator &d)
      : mp_vector (d.mp_vector), m_index (d.m_index)
    {
      //  .. nothing yet ..
    }

    stable_const_iterator (const std::vector<X *> &v, size_t index)
      : mp_vector (&v), m_index (index)
    {
      //  .. nothing yet ..
    }

    stable_const_iterator &operator= (stable_const_iterator d) 
    {
      mp_vector = d.mp_vector;
      m_index = d.m_index;
      return *this;
    }

    stable_const_iterator &operator= (stable_iterator d) 
    {
      mp_vector = d.mp_vector;
      m_index = d.m_index;
      return *this;
    }

    bool operator== (stable_const_iterator d) const
    {
      return mp_vector == d.mp_vector && m_index == d.m_index;
    }

    bool operator!= (stable_const_iterator d) const
    {
      return !operator== (d);
    }

    bool operator< (stable_const_iterator d) const
    {
      return m_index < d.m_index;
    }

    ptrdiff_t operator- (stable_const_iterator d) const
    {
      return m_index - d.m_index;
    }

    stable_const_iterator operator+ (ptrdiff_t n) const
    {
      return stable_const_iterator (*mp_vector, m_index + n);
    }

    stable_const_iterator operator- (ptrdiff_t n) const
    {
      return stable_const_iterator (*mp_vector, m_index - n);
    }

    stable_const_iterator &operator+= (ptrdiff_t n) 
    {
      m_index += n;
      return *this;
    }

    stable_const_iterator &operator-= (ptrdiff_t n)
    {
      m_index -= n;
      return *this;
    }

    stable_const_iterator &operator++ ()
    {
      ++m_index;
      return *this;
    }

    stable_const_iterator operator++ (int)
    {
      stable_const_iterator i = *this;
      ++m_index;
      return i;
    }

    stable_const_iterator &operator-- ()
    {
      --m_index;
      return *this;
    }

    stable_const_iterator operator-- (int)
    {
      stable_const_iterator i = *this;
      --m_index;
      return i;
    }

    const X &operator[] (ptrdiff_t n) const
    {
      return *(*mp_vector) [m_index + n];
    }

    const X &operator* () const
    {
      return *(*mp_vector) [m_index];
    }

    const X *operator-> () const
    {
      return (*mp_vector) [m_index];
    }

    size_t index () const
    {
      return m_index;
    }

  private:
    const std::vector<X *> *mp_vector;
    size_t m_index;
  };

  class stable_iterator 
  {
  public:
    typedef std::random_access_iterator_tag iterator_category;
    typedef ptrdiff_t difference_type;
    typedef X value_type;
    typedef X &reference;
    typedef X *pointer;

    stable_iterator ()
      : mp_vector (0), m_index (0)
    {
      //  .. nothing yet ..
    }

    stable_iterator (const stable_iterator &d)
      : mp_vector (d.mp_vector), m_index (d.m_index)
    {
      //  .. nothing yet ..
    }

    stable_iterator (std::vector<X *> &v, size_t index)
      : mp_vector (&v), m_index (index)
    {
      //  .. nothing yet ..
    }

    stable_iterator &operator= (stable_iterator d) 
    {
      mp_vector = d.mp_vector;
      m_index = d.m_index;
      return *this;
    }

    bool operator== (stable_iterator d) const
    {
      return mp_vector == d.mp_vector && m_index == d.m_index;
    }

    bool operator!= (stable_iterator d) const
    {
      return !operator== (d);
    }

    bool operator< (stable_iterator d) const
    {
      return m_index < d.m_index;
    }

    ptrdiff_t operator- (stable_iterator d) const
    {
      return m_index - d.m_index;
    }

    stable_iterator operator+ (ptrdiff_t n) const
    {
      return stable_iterator (*mp_vector, m_index + n);
    }

    stable_iterator operator- (ptrdiff_t n) const
    {
      return stable_iterator (*mp_vector, m_index - n);
    }

    stable_iterator &operator+= (ptrdiff_t n) 
    {
      m_index += n;
      return *this;
    }

    stable_iterator &operator-= (ptrdiff_t n)
    {
      m_index -= n;
      return *this;
    }

    stable_iterator &operator++ ()
    {
      ++m_index;
      return *this;
    }

    stable_iterator operator++ (int)
    {
      stable_iterator i = *this;
      ++m_index;
      return i;
    }

    stable_iterator &operator-- ()
    {
      --m_index;
      return *this;
    }

    stable_iterator operator-- (int)
    {
      stable_iterator i = *this;
      --m_index;
      return i;
    }

    X &operator[] (ptrdiff_t n) const
    {
      return *(*mp_vector) [m_index + n];
    }

    X &operator* () const
    {
      return *(*mp_vector) [m_index];
    }

    X *operator-> () const
    {
      return (*mp_vector) [m_index];
    }

    size_t index () const
    {
      return m_index;
    }

  private:
    std::vector<X *> *mp_vector;
    size_t m_index;
    friend class stable_vector::stable_const_iterator;
  };

  stable_vector () 
    : m_objects ()
  {
    //  .. nothing yet ..
  }

  stable_vector (const stable_vector<X> &d) 
    : m_objects ()
  {
    operator= (d);
  }

  ~stable_vector ()
  {
    delete_objects ();
  }

  void reserve (size_t n)
  {
    m_objects.reserve (n);
  }

  stable_vector &operator= (const stable_vector<X> &d)
  {
    if (&d != this) {
      delete_objects ();
      m_objects.reserve (d.size ());
      for (typename std::vector <X *>::const_iterator c = d.m_objects.begin (); c != d.m_objects.end (); ++c) {
        m_objects.push_back (new X (**c));
      }
    }
    return *this;
  }

  bool operator== (const stable_vector<X> &d) const
  {
    if (size () != d.size ()) {
      return false;
    }
    for (typename std::vector <X *>::const_iterator a = m_objects.begin (), b = d.m_objects.begin (); a != m_objects.end (); ++a, ++b) {
      if (**a != **b) {
        return false;
      }
    }
    return true;
  }

  bool operator!= (const stable_vector<X> &d) const
  {
    return !operator== (d);
  }

  bool operator< (const stable_vector<X> &d) const
  {
    if (size () != d.size ()) {
      return size () < d.size ();
    }
    for (typename std::vector <X *>::const_iterator a = m_objects.begin (), b = d.m_objects.begin (); a != m_objects.end (); ++a, ++b) {
      if (**a != **b) {
        return **a < **b;
      }
    }
    return false;
  }

  void clear ()
  {
    delete_objects ();
  }

  bool empty () const
  {
    return m_objects.empty ();
  }

  void swap (stable_vector<X> &d)
  {
    m_objects.swap (d.m_objects);
  }

  void push_back (const X &o) 
  {
    m_objects.push_back (new X (o));
  }

  void push_back (X *o) 
  {
    m_objects.push_back (o);
  }

  const X &back () const
  {
    return *m_objects.back ();
  }

  const X &front () const
  {
    return *m_objects.front ();
  }

  X &back () 
  {
    return *m_objects.back ();
  }

  X &front () 
  {
    return *m_objects.front ();
  }

  void pop_back () 
  {
    delete m_objects.back ();
    m_objects.pop_back ();
  }

  stable_iterator insert (stable_iterator pos, const X &value)
  {
    m_objects.insert (m_objects.begin () + pos.index (), new X (value));
    return pos;
  }

  stable_iterator insert (stable_iterator pos, X *value)
  {
    m_objects.insert (m_objects.begin () + pos.index (), value);
    return pos;
  }

  void erase (stable_iterator pos)
  {
    typename std::vector <X *>::iterator p = m_objects.begin () + pos.index ();
    delete *p;
    m_objects.erase (p);
  }

  void erase (stable_iterator from, stable_iterator to)
  {
    typename std::vector <X *>::iterator p = m_objects.begin () + from.index ();
    typename std::vector <X *>::iterator q = m_objects.begin () + to.index ();
    for (typename std::vector <X *>::iterator i = p; i != q; ++i) {
      delete *i;
    }
    m_objects.erase (p, q);
  }

  iterator insert (iterator pos, const X &value)
  {
    size_t p = pos - begin ();
    m_objects.insert (m_objects.begin () + p, new X (value));
    return begin () + p;
  }

  iterator insert (iterator pos, X *value)
  {
    size_t p = pos - begin ();
    m_objects.insert (m_objects.begin () + p, value);
    return begin () + p;
  }

  void erase (iterator pos)
  {
    typename std::vector <X *>::iterator p = m_objects.begin () + (pos - begin ());
    delete *p;
    m_objects.erase (p);
  }

  void erase (iterator from, iterator to)
  {
    typename std::vector <X *>::iterator p = m_objects.begin () + (from - begin ());
    typename std::vector <X *>::iterator q = m_objects.begin () + (to - begin ());
    for (typename std::vector <X *>::iterator i = p; i != q; ++i) {
      delete *i;
    }
    m_objects.erase (p, q);
  }

  X &operator[] (size_t i)
  {
    return *m_objects [i];
  }

  const X &operator[] (size_t i) const
  {
    return *m_objects [i];
  }

  stable_iterator begin_stable () 
  {
    return stable_iterator (m_objects, 0);
  }

  stable_const_iterator begin_stable () const
  {
    return stable_const_iterator (m_objects, 0);
  }

  stable_iterator end_stable () 
  {
    return stable_iterator (m_objects, size ());
  }

  stable_const_iterator end_stable () const
  {
    return stable_const_iterator (m_objects, size ());
  }

  iterator begin () 
  {
    return iterator (m_objects.begin ());
  }

  const_iterator begin () const
  {
    return const_iterator (m_objects.begin ());
  }

  iterator end () 
  {
    return iterator (m_objects.end ());
  }

  const_iterator end () const
  {
    return const_iterator (m_objects.end ());
  }

  size_t size () const
  {
    return m_objects.size ();
  }

private:
  std::vector <X *> m_objects;

  void delete_objects () 
  {
    for (typename std::vector <X *>::iterator c = m_objects.begin (); c != m_objects.end (); ++c) {
      delete *c;
    }
    m_objects.clear ();
  }
};


} // namespace tl

#endif

