1 #ifndef YASLI_VECTOR_H_
2 #define YASLI_VECTOR_H_
4 // $Id: yasli_vector.h 754 2006-10-17 19:59:11Z syntheticpp $
8 #include "yasli_fill_iterator.h"
9 #include "yasli_memory.h"
10 #include "yasli_traits.h"
11 #include "yasli_protocols.h"
15 #include "../TypeManip.h"
19 template <class T, class Allocator = allocator<T> >
26 template <class T, class Allocator>
29 struct ebo : public Allocator
33 ebo(const Allocator &a) : Allocator(a) {}
39 typedef vector<T, Allocator> this_type;//not standard
40 typedef typename Allocator::reference reference;
41 typedef typename Allocator::const_reference const_reference;
42 typedef typename Allocator::pointer iterator; // See 23.1
43 typedef typename Allocator::const_pointer const_iterator; // See 23.1
44 typedef typename Allocator::size_type size_type; // See 23.1
45 typedef typename Allocator::difference_type difference_type;// See 23.1
47 typedef Allocator allocator_type;
48 typedef typename Allocator::pointer pointer;
49 typedef typename Allocator::const_pointer const_pointer;
50 typedef std::reverse_iterator<iterator> reverse_iterator;
51 typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
56 #if YASLI_UNDEFINED_POINTERS_COPYABLE == 1
68 void init_move(vector &temp)
76 void init_fill(size_type n, const T &value, const Allocator &a)
78 // Will avoid catch (...)
79 vector<T, Allocator> temp(a);
80 temp.insert(temp.end(), n, value);
85 // 23.2.4.1 construct/copy/destroy:
86 template <class InputIterator, class looks_like_itr>
87 void init(InputIterator first, InputIterator last, looks_like_itr, const Allocator &a)
90 temp.insert(temp.end(), first, last);
94 template <class non_iterator>
95 void init(non_iterator n, non_iterator datum, Loki::Int2Type<false>,
98 init_fill((size_type)n, (const T &)datum, a);
107 explicit vector(const Allocator &a)
113 explicit vector(size_type n, const T &value = T(),
114 const Allocator &a = Allocator())
116 init_fill(n, value, a);
120 template <class InputIterator>
121 vector(InputIterator first, InputIterator last, const Allocator &a = Allocator())
123 init(first, last, Loki::Int2Type<
124 yasli_nstd::is_class<InputIterator>::value ||
125 yasli_nstd::is_pointer<InputIterator>::value >(), a);
129 vector(const vector<T,Allocator>& x)
131 vector temp(x.begin(), x.end(), x.ebo_);
137 yasli_nstd::destroy(ebo_, ebo_.beg_, size());
138 const size_type c = capacity();
139 if (c != 0) ebo_.deallocate(ebo_.beg_, c);
142 // Note pass by value
143 vector<T,Allocator>& operator=(vector<T,Allocator> temp)
149 template <class InputIterator>
150 void assign(InputIterator first, InputIterator last)
153 assign_pre_impl(first, last, Loki::Int2Type<yasli_nstd::
154 is_class<InputIterator>::value||yasli_nstd::
155 is_pointer<InputIterator>::value>());
158 private://-------ASSIGN IMPLEMENTATION
159 template <class InputIterator, class looks_like_itr>
160 void assign_pre_impl(InputIterator first, InputIterator last, looks_like_itr)
162 assign_impl(first, last,
163 std::iterator_traits<InputIterator>::iterator_category());
166 template <class InputIterator>
167 void assign_pre_impl(InputIterator n, InputIterator datum, Loki::Int2Type<false>)
169 assign((size_type) n, (const T &) datum);
172 template <class InputIterator>
173 void assign_impl(InputIterator first, InputIterator last, std::input_iterator_tag)
175 for (iterator i = begin(); i != end(); ++i, ++first)
184 // we filled up the vector, now insert the rest
185 insert(end(), first, last);
188 template <class RanIt>
189 void assign_impl(RanIt first, RanIt last, std::random_access_iterator_tag)
191 const typename std::iterator_traits<RanIt>::difference_type d =
194 size_type newSize = size_type(d);
195 assert(newSize == d); // no funky iterators
197 if (newSize >= size())
199 const size_t delta = newSize - size();
200 RanIt i = last - delta;
201 copy(first, i, ebo_.beg_);
202 insert(end(), i, last);
206 copy(first, last, ebo_.beg_);
209 assert(size() == newSize);
212 void assign(size_type n, const T &u)
214 const size_type s = size();
217 T *const newEnd = ebo_.beg_ + n;
218 fill(ebo_.beg_, newEnd, u);
219 yasli_nstd::destroy(ebo_, newEnd, s - n);
225 T *const newEnd = ebo_.beg_ + n;
226 fill(ebo_.beg_, end_, u);
227 uninitialized_fill(end_, newEnd, u);
231 assert(empty() || front() == back());
234 allocator_type get_allocator() const
243 const_iterator begin() const
251 const_iterator end() const
255 reverse_iterator rbegin()
257 return reverse_iterator(end());
259 const_reverse_iterator rbegin() const
261 return const_reverse_iterator(end());
263 reverse_iterator rend()
265 return reverse_iterator(begin());
267 const_reverse_iterator rend() const
269 return const_reverse_iterator(begin());
272 // 23.2.4.2 capacity:
274 size_type size() const
276 return end_ - ebo_.beg_;
278 size_type max_size() const
280 return ebo_.max_size();
283 void resize(size_type sz, T c = T())
285 const size_type oldSz = size();
288 erase(ebo_.beg_ + sz, end_);
293 uninitialized_fill(end_, end_ + (sz - oldSz), c);
294 end_ = ebo_.beg_ + sz;
296 assert(size() == sz);
300 void resize_impl(size_type sz, T c)
304 size_type capacity() const
306 return eos_ - ebo_.beg_;
310 return ebo_.beg_ == end_;
312 void reserve(size_type n)
320 ebo_.beg_ = ebo_.allocate(n);
324 ebo_.beg_ = yasli_nstd::allocator_traits<Allocator>::reallocate(
325 ebo_, ebo_.beg_, end_, n);
327 end_ = ebo_.beg_ + s;
328 eos_ = ebo_.beg_ + n;
329 assert(capacity() >= n);
332 bool reserve_inplace_nstd(size_type n)
334 if (capacity() >= n) return true;
335 if (!yasli_nstd::allocator_traits<Allocator>::reallocate_inplace(
340 eos_ = ebo_.beg_ + n;
344 reference operator[](size_type n)
349 const_reference operator[](size_type n) const
354 const_reference at(size_type n) const
356 // Fix by Joseph Canedo
357 if (n >= size()) throw std::range_error("vector<>::at");
360 reference at(size_type n)
362 // Fix by Joseph Canedo
363 if (n >= size()) throw std::range_error("vector<>::at");
371 const_reference front() const
381 const_reference back() const
389 void prepare_growth(size_type delta)
391 const size_type s = size();
392 // @@@ todo: replace magic constant with something meaningful
393 const size_type smallThreshold = 8;
394 if (s < smallThreshold)
396 reserve(std::max(smallThreshold, delta));
400 const size_type multiply = 3;
401 const size_type divide = 2;
402 const size_type suggestedSize = (s * multiply) / divide;
403 reserve(std::max(s + delta, suggestedSize));
408 // 23.2.4.3 modifiers:
409 void push_back(const T &x)
411 if (size() == capacity())
421 ebo_.destroy(--end_);
423 void move_back_nstd(T &x)
425 if (size() == capacity())
429 yasli_protocols::move_traits<T>::nondestructive_move(&x, &x + 1, end_);
432 // 23.2.4.3 modifiers:
433 iterator insert(iterator position, const T &x)
435 // @@@ be smarter about this reservation
437 const size_type pos = position - begin();
438 insert(position, (size_type)1, x);
439 return ebo_.beg_ + pos;
441 void insert(iterator position, size_type n, const T &x)
444 yasli_nstd::fill_iterator<const T &>(x),
445 yasli_nstd::fill_iterator<const T &>(x, n)
449 template <class InputIterator>
450 void insert(iterator position, InputIterator first, InputIterator last)
452 insert_pre_impl(position, first, last,
453 Loki::Int2Type<yasli_nstd::is_class<InputIterator>::value||
454 yasli_nstd::is_pointer<InputIterator>::value>());
457 template<class InputIterator, class looks_like_iterator>
459 insert_pre_impl(iterator position, InputIterator first, InputIterator last,
462 insert_impl(position, first, last,
463 typename std::iterator_traits<InputIterator>::iterator_category());
466 template <class non_iterator>
467 void insert_pre_impl(iterator position, non_iterator n, non_iterator x,
468 Loki::Int2Type<false>)
470 //used if e.g. T is int and insert(itr, 10, 6) is called
471 insert(position, static_cast<size_type>(n),
472 static_cast<value_type>(x));
475 template <class InputIterator>
476 void insert_impl(iterator position,
477 InputIterator first, InputIterator last, std::input_iterator_tag)
479 for (; first != last; ++first)
481 position = insert(position, *first) + 1;
484 template <class FwdIterator>
485 void insert_impl(iterator position,
486 FwdIterator first, FwdIterator last, std::forward_iterator_tag)
488 typedef yasli_protocols::move_traits<T> mt;
490 const typename std::iterator_traits<FwdIterator>::difference_type
491 count = std::distance(first, last);
493 if (eos_ - end_ > count || reserve_inplace_nstd(size() + count)) // there's enough room
495 if (count > end_ - &*position)
497 // Step 1: fill the hole between end_ and position+count
498 FwdIterator i1 = first;
499 std::advance(i1, end_ - &*position);
501 std::advance(i2, &*position + count - end_);//why not i2 = first; advance(i2,count);
502 T *const oldEnd = end_;
503 end_ = copy(i1, i2, end_);
504 assert(end_ == &*position + count);
505 // Step 2: move existing data to the end
506 mt::nondestructive_move(
510 end_ = oldEnd + count;
511 // Step 3: copy in the remaining data
512 copy(first, i1, position);
516 mt::nondestructive_move(
521 mt::nondestructive_assign_move(
525 copy(first, last, position);
530 vector<T, Allocator> temp(ebo_);
531 temp.reserve(size() + count);
532 // The calls below won't cause infinite recursion
533 // because they will fall on the other branch
534 // of the if statement
535 temp.insert(temp.end(), begin(), position);
536 temp.insert(temp.end(), first, last);
537 temp.insert(temp.end(), position, end());
538 assert(temp.size() == size() + count);
544 iterator erase(iterator position)
546 erase(position, position + 1);
549 iterator erase(iterator first, iterator last)
551 yasli_protocols::move_traits<T>::nondestructive_assign_move(
554 const size_type destroyed = last - first;
555 yasli_nstd::destroy(a, end_ - destroyed, destroyed);
559 void swap(vector<T,Allocator>& rhs)//COULD DO THIS WITH LESS TEMPORARIES
561 std::swap(static_cast<Allocator &>(ebo_), static_cast<Allocator &>(rhs.ebo_));
562 std::swap(ebo_.beg_, rhs.ebo_.beg_);
563 std::swap(end_, rhs.end_);
564 std::swap(eos_, rhs.eos_);
569 yasli_nstd::destroy(a, ebo_.beg_, size());
576 template <class T, class Allocator>
577 bool operator==(const vector<T,Allocator>& x,
578 const vector<T,Allocator>& y);
579 template <class T, class Allocator>
580 bool operator< (const vector<T,Allocator>& x,
581 const vector<T,Allocator>& y);
582 template <class T, class Allocator>
583 bool operator!=(const vector<T,Allocator>& x,
584 const vector<T,Allocator>& y);
585 template <class T, class Allocator>
586 bool operator> (const vector<T,Allocator>& x,
587 const vector<T,Allocator>& y);
588 template <class T, class Allocator>
589 bool operator>=(const vector<T,Allocator>& x,
590 const vector<T,Allocator>& y);
591 template <class T, class Allocator>
592 bool operator<=(const vector<T,Allocator>& x,
593 const vector<T,Allocator>& y);
594 // specialized algorithms:
595 template <class T, class Allocator>
596 void swap(vector<T,Allocator>& x, vector<T,Allocator>& y);
602 namespace yasli_protocols
604 template <class T, class A>
605 struct move_traits< yasli::vector<T, A> >:public
606 yasli_nstd::type_selector<
607 sizeof(yasli::vector<T, A>) != (3 * sizeof(T *)),
608 memmove_traits< std::complex<T> >,
609 safe_move_traits< std::complex<T> >