mirror of https://github.com/KLayout/klayout.git
1006 lines
20 KiB
C++
1006 lines
20 KiB
C++
|
|
/*
|
|
|
|
KLayout Layout Viewer
|
|
Copyright (C) 2006-2017 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_tlReuseVector
|
|
#define HDR_tlReuseVector
|
|
|
|
#include <stdlib.h>
|
|
#include <iterator>
|
|
#include <vector>
|
|
#include <cstring>
|
|
|
|
#include "tlAssert.h"
|
|
#include "tlTypeTraits.h"
|
|
|
|
namespace tl
|
|
{
|
|
|
|
template <class Value> class reuse_vector;
|
|
template <class Value> class reuse_vector_const_iterator;
|
|
|
|
/**
|
|
* @brief The iterator for a reuse_vector
|
|
*/
|
|
|
|
template <class Value>
|
|
class reuse_vector_iterator
|
|
{
|
|
public:
|
|
typedef size_t size_type;
|
|
typedef Value value_type;
|
|
typedef value_type *pointer;
|
|
typedef value_type &reference; // operator* returns a value
|
|
typedef std::forward_iterator_tag iterator_category;
|
|
typedef size_type difference_type;
|
|
|
|
/**
|
|
* @brief The default constructor
|
|
*/
|
|
reuse_vector_iterator ()
|
|
: mp_v (0), m_n (0)
|
|
{ }
|
|
|
|
/**
|
|
* @brief The constructor
|
|
*/
|
|
reuse_vector_iterator (reuse_vector<Value> *v, size_type n)
|
|
: mp_v (v), m_n (n)
|
|
{ }
|
|
|
|
/**
|
|
* @brief Equality with const iterator
|
|
*/
|
|
bool operator== (const reuse_vector_const_iterator<Value> &d) const
|
|
{
|
|
return mp_v == d.mp_v && m_n == d.m_n;
|
|
}
|
|
|
|
/**
|
|
* @brief Inequality with const iterator
|
|
*/
|
|
bool operator!= (const reuse_vector_const_iterator<Value> &d) const
|
|
{
|
|
return ! operator== (d);
|
|
}
|
|
|
|
/**
|
|
* @brief Equality
|
|
*/
|
|
bool operator== (const reuse_vector_iterator &d) const
|
|
{
|
|
return mp_v == d.mp_v && m_n == d.m_n;
|
|
}
|
|
|
|
/**
|
|
* @brief Inequality
|
|
*/
|
|
bool operator!= (const reuse_vector_iterator &d) const
|
|
{
|
|
return ! operator== (d);
|
|
}
|
|
|
|
/**
|
|
* @brief Less operator
|
|
*/
|
|
bool operator< (const reuse_vector_iterator &d) const
|
|
{
|
|
if (mp_v != d.mp_v) {
|
|
return mp_v < d.mp_v;
|
|
}
|
|
return m_n < d.m_n;
|
|
}
|
|
|
|
/**
|
|
* @brief Dereference operator
|
|
*/
|
|
value_type &operator* () const
|
|
{
|
|
tl_assert (mp_v->is_used (m_n));
|
|
return mp_v->item (m_n);
|
|
}
|
|
|
|
/**
|
|
* @brief Access operator
|
|
*/
|
|
value_type *operator-> () const
|
|
{
|
|
tl_assert (mp_v->is_used (m_n));
|
|
return &mp_v->item (m_n);
|
|
}
|
|
|
|
/**
|
|
* @brief Validity
|
|
*
|
|
* An iterator is valid if the object is still available
|
|
* This does not take care about the container, but just about elements inside it.
|
|
* If the container is deleted, the iterators become invalid without further notice.
|
|
*/
|
|
bool is_valid () const
|
|
{
|
|
return mp_v->is_used (m_n);
|
|
}
|
|
|
|
/**
|
|
* @brief Increment operator
|
|
*/
|
|
reuse_vector_iterator &operator++ ()
|
|
{
|
|
do {
|
|
++m_n;
|
|
} while (! at_end () && ! mp_v->is_used (m_n));
|
|
return *this;
|
|
}
|
|
|
|
/**
|
|
* @brief "at end" predicate
|
|
*/
|
|
bool at_end () const
|
|
{
|
|
return index () >= mp_v->last ();
|
|
}
|
|
|
|
/**
|
|
* @brief The index of the element pointed to
|
|
*/
|
|
size_t index () const
|
|
{
|
|
return m_n;
|
|
}
|
|
|
|
/**
|
|
* @brief The pointer to the vector that this iterator points into
|
|
*/
|
|
reuse_vector<Value> *vector () const
|
|
{
|
|
return mp_v;
|
|
}
|
|
|
|
/**
|
|
* @brief A distance between two vectors
|
|
*/
|
|
difference_type operator- (reuse_vector_iterator d) const
|
|
{
|
|
// KLUDGE: this is slow and can be optimized if the vector does not have deleted items
|
|
difference_type n = 0;
|
|
while (d != *this) {
|
|
++d;
|
|
++n;
|
|
}
|
|
return n;
|
|
}
|
|
|
|
private:
|
|
template <class V> friend class reuse_vector_const_iterator;
|
|
|
|
reuse_vector<Value> *mp_v;
|
|
size_type m_n;
|
|
};
|
|
|
|
|
|
/**
|
|
* @brief The const_iterator for a reuse_vector
|
|
*/
|
|
|
|
template <class Value>
|
|
class reuse_vector_const_iterator
|
|
{
|
|
public:
|
|
typedef size_t size_type;
|
|
typedef Value value_type;
|
|
typedef const value_type *pointer;
|
|
typedef const value_type &reference; // operator* returns a value
|
|
typedef std::forward_iterator_tag iterator_category;
|
|
typedef size_type difference_type;
|
|
|
|
/**
|
|
* @brief The default constructor
|
|
*/
|
|
reuse_vector_const_iterator ()
|
|
: mp_v (0), m_n (0)
|
|
{ }
|
|
|
|
/**
|
|
* @brief The constructor
|
|
*/
|
|
reuse_vector_const_iterator (const reuse_vector<Value> *v, size_type n)
|
|
: mp_v (v), m_n (n)
|
|
{ }
|
|
|
|
/**
|
|
* @brief The conversion of a non-const iterator to a const iterator
|
|
*/
|
|
reuse_vector_const_iterator (const reuse_vector_iterator<Value> &d)
|
|
: mp_v (d.mp_v), m_n (d.m_n)
|
|
{ }
|
|
|
|
/**
|
|
* @brief cast to non-const iterator
|
|
*/
|
|
reuse_vector_iterator<Value> to_non_const () const
|
|
{
|
|
return reuse_vector_iterator<Value> (const_cast<reuse_vector<Value> *> (mp_v), m_n);
|
|
}
|
|
|
|
/**
|
|
* @brief Equality
|
|
*/
|
|
bool operator== (const reuse_vector_const_iterator &d) const
|
|
{
|
|
return mp_v == d.mp_v && m_n == d.m_n;
|
|
}
|
|
|
|
/**
|
|
* @brief Inequality
|
|
*/
|
|
bool operator!= (const reuse_vector_const_iterator &d) const
|
|
{
|
|
return ! operator== (d);
|
|
}
|
|
|
|
/**
|
|
* @brief Less operator
|
|
*/
|
|
bool operator< (const reuse_vector_const_iterator &d) const
|
|
{
|
|
if (mp_v != d.mp_v) {
|
|
return mp_v < d.mp_v;
|
|
}
|
|
return m_n < d.m_n;
|
|
}
|
|
|
|
/**
|
|
* @brief Dereference operator
|
|
*/
|
|
const value_type &operator* () const
|
|
{
|
|
tl_assert (mp_v->is_used (m_n));
|
|
return mp_v->item (m_n);
|
|
}
|
|
|
|
/**
|
|
* @brief Access operator
|
|
*/
|
|
const value_type *operator-> () const
|
|
{
|
|
tl_assert (mp_v->is_used (m_n));
|
|
return &mp_v->item (m_n);
|
|
}
|
|
|
|
/**
|
|
* @brief Unsafe access to the target address
|
|
*
|
|
* This method is intended for special use cases such as the cached box picker in
|
|
* the box tree
|
|
*/
|
|
const value_type *unsafe_target_addr () const
|
|
{
|
|
return &mp_v->item (m_n);
|
|
}
|
|
|
|
/**
|
|
* @brief Validity
|
|
*
|
|
* An iterator is valid if the object is still available
|
|
* This does not take care about the container, but just about elements inside it.
|
|
* If the container is deleted, the iterators become invalid without further notice.
|
|
*/
|
|
bool is_valid () const
|
|
{
|
|
return mp_v->is_used (m_n);
|
|
}
|
|
|
|
/**
|
|
* @brief Increment operator
|
|
*/
|
|
reuse_vector_const_iterator &operator++ ()
|
|
{
|
|
do {
|
|
++m_n;
|
|
} while (! at_end () && ! mp_v->is_used (m_n));
|
|
return *this;
|
|
}
|
|
|
|
/**
|
|
* @brief "at end" predicate
|
|
*/
|
|
bool at_end () const
|
|
{
|
|
return index () >= mp_v->last ();
|
|
}
|
|
|
|
/**
|
|
* @brief The index of the element pointed to
|
|
*/
|
|
size_t index () const
|
|
{
|
|
return m_n;
|
|
}
|
|
|
|
/**
|
|
* @brief The pointer to the vector that this iterator points into
|
|
*/
|
|
const reuse_vector<Value> *vector () const
|
|
{
|
|
return mp_v;
|
|
}
|
|
|
|
/**
|
|
* @brief A distance between two vectors
|
|
*/
|
|
difference_type operator- (reuse_vector_const_iterator d) const
|
|
{
|
|
// KLUDGE: this is slow and can be optimized if the vector does not have deleted items
|
|
difference_type n = 0;
|
|
while (d != *this) {
|
|
++d;
|
|
++n;
|
|
}
|
|
return n;
|
|
}
|
|
|
|
private:
|
|
template <class V> friend class reuse_vector_iterator;
|
|
|
|
const reuse_vector<Value> *mp_v;
|
|
size_type m_n;
|
|
};
|
|
|
|
|
|
/**
|
|
* @brief A helper class describing the "unused" entries of a reuse_vector
|
|
*/
|
|
|
|
class ReuseData
|
|
{
|
|
public:
|
|
typedef size_t size_type;
|
|
|
|
ReuseData ()
|
|
: m_first_used (0), m_last_used (0), m_next_free (0), m_size (0)
|
|
{ }
|
|
|
|
ReuseData (size_type n)
|
|
: m_first_used (0), m_last_used (n), m_next_free (n), m_size (n)
|
|
{
|
|
m_used.resize (n, true);
|
|
}
|
|
|
|
size_type first () const
|
|
{
|
|
return m_first_used;
|
|
}
|
|
|
|
size_type last () const
|
|
{
|
|
return m_last_used;
|
|
}
|
|
|
|
size_type size () const
|
|
{
|
|
return m_size;
|
|
}
|
|
|
|
size_type allocate ()
|
|
{
|
|
tl_assert (can_allocate ());
|
|
|
|
size_type r = m_next_free;
|
|
m_used [r] = true;
|
|
|
|
if (r >= m_last_used) {
|
|
m_last_used = r + 1;
|
|
}
|
|
if (r < m_first_used) {
|
|
m_first_used = r;
|
|
}
|
|
|
|
while (m_next_free != m_used.size () && m_used [m_next_free]) {
|
|
++m_next_free;
|
|
}
|
|
|
|
++m_size;
|
|
|
|
return r;
|
|
}
|
|
|
|
bool can_allocate () const
|
|
{
|
|
return (m_next_free < m_used.size ());
|
|
}
|
|
|
|
void deallocate (size_type n)
|
|
{
|
|
m_used [n] = false;
|
|
|
|
if (n == m_first_used) {
|
|
while (m_first_used < m_last_used && ! m_used [m_first_used]) {
|
|
++m_first_used;
|
|
}
|
|
}
|
|
|
|
if (n == m_last_used - 1) {
|
|
while (m_last_used > m_first_used && ! m_used [m_last_used - 1]) {
|
|
--m_last_used;
|
|
}
|
|
}
|
|
|
|
if (n < m_next_free) {
|
|
m_next_free = n;
|
|
}
|
|
|
|
--m_size;
|
|
}
|
|
|
|
void reserve (size_type n)
|
|
{
|
|
m_used.reserve (n);
|
|
}
|
|
|
|
bool is_used (size_type n) const
|
|
{
|
|
return m_used [n];
|
|
}
|
|
|
|
size_t mem_reqd () const
|
|
{
|
|
return (m_used.size () + 7) / 8 + sizeof (*this);
|
|
}
|
|
|
|
size_t mem_used () const
|
|
{
|
|
return m_used.capacity () / 8 + sizeof (*this);
|
|
}
|
|
|
|
private:
|
|
std::vector<bool> m_used;
|
|
size_type m_first_used, m_last_used, m_next_free, m_size;
|
|
};
|
|
|
|
/**
|
|
* @brief A vector that maintains the order of elements but allows to reference elements in a stable way
|
|
*
|
|
* This container allows to insert and delete elements while references to them (through iterators)
|
|
* remain stable. The insert does not necessarily happen at a certain position. Instead, the vector
|
|
* keeps a reuseable member list (hence reuse_vector). In addition, the iterators deliver stable references
|
|
* by using indices and a container pointer. This way, the iterators point to the same element
|
|
* even after delete and insert (and potentially reallocation) actions.
|
|
*
|
|
* The memory requirements of this container are the same than that of a std::vector.
|
|
*
|
|
* One requirement is that sizeof(C) >= sizeof(void *).
|
|
*/
|
|
|
|
template <class Value>
|
|
class reuse_vector
|
|
{
|
|
public:
|
|
typedef Value value_type;
|
|
typedef size_t size_type;
|
|
typedef reuse_vector_iterator<value_type> iterator;
|
|
typedef reuse_vector_const_iterator<value_type> const_iterator;
|
|
|
|
/**
|
|
* @brief Default constructor
|
|
*/
|
|
reuse_vector ()
|
|
{
|
|
init ();
|
|
}
|
|
|
|
/**
|
|
* @brief Assignment constructor
|
|
*
|
|
* Assign the sequence of [from,to) to the vector.
|
|
*/
|
|
template <class Iter>
|
|
reuse_vector (Iter from, Iter to)
|
|
{
|
|
init ();
|
|
reserve (std::distance (from, to));
|
|
insert (from, to);
|
|
}
|
|
|
|
/**
|
|
* @brief Copy constructor
|
|
*
|
|
* See operator= for a description of the copy operation.
|
|
*/
|
|
reuse_vector (const reuse_vector &d)
|
|
{
|
|
init ();
|
|
reserve (d.size ());
|
|
for (const_iterator i = d.begin (); i != d.end (); ++i) {
|
|
insert (*i);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Destructor
|
|
*/
|
|
~reuse_vector ()
|
|
{
|
|
release ();
|
|
}
|
|
|
|
/**
|
|
* @brief Assignment
|
|
*
|
|
* The assignment will not only copy the items but also compact the vector, i.e.
|
|
* create a linear chain of elements without holes for unused ones and a capacity
|
|
* exactly matching the required count.
|
|
*/
|
|
reuse_vector &operator= (const reuse_vector &d)
|
|
{
|
|
if (&d != this) {
|
|
release ();
|
|
reserve (d.size ());
|
|
for (const_iterator i = d.begin (); i != d.end (); ++i) {
|
|
insert (*i);
|
|
}
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
/**
|
|
* @brief Assignment
|
|
*
|
|
* Assign the sequence of [from,to) to the vector.
|
|
* See operator= for a description of the assignment semantics.
|
|
*/
|
|
template <class Iter>
|
|
void assign (Iter from, Iter to)
|
|
{
|
|
release ();
|
|
reserve (std::distance (from, to));
|
|
insert (from, to);
|
|
}
|
|
|
|
/**
|
|
* @brief equality operator
|
|
*/
|
|
bool operator== (const reuse_vector &d) const
|
|
{
|
|
if (size () != d.size ()) {
|
|
return false;
|
|
}
|
|
|
|
const_iterator i = begin ();
|
|
const_iterator ii = d.begin ();
|
|
while (i != end ()) {
|
|
if (*i != *ii) {
|
|
return false;
|
|
}
|
|
++i;
|
|
++ii;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* @brief Inequality
|
|
*/
|
|
bool operator!= (const reuse_vector &d) const
|
|
{
|
|
return ! operator== (d);
|
|
}
|
|
|
|
/**
|
|
* @brief less operator
|
|
*/
|
|
bool operator< (const reuse_vector &d) const
|
|
{
|
|
if (size () != d.size ()) {
|
|
return size () < d.size ();
|
|
}
|
|
|
|
const_iterator i = begin ();
|
|
const_iterator ii = d.begin ();
|
|
while (i != end ()) {
|
|
if (*i != *ii) {
|
|
return *i < *ii;
|
|
}
|
|
++i;
|
|
++ii;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* @brief For a given pointer, tell if the element is a member of this container
|
|
*/
|
|
template <class V>
|
|
bool is_member_of (const V *ptr) const
|
|
{
|
|
return (ptr >= mp_start && ptr < mp_finish);
|
|
}
|
|
|
|
/**
|
|
* @brief Deliver the iterator for a certain element (given by pointer)
|
|
*/
|
|
iterator iterator_from_pointer (Value *ptr)
|
|
{
|
|
return iterator (this, ptr - mp_start);
|
|
}
|
|
|
|
/**
|
|
* @brief "begin" iterator
|
|
*/
|
|
iterator begin ()
|
|
{
|
|
return iterator (this, first ());
|
|
}
|
|
|
|
/**
|
|
* @brief "end" iterator
|
|
*/
|
|
iterator end ()
|
|
{
|
|
return iterator (this, last ());
|
|
}
|
|
|
|
/**
|
|
* @brief Deliver the iterator for a certain element (given by pointer)
|
|
*/
|
|
const_iterator iterator_from_pointer (const Value *ptr) const
|
|
{
|
|
return const_iterator (this, ptr - mp_start);
|
|
}
|
|
|
|
/**
|
|
* @brief "begin" const iterator
|
|
*/
|
|
const_iterator begin () const
|
|
{
|
|
return const_iterator (this, first ());
|
|
}
|
|
|
|
/**
|
|
* @brief "end" const iterator
|
|
*/
|
|
const_iterator end () const
|
|
{
|
|
return const_iterator (this, last ());
|
|
}
|
|
|
|
/**
|
|
* @brief Access by the basic index
|
|
*
|
|
* The basic index is the internal index reported from the iterator's index() method
|
|
*/
|
|
value_type &item (size_type n)
|
|
{
|
|
return mp_start [n];
|
|
}
|
|
|
|
/**
|
|
* @brief Access by the basic index
|
|
*
|
|
* The basic index is the internal index reported from the iterator's index() method
|
|
*/
|
|
const value_type &item (size_type n) const
|
|
{
|
|
return mp_start [n];
|
|
}
|
|
|
|
/**
|
|
* @brief Insert one element into the container
|
|
*/
|
|
iterator insert (const value_type &item)
|
|
{
|
|
size_type n = 0;
|
|
|
|
if (mp_rdata) {
|
|
n = mp_rdata->allocate ();
|
|
// when the last unused member is allocated, we can remove the
|
|
// ReuseData pointer and add to the end
|
|
if (! mp_rdata->can_allocate ()) {
|
|
delete mp_rdata;
|
|
mp_rdata = 0;
|
|
}
|
|
} else {
|
|
if (mp_finish == mp_capacity) {
|
|
// Special case: we are inserting an element from our own space - since reserve will first
|
|
// release the element we have to create a copy before we insert it.
|
|
if (&item >= mp_start && &item < mp_finish) {
|
|
value_type copy (item);
|
|
return insert (copy);
|
|
}
|
|
reserve (size () == 0 ? 4 : size () * 2);
|
|
}
|
|
n = size_t (mp_finish - mp_start);
|
|
++mp_finish;
|
|
}
|
|
|
|
new (mp_start + n) value_type (item);
|
|
|
|
return iterator (this, n);
|
|
}
|
|
|
|
/**
|
|
* @brief Insert a sequence of elements [from,to) into the container
|
|
*/
|
|
template <class Iter>
|
|
void insert (const Iter &from, const Iter &to)
|
|
{
|
|
if (! (from == to)) {
|
|
// don't reservce if the first element of the sequence comes from ourself.
|
|
// This implies that we try to duplicate our own elements which would invalidate
|
|
// the source upon reservation.
|
|
if (! (&*from >= mp_start && &*from < mp_finish)) {
|
|
reserve (size () + std::distance (from, to));
|
|
}
|
|
for (Iter i = from; i != to; ++i) {
|
|
insert (*i);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Erase the given element from the container
|
|
*
|
|
* If the element was erased already, nothing will happen.
|
|
*/
|
|
void erase (const iterator &i)
|
|
{
|
|
if (! mp_rdata) {
|
|
mp_rdata = new ReuseData (size ());
|
|
}
|
|
|
|
if (mp_rdata->is_used (i.index ())) {
|
|
item (i.index ()).~value_type ();
|
|
mp_rdata->deallocate (i.index ());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Erase the given sequence from the container
|
|
*/
|
|
void erase (const iterator &from, const iterator &to)
|
|
{
|
|
// trivial shortcut
|
|
if (from == to) {
|
|
return;
|
|
}
|
|
|
|
if (! mp_rdata) {
|
|
mp_rdata = new ReuseData (size ());
|
|
}
|
|
|
|
for (size_type i = from.index (); i != to.index (); ++i) {
|
|
if (mp_rdata->is_used (i)) {
|
|
item (i).~value_type ();
|
|
mp_rdata->deallocate (i);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Clear the container
|
|
*
|
|
* This does not release the memory allocated for this container,
|
|
* similar to that what std::vector does.
|
|
*/
|
|
void clear ()
|
|
{
|
|
if (mp_start) {
|
|
// call destructor
|
|
for (size_type i = first (); i < last (); ++i) {
|
|
if (is_used (i)) {
|
|
item (i).~value_type ();
|
|
}
|
|
}
|
|
}
|
|
if (mp_rdata) {
|
|
delete mp_rdata;
|
|
mp_rdata = 0;
|
|
}
|
|
|
|
mp_finish = mp_start;
|
|
}
|
|
|
|
/**
|
|
* @brief Return the size
|
|
*
|
|
* The size is the number of elements that are actually stored.
|
|
* The size is computed in linear time.
|
|
*/
|
|
size_type size () const
|
|
{
|
|
if (mp_rdata) {
|
|
return mp_rdata->size ();
|
|
} else {
|
|
return size_type (mp_finish - mp_start);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Empty predicate
|
|
*/
|
|
bool empty () const
|
|
{
|
|
return size () == 0;
|
|
}
|
|
|
|
/**
|
|
* @brief Return the capacity
|
|
*
|
|
* The capacity is the number of elements that can be stored without reallocation to happen.
|
|
*/
|
|
size_type capacity () const
|
|
{
|
|
return size_type (mp_capacity - mp_start);
|
|
}
|
|
|
|
/**
|
|
* @brief Reserve space for a given number of elements
|
|
*
|
|
* This guarantees that for the next n-size() inserts no reallocation will occure
|
|
* No resizing will happen, if n is less than the current capacity.
|
|
*/
|
|
void reserve (size_type n)
|
|
{
|
|
typename tl::type_traits<Value>::relocate_requirements relocate_requirements_tag;
|
|
internal_reserve (n, relocate_requirements_tag);
|
|
}
|
|
|
|
/**
|
|
* @brief Release the memory allocated and clear the container
|
|
*/
|
|
void release ()
|
|
{
|
|
if (mp_start) {
|
|
// call destructor
|
|
for (size_type i = first (); i < last (); ++i) {
|
|
if (is_used (i)) {
|
|
item (i).~value_type ();
|
|
}
|
|
}
|
|
delete [] ((char *) mp_start);
|
|
}
|
|
if (mp_rdata) {
|
|
delete mp_rdata;
|
|
mp_rdata = 0;
|
|
}
|
|
init ();
|
|
}
|
|
|
|
size_t mem_reqd () const
|
|
{
|
|
return (mp_capacity - mp_start) * sizeof (Value) + (mp_rdata != 0 ? mp_rdata->mem_reqd () : 0);
|
|
}
|
|
|
|
size_t mem_used () const
|
|
{
|
|
return (mp_finish - mp_start) * sizeof (Value) + (mp_rdata != 0 ? mp_rdata->mem_used () : 0);
|
|
}
|
|
|
|
private:
|
|
value_type *mp_start, *mp_finish, *mp_capacity;
|
|
ReuseData *mp_rdata;
|
|
|
|
template<class V> friend class reuse_vector_iterator;
|
|
template<class V> friend class reuse_vector_const_iterator;
|
|
|
|
void init ()
|
|
{
|
|
mp_start = mp_finish = mp_capacity = 0;
|
|
mp_rdata = 0;
|
|
}
|
|
|
|
bool is_used (size_type n) const
|
|
{
|
|
if (n >= first () && n < last ()) {
|
|
if (mp_rdata) {
|
|
return mp_rdata->is_used (n);
|
|
} else {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
size_type first () const
|
|
{
|
|
if (mp_rdata) {
|
|
return mp_rdata->first ();
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
size_type last () const
|
|
{
|
|
if (mp_rdata) {
|
|
return mp_rdata->last ();
|
|
} else {
|
|
return size_type (mp_finish - mp_start);
|
|
}
|
|
}
|
|
|
|
void internal_reserve (size_type n, tl::complex_relocate_required)
|
|
{
|
|
if (n > capacity ()) {
|
|
|
|
value_type *new_start = (value_type *) (new char [sizeof (value_type) * n]);
|
|
|
|
size_type l = last ();
|
|
for (size_type i = first (); i < l; ++i) {
|
|
if (is_used (i)) {
|
|
new (new_start + i) value_type (item (i));
|
|
item (i).~value_type ();
|
|
}
|
|
}
|
|
|
|
size_type e = size_type (mp_finish - mp_start);
|
|
|
|
if (mp_rdata) {
|
|
mp_rdata->reserve (n);
|
|
}
|
|
|
|
if (mp_start) {
|
|
delete [] ((char *) mp_start);
|
|
}
|
|
|
|
mp_start = new_start;
|
|
mp_finish = mp_start + e;
|
|
mp_capacity = mp_start + n;
|
|
|
|
}
|
|
}
|
|
|
|
void internal_reserve (size_type n, tl::trivial_relocate_required)
|
|
{
|
|
if (n > capacity ()) {
|
|
|
|
value_type *new_start = (value_type *) (new char [sizeof (value_type) * n]);
|
|
|
|
size_type l = last ();
|
|
size_type i = first ();
|
|
memcpy ((void *)(new_start + i), (void *)(mp_start + i), (l - i) * sizeof (Value));
|
|
|
|
size_type e = size_type (mp_finish - mp_start);
|
|
|
|
if (mp_rdata) {
|
|
mp_rdata->reserve (n);
|
|
}
|
|
|
|
if (mp_start) {
|
|
delete [] ((char *) mp_start);
|
|
}
|
|
|
|
mp_start = new_start;
|
|
mp_finish = mp_start + e;
|
|
mp_capacity = mp_start + n;
|
|
|
|
}
|
|
}
|
|
};
|
|
|
|
}
|
|
|
|
#endif
|
|
|