Nugget
fixed_slist.h
1 // Copyright (c) Electronic Arts Inc. All rights reserved.
4 
6 // This file implements an slist which uses a fixed size memory pool for its nodes.
8 
9 
10 #ifndef EASTL_FIXED_SLIST_H
11 #define EASTL_FIXED_SLIST_H
12 
13 
14 #include <EASTL/slist.h>
15 #include <EASTL/internal/fixed_pool.h>
16 
17 #if defined(EA_PRAGMA_ONCE_SUPPORTED)
18  #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.
19 #endif
20 
21 
22 
23 namespace eastl
24 {
31  #ifndef EASTL_FIXED_SLIST_DEFAULT_NAME
32  #define EASTL_FIXED_SLIST_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " fixed_slist" // Unless the user overrides something, this is "EASTL fixed_slist".
33  #endif
34 
35 
38  #ifndef EASTL_FIXED_SLIST_DEFAULT_ALLOCATOR
39  #define EASTL_FIXED_SLIST_DEFAULT_ALLOCATOR overflow_allocator_type(EASTL_FIXED_SLIST_DEFAULT_NAME)
40  #endif
41 
42 
43 
65  template <typename T, size_t nodeCount, bool bEnableOverflow = true, typename OverflowAllocator = EASTLAllocatorType>
66  class fixed_slist : public slist<T, fixed_node_allocator<sizeof(typename slist<T>::node_type),
67  nodeCount, EASTL_ALIGN_OF(typename slist<T>::node_type), 0, bEnableOverflow, OverflowAllocator> >
68  {
69  public:
70  typedef fixed_node_allocator<sizeof(typename slist<T>::node_type), nodeCount,
71  EASTL_ALIGN_OF(typename slist<T>::node_type), 0, bEnableOverflow, OverflowAllocator> fixed_allocator_type;
72  typedef OverflowAllocator overflow_allocator_type;
75  typedef typename base_type::size_type size_type;
76  typedef typename base_type::value_type value_type;
77  typedef typename base_type::node_type node_type;
78 
79  enum { kMaxSize = nodeCount };
80 
81  using base_type::assign;
82  using base_type::resize;
83  using base_type::size;
84 
85  protected:
86  char mBuffer[fixed_allocator_type::kBufferSize]; // kBufferSize will take into account alignment requirements.
87 
88  using base_type::internalAllocator;
89 
90  public:
91  fixed_slist();
92  explicit fixed_slist(const overflow_allocator_type& overflowAllocator); // Only applicable if bEnableOverflow is true.
93  explicit fixed_slist(size_type n); // Currently we don't support overflowAllocator specification for other constructors, for simplicity.
94  fixed_slist(size_type n, const value_type& value);
95  fixed_slist(const this_type& x);
97  fixed_slist(this_type&&, const overflow_allocator_type&);
98  fixed_slist(std::initializer_list<value_type> ilist, const overflow_allocator_type& overflowAllocator = EASTL_FIXED_SLIST_DEFAULT_ALLOCATOR);
99 
100  template <typename InputIterator>
101  fixed_slist(InputIterator first, InputIterator last);
102 
103  this_type& operator=(const this_type& x);
105  this_type& operator=(this_type&& x);
106 
107  void swap(this_type& x);
108  void reset_lose_memory(); // This is a unilateral reset to an initially empty state. No destructors are called, no deallocation occurs.
109  size_type max_size() const; // Returns the max fixed size, which is the user-supplied nodeCount parameter.
110  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.
111  bool has_overflowed() const; // Returns true if the allocations spilled over into the overflow allocator. Meaningful only if overflow is enabled.
112  bool can_overflow() const; // Returns the value of the bEnableOverflow template parameter.
113 
114  // OverflowAllocator
115  const overflow_allocator_type& get_overflow_allocator() const EA_NOEXCEPT;
116  overflow_allocator_type& get_overflow_allocator() EA_NOEXCEPT;
117  void set_overflow_allocator(const overflow_allocator_type& allocator);
118  }; // fixed_slist
119 
120 
121 
122 
124  // slist
126 
127  template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
129  : base_type(fixed_allocator_type(mBuffer))
130  {
131  #if EASTL_NAME_ENABLED
132  internalAllocator().set_name(EASTL_FIXED_SLIST_DEFAULT_NAME);
133  #endif
134  }
135 
136 
137  template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
138  inline fixed_slist<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_slist(const overflow_allocator_type& overflowAllocator)
139  : base_type(fixed_allocator_type(mBuffer, overflowAllocator))
140  {
141  #if EASTL_NAME_ENABLED
142  internalAllocator().set_name(EASTL_FIXED_SLIST_DEFAULT_NAME);
143  #endif
144  }
145 
146 
147  template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
148  inline fixed_slist<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_slist(size_type n)
149  : base_type(fixed_allocator_type(mBuffer))
150  {
151  #if EASTL_NAME_ENABLED
152  internalAllocator().set_name(EASTL_FIXED_SLIST_DEFAULT_NAME);
153  #endif
154 
155  resize(n);
156  }
157 
158 
159  template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
160  inline fixed_slist<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_slist(size_type n, const value_type& value)
161  : base_type(fixed_allocator_type(mBuffer))
162  {
163  #if EASTL_NAME_ENABLED
164  internalAllocator().set_name(EASTL_FIXED_SLIST_DEFAULT_NAME);
165  #endif
166 
167  resize(n, value);
168  }
169 
170 
171  template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
172  inline fixed_slist<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_slist(const this_type& x)
173  : base_type(fixed_allocator_type(mBuffer))
174  {
175  internalAllocator().copy_overflow_allocator(x.internalAllocator());
176 
177  #if EASTL_NAME_ENABLED
178  internalAllocator().set_name(x.internalAllocator().get_name());
179  #endif
180 
181  assign(x.begin(), x.end());
182  }
183 
184 
185  template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
186  inline fixed_slist<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_slist(this_type&& x)
187  : base_type(fixed_allocator_type(mBuffer))
188  {
189  // Since we are a fixed_list, we can't normally swap pointers unless both this and
190  // x are using using overflow and the overflow allocators are equal. To do:
191  //if(has_overflowed() && x.has_overflowed() && (get_overflow_allocator() == x.get_overflow_allocator()))
192  //{
193  // We can swap contents and may need to swap the allocators as well.
194  //}
195 
196  // The following is currently identical to the fixed_vector(const this_type& x) code above. If it stays that
197  // way then we may want to make a shared implementation.
198  internalAllocator().copy_overflow_allocator(x.internalAllocator());
199 
200  #if EASTL_NAME_ENABLED
201  internalAllocator().set_name(x.internalAllocator().get_name());
202  #endif
203 
204  assign(x.begin(), x.end());
205  }
206 
207  template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
208  inline fixed_slist<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_slist(this_type&& x, const overflow_allocator_type& overflowAllocator)
209  : base_type(fixed_allocator_type(mBuffer, overflowAllocator))
210  {
211  // See comments above.
212  internalAllocator().copy_overflow_allocator(x.internalAllocator());
213 
214  #if EASTL_NAME_ENABLED
215  internalAllocator().set_name(x.internalAllocator().get_name());
216  #endif
217 
218  assign(x.begin(), x.end());
219  }
220 
221 
222  template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
223  inline fixed_slist<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_slist(std::initializer_list<value_type> ilist, const overflow_allocator_type& overflowAllocator)
224  : base_type(fixed_allocator_type(mBuffer, overflowAllocator))
225  {
226  #if EASTL_NAME_ENABLED
227  internalAllocator().set_name(EASTL_FIXED_SLIST_DEFAULT_NAME);
228  #endif
229 
230  assign(ilist.begin(), ilist.end());
231  }
232 
233 
234  template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
235  template <typename InputIterator>
236  fixed_slist<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_slist(InputIterator first, InputIterator last)
237  : base_type(fixed_allocator_type(mBuffer))
238  {
239  #if EASTL_NAME_ENABLED
240  internalAllocator().set_name(EASTL_FIXED_SLIST_DEFAULT_NAME);
241  #endif
242 
243  assign(first, last);
244  }
245 
246 
247  template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
248  inline typename fixed_slist<T, nodeCount, bEnableOverflow, OverflowAllocator>::this_type&
249  fixed_slist<T, nodeCount, bEnableOverflow, OverflowAllocator>::operator=(const this_type& x)
250  {
251  if(this != &x)
252  {
253  base_type::clear();
254 
255  #if EASTL_ALLOCATOR_COPY_ENABLED
256  internalAllocator() = x.internalAllocator(); // The primary effect of this is to copy the overflow allocator.
257  #endif
258 
259  base_type::assign(x.begin(), x.end()); // It would probably be better to implement this like slist::operator=.
260  }
261  return *this;
262  }
263 
264 
265  template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
266  inline typename fixed_slist<T, nodeCount, bEnableOverflow, OverflowAllocator>::this_type&
267  fixed_slist<T, nodeCount, bEnableOverflow, OverflowAllocator>::operator=(this_type&& x)
268  {
269  return operator=(x);
270  }
271 
272 
273  template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
274  inline typename fixed_slist<T, nodeCount, bEnableOverflow, OverflowAllocator>::this_type&
275  fixed_slist<T, nodeCount, bEnableOverflow, OverflowAllocator>::operator=(std::initializer_list<value_type> ilist)
276  {
277  base_type::clear();
278  base_type::assign(ilist.begin(), ilist.end());
279  return *this;
280  }
281 
282 
283  template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
284  inline void fixed_slist<T, nodeCount, bEnableOverflow, OverflowAllocator>::swap(this_type& x)
285  {
286  // Fixed containers use a special swap that can deal with excessively large buffers.
287  eastl::fixed_swap(*this, x);
288  }
289 
290 
291  template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
292  inline void fixed_slist<T, nodeCount, bEnableOverflow, OverflowAllocator>::reset_lose_memory()
293  {
294  base_type::reset_lose_memory();
295  base_type::get_allocator().reset(mBuffer);
296  }
297 
298 
299  template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
300  inline typename fixed_slist<T, nodeCount, bEnableOverflow, OverflowAllocator>::size_type
301  fixed_slist<T, nodeCount, bEnableOverflow, OverflowAllocator>::max_size() const
302  {
303  return kMaxSize;
304  }
305 
306 
307  template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
308  inline bool fixed_slist<T, nodeCount, bEnableOverflow, OverflowAllocator>::full() const
309  {
310  // Note: This implementation isn't right in the case of bEnableOverflow = true because it will return
311  // false for the case that there are free nodes from the buffer but also nodes from the dynamic heap.
312  // This can happen if the container exceeds the fixed size and then frees some of the nodes from the fixed buffer.
313  return !internalAllocator().can_allocate(); // This is the quickest way of detecting this. has_overflowed uses a different method because it can't use this quick method.
314  }
315 
316 
317  template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
318  inline bool fixed_slist<T, nodeCount, bEnableOverflow, OverflowAllocator>::has_overflowed() const
319  {
320  #if EASTL_FIXED_SIZE_TRACKING_ENABLED // If we can use this faster pathway (as size() may be slow)...
321  return (internalAllocator().mPool.mnPeakSize > kMaxSize);
322  #else
323  return (size() > kMaxSize);
324  #endif
325  }
326 
327 
328  template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
329  inline bool fixed_slist<T, nodeCount, bEnableOverflow, OverflowAllocator>::can_overflow() const
330  {
331  return bEnableOverflow;
332  }
333 
334 
335  template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
336  inline const typename fixed_slist<T, nodeCount, bEnableOverflow, OverflowAllocator>::overflow_allocator_type&
337  fixed_slist<T, nodeCount, bEnableOverflow, OverflowAllocator>::get_overflow_allocator() const EA_NOEXCEPT
338  {
339  return internalAllocator().get_overflow_allocator();
340  }
341 
342 
343  template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
344  inline typename fixed_slist<T, nodeCount, bEnableOverflow, OverflowAllocator>::overflow_allocator_type&
345  fixed_slist<T, nodeCount, bEnableOverflow, OverflowAllocator>::get_overflow_allocator() EA_NOEXCEPT
346  {
347  return internalAllocator().get_overflow_allocator();
348  }
349 
350 
351  template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
352  inline void
353  fixed_slist<T, nodeCount, bEnableOverflow, OverflowAllocator>::set_overflow_allocator(const overflow_allocator_type& allocator)
354  {
355  internalAllocator().set_overflow_allocator(allocator);
356  }
357 
358 
359 
361  // global operators
363 
364  template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
365  inline void swap(fixed_slist<T, nodeCount, bEnableOverflow, OverflowAllocator>& a,
366  fixed_slist<T, nodeCount, bEnableOverflow, OverflowAllocator>& b)
367  {
368  // Fixed containers use a special swap that can deal with excessively large buffers.
369  eastl::fixed_swap(a, b);
370  }
371 
372 
373 
374 } // namespace eastl
375 
376 
377 #endif // Header include guard
378 
379 
380 
381 
382 
383 
384 
385 
386 
387 
388 
389 
Definition: allocator.h:52
Definition: fixed_pool.h:607
Definition: fixed_slist.h:68
Definition: slist.h:241
Definition: initializer_list.h:38
EA Standard Template Library.
Definition: algorithm.h:288
Definition: slist.h:123