1# EASTL Best Practices
2
3In this document we discuss best practices for using EASTL. The primary emphasis is on performance with a secondary emphasis on correctness and maintainability. Some best practices apply only to some situations, and these will be pointed out as we go along. In order to be easily digestible, we present these practices as a list of items in the tone of the Effective C++ series of books.
4
5## Summary
6
7The descriptions here are intentionally terse; this is to make them easier to visually scan.
8
91. [Consider intrusive containers.](#consider-intrusive-containers)
102. [Consider fixed-size containers.](#consider-fixed-size-containers)
113. [Consider custom allocators.](#consider-custom-allocators)
124. [Consider hash tables instead of maps.](#consider-hash-tables-instead-of-maps)
135. [Consider a vector_map (a.k.a. sorted vector) for unchanging data.](#consider-a-vector_map-aka-sorted-vector-for-unchanging-data)
146. [Consider slist instead of list.](#consider-slist-instead-of-list)
157. [Avoid redundant end() and size() in loops.](#avoid-redundant-end-and-size-in-loops)
168. [Iterate containers instead of using operator\[\].](#iterate-containers-instead-of-using-operator)
179. [Learn to use the string class appropriately.](#learn-to-use-the-string-class-appropriately)
1810. [Cache list size if you want size() to be O(1).](#cache-list-size-if-you-want-listsize-to-be-o1)
1911. [Use empty() instead of size() when possible.](#use-empty-instead-of-size-when-possible)
2012. [Know your container efficiencies.](#know-your-container-efficiencies)
2113. [Use vector::reserve.](#use-vectorreserve)
2214. [Use vector::set_capacity to trim memory usage.](#use-vectorset_capacity-to-trim-memory-usage)
2315. [Use swap() instead of a manually implemented version.](#use-swap-instead-of-a-manually-implemented-version)
2416. [Consider storing pointers instead of objects.](#consider-storing-pointers-instead-of-objects)
2517. [Consider smart pointers instead of raw pointers.](#consider-smart-pointers-instead-of-raw-pointers)
2618. [Use iterator pre-increment instead of post-increment.](#use-iterator-pre-increment-instead-of-post-increment)
2719. [Make temporary references so the code can be traced/debugged.](#make-temporary-references-so-the-code-can-be-traceddebugged)
2820. [Consider bitvector or bitset instead of vector\<bool>.](#consider-bitvector-or-bitset-instead-of-vector)
2921. [Vectors can be treated as contiguous memory.](#vectors-can-be-treated-as-contiguous-memory)
3022. [Search hash_map\<string> via find_as() instead of find().](#search-hash_map-via-find_as-instead-of-find)
3123. [Take advantage of type_traits (e.g. EASTL_DECLARE_TRIVIAL_RELOCATE).](#take-advantage-of-type_traits-eg-eastl_declare_trivial_relocate)
3224. [Name containers to track memory usage.](#name-containers-to-track-memory-usage)
3325. [Learn the algorithms.](#learn-the-algorithms)
3426. [Pass and return containers by reference instead of value.](#pass-and-return-containers-by-reference-instead-of-value)
3527. [Consider using reset() for fast container teardown.](#consider-using-reset-for-fast-container-teardown)
3628. [Consider using fixed_substring instead of copying strings.](#consider-using-fixed_substring-instead-of-copying-strings)
3729. [Consider using vector::push_back(void).](#consider-using-vectorpush_backvoid)
38
39## Detail
40
41### Consider intrusive containers.
42
43Intrusive containers (such as intrusive_list) differ from regular containers (such as list) in that they use the stored objects to manage the linked list instead of using nodes allocated from a memory heap. The result is better usage of memory. Additionally intrusive_list objects can be removed from their list without knowing what list they belong to. To make an intrusive_list of Widgets, you have Widget inherit from intrusive_list_node or simply have mpPrev/mpNext member variables.
44
45To create an intrusive_list container, you can use the following code:
46
47```cpp
48class Widget : public intrusive_list_node
49
50{ };
51
52
53
54intrusive_list<Widget> widgetList;
55
56widgetList.push_back(someWidget);
57```
58
59### Consider fixed-size containers.
60
61Fixed-size containers (such as fixed_list) are variations of regular containers (such as list) in that they allocate from a fixed block of local memory instead of allocating from a generic heap. The result is better usage of memory due to reduced fragmentation, better cache behavior, and faster allocation/deallocation. The presence of fixed-size containers negate the most common complaint that people have about STL: that it fragments the heap or "allocates all over the place."
62
63EASTL fixed containers include:
64
65* fixed_list
66* fixed_slist
67* fixed_vector
68* fixed_string
69* fixed_map
70* fixed_multimap
71* fixed_set
72* fixed_multiset
73* fixed_hash_map
74* fixed_hash_multimap
75* fixed_hash_set
76* fixed_hash_multiset
77
78To create a fixed_set, you can use the following code:
79
80```cpp
81fixed_set<int, 25> intSet; // Create a set capable of holding 250 elements.
82
83intSet.push_back(37);
84```
85
86### Consider custom allocators.
87
88While EASTL provides fixed-size containers in order to control container memory usage, EASTL lets you assign a custom allocator to any container. This lets you define your own memory pool. EASTL has a more flexible and powerful mechanism of doing this that standard STL, as EASTL understands object alignment requirements, allows for debug naming, allows for sharing allocators across containers, and allows dynamic allocator assignment.
89
90To create a list container that uses your custom allocator and uses block naming, you can use the following code:
91
92```cpp
93list<int> intList(pSomeAllocator, "graphics/intList");
94
95intList.push_back(37);
96```
97
98### Consider hash tables instead of maps.
99
100Hash containers (such as hash_map) provide the same interface as associative containers (such as map) but have faster lookup and use less memory. The primary disadvantage relative to associative containers is that hash containers are not sorted.
101
102To make a hash_map (dictionary) of integers to strings, you can use the following code:
103```cpp
104hash_map<int, const char*> stringTable;
105
106stringTable[37] = "hello";
107```
108
109### Consider a vector_map (a.k.a. sorted vector) for unchanging data.
110
111You can improve speed, memory usage, and cache behavior by using a vector_map instead of a map (or vector_set instead of set, etc.). The primary disadvantage of vector_map is that insertions and removal of elements is O(n) instead of O(1). However, if your associative container is not going to be changing much or at all, you can benefit from using a vector_map. Consider calling reserve on the vector_map in order to set the desired capacity up front.
112
113To make a vector_set, you can use the following code:
114
115```cpp
116vector_set<int> intSet(16); // Create a vector_set with an initial capacity of 16.
117
118intSet.insert(37);
119```
120
121Note that you can use containers other than vector to implement vector_set. Here's how you do it with deque:
122
123```cpp
124vector_set<int, less<int>, EASTLAllocatorType, deque<int> > intSet;
125
126intSet.insert(37);
127```
128
129### Consider slist instead of list.
130
131An slist is a singly-linked list; it is much like a list except that it can only be traversed in a forward direction and not a backward direction. The benefit is that each node is 4 bytes instead of 8 bytes. This is a small improvement, but if you don't need reverse iteration then it can be an improvement. There's also intrusive_slist as an option.
132
133To make an slist, you can use the following code:
134
135```cpp
136slist<int> intSlist;
137
138intSlist.push_front(37);
139```
140
141### Avoid redundant end() and size() in loops.
142
143Instead of writing code like this:
144
145```cpp
146for(deque<int>::iterator it = d.begin(); it != d.end(); ++it)
147
148    ...
149```
150
151write code like this:
152
153```cpp
154for(deque<int>::iterator it = d.begin(), itEnd = d.end(); it != itEnd; ++it)
155
156    ...
157```
158
159The latter avoids a function call and return of an object (which in deque's case happens to be more than just a pointer). The above only works when the container is unchanged or for containers that have a constant end value. But "constant end value" we mean containers which can be modified but end always remains the same.
160
161| Constant begin | Non-constant begin | Constant end | Non-constant end |
162|------|------|------|------|
163| array<sup>1</sup> | string<br> vector<br> deque<br> intrusive_list<br> intrusive_slist<br> vector_map<br> vector_multimap<br> vector_set<br> vector_multiset<br> bit_vector<br> hash_map<br> hash_multimap<br> hash_set<br> hash_multiset<br> intrusive_hash_map<br> intrusive_hash_multimap<br> intrusive_hash_set<br> intrusive_hash_multiset | array<br> list<br> slist<br> intrusive_list<br> intrusive_slist<br> map<br> multimap<br> set<br> multiset<br> hash_map<sup>2</sup><br> hash_multimap<sup>2</sup><br> hash_set<sup>2</sup><br> hash_multiset<sup>2</sup><br> intrusive_hash_map<br> intrusive_hash_multimap<br> intrusive_hash_set<br> intrusive_hash_multiset | string<br> vector<br> deque<br> vector_map<br> vector_multimap<br> vector_set<br> vector_multiset<br> bit_vector |
164
165* <sup>1</sup> Arrays can be neither resized nor reallocated.
166* <sup>2</sup> Constant end if the hashtable can't/won't re-hash. Non-constant if it can re-hash.
167
168### Iterate containers instead of using operator[].
169
170It's faster to iterate random access containers via iterators than via operator[], though operator[] usage may look simpler.
171
172Instead of doing this:
173
174```cpp
175for(unsigned i = 0, iEnd = intVector.size(); i != iEnd; ++i)
176
177    intVector[i] = 37;
178```
179
180you can execute more efficiently by doing this:
181
182```cpp
183for(vector<int>::iterator it = intVector.begin(), itEnd = intVector.end(); it != itEnd; ++it)
184
185    *it = 37;
186```
187
188### Learn to use the string class appropriately.
189
190Oddly enough, the most mis-used STL container is easily the string class. The tales of string abuse could rival the 1001 Arabian Nights. Most of the abuses involve doing things in a harder way than need be. In examining the historical mis-uses of string, it is clear that many of the problems stem from the user thinking in terms of C-style string operations instead of object-oriented strings. This explains why statements such as strlen(s.c_str()) are so common, whereas the user could just use s.length() instead and be both clearer and more efficient.
191
192Here we provide a table of actual collected examples of things done and how they could have been done instead.
193
194| What was written | What could have been written |
195|------|------|
196| `s = s.Left(i) + '+' + s.Right(s.length() - i - 1);` | `s[i] = '+';` |
197| `string s(""); // This is the most commonly found misuse.` | `string s;` |
198| `s = "";` | `s.clear();` |
199| `s.c_str()[0] = 'u';` | `s[0] = 'u';` |
200| `len = strlen(s.c_str());` | `len = s.length();` |
201| `s = string("u");` | `s = "u";` |
202| `puts(s + string("u"));` | `puts(s + "u");` |
203| `string s(" ");`<br> `puts(s.c_str());` | `puts(" ");` |
204| `s.sprintf("u");` | s = "u";` |
205| `char array[32];`<br> `sprintf(array, "%d", 10);`<br> `s = string(array);` | `s.sprintf("%d", 10);` |
206
207The chances are that if you want to do something with a string, there is a very basic way to do it. You don't want your code to appear in a future version of the above table.
208
209### Cache list size if you want list::size() to be O(1).
210
211EASTL's list, slist, intrusive_list, and intrusive_slist containers have a size() implementation which is O(n). That is, these containers don't keep a count (cache) of the current list size and when you call the size() function they iterate the list. This is by design and the reasoning behind it has been deeply debated and considered (and is discussed in the FAQ and the list header file). In summary, list doesn't cache its size because the only function that would benefit is the size function while many others would be negatively impacted and the memory footprint would be negatively impacted, yet list::size is not a very frequently called function in well-designed code. At the same time, nothing prevents the user from caching the size himself, though admittedly it adds some tedium and risk to the code writing process.
212
213Here's an example of caching the list size manually:
214
215```cpp
216list<int> intList;
217
218  size_t    n = 0;
219
220
221
222  intList.push_back(37);
223
224  ++n;
225
226  intList.pop_front();
227
228  --n;
229```
230
231### Use empty() instead of size() when possible.
232
233All conventional containers have both an empty function and a size function. For all containers empty() executes with O(1) (constant time) efficiency. However, this is not so for size(), as some containers need to calculate the size and others need to do pointer subtraction (which may involve integer division) to find the size.
234
235### Know your container efficiencies.
236
237The above two practices lead us to this practice, which is a generalization of the above. We present a table of basic information for the conventional EASTL containers. The values are described at the bottom.
238
239| Container | empty() efficiency | size() efficiency | operator[] efficiency | insert() efficiency | erase() efficiency | find() efficiency | sort efficiency |
240|------|------|------|------|------|------|------|------|
241| slist | 1 | O(n) | - | O(1) | O(1) | O(n) | O(n+) |
242| list | 1 | n | - | 1 | 1 | n | n log(n) |
243| intrusive_slist | 1 | n | - | 1 | 1 | 1 | n+ |
244| intrusive_list | 1 | n | - | 1 | 1 | 1 | n log(n) |
245| array | 1 | 1 | 1 | - | - | n | n log(n) |
246| vector | 1 | 1<sup>a</sup> | 1 | 	1 at end, else n | 1 at end, else n | n | n log(n) |
247| vector_set | 1 | 1<sup>a</sup> | 1 | 1 at end, else n | 1 at end, else n | log(n) | 1 |
248| vector_multiset | 1 | 1<sup>a</sup> | 1 | 1 at end, else n | 1 at end, else n | log(n) | 1 |
249| vector_map | 1 | 1<sup>a</sup> | 1 | 1 at end, else n | 1 at end, else n | log(n) | 1 |
250| vector_multimap | 1 | 1<sup>a</sup> | 1 | 1 at end, else n | 1 at end, else n | log(n) | 1 |
251| deque | 1 | 1<sup>a</sup> | 1 | 1 at begin or end, else n / 2 | 1 at begin or end, else n / 2 | n | n log(n) |
252| bit_vector | 1 | 1<sup>a</sup> | 1 | 1 at end, else n | 1 at end, else n | n | n log(n) |
253| string, cow_string  | 1 | 1<sup>a</sup> | 1 | 1 at end, else n | 1 at end, else n | n | n log(n) |
254| set | 1 | 1 | - | log(n) | log(n) | log(n) | 1 |
255| multiset | 1 | 1 | - | log(n) | log(n) | log(n) | 1 |
256| map | 1 | 1 | log(n) | log(n) | log(n) | log(n) | 1 |
257| multimap | 1 | 1 | - | log(n) | log(n) | log(n) | 1 |
258| hash_set | 1 | 1 | - | 1 | 1 | 1 | - |
259| hash_multiset | 1 | 1 | - | 1 | 1 | 1 | - |
260| hash_map | 1 | 1 | - | 1 | 1 | 1 | - |
261| hash_multimap | 1 | 1 | - | 1 | 1 | 1 | - |
262| intrusive_hash_set | 1 | 1 | - | 1 | 1 | 1 | - |
263| intrusive_hash_multiset | 1 | 1 | - | 1 | 1 | 1 | - |
264| intrusive_hash_map | 1 | 1 | - | 1 | 1 | 1 | - |
265| intrusive_hash_multimap | 1 | 1 | - | 1 | 1 | 1 | - |
266
267Notes:
268
269* \- means that the operation does not exist.
270* 1 means amortized constant time. Also known as O(1)
271* n means time proportional to the container size. Also known as O(n)
272* log(n) means time proportional to the natural logarithm of the container size. Also known as O(log(n))
273* n log(n) means time proportional to log(n) times the size of the container. Also known as O(n log(n))
274* n+ means that the time is at least n, and possibly higher.
275* Inserting at the end of a vector may cause the vector to be resized; resizing a vector is O(n). However, the amortized time complexity for vector insertions at the end is constant.
276* Sort assumes the usage of the best possible sort for a large container of random data. Some sort algorithms (e.g. quick_sort) require random access iterators and so the sorting of some containers requires a different sort algorithm. We do not include bucket or radix sorts, as they are always O(n).
277* <sup>a</sup> vector, deque, string size is O(1) but involves pointer subtraction and thus integer division and so is not as efficient as containers that store the size directly.
278
279### Use vector::reserve.
280
281You can prevent vectors (and strings) from reallocating as you add items by specifying up front how many items you will be requiring. You can do this in the constructor or by calling the reserve function at any time. The capacity function returns the amount of space which is currently reserved.
282
283Here's how you could specify reserved capacity in a vector:
284
285```cpp
286vector<Widget> v(37);   // Reserve space to hold up to 37 items.
287
288    or
289
290vector<Widget> v;       // This empty construction causes to memory to be allocated or reserved.
291
292  v.reserve(37);
293```
294
295The EASTL vector (and string) implementation looks like this:
296
297```cpp
298template <typename T>
299
300  class vector {
301
302    T* mpBegin;     // Beginning of used element memory.
303
304    T* mpEnd;       // End of used element memory.
305
306    T* mpCapacity;  // End of storage capacity. Is >= mpEnd
307
308   }
309```
310
311Another approach to being efficient with vector memory usage is to use fixed_vector.
312
313### Use vector::set_capacity to trim memory usage.
314
315A commonly asked question about vectors and strings is, "How do I reduce the capacity of a vector?" The conventional solution for std STL is to use the somewhat non-obvious trick of using vector<Widget>(v).swap(v). EASTL provides the same functionality via a member function called set_capacity() which is present in both the vector and string classes.
316
317An example of reducing a vector is the following:
318
319```cpp
320vector<Widget> v;
321
322...
323
324 v.set_capacity();
325```
326
327An example of resizing to zero and completely freeing the memory of a vector is the following:
328
329```cpp
330vector<Widget> v;
331
332  ...
333
334   v.set_capacity(0);
335```
336
337### Use swap() instead of a manually implemented version.
338
339The generic swap algorithm provides a basic version for any kind of object. However, each EASTL container provides a specialization of swap which is optimized for that container. For example, the list container implements swap by simply swapping the internal member pointers and not by moving individual elements.
340
341### Consider storing pointers instead of objects.
342
343There are times when storing pointers to objects is more efficient or useful than storing objects directly in containers. It can be more efficient to store pointers when the objects are big and the container may need to construct, copy, and destruct objects during sorting or resizing. Moving pointers is usually faster than moving objects. It can be useful to store pointers instead of objects when somebody else owns the objects or the objects are in another container. It might be useful for a Widget to be in a list and in a hash table at the same time.
344
345### Consider smart pointers instead of raw pointers.
346
347If you take the above recommendation and store objects as pointers instead of as objects, you may want to consider storing them as smart pointers instead of as regular pointers. This is particularly useful for when you want to delete the object when it is removed from the container. Smart pointers will automatically delete the pointed-to object when the smart pointer is destroyed. Otherwise, you will have to be careful about how you work with the list so that you don't generate memory leaks. Smart pointers implement a shared reference count on the stored pointer, as so any operation you do on a smart pointer container will do the right thing. Any pointer can be stored in a smart pointer, and custom new/delete mechanisms can work with smart pointers. The primary smart pointer is shared_ptr.
348
349Here is an example of creating and using a shared_ptr:
350
351```cpp
352typedef shared_ptr<Widget> WPtr;
353
354  list<WPtr> wList;
355
356
357
358  wList.push_back(WPtr(new Widget)); // The user may have operator new/delete overrides.
359
360wList.pop_back();                  // Implicitly deletes the Widget.
361```
362
363Here is an example of creating and using a shared_ptr that uses a custom allocation and deallocation mechanism:
364
365```cpp
366typedef shared_ptr<Widget, EASTLAllocatorType, WidgetDelete> WPtr; // WidgetDelete is a custom destroyer.
367
368  list<WPtr> wList;
369
370
371
372  wList.push_back(WPtr(WidgetCreate(Widget))); // WidgetCreate is a custom allocator.
373
374wList.pop_back();                            // Implicitly calls WidgetDelete.
375```
376
377### Use iterator pre-increment instead of post-increment.
378
379Pre-increment (e.g. ++x) of iterators is better than post-increment (x++) when the latter is not specifically needed. It is common to find code that uses post-incrementing when it could instead use pre-incrementing; presumably this is due to post-increment looking a little better visually. The problem is that the latter constructs a temporary object before doing the increment. With built-in types such as pointers and integers, the compiler will recognize that the object is a trivial built-in type and that the temporary is not needed, but the compiler cannot do this for other types, even if the compiler sees that the temporary is not used; this is because the constructor may have important side effects and the compiler would be broken if it didn't construct the temporary object.
380
381EASTL iterators are usually not trivial types and so it's best not to hope the compiler will do the best thing. Thus you should always play it safe an use pre-increment of iterators whenever post-increment is not required.
382
383Here is an example of using iterator pre-increment; for loops like this should always use pre-increment:
384
385```cpp
386for(set<int>::iterator it(intSet.begin()), itEnd(intSet.end()); it != itEnd; ++it)
387
388      *it = 37;
389```
390
391### Make temporary references so the code can be traced/debugged.
392
393Users want to be able to inspect or modify variables which are referenced by iterators. While EASTL containers and iterators are designed to make this easier than other STL implementations, it makes things very easy if the code explicitly declares a reference to the iterated element. In addition to making the variable easier to debug, it also makes code easier to read and makes the debug (and possibly release) version of the application run more efficiently.
394
395Instead of doing this:
396
397```cpp
398for(list<Widget>::iterator it = wl.begin(), itEnd = wl.end(); it != itEnd; ++it) {
399
400      (*it).x = 37;
401
402      (*it).y = 38;
403
404      (*it).z = 39;
405
406  }
407```
408
409Consider doing this:
410
411```cpp
412for(list<Widget>::iterator it = wl.begin(), itEnd = wl.end(); it != itEnd; ++it) {
413
414      Widget& w = *it; // The user can easily inspect or modify w here.
415
416      w.x = 37;
417
418      w.y = 38;
419
420      w.z = 39;
421
422  }
423```
424
425### Consider bitvector or bitset instead of vector<bool>.
426
427In EASTL, a vector of bool is exactly that. It intentionally does not attempt to make a specialization which implements a packed bit array. The bitvector class is specifically designed for this purpose. There are arguments either way, but if vector<bool> were allowed to be something other than an array of bool, it would go against user expectations and prevent users from making a true array of bool. There's a mechanism for specifically getting the bit packing, and it is bitvector.
428
429Additionally there is bitset, which is not a conventional iterateable container but instead acts like bit flags. bitset may better suit your needs than bitvector if you need to do flag/bit operations instead of array operations. bitset does have an operator[], though.
430
431### Vectors can be treated as contiguous memory.
432
433EASTL vectors (and strings) guarantee that elements are present in a linear contiguous array. This means that you can use a vector as you would a C-style array by using the vector data() member function or by using &v[0].
434
435To use a vector as a pointer to an array, you can use the following code:
436
437```cpp
438struct Widget {
439
440      uint32_t x;
441
442      uint32_t y;
443
444  };
445
446
447
448  vector<Widget> v;
449
450
451
452  quick_sort((uint64_t*)v.data(), (uint64_t*)(v.data() + v.size()));
453```
454
455### Search hash_map<string> via find_as() instead of find().
456
457EASTL hash tables offer a bonus function called find_as when lets you search a hash table by something other than the container type. This is particularly useful for hash tables of string objects that you want to search for by string literals (e.g. "hello") or char pointers. If you search for a string via the find function, your string literal will necessarily be converted to a temporary string object, which is inefficient.
458
459To use find_as, you can use the following code:
460
461```cpp
462hash_map<string, int> hashMap;
463
464  hash_map<string, int>::iterator it = hashMap.find_as("hello"); // Using default hash and compare.
465```
466
467### Take advantage of type_traits (e.g. EASTL_DECLARE_TRIVIAL_RELOCATE).
468
469EASTL includes a fairly serious type traits library that is on par with the one found in Boost but offers some additional performance-enhancing help as well. The type_traits library provides information about class *types*, as opposed to class instances. For example, the is_integral type trait tells if a type is one of int, short, long, char, uint64_t, etc.
470
471There are three primary uses of type traits:
472
473* Allowing for optimized operations on some data types.
474* Allowing for different logic pathways based on data types.
475* Allowing for compile-type assertions about data type expectations.
476
477Most of the type traits are automatically detected and implemented by the compiler. However, EASTL allows for the user to explicitly give the compiler hints about type traits that the compiler cannot know, via the EASTL_DECLARE declarations. If the user has a class that is relocatable (i.e. can safely use memcpy to copy values), the user can use the EASTL_DECLARE_TRIVIAL_RELOCATE declaration to tell the compiler that the class can be copied via memcpy. This will automatically significantly speed up some containers and algorithms that use that class.
478
479Here is an example of using type traits to tell if a value is a floating point value or not:
480
481```cpp
482template <typename T>
483
484  DoSomething(T t) {
485
486    assert(is_floating_point<T>::value);
487
488  }
489```
490
491Here is an example of declaring a class as relocatable and using it in a vector.
492
493```cpp
494EASTL_DECLARE_TRIVIAL_RELOCATE(Widget); // Usually you put this at the Widget class declaration.
495
496  vector<Widget> wVector;
497
498  wVector.erase(wVector.begin());         // This operation will be optimized via using memcpy.
499```
500
501The following is a full list of the currently recognized type traits. Most of these are implemented as of this writing, but if there is one that is missing, feel free to contact the maintainer of this library and request that it be completed.
502
503* is_void
504* is_integral
505* is_floating_point
506* is_arithmetic
507* is_fundamental
508* is_const
509* is_volatile
510* is_abstract
511* is_signed
512* is_unsigned
513* is_array
514* is_pointer
515* is_reference
516* is_member_object_pointer
517* is_member_function_pointer
518* is_member_pointer
519* is_enum
520* is_union
521* is_class
522* is_polymorphic
523* is_function
524* is_object
525* is_scalar
526* is_compound
527* is_same
528* is_convertible
529* is_base_of
530* is_empty
531* is_pod
532* is_aligned
533* has_trivial_constructor
534* has_trivial_copy
535* has_trivial_assign
536* has_trivial_destructor
537* has_trivial_relocate1
538* has_nothrow_constructor
539* has_nothrow_copy
540* has_nothrow_assign
541* has_virtual_destructor
542* alignment_of
543* rank
544* extent
545*
546<sup>1</sup> has_trivial_relocate is not found in Boost nor the C++ standard update proposal. However, it is very useful in allowing for the generation of optimized object moving operations. It is similar to the is_pod type trait, but goes further and allows non-pod classes to be categorized as relocatable. Such categorization is something that no compiler can do, as only the user can know if it is such. Thus EASTL_DECLARE_TRIVIAL_RELOCATE  is provided to allow the user to give the compiler a hint.
547
548### Name containers to track memory usage.
549
550All EASTL containers which allocate memory have a built-in function called set_name and have a constructor argument that lets you specify the container name. This name is used in memory tracking and allows for the categorization and measurement of memory usage. You merely need to supply a name for your containers to use and it does the rest.
551
552Here is an example of creating a list and naming it "collision list":
553
554`list<CollisionData> collisionList(allocator("collision list"));`
555
556or
557
558```cpp
559list<CollisionData> collisionList;
560
561collisionList.get_allocator().set_name("collision list");
562```
563
564Note that EASTL containers do not copy the name contents but merely copy the name pointer. This is done for simplicity and efficiency. A user can get around this limitation by creating a persistently present string table. Additionally, the user can get around this by declaring static but non-const strings and modifying them at runtime.
565
566### Learn the algorithms.
567
568EASTL algorithms provide a variety of optimized implementations of fundamental algorithms. Many of the EASTL algorithms are the same as the STL algorithm set, though EASTL adds additional algorithms and additional optimizations not found in STL implementations such as Microsoft's. The copy algorithm, for example, will memcpy data types that have the has_trivial_relocate type trait instead of doing an element-by-element copy.
569
570The classifications we use here are not exactly the same as found in the C++ standard; they have been modified to be a little more intuitive. Not all the functions listed here may be yet available in EASTL as you read this. If you want some function then send a request to the maintainer. Detailed documentation for each algorithm is found in algorithm.h or the otherwise corresponding header file for the algorithm.
571
572**Search**
573
574* find, find_if
575* find_end
576* find_first_of
577* adjacent_find
578* binary_search
579* search, search_n
580* lower_bound
581* upper_bound
582* equal_range
583
584**Sort**
585
586* is_sorted
587* quick_sort
588* insertion_sort
589* shell_sort
590* heap_sort
591* merge_sort, merge_sort_buffer
592* merge
593* inplace_merge
594* partial_sort
595* stable_sort
596* partial_sort_copy
597* <other sort functions found in the EASTL bonus directories>
598
599**Modifying**
600
601* fill, fill_n
602* generate, generate_n
603* random_shuffle
604* swap
605* iter_swap
606* swap_ranges
607* remove, remove_if
608* remove_copy, remove_copy_if
609* replace, replace_if
610* replace_copy, replace_copy_if
611* reverse
612* reverse_copy
613* rotate
614* rotate_copy
615* partition
616* stable_partition
617* transform
618* next_permutation
619* prev_permutation
620* unique
621* unique_copy
622
623**Non-Modifying**
624
625* for_each
626* copy
627* copy_backward
628* count, count_if
629* equal
630* mismatch
631* min
632* max
633* min_element
634* max_element
635* lexicographical_compare
636* nth_element
637
638**Heap**
639
640* is_heap
641* make_heap
642* push_heap
643* pop_heap
644* change_heap
645* sort_heap
646* remove_heap
647
648**Set**
649
650* includes
651* set_difference
652* set_symmetric_difference
653* set_intersection
654* set_union
655
656### Pass and return containers by reference instead of value.
657
658If you aren't paying attention you might accidentally write code like this:
659
660```cpp
661void DoSomething(list<Widget> widgetList) {
662
663      ...
664
665}
666```
667
668The problem with the above is that widgetList is passed by value and not by reference. Thus the a copy of the container is made and passed instead of a reference of the container being passed. This may seem obvious to some but this happens periodically and the compiler gives no warning and the code will often execute properly, but inefficiently. Of course there are some occasions where you really do want to pass values instead of references.
669
670### Consider using reset() for fast container teardown.
671
672EASTL containers have a reset function which unilaterally resets the container to a newly constructed state. The contents of the container are forgotten; no destructors are called and no memory is freed. This is a risky but power function for the purpose of implementing very fast temporary containers. There are numerous cases in high performance programming when you want to create a temporary container out of a scratch buffer area, use the container, and then just "vaporize" it, as it would be waste of time to go through the trouble of clearing the container and destroying and freeing the objects. Such functionality is often used with hash tables or maps and with a stack allocator (a.k.a. linear allocator).
673
674Here's an example of usage of the reset function and a PPMalloc-like StackAllocator:
675
676```cpp
677pStackAllocator->push_bookmark();
678
679  hash_set<Widget, less<Widget>, StackAllocator> wSet(pStackAllocator);
680
681<use wSet>
682
683  wSet.reset();
684
685  pStackAllocator->pop_bookmark();
686```
687
688### Consider using fixed_substring instead of copying strings.
689
690EASTL provides a fixed_substring class which uses a reference to a character segment instead of allocating its own string memory. This can be a more efficient way to work with strings under some circumstances.
691
692Here's an example of usage of fixed_substring:
693
694```cpp
695basic_string<char> str("hello world");
696
697  fixed_substring<char> sub(str, 6, 5); // sub == "world"
698
699fixed_substring can refer to any character array and not just one that derives from a string object.
700```
701
702### Consider using vector::push_back(void).
703
704EASTL provides an alternative way to insert elements into containers that avoids copy construction and/or the creation of temporaries. Consider the following code:
705
706```cpp
707vector<Widget> widgetArray;
708
709  widgetArray.push_back(Widget());
710```
711
712The standard vector push_back function requires you to supply an object to copy from. This incurs the cost of the creation of a temporary and for some types of classes or situations this cost may be undesirable. It additionally requires that your contained class support copy-construction whereas you may not be able to support copy construction. As an alternative, EASTL provides a push_back(void) function which requires nothing to copy from but instead constructs the object in place in the container. So you can do this:
713
714```cpp
715vector<Widget> widgetArray;
716
717  widgetArray.push_back();
718
719widgetArray.back().x = 0; // Example of how to reference the new object.
720```
721
722Other containers with such copy-less functions include:
723
724```cpp
725vector::push_back()
726
727  deque::push_back()
728
729  deque::push_front()
730
731  list::push_back()
732
733  list::push_front()
734
735  slist::push_front()
736
737  map::insert(const key_type& key)
738
739  multimap::insert(const key_type& key)
740
741  hash_map::insert(const key_type& key)
742
743  hash_multimap::insert(const key_type& key)
744```
745
746Note that the map functions above allow you to insert a default value specified by key alone and not a value_type like with the other map insert functions.
747
748----------------------------------------------
749End of document
750