Nugget
fixed_vector.h
1 // Copyright (c) Electronic Arts Inc. All rights reserved.
4 
6 // This file implements a vector which uses a fixed size memory pool.
7 // The bEnableOverflow template parameter allows the container to resort to
8 // heap allocations if the memory pool is exhausted.
10 
11 
12 #ifndef EASTL_FIXED_VECTOR_H
13 #define EASTL_FIXED_VECTOR_H
14 
15 
16 #include <EASTL/vector.h>
17 #include <EASTL/internal/fixed_pool.h>
18 
19 #if defined(EA_PRAGMA_ONCE_SUPPORTED)
20  #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.
21 #endif
22 
23 
24 
25 namespace eastl
26 {
33  #ifndef EASTL_FIXED_VECTOR_DEFAULT_NAME
34  #define EASTL_FIXED_VECTOR_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " fixed_vector" // Unless the user overrides something, this is "EASTL fixed_vector".
35  #endif
36 
37 
40  #ifndef EASTL_FIXED_VECTOR_DEFAULT_ALLOCATOR
41  #define EASTL_FIXED_VECTOR_DEFAULT_ALLOCATOR overflow_allocator_type(EASTL_FIXED_VECTOR_DEFAULT_NAME)
42  #endif
43 
44 
70  template <typename T, size_t nodeCount, bool bEnableOverflow = true, typename OverflowAllocator = typename eastl::type_select<bEnableOverflow, EASTLAllocatorType, EASTLDummyAllocatorType>::type>
71  class fixed_vector : public vector<T, fixed_vector_allocator<sizeof(T), nodeCount, EASTL_ALIGN_OF(T), 0, bEnableOverflow, OverflowAllocator> >
72  {
73  public:
74  typedef fixed_vector_allocator<sizeof(T), nodeCount, EASTL_ALIGN_OF(T),
75  0, bEnableOverflow, OverflowAllocator> fixed_allocator_type;
76  typedef OverflowAllocator overflow_allocator_type;
79  typedef typename base_type::size_type size_type;
80  typedef typename base_type::value_type value_type;
81  typedef typename base_type::reference reference;
82  typedef typename base_type::iterator iterator;
83  typedef typename base_type::const_iterator const_iterator;
84  typedef aligned_buffer<nodeCount * sizeof(T), EASTL_ALIGN_OF(T)> aligned_buffer_type;
85 
86  enum { kMaxSize = nodeCount };
87 
88  using base_type::get_allocator;
89  using base_type::mpBegin;
90  using base_type::mpEnd;
91  using base_type::internalCapacityPtr;
92  using base_type::resize;
93  using base_type::clear;
94  using base_type::size;
95  using base_type::assign;
96  using base_type::npos;
97  using base_type::DoAllocate;
98  using base_type::DoFree;
99  using base_type::DoAssign;
100  using base_type::DoAssignFromIterator;
101 
102  protected:
103  aligned_buffer_type mBuffer;
104 
105  public:
106  fixed_vector();
107  explicit fixed_vector(const overflow_allocator_type& overflowAllocator); // Only applicable if bEnableOverflow is true.
108  explicit fixed_vector(size_type n); // Currently we don't support overflowAllocator specification for other constructors, for simplicity.
109  fixed_vector(size_type n, const value_type& value);
110  fixed_vector(const this_type& x);
111  fixed_vector(this_type&& x);
112  fixed_vector(this_type&& x, const overflow_allocator_type& overflowAllocator);
113  fixed_vector(std::initializer_list<T> ilist, const overflow_allocator_type& overflowAllocator = EASTL_FIXED_VECTOR_DEFAULT_ALLOCATOR);
114 
115  template <typename InputIterator>
116  fixed_vector(InputIterator first, InputIterator last);
117 
118  this_type& operator=(const this_type& x);
119  this_type& operator=(std::initializer_list<T> ilist);
120  this_type& operator=(this_type&& x);
121 
122  void swap(this_type& x);
123 
124  void set_capacity(size_type n);
125  void clear(bool freeOverflow);
126  void reset_lose_memory(); // This is a unilateral reset to an initially empty state. No destructors are called, no deallocation occurs.
127  size_type max_size() const; // Returns the max fixed size, which is the user-supplied nodeCount parameter.
128  bool full() const; // Returns true if the fixed space has been fully allocated. Note that if overflow is enabled, the container size can be greater than nodeCount but full() could return true because the fixed space may have a recently freed slot.
129  bool has_overflowed() const; // Returns true if the allocations spilled over into the overflow allocator. Meaningful only if overflow is enabled.
130  bool can_overflow() const; // Returns the value of the bEnableOverflow template parameter.
131 
132  void* push_back_uninitialized();
133  void push_back(const value_type& value); // We implement push_back here because we have a specialization that's
134  reference push_back(); // smaller for the case of overflow being disabled.
135  void push_back(value_type&& value);
136 
137  // OverflowAllocator
138  const overflow_allocator_type& get_overflow_allocator() const EA_NOEXCEPT;
139  overflow_allocator_type& get_overflow_allocator() EA_NOEXCEPT;
140  void set_overflow_allocator(const overflow_allocator_type& allocator);
141 
142  protected:
143  void* DoPushBackUninitialized(true_type);
144  void* DoPushBackUninitialized(false_type);
145 
146  void DoPushBack(true_type, const value_type& value);
147  void DoPushBack(false_type, const value_type& value);
148 
149  void DoPushBackMove(true_type, value_type&& value);
150  void DoPushBackMove(false_type, value_type&& value);
151 
152  reference DoPushBack(false_type);
153  reference DoPushBack(true_type);
154 
155  }; // fixed_vector
156 
157 
158 
159 
161  // fixed_vector
163 
164  template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
166  : base_type(fixed_allocator_type(mBuffer.buffer))
167  {
168  #if EASTL_NAME_ENABLED
169  get_allocator().set_name(EASTL_FIXED_VECTOR_DEFAULT_NAME);
170  #endif
171 
172  mpBegin = mpEnd = (value_type*)&mBuffer.buffer[0];
173  internalCapacityPtr() = mpBegin + nodeCount;
174  }
175 
176  template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
177  inline fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_vector(const overflow_allocator_type& overflowAllocator)
178  : base_type(fixed_allocator_type(mBuffer.buffer, overflowAllocator))
179  {
180  #if EASTL_NAME_ENABLED
181  get_allocator().set_name(EASTL_FIXED_VECTOR_DEFAULT_NAME);
182  #endif
183 
184  mpBegin = mpEnd = (value_type*)&mBuffer.buffer[0];
185  internalCapacityPtr() = mpBegin + nodeCount;
186  }
187 
188  template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
189  inline fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_vector(size_type n)
190  : base_type(fixed_allocator_type(mBuffer.buffer))
191  {
192  #if EASTL_NAME_ENABLED
193  get_allocator().set_name(EASTL_FIXED_VECTOR_DEFAULT_NAME);
194  #endif
195 
196  mpBegin = mpEnd = (value_type*)&mBuffer.buffer[0];
197  internalCapacityPtr() = mpBegin + nodeCount;
198  resize(n);
199  }
200 
201 
202  template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
203  inline fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_vector(size_type n, const value_type& value)
204  : base_type(fixed_allocator_type(mBuffer.buffer))
205  {
206  #if EASTL_NAME_ENABLED
207  get_allocator().set_name(EASTL_FIXED_VECTOR_DEFAULT_NAME);
208  #endif
209 
210  mpBegin = mpEnd = (value_type*)&mBuffer.buffer[0];
211  internalCapacityPtr() = mpBegin + nodeCount;
212  resize(n, value);
213  }
214 
215 
216  template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
217  inline fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_vector(const this_type& x)
218  : base_type(fixed_allocator_type(mBuffer.buffer))
219  {
220  get_allocator().copy_overflow_allocator(x.get_allocator());
221 
222  #if EASTL_NAME_ENABLED
223  get_allocator().set_name(x.get_allocator().get_name());
224  #endif
225 
226  mpBegin = mpEnd = (value_type*)&mBuffer.buffer[0];
227  internalCapacityPtr() = mpBegin + nodeCount;
228  base_type::template DoAssign<const_iterator, false>(x.begin(), x.end(), false_type());
229  }
230 
231 
232  template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
233  inline fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_vector(this_type&& x)
234  : base_type(fixed_allocator_type(mBuffer.buffer))
235  {
236  // Since we are a fixed_vector, we can't swap pointers. We can possibly so something like fixed_swap or
237  // we can just do an assignment from x. If we want to do the former then we need to have some complicated
238  // code to deal with overflow or no overflow, and whether the memory is in the fixed-size buffer or in
239  // the overflow allocator. 90% of the time the memory should be in the fixed buffer, in which case
240  // a simple assignment is no worse than the fancy pathway.
241 
242  // Since we are a fixed_list, we can't normally swap pointers unless both this and
243  // x are using using overflow and the overflow allocators are equal. To do:
244  //if(has_overflowed() && x.has_overflowed() && (get_overflow_allocator() == x.get_overflow_allocator()))
245  //{
246  // We can swap contents and may need to swap the allocators as well.
247  //}
248 
249  // The following is currently identical to the fixed_vector(const this_type& x) code above. If it stays that
250  // way then we may want to make a shared implementation.
251  get_allocator().copy_overflow_allocator(x.get_allocator());
252 
253  #if EASTL_NAME_ENABLED
254  get_allocator().set_name(x.get_allocator().get_name());
255  #endif
256 
257  mpBegin = mpEnd = (value_type*)&mBuffer.buffer[0];
258  internalCapacityPtr() = mpBegin + nodeCount;
259  base_type::template DoAssign<move_iterator<iterator>, true>(eastl::make_move_iterator(x.begin()), eastl::make_move_iterator(x.end()), false_type());
260  }
261 
262 
263  template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
264  inline fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_vector(this_type&& x, const overflow_allocator_type& overflowAllocator)
265  : base_type(fixed_allocator_type(mBuffer.buffer, overflowAllocator))
266  {
267  // See the discussion above.
268 
269  // The following is currently identical to the fixed_vector(const this_type& x) code above. If it stays that
270  // way then we may want to make a shared implementation.
271  get_allocator().copy_overflow_allocator(x.get_allocator());
272 
273  #if EASTL_NAME_ENABLED
274  get_allocator().set_name(x.get_allocator().get_name());
275  #endif
276 
277  mpBegin = mpEnd = (value_type*)&mBuffer.buffer[0];
278  internalCapacityPtr() = mpBegin + nodeCount;
279  base_type::template DoAssign<iterator, true>(x.begin(), x.end(), false_type());
280  }
281 
282 
283  template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
284  inline fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_vector(std::initializer_list<T> ilist, const overflow_allocator_type& overflowAllocator)
285  : base_type(fixed_allocator_type(mBuffer.buffer, overflowAllocator))
286  {
287  typedef typename std::initializer_list<value_type>::iterator InputIterator;
288  typedef typename eastl::iterator_traits<InputIterator>::iterator_category IC;
289 
290  mpBegin = mpEnd = (value_type*)&mBuffer.buffer[0];
291  internalCapacityPtr() = mpBegin + nodeCount;
292  base_type::template DoAssignFromIterator<InputIterator, false>(ilist.begin(), ilist.end(), IC());
293  }
294 
295 
296  template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
297  template <typename InputIterator>
298  fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_vector(InputIterator first, InputIterator last)
299  : base_type(fixed_allocator_type(mBuffer.buffer))
300  {
301  #if EASTL_NAME_ENABLED
302  get_allocator().set_name(EASTL_FIXED_VECTOR_DEFAULT_NAME);
303  #endif
304 
305  mpBegin = mpEnd = (value_type*)&mBuffer.buffer[0];
306  internalCapacityPtr() = mpBegin + nodeCount;
307  base_type::template DoAssign<InputIterator, false>(first, last, is_integral<InputIterator>());
308  }
309 
310 
311  template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
312  inline typename fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::this_type&
313  fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::operator=(const this_type& x)
314  {
315  if(this != &x)
316  {
317  clear();
318 
319  #if EASTL_ALLOCATOR_COPY_ENABLED
320  get_allocator() = x.get_allocator(); // The primary effect of this is to copy the overflow allocator.
321  #endif
322 
323  base_type::template DoAssign<const_iterator, false>(x.begin(), x.end(), false_type()); // Shorter route.
324  }
325  return *this;
326  }
327 
328 
329  template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
330  inline typename fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::this_type&
331  fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::operator=(std::initializer_list<T> ilist)
332  {
333  typedef typename std::initializer_list<value_type>::iterator InputIterator;
334  typedef typename eastl::iterator_traits<InputIterator>::iterator_category IC;
335 
336  clear();
337  base_type::template DoAssignFromIterator<InputIterator, false>(ilist.begin(), ilist.end(), IC());
338  return *this;
339  }
340 
341 
342  template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
343  inline typename fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::this_type&
344  fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::operator=(this_type&& x)
345  {
346  // Since we are a fixed_vector, we can't swap pointers. We can possibly do something like fixed_swap or
347  // we can just do an assignment from x. If we want to do the former then we need to have some complicated
348  // code to deal with overflow or no overflow, and whether the memory is in the fixed-size buffer or in
349  // the overflow allocator. 90% of the time the memory should be in the fixed buffer, in which case
350  // a simple assignment is no worse than the fancy pathway.
351  if (this != &x)
352  {
353  clear();
354 
355  #if EASTL_ALLOCATOR_COPY_ENABLED
356  get_allocator() = x.get_allocator(); // The primary effect of this is to copy the overflow allocator.
357  #endif
358 
359  base_type::template DoAssign<move_iterator<iterator>, true>(eastl::make_move_iterator(x.begin()), eastl::make_move_iterator(x.end()), false_type()); // Shorter route.
360  }
361  return *this;
362  }
363 
364 
365  template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
366  inline void fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::swap(this_type& x)
367  {
368  if((has_overflowed() && x.has_overflowed()) && (get_overflow_allocator() == x.get_overflow_allocator())) // If both containers are using the heap instead of local memory
369  { // then we can do a fast pointer swap instead of content swap.
370  eastl::swap(mpBegin, x.mpBegin);
371  eastl::swap(mpEnd, x.mpEnd);
372  eastl::swap(internalCapacityPtr(), x.internalCapacityPtr());
373  }
374  else
375  {
376  // Fixed containers use a special swap that can deal with excessively large buffers.
377  eastl::fixed_swap(*this, x);
378  }
379  }
380 
381 
382  template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
383  inline void fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::set_capacity(size_type n)
384  {
385  const size_type nPrevSize = (size_type)(mpEnd - mpBegin);
386  const size_type nPrevCapacity = (size_type)(internalCapacityPtr() - mpBegin);
387 
388  if(n == npos) // If the user means to set the capacity so that it equals the size (i.e. free excess capacity)...
389  n = nPrevSize;
390 
391  if(n != nPrevCapacity) // If the request results in a capacity change...
392  {
393  if(can_overflow() && (((uintptr_t)mpBegin != (uintptr_t)mBuffer.buffer) || (n > kMaxSize))) // If we are or would be using dynamically allocated memory instead of our fixed-size member buffer...
394  {
395  T* const pNewData = (n <= kMaxSize) ? (T*)&mBuffer.buffer[0] : DoAllocate(n);
396  T* const pCopyEnd = (n < nPrevSize) ? (mpBegin + n) : mpEnd;
397  eastl::uninitialized_move_ptr(mpBegin, pCopyEnd, pNewData); // Move [mpBegin, pCopyEnd) to p.
398  eastl::destruct(mpBegin, mpEnd);
399  if((uintptr_t)mpBegin != (uintptr_t)mBuffer.buffer)
400  DoFree(mpBegin, (size_type)(internalCapacityPtr() - mpBegin));
401 
402  mpEnd = pNewData + (pCopyEnd - mpBegin);
403  mpBegin = pNewData;
404  internalCapacityPtr() = mpBegin + n;
405  } // Else the new capacity would be within our fixed buffer.
406  else if(n < nPrevSize) // If the newly requested capacity is less than our size, we do what vector::set_capacity does and resize, even though we actually aren't reducing the capacity.
407  resize(n);
408  }
409  }
410 
411 
412  template <typename T, size_t nodeCount, bool bEnableOverflow, typename Allocator>
413  inline void fixed_vector<T, nodeCount, bEnableOverflow, Allocator>::clear(bool freeOverflow)
414  {
415  base_type::clear();
416  if (freeOverflow && mpBegin != (value_type*)&mBuffer.buffer[0])
417  {
418  EASTLFree(get_allocator(), mpBegin, (internalCapacityPtr() - mpBegin) * sizeof(T));
419  mpBegin = mpEnd = (value_type*)&mBuffer.buffer[0];
420  internalCapacityPtr() = mpBegin + nodeCount;
421  }
422  }
423 
424 
425  template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
426  inline void fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::reset_lose_memory()
427  {
428  mpBegin = mpEnd = (value_type*)&mBuffer.buffer[0];
429  internalCapacityPtr() = mpBegin + nodeCount;
430  }
431 
432 
433  template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
434  inline typename fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::size_type
435  fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::max_size() const
436  {
437  return kMaxSize;
438  }
439 
440 
441  template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
442  inline bool fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::full() const
443  {
444  // If size >= capacity, then we are definitely full.
445  // Also, if our size is smaller but we've switched away from mBuffer due to a previous overflow, then we are considered full.
446  return ((size_t)(mpEnd - mpBegin) >= kMaxSize) || ((void*)mpBegin != (void*)mBuffer.buffer);
447  }
448 
449 
450  template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
451  inline bool fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::has_overflowed() const
452  {
453  // This will be incorrect for the case that bOverflowEnabled is true and the container was resized
454  // down to a small size where the fixed buffer could take over ownership of the data again.
455  // The only simple fix for this is to take on another member variable which tracks whether this overflow
456  // has occurred at some point in the past.
457  return ((void*)mpBegin != (void*)mBuffer.buffer);
458  }
459 
460 
461  template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
462  inline bool fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::can_overflow() const
463  {
464  return bEnableOverflow;
465  }
466 
467 
468  template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
469  inline void* fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::push_back_uninitialized()
470  {
471  return DoPushBackUninitialized(typename type_select<bEnableOverflow, true_type, false_type>::type());
472  }
473 
474 
475  template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
476  inline void* fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::DoPushBackUninitialized(true_type)
477  {
478  return base_type::push_back_uninitialized();
479  }
480 
481 
482  template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
483  inline void* fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::DoPushBackUninitialized(false_type)
484  {
485  EASTL_ASSERT(mpEnd < internalCapacityPtr());
486 
487  return mpEnd++;
488  }
489 
490 
491  template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
492  inline void fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::push_back(const value_type& value)
493  {
494  DoPushBack(typename type_select<bEnableOverflow, true_type, false_type>::type(), value);
495  }
496 
497 
498  template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
499  inline void fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::DoPushBack(true_type, const value_type& value)
500  {
501  base_type::push_back(value);
502  }
503 
504 
505  // This template specializes for overflow NOT enabled.
506  // In this configuration, there is no need for the heavy weight push_back() which tests to see if the container should grow (it never will)
507  template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
508  inline void fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::DoPushBack(false_type, const value_type& value)
509  {
510  EASTL_ASSERT(mpEnd < internalCapacityPtr());
511 
512  ::new((void*)mpEnd++) value_type(value);
513  }
514 
515 
516  template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
517  inline typename fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::reference fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::push_back()
518  {
519  return DoPushBack(typename type_select<bEnableOverflow, true_type, false_type>::type());
520  }
521 
522 
523  template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
524  inline typename fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::reference fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::DoPushBack(true_type)
525  {
526  return base_type::push_back();
527  }
528 
529 
530  // This template specializes for overflow NOT enabled.
531  // In this configuration, there is no need for the heavy weight push_back() which tests to see if the container should grow (it never will)
532  template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
533  inline typename fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::reference fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::DoPushBack(false_type)
534  {
535  EASTL_ASSERT(mpEnd < internalCapacityPtr());
536 
537  ::new((void*)mpEnd++) value_type; // Note that this isn't value_type() as that syntax doesn't work on all compilers for POD types.
538 
539  return *(mpEnd - 1); // Same as return back();
540  }
541 
542 
543  template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
544  inline void fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::push_back(value_type&& value)
545  {
546  DoPushBackMove(typename type_select<bEnableOverflow, true_type, false_type>::type(), eastl::move(value));
547  }
548 
549 
550  template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
551  inline void fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::DoPushBackMove(true_type, value_type&& value)
552  {
553  base_type::push_back(eastl::move(value)); // This will call vector::push_back(value_type &&), and possibly swap value with *mpEnd.
554  }
555 
556 
557  // This template specializes for overflow NOT enabled.
558  // In this configuration, there is no need for the heavy weight push_back() which tests to see if the container should grow (it never will)
559  template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
560  inline void fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::DoPushBackMove(false_type, value_type&& value)
561  {
562  EASTL_ASSERT(mpEnd < internalCapacityPtr());
563 
564  ::new((void*)mpEnd++) value_type(eastl::move(value)); // This will call the value_type(value_type&&) constructor, and possibly swap value with *mpEnd.
565  }
566 
567 
568  template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
569  inline const typename fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::overflow_allocator_type&
570  fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::get_overflow_allocator() const EA_NOEXCEPT
571  {
572  return get_allocator().get_overflow_allocator();
573  }
574 
575 
576  template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
577  inline typename fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::overflow_allocator_type&
578  fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::get_overflow_allocator() EA_NOEXCEPT
579  {
580  return get_allocator().get_overflow_allocator();
581  }
582 
583 
584  template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
585  inline void
586  fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::set_overflow_allocator(const overflow_allocator_type& allocator)
587  {
588  get_allocator().set_overflow_allocator(allocator);
589  }
590 
591 
592 
594  // global operators
596 
597  // operator ==, !=, <, >, <=, >= come from the vector implementations.
598 
599  template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
600  inline void swap(fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>& a,
601  fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>& b)
602  {
603  // Fixed containers use a special swap that can deal with excessively large buffers.
604  eastl::fixed_swap(a, b);
605  }
606 
607 
608 
609 } // namespace eastl
610 
611 
612 
613 #endif // Header include guard
614 
615 
616 
617 
618 
619 
620 
621 
622 
623 
624 
625 
Definition: allocator.h:52
Definition: fixed_pool.h:1329
Definition: fixed_vector.h:72
Definition: vector.h:178
T * mpBegin
-1 is reserved for 'npos'. It also happens to be slightly beneficial that kMaxSize is a value less th...
Definition: vector.h:142
Definition: initializer_list.h:38
EA Standard Template Library.
Definition: algorithm.h:288
OutputIterator move(InputIterator first, InputIterator last, OutputIterator result)
Definition: copy_help.h:170
void destruct(T *p)
Definition: memory.h:1324
Definition: fixed_pool.h:82
Definition: type_traits.h:263