Nugget
deque.h
1 // Copyright (c) Electronic Arts Inc. All rights reserved.
4 
6 // deque design
7 //
8 // A deque (pronounced "deck") is a double-ended queue, though this is partially
9 // of a misnomer. A deque does indeed let you add and remove values from both ends
10 // of the container, but it's not usually used for such a thing and instead is used
11 // as a more flexible version of a vector. It provides operator[] (random access)
12 // and can insert items anywhere and not just at the front and back.
13 //
14 // While you can implement a double-ended queue via a doubly-linked list, deque is
15 // instead implemented as a list of arrays. The benefit of this is that memory usage
16 // is lower and that random access can be had with decent efficiency.
17 //
18 // Our implementation of deque is just like every other implementation of deque,
19 // as the C++ standard all but dictates that you make it work this way. Below
20 // we have a depiction of an array (or vector) of 48 items, with each node being
21 // a '+' character and extra capacity being a '-' character. What we have is one
22 // contiguous block of memory:
23 //
24 // ++++++++++++++++++++++++++++++++++++++++++++++++-----------------
25 // 0 47
26 //
27 // With a deque, the same array of 48 items would be implemented as multiple smaller
28 // arrays of contiguous memory, each of fixed size. We will call these "sub-arrays."
29 // In the case here, we have six arrays of 8 nodes:
30 //
31 // ++++++++ ++++++++ ++++++++ ++++++++ ++++++++ ++++++++
32 //
33 // With an vector, item [0] is the first item and item [47] is the last item. With a
34 // deque, item [0] is usually not the first item and neither is item [47]. There is
35 // extra capacity on both the front side and the back side of the deque. So a deque
36 // (of 24 items) actually looks like this:
37 //
38 // -------- -----+++ ++++++++ ++++++++ +++++--- --------
39 // 0 23
40 //
41 // To insert items at the front, you move into the capacity on the left, and to insert
42 // items at the back, you append items on the right. As you can see, inserting an item
43 // at the front doesn't require allocating new memory nor does it require moving any
44 // items in the container. It merely involves moving the pointer to the [0] item to
45 // the left by one node.
46 //
47 // We keep track of these sub-arrays by having an array of pointers, with each array
48 // entry pointing to each of the sub-arrays. We could alternatively use a linked
49 // list of pointers, but it turns out we can implement our deque::operator[] more
50 // efficiently if we use an array of pointers instead of a list of pointers.
51 //
52 // To implement deque::iterator, we could keep a struct which is essentially this:
53 // struct iterator {
54 // int subArrayIndex;
55 // int subArrayOffset;
56 // }
57 //
58 // In practice, we implement iterators a little differently, but in reality our
59 // implementation isn't much different from the above. It turns out that it's most
60 // simple if we also manage the location of item [0] and item [end] by using these
61 // same iterators.
62 //
63 // To consider: Implement the deque as a circular deque instead of a linear one.
64 // This would use a similar subarray layout but iterators would
65 // wrap around when they reached the end of the subarray pointer list.
66 //
68 
69 
70 #ifndef EASTL_DEQUE_H
71 #define EASTL_DEQUE_H
72 
73 
74 #include <EASTL/internal/config.h>
75 #include <EASTL/allocator.h>
76 #include <EASTL/algorithm.h>
77 #include <EASTL/type_traits.h>
78 #include <EASTL/iterator.h>
79 #include <EASTL/memory.h>
80 #include <EASTL/initializer_list.h>
81 
82 EA_DISABLE_ALL_VC_WARNINGS()
83 #include <new>
84 #include <stddef.h>
85 EA_RESTORE_ALL_VC_WARNINGS()
86 
87 #if EASTL_EXCEPTIONS_ENABLED
88  EA_DISABLE_ALL_VC_WARNINGS()
89  #include <stdexcept> // std::out_of_range, std::length_error.
90  EA_RESTORE_ALL_VC_WARNINGS()
91 #endif
92 
93 
94 // 4267 - 'argument' : conversion from 'size_t' to 'const uint32_t', possible loss of data. This is a bogus warning resulting from a bug in VC++.
95 // 4345 - Behavior change: an object of POD type constructed with an initializer of the form () will be default-initialized
96 // 4480 - nonstandard extension used: specifying underlying type for enum
97 // 4530 - C++ exception handler used, but unwind semantics are not enabled. Specify /EHsc
98 // 4571 - catch(...) semantics changed since Visual C++ 7.1; structured exceptions (SEH) are no longer caught.
99 EA_DISABLE_VC_WARNING(4267 4345 4480 4530 4571);
100 
101 #if EASTL_EXCEPTIONS_ENABLED
102  // 4703 - potentially uninitialized local pointer variable used. VC++ is mistakenly analyzing the possibility of uninitialized variables, though it's not easy for it to do so.
103  // 4701 - potentially uninitialized local variable used.
104  EA_DISABLE_VC_WARNING(4703 4701)
105 #endif
106 
107 
108 #if defined(EA_PRAGMA_ONCE_SUPPORTED)
109  #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result.
110 #endif
111 
112 
113 namespace eastl
114 {
115 
120  #ifndef EASTL_DEQUE_DEFAULT_NAME
121  #define EASTL_DEQUE_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " deque" // Unless the user overrides something, this is "EASTL deque".
122  #endif
123 
124 
127  #ifndef EASTL_DEQUE_DEFAULT_ALLOCATOR
128  #define EASTL_DEQUE_DEFAULT_ALLOCATOR allocator_type(EASTL_DEQUE_DEFAULT_NAME)
129  #endif
130 
131 
138  #if !defined(__GNUC__) || (__GNUC__ >= 3) // GCC 2.x can't handle the declaration below.
139  #define DEQUE_DEFAULT_SUBARRAY_SIZE(T) ((sizeof(T) <= 4) ? 64 : ((sizeof(T) <= 8) ? 32 : ((sizeof(T) <= 16) ? 16 : ((sizeof(T) <= 32) ? 8 : 4))))
140  #else
141  #define DEQUE_DEFAULT_SUBARRAY_SIZE(T) 16
142  #endif
143 
144 
145 
151  template <typename T, typename Pointer, typename Reference, unsigned kDequeSubarraySize>
153  {
157  typedef ptrdiff_t difference_type;
158  typedef EASTL_ITC_NS::random_access_iterator_tag iterator_category;
159  typedef T value_type;
160  typedef T* pointer;
161  typedef T& reference;
162 
163  public:
164  DequeIterator();
165  DequeIterator(const iterator& x);
166 
167  pointer operator->() const;
168  reference operator*() const;
169 
170  this_type& operator++();
171  this_type operator++(int);
172 
173  this_type& operator--();
174  this_type operator--(int);
175 
176  this_type& operator+=(difference_type n);
177  this_type& operator-=(difference_type n);
178 
179  this_type operator+(difference_type n) const;
180  this_type operator-(difference_type n) const;
181 
182  protected:
183  template <typename, typename, typename, unsigned>
184  friend struct DequeIterator;
185 
186  template <typename, typename, unsigned>
187  friend struct DequeBase;
188 
189  template <typename, typename, unsigned>
190  friend class deque;
191 
192  template <typename U, typename PointerA, typename ReferenceA, typename PointerB, typename ReferenceB, unsigned kDequeSubarraySizeU>
195 
196  template <typename U, typename PointerA, typename ReferenceA, typename PointerB, typename ReferenceB, unsigned kDequeSubarraySizeU>
199 
200  template <typename U, typename PointerU, typename ReferenceU, unsigned kDequeSubarraySizeU>
201  friend bool operator!=(const DequeIterator<U, PointerU, ReferenceU, kDequeSubarraySizeU>& a,
203 
204  template <typename U, typename PointerA, typename ReferenceA, typename PointerB, typename ReferenceB, unsigned kDequeSubarraySizeU>
207 
208  template <typename U, typename PointerA, typename ReferenceA, typename PointerB, typename ReferenceB, unsigned kDequeSubarraySizeU>
211 
212  template <typename U, typename PointerA, typename ReferenceA, typename PointerB, typename ReferenceB, unsigned kDequeSubarraySizeU>
215 
216  template <typename U, typename PointerA, typename ReferenceA, typename PointerB, typename ReferenceB, unsigned kDequeSubarraySizeU>
219 
220  template <typename U, typename PointerA, typename ReferenceA, typename PointerB, typename ReferenceB, unsigned kDequeSubarraySizeU>
221  friend typename DequeIterator<U, PointerA, ReferenceA, kDequeSubarraySizeU>::difference_type
224 
225  protected:
226  T* mpCurrent; // Where we currently point. Declared first because it's used most often.
227  T* mpBegin; // The beginning of the current subarray.
228  T* mpEnd; // The end of the current subarray. To consider: remove this member, as it is always equal to 'mpBegin + kDequeSubarraySize'. Given that deque subarrays usually consist of hundreds of bytes, this isn't a massive win. Also, now that we are implementing a zero-allocation new deque policy, mpEnd may in fact not be equal to 'mpBegin + kDequeSubarraySize'.
229  T** mpCurrentArrayPtr; // Pointer to current subarray. We could alternatively implement this as a list node iterator if the deque used a linked list.
230 
231  struct Increment {};
232  struct Decrement {};
233  struct FromConst {};
234 
235  DequeIterator(T** pCurrentArrayPtr, T* pCurrent);
236  DequeIterator(const const_iterator& x, FromConst) : mpCurrent(x.mpCurrent), mpBegin(x.mpBegin), mpEnd(x.mpEnd), mpCurrentArrayPtr(x.mpCurrentArrayPtr){}
237  DequeIterator(const iterator& x, Increment);
238  DequeIterator(const iterator& x, Decrement);
239 
240  this_type copy(const iterator& first, const iterator& last, true_type); // true means that value_type has the type_trait has_trivial_relocate,
241  this_type copy(const iterator& first, const iterator& last, false_type); // false means it does not.
242 
243  void copy_backward(const iterator& first, const iterator& last, true_type); // true means that value_type has the type_trait has_trivial_relocate,
244  void copy_backward(const iterator& first, const iterator& last, false_type); // false means it does not.
245 
246  void SetSubarray(T** pCurrentArrayPtr);
247  };
248 
249 
250 
251 
258  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
259  struct DequeBase
260  {
261  typedef T value_type;
262  typedef Allocator allocator_type;
263  typedef eastl_size_t size_type; // See config.h for the definition of eastl_size_t, which defaults to size_t.
264  typedef ptrdiff_t difference_type;
267 
268  static const size_type npos = (size_type)-1;
269  static const size_type kMaxSize = (size_type)-2;
270 
271  enum
272  {
273  kMinPtrArraySize = 8,
274  kSubarraySize = kDequeSubarraySize
275  //kNodeSize = kDequeSubarraySize * sizeof(T) /// Disabled because it prevents the ability to do this: struct X{ eastl::deque<X, EASTLAllocatorType, 16> mDequeOfSelf; };
276  };
277 
278  enum Side
279  {
280  kSideFront,
281  kSideBack
282  };
283 
284  protected:
285  T** mpPtrArray; // Array of pointers to subarrays.
286  size_type mnPtrArraySize; // Possibly we should store this as T** mpArrayEnd.
287  iterator mItBegin; // Where within the subarrays is our beginning.
288  iterator mItEnd; // Where within the subarrays is our end.
289  allocator_type mAllocator; // To do: Use base class optimization to make this go away.
290 
291  public:
292  DequeBase(const allocator_type& allocator);
293  DequeBase(size_type n);
294  DequeBase(size_type n, const allocator_type& allocator);
295  ~DequeBase();
296 
297  const allocator_type& get_allocator() const EA_NOEXCEPT;
298  allocator_type& get_allocator() EA_NOEXCEPT;
299  void set_allocator(const allocator_type& allocator);
300 
301  protected:
302  T* DoAllocateSubarray();
303  void DoFreeSubarray(T* p);
304  void DoFreeSubarrays(T** pBegin, T** pEnd);
305 
306  T** DoAllocatePtrArray(size_type n);
307  void DoFreePtrArray(T** p, size_t n);
308 
309  iterator DoReallocSubarray(size_type nAdditionalCapacity, Side allocationSide);
310  void DoReallocPtrArray(size_type nAdditionalCapacity, Side allocationSide);
311 
312  void DoInit(size_type n);
313 
314  }; // DequeBase
315 
316 
317 
318 
336  template <typename T, typename Allocator = EASTLAllocatorType, unsigned kDequeSubarraySize = DEQUE_DEFAULT_SUBARRAY_SIZE(T)>
337  class deque : public DequeBase<T, Allocator, kDequeSubarraySize>
338  {
339  public:
342  typedef T value_type;
343  typedef T* pointer;
344  typedef const T* const_pointer;
345  typedef T& reference;
346  typedef const T& const_reference;
351  typedef typename base_type::size_type size_type;
352  typedef typename base_type::difference_type difference_type;
353  typedef typename base_type::allocator_type allocator_type;
354 
355  using base_type::kSideFront;
356  using base_type::kSideBack;
357  using base_type::mpPtrArray;
358  using base_type::mnPtrArraySize;
359  using base_type::mItBegin;
360  using base_type::mItEnd;
361  using base_type::mAllocator;
362  using base_type::npos;
363  using base_type::DoAllocateSubarray;
364  using base_type::DoFreeSubarray;
365  using base_type::DoFreeSubarrays;
366  using base_type::DoAllocatePtrArray;
367  using base_type::DoFreePtrArray;
368  using base_type::DoReallocSubarray;
369  using base_type::DoReallocPtrArray;
370 
371  public:
372  deque();
373  explicit deque(const allocator_type& allocator);
374  explicit deque(size_type n, const allocator_type& allocator = EASTL_DEQUE_DEFAULT_ALLOCATOR);
375  deque(size_type n, const value_type& value, const allocator_type& allocator = EASTL_DEQUE_DEFAULT_ALLOCATOR);
376  deque(const this_type& x);
377  deque(this_type&& x);
378  deque(this_type&& x, const allocator_type& allocator);
379  deque(std::initializer_list<value_type> ilist, const allocator_type& allocator = EASTL_DEQUE_DEFAULT_ALLOCATOR);
380 
381  template <typename InputIterator>
382  deque(InputIterator first, InputIterator last); // allocator arg removed because VC7.1 fails on the default arg. To do: Make a second version of this function without a default arg.
383 
384  ~deque();
385 
386  this_type& operator=(const this_type& x);
388  this_type& operator=(this_type&& x);
389 
390  void swap(this_type& x);
391 
392  void assign(size_type n, const value_type& value);
393  void assign(std::initializer_list<value_type> ilist);
394 
395  template <typename InputIterator> // It turns out that the C++ std::deque<int, int> specifies a two argument
396  void assign(InputIterator first, InputIterator last); // version of assign that takes (int size, int value). These are not
397  // iterators, so we need to do a template compiler trick to do the right thing.
398 
399  iterator begin() EA_NOEXCEPT;
400  const_iterator begin() const EA_NOEXCEPT;
401  const_iterator cbegin() const EA_NOEXCEPT;
402 
403  iterator end() EA_NOEXCEPT;
404  const_iterator end() const EA_NOEXCEPT;
405  const_iterator cend() const EA_NOEXCEPT;
406 
407  reverse_iterator rbegin() EA_NOEXCEPT;
408  const_reverse_iterator rbegin() const EA_NOEXCEPT;
409  const_reverse_iterator crbegin() const EA_NOEXCEPT;
410 
411  reverse_iterator rend() EA_NOEXCEPT;
412  const_reverse_iterator rend() const EA_NOEXCEPT;
413  const_reverse_iterator crend() const EA_NOEXCEPT;
414 
415  bool empty() const EA_NOEXCEPT;
416  size_type size() const EA_NOEXCEPT;
417 
418  void resize(size_type n, const value_type& value);
419  void resize(size_type n);
420 
421  void shrink_to_fit();
422  void set_capacity(size_type n = base_type::npos);
423 
424  reference operator[](size_type n);
425  const_reference operator[](size_type n) const;
426 
427  reference at(size_type n);
428  const_reference at(size_type n) const;
429 
430  reference front();
431  const_reference front() const;
432 
433  reference back();
434  const_reference back() const;
435 
436  void push_front(const value_type& value);
437  reference push_front();
438  void push_front(value_type&& value);
439 
440  void push_back(const value_type& value);
441  reference push_back();
442  void push_back(value_type&& value);
443 
444  void pop_front();
445  void pop_back();
446 
447  template<class... Args>
448  iterator emplace(const_iterator position, Args&&... args);
449 
450  template<class... Args>
451  void emplace_front(Args&&... args);
452 
453  template<class... Args>
454  void emplace_back(Args&&... args);
455 
456  iterator insert(const_iterator position, const value_type& value);
457  iterator insert(const_iterator position, value_type&& value);
458  void insert(const_iterator position, size_type n, const value_type& value);
459  iterator insert(const_iterator position, std::initializer_list<value_type> ilist);
460 
461  template <typename InputIterator>
462  void insert(const_iterator position, InputIterator first, InputIterator last);
463 
464  iterator erase(const_iterator position);
465  iterator erase(const_iterator first, const_iterator last);
466  reverse_iterator erase(reverse_iterator position);
468 
469  void clear();
470  //void reset_lose_memory(); // Disabled until it can be implemented efficiently and cleanly. // This is a unilateral reset to an initially empty state. No destructors are called, no deallocation occurs.
471 
472  bool validate() const;
473  int validate_iterator(const_iterator i) const;
474 
475  protected:
476  template <typename Integer>
477  void DoInit(Integer n, Integer value, true_type);
478 
479  template <typename InputIterator>
480  void DoInit(InputIterator first, InputIterator last, false_type);
481 
482  template <typename InputIterator>
483  void DoInitFromIterator(InputIterator first, InputIterator last, EASTL_ITC_NS::input_iterator_tag);
484 
485  template <typename ForwardIterator>
486  void DoInitFromIterator(ForwardIterator first, ForwardIterator last, EASTL_ITC_NS::forward_iterator_tag);
487 
488  void DoFillInit(const value_type& value);
489 
490  template <typename Integer>
491  void DoAssign(Integer n, Integer value, true_type);
492 
493  template <typename InputIterator>
494  void DoAssign(InputIterator first, InputIterator last, false_type);
495 
496  void DoAssignValues(size_type n, const value_type& value);
497 
498  template <typename Integer>
499  void DoInsert(const const_iterator& position, Integer n, Integer value, true_type);
500 
501  template <typename InputIterator>
502  void DoInsert(const const_iterator& position, const InputIterator& first, const InputIterator& last, false_type);
503 
504  template <typename InputIterator>
505  void DoInsertFromIterator(const_iterator position, const InputIterator& first, const InputIterator& last, EASTL_ITC_NS::forward_iterator_tag);
506 
507  void DoInsertValues(const_iterator position, size_type n, const value_type& value);
508 
509  void DoSwap(this_type& x);
510  }; // class deque
511 
512 
513 
514 
516  // DequeBase
518 
519  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
520  DequeBase<T, Allocator, kDequeSubarraySize>::DequeBase(const allocator_type& allocator)
521  : mpPtrArray(NULL),
522  mnPtrArraySize(0),
523  mItBegin(),
524  mItEnd(),
525  mAllocator(allocator)
526  {
527  // It is assumed here that the deque subclass will init us when/as needed.
528  }
529 
530 
531  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
533  : mpPtrArray(NULL),
534  mnPtrArraySize(0),
535  mItBegin(),
536  mItEnd(),
537  mAllocator(EASTL_DEQUE_DEFAULT_NAME)
538  {
539  // It's important to note that DoInit creates space for elements and assigns
540  // mItBegin/mItEnd to point to them, but these elements are not constructed.
541  // You need to immediately follow this constructor with code that constructs the values.
542  DoInit(n);
543  }
544 
545 
546  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
547  DequeBase<T, Allocator, kDequeSubarraySize>::DequeBase(size_type n, const allocator_type& allocator)
548  : mpPtrArray(NULL),
549  mnPtrArraySize(0),
550  mItBegin(),
551  mItEnd(),
552  mAllocator(allocator)
553  {
554  // It's important to note that DoInit creates space for elements and assigns
555  // mItBegin/mItEnd to point to them, but these elements are not constructed.
556  // You need to immediately follow this constructor with code that constructs the values.
557  DoInit(n);
558  }
559 
560 
561  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
562  DequeBase<T, Allocator, kDequeSubarraySize>::~DequeBase()
563  {
564  if(mpPtrArray)
565  {
566  DoFreeSubarrays(mItBegin.mpCurrentArrayPtr, mItEnd.mpCurrentArrayPtr + 1);
567  DoFreePtrArray(mpPtrArray, mnPtrArraySize);
568  mpPtrArray = nullptr;
569  }
570  }
571 
572 
573  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
574  const typename DequeBase<T, Allocator, kDequeSubarraySize>::allocator_type&
575  DequeBase<T, Allocator, kDequeSubarraySize>::get_allocator() const EA_NOEXCEPT
576  {
577  return mAllocator;
578  }
579 
580 
581  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
582  typename DequeBase<T, Allocator, kDequeSubarraySize>::allocator_type&
583  DequeBase<T, Allocator, kDequeSubarraySize>::get_allocator() EA_NOEXCEPT
584  {
585  return mAllocator;
586  }
587 
588 
589  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
590  void DequeBase<T, Allocator, kDequeSubarraySize>::set_allocator(const allocator_type& allocator)
591  {
592  // The only time you can set an allocator is with an empty unused container, such as right after construction.
593  if(EASTL_LIKELY(mAllocator != allocator))
594  {
595  if(EASTL_LIKELY(mpPtrArray && (mItBegin.mpCurrentArrayPtr == mItEnd.mpCurrentArrayPtr))) // If we are empty and so can safely deallocate the existing memory... We could also test for empty(), but that's a more expensive calculation and more involved clearing, though it would be more flexible.
596  {
597  DoFreeSubarrays(mItBegin.mpCurrentArrayPtr, mItEnd.mpCurrentArrayPtr + 1);
598  DoFreePtrArray(mpPtrArray, mnPtrArraySize);
599 
600  mAllocator = allocator;
601  DoInit(0);
602  }
603  else
604  {
605  EASTL_FAIL_MSG("DequeBase::set_allocator -- atempt to change allocator after allocating elements.");
606  }
607  }
608  }
609 
610 
611  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
612  T* DequeBase<T, Allocator, kDequeSubarraySize>::DoAllocateSubarray()
613  {
614  T* p = (T*)allocate_memory(mAllocator, kDequeSubarraySize * sizeof(T), EASTL_ALIGN_OF(T), 0);
615  EASTL_ASSERT_MSG(p != nullptr, "the behaviour of eastl::allocators that return nullptr is not defined.");
616 
617  #if EASTL_DEBUG
618  memset((void*)p, 0, kDequeSubarraySize * sizeof(T));
619  #endif
620 
621  return (T*)p;
622  }
623 
624 
625  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
626  void DequeBase<T, Allocator, kDequeSubarraySize>::DoFreeSubarray(T* p)
627  {
628  if(p)
629  EASTLFree(mAllocator, p, kDequeSubarraySize * sizeof(T));
630  }
631 
632  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
633  void DequeBase<T, Allocator, kDequeSubarraySize>::DoFreeSubarrays(T** pBegin, T** pEnd)
634  {
635  while(pBegin < pEnd)
636  DoFreeSubarray(*pBegin++);
637  }
638 
639  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
640  T** DequeBase<T, Allocator, kDequeSubarraySize>::DoAllocatePtrArray(size_type n)
641  {
642  #if EASTL_ASSERT_ENABLED
643  if(EASTL_UNLIKELY(n >= 0x80000000))
644  EASTL_FAIL_MSG("deque::DoAllocatePtrArray -- improbably large request.");
645  #endif
646 
647  T** pp = (T**)allocate_memory(mAllocator, n * sizeof(T*), EASTL_ALIGN_OF(T), 0);
648  EASTL_ASSERT_MSG(pp != nullptr, "the behaviour of eastl::allocators that return nullptr is not defined.");
649 
650  #if EASTL_DEBUG
651  memset((void*)pp, 0, n * sizeof(T*));
652  #endif
653 
654  return pp;
655  }
656 
657 
658  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
659  void DequeBase<T, Allocator, kDequeSubarraySize>::DoFreePtrArray(T** pp, size_t n)
660  {
661  if(pp)
662  EASTLFree(mAllocator, pp, n * sizeof(T*));
663  }
664 
665 
666  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
667  typename DequeBase<T, Allocator, kDequeSubarraySize>::iterator
668  DequeBase<T, Allocator, kDequeSubarraySize>::DoReallocSubarray(size_type nAdditionalCapacity, Side allocationSide)
669  {
670  // nAdditionalCapacity refers to the amount of additional space we need to be
671  // able to store in this deque. Typically this function is called as part of
672  // an insert or append operation. This is the function that makes sure there
673  // is enough capacity for the new elements to be copied into the deque.
674  // The new capacity here is always at the front or back of the deque.
675  // This function returns an iterator to that points to the new begin or
676  // the new end of the deque space, depending on allocationSide.
677 
678  if(allocationSide == kSideFront)
679  {
680  // There might be some free space (nCurrentAdditionalCapacity) at the front of the existing subarray.
681  const size_type nCurrentAdditionalCapacity = (size_type)(mItBegin.mpCurrent - mItBegin.mpBegin);
682 
683  if(EASTL_UNLIKELY(nCurrentAdditionalCapacity < nAdditionalCapacity)) // If we need to grow downward into a new subarray...
684  {
685  const difference_type nSubarrayIncrease = (difference_type)(((nAdditionalCapacity - nCurrentAdditionalCapacity) + kDequeSubarraySize - 1) / kDequeSubarraySize);
686  difference_type i;
687 
688  if(nSubarrayIncrease > (mItBegin.mpCurrentArrayPtr - mpPtrArray)) // If there are not enough pointers in front of the current (first) one...
689  DoReallocPtrArray((size_type)(nSubarrayIncrease - (mItBegin.mpCurrentArrayPtr - mpPtrArray)), kSideFront);
690 
691  #if EASTL_EXCEPTIONS_ENABLED
692  try
693  {
694  #endif
695  for(i = 1; i <= nSubarrayIncrease; ++i)
696  mItBegin.mpCurrentArrayPtr[-i] = DoAllocateSubarray();
697  #if EASTL_EXCEPTIONS_ENABLED
698  }
699  catch(...)
700  {
701  for(difference_type j = 1; j < i; ++j)
702  DoFreeSubarray(mItBegin.mpCurrentArrayPtr[-j]);
703  throw;
704  }
705  #endif
706  }
707 
708  return mItBegin - (difference_type)nAdditionalCapacity;
709  }
710  else // else kSideBack
711  {
712  const size_type nCurrentAdditionalCapacity = (size_type)((mItEnd.mpEnd - 1) - mItEnd.mpCurrent);
713 
714  if(EASTL_UNLIKELY(nCurrentAdditionalCapacity < nAdditionalCapacity)) // If we need to grow forward into a new subarray...
715  {
716  const difference_type nSubarrayIncrease = (difference_type)(((nAdditionalCapacity - nCurrentAdditionalCapacity) + kDequeSubarraySize - 1) / kDequeSubarraySize);
717  difference_type i;
718 
719  if(nSubarrayIncrease > ((mpPtrArray + mnPtrArraySize) - mItEnd.mpCurrentArrayPtr) - 1) // If there are not enough pointers after the current (last) one...
720  DoReallocPtrArray((size_type)(nSubarrayIncrease - (((mpPtrArray + mnPtrArraySize) - mItEnd.mpCurrentArrayPtr) - 1)), kSideBack);
721 
722  #if EASTL_EXCEPTIONS_ENABLED
723  try
724  {
725  #endif
726  for(i = 1; i <= nSubarrayIncrease; ++i)
727  mItEnd.mpCurrentArrayPtr[i] = DoAllocateSubarray();
728  #if EASTL_EXCEPTIONS_ENABLED
729  }
730  catch(...)
731  {
732  for(difference_type j = 1; j < i; ++j)
733  DoFreeSubarray(mItEnd.mpCurrentArrayPtr[j]);
734  throw;
735  }
736  #endif
737  }
738 
739  return mItEnd + (difference_type)nAdditionalCapacity;
740  }
741  }
742 
743 
744  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
745  void DequeBase<T, Allocator, kDequeSubarraySize>::DoReallocPtrArray(size_type nAdditionalCapacity, Side allocationSide)
746  {
747  // This function is not called unless the capacity is known to require a resize.
748  //
749  // We have an array of pointers (mpPtrArray), of which a segment of them are in use and
750  // at either end of the array are zero or more unused pointers. This function is being
751  // called because we need to extend the capacity on either side of this array by
752  // nAdditionalCapacity pointers. However, it's possible that if the user is continually
753  // using push_back and pop_front then the pointer array will continue to be extended
754  // on the back side and unused on the front side. So while we are doing this resizing
755  // here we also take the opportunity to recenter the pointers and thus be balanced.
756  // It man turn out that we don't even need to reallocate the pointer array in order
757  // to increase capacity on one side, as simply moving the pointers to the center may
758  // be enough to open up the requires space.
759  //
760  // Balanced pointer array Unbalanced pointer array (unused space at front, no free space at back)
761  // ----++++++++++++---- ---------+++++++++++
762 
763  const size_type nUnusedPtrCountAtFront = (size_type)(mItBegin.mpCurrentArrayPtr - mpPtrArray);
764  const size_type nUsedPtrCount = (size_type)(mItEnd.mpCurrentArrayPtr - mItBegin.mpCurrentArrayPtr) + 1;
765  const size_type nUsedPtrSpace = nUsedPtrCount * sizeof(void*);
766  const size_type nUnusedPtrCountAtBack = (mnPtrArraySize - nUnusedPtrCountAtFront) - nUsedPtrCount;
767  value_type** pPtrArrayBegin;
768 
769  if((allocationSide == kSideBack) && (nAdditionalCapacity <= nUnusedPtrCountAtFront)) // If we can take advantage of unused pointers at the front without doing any reallocation...
770  {
771  if(nAdditionalCapacity < (nUnusedPtrCountAtFront / 2)) // Possibly use more space than required, if there's a lot of extra space.
772  nAdditionalCapacity = (nUnusedPtrCountAtFront / 2);
773 
774  pPtrArrayBegin = mpPtrArray + (nUnusedPtrCountAtFront - nAdditionalCapacity);
775  memmove(pPtrArrayBegin, mItBegin.mpCurrentArrayPtr, nUsedPtrSpace);
776 
777  #if EASTL_DEBUG
778  memset(pPtrArrayBegin + nUsedPtrCount, 0, (size_t)(mpPtrArray + mnPtrArraySize) - (size_t)(pPtrArrayBegin + nUsedPtrCount));
779  #endif
780  }
781  else if((allocationSide == kSideFront) && (nAdditionalCapacity <= nUnusedPtrCountAtBack)) // If we can take advantage of unused pointers at the back without doing any reallocation...
782  {
783  if(nAdditionalCapacity < (nUnusedPtrCountAtBack / 2)) // Possibly use more space than required, if there's a lot of extra space.
784  nAdditionalCapacity = (nUnusedPtrCountAtBack / 2);
785 
786  pPtrArrayBegin = mItBegin.mpCurrentArrayPtr + nAdditionalCapacity;
787  memmove(pPtrArrayBegin, mItBegin.mpCurrentArrayPtr, nUsedPtrSpace);
788 
789  #if EASTL_DEBUG
790  memset(mpPtrArray, 0, (size_t)((uintptr_t)pPtrArrayBegin - (uintptr_t)mpPtrArray));
791  #endif
792  }
793  else
794  {
795  // In this case we will have to do a reallocation.
796  const size_type nNewPtrArraySize = mnPtrArraySize + eastl::max_alt(mnPtrArraySize, nAdditionalCapacity) + 2; // Allocate extra capacity.
797  value_type** const pNewPtrArray = DoAllocatePtrArray(nNewPtrArraySize);
798 
799  pPtrArrayBegin = pNewPtrArray + (mItBegin.mpCurrentArrayPtr - mpPtrArray) + ((allocationSide == kSideFront) ? nAdditionalCapacity : 0);
800 
801  // The following is equivalent to: eastl::copy(mItBegin.mpCurrentArrayPtr, mItEnd.mpCurrentArrayPtr + 1, pPtrArrayBegin);
802  // It's OK to use memcpy instead of memmove because the destination is guaranteed to non-overlap the source.
803  if(mpPtrArray) // Could also say: 'if(mItBegin.mpCurrentArrayPtr)'
804  memcpy(pPtrArrayBegin, mItBegin.mpCurrentArrayPtr, nUsedPtrSpace);
805 
806  DoFreePtrArray(mpPtrArray, mnPtrArraySize);
807 
808  mpPtrArray = pNewPtrArray;
809  mnPtrArraySize = nNewPtrArraySize;
810  }
811 
812  // We need to reset the begin and end iterators, as code that calls this expects them to *not* be invalidated.
813  mItBegin.SetSubarray(pPtrArrayBegin);
814  mItEnd.SetSubarray((pPtrArrayBegin + nUsedPtrCount) - 1);
815  }
816 
817 
818  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
819  void DequeBase<T, Allocator, kDequeSubarraySize>::DoInit(size_type n)
820  {
821  // This code is disabled because it doesn't currently work properly.
822  // We are trying to make it so that a deque can have a zero allocation
823  // initial empty state, but we (OK, I) am having a hard time making
824  // this elegant and efficient.
825  //if(n)
826  //{
827  const size_type nNewPtrArraySize = (size_type)((n / kDequeSubarraySize) + 1); // Always have at least one, even if n is zero.
828  const size_type kMinPtrArraySize_ = kMinPtrArraySize;
829 
830  mnPtrArraySize = eastl::max_alt(kMinPtrArraySize_, (nNewPtrArraySize + 2));
831  mpPtrArray = DoAllocatePtrArray(mnPtrArraySize);
832 
833  value_type** const pPtrArrayBegin = (mpPtrArray + ((mnPtrArraySize - nNewPtrArraySize) / 2)); // Try to place it in the middle.
834  value_type** const pPtrArrayEnd = pPtrArrayBegin + nNewPtrArraySize;
835  value_type** pPtrArrayCurrent = pPtrArrayBegin;
836 
837  #if EASTL_EXCEPTIONS_ENABLED
838  try
839  {
840  try
841  {
842  #endif
843  while(pPtrArrayCurrent < pPtrArrayEnd)
844  *pPtrArrayCurrent++ = DoAllocateSubarray();
845  #if EASTL_EXCEPTIONS_ENABLED
846  }
847  catch(...)
848  {
849  DoFreeSubarrays(pPtrArrayBegin, pPtrArrayCurrent);
850  throw;
851  }
852  }
853  catch(...)
854  {
855  DoFreePtrArray(mpPtrArray, mnPtrArraySize);
856  mpPtrArray = NULL;
857  mnPtrArraySize = 0;
858  throw;
859  }
860  #endif
861 
862  mItBegin.SetSubarray(pPtrArrayBegin);
863  mItBegin.mpCurrent = mItBegin.mpBegin;
864 
865  mItEnd.SetSubarray(pPtrArrayEnd - 1);
866  mItEnd.mpCurrent = mItEnd.mpBegin + (difference_type)(n % kDequeSubarraySize);
867  //}
868  //else // Else we do a zero-allocation initialization.
869  //{
870  // mpPtrArray = NULL;
871  // mnPtrArraySize = 0;
872  //
873  // mItBegin.mpCurrentArrayPtr = NULL;
874  // mItBegin.mpBegin = NULL;
875  // mItBegin.mpEnd = NULL; // We intentionally create a situation whereby the subarray that has no capacity.
876  // mItBegin.mpCurrent = NULL;
877  //
878  // mItEnd = mItBegin;
879  //}
880  }
881 
882 
883 
885  // DequeIterator
887 
888  template <typename T, typename Pointer, typename Reference, unsigned kDequeSubarraySize>
889  DequeIterator<T, Pointer, Reference, kDequeSubarraySize>::DequeIterator()
890  : mpCurrent(NULL), mpBegin(NULL), mpEnd(NULL), mpCurrentArrayPtr(NULL)
891  {
892  // Empty
893  }
894 
895 
896  template <typename T, typename Pointer, typename Reference, unsigned kDequeSubarraySize>
897  DequeIterator<T, Pointer, Reference, kDequeSubarraySize>::DequeIterator(T** pCurrentArrayPtr, T* pCurrent)
898  : mpCurrent(pCurrent), mpBegin(*pCurrentArrayPtr), mpEnd(pCurrent + kDequeSubarraySize), mpCurrentArrayPtr(pCurrentArrayPtr)
899  {
900  // Empty
901  }
902 
903 
904  template <typename T, typename Pointer, typename Reference, unsigned kDequeSubarraySize>
905  DequeIterator<T, Pointer, Reference, kDequeSubarraySize>::DequeIterator(const iterator& x)
906  : mpCurrent(x.mpCurrent), mpBegin(x.mpBegin), mpEnd(x.mpEnd), mpCurrentArrayPtr(x.mpCurrentArrayPtr)
907  {
908  // Empty
909  }
910 
911 
912  template <typename T, typename Pointer, typename Reference, unsigned kDequeSubarraySize>
913  DequeIterator<T, Pointer, Reference, kDequeSubarraySize>::DequeIterator(const iterator& x, Increment)
914  : mpCurrent(x.mpCurrent), mpBegin(x.mpBegin), mpEnd(x.mpEnd), mpCurrentArrayPtr(x.mpCurrentArrayPtr)
915  {
916  operator++();
917  }
918 
919 
920  template <typename T, typename Pointer, typename Reference, unsigned kDequeSubarraySize>
921  DequeIterator<T, Pointer, Reference, kDequeSubarraySize>::DequeIterator(const iterator& x, Decrement)
922  : mpCurrent(x.mpCurrent), mpBegin(x.mpBegin), mpEnd(x.mpEnd), mpCurrentArrayPtr(x.mpCurrentArrayPtr)
923  {
924  operator--();
925  }
926 
927 
928  template <typename T, typename Pointer, typename Reference, unsigned kDequeSubarraySize>
929  typename DequeIterator<T, Pointer, Reference, kDequeSubarraySize>::pointer
930  DequeIterator<T, Pointer, Reference, kDequeSubarraySize>::operator->() const
931  {
932  return mpCurrent;
933  }
934 
935 
936  template <typename T, typename Pointer, typename Reference, unsigned kDequeSubarraySize>
937  typename DequeIterator<T, Pointer, Reference, kDequeSubarraySize>::reference
938  DequeIterator<T, Pointer, Reference, kDequeSubarraySize>::operator*() const
939  {
940  return *mpCurrent;
941  }
942 
943 
944  template <typename T, typename Pointer, typename Reference, unsigned kDequeSubarraySize>
945  typename DequeIterator<T, Pointer, Reference, kDequeSubarraySize>::this_type&
946  DequeIterator<T, Pointer, Reference, kDequeSubarraySize>::operator++()
947  {
948  if(EASTL_UNLIKELY(++mpCurrent == mpEnd))
949  {
950  mpBegin = *++mpCurrentArrayPtr;
951  mpEnd = mpBegin + kDequeSubarraySize;
952  mpCurrent = mpBegin;
953  }
954  return *this;
955  }
956 
957 
958  template <typename T, typename Pointer, typename Reference, unsigned kDequeSubarraySize>
959  typename DequeIterator<T, Pointer, Reference, kDequeSubarraySize>::this_type
960  DequeIterator<T, Pointer, Reference, kDequeSubarraySize>::operator++(int)
961  {
962  const this_type temp(*this);
963  operator++();
964  return temp;
965  }
966 
967 
968  template <typename T, typename Pointer, typename Reference, unsigned kDequeSubarraySize>
969  typename DequeIterator<T, Pointer, Reference, kDequeSubarraySize>::this_type&
970  DequeIterator<T, Pointer, Reference, kDequeSubarraySize>::operator--()
971  {
972  if(EASTL_UNLIKELY(mpCurrent == mpBegin))
973  {
974  mpBegin = *--mpCurrentArrayPtr;
975  mpEnd = mpBegin + kDequeSubarraySize;
976  mpCurrent = mpEnd; // fall through...
977  }
978  --mpCurrent;
979  return *this;
980  }
981 
982 
983  template <typename T, typename Pointer, typename Reference, unsigned kDequeSubarraySize>
984  typename DequeIterator<T, Pointer, Reference, kDequeSubarraySize>::this_type
985  DequeIterator<T, Pointer, Reference, kDequeSubarraySize>::operator--(int)
986  {
987  const this_type temp(*this);
988  operator--();
989  return temp;
990  }
991 
992 
993  template <typename T, typename Pointer, typename Reference, unsigned kDequeSubarraySize>
994  typename DequeIterator<T, Pointer, Reference, kDequeSubarraySize>::this_type&
995  DequeIterator<T, Pointer, Reference, kDequeSubarraySize>::operator+=(difference_type n)
996  {
997  const difference_type subarrayPosition = (mpCurrent - mpBegin) + n;
998 
999  // Cast from signed to unsigned (size_t) in order to obviate the need to compare to < 0.
1000  if((size_t)subarrayPosition < (size_t)kDequeSubarraySize) // If the new position is within the current subarray (i.e. >= 0 && < kSubArraySize)...
1001  mpCurrent += n;
1002  else
1003  {
1004  // This implementation is a branchless version which works by offsetting
1005  // the math to always be in the positive range. Much of the values here
1006  // reduce to constants and both the multiplication and division are of
1007  // power of two sizes and so this calculation ends up compiling down to
1008  // just one addition, one shift and one subtraction. This algorithm has
1009  // a theoretical weakness in that on 32 bit systems it will fail if the
1010  // value of n is >= (2^32 - 2^24) or 4,278,190,080 of if kDequeSubarraySize
1011  // is >= 2^24 or 16,777,216.
1012  EASTL_CT_ASSERT((kDequeSubarraySize & (kDequeSubarraySize - 1)) == 0); // Verify that it is a power of 2.
1013  const difference_type subarrayIndex = (((16777216 + subarrayPosition) / (difference_type)kDequeSubarraySize)) - (16777216 / (difference_type)kDequeSubarraySize);
1014 
1015  SetSubarray(mpCurrentArrayPtr + subarrayIndex);
1016  mpCurrent = mpBegin + (subarrayPosition - (subarrayIndex * (difference_type)kDequeSubarraySize));
1017  }
1018  return *this;
1019  }
1020 
1021 
1022  template <typename T, typename Pointer, typename Reference, unsigned kDequeSubarraySize>
1023  typename DequeIterator<T, Pointer, Reference, kDequeSubarraySize>::this_type&
1024  DequeIterator<T, Pointer, Reference, kDequeSubarraySize>::operator-=(difference_type n)
1025  {
1026  return (*this).operator+=(-n);
1027  }
1028 
1029 
1030  template <typename T, typename Pointer, typename Reference, unsigned kDequeSubarraySize>
1031  typename DequeIterator<T, Pointer, Reference, kDequeSubarraySize>::this_type
1032  DequeIterator<T, Pointer, Reference, kDequeSubarraySize>::operator+(difference_type n) const
1033  {
1034  return this_type(*this).operator+=(n);
1035  }
1036 
1037 
1038  template <typename T, typename Pointer, typename Reference, unsigned kDequeSubarraySize>
1039  typename DequeIterator<T, Pointer, Reference, kDequeSubarraySize>::this_type
1040  DequeIterator<T, Pointer, Reference, kDequeSubarraySize>::operator-(difference_type n) const
1041  {
1042  return this_type(*this).operator+=(-n);
1043  }
1044 
1045 
1046  template <typename T, typename Pointer, typename Reference, unsigned kDequeSubarraySize>
1047  typename DequeIterator<T, Pointer, Reference, kDequeSubarraySize>::this_type
1048  DequeIterator<T, Pointer, Reference, kDequeSubarraySize>::copy(const iterator& first, const iterator& last, true_type)
1049  {
1050  // To do: Implement this as a loop which does memcpys between subarrays appropriately.
1051  // Currently we only do memcpy if the entire operation occurs within a single subarray.
1052  if((first.mpBegin == last.mpBegin) && (first.mpBegin == mpBegin)) // If all operations are within the same subarray, implement the operation as a memmove.
1053  {
1054  memmove(mpCurrent, first.mpCurrent, (size_t)((uintptr_t)last.mpCurrent - (uintptr_t)first.mpCurrent));
1055  return *this + (last.mpCurrent - first.mpCurrent);
1056  }
1057  return eastl::copy(eastl::make_move_iterator(first), eastl::make_move_iterator(last), eastl::make_move_iterator(*this)).base();
1058  }
1059 
1060 
1061  template <typename T, typename Pointer, typename Reference, unsigned kDequeSubarraySize>
1062  typename DequeIterator<T, Pointer, Reference, kDequeSubarraySize>::this_type
1063  DequeIterator<T, Pointer, Reference, kDequeSubarraySize>::copy(const iterator& first, const iterator& last, false_type)
1064  {
1065  return eastl::copy(eastl::make_move_iterator(first), eastl::make_move_iterator(last), eastl::make_move_iterator(*this)).base();
1066  }
1067 
1068 
1069  template <typename T, typename Pointer, typename Reference, unsigned kDequeSubarraySize>
1070  void DequeIterator<T, Pointer, Reference, kDequeSubarraySize>::copy_backward(const iterator& first, const iterator& last, true_type)
1071  {
1072  // To do: Implement this as a loop which does memmoves between subarrays appropriately.
1073  // Currently we only do memcpy if the entire operation occurs within a single subarray.
1074  if((first.mpBegin == last.mpBegin) && (first.mpBegin == mpBegin)) // If all operations are within the same subarray, implement the operation as a memcpy.
1075  memmove(mpCurrent - (last.mpCurrent - first.mpCurrent), first.mpCurrent, (size_t)((uintptr_t)last.mpCurrent - (uintptr_t)first.mpCurrent));
1076  else
1077  eastl::copy_backward(eastl::make_move_iterator(first), eastl::make_move_iterator(last), eastl::make_move_iterator(*this));
1078  }
1079 
1080 
1081  template <typename T, typename Pointer, typename Reference, unsigned kDequeSubarraySize>
1082  void DequeIterator<T, Pointer, Reference, kDequeSubarraySize>::copy_backward(const iterator& first, const iterator& last, false_type)
1083  {
1084  eastl::copy_backward(eastl::make_move_iterator(first), eastl::make_move_iterator(last), eastl::make_move_iterator(*this)).base();
1085  }
1086 
1087 
1088  template <typename T, typename Pointer, typename Reference, unsigned kDequeSubarraySize>
1089  void DequeIterator<T, Pointer, Reference, kDequeSubarraySize>::SetSubarray(T** pCurrentArrayPtr)
1090  {
1091  mpCurrentArrayPtr = pCurrentArrayPtr;
1092  mpBegin = *pCurrentArrayPtr;
1093  mpEnd = mpBegin + kDequeSubarraySize;
1094  }
1095 
1096 
1097  // The C++ defect report #179 requires that we support comparisons between const and non-const iterators.
1098  // Thus we provide additional template paremeters here to support this. The defect report does not
1099  // require us to support comparisons between reverse_iterators and const_reverse_iterators.
1100  template <typename T, typename PointerA, typename ReferenceA, typename PointerB, typename ReferenceB, unsigned kDequeSubarraySize>
1101  inline bool operator==(const DequeIterator<T, PointerA, ReferenceA, kDequeSubarraySize>& a,
1102  const DequeIterator<T, PointerB, ReferenceB, kDequeSubarraySize>& b)
1103  {
1104  return a.mpCurrent == b.mpCurrent;
1105  }
1106 
1107 
1108  template <typename T, typename PointerA, typename ReferenceA, typename PointerB, typename ReferenceB, unsigned kDequeSubarraySize>
1109  inline bool operator!=(const DequeIterator<T, PointerA, ReferenceA, kDequeSubarraySize>& a,
1110  const DequeIterator<T, PointerB, ReferenceB, kDequeSubarraySize>& b)
1111  {
1112  return a.mpCurrent != b.mpCurrent;
1113  }
1114 
1115 
1116  // We provide a version of operator!= for the case where the iterators are of the
1117  // same type. This helps prevent ambiguity errors in the presence of rel_ops.
1118  template <typename T, typename Pointer, typename Reference, unsigned kDequeSubarraySize>
1119  inline bool operator!=(const DequeIterator<T, Pointer, Reference, kDequeSubarraySize>& a,
1120  const DequeIterator<T, Pointer, Reference, kDequeSubarraySize>& b)
1121  {
1122  return a.mpCurrent != b.mpCurrent;
1123  }
1124 
1125 
1126  template <typename T, typename PointerA, typename ReferenceA, typename PointerB, typename ReferenceB, unsigned kDequeSubarraySize>
1127  inline bool operator<(const DequeIterator<T, PointerA, ReferenceA, kDequeSubarraySize>& a,
1128  const DequeIterator<T, PointerB, ReferenceB, kDequeSubarraySize>& b)
1129  {
1130  return (a.mpCurrentArrayPtr == b.mpCurrentArrayPtr) ? (a.mpCurrent < b.mpCurrent) : (a.mpCurrentArrayPtr < b.mpCurrentArrayPtr);
1131  }
1132 
1133 
1134  template <typename T, typename PointerA, typename ReferenceA, typename PointerB, typename ReferenceB, unsigned kDequeSubarraySize>
1135  inline bool operator>(const DequeIterator<T, PointerA, ReferenceA, kDequeSubarraySize>& a,
1136  const DequeIterator<T, PointerB, ReferenceB, kDequeSubarraySize>& b)
1137  {
1138  return (a.mpCurrentArrayPtr == b.mpCurrentArrayPtr) ? (a.mpCurrent > b.mpCurrent) : (a.mpCurrentArrayPtr > b.mpCurrentArrayPtr);
1139  }
1140 
1141 
1142  template <typename T, typename PointerA, typename ReferenceA, typename PointerB, typename ReferenceB, unsigned kDequeSubarraySize>
1143  inline bool operator<=(const DequeIterator<T, PointerA, ReferenceA, kDequeSubarraySize>& a,
1144  const DequeIterator<T, PointerB, ReferenceB, kDequeSubarraySize>& b)
1145  {
1146  return (a.mpCurrentArrayPtr == b.mpCurrentArrayPtr) ? (a.mpCurrent <= b.mpCurrent) : (a.mpCurrentArrayPtr <= b.mpCurrentArrayPtr);
1147  }
1148 
1149 
1150  template <typename T, typename PointerA, typename ReferenceA, typename PointerB, typename ReferenceB, unsigned kDequeSubarraySize>
1151  inline bool operator>=(const DequeIterator<T, PointerA, ReferenceA, kDequeSubarraySize>& a,
1152  const DequeIterator<T, PointerB, ReferenceB, kDequeSubarraySize>& b)
1153  {
1154  return (a.mpCurrentArrayPtr == b.mpCurrentArrayPtr) ? (a.mpCurrent >= b.mpCurrent) : (a.mpCurrentArrayPtr >= b.mpCurrentArrayPtr);
1155  }
1156 
1157 
1158  // Random access iterators must support operator + and operator -.
1159  // You can only add an integer to an iterator, and you cannot add two iterators.
1160  template <typename T, typename Pointer, typename Reference, unsigned kDequeSubarraySize>
1161  inline DequeIterator<T, Pointer, Reference, kDequeSubarraySize>
1162  operator+(ptrdiff_t n, const DequeIterator<T, Pointer, Reference, kDequeSubarraySize>& x)
1163  {
1164  return x + n; // Implement (n + x) in terms of (x + n).
1165  }
1166 
1167 
1168  // You can only add an integer to an iterator, but you can subtract two iterators.
1169  // The C++ defect report #179 mentioned above specifically refers to
1170  // operator - and states that we support the subtraction of const and non-const iterators.
1171  template <typename T, typename PointerA, typename ReferenceA, typename PointerB, typename ReferenceB, unsigned kDequeSubarraySize>
1172  inline typename DequeIterator<T, PointerA, ReferenceA, kDequeSubarraySize>::difference_type
1173  operator-(const DequeIterator<T, PointerA, ReferenceA, kDequeSubarraySize>& a,
1174  const DequeIterator<T, PointerB, ReferenceB, kDequeSubarraySize>& b)
1175  {
1176  // This is a fairly clever algorithm that has been used in STL deque implementations since the original HP STL:
1177  typedef typename DequeIterator<T, PointerA, ReferenceA, kDequeSubarraySize>::difference_type difference_type;
1178 
1179  return ((difference_type)kDequeSubarraySize * ((a.mpCurrentArrayPtr - b.mpCurrentArrayPtr) - 1)) + (a.mpCurrent - a.mpBegin) + (b.mpEnd - b.mpCurrent);
1180  }
1181 
1182 
1183 
1184 
1186  // deque
1188 
1189  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
1190  inline deque<T, Allocator, kDequeSubarraySize>::deque()
1191  : base_type((size_type)0)
1192  {
1193  // Empty
1194  }
1195 
1196 
1197  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
1198  inline deque<T, Allocator, kDequeSubarraySize>::deque(const allocator_type& allocator)
1199  : base_type((size_type)0, allocator)
1200  {
1201  // Empty
1202  }
1203 
1204 
1205  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
1206  inline deque<T, Allocator, kDequeSubarraySize>::deque(size_type n, const allocator_type& allocator)
1207  : base_type(n, allocator)
1208  {
1209  DoFillInit(value_type());
1210  }
1211 
1212 
1213  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
1214  inline deque<T, Allocator, kDequeSubarraySize>::deque(size_type n, const value_type& value, const allocator_type& allocator)
1215  : base_type(n, allocator)
1216  {
1217  DoFillInit(value);
1218  }
1219 
1220 
1221  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
1222  inline deque<T, Allocator, kDequeSubarraySize>::deque(const this_type& x)
1223  : base_type(x.size(), x.mAllocator)
1224  {
1225  eastl::uninitialized_copy(x.mItBegin, x.mItEnd, mItBegin);
1226  }
1227 
1228 
1229  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
1230  inline deque<T, Allocator, kDequeSubarraySize>::deque(this_type&& x)
1231  : base_type((size_type)0, x.mAllocator)
1232  {
1233  swap(x);
1234  }
1235 
1236 
1237  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
1238  inline deque<T, Allocator, kDequeSubarraySize>::deque(this_type&& x, const allocator_type& allocator)
1239  : base_type((size_type)0, allocator)
1240  {
1241  swap(x); // member swap handles the case that x has a different allocator than our allocator by doing a copy.
1242  }
1243 
1244 
1245  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
1246  inline deque<T, Allocator, kDequeSubarraySize>::deque(std::initializer_list<value_type> ilist, const allocator_type& allocator)
1247  : base_type(allocator)
1248  {
1249  DoInit(ilist.begin(), ilist.end(), false_type());
1250  }
1251 
1252 
1253  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
1254  template <typename InputIterator>
1255  inline deque<T, Allocator, kDequeSubarraySize>::deque(InputIterator first, InputIterator last)
1256  : base_type(EASTL_DEQUE_DEFAULT_ALLOCATOR) // Call the empty base constructor, which does nothing. We need to do all the work in our own DoInit.
1257  {
1258  DoInit(first, last, is_integral<InputIterator>());
1259  }
1260 
1261 
1262  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
1263  inline deque<T, Allocator, kDequeSubarraySize>::~deque()
1264  {
1265  // Call destructors. Parent class will free the memory.
1266  for(iterator itCurrent(mItBegin); itCurrent != mItEnd; ++itCurrent)
1267  itCurrent.mpCurrent->~value_type();
1268  }
1269 
1270 
1271  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
1272  typename deque<T, Allocator, kDequeSubarraySize>::this_type&
1273  deque<T, Allocator, kDequeSubarraySize>::operator=(const this_type& x)
1274  {
1275  if(&x != this) // If not assigning to ourselves...
1276  {
1277  // If (EASTL_ALLOCATOR_COPY_ENABLED == 1) and the current contents are allocated by an
1278  // allocator that's unequal to x's allocator, we need to reallocate our elements with
1279  // our current allocator and reallocate it with x's allocator. If the allocators are
1280  // equal then we can use a more optimal algorithm that doesn't reallocate our elements
1281  // but instead can copy them in place.
1282 
1283  #if EASTL_ALLOCATOR_COPY_ENABLED
1284  bool bSlowerPathwayRequired = (mAllocator != x.mAllocator);
1285  #else
1286  bool bSlowerPathwayRequired = false;
1287  #endif
1288 
1289  if(bSlowerPathwayRequired)
1290  {
1291  // We can't currently use set_capacity(0) or shrink_to_fit, because they
1292  // leave a remaining allocation with our old allocator. So we do a similar
1293  // thing but set our allocator to x.mAllocator while doing so.
1294  this_type temp(x.mAllocator);
1295  DoSwap(temp);
1296  // Now we have an empty container with an allocator equal to x.mAllocator, ready to assign from x.
1297  }
1298 
1299  DoAssign(x.begin(), x.end(), eastl::false_type());
1300  }
1301 
1302  return *this;
1303  }
1304 
1305 
1306  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
1307  inline typename deque<T, Allocator, kDequeSubarraySize>::this_type&
1308  deque<T, Allocator, kDequeSubarraySize>::operator=(this_type&& x)
1309  {
1310  if(this != &x)
1311  {
1312  set_capacity(0); // To consider: Are we really required to clear here? x is going away soon and will clear itself in its dtor.
1313  swap(x); // member swap handles the case that x has a different allocator than our allocator by doing a copy.
1314  }
1315  return *this;
1316  }
1317 
1318 
1319  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
1320  inline typename deque<T, Allocator, kDequeSubarraySize>::this_type&
1321  deque<T, Allocator, kDequeSubarraySize>::operator=(std::initializer_list<value_type> ilist)
1322  {
1323  DoAssign(ilist.begin(), ilist.end(), false_type());
1324  return *this;
1325  }
1326 
1327 
1328  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
1329  inline void deque<T, Allocator, kDequeSubarraySize>::assign(size_type n, const value_type& value)
1330  {
1331  DoAssignValues(n, value);
1332  }
1333 
1334 
1335  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
1336  inline void deque<T, Allocator, kDequeSubarraySize>::assign(std::initializer_list<value_type> ilist)
1337  {
1338  DoAssign(ilist.begin(), ilist.end(), false_type());
1339  }
1340 
1341 
1342  // It turns out that the C++ std::deque specifies a two argument
1343  // version of assign that takes (int size, int value). These are not
1344  // iterators, so we need to do a template compiler trick to do the right thing.
1345  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
1346  template <typename InputIterator>
1347  inline void deque<T, Allocator, kDequeSubarraySize>::assign(InputIterator first, InputIterator last)
1348  {
1349  DoAssign(first, last, is_integral<InputIterator>());
1350  }
1351 
1352 
1353  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
1354  inline typename deque<T, Allocator, kDequeSubarraySize>::iterator
1355  deque<T, Allocator, kDequeSubarraySize>::begin() EA_NOEXCEPT
1356  {
1357  return mItBegin;
1358  }
1359 
1360 
1361  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
1362  inline typename deque<T, Allocator, kDequeSubarraySize>::const_iterator
1363  deque<T, Allocator, kDequeSubarraySize>::begin() const EA_NOEXCEPT
1364  {
1365  return mItBegin;
1366  }
1367 
1368 
1369  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
1370  inline typename deque<T, Allocator, kDequeSubarraySize>::const_iterator
1371  deque<T, Allocator, kDequeSubarraySize>::cbegin() const EA_NOEXCEPT
1372  {
1373  return mItBegin;
1374  }
1375 
1376 
1377  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
1378  inline typename deque<T, Allocator, kDequeSubarraySize>::iterator
1379  deque<T, Allocator, kDequeSubarraySize>::end() EA_NOEXCEPT
1380  {
1381  return mItEnd;
1382  }
1383 
1384 
1385  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
1386  typename deque<T, Allocator, kDequeSubarraySize>::const_iterator
1387  deque<T, Allocator, kDequeSubarraySize>::end() const EA_NOEXCEPT
1388  {
1389  return mItEnd;
1390  }
1391 
1392 
1393  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
1394  inline typename deque<T, Allocator, kDequeSubarraySize>::const_iterator
1395  deque<T, Allocator, kDequeSubarraySize>::cend() const EA_NOEXCEPT
1396  {
1397  return mItEnd;
1398  }
1399 
1400 
1401  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
1402  inline typename deque<T, Allocator, kDequeSubarraySize>::reverse_iterator
1403  deque<T, Allocator, kDequeSubarraySize>::rbegin() EA_NOEXCEPT
1404  {
1405  return reverse_iterator(mItEnd);
1406  }
1407 
1408 
1409  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
1410  inline typename deque<T, Allocator, kDequeSubarraySize>::const_reverse_iterator
1411  deque<T, Allocator, kDequeSubarraySize>::rbegin() const EA_NOEXCEPT
1412  {
1413  return const_reverse_iterator(mItEnd);
1414  }
1415 
1416 
1417  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
1418  inline typename deque<T, Allocator, kDequeSubarraySize>::const_reverse_iterator
1419  deque<T, Allocator, kDequeSubarraySize>::crbegin() const EA_NOEXCEPT
1420  {
1421  return const_reverse_iterator(mItEnd);
1422  }
1423 
1424 
1425  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
1426  inline typename deque<T, Allocator, kDequeSubarraySize>::reverse_iterator
1427  deque<T, Allocator, kDequeSubarraySize>::rend() EA_NOEXCEPT
1428  {
1429  return reverse_iterator(mItBegin);
1430  }
1431 
1432 
1433  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
1434  inline typename deque<T, Allocator, kDequeSubarraySize>::const_reverse_iterator
1435  deque<T, Allocator, kDequeSubarraySize>::rend() const EA_NOEXCEPT
1436  {
1437  return const_reverse_iterator(mItBegin);
1438  }
1439 
1440 
1441  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
1442  inline typename deque<T, Allocator, kDequeSubarraySize>::const_reverse_iterator
1443  deque<T, Allocator, kDequeSubarraySize>::crend() const EA_NOEXCEPT
1444  {
1445  return const_reverse_iterator(mItBegin);
1446  }
1447 
1448 
1449  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
1450  inline bool deque<T, Allocator, kDequeSubarraySize>::empty() const EA_NOEXCEPT
1451  {
1452  return mItBegin.mpCurrent == mItEnd.mpCurrent;
1453  }
1454 
1455 
1456  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
1457  typename deque<T, Allocator, kDequeSubarraySize>::size_type
1458  inline deque<T, Allocator, kDequeSubarraySize>::size() const EA_NOEXCEPT
1459  {
1460  return (size_type)(mItEnd - mItBegin);
1461  }
1462 
1463 
1464  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
1465  inline void deque<T, Allocator, kDequeSubarraySize>::resize(size_type n, const value_type& value)
1466  {
1467  const size_type nSizeCurrent = size();
1468 
1469  if(n > nSizeCurrent) // We expect that more often than not, resizes will be upsizes.
1470  insert(mItEnd, n - nSizeCurrent, value);
1471  else
1472  erase(mItBegin + (difference_type)n, mItEnd);
1473  }
1474 
1475 
1476  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
1477  inline void deque<T, Allocator, kDequeSubarraySize>::resize(size_type n)
1478  {
1479  resize(n, value_type());
1480  }
1481 
1482 
1483  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
1484  inline void deque<T, Allocator, kDequeSubarraySize>::shrink_to_fit()
1485  {
1486  this_type x(eastl::make_move_iterator(begin()), eastl::make_move_iterator(end()));
1487  swap(x);
1488  }
1489 
1490 
1491  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
1492  inline void deque<T, Allocator, kDequeSubarraySize>::set_capacity(size_type n)
1493  {
1494  // Currently there isn't a way to remove all allocations from a deque, as it
1495  // requires a single starting allocation for the subarrays. So we can't just
1496  // free all memory without leaving it in a bad state. So the best means of
1497  // implementing set_capacity() is to do what we do below.
1498 
1499  if(n == 0)
1500  {
1501  this_type temp(mAllocator);
1502  DoSwap(temp);
1503  }
1504  else if(n < size())
1505  {
1506  // We currently ignore the request to reduce capacity. To do: Implement this
1507  // and do it in a way that doesn't result in temporarily ~doubling our memory usage.
1508  // That might involve trimming unused subarrays from the front or back of
1509  // the container.
1510  resize(n);
1511  }
1512  }
1513 
1514 
1515  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
1516  typename deque<T, Allocator, kDequeSubarraySize>::reference
1517  deque<T, Allocator, kDequeSubarraySize>::operator[](size_type n)
1518  {
1519  #if EASTL_ASSERT_ENABLED && EASTL_EMPTY_REFERENCE_ASSERT_ENABLED
1520  if (EASTL_UNLIKELY(n >= (size_type)(mItEnd - mItBegin)))
1521  EASTL_FAIL_MSG("deque::operator[] -- out of range");
1522  #elif EASTL_ASSERT_ENABLED
1523  // We allow taking a reference to deque[0]
1524  if (EASTL_UNLIKELY((n != 0) && n >= (size_type)(mItEnd - mItBegin)))
1525  EASTL_FAIL_MSG("deque::operator[] -- out of range");
1526  #endif
1527 
1528  // See DequeIterator::operator+=() for an explanation of the code below.
1529  iterator it(mItBegin);
1530 
1531  const difference_type subarrayPosition = (difference_type)((it.mpCurrent - it.mpBegin) + (difference_type)n);
1532  const difference_type subarrayIndex = (((16777216 + subarrayPosition) / (difference_type)kDequeSubarraySize)) - (16777216 / (difference_type)kDequeSubarraySize);
1533 
1534  return *(*(it.mpCurrentArrayPtr + subarrayIndex) + (subarrayPosition - (subarrayIndex * (difference_type)kDequeSubarraySize)));
1535  }
1536 
1537 
1538  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
1539  typename deque<T, Allocator, kDequeSubarraySize>::const_reference
1540  deque<T, Allocator, kDequeSubarraySize>::operator[](size_type n) const
1541  {
1542  #if EASTL_ASSERT_ENABLED && EASTL_EMPTY_REFERENCE_ASSERT_ENABLED
1543  if (EASTL_UNLIKELY(n >= (size_type)(mItEnd - mItBegin)))
1544  EASTL_FAIL_MSG("deque::operator[] -- out of range");
1545  #elif EASTL_ASSERT_ENABLED
1546  // We allow the user to use a reference to deque[0] of an empty container.
1547  if (EASTL_UNLIKELY((n != 0) && n >= (size_type)(mItEnd - mItBegin)))
1548  EASTL_FAIL_MSG("deque::operator[] -- out of range");
1549  #endif
1550 
1551  // See DequeIterator::operator+=() for an explanation of the code below.
1552  iterator it(mItBegin);
1553 
1554  const difference_type subarrayPosition = (it.mpCurrent - it.mpBegin) + (difference_type)n;
1555  const difference_type subarrayIndex = (((16777216 + subarrayPosition) / (difference_type)kDequeSubarraySize)) - (16777216 / (difference_type)kDequeSubarraySize);
1556 
1557  return *(*(it.mpCurrentArrayPtr + subarrayIndex) + (subarrayPosition - (subarrayIndex * (difference_type)kDequeSubarraySize)));
1558  }
1559 
1560 
1561  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
1562  typename deque<T, Allocator, kDequeSubarraySize>::reference
1563  deque<T, Allocator, kDequeSubarraySize>::at(size_type n)
1564  {
1565  #if EASTL_EXCEPTIONS_ENABLED
1566  if(n >= (size_type)(mItEnd - mItBegin))
1567  throw std::out_of_range("deque::at -- out of range");
1568  #elif EASTL_ASSERT_ENABLED
1569  if(n >= (size_type)(mItEnd - mItBegin))
1570  EASTL_FAIL_MSG("deque::at -- out of range");
1571  #endif
1572  return *(mItBegin.operator+((difference_type)n));
1573  }
1574 
1575 
1576  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
1577  typename deque<T, Allocator, kDequeSubarraySize>::const_reference
1578  deque<T, Allocator, kDequeSubarraySize>::at(size_type n) const
1579  {
1580  #if EASTL_EXCEPTIONS_ENABLED
1581  if(n >= (size_type)(mItEnd - mItBegin))
1582  throw std::out_of_range("deque::at -- out of range");
1583  #elif EASTL_ASSERT_ENABLED
1584  if(n >= (size_type)(mItEnd - mItBegin))
1585  EASTL_FAIL_MSG("deque::at -- out of range");
1586  #endif
1587  return *(mItBegin.operator+((difference_type)n));
1588  }
1589 
1590 
1591  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
1592  typename deque<T, Allocator, kDequeSubarraySize>::reference
1593  deque<T, Allocator, kDequeSubarraySize>::front()
1594  {
1595  #if EASTL_ASSERT_ENABLED && EASTL_EMPTY_REFERENCE_ASSERT_ENABLED
1596  if (EASTL_UNLIKELY((size_type)(mItEnd == mItBegin)))
1597  EASTL_FAIL_MSG("deque::front -- empty deque");
1598  #else
1599  // We allow the user to reference an empty container.
1600  #endif
1601 
1602  return *mItBegin;
1603  }
1604 
1605 
1606  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
1607  typename deque<T, Allocator, kDequeSubarraySize>::const_reference
1608  deque<T, Allocator, kDequeSubarraySize>::front() const
1609  {
1610  #if EASTL_ASSERT_ENABLED && EASTL_EMPTY_REFERENCE_ASSERT_ENABLED
1611  if (EASTL_UNLIKELY((size_type)(mItEnd == mItBegin)))
1612  EASTL_FAIL_MSG("deque::front -- empty deque");
1613  #else
1614  // We allow the user to reference an empty container.
1615  #endif
1616 
1617  return *mItBegin;
1618  }
1619 
1620 
1621  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
1622  typename deque<T, Allocator, kDequeSubarraySize>::reference
1623  deque<T, Allocator, kDequeSubarraySize>::back()
1624  {
1625  #if EASTL_ASSERT_ENABLED && EASTL_EMPTY_REFERENCE_ASSERT_ENABLED
1626  if (EASTL_UNLIKELY((size_type)(mItEnd == mItBegin)))
1627  EASTL_FAIL_MSG("deque::back -- empty deque");
1628  #else
1629  // We allow the user to reference an empty container.
1630  #endif
1631 
1632  return *iterator(mItEnd, typename iterator::Decrement());
1633  }
1634 
1635 
1636  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
1637  typename deque<T, Allocator, kDequeSubarraySize>::const_reference
1638  deque<T, Allocator, kDequeSubarraySize>::back() const
1639  {
1640  #if EASTL_ASSERT_ENABLED && EASTL_EMPTY_REFERENCE_ASSERT_ENABLED
1641  if (EASTL_UNLIKELY((size_type)(mItEnd == mItBegin)))
1642  EASTL_FAIL_MSG("deque::back -- empty deque");
1643  #else
1644  // We allow the user to reference an empty container.
1645  #endif
1646 
1647  return *iterator(mItEnd, typename iterator::Decrement());
1648  }
1649 
1650 
1651  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
1652  void deque<T, Allocator, kDequeSubarraySize>::push_front(const value_type& value)
1653  {
1654  emplace_front(value);
1655  }
1656 
1657 
1658  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
1659  void deque<T, Allocator, kDequeSubarraySize>::push_front(value_type&& value)
1660  {
1661  emplace_front(eastl::move(value));
1662  }
1663 
1664 
1665  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
1666  typename deque<T, Allocator, kDequeSubarraySize>::reference
1667  deque<T, Allocator, kDequeSubarraySize>::push_front()
1668  {
1669  emplace_front(value_type());
1670  return *mItBegin; // Same as return front();
1671  }
1672 
1673 
1674  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
1675  void deque<T, Allocator, kDequeSubarraySize>::push_back(const value_type& value)
1676  {
1677  emplace_back(value);
1678  }
1679 
1680 
1681  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
1682  void deque<T, Allocator, kDequeSubarraySize>::push_back(value_type&& value)
1683  {
1684  emplace_back(eastl::move(value));
1685  }
1686 
1687 
1688  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
1689  typename deque<T, Allocator, kDequeSubarraySize>::reference
1690  deque<T, Allocator, kDequeSubarraySize>::push_back()
1691  {
1692  emplace_back(value_type());
1693  return *iterator(mItEnd, typename iterator::Decrement()); // Same thing as return back();
1694  }
1695 
1696 
1697  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
1698  void deque<T, Allocator, kDequeSubarraySize>::pop_front()
1699  {
1700  #if EASTL_ASSERT_ENABLED
1701  if(EASTL_UNLIKELY((size_type)(mItEnd == mItBegin)))
1702  EASTL_FAIL_MSG("deque::pop_front -- empty deque");
1703  #endif
1704 
1705  if((mItBegin.mpCurrent + 1) != mItBegin.mpEnd) // If the operation is very simple...
1706  (mItBegin.mpCurrent++)->~value_type();
1707  else
1708  {
1709  // This is executed only when we are popping the end (last) item off the front-most subarray.
1710  // In this case we need to free the subarray and point mItBegin to the next subarray.
1711  #ifdef EA_DEBUG
1712  value_type** pp = mItBegin.mpCurrentArrayPtr;
1713  #endif
1714 
1715  mItBegin.mpCurrent->~value_type(); // mpCurrent == mpEnd - 1
1716  DoFreeSubarray(mItBegin.mpBegin);
1717  mItBegin.SetSubarray(mItBegin.mpCurrentArrayPtr + 1);
1718  mItBegin.mpCurrent = mItBegin.mpBegin;
1719 
1720  #ifdef EA_DEBUG
1721  *pp = NULL;
1722  #endif
1723  }
1724  }
1725 
1726 
1727  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
1728  void deque<T, Allocator, kDequeSubarraySize>::pop_back()
1729  {
1730  #if EASTL_ASSERT_ENABLED
1731  if(EASTL_UNLIKELY((size_type)(mItEnd == mItBegin)))
1732  EASTL_FAIL_MSG("deque::pop_back -- empty deque");
1733  #endif
1734 
1735  if(mItEnd.mpCurrent != mItEnd.mpBegin) // If the operation is very simple...
1736  (--mItEnd.mpCurrent)->~value_type();
1737  else
1738  {
1739  // This is executed only when we are popping the first item off the last subarray.
1740  // In this case we need to free the subarray and point mItEnd to the previous subarray.
1741  #ifdef EA_DEBUG
1742  value_type** pp = mItEnd.mpCurrentArrayPtr;
1743  #endif
1744 
1745  DoFreeSubarray(mItEnd.mpBegin);
1746  mItEnd.SetSubarray(mItEnd.mpCurrentArrayPtr - 1);
1747  mItEnd.mpCurrent = mItEnd.mpEnd - 1; // Recall that mItEnd points to one-past the last item in the container.
1748  mItEnd.mpCurrent->~value_type(); // Thus we need to call the destructor on the item *before* that last item.
1749 
1750  #ifdef EA_DEBUG
1751  *pp = NULL;
1752  #endif
1753  }
1754  }
1755 
1756 
1757  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
1758  template<class... Args>
1759  typename deque<T, Allocator, kDequeSubarraySize>::iterator
1760  deque<T, Allocator, kDequeSubarraySize>::emplace(const_iterator position, Args&&... args)
1761  {
1762  if(EASTL_UNLIKELY(position.mpCurrent == mItEnd.mpCurrent)) // If we are doing the same thing as push_back...
1763  {
1764  emplace_back(eastl::forward<Args>(args)...);
1765  return iterator(mItEnd, typename iterator::Decrement()); // Unfortunately, we need to make an iterator here, as the above push_back is an operation that can invalidate existing iterators.
1766  }
1767  else if(EASTL_UNLIKELY(position.mpCurrent == mItBegin.mpCurrent)) // If we are doing the same thing as push_front...
1768  {
1769  emplace_front(eastl::forward<Args>(args)...);
1770  return mItBegin;
1771  }
1772 
1773  iterator itPosition(position, typename iterator::FromConst());
1774  value_type valueSaved(eastl::forward<Args>(args)...); // We need to save this because value may come from within our container. It would be somewhat tedious to make a workaround that could avoid this.
1775  const difference_type i(itPosition - mItBegin);
1776 
1777  #if EASTL_ASSERT_ENABLED
1778  EASTL_ASSERT(!empty()); // The push_front and push_back calls below assume that we are non-empty. It turns out this is never called unless so.
1779 
1780  if(EASTL_UNLIKELY(!(validate_iterator(itPosition) & isf_valid)))
1781  EASTL_FAIL_MSG("deque::emplace -- invalid iterator");
1782  #endif
1783 
1784  if(i < (difference_type)(size() / 2)) // Should we insert at the front or at the back? We divide the range in half.
1785  {
1786  emplace_front(eastl::move(*mItBegin)); // This operation potentially invalidates all existing iterators and so we need to assign them anew relative to mItBegin below.
1787 
1788  itPosition = mItBegin + i;
1789 
1790  const iterator newPosition (itPosition, typename iterator::Increment());
1791  iterator oldBegin (mItBegin, typename iterator::Increment());
1792  const iterator oldBeginPlus1(oldBegin, typename iterator::Increment());
1793 
1794  oldBegin.copy(oldBeginPlus1, newPosition, eastl::has_trivial_relocate<value_type>());
1795  }
1796  else
1797  {
1798  emplace_back(eastl::move(*iterator(mItEnd, typename iterator::Decrement())));
1799 
1800  itPosition = mItBegin + i;
1801 
1802  iterator oldBack (mItEnd, typename iterator::Decrement());
1803  const iterator oldBackMinus1(oldBack, typename iterator::Decrement());
1804 
1805  oldBack.copy_backward(itPosition, oldBackMinus1, eastl::has_trivial_relocate<value_type>());
1806  }
1807 
1808  *itPosition = eastl::move(valueSaved);
1809 
1810  return itPosition;
1811  }
1812 
1813  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
1814  template<class... Args>
1815  void deque<T, Allocator, kDequeSubarraySize>::emplace_front(Args&&... args)
1816  {
1817  if(mItBegin.mpCurrent != mItBegin.mpBegin) // If we have room in the first subarray... we hope that usually this 'new' pathway gets executed, as it is slightly faster.
1818  ::new((void*)--mItBegin.mpCurrent) value_type(eastl::forward<Args>(args)...); // Construct in place. If args is a single arg of type value_type&& then it this will be a move construction.
1819  else
1820  {
1821  // To consider: Detect if value isn't coming from within this container and handle that efficiently.
1822  value_type valueSaved(eastl::forward<Args>(args)...); // We need to make a temporary, because args may be a value_type that comes from within our container and the operations below may change the container. But we can use move instead of copy.
1823 
1824  if(mItBegin.mpCurrentArrayPtr == mpPtrArray) // If there are no more pointers in front of the current (first) one...
1825  DoReallocPtrArray(1, kSideFront);
1826 
1827  mItBegin.mpCurrentArrayPtr[-1] = DoAllocateSubarray();
1828 
1829  #if EASTL_EXCEPTIONS_ENABLED
1830  try
1831  {
1832  #endif
1833  mItBegin.SetSubarray(mItBegin.mpCurrentArrayPtr - 1);
1834  mItBegin.mpCurrent = mItBegin.mpEnd - 1;
1835  ::new((void*)mItBegin.mpCurrent) value_type(eastl::move(valueSaved));
1836  #if EASTL_EXCEPTIONS_ENABLED
1837  }
1838  catch(...)
1839  {
1840  ++mItBegin; // The exception could only occur in the new operation above, after we have incremented mItBegin. So we need to undo it.
1841  DoFreeSubarray(mItBegin.mpCurrentArrayPtr[-1]);
1842  throw;
1843  }
1844  #endif
1845  }
1846  }
1847 
1848  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
1849  template<class... Args>
1850  void deque<T, Allocator, kDequeSubarraySize>::emplace_back(Args&&... args)
1851  {
1852  if((mItEnd.mpCurrent + 1) != mItEnd.mpEnd) // If we have room in the last subarray... we hope that usually this 'new' pathway gets executed, as it is slightly faster.
1853  ::new((void*)mItEnd.mpCurrent++) value_type(eastl::forward<Args>(args)...); // Construct in place. If args is a single arg of type value_type&& then it this will be a move construction.
1854  else
1855  {
1856  // To consider: Detect if value isn't coming from within this container and handle that efficiently.
1857  value_type valueSaved(eastl::forward<Args>(args)...); // We need to make a temporary, because args may be a value_type that comes from within our container and the operations below may change the container. But we can use move instead of copy.
1858  if(((mItEnd.mpCurrentArrayPtr - mpPtrArray) + 1) >= (difference_type)mnPtrArraySize) // If there are no more pointers after the current (last) one.
1859  DoReallocPtrArray(1, kSideBack);
1860 
1861  mItEnd.mpCurrentArrayPtr[1] = DoAllocateSubarray();
1862 
1863  #if EASTL_EXCEPTIONS_ENABLED
1864  try
1865  {
1866  #endif
1867  ::new((void*)mItEnd.mpCurrent) value_type(eastl::move(valueSaved)); // We can move valueSaved into position.
1868  mItEnd.SetSubarray(mItEnd.mpCurrentArrayPtr + 1);
1869  mItEnd.mpCurrent = mItEnd.mpBegin;
1870  #if EASTL_EXCEPTIONS_ENABLED
1871  }
1872  catch(...)
1873  {
1874  // No need to execute '--mItEnd', as the exception could only occur in the new operation above before we set mItEnd.
1875  DoFreeSubarray(mItEnd.mpCurrentArrayPtr[1]);
1876  throw;
1877  }
1878  #endif
1879  }
1880  }
1881 
1882 
1883  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
1884  typename deque<T, Allocator, kDequeSubarraySize>::iterator
1885  deque<T, Allocator, kDequeSubarraySize>::insert(const_iterator position, const value_type& value)
1886  {
1887  return emplace(position, value);
1888  }
1889 
1890 
1891  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
1892  typename deque<T, Allocator, kDequeSubarraySize>::iterator
1893  deque<T, Allocator, kDequeSubarraySize>::insert(const_iterator position, value_type&& value)
1894  {
1895  return emplace(position, eastl::move(value));
1896  }
1897 
1898 
1899  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
1900  void deque<T, Allocator, kDequeSubarraySize>::insert(const_iterator position, size_type n, const value_type& value)
1901  {
1902  DoInsertValues(position, n, value);
1903  }
1904 
1905 
1906  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
1907  template <typename InputIterator>
1908  void deque<T, Allocator, kDequeSubarraySize>::insert(const_iterator position, InputIterator first, InputIterator last)
1909  {
1910  DoInsert(position, first, last, is_integral<InputIterator>()); // The C++ standard requires this sort of behaviour, as InputIterator might actually be Integer and 'first' is really 'count' and 'last' is really 'value'.
1911  }
1912 
1913 
1914  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
1915  typename deque<T, Allocator, kDequeSubarraySize>::iterator
1916  deque<T, Allocator, kDequeSubarraySize>::insert(const_iterator position, std::initializer_list<value_type> ilist)
1917  {
1918  const difference_type i(position - mItBegin);
1919  DoInsert(position, ilist.begin(), ilist.end(), false_type());
1920  return (mItBegin + i);
1921  }
1922 
1923 
1924  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
1925  typename deque<T, Allocator, kDequeSubarraySize>::iterator
1926  deque<T, Allocator, kDequeSubarraySize>::erase(const_iterator position)
1927  {
1928  #if EASTL_ASSERT_ENABLED
1929  if(EASTL_UNLIKELY(!(validate_iterator(position) & isf_valid)))
1930  EASTL_FAIL_MSG("deque::erase -- invalid iterator");
1931 
1932  if(EASTL_UNLIKELY(position == end()))
1933  EASTL_FAIL_MSG("deque::erase -- end() iterator is an invalid iterator for erase");
1934  #endif
1935 
1936  iterator itPosition(position, typename iterator::FromConst());
1937  iterator itNext(itPosition, typename iterator::Increment());
1938  const difference_type i(itPosition - mItBegin);
1939 
1940  if(i < (difference_type)(size() / 2)) // Should we move the front entries forward or the back entries backward? We divide the range in half.
1941  {
1942  itNext.copy_backward(mItBegin, itPosition, eastl::has_trivial_relocate<value_type>());
1943  pop_front();
1944  }
1945  else
1946  {
1947  itPosition.copy(itNext, mItEnd, eastl::has_trivial_relocate<value_type>());
1948  pop_back();
1949  }
1950 
1951  return mItBegin + i;
1952  }
1953 
1954 
1955  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
1956  typename deque<T, Allocator, kDequeSubarraySize>::iterator
1957  deque<T, Allocator, kDequeSubarraySize>::erase(const_iterator first, const_iterator last)
1958  {
1959  iterator itFirst(first, typename iterator::FromConst());
1960  iterator itLast(last, typename iterator::FromConst());
1961 
1962  #if EASTL_ASSERT_ENABLED
1963  if(EASTL_UNLIKELY(!(validate_iterator(itFirst) & isf_valid)))
1964  EASTL_FAIL_MSG("deque::erase -- invalid iterator");
1965  if(EASTL_UNLIKELY(!(validate_iterator(itLast) & isf_valid)))
1966  EASTL_FAIL_MSG("deque::erase -- invalid iterator");
1967  #endif
1968 
1969  if((itFirst != mItBegin) || (itLast != mItEnd)) // If not erasing everything... (We expect that the user won't call erase(begin, end) because instead the user would just call clear.)
1970  {
1971  const difference_type n(itLast - itFirst);
1972  const difference_type i(itFirst - mItBegin);
1973 
1974  if(i < (difference_type)((size() - n) / 2)) // Should we move the front entries forward or the back entries backward? We divide the range in half.
1975  {
1976  const iterator itNewBegin(mItBegin + n);
1977  value_type** const pPtrArrayBegin = mItBegin.mpCurrentArrayPtr;
1978 
1979  itLast.copy_backward(mItBegin, itFirst, eastl::has_trivial_relocate<value_type>());
1980 
1981  for(; mItBegin != itNewBegin; ++mItBegin) // Question: If value_type is a POD type, will the compiler generate this loop at all?
1982  mItBegin.mpCurrent->~value_type(); // If so, then we need to make a specialization for destructing PODs.
1983 
1984  DoFreeSubarrays(pPtrArrayBegin, itNewBegin.mpCurrentArrayPtr);
1985 
1986  // mItBegin = itNewBegin; <-- Not necessary, as the above loop makes it so already.
1987  }
1988  else // Else we will be moving back entries backward.
1989  {
1990  iterator itNewEnd(mItEnd - n);
1991  value_type** const pPtrArrayEnd = itNewEnd.mpCurrentArrayPtr + 1;
1992 
1993  itFirst.copy(itLast, mItEnd, eastl::has_trivial_relocate<value_type>());
1994 
1995  for(iterator itTemp(itNewEnd); itTemp != mItEnd; ++itTemp)
1996  itTemp.mpCurrent->~value_type();
1997 
1998  DoFreeSubarrays(pPtrArrayEnd, mItEnd.mpCurrentArrayPtr + 1);
1999 
2000  mItEnd = itNewEnd;
2001  }
2002 
2003  return mItBegin + i;
2004  }
2005 
2006  clear();
2007  return mItEnd;
2008  }
2009 
2010 
2011  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
2012  typename deque<T, Allocator, kDequeSubarraySize>::reverse_iterator
2013  deque<T, Allocator, kDequeSubarraySize>::erase(reverse_iterator position)
2014  {
2015  return reverse_iterator(erase((++position).base()));
2016  }
2017 
2018 
2019  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
2020  typename deque<T, Allocator, kDequeSubarraySize>::reverse_iterator
2021  deque<T, Allocator, kDequeSubarraySize>::erase(reverse_iterator first, reverse_iterator last)
2022  {
2023  // Version which erases in order from first to last.
2024  // difference_type i(first.base() - last.base());
2025  // while(i--)
2026  // first = erase(first);
2027  // return first;
2028 
2029  // Version which erases in order from last to first, but is slightly more efficient:
2030  return reverse_iterator(erase(last.base(), first.base()));
2031  }
2032 
2033 
2034  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
2035  void deque<T, Allocator, kDequeSubarraySize>::clear()
2036  {
2037  // Destroy all values and all subarrays they belong to, except for the first one,
2038  // as we need to reserve some space for a valid mItBegin/mItEnd.
2039  if(mItBegin.mpCurrentArrayPtr != mItEnd.mpCurrentArrayPtr) // If there are multiple subarrays (more often than not, this will be so)...
2040  {
2041  for(value_type* p1 = mItBegin.mpCurrent; p1 < mItBegin.mpEnd; ++p1)
2042  p1->~value_type();
2043  for(value_type* p2 = mItEnd.mpBegin; p2 < mItEnd.mpCurrent; ++p2)
2044  p2->~value_type();
2045  DoFreeSubarray(mItEnd.mpBegin); // Leave mItBegin with a valid subarray.
2046  }
2047  else
2048  {
2049  for(value_type* p = mItBegin.mpCurrent; p < mItEnd.mpCurrent; ++p)
2050  p->~value_type();
2051  // Don't free the one existing subarray, as we need it for mItBegin/mItEnd.
2052  }
2053 
2054  for(value_type** pPtrArray = mItBegin.mpCurrentArrayPtr + 1; pPtrArray < mItEnd.mpCurrentArrayPtr; ++pPtrArray)
2055  {
2056  for(value_type* p = *pPtrArray, *pEnd = *pPtrArray + kDequeSubarraySize; p < pEnd; ++p)
2057  p->~value_type();
2058  DoFreeSubarray(*pPtrArray);
2059  }
2060 
2061  mItEnd = mItBegin; // mItBegin/mItEnd will not be dereferencable.
2062  }
2063 
2064 
2065  //template <typename T, typename Allocator, unsigned kDequeSubarraySize>
2066  //void deque<T, Allocator, kDequeSubarraySize>::reset_lose_memory()
2067  //{
2068  // // The reset_lose_memory function is a special extension function which unilaterally
2069  // // resets the container to an empty state without freeing the memory of
2070  // // the contained objects. This is useful for very quickly tearing down a
2071  // // container built into scratch memory.
2072  //
2073  // // Currently we are unable to get this reset_lose_memory operation to work correctly
2074  // // as we haven't been able to find a good way to have a deque initialize
2075  // // without allocating memory. We can lose the old memory, but DoInit
2076  // // would necessarily do a ptrArray allocation. And this is not within
2077  // // our definition of how reset_lose_memory works.
2078  // base_type::DoInit(0);
2079  //
2080  //}
2081 
2082 
2083  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
2084  void deque<T, Allocator, kDequeSubarraySize>::swap(deque& x)
2085  {
2086  #if defined(EASTL_DEQUE_LEGACY_SWAP_BEHAVIOUR_REQUIRES_COPY_CTOR) && EASTL_DEQUE_LEGACY_SWAP_BEHAVIOUR_REQUIRES_COPY_CTOR
2087  if(mAllocator == x.mAllocator) // If allocators are equivalent...
2088  DoSwap(x);
2089  else // else swap the contents.
2090  {
2091  const this_type temp(*this); // Can't call eastl::swap because that would
2092  *this = x; // itself call this member swap function.
2093  x = temp;
2094  }
2095  #else
2096  // NOTE(rparolin): The previous implementation required T to be copy-constructible in the fall-back case where
2097  // allocators with unique instances copied elements. This was an unnecessary restriction and prevented the common
2098  // usage of deque with non-copyable types (eg. eastl::deque<non_copyable> or eastl::deque<unique_ptr>).
2099  //
2100  // The previous implementation violated the following requirements of deque::swap so the fall-back code has
2101  // been removed. EASTL implicitly defines 'propagate_on_container_swap = false' therefore the fall-back case is
2102  // undefined behaviour. We simply swap the contents and the allocator as that is the common expectation of
2103  // users and does not put the container into an invalid state since it can not free its memory via its current
2104  // allocator instance.
2105  //
2106  DoSwap(x);
2107  #endif
2108  }
2109 
2110 
2111  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
2112  template <typename Integer>
2113  void deque<T, Allocator, kDequeSubarraySize>::DoInit(Integer n, Integer value, true_type)
2114  {
2115  base_type::DoInit(n); // Call the base uninitialized init function.
2116  DoFillInit(value);
2117  }
2118 
2119 
2120  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
2121  template <typename InputIterator>
2122  void deque<T, Allocator, kDequeSubarraySize>::DoInit(InputIterator first, InputIterator last, false_type)
2123  {
2124  typedef typename eastl::iterator_traits<InputIterator>::iterator_category IC;
2125  DoInitFromIterator(first, last, IC());
2126  }
2127 
2128 
2129  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
2130  template <typename InputIterator>
2131  void deque<T, Allocator, kDequeSubarraySize>::DoInitFromIterator(InputIterator first, InputIterator last, EASTL_ITC_NS::input_iterator_tag)
2132  {
2133  base_type::DoInit(0); // Call the base uninitialized init function, but don't actually allocate any values.
2134 
2135  #if EASTL_EXCEPTIONS_ENABLED
2136  try
2137  {
2138  #endif
2139  // We have little choice but to turn through the source iterator and call
2140  // push_back for each item. It can be slow because it will keep reallocating the
2141  // container memory as we go. We are not allowed to use distance() on an InputIterator.
2142  for(; first != last; ++first) // InputIterators by definition actually only allow you to iterate through them once.
2143  { // Thus the standard *requires* that we do this (inefficient) implementation.
2144  push_back(*first); // Luckily, InputIterators are in practice almost never used, so this code will likely never get executed.
2145  }
2146  #if EASTL_EXCEPTIONS_ENABLED
2147  }
2148  catch(...)
2149  {
2150  clear();
2151  throw;
2152  }
2153  #endif
2154  }
2155 
2156 
2157  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
2158  template <typename ForwardIterator>
2159  void deque<T, Allocator, kDequeSubarraySize>::DoInitFromIterator(ForwardIterator first, ForwardIterator last, EASTL_ITC_NS::forward_iterator_tag)
2160  {
2161  typedef typename eastl::remove_const<ForwardIterator>::type non_const_iterator_type; // If T is a const type (e.g. const int) then we need to initialize it as if it were non-const.
2162  typedef typename eastl::remove_const<value_type>::type non_const_value_type;
2163 
2164  const size_type n = (size_type)eastl::distance(first, last);
2165  value_type** pPtrArrayCurrent;
2166 
2167  base_type::DoInit(n); // Call the base uninitialized init function.
2168 
2169  #if EASTL_EXCEPTIONS_ENABLED
2170  try
2171  {
2172  #endif
2173  for(pPtrArrayCurrent = mItBegin.mpCurrentArrayPtr; pPtrArrayCurrent < mItEnd.mpCurrentArrayPtr; ++pPtrArrayCurrent) // Copy to the known-to-be-completely-used subarrays.
2174  {
2175  // We implment an algorithm here whereby we use uninitialized_copy() and advance() instead of just iterating from first to last and constructing as we go. The reason for this is that we can take advantage of POD data types and implement construction as memcpy operations.
2176  ForwardIterator current(first); // To do: Implement a specialization of this algorithm for non-PODs which eliminates the need for 'current'.
2177 
2178  eastl::advance(current, kDequeSubarraySize);
2179  eastl::uninitialized_copy((non_const_iterator_type)first, (non_const_iterator_type)current, (non_const_value_type*)*pPtrArrayCurrent);
2180  first = current;
2181  }
2182 
2183  eastl::uninitialized_copy((non_const_iterator_type)first, (non_const_iterator_type)last, (non_const_value_type*)mItEnd.mpBegin);
2184  #if EASTL_EXCEPTIONS_ENABLED
2185  }
2186  catch(...)
2187  {
2188  for(iterator itCurrent(mItBegin), itEnd(pPtrArrayCurrent, *pPtrArrayCurrent); itCurrent != itEnd; ++itCurrent)
2189  itCurrent.mpCurrent->~value_type();
2190  throw;
2191  }
2192  #endif
2193  }
2194 
2195 
2196  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
2197  void deque<T, Allocator, kDequeSubarraySize>::DoFillInit(const value_type& value)
2198  {
2199  value_type** pPtrArrayCurrent = mItBegin.mpCurrentArrayPtr;
2200 
2201  #if EASTL_EXCEPTIONS_ENABLED
2202  try
2203  {
2204  #endif
2205  while(pPtrArrayCurrent < mItEnd.mpCurrentArrayPtr)
2206  {
2207  eastl::uninitialized_fill(*pPtrArrayCurrent, *pPtrArrayCurrent + kDequeSubarraySize, value);
2208  ++pPtrArrayCurrent;
2209  }
2210  eastl::uninitialized_fill(mItEnd.mpBegin, mItEnd.mpCurrent, value);
2211  #if EASTL_EXCEPTIONS_ENABLED
2212  }
2213  catch(...)
2214  {
2215  for(iterator itCurrent(mItBegin), itEnd(pPtrArrayCurrent, *pPtrArrayCurrent); itCurrent != itEnd; ++itCurrent)
2216  itCurrent.mpCurrent->~value_type();
2217  throw;
2218  }
2219  #endif
2220  }
2221 
2222 
2223  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
2224  template <typename Integer>
2225  void deque<T, Allocator, kDequeSubarraySize>::DoAssign(Integer n, Integer value, true_type) // false_type means this is the integer version instead of iterator version.
2226  {
2227  DoAssignValues(static_cast<size_type>(n), static_cast<value_type>(value));
2228  }
2229 
2230 
2231  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
2232  template <typename InputIterator>
2233  void deque<T, Allocator, kDequeSubarraySize>::DoAssign(InputIterator first, InputIterator last, false_type) // false_type means this is the iterator version instead of integer version.
2234  {
2235  // Actually, the implementation below requires first/last to be a ForwardIterator and not just an InputIterator.
2236  // But Paul Pedriana if you somehow need to work with an InputIterator and we can deal with it.
2237  const size_type n = (size_type)eastl::distance(first, last);
2238  const size_type nSize = size();
2239 
2240  if(n > nSize) // If we are increasing the size...
2241  {
2242  InputIterator atEnd(first);
2243 
2244  eastl::advance(atEnd, (difference_type)nSize);
2245  eastl::copy(first, atEnd, mItBegin);
2246  insert(mItEnd, atEnd, last);
2247  }
2248  else // n is <= size.
2249  {
2250  iterator itEnd(eastl::copy(first, last, mItBegin));
2251 
2252  if(n < nSize) // If we need to erase any trailing elements...
2253  erase(itEnd, mItEnd);
2254  }
2255  }
2256 
2257 
2258  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
2259  void deque<T, Allocator, kDequeSubarraySize>::DoAssignValues(size_type n, const value_type& value)
2260  {
2261  const size_type nSize = size();
2262 
2263  if(n > nSize) // If we are increasing the size...
2264  {
2265  eastl::fill(mItBegin, mItEnd, value);
2266  insert(mItEnd, n - nSize, value);
2267  }
2268  else
2269  {
2270  erase(mItBegin + (difference_type)n, mItEnd);
2271  eastl::fill(mItBegin, mItEnd, value);
2272  }
2273  }
2274 
2275 
2276  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
2277  template <typename Integer>
2278  void deque<T, Allocator, kDequeSubarraySize>::DoInsert(const const_iterator& position, Integer n, Integer value, true_type)
2279  {
2280  DoInsertValues(position, (size_type)n, (value_type)value);
2281  }
2282 
2283 
2284  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
2285  template <typename InputIterator>
2286  void deque<T, Allocator, kDequeSubarraySize>::DoInsert(const const_iterator& position, const InputIterator& first, const InputIterator& last, false_type)
2287  {
2288  typedef typename eastl::iterator_traits<InputIterator>::iterator_category IC;
2289  DoInsertFromIterator(position, first, last, IC());
2290  }
2291 
2292 
2293  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
2294  template <typename InputIterator>
2295  void deque<T, Allocator, kDequeSubarraySize>::DoInsertFromIterator(const_iterator position, const InputIterator& first, const InputIterator& last, EASTL_ITC_NS::forward_iterator_tag)
2296  {
2297  const size_type n = (size_type)eastl::distance(first, last);
2298 
2299  // This implementation is nearly identical to DoInsertValues below.
2300  // If you make a bug fix to one, you will likely want to fix the other.
2301  if(position.mpCurrent == mItBegin.mpCurrent) // If inserting at the beginning or into an empty container...
2302  {
2303  iterator itNewBegin(DoReallocSubarray(n, kSideFront)); // itNewBegin to mItBegin refers to memory that isn't initialized yet; so it's not truly a valid iterator. Or at least not a dereferencable one.
2304 
2305  #if EASTL_EXCEPTIONS_ENABLED
2306  try
2307  {
2308  #endif
2309  // We would like to use move here instead of copy when possible, which would be useful for
2310  // when inserting from a std::initializer_list, for example.
2311  // To do: solve this by having a template or runtime parameter which specifies move vs copy.
2312  eastl::uninitialized_copy(first, last, itNewBegin);
2313  mItBegin = itNewBegin;
2314  #if EASTL_EXCEPTIONS_ENABLED
2315  }
2316  catch(...)
2317  {
2318  DoFreeSubarrays(itNewBegin.mpCurrentArrayPtr, mItBegin.mpCurrentArrayPtr);
2319  throw;
2320  }
2321  #endif
2322  }
2323  else if(EASTL_UNLIKELY(position.mpCurrent == mItEnd.mpCurrent)) // If inserting at the end (i.e. appending)...
2324  {
2325  const iterator itNewEnd(DoReallocSubarray(n, kSideBack)); // mItEnd to itNewEnd refers to memory that isn't initialized yet; so it's not truly a valid iterator. Or at least not a dereferencable one.
2326 
2327  #if EASTL_EXCEPTIONS_ENABLED
2328  try
2329  {
2330  #endif
2331  // We would like to use move here instead of copy when possible, which would be useful for
2332  // when inserting from a std::initializer_list, for example.
2333  // To do: solve this by having a template or runtime parameter which specifies move vs copy.
2334  eastl::uninitialized_copy(first, last, mItEnd);
2335  mItEnd = itNewEnd;
2336  #if EASTL_EXCEPTIONS_ENABLED
2337  }
2338  catch(...)
2339  {
2340  DoFreeSubarrays(mItEnd.mpCurrentArrayPtr + 1, itNewEnd.mpCurrentArrayPtr + 1);
2341  throw;
2342  }
2343  #endif
2344  }
2345  else
2346  {
2347  const difference_type nInsertionIndex = position - mItBegin;
2348  const size_type nSize = size();
2349 
2350  if(nInsertionIndex < (difference_type)(nSize / 2)) // If the insertion index is in the front half of the deque... grow the deque at the front.
2351  {
2352  const iterator itNewBegin(DoReallocSubarray(n, kSideFront)); // itNewBegin to mItBegin refers to memory that isn't initialized yet; so it's not truly a valid iterator. Or at least not a dereferencable one.
2353  const iterator itOldBegin(mItBegin);
2354  const iterator itPosition(mItBegin + nInsertionIndex); // We need to reset this value because the reallocation above can invalidate iterators.
2355 
2356  #if EASTL_EXCEPTIONS_ENABLED
2357  try
2358  {
2359  #endif
2360  // We have a problem here: we would like to use move instead of copy, but it may be that the range to be inserted comes from
2361  // this container and comes from the segment we need to move. So we can't use move operations unless we are careful to handle
2362  // that situation. The newly inserted contents must be contents that were moved to and not moved from. To do: solve this.
2363  if(nInsertionIndex >= (difference_type)n) // If the newly inserted items will be entirely within the old area...
2364  {
2365  iterator itUCopyEnd(mItBegin + (difference_type)n);
2366 
2367  eastl::uninitialized_copy(mItBegin, itUCopyEnd, itNewBegin); // This can throw.
2368  itUCopyEnd = eastl::copy(itUCopyEnd, itPosition, itOldBegin); // Recycle 'itUCopyEnd' to mean something else.
2369  eastl::copy(first, last, itUCopyEnd);
2370  }
2371  else // Else the newly inserted items are going within the newly allocated area at the front.
2372  {
2373  InputIterator mid(first);
2374 
2375  eastl::advance(mid, (difference_type)n - nInsertionIndex);
2376  eastl::uninitialized_copy_copy(mItBegin, itPosition, first, mid, itNewBegin); // This can throw.
2377  eastl::copy(mid, last, itOldBegin);
2378  }
2379  mItBegin = itNewBegin;
2380  #if EASTL_EXCEPTIONS_ENABLED
2381  }
2382  catch(...)
2383  {
2384  DoFreeSubarrays(itNewBegin.mpCurrentArrayPtr, mItBegin.mpCurrentArrayPtr);
2385  throw;
2386  }
2387  #endif
2388  }
2389  else
2390  {
2391  const iterator itNewEnd(DoReallocSubarray(n, kSideBack));
2392  const iterator itOldEnd(mItEnd);
2393  const difference_type nPushedCount = (difference_type)nSize - nInsertionIndex;
2394  const iterator itPosition(mItEnd - nPushedCount); // We need to reset this value because the reallocation above can invalidate iterators.
2395 
2396  #if EASTL_EXCEPTIONS_ENABLED
2397  try
2398  {
2399  #endif
2400  // We have a problem here: we would like to use move instead of copy, but it may be that the range to be inserted comes from
2401  // this container and comes from the segment we need to move. So we can't use move operations unless we are careful to handle
2402  // that situation. The newly inserted contents must be contents that were moved to and not moved from. To do: solve this.
2403  if(nPushedCount > (difference_type)n)
2404  {
2405  const iterator itUCopyEnd(mItEnd - (difference_type)n);
2406 
2407  eastl::uninitialized_copy(itUCopyEnd, mItEnd, mItEnd);
2408  eastl::copy_backward(itPosition, itUCopyEnd, itOldEnd);
2409  eastl::copy(first, last, itPosition);
2410  }
2411  else
2412  {
2413  InputIterator mid(first);
2414 
2415  eastl::advance(mid, nPushedCount);
2416  eastl::uninitialized_copy_copy(mid, last, itPosition, mItEnd, mItEnd);
2417  eastl::copy(first, mid, itPosition);
2418  }
2419  mItEnd = itNewEnd;
2420  #if EASTL_EXCEPTIONS_ENABLED
2421  }
2422  catch(...)
2423  {
2424  DoFreeSubarrays(mItEnd.mpCurrentArrayPtr + 1, itNewEnd.mpCurrentArrayPtr + 1);
2425  throw;
2426  }
2427  #endif
2428  }
2429  }
2430  }
2431 
2432 
2433  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
2434  void deque<T, Allocator, kDequeSubarraySize>::DoInsertValues(const_iterator position, size_type n, const value_type& value)
2435  {
2436  #if EASTL_ASSERT_ENABLED
2437  if(EASTL_UNLIKELY(!(validate_iterator(position) & isf_valid)))
2438  EASTL_FAIL_MSG("deque::insert -- invalid iterator");
2439  #endif
2440 
2441  // This implementation is nearly identical to DoInsertFromIterator above.
2442  // If you make a bug fix to one, you will likely want to fix the other.
2443  if(position.mpCurrent == mItBegin.mpCurrent) // If inserting at the beginning...
2444  {
2445  const iterator itNewBegin(DoReallocSubarray(n, kSideFront));
2446 
2447  #if EASTL_EXCEPTIONS_ENABLED
2448  try
2449  {
2450  #endif
2451  // Note that we don't make a temp copy of 'value' here. This is because in a
2452  // deque, insertion at either the front or back doesn't cause a reallocation
2453  // or move of data in the middle. That's a key feature of deques, in fact.
2454  eastl::uninitialized_fill(itNewBegin, mItBegin, value);
2455  mItBegin = itNewBegin;
2456  #if EASTL_EXCEPTIONS_ENABLED
2457  }
2458  catch(...)
2459  {
2460  DoFreeSubarrays(itNewBegin.mpCurrentArrayPtr, mItBegin.mpCurrentArrayPtr);
2461  throw;
2462  }
2463  #endif
2464  }
2465  else if(EASTL_UNLIKELY(position.mpCurrent == mItEnd.mpCurrent)) // If inserting at the end (i.e. appending)...
2466  {
2467  const iterator itNewEnd(DoReallocSubarray(n, kSideBack));
2468 
2469  #if EASTL_EXCEPTIONS_ENABLED
2470  try
2471  {
2472  #endif
2473  // Note that we don't make a temp copy of 'value' here. This is because in a
2474  // deque, insertion at either the front or back doesn't cause a reallocation
2475  // or move of data in the middle. That's a key feature of deques, in fact.
2476  eastl::uninitialized_fill(mItEnd, itNewEnd, value);
2477  mItEnd = itNewEnd;
2478  #if EASTL_EXCEPTIONS_ENABLED
2479  }
2480  catch(...)
2481  {
2482  DoFreeSubarrays(mItEnd.mpCurrentArrayPtr + 1, itNewEnd.mpCurrentArrayPtr + 1);
2483  throw;
2484  }
2485  #endif
2486  }
2487  else
2488  {
2489  // A key purpose of a deque is to implement insertions and removals more efficiently
2490  // than with a vector. We are inserting into the middle of the deque here. A quick and
2491  // dirty implementation of this would be to reallocate the subarrays and simply push
2492  // all values in the middle upward like you would do with a vector. Instead we implement
2493  // the minimum amount of reallocations needed but may need to do some value moving,
2494  // as the subarray sizes need to remain constant and can have no holes in them.
2495  const difference_type nInsertionIndex = position - mItBegin;
2496  const size_type nSize = size();
2497  const value_type valueSaved(value);
2498 
2499  if(nInsertionIndex < (difference_type)(nSize / 2)) // If the insertion index is in the front half of the deque... grow the deque at the front.
2500  {
2501  const iterator itNewBegin(DoReallocSubarray(n, kSideFront));
2502  const iterator itOldBegin(mItBegin);
2503  const iterator itPosition(mItBegin + nInsertionIndex); // We need to reset this value because the reallocation above can invalidate iterators.
2504 
2505  #if EASTL_EXCEPTIONS_ENABLED
2506  try
2507  {
2508  #endif
2509  if(nInsertionIndex >= (difference_type)n) // If the newly inserted items will be entirely within the old area...
2510  {
2511  iterator itUCopyEnd(mItBegin + (difference_type)n);
2512 
2513  eastl::uninitialized_move_if_noexcept(mItBegin, itUCopyEnd, itNewBegin); // This can throw.
2514  itUCopyEnd = eastl::move(itUCopyEnd, itPosition, itOldBegin); // Recycle 'itUCopyEnd' to mean something else.
2515  eastl::fill(itUCopyEnd, itPosition, valueSaved);
2516  }
2517  else // Else the newly inserted items are going within the newly allocated area at the front.
2518  {
2519  eastl::uninitialized_move_fill(mItBegin, itPosition, itNewBegin, mItBegin, valueSaved); // This can throw.
2520  eastl::fill(itOldBegin, itPosition, valueSaved);
2521  }
2522  mItBegin = itNewBegin;
2523  #if EASTL_EXCEPTIONS_ENABLED
2524  }
2525  catch(...)
2526  {
2527  DoFreeSubarrays(itNewBegin.mpCurrentArrayPtr, mItBegin.mpCurrentArrayPtr);
2528  throw;
2529  }
2530  #endif
2531  }
2532  else // Else the insertion index is in the back half of the deque, so grow the deque at the back.
2533  {
2534  const iterator itNewEnd(DoReallocSubarray(n, kSideBack));
2535  const iterator itOldEnd(mItEnd);
2536  const difference_type nPushedCount = (difference_type)nSize - nInsertionIndex;
2537  const iterator itPosition(mItEnd - nPushedCount); // We need to reset this value because the reallocation above can invalidate iterators.
2538 
2539  #if EASTL_EXCEPTIONS_ENABLED
2540  try
2541  {
2542  #endif
2543  if(nPushedCount > (difference_type)n) // If the newly inserted items will be entirely within the old area...
2544  {
2545  iterator itUCopyEnd(mItEnd - (difference_type)n);
2546 
2547  eastl::uninitialized_move_if_noexcept(itUCopyEnd, mItEnd, mItEnd); // This can throw.
2548  itUCopyEnd = eastl::move_backward(itPosition, itUCopyEnd, itOldEnd); // Recycle 'itUCopyEnd' to mean something else.
2549  eastl::fill(itPosition, itUCopyEnd, valueSaved);
2550  }
2551  else // Else the newly inserted items are going within the newly allocated area at the back.
2552  {
2553  eastl::uninitialized_fill_move(mItEnd, itPosition + (difference_type)n, valueSaved, itPosition, mItEnd); // This can throw.
2554  eastl::fill(itPosition, itOldEnd, valueSaved);
2555  }
2556  mItEnd = itNewEnd;
2557  #if EASTL_EXCEPTIONS_ENABLED
2558  }
2559  catch(...)
2560  {
2561  DoFreeSubarrays(mItEnd.mpCurrentArrayPtr + 1, itNewEnd.mpCurrentArrayPtr + 1);
2562  throw;
2563  }
2564  #endif
2565  }
2566  }
2567  }
2568 
2569 
2570  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
2571  inline void deque<T, Allocator, kDequeSubarraySize>::DoSwap(this_type& x)
2572  {
2573  eastl::swap(mpPtrArray, x.mpPtrArray);
2574  eastl::swap(mnPtrArraySize, x.mnPtrArraySize);
2575  eastl::swap(mItBegin, x.mItBegin);
2576  eastl::swap(mItEnd, x.mItEnd);
2577  eastl::swap(mAllocator, x.mAllocator); // We do this even if EASTL_ALLOCATOR_COPY_ENABLED is 0.
2578 
2579  }
2580 
2581 
2582  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
2583  inline bool deque<T, Allocator, kDequeSubarraySize>::validate() const
2584  {
2585  // To do: More detailed validation.
2586  // To do: Try to make the validation resistant to crashes if the data is invalid.
2587  if((end() - begin()) < 0)
2588  return false;
2589  return true;
2590  }
2591 
2592 
2593  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
2594  inline int deque<T, Allocator, kDequeSubarraySize>::validate_iterator(const_iterator i) const
2595  {
2596  // To do: We don't currently track isf_current, will need to make it do so.
2597  // To do: Fix the validation below, as it will not catch all invalid iterators.
2598  if((i - begin()) < 0)
2599  return isf_none;
2600 
2601  if((end() - i) < 0)
2602  return isf_none;
2603 
2604  if(i == end())
2605  return (isf_valid | isf_current);
2606 
2607  return (isf_valid | isf_current | isf_can_dereference);
2608  }
2609 
2610 
2611 
2613  // global operators
2615 
2616  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
2617  inline bool operator==(const deque<T, Allocator, kDequeSubarraySize>& a, const deque<T, Allocator, kDequeSubarraySize>& b)
2618  {
2619  return ((a.size() == b.size()) && eastl::equal(a.begin(), a.end(), b.begin()));
2620  }
2621 
2622  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
2623  inline bool operator!=(const deque<T, Allocator, kDequeSubarraySize>& a, const deque<T, Allocator, kDequeSubarraySize>& b)
2624  {
2625  return ((a.size() != b.size()) || !eastl::equal(a.begin(), a.end(), b.begin()));
2626  }
2627 
2628  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
2629  inline bool operator<(const deque<T, Allocator, kDequeSubarraySize>& a, const deque<T, Allocator, kDequeSubarraySize>& b)
2630  {
2631  return eastl::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end());
2632  }
2633 
2634  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
2635  inline bool operator>(const deque<T, Allocator, kDequeSubarraySize>& a, const deque<T, Allocator, kDequeSubarraySize>& b)
2636  {
2637  return b < a;
2638  }
2639 
2640  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
2641  inline bool operator<=(const deque<T, Allocator, kDequeSubarraySize>& a, const deque<T, Allocator, kDequeSubarraySize>& b)
2642  {
2643  return !(b < a);
2644  }
2645 
2646  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
2647  inline bool operator>=(const deque<T, Allocator, kDequeSubarraySize>& a, const deque<T, Allocator, kDequeSubarraySize>& b)
2648  {
2649  return !(a < b);
2650  }
2651 
2652  template <typename T, typename Allocator, unsigned kDequeSubarraySize>
2653  inline void swap(deque<T, Allocator, kDequeSubarraySize>& a, deque<T, Allocator, kDequeSubarraySize>& b)
2654  {
2655  a.swap(b);
2656  }
2657 
2659  // erase / erase_if
2660  //
2661  // https://en.cppreference.com/w/cpp/container/deque/erase2
2663  template <class T, class Allocator, class U>
2664  void erase(deque<T, Allocator>& c, const U& value)
2665  {
2666  // Erases all elements that compare equal to value from the container.
2667  c.erase(eastl::remove(c.begin(), c.end(), value), c.end());
2668  }
2669 
2670  template <class T, class Allocator, class Predicate>
2671  void erase_if(deque<T, Allocator>& c, Predicate predicate)
2672  {
2673  // Erases all elements that satisfy the predicate pred from the container.
2674  c.erase(eastl::remove_if(c.begin(), c.end(), predicate), c.end());
2675  }
2676 
2677 
2678 } // namespace eastl
2679 
2680 
2681 EA_RESTORE_VC_WARNING();
2682 #if EASTL_EXCEPTIONS_ENABLED
2683  EA_RESTORE_VC_WARNING();
2684 #endif
2685 
2686 
2687 #endif // Header include guard
Definition: allocator.h:52
Definition: deque.h:338
Definition: iterator.h:224
Definition: initializer_list.h:38
EA Standard Template Library.
Definition: algorithm.h:288
ForwardIterator uninitialized_move_if_noexcept(InputIterator first, InputIterator last, ForwardIterator dest)
Definition: memory.h:777
void uninitialized_move_fill(InputIterator first1, InputIterator last1, ForwardIterator first2, ForwardIterator last2, const T &value)
Definition: memory.h:1199
ForwardIterator uninitialized_copy_copy(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, ForwardIterator result)
Definition: memory.h:1289
ForwardIterator remove(ForwardIterator first, ForwardIterator last, const T &value)
Definition: algorithm.h:2581
ForwardIterator uninitialized_fill_move(ForwardIterator result, ForwardIterator mid, const T &value, InputIterator first, InputIterator last)
Definition: memory.h:1259
OutputIterator copy(InputIterator first, InputIterator last, OutputIterator result)
Definition: copy_help.h:191
void fill(ForwardIterator first, ForwardIterator last, const T &value)
Definition: fill_help.h:75
OutputIterator move(InputIterator first, InputIterator last, OutputIterator result)
Definition: copy_help.h:170
ForwardIterator remove_if(ForwardIterator first, ForwardIterator last, Predicate predicate)
Definition: algorithm.h:2618
EA_CPP14_CONSTEXPR bool equal(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2)
Definition: algorithm.h:1856
EA_CONSTEXPR eastl::enable_if< eastl::is_scalar< T >::value, T >::type max_alt(T a, T b)
Definition: algorithm.h:584
ForwardIterator uninitialized_copy(InputIterator first, InputIterator last, ForwardIterator result)
Definition: memory.h:601
bool lexicographical_compare(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2)
Definition: algorithm.h:1996
BidirectionalIterator2 move_backward(BidirectionalIterator1 first, BidirectionalIterator1 last, BidirectionalIterator2 resultEnd)
Definition: algorithm.h:1304
void * allocate_memory(Allocator &a, size_t n, size_t alignment, size_t alignmentOffset)
Definition: allocator.h:354
BidirectionalIterator2 copy_backward(BidirectionalIterator1 first, BidirectionalIterator1 last, BidirectionalIterator2 resultEnd)
Definition: algorithm.h:1325
Definition: deque.h:260
static const size_type kMaxSize
'npos' means non-valid position or simply non-position.
Definition: deque.h:269
Side
Defines the side of the deque: front or back.
Definition: deque.h:279
@ kSideBack
Identifies the front side of the deque.
Definition: deque.h:281
@ kSubarraySize
A new empty deque has a ptrArraySize of 0, but any allocated ptrArrays use this min size.
Definition: deque.h:274
Definition: deque.h:232
Definition: deque.h:233
Definition: deque.h:231
Definition: deque.h:153
Definition: iterator.h:75
Definition: type_pod.h:398
Definition: iterator.h:73
Definition: type_traits.h:263
Definition: iterator.h:86