b831f56c1f
git-svn-id: svn://svn.code.sf.net/p/loki-lib/code/trunk@754 7ec92016-0320-0410-acc4-a06ded1c099a
583 lines
No EOL
18 KiB
C++
583 lines
No EOL
18 KiB
C++
#ifndef YASLI_VECTOR_H_
|
|
#define YASLI_VECTOR_H_
|
|
|
|
// $Id$
|
|
|
|
|
|
#include "platform.h"
|
|
#include "yasli_fill_iterator.h"
|
|
#include "yasli_memory.h"
|
|
#include "yasli_traits.h"
|
|
#include "yasli_protocols.h"
|
|
#include <iterator>
|
|
#include <cassert>
|
|
#include <stdexcept>
|
|
#include "../TypeManip.h"
|
|
|
|
namespace yasli
|
|
{
|
|
template <class T, class Allocator = allocator<T> >
|
|
class vector;
|
|
}
|
|
|
|
namespace yasli {
|
|
|
|
template <class T, class Allocator>
|
|
class vector
|
|
{
|
|
struct ebo : public Allocator
|
|
{
|
|
T *beg_;
|
|
ebo() {}
|
|
ebo(const Allocator& a) : Allocator(a) {}
|
|
} ebo_;
|
|
T *end_;
|
|
T *eos_;
|
|
public:
|
|
// types:
|
|
typedef vector<T, Allocator> this_type;//not standard
|
|
typedef typename Allocator::reference reference;
|
|
typedef typename Allocator::const_reference const_reference;
|
|
typedef typename Allocator::pointer iterator; // See 23.1
|
|
typedef typename Allocator::const_pointer const_iterator; // See 23.1
|
|
typedef typename Allocator::size_type size_type; // See 23.1
|
|
typedef typename Allocator::difference_type difference_type;// See 23.1
|
|
typedef T value_type;
|
|
typedef Allocator allocator_type;
|
|
typedef typename Allocator::pointer pointer;
|
|
typedef typename Allocator::const_pointer const_pointer;
|
|
typedef std::reverse_iterator<iterator> reverse_iterator;
|
|
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
|
|
private:
|
|
void init_empty()
|
|
{
|
|
|
|
#if YASLI_UNDEFINED_POINTERS_COPYABLE == 1
|
|
end_ = ebo_.beg_;
|
|
eos_ = ebo_.beg_;
|
|
#else
|
|
ebo_.beg_ = 0;
|
|
end_ = 0;
|
|
eos_ = 0;
|
|
#endif
|
|
assert(empty());
|
|
|
|
}
|
|
|
|
void init_move(vector& temp)
|
|
{
|
|
ebo_ = temp.ebo_;
|
|
end_ = temp.end_;
|
|
eos_ = temp.eos_;
|
|
temp.init_empty();
|
|
}
|
|
|
|
void init_fill(size_type n, const T& value, const Allocator& a)
|
|
{
|
|
// Will avoid catch (...)
|
|
vector<T, Allocator> temp(a);
|
|
temp.insert(temp.end(), n, value);
|
|
init_move(temp);
|
|
assert(size() == n);
|
|
}
|
|
|
|
// 23.2.4.1 construct/copy/destroy:
|
|
template <class InputIterator, class looks_like_itr>
|
|
void init(InputIterator first, InputIterator last, looks_like_itr, const Allocator& a)
|
|
{
|
|
vector temp(a);
|
|
temp.insert(temp.end(), first, last);
|
|
init_move(temp);
|
|
}
|
|
|
|
template <class non_iterator>
|
|
void init(non_iterator n, non_iterator datum, Loki::Int2Type<false>,
|
|
const Allocator& a)
|
|
{
|
|
init_fill((size_type)n, (const T&)datum, a);
|
|
}
|
|
|
|
public:
|
|
vector()
|
|
{
|
|
init_empty();
|
|
}
|
|
|
|
explicit vector(const Allocator& a)
|
|
: ebo_(a)
|
|
{
|
|
init_empty();
|
|
}
|
|
|
|
explicit vector(size_type n, const T& value = T(),
|
|
const Allocator& a = Allocator())
|
|
{
|
|
init_fill(n, value, a);
|
|
}
|
|
|
|
//!! avoid enable_if
|
|
template <class InputIterator>
|
|
vector(InputIterator first, InputIterator last, const Allocator& a = Allocator())
|
|
{
|
|
init(first, last, Loki::Int2Type<
|
|
yasli_nstd::is_class<InputIterator>::value ||
|
|
yasli_nstd::is_pointer<InputIterator>::value >(), a);
|
|
}
|
|
|
|
public:
|
|
vector(const vector<T,Allocator>& x)
|
|
{
|
|
vector temp(x.begin(), x.end(), x.ebo_);
|
|
init_move(temp);
|
|
}
|
|
|
|
~vector()
|
|
{
|
|
yasli_nstd::destroy(ebo_, ebo_.beg_, size());
|
|
const size_type c = capacity();
|
|
if (c != 0) ebo_.deallocate(ebo_.beg_, c);
|
|
}
|
|
|
|
// Note pass by value
|
|
vector<T,Allocator>& operator=(vector<T,Allocator> temp)
|
|
{
|
|
temp.swap(*this);
|
|
return *this;
|
|
}
|
|
|
|
template <class InputIterator>
|
|
void assign(InputIterator first, InputIterator last)
|
|
{
|
|
|
|
assign_pre_impl(first, last, Loki::Int2Type<yasli_nstd::
|
|
is_class<InputIterator>::value||yasli_nstd::
|
|
is_pointer<InputIterator>::value>());
|
|
}
|
|
|
|
private://-------ASSIGN IMPLEMENTATION
|
|
template <class InputIterator, class looks_like_itr>
|
|
void assign_pre_impl(InputIterator first, InputIterator last, looks_like_itr)
|
|
{
|
|
assign_impl(first, last,
|
|
std::iterator_traits<InputIterator>::iterator_category());
|
|
}
|
|
|
|
template <class InputIterator>
|
|
void assign_pre_impl(InputIterator n, InputIterator datum, Loki::Int2Type<false>)
|
|
{
|
|
assign((size_type) n, (const T&) datum);
|
|
}
|
|
|
|
template <class InputIterator>
|
|
void assign_impl(InputIterator first, InputIterator last, std::input_iterator_tag)
|
|
{
|
|
for (iterator i = begin(); i != end(); ++i, ++first)
|
|
{
|
|
if (first == last)
|
|
{
|
|
resize(i - begin());
|
|
return;
|
|
}
|
|
*i = *first;
|
|
}
|
|
// we filled up the vector, now insert the rest
|
|
insert(end(), first, last);
|
|
}
|
|
|
|
template <class RanIt>
|
|
void assign_impl(RanIt first, RanIt last, std::random_access_iterator_tag)
|
|
{
|
|
const typename std::iterator_traits<RanIt>::difference_type d =
|
|
last - first;
|
|
assert(d >= 0);
|
|
size_type newSize = size_type(d);
|
|
assert(newSize == d); // no funky iterators
|
|
reserve(newSize);
|
|
if (newSize >= size())
|
|
{
|
|
const size_t delta = newSize - size();
|
|
RanIt i = last - delta;
|
|
copy(first, i, ebo_.beg_);
|
|
insert(end(), i, last);
|
|
}
|
|
else
|
|
{
|
|
copy(first, last, ebo_.beg_);
|
|
resize(newSize);
|
|
}
|
|
assert(size() == newSize);
|
|
}
|
|
public:
|
|
void assign(size_type n, const T& u)
|
|
{
|
|
const size_type s = size();
|
|
if (n <= s)
|
|
{
|
|
T* const newEnd = ebo_.beg_ + n;
|
|
fill(ebo_.beg_, newEnd, u);
|
|
yasli_nstd::destroy(ebo_, newEnd, s - n);
|
|
end_ = newEnd;
|
|
}
|
|
else
|
|
{
|
|
reserve(n);
|
|
T* const newEnd = ebo_.beg_ + n;
|
|
fill(ebo_.beg_, end_, u);
|
|
uninitialized_fill(end_, newEnd, u);
|
|
end_ = newEnd;
|
|
}
|
|
assert(size() == n);
|
|
assert(empty() || front() == back());
|
|
}
|
|
|
|
allocator_type get_allocator() const
|
|
{
|
|
return ebo_;
|
|
}
|
|
// iterators:
|
|
iterator begin() { return ebo_.beg_; }
|
|
const_iterator begin() const { return ebo_.beg_; }
|
|
iterator end() { return end_; }
|
|
const_iterator end() const { return end_; }
|
|
reverse_iterator rbegin() { return reverse_iterator(end()); }
|
|
const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); }
|
|
reverse_iterator rend() { return reverse_iterator(begin()); }
|
|
const_reverse_iterator rend() const { return const_reverse_iterator(begin()); }
|
|
|
|
// 23.2.4.2 capacity:
|
|
|
|
size_type size() const { return end_ - ebo_.beg_; }
|
|
size_type max_size() const { return ebo_.max_size(); }
|
|
|
|
void resize(size_type sz, T c = T())
|
|
{
|
|
const size_type oldSz = size();
|
|
if (oldSz >= sz)
|
|
{
|
|
erase(ebo_.beg_ + sz, end_);
|
|
}
|
|
else
|
|
{
|
|
reserve(sz);
|
|
uninitialized_fill(end_, end_ + (sz - oldSz), c);
|
|
end_ = ebo_.beg_ + sz;
|
|
}
|
|
assert(size() == sz);
|
|
}
|
|
private:
|
|
template<class is>
|
|
void resize_impl(size_type sz, T c)
|
|
{
|
|
}
|
|
public:
|
|
size_type capacity() const
|
|
{
|
|
return eos_ - ebo_.beg_;
|
|
}
|
|
bool empty() const
|
|
{
|
|
return ebo_.beg_ == end_;
|
|
}
|
|
void reserve(size_type n)
|
|
{
|
|
const size_type
|
|
s = size(),
|
|
c = capacity();
|
|
if (c >= n) return;
|
|
if (capacity() == 0)
|
|
{
|
|
ebo_.beg_ = ebo_.allocate(n);
|
|
}
|
|
else
|
|
{
|
|
ebo_.beg_ = yasli_nstd::allocator_traits<Allocator>::reallocate(
|
|
ebo_, ebo_.beg_, end_, n);
|
|
}
|
|
end_ = ebo_.beg_ + s;
|
|
eos_ = ebo_.beg_ + n;
|
|
assert(capacity() >= n);
|
|
assert(size() == s);
|
|
}
|
|
bool reserve_inplace_nstd(size_type n)
|
|
{
|
|
if (capacity() >= n) return true;
|
|
if (!yasli_nstd::allocator_traits<Allocator>::reallocate_inplace(
|
|
ebo_, ebo_.beg_, n))
|
|
{
|
|
return false;
|
|
}
|
|
eos_ = ebo_.beg_ + n;
|
|
return true;
|
|
}
|
|
// element access:
|
|
reference operator[](size_type n)
|
|
{
|
|
assert(n < size());
|
|
return ebo_.beg_[n];
|
|
}
|
|
const_reference operator[](size_type n) const
|
|
{
|
|
assert(n < size());
|
|
return ebo_.beg_[n];
|
|
}
|
|
const_reference at(size_type n) const
|
|
{
|
|
// Fix by Joseph Canedo
|
|
if (n >= size()) throw std::range_error("vector<>::at");
|
|
return ebo_.beg_[n];
|
|
}
|
|
reference at(size_type n)
|
|
{
|
|
// Fix by Joseph Canedo
|
|
if (n >= size()) throw std::range_error("vector<>::at");
|
|
return ebo_.beg_[n];
|
|
}
|
|
reference front()
|
|
{
|
|
assert(!empty());
|
|
return *ebo_.beg_;
|
|
}
|
|
const_reference front() const
|
|
{
|
|
assert(!empty());
|
|
return *ebo_.beg_;
|
|
}
|
|
reference back()
|
|
{
|
|
assert(!empty());
|
|
return end_[-1];
|
|
}
|
|
const_reference back() const
|
|
{
|
|
assert(!empty());
|
|
return end_[-1];
|
|
}
|
|
|
|
private:
|
|
|
|
void prepare_growth(size_type delta)
|
|
{
|
|
const size_type s = size();
|
|
// @@@ todo: replace magic constant with something meaningful
|
|
const size_type smallThreshold = 8;
|
|
if (s < smallThreshold)
|
|
{
|
|
reserve(std::max(smallThreshold, delta));
|
|
}
|
|
else
|
|
{
|
|
const size_type multiply = 3;
|
|
const size_type divide = 2;
|
|
const size_type suggestedSize = (s * multiply) / divide;
|
|
reserve(std::max(s + delta, suggestedSize));
|
|
}
|
|
}
|
|
|
|
public:
|
|
// 23.2.4.3 modifiers:
|
|
void push_back(const T& x)
|
|
{
|
|
if (size() == capacity())
|
|
{
|
|
prepare_growth(1);
|
|
}
|
|
new(end_) T(x);
|
|
++end_;
|
|
}
|
|
void pop_back()
|
|
{
|
|
assert(!empty());
|
|
ebo_.destroy(--end_);
|
|
}
|
|
void move_back_nstd(T& x)
|
|
{
|
|
if (size() == capacity())
|
|
{
|
|
prepare_growth(1);
|
|
}
|
|
yasli_protocols::move_traits<T>::nondestructive_move(&x, &x + 1, end_);
|
|
}
|
|
|
|
// 23.2.4.3 modifiers:
|
|
iterator insert(iterator position, const T& x)
|
|
{
|
|
// @@@ be smarter about this reservation
|
|
reserve(size() + 1);
|
|
const size_type pos = position - begin();
|
|
insert(position, (size_type)1, x);
|
|
return ebo_.beg_ + pos;
|
|
}
|
|
void insert(iterator position, size_type n, const T& x)
|
|
{
|
|
insert(position,
|
|
yasli_nstd::fill_iterator<const T&>(x),
|
|
yasli_nstd::fill_iterator<const T&>(x, n)
|
|
);
|
|
}
|
|
|
|
template <class InputIterator>
|
|
void insert(iterator position, InputIterator first, InputIterator last)
|
|
{
|
|
insert_pre_impl(position, first, last,
|
|
Loki::Int2Type<yasli_nstd::is_class<InputIterator>::value||
|
|
yasli_nstd::is_pointer<InputIterator>::value>());
|
|
}
|
|
private:
|
|
template<class InputIterator, class looks_like_iterator>
|
|
void
|
|
insert_pre_impl(iterator position, InputIterator first, InputIterator last,
|
|
looks_like_iterator)
|
|
{
|
|
insert_impl(position, first, last,
|
|
typename std::iterator_traits<InputIterator>::iterator_category());
|
|
}
|
|
|
|
template <class non_iterator>
|
|
void insert_pre_impl(iterator position, non_iterator n, non_iterator x,
|
|
Loki::Int2Type<false>)
|
|
{ //used if e.g. T is int and insert(itr, 10, 6) is called
|
|
insert(position, static_cast<size_type>(n),
|
|
static_cast<value_type>(x));
|
|
}
|
|
|
|
template <class InputIterator>
|
|
void insert_impl(iterator position,
|
|
InputIterator first, InputIterator last, std::input_iterator_tag)
|
|
{
|
|
for (; first != last; ++first)
|
|
{
|
|
position = insert(position, *first) + 1;
|
|
}
|
|
}
|
|
template <class FwdIterator>
|
|
void insert_impl(iterator position,
|
|
FwdIterator first, FwdIterator last, std::forward_iterator_tag)
|
|
{
|
|
typedef yasli_protocols::move_traits<T> mt;
|
|
|
|
const typename std::iterator_traits<FwdIterator>::difference_type
|
|
count = std::distance(first, last);
|
|
|
|
if (eos_ - end_ > count || reserve_inplace_nstd(size() + count)) // there's enough room
|
|
{
|
|
if (count > end_ - &*position)
|
|
{
|
|
// Step 1: fill the hole between end_ and position+count
|
|
FwdIterator i1 = first;
|
|
std::advance(i1, end_ - &*position);
|
|
FwdIterator i2 = i1;
|
|
std::advance(i2, &*position + count - end_);//why not i2 = first; advance(i2,count);
|
|
T* const oldEnd = end_;
|
|
end_ = copy(i1, i2, end_);
|
|
assert(end_ == &*position + count);
|
|
// Step 2: move existing data to the end
|
|
mt::nondestructive_move(
|
|
position,
|
|
oldEnd,
|
|
end_);
|
|
end_ = oldEnd + count;
|
|
// Step 3: copy in the remaining data
|
|
copy(first, i1, position);
|
|
}
|
|
else // simpler case
|
|
{
|
|
mt::nondestructive_move(
|
|
end_ - count,
|
|
end_,
|
|
end_);
|
|
end_ += count;
|
|
mt::nondestructive_assign_move(
|
|
position,
|
|
end_ - count,
|
|
position + count);
|
|
copy(first, last, position);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
vector<T, Allocator> temp(ebo_);
|
|
temp.reserve(size() + count);
|
|
// The calls below won't cause infinite recursion
|
|
// because they will fall on the other branch
|
|
// of the if statement
|
|
temp.insert(temp.end(), begin(), position);
|
|
temp.insert(temp.end(), first, last);
|
|
temp.insert(temp.end(), position, end());
|
|
assert(temp.size() == size() + count);
|
|
temp.swap(*this);
|
|
}
|
|
}
|
|
public:
|
|
|
|
iterator erase(iterator position)
|
|
{
|
|
erase(position, position + 1);
|
|
return position;
|
|
}
|
|
iterator erase(iterator first, iterator last)
|
|
{
|
|
yasli_protocols::move_traits<T>::nondestructive_assign_move(
|
|
last, end(), first);
|
|
Allocator& a = ebo_;
|
|
const size_type destroyed = last - first;
|
|
yasli_nstd::destroy(a, end_ - destroyed, destroyed);
|
|
end_ -= destroyed;
|
|
return first;
|
|
}
|
|
void swap(vector<T,Allocator>& rhs)//COULD DO THIS WITH LESS TEMPORARIES
|
|
{
|
|
std::swap(static_cast<Allocator&>(ebo_), static_cast<Allocator&>(rhs.ebo_));
|
|
std::swap(ebo_.beg_, rhs.ebo_.beg_);
|
|
std::swap(end_, rhs.end_);
|
|
std::swap(eos_, rhs.eos_);
|
|
}
|
|
void clear()
|
|
{
|
|
Allocator& a = ebo_;
|
|
yasli_nstd::destroy(a, ebo_.beg_, size());
|
|
end_ = ebo_.beg_;
|
|
}
|
|
};//vector
|
|
|
|
|
|
|
|
template <class T, class Allocator>
|
|
bool operator==(const vector<T,Allocator>& x,
|
|
const vector<T,Allocator>& y);
|
|
template <class T, class Allocator>
|
|
bool operator< (const vector<T,Allocator>& x,
|
|
const vector<T,Allocator>& y);
|
|
template <class T, class Allocator>
|
|
bool operator!=(const vector<T,Allocator>& x,
|
|
const vector<T,Allocator>& y);
|
|
template <class T, class Allocator>
|
|
bool operator> (const vector<T,Allocator>& x,
|
|
const vector<T,Allocator>& y);
|
|
template <class T, class Allocator>
|
|
bool operator>=(const vector<T,Allocator>& x,
|
|
const vector<T,Allocator>& y);
|
|
template <class T, class Allocator>
|
|
bool operator<=(const vector<T,Allocator>& x,
|
|
const vector<T,Allocator>& y);
|
|
// specialized algorithms:
|
|
template <class T, class Allocator>
|
|
void swap(vector<T,Allocator>& x, vector<T,Allocator>& y);
|
|
|
|
}//yasli
|
|
|
|
|
|
|
|
namespace yasli_protocols
|
|
{
|
|
template <class T, class A>
|
|
struct move_traits< yasli::vector<T, A> >:public
|
|
yasli_nstd::type_selector<
|
|
sizeof(yasli::vector<T, A>) != (3 * sizeof(T*)),
|
|
memmove_traits< std::complex<T> >,
|
|
safe_move_traits< std::complex<T> >
|
|
>::result
|
|
{
|
|
};
|
|
}
|
|
|
|
#endif |