pandorafms/extras/anytermd/libpbe/include/bistrector.hh

275 lines
6.3 KiB
C++

// include/bistrector.hh
// This file is part of libpbe; see http://svn.chezphil.org/libpbe/
// (C) 2008 Philip Endecott
// 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
// 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef libpbe_bistrector_hh
#define libpbe_bistrector_hh
// bistrector: bidirectionally-stretchy-vector
// -------------------------------------------
//
// Provides a vector which stretches when new elements are accessed
// using operator[]. It stretches in both directions, i.e. only enough
// space for elements between the minimum and maximem indices is
// allocated. In contrast, a strector allocates space between 0 and
// the maximum index.
//
// This is actually implemented using a pair of strectors, one for elements
// above the first one added and a reversed one for those below it. A
// consequence is that if elements are erased the bistrector cannot shrink
// beyond the first element added. In fact, erasing elements in general
// is problematic because of this and is not implemented, except for clear().
//
// The rules for invalidation etc. are the same as for strector.
//
// An additional optional constructor parameter allows you to specify a value
// used for new elements when the vector is resized during operator[] and
// when a beyond-the-end element is read as above.
#include "strector.hh"
#include <boost/iterator/iterator_facade.hpp>
namespace pbe {
template < typename T, typename ALLOC=std::allocator<T> >
class bistrector: public std::vector<T,ALLOC> {
typedef strector<T,ALLOC> strector_t;
strector_t bottom;
strector_t top;
size_t mid_index;
public:
typedef T value_type;
typedef T* pointer;
typedef T& reference;
typedef const T& const_reference;
typedef size_t size_type;
typedef ssize_t difference_type;
// Most of the vector ctors don't make much sense and aren't implemented.
bistrector(): mid_index(0) {}
explicit bistrector(const T& default_t): bottom(default_t), top(default_t), mid_index(0) {}
bistrector(const bistrector& other): bottom(other.bottom), top(other.top), mid_index(other.mid_index) {}
template <typename iter_t>
void advance_iterator(iter_t& i, bool& top_half, size_t n) {
if (n>0) {
if (top_half) {
i += n;
} else if (i-bottom.begin() >= n) {
i -= n;
} else {
i = top.begin() + (i-bottom.begin()) + (n-1);
top_half = true;
}
} else {
if (!top_half) {
i -= n;
} else if (i-top.begin() >= -n) {
i += n;
} else {
i = bottom.begin() + (i-top.begin()) + (-n-1);
top_half = false;
}
}
}
class iterator:
public boost::iterator_facade< iterator, T, std::random_access_iterator_tag > {
friend class boost::iterator_core_access;
friend class bistrector;
const bistrector& b;
bool top_half;
typename strector_t::iterator i;
iterator(const bistrector& b_, bool top_half_, typename strector_t::iterator i_):
b(b_), top_half(top_half_), i(i_)
{}
T& dereference() {
return *i;
}
bool equal(const iterator& other) {
return i == other.i;
}
void advance(size_t n) {
b.advance_iterator(i,top_half,n);
}
void increment() {
advance(1);
}
void decrement() {
advance(-1);
}
};
class const_iterator:
public boost::iterator_facade< const_iterator, T, std::random_access_iterator_tag, const T& > {
friend class boost::iterator_core_access;
friend class bistrector;
const bistrector& b;
bool top_half;
typename strector_t::const_iterator i;
const_iterator(const bistrector& b_, bool top_half_, typename strector_t::const_iterator i_):
b(b_), top_half(top_half_), i(i_)
{}
const T& dereference() {
return *i;
}
bool equal(const const_iterator& other) {
return i == other.i;
}
void advance(size_t n) {
bistrector::advance_iterator(i,top_half,n);
}
void increment() {
advance(1);
}
void decrement() {
advance(-1);
}
};
iterator begin() {
if (bottom.empty()) {
return iterator(*this,true,top.begin());
} else {
return iterator(*this,false,bottom.end()-1);
}
}
iterator end() {
return iterator(*this,true,top.end());
}
const_iterator begin() const {
if (bottom.empty()) {
return const_iterator(*this,true,top.begin());
} else {
return const_iterator(*this,false,bottom.end()-1);
}
}
const_iterator end() const {
return const_iterator(*this,true,top.end());
}
size_type size() const {
return top.size() + bottom.size();
}
size_type max_size() const {
return top.max_size() + bottom.max_size();
}
bool empty() const {
return top.empty() && bottom.empty();
}
reference operator[](size_type n) {
if (top.empty() && bottom.empty()) {
mid_index = n;
}
if (n>=mid_index) {
return top[n-mid_index];
} else {
return bottom[mid_index-n-1];
}
}
const_reference operator[](size_type n) const {
if (n>=mid_index) {
return top[n-mid_index];
} else {
return bottom[mid_index-n-1];
}
}
reference front() {
if (bottom.empty()) {
return top.front();
} else {
return bottom.back();
}
}
const_reference front() const {
if (bottom.empty()) {
return top.front();
} else {
return bottom.back();
}
}
reference back() {
if (top.empty()) {
return bottom.front();
} else {
return top.back();
}
}
const_reference back() const {
if (top.empty()) {
return bottom.front();
} else {
return top.back();
}
}
void push_back(const T& t) {
top.push_back(t);
}
void clear() {
top.clear();
bottom.clear();
}
};
};
#endif