Nugget
fixed_string.h
1 // Copyright (c) Electronic Arts Inc. All rights reserved.
4 
6 // This file implements a string 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_STRING_H
13 #define EASTL_FIXED_STRING_H
14 
15 #include <EASTL/internal/config.h>
16 #include <EASTL/string.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 namespace eastl
25 {
32  #ifndef EASTL_FIXED_STRING_DEFAULT_NAME
33  #define EASTL_FIXED_STRING_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " fixed_string" // Unless the user overrides something, this is "EASTL fixed_string".
34  #endif
35 
36 
37 
73  template <typename T, int nodeCount, bool bEnableOverflow = true, typename OverflowAllocator = EASTLAllocatorType>
74  class fixed_string : public basic_string<T, fixed_vector_allocator<sizeof(T), nodeCount, EASTL_ALIGN_OF(T), 0, bEnableOverflow, OverflowAllocator> >
75  {
76  public:
77  typedef fixed_vector_allocator<sizeof(T), nodeCount, EASTL_ALIGN_OF(T),
78  0, bEnableOverflow, OverflowAllocator> fixed_allocator_type;
79  typedef typename fixed_allocator_type::overflow_allocator_type overflow_allocator_type;
82  typedef typename base_type::size_type size_type;
83  typedef typename base_type::value_type value_type;
85  typedef typename base_type::CtorSprintf CtorSprintf;
86  typedef aligned_buffer<nodeCount * sizeof(T), EASTL_ALIGN_OF(T)> aligned_buffer_type;
87 
88  enum { kMaxSize = nodeCount - 1 }; // -1 because we need to save one element for the silent terminating null.
89 
90  using base_type::npos;
91  using base_type::mPair;
92  using base_type::append;
93  using base_type::resize;
94  using base_type::clear;
95  using base_type::capacity;
96  using base_type::size;
97  using base_type::sprintf_va_list;
98  using base_type::DoAllocate;
99  using base_type::DoFree;
100  using base_type::internalLayout;
101  using base_type::get_allocator;
102 
103  protected:
104  union // We define a union in order to avoid strict pointer aliasing issues with compilers like GCC.
105  {
106  value_type mArray[1];
107  aligned_buffer_type mBuffer; // Question: Why are we doing this aligned_buffer thing? Why not just do an array of value_type, given that we are using just strings of char types.
108  };
109 
110  public:
111  fixed_string();
112  explicit fixed_string(const overflow_allocator_type& overflowAllocator); // Only applicable if bEnableOverflow is true.
113  fixed_string(const base_type& x, size_type position, size_type n = base_type::npos); // Currently we don't support overflowAllocator specification for other constructors, for simplicity.
114  fixed_string(const value_type* p, size_type n);
115  fixed_string(const value_type* p);
116  fixed_string(size_type n, const value_type& value);
117  fixed_string(const this_type& x);
118  fixed_string(const this_type& x, const overflow_allocator_type& overflowAllocator);
119  fixed_string(const base_type& x);
120  fixed_string(const value_type* pBegin, const value_type* pEnd);
121  fixed_string(CtorDoNotInitialize, size_type n);
122  fixed_string(CtorSprintf, const value_type* pFormat, ...);
123  fixed_string(std::initializer_list<T> ilist, const overflow_allocator_type& overflowAllocator);
124  fixed_string(this_type&& x);
125  fixed_string(this_type&& x, const overflow_allocator_type& overflowAllocator);
126 
127  this_type& operator=(const this_type& x);
128  this_type& operator=(const base_type& x);
129  this_type& operator=(const value_type* p);
130  this_type& operator=(const value_type c);
131  this_type& operator=(std::initializer_list<T> ilist);
132  this_type& operator=(this_type&& x);
133 
134  void swap(this_type& x);
135 
136  void set_capacity(size_type n);
137  void reset_lose_memory(); // This is a unilateral reset to an initially empty state. No destructors are called, no deallocation occurs.
138  size_type max_size() const;
139  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.
140  bool has_overflowed() const; // Returns true if the allocations spilled over into the overflow allocator. Meaningful only if overflow is enabled.
141  bool can_overflow() const; // Returns the value of the bEnableOverflow template parameter.
142 
143  // The inherited versions of substr/left/right call the basic_string constructor,
144  // which will call the overflow allocator and fail if bEnableOverflow == false
145  this_type substr(size_type position, size_type n) const;
146  this_type left(size_type n) const;
147  this_type right(size_type n) const;
148 
149  // OverflowAllocator
150  const overflow_allocator_type& get_overflow_allocator() const EA_NOEXCEPT;
151  overflow_allocator_type& get_overflow_allocator() EA_NOEXCEPT;
152  void set_overflow_allocator(const overflow_allocator_type& allocator);
153  }; // fixed_string
154 
155 
156 
157 
158 
160  // fixed_string
162 
163  template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
165  : base_type(fixed_allocator_type(mBuffer.buffer))
166  {
167  #if EASTL_NAME_ENABLED
168  get_allocator().set_name(EASTL_FIXED_STRING_DEFAULT_NAME);
169  #endif
170 
171  internalLayout().SetHeapBeginPtr(mArray);
172  internalLayout().SetHeapCapacity(nodeCount - 1);
173  internalLayout().SetHeapSize(0);
174 
175  *internalLayout().HeapBeginPtr() = 0;
176  }
177 
178 
179  template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
180  inline fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_string(const overflow_allocator_type& overflowAllocator)
181  : base_type(fixed_allocator_type(mBuffer.buffer, overflowAllocator))
182  {
183  #if EASTL_NAME_ENABLED
184  get_allocator().set_name(EASTL_FIXED_STRING_DEFAULT_NAME);
185  #endif
186 
187  internalLayout().SetHeapBeginPtr(mArray);
188  internalLayout().SetHeapCapacity(nodeCount - 1);
189  internalLayout().SetHeapSize(0);
190 
191  *internalLayout().HeapBeginPtr() = 0;
192  }
193 
194 
195  template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
196  inline fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_string(const this_type& x)
197  : base_type(fixed_allocator_type(mBuffer.buffer))
198  {
199  get_allocator().copy_overflow_allocator(x.get_allocator());
200 
201  #if EASTL_NAME_ENABLED
202  get_allocator().set_name(x.get_allocator().get_name());
203  #endif
204 
205  internalLayout().SetHeapBeginPtr(mArray);
206  internalLayout().SetHeapCapacity(nodeCount - 1);
207  internalLayout().SetHeapSize(0);
208 
209  *internalLayout().HeapBeginPtr() = 0;
210 
211  append(x);
212  }
213 
214 
215  template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
216  inline fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_string(const this_type& x, const overflow_allocator_type& overflowAllocator)
217  : base_type(fixed_allocator_type(mBuffer.buffer, overflowAllocator))
218  {
219  get_allocator().copy_overflow_allocator(x.get_allocator());
220 
221  #if EASTL_NAME_ENABLED
222  get_allocator().set_name(x.get_allocator().get_name());
223  #endif
224 
225  internalLayout().SetHeapBeginPtr(mArray);
226  internalLayout().SetHeapCapacity(nodeCount - 1);
227  internalLayout().SetHeapSize(0);
228 
229  *internalLayout().HeapBeginPtr() = 0;
230 
231  append(x);
232  }
233 
234 
235  template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
236  inline fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_string(const base_type& x)
237  : base_type(fixed_allocator_type(mBuffer.buffer))
238  {
239  #if EASTL_NAME_ENABLED
240  get_allocator().set_name(x.get_allocator().get_name());
241  #endif
242 
243  internalLayout().SetHeapBeginPtr(mArray);
244  internalLayout().SetHeapCapacity(nodeCount - 1);
245  internalLayout().SetHeapSize(0);
246 
247  *internalLayout().HeapBeginPtr() = 0;
248 
249  append(x);
250  }
251 
252 
253  template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
254  inline fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_string(const base_type& x, size_type position, size_type n)
255  : base_type(fixed_allocator_type(mBuffer.buffer))
256  {
257  #if EASTL_NAME_ENABLED
258  get_allocator().set_name(x.get_allocator().get_name());
259  #endif
260 
261  internalLayout().SetHeapBeginPtr(mArray);
262  internalLayout().SetHeapCapacity(nodeCount - 1);
263  internalLayout().SetHeapSize(0);
264 
265  *internalLayout().HeapBeginPtr() = 0;
266 
267  append(x, position, n);
268  }
269 
270 
271  template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
272  inline fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_string(const value_type* p, size_type n)
273  : base_type(fixed_allocator_type(mBuffer.buffer))
274  {
275  #if EASTL_NAME_ENABLED
276  get_allocator().set_name(EASTL_FIXED_STRING_DEFAULT_NAME);
277  #endif
278 
279  internalLayout().SetHeapBeginPtr(mArray);
280  internalLayout().SetHeapCapacity(nodeCount - 1);
281  internalLayout().SetHeapSize(0);
282 
283  *internalLayout().HeapBeginPtr() = 0;
284 
285  append(p, n);
286  }
287 
288 
289  template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
290  inline fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_string(const value_type* p)
291  : base_type(fixed_allocator_type(mBuffer.buffer))
292  {
293  #if EASTL_NAME_ENABLED
294  get_allocator().set_name(EASTL_FIXED_STRING_DEFAULT_NAME);
295  #endif
296 
297  internalLayout().SetHeapBeginPtr(mArray);
298  internalLayout().SetHeapCapacity(nodeCount - 1);
299  internalLayout().SetHeapSize(0);
300 
301  *internalLayout().HeapBeginPtr() = 0;
302 
303  append(p); // There better be enough space to hold the assigned string.
304  }
305 
306 
307  template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
308  inline fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_string(size_type n, const value_type& value)
309  : base_type(fixed_allocator_type(mBuffer.buffer))
310  {
311  #if EASTL_NAME_ENABLED
312  get_allocator().set_name(EASTL_FIXED_STRING_DEFAULT_NAME);
313  #endif
314 
315  internalLayout().SetHeapBeginPtr(mArray);
316  internalLayout().SetHeapCapacity(nodeCount - 1);
317  internalLayout().SetHeapSize(0);
318 
319  *internalLayout().HeapBeginPtr() = 0;
320 
321  append(n, value); // There better be enough space to hold the assigned string.
322  }
323 
324 
325  template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
326  inline fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_string(const value_type* pBegin, const value_type* pEnd)
327  : base_type(fixed_allocator_type(mBuffer.buffer))
328  {
329  #if EASTL_NAME_ENABLED
330  get_allocator().set_name(EASTL_FIXED_STRING_DEFAULT_NAME);
331  #endif
332 
333  internalLayout().SetHeapBeginPtr(mArray);
334  internalLayout().SetHeapCapacity(nodeCount - 1);
335  internalLayout().SetHeapSize(0);
336 
337  *internalLayout().HeapBeginPtr() = 0;
338 
339  append(pBegin, pEnd);
340  }
341 
342 
343  template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
344  inline fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_string(CtorDoNotInitialize, size_type n)
345  : base_type(fixed_allocator_type(mBuffer.buffer))
346  {
347  #if EASTL_NAME_ENABLED
348  get_allocator().set_name(EASTL_FIXED_STRING_DEFAULT_NAME);
349  #endif
350 
351  internalLayout().SetHeapBeginPtr(mArray);
352  internalLayout().SetHeapCapacity(nodeCount - 1);
353 
354  if(n < nodeCount)
355  {
356  internalLayout().SetHeapSize(n);
357  *internalLayout().HeapEndPtr() = 0;
358  }
359  else
360  {
361  internalLayout().SetHeapSize(0);
362  *internalLayout().HeapEndPtr() = 0;
363 
364  resize(n);
365  }
366  }
367 
368 
369  template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
370  inline fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_string(CtorSprintf, const value_type* pFormat, ...)
371  : base_type(fixed_allocator_type(mBuffer.buffer))
372  {
373  #if EASTL_NAME_ENABLED
374  get_allocator().set_name(EASTL_FIXED_STRING_DEFAULT_NAME);
375  #endif
376 
377  internalLayout().SetHeapBeginPtr(mArray);
378  internalLayout().SetHeapCapacity(nodeCount - 1);
379  internalLayout().SetHeapSize(0);
380  *internalLayout().HeapBeginPtr() = 0;
381 
382  va_list arguments;
383  va_start(arguments, pFormat);
384  sprintf_va_list(pFormat, arguments);
385  va_end(arguments);
386  }
387 
388 
389  template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
390  inline fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_string(std::initializer_list<T> ilist, const overflow_allocator_type& overflowAllocator)
391  : base_type(fixed_allocator_type(mBuffer.buffer, overflowAllocator))
392  {
393  #if EASTL_NAME_ENABLED
394  get_allocator().set_name(EASTL_FIXED_STRING_DEFAULT_NAME);
395  #endif
396 
397  internalLayout().SetHeapBeginPtr(mArray);
398  internalLayout().SetHeapCapacity(nodeCount - 1);
399  internalLayout().SetHeapSize(0);
400 
401  *internalLayout().HeapBeginPtr() = 0;
402 
403  append(ilist.begin(), ilist.end());
404  }
405 
406 
407  template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
408  inline fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_string(this_type&& x)
409  : base_type(fixed_allocator_type(mBuffer.buffer))
410  {
411  // We copy from x instead of trade with it. We need to do so because fixed_ containers use local memory buffers.
412  #if EASTL_NAME_ENABLED
413  get_allocator().set_name(x.get_allocator().get_name());
414  #endif
415 
416  internalLayout().SetHeapBeginPtr(mArray);
417  internalLayout().SetHeapCapacity(nodeCount - 1);
418  internalLayout().SetHeapSize(0);
419 
420  *internalLayout().HeapBeginPtr() = 0;
421 
422  append(x); // Let x destruct its own items.
423  }
424 
425  template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
426  inline fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_string(this_type&& x, const overflow_allocator_type& overflowAllocator)
427  : base_type(fixed_allocator_type(mBuffer.buffer, overflowAllocator))
428  {
429  // We copy from x instead of trade with it. We need to do so because fixed_ containers use local memory buffers.
430  #if EASTL_NAME_ENABLED
431  get_allocator().set_name(x.get_allocator().get_name());
432  #endif
433 
434  internalLayout().SetHeapBeginPtr(mArray);
435  internalLayout().SetHeapCapacity(nodeCount - 1);
436  internalLayout().SetHeapSize(0);
437 
438  *internalLayout().HeapBeginPtr() = 0;
439 
440  append(x); // Let x destruct its own items.
441  }
442 
443 
444  template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
445  inline typename fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::this_type&
446  fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::operator=(const this_type& x)
447  {
448  if(this != &x)
449  {
450  clear();
451 
452  #if EASTL_ALLOCATOR_COPY_ENABLED
453  get_allocator() = x.get_allocator();
454  #endif
455 
456  append(x);
457  }
458  return *this;
459  }
460 
461 
462  template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
463  inline typename fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::
464  this_type& fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::operator=(const base_type& x)
465  {
466  if(static_cast<base_type*>(this) != &x)
467  {
468  clear();
469 
470  #if EASTL_ALLOCATOR_COPY_ENABLED
471  get_allocator() = x.get_allocator();
472  #endif
473 
474  append(x);
475  }
476  return *this;
477  }
478 
479 
480  template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
481  inline typename fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::
482  this_type& fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::operator=(const value_type* p)
483  {
484  if(internalLayout().HeapBeginPtr() != p)
485  {
486  clear();
487  append(p);
488  }
489  return *this;
490  }
491 
492 
493  template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
494  inline typename fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::
495  this_type& fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::operator=(const value_type c)
496  {
497  clear();
498  append((size_type)1, c);
499  return *this;
500  }
501 
502 
503  template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
504  inline typename fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::
505  this_type& fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::operator=(std::initializer_list<T> ilist)
506  {
507  clear();
508  append(ilist.begin(), ilist.end());
509  return *this;
510  }
511 
512 
513  template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
514  inline typename fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::
515  this_type& fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::operator=(this_type&& x)
516  {
517  // We copy from x instead of trade with it. We need to do so because fixed_ containers use local memory buffers.
518 
519  // if(static_cast<base_type*>(this) != &x) This should be impossible, so we disable it until proven otherwise.
520  {
521  clear();
522 
523  #if EASTL_ALLOCATOR_COPY_ENABLED
524  get_allocator() = x.get_allocator();
525  #endif
526 
527  append(x); // Let x destruct its own items.
528  }
529  return *this;
530  }
531 
532 
533  template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
534  inline void fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::swap(this_type& x)
535  {
536  // Fixed containers use a special swap that can deal with excessively large buffers.
537  eastl::fixed_swap(*this, x);
538  }
539 
540 
541  template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
542  inline void fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::set_capacity(size_type n)
543  {
544  const size_type nPrevSize = internalLayout().GetSize();
545  const size_type nPrevCapacity = capacity();
546 
547  if(n == npos) // If the user means to set the capacity so that it equals the size (i.e. free excess capacity)...
548  n = nPrevSize;
549 
550  if(n != nPrevCapacity) // If the request results in a capacity change...
551  {
552  const size_type allocSize = (n + 1); // +1 because the terminating 0 isn't included in the supplied capacity value. So now n refers the amount of memory we need.
553 
554  if(can_overflow() && (((uintptr_t)internalLayout().HeapBeginPtr() != (uintptr_t)mBuffer.buffer) || (allocSize > kMaxSize))) // If we are or would be using dynamically allocated memory instead of our fixed-size member buffer...
555  {
556  T* const pNewData = (allocSize <= kMaxSize) ? (T*)&mBuffer.buffer[0] : DoAllocate(allocSize);
557  T* const pCopyEnd = (n < nPrevSize) ? (internalLayout().HeapBeginPtr() + n) : internalLayout().HeapEndPtr();
558  CharStringUninitializedCopy(internalLayout().HeapBeginPtr(), pCopyEnd, pNewData); // Copy [internalLayout().heap.mpBegin, pCopyEnd) to pNewData.
559  if((uintptr_t)internalLayout().HeapBeginPtr() != (uintptr_t)mBuffer.buffer)
560  DoFree(internalLayout().HeapBeginPtr(), internalLayout().GetHeapCapacity() + 1);
561 
562  internalLayout().SetHeapSize((size_type)(pCopyEnd - internalLayout().HeapBeginPtr()));
563  internalLayout().SetHeapBeginPtr(pNewData);
564  internalLayout().SetHeapCapacity(allocSize - 1);
565  } // Else the new capacity would be within our fixed buffer.
566  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.
567  resize(n);
568  }
569  }
570 
571 
572  template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
573  inline void fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::reset_lose_memory()
574  {
575  internalLayout().SetHeapBeginPtr(mArray);
576  internalLayout().SetHeapSize(0);
577  internalLayout().SetHeapCapacity(nodeCount - 1);
578  }
579 
580 
581  template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
582  inline typename fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::
583  size_type fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::max_size() const
584  {
585  return kMaxSize;
586  }
587 
588 
589  template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
590  inline bool fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::full() const
591  {
592  // If size >= capacity, then we are definitely full.
593  // Also, if our size is smaller but we've switched away from mBuffer due to a previous overflow, then we are considered full.
594  return ((size_t)(internalLayout().HeapEndPtr() - internalLayout().HeapBeginPtr()) >= kMaxSize) || ((void*)internalLayout().HeapBeginPtr() != (void*)mBuffer.buffer);
595  }
596 
597 
598  template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
599  inline bool fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::has_overflowed() const
600  {
601  // This will be incorrect for the case that bOverflowEnabled is true and the container was resized
602  // down to a small size where the fixed buffer could take over ownership of the data again.
603  // The only simple fix for this is to take on another member variable which tracks whether this overflow
604  // has occurred at some point in the past.
605  return ((void*)internalLayout().HeapBeginPtr() != (void*)mBuffer.buffer);
606  }
607 
608 
609  template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
610  inline bool fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::can_overflow() const
611  {
612  return bEnableOverflow;
613  }
614 
615 
616  template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
617  inline typename fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::
618  this_type fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::substr(size_type position, size_type n) const
619  {
620  #if EASTL_STRING_OPT_RANGE_ERRORS
621  if(position > internalLayout().GetSize())
622  base_type::ThrowRangeException();
623  #endif
624 
625  return fixed_string(internalLayout().HeapBeginPtr() + position,
626  internalLayout().HeapBeginPtr() + position + eastl::min_alt(n, internalLayout().GetSize() - position));
627  }
628 
629 
630  template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
631  inline typename fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::
632  this_type fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::left(size_type n) const
633  {
634  const size_type nLength = size();
635  if(n < nLength)
636  return fixed_string(internalLayout().HeapBeginPtr(), internalLayout().HeapBeginPtr() + n);
637  return *this;
638  }
639 
640 
641  template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
642  inline typename fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::
643  this_type fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::right(size_type n) const
644  {
645  const size_type nLength = size();
646  if(n < nLength)
647  return fixed_string(internalLayout().HeapEndPtr() - n, internalLayout().HeapEndPtr());
648  return *this;
649  }
650 
651 
652  template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
653  inline const typename fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::
654  overflow_allocator_type& fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::get_overflow_allocator() const EA_NOEXCEPT
655  {
656  return get_allocator().get_overflow_allocator();
657  }
658 
659 
660  template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
661  inline typename fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::
662  overflow_allocator_type& fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::get_overflow_allocator() EA_NOEXCEPT
663  {
664  return get_allocator().get_overflow_allocator();
665  }
666 
667 
668  template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
669  inline void
670  fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::set_overflow_allocator(const overflow_allocator_type& allocator)
671  {
672  get_allocator().set_overflow_allocator(allocator);
673  }
674 
675 
677  // global operators
679 
680 
681  // Operator +
682  template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
683  fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator> operator+(const fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>& a,
684  const fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>& b)
685  {
686  // We have a problem here because need to return an fixed_string by value. This will typically result in it
687  // using stack space equal to its size. That size may be too large to be workable.
688  typedef fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator> this_type;
689 
690  this_type result(const_cast<this_type&>(a).get_overflow_allocator());
691  result.append(a);
692  result.append(b);
693  return result;
694  }
695 
696 
697  template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
698  fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator> operator+(const typename fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::value_type* p,
699  const fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>& b)
700  {
701  typedef fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator> this_type;
702 
703  const typename this_type::size_type n = (typename this_type::size_type)CharStrlen(p);
704  this_type result(const_cast<this_type&>(b).get_overflow_allocator());
705  result.append(p, p + n);
706  result.append(b);
707  return result;
708  }
709 
710 
711  template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
712  fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator> operator+(typename fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::value_type c,
713  const fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>& b)
714  {
715  typedef fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator> this_type;
716 
717  this_type result(const_cast<this_type&>(b).get_overflow_allocator());
718  result.push_back(c);
719  result.append(b);
720  return result;
721  }
722 
723 
724  template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
725  fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator> operator+(const fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>& a,
726  const typename fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::value_type* p)
727  {
728  typedef fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator> this_type;
729 
730  const typename this_type::size_type n = (typename this_type::size_type)CharStrlen(p);
731  this_type result(const_cast<this_type&>(a).get_overflow_allocator());
732  result.append(a);
733  result.append(p, p + n);
734  return result;
735  }
736 
737 
738  template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
739  fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator> operator+(const fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>& a,
740  typename fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::value_type c)
741  {
742  typedef fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator> this_type;
743 
744  this_type result(const_cast<this_type&>(a).get_overflow_allocator());
745  result.append(a);
746  result.push_back(c);
747  return result;
748  }
749 
750 
751  template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
752  fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator> operator+(fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>&& a,
753  fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>&& b)
754  {
755  a.append(b); // Using an rvalue by name results in it becoming an lvalue.
756  return eastl::move(a);
757  }
758 
759  template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
760  fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator> operator+(fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>&& a,
761  const fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>& b)
762  {
763  a.append(b);
764  return eastl::move(a);
765  }
766 
767  template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
768  fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator> operator+(const typename fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::value_type* p,
769  fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>&& b)
770  {
771  b.insert(0, p);
772  return eastl::move(b);
773  }
774 
775  template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
776  fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator> operator+(fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>&& a,
777  const typename fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::value_type* p)
778  {
779  a.append(p);
780  return eastl::move(a);
781  }
782 
783  template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
784  fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator> operator+(fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>&& a,
785  typename fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::value_type c)
786  {
787  a.push_back(c);
788  return eastl::move(a);
789  }
790 
791 
792  // operator ==, !=, <, >, <=, >= come from the string implementations.
793 
794  template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
795  inline void swap(fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>& a,
796  fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>& b)
797  {
798  // Fixed containers use a special swap that can deal with excessively large buffers.
799  eastl::fixed_swap(a, b);
800  }
801 
802 
803 } // namespace eastl
804 
805 #endif // Header include guard
Definition: allocator.h:52
Definition: string.h:280
Definition: fixed_string.h:75
Definition: fixed_pool.h:1329
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
EA_CONSTEXPR eastl::enable_if< eastl::is_scalar< T >::value, T >::type min_alt(T a, T b)
Definition: algorithm.h:472
Definition: fixed_pool.h:82
'npos' means non-valid position or simply non-position.
Definition: string.h:302
Definition: string.h:310