This commit is contained in:
Rob Parolin
2019-05-31 11:12:44 -07:00
parent 2491faf753
commit af7e82c45c
46 changed files with 5121 additions and 1010 deletions

View File

@@ -1,340 +0,0 @@
[AutoExpand]
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; EASTL ;
; ;
; Due to weaknesses in the VC debugger, you ;
; may find that you need to tweak the spacing ;
; in the templates specified below or your app's ;
; template instantiations. ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
eastl::vector<*>{
children
(
#(
[raw members]: [$e,!],
size: $e.mpEnd-$e.mpBegin,
capacity: $e.mpCapacity-$e.mpBegin,
#array
(
expr : ($e.mpBegin)[$i],
size : $e.mpEnd-$e.mpBegin
)
)
)
preview
(
#(
"[",
$e.mpEnd - $e.mpBegin,
"](",
#array
(
expr : ($e.mpBegin)[$i],
size : $e.mpEnd-$e.mpBegin
),
")"
)
)
}
; Same as eastl::vector
eastl::fixed_vector<*>{
children
(
#(
[raw members]: [$e,!],
size: $e.mpEnd-$e.mpBegin,
capacity: $e.mpCapacity-$e.mpBegin,
#array
(
expr : ($e.mpBegin)[$i],
size : $e.mpEnd-$e.mpBegin
)
)
)
preview
(
#(
"[",
$e.mpEnd - $e.mpBegin,
"] {",
#array
(
expr : ($e.mpBegin)[$i],
size : $e.mpEnd-$e.mpBegin
),
"}"
)
)
}
; Same as eastl::vector
eastl::vector_set<*>{
children
(
#(
[raw members]: [$e,!],
size: $e.mpEnd-$e.mpBegin,
capacity: $e.mpCapacity-$e.mpBegin,
#array
(
expr : ($e.mpBegin)[$i],
size : $e.mpEnd-$e.mpBegin
)
)
)
preview
(
#(
"[",
$e.mpEnd - $e.mpBegin,
"] (",
#array
(
expr : ($e.mpBegin)[$i],
size : $e.mpEnd-$e.mpBegin
),
")"
)
)
}
; Same as eastl::vector
eastl::vector_map<*>{
children
(
#(
[raw members]: [$e,!],
size: $e.mpEnd-$e.mpBegin,
capacity: $e.mpCapacity-$e.mpBegin,
#array
(
expr : ($e.mpBegin)[$i],
size : $e.mpEnd-$e.mpBegin
)
)
)
preview
(
#(
"[",
$e.mpEnd - $e.mpBegin,
"] (",
#array
(
expr : ($e.mpBegin)[$i],
size : $e.mpEnd-$e.mpBegin
),
")"
)
)
}
eastl::basic_string<char,*>{
preview([$e.mpBegin,s8])
stringview([$e.mpBegin,s8b])
}
eastl::basic_string<wchar_t,*>{
preview([$e.mpBegin,su])
stringview([$e.mpBegin,sub])
}
eastl::hashtable<*>{
preview
(
#(
"elements=", $e.mnElementCount
)
)
children
(
#(
#array
(
expr: &$e.mpBucketArray[$i],
size: $e.mnBucketCount
) : #(
#list
(
head: $e,
next: mpNext
) : $e.mValue
)
)
)
}
eastl::list<*,*>{
children
(
#(
[raw members]: [$e,!],
#list
(
head: $e.mNode.mpNext,
next: mpNext,
skip: &$e.mNode
) : (eastl::ListNode<$T1> *)&($e)
)
)
preview
(
#(
"(",
#list
(
head: $e.mNode.mpNext,
next: mpNext,
skip: &$e.mNode
) : ((eastl::ListNode<$T1> *)&($e))->mValue,
")"
)
)
}
eastl::intrusive_list<*>{
children
(
#(
[raw members]: [$e,!],
#list
(
head: $e.mAnchor.mpNext,
next: mpNext,
skip: &$e
) : ($T1 *)&$e
)
)
}
eastl::set<*,*,*>|eastl::fixed_set<*,*,*,*,*>|eastl::multiset<*,*,*>{
preview
(
#(
"[", $e.mnSize, "] {",
#tree
(
head : (eastl::rbtree_node_base*)(($e.mAnchor.mpNodeParent.value) & ~1u),
skip : $e.mAnchor,
size : $e.mnSize,
left : mpNodeLeft,
right : mpNodeRight
) : ((eastl::rbtree_node<$T1> *)&$e)->mValue,
"}"
) : ((eastl::rbtree_node<$T1> *)&$e)->mValue
)
children
(
#(
[raw members]: [$e,!],
#tree
(
head : (eastl::rbtree_node_base*)(($e.mAnchor.mpNodeParent.value) & ~1u),
skip : $e.mAnchor,
size : $e.mnSize,
left : mpNodeLeft,
right : mpNodeRight
) : ((eastl::rbtree_node<$T1> *)&$e)->mValue
)
)
}
eastl::map<*,*,*,*>|eastl::multimap<*,*,*,*>|eastl::fixed_map<*,*,*,*,*,*>{
preview
(
#(
"[", $e.mnSize, "] {",
#tree
(
head : (eastl::rbtree_node_base*)(($e.mAnchor.mpNodeParent.value) & ~1u),
skip : $e.mAnchor,
size : $e.mnSize,
left : mpNodeLeft,
right : mpNodeRight
) : ((eastl::rbtree_node<eastl::pair<$T1 const ,$T2> > *)&$e)->mValue,
"}"
) : ((eastl::rbtree_node<eastl::pair<$T1 const ,$T2> > *)&$e)->mValue
)
children
(
#(
[raw members]: [$e,!],
#tree
(
head : (eastl::rbtree_node_base*)(($e.mAnchor.mpNodeParent.value) & ~1u),
skip : $e.mAnchor,
size : $e.mnSize,
left : mpNodeLeft,
right : mpNodeRight
) : ((eastl::rbtree_node<eastl::pair<$T1 const ,$T2> > *)&$e)->mValue
)
)
}
eastl::pair<*,*>{
preview
(
#(
"(",
[$e.first],
",",
[$e.second],
")"
)
)
}

851
doc/Benchmarks.md Normal file
View File

@@ -0,0 +1,851 @@
# EASTL Benchmarks
## Introduction
This document provides a number of benchmark results of EASTL. Where possible, these benchmarks are implemented as comparisons with equivalent functionality found in other libraries such as compiler STL libraries or other well-known libraries. These comparison benchmarks concentrate on highlighting the differences between implementations rather than the similarities. In many mundane cases -- such as accessing a vector element via operator [] -- virtually all vector/array implementations you are likely to run into will have identical performance.
It's also important to note that the platform you run on can make a significant difference in the results. On a modern 3+GHz Windows PC many operations are fast due to large memory caches, intelligent branch prediction, and parallel instruction execution. However, on embedded or console systems none of these may be the case.
While EASTL generally outperforms std STL, there are some benchmarks here in which EASTL is slower than std STL. There are three primary explanations of this:
1. EASTL is making some kind of speed, memory, or design tradeoff that results in the given speed difference. In may such cases, EASTL goes slower on one benchmark in order to go faster on another benchmark deemed more important. This explanation constitutes about 60% of the cases.
2. Compiler optimizations and resulting code generation is coincidencally favoring one kind of implementation over another, often when they are visually virtually identical. This explantation constitutes about 30% of the cases.
3. EASTL is simply not yet as optimized as it could be. This explanation constitutes about 10% of the cases (as of this writing there are about three such functions throughout EASTL).
## Benchmarks
Below is a table of links to detailed benchmark results derived from the Benchmark test present in the EASTL package. The detailed results are present below the table. Additional platforms will be added as results become available for those platforms. Debug benchmarks are present because (lack of) debug performance can be significant for highly templated libraries. EASTL has specific optimizations to enhance debug performance relative to other standard libraries; in some cases it is 10x or more faster than alternatives (though there are exceptions where EASTL is slower). Feel free to submit results for additional compilers/platforms.
| Platform | Compiler | STL type | Build | Results |
|------|------|------|------|------|
| Win32 | VC++ 7.1 | Microsoft (Dinkumware) | Debug | [Detail]() |
| Win32 | VC++ 7.1 | Microsoft (Dinkumware) | Release | [Detail]() |
| Win32 | VC++ 7.1 | STLPort | Debug | [Detail]() |
| Win32 | VC++ 7.1 | STLPort | Release | [Detail]() |
### Win32.VC71.MS.Debug
```
EASTL version: 0.96.00
Platform: Windows on X86
Compiler: Microsoft Visual C++ compiler, version 1310
Allocator: PPMalloc::GeneralAllocatorDebug. Thread safety enabled.
Build: Debug. Inlining disabled. STL debug features disabled.
Values are times to complete tests; smaller values are better.
Alarm indicates a greater than 10% difference.
Test VC++ EASTL Ratio Alarm
----------------------------------------------------------------------------------------
algorithm/adj_find/vector<TestObject> 33061345 6497757 5.09 *
algorithm/copy/vector<LargePOD> 5844906 4876076 1.20 *
algorithm/copy/vector<uint32_t> 1634346 166065 9.84 *
algorithm/copy_backward/vector<LargePOD> 4515974 4638892 0.97
algorithm/copy_backward/vector<uint32_t> 1821168 121746 14.96 *
algorithm/count/vector<uint64_t> 17048884 2720766 6.27 *
algorithm/equal_range/vector<uint64_t> 1111147812 448756888 2.48 *
algorithm/fill/bool[] 1728722 91936 18.80 *
algorithm/fill/char[]/'d' 1299200 33745 38.50 *
algorithm/fill/vector<char>/'d' 10205092 33796 100.00 *
algorithm/fill/vector<char>/0 10200748 33805 100.00 *
algorithm/fill/vector<uint64_t> 10416538 1399687 7.44 *
algorithm/fill/vector<void*> 10221837 1307700 7.82 *
algorithm/fill_n/bool[] 1399033 34196 40.91 *
algorithm/fill_n/char[] 1299225 33754 38.49 *
algorithm/fill_n/vector<uint64_t> 5961637 1371900 4.35 *
algorithm/find_end/string/end 16569373 2657372 6.24 *
algorithm/find_end/string/middle 16558638 20242410 0.82 *
algorithm/find_end/string/none 16811207 40480468 0.42 *
algorithm/lex_cmp/schar[] 1749674 194429 9.00 *
algorithm/lex_cmp/vector<TestObject> 32824195 5253587 6.25 *
algorithm/lex_cmp/vector<uchar> 29852034 202658 100.00 *
algorithm/lower_bound/vector<TestObject> 798624462 350027935 2.28 *
algorithm/min_element/vector<TestObject> 21675298 5314676 4.08 *
algorithm/rand_shuffle/vector<uint64_t> 84236190 43677506 1.93 *
algorithm/reverse/list<TestObject> 3007292 2105799 1.43 *
algorithm/reverse/vector<TestObject> 2974618 2124796 1.40 *
algorithm/search/string<char> 16228158 3594268 4.52 *
algorithm/search_n/string<char> 16926985 1522096 11.12 *
algorithm/unique/vector<TestObject> 54206243 9988002 5.43 *
algorithm/unique/vector<uint32_t> 26940079 1741991 15.47 *
algorithm/unique/vector<uint64_t> 47621344 5213127 9.13 *
algorithm/upper_bound/vector<uint32_t> 372381295 137901552 2.70 *
bitset<1500>/>>=/1 90196544 92539832 0.97
bitset<1500>/count 50753832 53742117 0.94
bitset<1500>/flip 86935875 85121117 1.02
bitset<1500>/reset 78153837 79922611 0.98
bitset<1500>/set() 79214968 79360658 1.00
bitset<1500>/set(i) 11300589 12199651 0.93
bitset<1500>/test 11282679 13186450 0.86 *
bitset<15>/>>=/1 10500577 6000559 1.75 *
bitset<15>/count 4000356 6399753 0.63 *
bitset<15>/flip 7268877 5647944 1.29 *
bitset<15>/reset 8564235 5800163 1.48 *
bitset<15>/set() 9935523 5914012 1.68 *
bitset<15>/set(i) 11199703 12503637 0.90 *
bitset<15>/test 10600623 12899592 0.82 *
bitset<35>/>>=/1 13076052 6599834 1.98 *
bitset<35>/count 4800384 11500330 0.42 *
bitset<35>/flip 7915439 5816313 1.36 *
bitset<35>/reset 9400049 5803180 1.62 *
bitset<35>/set() 10701152 5840316 1.83 *
bitset<35>/set(i) 11342936 12271128 0.92
bitset<35>/test 10670799 13099682 0.81 *
bitset<75>/>>=/1 14198834 17151088 0.83 *
bitset<75>/count 5795530 8576373 0.68 *
bitset<75>/flip 8516703 8922995 0.95
bitset<75>/reset 9999970 8526095 1.17 *
bitset<75>/set() 11124877 9009686 1.23 *
bitset<75>/set(i) 11300563 12531618 0.90 *
bitset<75>/test 11031913 13100523 0.84 *
deque<ValuePair>/erase 743801706 335646802 2.22 *
deque<ValuePair>/insert 742331809 341912866 2.17 *
deque<ValuePair>/iteration 29097030 16315827 1.78 *
deque<ValuePair>/operator[] 49859598 24026313 2.08 *
deque<ValuePair>/push_back 424807033 34497608 12.31 *
deque<ValuePair>/push_front 402313373 38006322 10.59 *
deque<ValuePair>/sort 725101017 581796551 1.25 *
hash_map<string, uint32_t>/clear 559462 961019 0.58 *
hash_map<string, uint32_t>/count 53377807 8091448 6.60 *
hash_map<string, uint32_t>/erase pos 613573 858084 0.72 *
hash_map<string, uint32_t>/erase range 5488748 461134 11.90 *
hash_map<string, uint32_t>/erase val 35760096 16379858 2.18 *
hash_map<string, uint32_t>/find 43490335 10324823 4.21 *
hash_map<string, uint32_t>/find_as/char* 49343818 8617139 5.73 *
hash_map<string, uint32_t>/insert 107420281 168690439 0.64 *
hash_map<string, uint32_t>/iteration 2456356 1255153 1.96 *
hash_map<string, uint32_t>/operator[] 47209502 12581624 3.75 *
hash_map<uint32_t, TestObject>/clear 533172 546449 0.98
hash_map<uint32_t, TestObject>/count 28667432 2899997 9.89 *
hash_map<uint32_t, TestObject>/erase pos 683239 538289 1.27 *
hash_map<uint32_t, TestObject>/erase range 9632676 253037 38.07 *
hash_map<uint32_t, TestObject>/erase val 25466026 7752188 3.29 *
hash_map<uint32_t, TestObject>/find 20048253 4678502 4.29 *
hash_map<uint32_t, TestObject>/insert 71085798 37686187 1.89 *
hash_map<uint32_t, TestObject>/iteration 1460318 1338317 1.09
hash_map<uint32_t, TestObject>/operator[] 23226692 7888748 2.94 *
heap (uint32_t[])/make_heap 5399966 6961305 0.78 *
heap (uint32_t[])/pop_heap 108060534 103511318 1.04
heap (uint32_t[])/push_heap 22595661 16640688 1.36 *
heap (uint32_t[])/sort_heap 93559424 83076731 1.13 *
heap (vector<TestObject>)/make_heap 91770743 21724870 4.22 *
heap (vector<TestObject>)/pop_heap 1175599317 284007398 4.14 *
heap (vector<TestObject>)/push_heap 207804541 45918046 4.53 *
heap (vector<TestObject>)/sort_heap 970394145 208321477 4.66 *
list<TestObject>/ctor(it) 805539509 760938607 1.06
list<TestObject>/ctor(n) 80959236 75106995 1.08
list<TestObject>/erase 1052543704 1044976137 1.01
list<TestObject>/find 97785267 75970884 1.29 *
list<TestObject>/insert 873895175 807051107 1.08
list<TestObject>/push_back 812797710 780742425 1.04
list<TestObject>/remove 1850600714 1436980599 1.29 *
list<TestObject>/reverse 180270465 80466636 2.24 *
list<TestObject>/size/1 440148 599642 0.73 *
list<TestObject>/size/10 439433 1329817 0.33 * EASTL intentionally implements list::size as O(n).
list<TestObject>/size/100 439595 11030060 0.04 * EASTL intentionally implements list::size as O(n).
list<TestObject>/splice 177106094 69383027 2.55 *
map<TestObject, uint32_t>/clear 508283 470807 1.08
map<TestObject, uint32_t>/count 43145354 14280357 3.02 *
map<TestObject, uint32_t>/equal_range 38594004 16520447 2.34 *
map<TestObject, uint32_t>/erase/key 33948082 16123175 2.11 *
map<TestObject, uint32_t>/erase/pos 578332 455201 1.27 * MS uses a code bloating implementation of erase.
map<TestObject, uint32_t>/erase/range 387345 284538 1.36 *
map<TestObject, uint32_t>/find 22897224 12766100 1.79 *
map<TestObject, uint32_t>/insert 61665800 47286928 1.30 *
map<TestObject, uint32_t>/iteration 1977202 745391 2.65 *
map<TestObject, uint32_t>/lower_bound 19892941 12260928 1.62 *
map<TestObject, uint32_t>/operator[] 24199084 15429634 1.57 *
map<TestObject, uint32_t>/upper_bound 19842409 12064441 1.64 *
set<uint32_t>/clear 1027625 1000901 1.03
set<uint32_t>/count 39730182 13329565 2.98 *
set<uint32_t>/equal_range 34681649 14768827 2.35 *
set<uint32_t>/erase range 841458 602030 1.40 *
set<uint32_t>/erase/pos 1380485 1084303 1.27 * MS uses a code bloating implementation of erase.
set<uint32_t>/erase/val 31617425 13344023 2.37 *
set<uint32_t>/find 19582428 10788864 1.82 *
set<uint32_t>/insert 61434014 48232086 1.27 *
set<uint32_t>/iteration 1512057 667820 2.26 *
set<uint32_t>/lower_bound 18394885 10402785 1.77 *
set<uint32_t>/upper_bound 17189083 10554425 1.63 *
sort/q_sort/TestObject[] 87088799 15037988 5.79 *
sort/q_sort/TestObject[]/sorted 21502892 3284299 6.55 *
sort/q_sort/vector<TestObject> 87962047 15004677 5.86 *
sort/q_sort/vector<TestObject>/sorted 21396523 3341163 6.40 *
sort/q_sort/vector<ValuePair> 80334589 10429161 7.70 *
sort/q_sort/vector<ValuePair>/sorted 22133295 3230553 6.85 *
sort/q_sort/vector<uint32> 72195388 5940302 12.15 *
sort/q_sort/vector<uint32>/sorted 19635171 995495 19.72 *
string<char16_t>/compare 523013373 534722089 0.98
string<char16_t>/erase/pos,n 3446597 3439492 1.00
string<char16_t>/find/p,pos,n 383873158 441902786 0.87 *
string<char16_t>/find_first_not_of/p,pos,n 174157 134131 1.30 *
string<char16_t>/find_first_of/p,pos,n 11715423 8520944 1.37 *
string<char16_t>/find_last_of/p,pos,n 1871556 1226457 1.53 *
string<char16_t>/insert/pos,p 3624877 3357058 1.08
string<char16_t>/iteration 6766787933 581916665 11.63 *
string<char16_t>/operator[] 4820827 2335579 2.06 *
string<char16_t>/push_back 59812962 6757466 8.85 *
string<char16_t>/replace/pos,n,p,n 4371279 4459713 0.98
string<char16_t>/reserve 2307530 1919386 1.20 *
string<char16_t>/rfind/p,pos,n 734826 372615 1.97 *
string<char16_t>/size 41608 28866 1.44 *
string<char16_t>/swap 1033932 1490994 0.69 *
string<char8_t>/compare 63086797 64194771 0.98
string<char8_t>/erase/pos,n 2045687 1960270 1.04
string<char8_t>/find/p,pos,n 123872549 471364764 0.26 *
string<char8_t>/find_first_not_of/p,pos,n 140013 130271 1.07
string<char8_t>/find_first_of/p,pos,n 8051906 8749994 0.92
string<char8_t>/find_last_of/p,pos,n 1318835 1230715 1.07
string<char8_t>/insert/pos,p 1770610 1724234 1.03
string<char8_t>/iteration 28112136 2544475 11.05 *
string<char8_t>/operator[] 4810525 2255841 2.13 *
string<char8_t>/push_back 54869634 6127447 8.95 *
string<char8_t>/replace/pos,n,p,n 2737578 2847900 0.96
string<char8_t>/reserve 1123395 394902 2.84 *
string<char8_t>/rfind/p,pos,n 737299 368518 2.00 *
string<char8_t>/size 42245 26801 1.58 *
string<char8_t>/swap 1036142 1491028 0.69 *
vector<uint64>/erase 56417135 55770251 1.01
vector<uint64>/insert 56617761 56100468 1.01
vector<uint64>/iteration 10413895 1291269 8.06 *
vector<uint64>/operator[] 23507193 3479390 6.76 *
vector<uint64>/push_back 34687939 13806627 2.51 *
vector<uint64>/sort 256886550 84669657 3.03 *
```
### Win32.VC71.MS.Release
```
EASTL version: 0.96.00
Platform: Windows on X86
Compiler: Microsoft Visual C++ compiler, version 1310
Allocator: PPMalloc::GeneralAllocator. Thread safety enabled.
Build: Full optimization. Inlining enabled.
Values are times to complete tests; smaller values are better.
Alarm indicates a greater than 10% difference.
Test VC++ EASTL Ratio Alarm
----------------------------------------------------------------------------------------
algorithm/adj_find/vector<TestObject> 2783546 2750660 1.01
algorithm/copy/vector<LargePOD> 6474025 4972738 1.30 *
algorithm/copy/vector<uint32_t> 157267 173162 0.91
algorithm/copy_backward/vector<LargePOD> 4836406 4374780 1.11 *
algorithm/copy_backward/vector<uint32_t> 104780 120912 0.87 *
algorithm/count/vector<uint64_t> 1368440 1368696 1.00
algorithm/equal_range/vector<uint64_t> 114199387 102783938 1.11 *
algorithm/fill/bool[] 253215 27353 9.26 *
algorithm/fill/char[]/'d' 253164 27404 9.24 *
algorithm/fill/vector<char>/'d' 253105 27362 9.25 *
algorithm/fill/vector<char>/0 253275 27353 9.26 *
algorithm/fill/vector<uint64_t> 397001 394323 1.01
algorithm/fill/vector<void*> 547196 642362 0.85 *
algorithm/fill_n/bool[] 229177 27361 8.38 *
algorithm/fill_n/char[] 228845 27404 8.35 *
algorithm/fill_n/vector<uint64_t> 565233 1376822 0.41 *
algorithm/find_end/string/end 2107116 82356 25.59 *
algorithm/find_end/string/middle 2111672 664283 3.18 *
algorithm/find_end/string/none 2110423 1519596 1.39 *
algorithm/lex_cmp/schar[] 741021 176162 4.21 *
algorithm/lex_cmp/vector<TestObject> 2610494 2642183 0.99
algorithm/lex_cmp/vector<uchar> 697595 167866 4.16 *
algorithm/lower_bound/vector<TestObject> 62462233 58146664 1.07
algorithm/min_element/vector<TestObject> 4350385 2671227 1.63 *
algorithm/rand_shuffle/vector<uint64_t> 10868261 11300818 0.96
algorithm/reverse/list<TestObject> 483718 470024 1.03
algorithm/reverse/vector<TestObject> 476739 484322 0.98
algorithm/search/string<char> 2560387 1259496 2.03 *
algorithm/search_n/string<char> 2770991 458524 6.04 *
algorithm/unique/vector<TestObject> 4194520 4658910 0.90 *
algorithm/unique/vector<uint32_t> 538730 787924 0.68 *
algorithm/unique/vector<uint64_t> 3169829 2575636 1.23 *
algorithm/upper_bound/vector<uint32_t> 27495562 25321593 1.09
bitset<1500>/>>=/1 33464228 33469719 1.00
bitset<1500>/count 18736116 18814903 1.00
bitset<1500>/flip 19299309 18605438 1.04
bitset<1500>/reset 22200487 15262847 1.45 *
bitset<1500>/set() 14418193 17557319 0.82 *
bitset<1500>/set(i) 1599250 1599199 1.00
bitset<1500>/test 1599241 1599233 1.00
bitset<15>/>>=/1 2199222 2264442 0.97
bitset<15>/count 1399406 1399193 1.00
bitset<15>/flip 1266712 1199197 1.06
bitset<15>/reset 1399364 1399109 1.00
bitset<15>/set() 1199197 999201 1.20 *
bitset<15>/set(i) 1599258 1462952 1.09
bitset<15>/test 1599275 1599224 1.00
bitset<35>/>>=/1 2599266 1933376 1.34 *
bitset<35>/count 2599240 2592559 1.00
bitset<35>/flip 1693124 1199188 1.41 *
bitset<35>/reset 1399406 999201 1.40 *
bitset<35>/set() 1599403 1199205 1.33 *
bitset<35>/set(i) 1599241 1599190 1.00
bitset<35>/test 1599250 1599232 1.00
bitset<75>/>>=/1 4199332 4199213 1.00
bitset<75>/count 2999497 2199341 1.36 *
bitset<75>/flip 2399499 1830178 1.31 *
bitset<75>/reset 2199468 1199197 1.83 *
bitset<75>/set() 1999387 1199851 1.67 *
bitset<75>/set(i) 1599266 1599198 1.00
bitset<75>/test 1599241 1662651 0.96
deque<ValuePair>/erase 90444165 37113253 2.44 *
deque<ValuePair>/insert 93299349 36175167 2.58 *
deque<ValuePair>/iteration 2756414 2122076 1.30 *
deque<ValuePair>/operator[] 5117969 4632075 1.10
deque<ValuePair>/push_back 30300757 3060357 9.90 *
deque<ValuePair>/push_front 25498529 2808392 9.08 *
deque<ValuePair>/sort 142283047 111292464 1.28 *
hash_map<string, uint32_t>/clear 146769 389699 0.38 *
hash_map<string, uint32_t>/count 13059434 3460324 3.77 *
hash_map<string, uint32_t>/erase pos 184246 331925 0.56 *
hash_map<string, uint32_t>/erase range 382432 167237 2.29 *
hash_map<string, uint32_t>/erase val 6187898 3302114 1.87 *
hash_map<string, uint32_t>/find 11289369 3459024 3.26 *
hash_map<string, uint32_t>/find_as/char* 13559192 3662387 3.70 *
hash_map<string, uint32_t>/insert 17514012 14095176 1.24 *
hash_map<string, uint32_t>/iteration 801014 218450 3.67 *
hash_map<string, uint32_t>/operator[] 11457065 3690385 3.10 *
hash_map<uint32_t, TestObject>/clear 141865 265379 0.53 *
hash_map<uint32_t, TestObject>/count 1766045 703613 2.51 *
hash_map<uint32_t, TestObject>/erase pos 172337 218458 0.79 *
hash_map<uint32_t, TestObject>/erase range 537846 102340 5.26 *
hash_map<uint32_t, TestObject>/erase val 2220132 1441787 1.54 *
hash_map<uint32_t, TestObject>/find 1612994 1043953 1.55 *
hash_map<uint32_t, TestObject>/insert 7141547 4348056 1.64 *
hash_map<uint32_t, TestObject>/iteration 199512 169328 1.18 *
hash_map<uint32_t, TestObject>/operator[] 1831733 1519707 1.21 *
heap (uint32_t[])/make_heap 3366247 1949093 1.73 *
heap (uint32_t[])/pop_heap 57280514 53779440 1.07
heap (uint32_t[])/push_heap 9700217 7582935 1.28 *
heap (uint32_t[])/sort_heap 47227751 46131948 1.02
heap (vector<TestObject>)/make_heap 11458442 11510819 1.00
heap (vector<TestObject>)/pop_heap 122897267 119061132 1.03
heap (vector<TestObject>)/push_heap 21688481 21176220 1.02
heap (vector<TestObject>)/sort_heap 90867380 88869523 1.02
list<TestObject>/ctor(it) 74591104 69845817 1.07
list<TestObject>/ctor(n) 6243998 5838582 1.07
list<TestObject>/erase 299509298 206013676 1.45 *
list<TestObject>/find 40927185 14514243 2.82 *
list<TestObject>/insert 71277251 47234534 1.51 *
list<TestObject>/push_back 73780527 44116725 1.67 *
list<TestObject>/remove 786197776 326434612 2.41 *
list<TestObject>/reverse 49283128 25029678 1.97 *
list<TestObject>/size/1 159741 139400 1.15 *
list<TestObject>/size/10 159324 346579 0.46 * EASTL intentionally implements list::size as O(n).
list<TestObject>/size/100 159188 97235419 0.00 * EASTL intentionally implements list::size as O(n).
list<TestObject>/splice 63548584 19322931 3.29 *
map<TestObject, uint32_t>/clear 167408 170501 0.98
map<TestObject, uint32_t>/count 10213685 4748346 2.15 *
map<TestObject, uint32_t>/equal_range 9515053 5677558 1.68 *
map<TestObject, uint32_t>/erase/key 6646260 4302300 1.54 *
map<TestObject, uint32_t>/erase/pos 297135 327938 0.91 MS uses a code bloating implementation of erase.
map<TestObject, uint32_t>/erase/range 148614 163702 0.91
map<TestObject, uint32_t>/find 5637531 4767055 1.18 *
map<TestObject, uint32_t>/insert 9591128 9030349 1.06
map<TestObject, uint32_t>/iteration 323595 325261 0.99
map<TestObject, uint32_t>/lower_bound 5398239 4784089 1.13 *
map<TestObject, uint32_t>/operator[] 5631250 5141166 1.10
map<TestObject, uint32_t>/upper_bound 5436336 4762431 1.14 *
set<uint32_t>/clear 155983 156026 1.00
set<uint32_t>/count 9635965 4392146 2.19 *
set<uint32_t>/equal_range 8504157 5247832 1.62 *
set<uint32_t>/erase range 140488 119408 1.18 *
set<uint32_t>/erase/pos 260678 286697 0.91 MS uses a code bloating implementation of erase.
set<uint32_t>/erase/val 6008225 4012825 1.50 *
set<uint32_t>/find 5145432 4381945 1.17 *
set<uint32_t>/insert 8087129 8697251 0.93
set<uint32_t>/iteration 271507 304538 0.89 *
set<uint32_t>/lower_bound 4666228 4404250 1.06
set<uint32_t>/upper_bound 4623600 4402974 1.05
sort/q_sort/TestObject[] 9596169 5578652 1.72 *
sort/q_sort/TestObject[]/sorted 602463 1016132 0.59 *
sort/q_sort/vector<TestObject> 9674828 5430199 1.78 *
sort/q_sort/vector<TestObject>/sorted 606908 1111647 0.55 *
sort/q_sort/vector<ValuePair> 6284194 3423452 1.84 *
sort/q_sort/vector<ValuePair>/sorted 711629 569364 1.25 *
sort/q_sort/vector<uint32> 5453379 2916146 1.87 *
sort/q_sort/vector<uint32>/sorted 537047 419144 1.28 *
string<char16_t>/compare 435083295 251985824 1.73 *
string<char16_t>/erase/pos,n 3454842 3451858 1.00
string<char16_t>/find/p,pos,n 401954723 165298157 2.43 *
string<char16_t>/find_first_not_of/p,pos,n 131452 65374 2.01 *
string<char16_t>/find_first_of/p,pos,n 11657444 4144515 2.81 *
string<char16_t>/find_last_of/p,pos,n 1604248 567571 2.83 *
string<char16_t>/insert/pos,p 3398734 3355460 1.01
string<char16_t>/iteration 218856504 218771844 1.00
string<char16_t>/operator[] 714161 240023 2.98 *
string<char16_t>/push_back 34968235 2444897 14.30 *
string<char16_t>/replace/pos,n,p,n 4226693 4198498 1.01
string<char16_t>/reserve 1901765 390805 4.87 *
string<char16_t>/rfind/p,pos,n 195483 150985 1.29 *
string<char16_t>/size 11169 11245 0.99
string<char16_t>/swap 1459280 419807 3.48 *
string<char8_t>/compare 63071275 77209580 0.82 *
string<char8_t>/erase/pos,n 2008652 1944494 1.03
string<char8_t>/find/p,pos,n 123201023 167536164 0.74 *
string<char8_t>/find_first_not_of/p,pos,n 93372 67864 1.38 *
string<char8_t>/find_first_of/p,pos,n 7542492 3375758 2.23 *
string<char8_t>/find_last_of/p,pos,n 933972 583576 1.60 *
string<char8_t>/insert/pos,p 1737213 1750847 0.99
string<char8_t>/iteration 893834 899130 0.99
string<char8_t>/operator[] 817879 313437 2.61 *
string<char8_t>/push_back 20857734 2004410 10.41 *
string<char8_t>/replace/pos,n,p,n 2578696 2607655 0.99
string<char8_t>/reserve 915127 85289 10.73 *
string<char8_t>/rfind/p,pos,n 196103 148894 1.32 *
string<char8_t>/size 11619 11220 1.04
string<char8_t>/swap 1461056 419874 3.48 *
vector<uint64>/erase 55235116 55284587 1.00
vector<uint64>/insert 55166046 55142755 1.00
vector<uint64>/iteration 553954 509719 1.09
vector<uint64>/operator[] 1284239 798516 1.61 *
vector<uint64>/push_back 5399549 3867959 1.40 *
vector<uint64>/sort 43636314 42619952 1.02
```
### Win32.VC71.STLPort.Debug
```
EASTL version: 0.96.00
Platform: Windows on X86
Compiler: Microsoft Visual C++ compiler, version 1310
Allocator: PPMalloc::GeneralAllocatorDebug. Thread safety enabled.
Build: Debug. Inlining disabled. STL debug features disabled.
Values are times to complete tests; smaller values are better.
Alarm indicates a greater than 10% difference.
Test STLPort EASTL Ratio Alarm
----------------------------------------------------------------------------------------
algorithm/adj_find/vector<TestObject> 5661170 5689517 1.00
algorithm/copy/vector<LargePOD> 5573815 5124428 1.09
algorithm/copy/vector<uint32_t> 148273 125782 1.18 *
algorithm/copy_backward/vector<LargePOD> 5429791 4834510 1.12 *
algorithm/copy_backward/vector<uint32_t> 156765 163038 0.96
algorithm/count/vector<uint64_t> 2730922 2730072 1.00
algorithm/equal_range/vector<uint64_t> 639366489 452896251 1.41 *
algorithm/fill/bool[] 1299326 27361 47.49 *
algorithm/fill/char[]/'d' 27378 27361 1.00
algorithm/fill/vector<char>/'d' 34459 27361 1.26 *
algorithm/fill/vector<char>/0 1299224 27361 47.48 *
algorithm/fill/vector<uint64_t> 1400647 1400145 1.00
algorithm/fill/vector<void*> 1308779 1309085 1.00
algorithm/fill_n/bool[] 1299156 27352 47.50 *
algorithm/fill_n/char[] 1299258 27369 47.47 *
algorithm/fill_n/vector<uint64_t> 1451162 1313632 1.10
algorithm/find_end/string/end 13089999 2526412 5.18 *
algorithm/find_end/string/middle 12627412 20190101 0.63 *
algorithm/find_end/string/none 12704185 40728803 0.31 *
algorithm/lex_cmp/schar[] 1749844 195806 8.94 *
algorithm/lex_cmp/vector<TestObject> 5060968 4799882 1.05
algorithm/lex_cmp/vector<uchar> 1668354 189490 8.80 *
algorithm/lower_bound/vector<TestObject> 450240945 353437573 1.27 *
algorithm/min_element/vector<TestObject> 5861744 5326371 1.10
algorithm/rand_shuffle/vector<uint64_t> 40780449 45780090 0.89 *
algorithm/reverse/list<TestObject> 2657678 2130627 1.25 *
algorithm/reverse/vector<TestObject> 2666424 2124889 1.25 *
algorithm/search/string<char> 3110379 3613460 0.86 *
algorithm/search_n/string<char> 3061665 1521261 2.01 *
algorithm/unique/vector<TestObject> 12423684 9485439 1.31 *
algorithm/unique/vector<uint32_t> 3718699 1726596 2.15 *
algorithm/unique/vector<uint64_t> 6205110 4591631 1.35 *
algorithm/upper_bound/vector<uint32_t> 185391094 139336317 1.33 *
bitset<1500>/>>=/1 120666960 92449816 1.31 * STLPort is broken, neglects wraparound check.
bitset<1500>/count 201709793 52874726 3.81 *
bitset<1500>/flip 87360297 81737071 1.07
bitset<1500>/reset 23950178 77390323 0.31 *
bitset<1500>/set() 84608107 76912011 1.10
bitset<1500>/set(i) 18023620 12229604 1.47 *
bitset<1500>/test 18006553 13276396 1.36 *
bitset<15>/>>=/1 11935904 6012695 1.99 * STLPort is broken, neglects wraparound check.
bitset<15>/count 9368581 6022742 1.56 *
bitset<15>/flip 11600706 6533635 1.78 *
bitset<15>/reset 5830957 5874690 0.99
bitset<15>/set() 11695328 5701621 2.05 *
bitset<15>/set(i) 16363205 12570216 1.30 *
bitset<15>/test 16743172 13201452 1.27 *
bitset<35>/>>=/1 22950918 6774457 3.39 * STLPort is broken, neglects wraparound check.
bitset<35>/count 12655309 11736256 1.08
bitset<35>/flip 13738575 5800042 2.37 *
bitset<35>/reset 15561434 5800510 2.68 *
bitset<35>/set() 13564283 5600709 2.42 *
bitset<35>/set(i) 18519689 12199973 1.52 *
bitset<35>/test 18000569 13103566 1.37 *
bitset<75>/>>=/1 25579525 16669664 1.53 * STLPort is broken, neglects wraparound check.
bitset<75>/count 18740698 8480492 2.21 *
bitset<75>/flip 13555630 8300335 1.63 *
bitset<75>/reset 15200133 8200000 1.85 *
bitset<75>/set() 14408112 8001959 1.80 *
bitset<75>/set(i) 18137741 12374257 1.47 *
bitset<75>/test 18422135 13100038 1.41 *
deque<ValuePair>/erase 651933790 326443043 2.00 *
deque<ValuePair>/insert 659786183 333304660 1.98 *
deque<ValuePair>/iteration 23734592 16173706 1.47 *
deque<ValuePair>/operator[] 59126816 23911774 2.47 *
deque<ValuePair>/push_back 58056988 31859266 1.82 *
deque<ValuePair>/push_front 57780891 31743199 1.82 *
deque<ValuePair>/sort 818414195 596568113 1.37 *
hash_map<string, uint32_t>/clear 3422133 2204517 1.55 *
hash_map<string, uint32_t>/count 9869545 8624924 1.14 *
hash_map<string, uint32_t>/erase pos 3256350 2069299 1.57 *
hash_map<string, uint32_t>/erase range 3230203 1151392 2.81 *
hash_map<string, uint32_t>/erase val 16860362 15939778 1.06
hash_map<string, uint32_t>/find 10286971 9920910 1.04
hash_map<string, uint32_t>/find_as/char* 118136025 9458468 12.49 *
hash_map<string, uint32_t>/insert 188948336 174490082 1.08
hash_map<string, uint32_t>/iteration 4037049 2021036 2.00 *
hash_map<string, uint32_t>/operator[] 11472127 12887699 0.89 *
hash_map<uint32_t, TestObject>/clear 2522264 1331848 1.89 *
hash_map<uint32_t, TestObject>/count 3210739 2897063 1.11 *
hash_map<uint32_t, TestObject>/erase pos 1862281 1304783 1.43 *
hash_map<uint32_t, TestObject>/erase range 698079 579606 1.20 *
hash_map<uint32_t, TestObject>/erase val 8806722 7041298 1.25 *
hash_map<uint32_t, TestObject>/find 3604875 4709645 0.77 *
hash_map<uint32_t, TestObject>/insert 40785711 40376342 1.01
hash_map<uint32_t, TestObject>/iteration 3064088 1508834 2.03 *
hash_map<uint32_t, TestObject>/operator[] 6053742 8176906 0.74 *
heap (uint32_t[])/make_heap 5799813 5738596 1.01
heap (uint32_t[])/pop_heap 113775168 102076134 1.11 *
heap (uint32_t[])/push_heap 21649151 16854845 1.28 *
heap (uint32_t[])/sort_heap 97535213 83290735 1.17 *
heap (vector<TestObject>)/make_heap 22215557 22277063 1.00
heap (vector<TestObject>)/pop_heap 275392171 277340039 0.99
heap (vector<TestObject>)/push_heap 51479442 47342577 1.09
heap (vector<TestObject>)/sort_heap 214474736 218497540 0.98
list<TestObject>/ctor(it) 767753795 753421427 1.02
list<TestObject>/ctor(n) 74185322 73386245 1.01
list<TestObject>/erase 1021003824 1033873589 0.99
list<TestObject>/find 77666072 74917622 1.04
list<TestObject>/insert 788071150 774188737 1.02
list<TestObject>/push_back 760490154 737327348 1.03
list<TestObject>/remove 1682511938 1434771006 1.17 *
list<TestObject>/reverse 87237327 80394623 1.09
list<TestObject>/size/1 3828111 599530 6.39 *
list<TestObject>/size/10 9600605 1329535 7.22 * EASTL intentionally implements list::size as O(n).
list<TestObject>/size/100 62952334 15022551 4.19 * EASTL intentionally implements list::size as O(n).
list<TestObject>/splice 96536412 60804817 1.59 *
map<TestObject, uint32_t>/clear 1142127 1099066 1.04
map<TestObject, uint32_t>/count 19659726 14647548 1.34 *
map<TestObject, uint32_t>/equal_range 36680687 18219086 2.01 *
map<TestObject, uint32_t>/erase/key 28892154 16037774 1.80 *
map<TestObject, uint32_t>/erase/pos 1209643 1185495 1.02
map<TestObject, uint32_t>/erase/range 715402 670539 1.07
map<TestObject, uint32_t>/find 21020992 13429575 1.57 *
map<TestObject, uint32_t>/insert 59530871 51120640 1.16 *
map<TestObject, uint32_t>/iteration 972825 1191946 0.82 *
map<TestObject, uint32_t>/lower_bound 18852651 12495034 1.51 *
map<TestObject, uint32_t>/operator[] 22889573 16676736 1.37 *
map<TestObject, uint32_t>/upper_bound 18603584 12406922 1.50 *
set<uint32_t>/clear 919555 882988 1.04
set<uint32_t>/count 17561110 12461084 1.41 *
set<uint32_t>/equal_range 31522488 15230282 2.07 *
set<uint32_t>/erase range 687582 564765 1.22 *
set<uint32_t>/erase/pos 1044352 1045355 1.00
set<uint32_t>/erase/val 25525304 12940774 1.97 *
set<uint32_t>/find 17140751 10704866 1.60 *
set<uint32_t>/insert 56035051 45555664 1.23 *
set<uint32_t>/iteration 682669 640831 1.07
set<uint32_t>/lower_bound 16339932 10475740 1.56 *
set<uint32_t>/upper_bound 17779424 10652599 1.67 *
sort/q_sort/TestObject[] 17000866 14823515 1.15 *
sort/q_sort/TestObject[]/sorted 6658559 3263328 2.04 *
sort/q_sort/vector<TestObject> 17476629 14953285 1.17 *
sort/q_sort/vector<TestObject>/sorted 6667034 3327435 2.00 *
sort/q_sort/vector<ValuePair> 15391357 10820848 1.42 *
sort/q_sort/vector<ValuePair>/sorted 6617122 3232949 2.05 *
sort/q_sort/vector<uint32> 8343906 6014846 1.39 *
sort/q_sort/vector<uint32>/sorted 3039430 1003127 3.03 *
string<char16_t>/compare 1489709846 532664000 2.80 *
string<char16_t>/erase/pos,n 3528690 3439864 1.03
string<char16_t>/find/p,pos,n 2521448321 443752189 5.68 *
string<char16_t>/find_first_not_of/p,pos,n 661206 137419 4.81 *
string<char16_t>/find_first_of/p,pos,n 54746434 8521335 6.42 *
string<char16_t>/find_last_of/p,pos,n 10607778 1212414 8.75 *
string<char16_t>/insert/pos,p 3445016 3360126 1.03
string<char16_t>/iteration 580955636 579452556 1.00
string<char16_t>/operator[] 2206353 1987809 1.11 *
string<char16_t>/push_back 22421368 6007808 3.73 *
string<char16_t>/replace/pos,n,p,n 5138454 4464786 1.15 *
string<char16_t>/reserve 4922413418 335622 100.00 *
string<char16_t>/rfind/p,pos,n 1440308 380578 3.78 *
string<char16_t>/size 25355 25398 1.00
string<char16_t>/swap 2122704 1490823 1.42 *
string<char8_t>/compare 77222134 77443134 1.00
string<char8_t>/erase/pos,n 1965344 1956521 1.00
string<char8_t>/find/p,pos,n 2468091951 474205522 5.20 *
string<char8_t>/find_first_not_of/p,pos,n 660960 130211 5.08 *
string<char8_t>/find_first_of/p,pos,n 55020899 9240171 5.95 *
string<char8_t>/find_last_of/p,pos,n 10576210 1239053 8.54 *
string<char8_t>/insert/pos,p 1822756 1750880 1.04
string<char8_t>/iteration 2617889 2540148 1.03
string<char8_t>/operator[] 2254794 2256443 1.00
string<char8_t>/push_back 12463022 5210321 2.39 *
string<char8_t>/replace/pos,n,p,n 3744862 2855260 1.31 *
string<char8_t>/reserve 1372046888 218815 100.00 *
string<char8_t>/rfind/p,pos,n 1446232 366902 3.94 *
string<char8_t>/size 26859 25431 1.06
string<char8_t>/swap 2123350 1490509 1.42 *
vector<uint64>/erase 55164013 56417449 0.98
vector<uint64>/insert 55872973 56432664 0.99
vector<uint64>/iteration 1329102 1324623 1.00
vector<uint64>/operator[] 5264738 3136746 1.68 *
vector<uint64>/push_back 14903245 13171175 1.13 *
vector<uint64>/sort 88429095 88542171 1.00
```
### Win32.VC71.STLPort.Release
```
EASTL version: 0.96.00
Platform: Windows on X86
Compiler: Microsoft Visual C++ compiler, version 1310
Allocator: PPMalloc::GeneralAllocator. Thread safety enabled.
Build: Full optimization. Inlining enabled.
Values are times to complete tests; smaller values are better.
Alarm indicates a greater than 10% difference.
Test STLPort EASTL Ratio Alarm
----------------------------------------------------------------------------------------
algorithm/adj_find/vector<TestObject> 2741046 2731441 1.00
algorithm/copy/vector<LargePOD> 6065923 5085142 1.19 *
algorithm/copy/vector<uint32_t> 158304 165555 0.96
algorithm/copy_backward/vector<LargePOD> 4710258 4896476 0.96
algorithm/copy_backward/vector<uint32_t> 146030 142630 1.02
algorithm/count/vector<uint64_t> 1395921 1406334 0.99
algorithm/equal_range/vector<uint64_t> 211692764 118969493 1.78 *
algorithm/fill/bool[] 366078 33737 10.85 *
algorithm/fill/char[]/'d' 33736 33771 1.00
algorithm/fill/vector<char>/'d' 28466 33720 0.84 *
algorithm/fill/vector<char>/0 366086 33728 10.85 *
algorithm/fill/vector<uint64_t> 466250 401591 1.16 *
algorithm/fill/vector<void*> 521603 693481 0.75 *
algorithm/fill_n/bool[] 599709 33762 17.76 *
algorithm/fill_n/char[] 599573 33711 17.79 *
algorithm/fill_n/vector<uint64_t> 434971 1374084 0.32 *
algorithm/find_end/string/end 1494742 85349 17.51 *
algorithm/find_end/string/middle 1480700 687208 2.15 *
algorithm/find_end/string/none 1540540 1546431 1.00
algorithm/lex_cmp/schar[] 921638 178797 5.15 *
algorithm/lex_cmp/vector<TestObject> 2623559 2643551 0.99
algorithm/lex_cmp/vector<uchar> 960899 183608 5.23 *
algorithm/lower_bound/vector<TestObject> 60630534 56531528 1.07
algorithm/min_element/vector<TestObject> 4209022 2768527 1.52 *
algorithm/rand_shuffle/vector<uint64_t> 13762010 15969052 0.86 *
algorithm/reverse/list<TestObject> 673387 731825 0.92
algorithm/reverse/vector<TestObject> 634576 754511 0.84 *
algorithm/search/string<char> 1262599 1387608 0.91
algorithm/search_n/string<char> 1166242 458592 2.54 *
algorithm/unique/vector<TestObject> 4912193 5336317 0.92
algorithm/unique/vector<uint32_t> 809387 809081 1.00
algorithm/unique/vector<uint64_t> 4371814 2414255 1.81 *
algorithm/upper_bound/vector<uint32_t> 31899081 29555596 1.08
bitset<1500>/>>=/1 63308136 40553560 1.56 * STLPort is broken, neglects wraparound check.
bitset<1500>/count 62523178 22799473 2.74 *
bitset<1500>/flip 20302845 19919232 1.02
bitset<1500>/reset 18892015 15403148 1.23 *
bitset<1500>/set() 15803302 17322192 0.91
bitset<1500>/set(i) 2799271 2999310 0.93
bitset<1500>/test 2999293 2799262 1.07
bitset<15>/>>=/1 1199239 3199256 0.37 * STLPort is broken, neglects wraparound check.
bitset<15>/count 3599461 2199231 1.64 *
bitset<15>/flip 1199231 1199188 1.00
bitset<15>/reset 1199188 1199180 1.00
bitset<15>/set() 1199214 1199180 1.00
bitset<15>/set(i) 2599257 1399262 1.86 *
bitset<15>/test 2599274 2599283 1.00
bitset<35>/>>=/1 6643974 4599239 1.44 * STLPort is broken, neglects wraparound check.
bitset<35>/count 5151331 5399438 0.95
bitset<35>/flip 1999404 1199273 1.67 *
bitset<35>/reset 9805285 1399313 7.01 *
bitset<35>/set() 2799279 1199248 2.33 *
bitset<35>/set(i) 2799246 1599241 1.75 *
bitset<35>/test 2999234 2999251 1.00
bitset<75>/>>=/1 7002045 6999333 1.00 STLPort is broken, neglects wraparound check.
bitset<75>/count 5999351 3002259 2.00 *
bitset<75>/flip 3599334 3599163 1.00
bitset<75>/reset 9799344 3399218 2.88 *
bitset<75>/set() 3599232 3599062 1.00
bitset<75>/set(i) 2799228 1599284 1.75 *
bitset<75>/test 2999250 2799339 1.07
deque<ValuePair>/erase 127108651 115258113 1.10
deque<ValuePair>/insert 137727889 116552332 1.18 *
deque<ValuePair>/iteration 7144182 6009899 1.19 *
deque<ValuePair>/operator[] 34241222 20535039 1.67 *
deque<ValuePair>/push_back 6585800 3932126 1.67 *
deque<ValuePair>/push_front 6805865 3993513 1.70 *
deque<ValuePair>/sort 395352323 348778188 1.13 *
hash_map<string, uint32_t>/clear 426640 447015 0.95
hash_map<string, uint32_t>/count 4359344 3883089 1.12 *
hash_map<string, uint32_t>/erase pos 584392 458142 1.28 *
hash_map<string, uint32_t>/erase range 221034 196078 1.13 *
hash_map<string, uint32_t>/erase val 3539867 3790813 0.93
hash_map<string, uint32_t>/find 3966831 3811910 1.04
hash_map<string, uint32_t>/find_as/char* 11591612 4243710 2.73 *
hash_map<string, uint32_t>/insert 16763887 16719194 1.00
hash_map<string, uint32_t>/iteration 909968 478609 1.90 *
hash_map<string, uint32_t>/operator[] 4360041 4108313 1.06
hash_map<uint32_t, TestObject>/clear 302634 283722 1.07
hash_map<uint32_t, TestObject>/count 916487 907426 1.01
hash_map<uint32_t, TestObject>/erase pos 388042 321385 1.21 *
hash_map<uint32_t, TestObject>/erase range 122680 116280 1.06
hash_map<uint32_t, TestObject>/erase val 1710931 1729529 0.99
hash_map<uint32_t, TestObject>/find 1089462 1346527 0.81 *
hash_map<uint32_t, TestObject>/insert 4560310 5072350 0.90 *
hash_map<uint32_t, TestObject>/iteration 960117 495354 1.94 *
hash_map<uint32_t, TestObject>/operator[] 1872830 1890595 0.99
heap (uint32_t[])/make_heap 3528418 3327257 1.06
heap (uint32_t[])/pop_heap 63243859 61011853 1.04
heap (uint32_t[])/push_heap 11602424 10045869 1.15 *
heap (uint32_t[])/sort_heap 52965362 48744729 1.09
heap (vector<TestObject>)/make_heap 13191456 13089711 1.01
heap (vector<TestObject>)/pop_heap 148555656 144787742 1.03
heap (vector<TestObject>)/push_heap 28696689 26618830 1.08
heap (vector<TestObject>)/sort_heap 112473989 114018643 0.99
list<TestObject>/ctor(it) 80186731 74006287 1.08
list<TestObject>/ctor(n) 6232311 6128007 1.02
list<TestObject>/erase 344556374 212877808 1.62 *
list<TestObject>/find 39859075 14591347 2.73 *
list<TestObject>/insert 86935153 56138233 1.55 *
list<TestObject>/push_back 79569180 46700641 1.70 *
list<TestObject>/remove 785786758 324201016 2.42 *
list<TestObject>/reverse 45248186 24852759 1.82 *
list<TestObject>/size/1 219844 219496 1.00
list<TestObject>/size/10 519563 519579 1.00 EASTL intentionally implements list::size as O(n).
list<TestObject>/size/100 4567194 101230266 0.05 * EASTL intentionally implements list::size as O(n).
list<TestObject>/splice 68321087 23601687 2.89 *
map<TestObject, uint32_t>/clear 168011 180540 0.93
map<TestObject, uint32_t>/count 4830439 5139287 0.94
map<TestObject, uint32_t>/equal_range 8700090 6158531 1.41 *
map<TestObject, uint32_t>/erase/key 6696776 4617038 1.45 *
map<TestObject, uint32_t>/erase/pos 309273 333183 0.93
map<TestObject, uint32_t>/erase/range 137419 136068 1.01
map<TestObject, uint32_t>/find 4773498 4931352 0.97
map<TestObject, uint32_t>/insert 9651877 9311699 1.04
map<TestObject, uint32_t>/iteration 372946 416364 0.90 *
map<TestObject, uint32_t>/lower_bound 4784234 4915797 0.97
map<TestObject, uint32_t>/operator[] 5040254 5183147 0.97
map<TestObject, uint32_t>/upper_bound 4724292 4915984 0.96
set<uint32_t>/clear 165300 173289 0.95
set<uint32_t>/count 4958654 4885086 1.02
set<uint32_t>/equal_range 8434134 5698681 1.48 *
set<uint32_t>/erase range 145554 133960 1.09
set<uint32_t>/erase/pos 299914 324760 0.92
set<uint32_t>/erase/val 6506155 4335034 1.50 *
set<uint32_t>/find 4866879 4556043 1.07
set<uint32_t>/insert 8340523 8957257 0.93
set<uint32_t>/iteration 294465 343442 0.86 *
set<uint32_t>/lower_bound 4548095 4756498 0.96
set<uint32_t>/upper_bound 4559196 4521498 1.01
sort/q_sort/TestObject[] 7316766 7013894 1.04
sort/q_sort/TestObject[]/sorted 1668439 1332885 1.25 *
sort/q_sort/vector<TestObject> 7331530 7017260 1.04
sort/q_sort/vector<TestObject>/sorted 1601629 1247120 1.28 *
sort/q_sort/vector<ValuePair> 7071643 7067869 1.00
sort/q_sort/vector<ValuePair>/sorted 2136390 1703799 1.25 *
sort/q_sort/vector<uint32> 3292891 2943627 1.12 *
sort/q_sort/vector<uint32>/sorted 653693 473612 1.38 *
string<char16_t>/compare 356579259 432760228 0.82 *
string<char16_t>/erase/pos,n 3430422 3428645 1.00
string<char16_t>/find/p,pos,n 229263402 225830975 1.02
string<char16_t>/find_first_not_of/p,pos,n 187391 81404 2.30 *
string<char16_t>/find_first_of/p,pos,n 4411831 4413532 1.00
string<char16_t>/find_last_of/p,pos,n 731655 726155 1.01
string<char16_t>/insert/pos,p 3408628 3319726 1.03
string<char16_t>/iteration 309993861 310333547 1.00
string<char16_t>/operator[] 580839 579904 1.00
string<char16_t>/push_back 3983338 2975553 1.34 *
string<char16_t>/replace/pos,n,p,n 4361095 4211504 1.04
string<char16_t>/reserve 935141729 247010 100.00 *
string<char16_t>/rfind/p,pos,n 248956 223397 1.11 *
string<char16_t>/size 13311 13107 1.02
string<char16_t>/swap 519129 579445 0.90 *
string<char8_t>/compare 76695559 76828015 1.00
string<char8_t>/erase/pos,n 1951566 1947282 1.00
string<char8_t>/find/p,pos,n 185878944 185605039 1.00
string<char8_t>/find_first_not_of/p,pos,n 196877 81600 2.41 *
string<char8_t>/find_first_of/p,pos,n 4147685 4145356 1.00
string<char8_t>/find_last_of/p,pos,n 605897 598222 1.01
string<char8_t>/insert/pos,p 1781592 1768264 1.01
string<char8_t>/iteration 921502 921272 1.00
string<char8_t>/operator[] 361250 359873 1.00
string<char8_t>/push_back 3363288 2530493 1.33 *
string<char8_t>/replace/pos,n,p,n 2682600 2633130 1.02
string<char8_t>/reserve 672517501 78387 100.00 *
string<char8_t>/rfind/p,pos,n 226202 200013 1.13 *
string<char8_t>/size 11280 11109 1.02
string<char8_t>/swap 519393 559759 0.93
vector<uint64>/erase 55184856 55192217 1.00
vector<uint64>/insert 56764267 55682726 1.02
vector<uint64>/iteration 423122 424039 1.00
vector<uint64>/operator[] 1189397 860991 1.38 *
vector<uint64>/push_back 5626609 4027317 1.40 *
vector<uint64>/sort 49227036 49231362 1.00
```
----------------------------------------------
End of document

749
doc/BestPractices.md Normal file
View File

@@ -0,0 +1,749 @@
# EASTL Best Practices
In 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.
## Summary
The descriptions here are intentionally terse; this is to make them easier to visually scan.
1. [Consider intrusive containers.](#consider-intrusive-containers)
2. [Consider fixed-size containers.](#consider-fixed-size-containers)
3. [Consider custom allocators.](#consider-custom-allocators)
4. [Consider hash tables instead of maps.](#consider-hash-tables-instead-of-maps)
5. [Consider a vector_map (a.k.a. sorted vector) for unchanging data.](#consider-a-vector_map-aka-sorted-vector-for-unchanging-data)
6. [Consider slist instead of list.](#consider-slist-instead-of-list)
7. [Avoid redundant end() and size() in loops.](#avoid-redundant-end-and-size-in-loops)
8. [Iterate containers instead of using operator\[\].](#iterate-containers-instead-of-using-operator)
9. [Learn to use the string class appropriately.](#learn-to-use-the-string-class-appropriately)
10. [Cache list size if you want size() to be O(1).](#cache-list-size-if-you-want-listsize-to-be-o1)
11. [Use empty() instead of size() when possible.](#use-empty-instead-of-size-when-possible)
12. [Know your container efficiencies.](#know-your-container-efficiencies)
13. [Use vector::reserve.](#use-vectorreserve)
14. [Use vector::set_capacity to trim memory usage.](#use-vectorset_capacity-to-trim-memory-usage)
15. [Use swap() instead of a manually implemented version.](#use-swap-instead-of-a-manually-implemented-version)
16. [Consider storing pointers instead of objects.](#consider-storing-pointers-instead-of-objects)
17. [Consider smart pointers instead of raw pointers.](#consider-smart-pointers-instead-of-raw-pointers)
18. [Use iterator pre-increment instead of post-increment.](#use-iterator-pre-increment-instead-of-post-increment)
19. [Make temporary references so the code can be traced/debugged.](#make-temporary-references-so-the-code-can-be-traceddebugged)
20. [Consider bitvector or bitset instead of vector\<bool>.](#consider-bitvector-or-bitset-instead-of-vector)
21. [Vectors can be treated as contiguous memory.](#vectors-can-be-treated-as-contiguous-memory)
22. [Search hash_map\<string> via find_as() instead of find().](#search-hash_map-via-find_as-instead-of-find)
23. [Take advantage of type_traits (e.g. EASTL_DECLARE_TRIVIAL_RELOCATE).](#take-advantage-of-type_traits-eg-eastl_declare_trivial_relocate)
24. [Name containers to track memory usage.](#name-containers-to-track-memory-usage)
25. [Learn the algorithms.](#learn-the-algorithms)
26. [Pass and return containers by reference instead of value.](#pass-and-return-containers-by-reference-instead-of-value)
27. [Consider using reset() for fast container teardown.](#consider-using-reset-for-fast-container-teardown)
28. [Consider using fixed_substring instead of copying strings.](#consider-using-fixed_substring-instead-of-copying-strings)
29. [Consider using vector::push_back(void).](#consider-using-vectorpush_backvoid)
## Detail
### Consider intrusive containers.
Intrusive 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.
To create an intrusive_list container, you can use the following code:
```cpp
class Widget : public intrusive_list_node
{ };
intrusive_list<Widget> widgetList;
widgetList.push_back(someWidget);
```
### Consider fixed-size containers.
Fixed-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."
EASTL fixed containers include:
* fixed_list
* fixed_slist
* fixed_vector
* fixed_string
* fixed_map
* fixed_multimap
* fixed_set
* fixed_multiset
* fixed_hash_map
* fixed_hash_multimap
* fixed_hash_set
* fixed_hash_multiset
To create a fixed_set, you can use the following code:
```cpp
fixed_set<int, 25> intSet; // Create a set capable of holding 250 elements.
intSet.push_back(37);
```
### Consider custom allocators.
While 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.
To create a list container that uses your custom allocator and uses block naming, you can use the following code:
```cpp
list<int> intList(pSomeAllocator, "graphics/intList");
intList.push_back(37);
```
### Consider hash tables instead of maps.
Hash 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.
To make a hash_map (dictionary) of integers to strings, you can use the following code:
```cpp
hash_map<int, const char*> stringTable;
stringTable[37] = "hello";
```
### Consider a vector_map (a.k.a. sorted vector) for unchanging data.
You 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.
To make a vector_set, you can use the following code:
```cpp
vector_set<int> intSet(16); // Create a vector_set with an initial capacity of 16.
intSet.insert(37);
```
Note that you can use containers other than vector to implement vector_set. Here's how you do it with deque:
```cpp
vector_set<int, less<int>, EASTLAllocatorType, deque<int> > intSet;
intSet.insert(37);
```
### Consider slist instead of list.
An 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.
To make an slist, you can use the following code:
```cpp
slist<int> intSlist;
intSlist.push_front(37);
```
### Avoid redundant end() and size() in loops.
Instead of writing code like this:
```cpp
for(deque<int>::iterator it = d.begin(); it != d.end(); ++it)
...
```
write code like this:
```cpp
for(deque<int>::iterator it = d.begin(), itEnd = d.end(); it != itEnd; ++it)
...
```
The 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.
| Constant begin | Non-constant begin | Constant end | Non-constant end |
|------|------|------|------|
| 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 |
* <sup>1</sup> Arrays can be neither resized nor reallocated.
* <sup>2</sup> Constant end if the hashtable can't/won't re-hash. Non-constant if it can re-hash.
### Iterate containers instead of using operator[].
It's faster to iterate random access containers via iterators than via operator[], though operator[] usage may look simpler.
Instead of doing this:
```cpp
for(unsigned i = 0, iEnd = intVector.size(); i != iEnd; ++i)
intVector[i] = 37;
```
you can execute more efficiently by doing this:
```cpp
for(vector<int>::iterator it = intVector.begin(), itEnd = intVector.end(); it != itEnd; ++it)
*it = 37;
```
### Learn to use the string class appropriately.
Oddly 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.
Here we provide a table of actual collected examples of things done and how they could have been done instead.
| What was written | What could have been written |
|------|------|
| `s = s.Left(i) + '+' + s.Right(s.length() - i - 1);` | `s[i] = '+';` |
| `string s(""); // This is the most commonly found misuse.` | `string s;` |
| `s = "";` | `s.clear();` |
| `s.c_str()[0] = 'u';` | `s[0] = 'u';` |
| `len = strlen(s.c_str());` | `len = s.length();` |
| `s = string("u");` | `s = "u";` |
| `puts(s + string("u"));` | `puts(s + "u");` |
| `string s(" ");`<br> `puts(s.c_str());` | `puts(" ");` |
| `s.sprintf("u");` | s = "u";` |
| `char array[32];`<br> `sprintf(array, "%d", 10);`<br> `s = string(array);` | `s.sprintf("%d", 10);` |
The 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.
### Cache list size if you want list::size() to be O(1).
EASTL'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.
Here's an example of caching the list size manually:
```cpp
list<int> intList;
size_t n = 0;
intList.push_back(37);
++n;
intList.pop_front();
--n;
```
### Use empty() instead of size() when possible.
All 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.
### Know your container efficiencies.
The 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.
| Container | empty() efficiency | size() efficiency | operator[] efficiency | insert() efficiency | erase() efficiency | find() efficiency | sort efficiency |
|------|------|------|------|------|------|------|------|
| slist | 1 | O(n) | - | O(1) | O(1) | O(n) | O(n+) |
| list | 1 | n | - | 1 | 1 | n | n log(n) |
| intrusive_slist | 1 | n | - | 1 | 1 | 1 | n+ |
| intrusive_list | 1 | n | - | 1 | 1 | 1 | n log(n) |
| array | 1 | 1 | 1 | - | - | n | n log(n) |
| vector | 1 | 1<sup>a</sup> | 1 | 1 at end, else n | 1 at end, else n | n | n log(n) |
| vector_set | 1 | 1<sup>a</sup> | 1 | 1 at end, else n | 1 at end, else n | log(n) | 1 |
| vector_multiset | 1 | 1<sup>a</sup> | 1 | 1 at end, else n | 1 at end, else n | log(n) | 1 |
| vector_map | 1 | 1<sup>a</sup> | 1 | 1 at end, else n | 1 at end, else n | log(n) | 1 |
| vector_multimap | 1 | 1<sup>a</sup> | 1 | 1 at end, else n | 1 at end, else n | log(n) | 1 |
| 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) |
| bit_vector | 1 | 1<sup>a</sup> | 1 | 1 at end, else n | 1 at end, else n | n | n log(n) |
| string, cow_string | 1 | 1<sup>a</sup> | 1 | 1 at end, else n | 1 at end, else n | n | n log(n) |
| set | 1 | 1 | - | log(n) | log(n) | log(n) | 1 |
| multiset | 1 | 1 | - | log(n) | log(n) | log(n) | 1 |
| map | 1 | 1 | log(n) | log(n) | log(n) | log(n) | 1 |
| multimap | 1 | 1 | - | log(n) | log(n) | log(n) | 1 |
| hash_set | 1 | 1 | - | 1 | 1 | 1 | - |
| hash_multiset | 1 | 1 | - | 1 | 1 | 1 | - |
| hash_map | 1 | 1 | - | 1 | 1 | 1 | - |
| hash_multimap | 1 | 1 | - | 1 | 1 | 1 | - |
| intrusive_hash_set | 1 | 1 | - | 1 | 1 | 1 | - |
| intrusive_hash_multiset | 1 | 1 | - | 1 | 1 | 1 | - |
| intrusive_hash_map | 1 | 1 | - | 1 | 1 | 1 | - |
| intrusive_hash_multimap | 1 | 1 | - | 1 | 1 | 1 | - |
Notes:
* \- means that the operation does not exist.
* 1 means amortized constant time. Also known as O(1)
* n means time proportional to the container size. Also known as O(n)
* log(n) means time proportional to the natural logarithm of the container size. Also known as O(log(n))
* n log(n) means time proportional to log(n) times the size of the container. Also known as O(n log(n))
* n+ means that the time is at least n, and possibly higher.
* 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.
* 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).
* <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.
### Use vector::reserve.
You 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.
Here's how you could specify reserved capacity in a vector:
```cpp
vector<Widget> v(37); // Reserve space to hold up to 37 items.
or
vector<Widget> v; // This empty construction causes to memory to be allocated or reserved.
v.reserve(37);
```
The EASTL vector (and string) implementation looks like this:
```cpp
template <typename T>
class vector {
T* mpBegin; // Beginning of used element memory.
T* mpEnd; // End of used element memory.
T* mpCapacity; // End of storage capacity. Is >= mpEnd
}
```
Another approach to being efficient with vector memory usage is to use fixed_vector.
### Use vector::set_capacity to trim memory usage.
A 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.
An example of reducing a vector is the following:
```cpp
vector<Widget> v;
...
v.set_capacity();
```
An example of resizing to zero and completely freeing the memory of a vector is the following:
```cpp
vector<Widget> v;
...
v.set_capacity(0);
```
### Use swap() instead of a manually implemented version.
The 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.
### Consider storing pointers instead of objects.
There 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.
### Consider smart pointers instead of raw pointers.
If 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.
Here is an example of creating and using a shared_ptr:
```cpp
typedef shared_ptr<Widget> WPtr;
list<WPtr> wList;
wList.push_back(WPtr(new Widget)); // The user may have operator new/delete overrides.
wList.pop_back(); // Implicitly deletes the Widget.
```
Here is an example of creating and using a shared_ptr that uses a custom allocation and deallocation mechanism:
```cpp
typedef shared_ptr<Widget, EASTLAllocatorType, WidgetDelete> WPtr; // WidgetDelete is a custom destroyer.
list<WPtr> wList;
wList.push_back(WPtr(WidgetCreate(Widget))); // WidgetCreate is a custom allocator.
wList.pop_back(); // Implicitly calls WidgetDelete.
```
### Use iterator pre-increment instead of post-increment.
Pre-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.
EASTL 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.
Here is an example of using iterator pre-increment; for loops like this should always use pre-increment:
```cpp
for(set<int>::iterator it(intSet.begin()), itEnd(intSet.end()); it != itEnd; ++it)
*it = 37;
```
### Make temporary references so the code can be traced/debugged.
Users 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.
Instead of doing this:
```cpp
for(list<Widget>::iterator it = wl.begin(), itEnd = wl.end(); it != itEnd; ++it) {
(*it).x = 37;
(*it).y = 38;
(*it).z = 39;
}
```
Consider doing this:
```cpp
for(list<Widget>::iterator it = wl.begin(), itEnd = wl.end(); it != itEnd; ++it) {
Widget& w = *it; // The user can easily inspect or modify w here.
w.x = 37;
w.y = 38;
w.z = 39;
}
```
### Consider bitvector or bitset instead of vector<bool>.
In 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.
Additionally 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.
### Vectors can be treated as contiguous memory.
EASTL 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].
To use a vector as a pointer to an array, you can use the following code:
```cpp
struct Widget {
uint32_t x;
uint32_t y;
};
vector<Widget> v;
quick_sort((uint64_t*)v.data(), (uint64_t*)(v.data() + v.size()));
```
### Search hash_map<string> via find_as() instead of find().
EASTL 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.
To use find_as, you can use the following code:
```cpp
hash_map<string, int> hashMap;
hash_map<string, int>::iterator it = hashMap.find_as("hello"); // Using default hash and compare.
```
### Take advantage of type_traits (e.g. EASTL_DECLARE_TRIVIAL_RELOCATE).
EASTL 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.
There are three primary uses of type traits:
* Allowing for optimized operations on some data types.
* Allowing for different logic pathways based on data types.
* Allowing for compile-type assertions about data type expectations.
Most 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.
Here is an example of using type traits to tell if a value is a floating point value or not:
```cpp
template <typename T>
DoSomething(T t) {
assert(is_floating_point<T>::value);
}
```
Here is an example of declaring a class as relocatable and using it in a vector.
```cpp
EASTL_DECLARE_TRIVIAL_RELOCATE(Widget); // Usually you put this at the Widget class declaration.
vector<Widget> wVector;
wVector.erase(wVector.begin()); // This operation will be optimized via using memcpy.
```
The 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.
* is_void
* is_integral
* is_floating_point
* is_arithmetic
* is_fundamental
* is_const
* is_volatile
* is_abstract
* is_signed
* is_unsigned
* is_array
* is_pointer
* is_reference
* is_member_object_pointer
* is_member_function_pointer
* is_member_pointer
* is_enum
* is_union
* is_class
* is_polymorphic
* is_function
* is_object
* is_scalar
* is_compound
* is_same
* is_convertible
* is_base_of
* is_empty
* is_pod
* is_aligned
* has_trivial_constructor
* has_trivial_copy
* has_trivial_assign
* has_trivial_destructor
* has_trivial_relocate1
* has_nothrow_constructor
* has_nothrow_copy
* has_nothrow_assign
* has_virtual_destructor
* alignment_of
* rank
* extent
*
<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.
### Name containers to track memory usage.
All 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.
Here is an example of creating a list and naming it "collision list":
`list<CollisionData> collisionList(allocator("collision list"));`
or
```cpp
list<CollisionData> collisionList;
collisionList.get_allocator().set_name("collision list");
```
Note 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.
### Learn the algorithms.
EASTL 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.
The 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.
**Search**
* find, find_if
* find_end
* find_first_of
* adjacent_find
* binary_search
* search, search_n
* lower_bound
* upper_bound
* equal_range
**Sort**
* is_sorted
* quick_sort
* insertion_sort
* shell_sort
* heap_sort
* merge_sort, merge_sort_buffer
* merge
* inplace_merge
* partial_sort
* stable_sort
* partial_sort_copy
* <other sort functions found in the EASTL bonus directories>
**Modifying**
* fill, fill_n
* generate, generate_n
* random_shuffle
* swap
* iter_swap
* swap_ranges
* remove, remove_if
* remove_copy, remove_copy_if
* replace, replace_if
* replace_copy, replace_copy_if
* reverse
* reverse_copy
* rotate
* rotate_copy
* partition
* stable_partition
* transform
* next_permutation
* prev_permutation
* unique
* unique_copy
**Non-Modifying**
* for_each
* copy
* copy_backward
* count, count_if
* equal
* mismatch
* min
* max
* min_element
* max_element
* lexicographical_compare
* nth_element
**Heap**
* is_heap
* make_heap
* push_heap
* pop_heap
* change_heap
* sort_heap
* remove_heap
**Set**
* includes
* set_difference
* set_symmetric_difference
* set_intersection
* set_union
### Pass and return containers by reference instead of value.
If you aren't paying attention you might accidentally write code like this:
```cpp
void DoSomething(list<Widget> widgetList) {
...
}
```
The 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.
### Consider using reset() for fast container teardown.
EASTL 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).
Here's an example of usage of the reset function and a PPMalloc-like StackAllocator:
```cpp
pStackAllocator->push_bookmark();
hash_set<Widget, less<Widget>, StackAllocator> wSet(pStackAllocator);
<use wSet>
wSet.reset();
pStackAllocator->pop_bookmark();
```
### Consider using fixed_substring instead of copying strings.
EASTL 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.
Here's an example of usage of fixed_substring:
```cpp
basic_string<char> str("hello world");
fixed_substring<char> sub(str, 6, 5); // sub == "world"
fixed_substring can refer to any character array and not just one that derives from a string object.
```
### Consider using vector::push_back(void).
EASTL provides an alternative way to insert elements into containers that avoids copy construction and/or the creation of temporaries. Consider the following code:
```cpp
vector<Widget> widgetArray;
widgetArray.push_back(Widget());
```
The 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:
```cpp
vector<Widget> widgetArray;
widgetArray.push_back();
widgetArray.back().x = 0; // Example of how to reference the new object.
```
Other containers with such copy-less functions include:
```cpp
vector::push_back()
deque::push_back()
deque::push_front()
list::push_back()
list::push_front()
slist::push_front()
map::insert(const key_type& key)
multimap::insert(const key_type& key)
hash_map::insert(const key_type& key)
hash_multimap::insert(const key_type& key)
```
Note 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.
----------------------------------------------
End of document

374
doc/Design.md Normal file
View File

@@ -0,0 +1,374 @@
# EASTL Design
## Introduction
EASTL (EA Standard Template Library) is designed to be a template library which encompasses and extends the functionality of standard C++ STL while improving it in various ways useful to game development. Much of EASTL's design is identical to standard STL, as the large majority of the STL is well-designed for many uses. The primary areas where EASTL deviates from standard STL implementations are essentially the following:
* EASTL has a simplified and more flexible custom allocation scheme.
* EASTL has significantly easier to read code.
* EASTL has extension containers and algorithms.
* EASTL has optimizations designed for game development.
Of the above items, the only one which is an incompatible difference with STL is the case of memory allocation. The method for defining a custom allocator for EASTL is slightly different than that of standard STL, though they are 90% similar. The 10% difference, however, is what makes EASTL generally easier and more powerful to work with than standard STL. Containers without custom allocators act identically between EASTL and standard STL.
## Motivations
Our motifications for making EASTL drive the design of EASTL. As identified in the EASTL RFC (Request for Comment), the primary reasons for implementing a custom version of the STL are:
* <span class="458151900-03082005"><font><font>Some STL implementations (especially Microsoft STL) have inferior performance characteristics that make them unsuitable for game development. EASTL is faster than all existing STL implementations.</font></font></span>
* The STL is sometimes hard to debug, as most STL implementations use cryptic variable names and unusual data structures.
* STL allocators are sometimes painful to work with, as they have many requirements and cannot be modified once bound to a container.
* The STL includes excess functionality that can lead to larger code than desirable. It's not very easy to tell programmers they shouldn't use that functionality.
* The STL is implemented with very deep function calls. This results is unacceptable performance in non-optimized builds and sometimes in optimized builds as well.
* The STL doesn't support alignment of contained objects.
* STL containers won't let you insert an entry into a container without supplying an entry to copy from. This can be inefficient.
* Useful STL extensions (e.g. slist, hash_map, shared_ptr) found in existing STL implementations such as STLPort are not portable because they don't exist in other versions of STL or aren't consistent between STL versions.
* The STL lacks useful extensions that game programmers find useful (e.g. intrusive_list) but which could be best optimized in a portable STL environment.
* The STL has specifications that limit our ability to use it efficiently. For example, STL vectors are not guaranteed to use contiguous memory and so cannot be safely used as an array.
* The STL puts an emphasis on correctness before performance, whereas sometimes you can get significant performance gains by making things less academcially pure.
* STL containers have private implementations that don't allow you to work with their data in a portable way, yet sometimes this is an important thing to be able to do (e.g. node pools).
* All existing versions of STL allocate memory in empty versions of at least some of their containers. This is not ideal and prevents optimizations such as container memory resets that can greatly increase performance in some situations.
* The STL is slow to compile, as most modern STL implementations are very large.
* There are legal issues that make it hard for us to freely use portable STL implementations such as STLPort.
* We have no say in the design and implementation of the STL and so are unable to change it to work for our needs.
## Prime Directives
The implementation of EASTL is guided foremost by the following directives which are listed in order of importance.
1. Efficiency (speed and memory usage)
2. Correctness
3. Portability
4. Readability
Note that unlike commercial STL implementations which must put correctness above all, we put a higher value on efficiency. As a result, some functionality may have some usage limitation that is not present in other similar systems but which allows for more efficient operation, especially on the platforms of significance to us.
Portability is significant, but not critical. Yes, EASTL must compile and run on all platforms that we will ship games for. But we don't take that to mean under all compilers that could be conceivably used for such platforms. For example, Microsoft VC6 can be used to compile Windows programs, but VC6's C++ support is too weak for EASTL and so you simply cannot use EASTL under VC6.
Readability is something that EASTL achieves better than many other templated libraries, particularly Microsoft STL and STLPort. We make every attempt to make EASTL code clean and sensible. Sometimes our need to provide optimizations (particularly related to type_traits and iterator types) results in less simple code, but efficiency happens to be our prime directive and so it overrides all other considerations.
## Thread Safety
It's not simple enough to simply say that EASTL is thread-safe or thread-unsafe. However, we can say that with respect to thread safety that EASTL does the right thing.
Individual EASTL containers are not thread-safe. That is, access to an instance of a container from multiple threads at the same time is unsafe if any of those accesses are modifying operations. A given container can be read from multiple threads simultaneously as well as any other standalone data structure. If a user wants to be able to have modifying access an instance of a container from multiple threads, it is up to the user to ensure that proper thread synchronization occurs. This usually means using a mutex.
EASTL classes other than containers are the same as containers with respect to thread safety. EASTL functions (e.g. algorithms) are inherently thread-safe as they have no instance data and operate entirely on the stack. As of this writing, no EASTL function allocates memory and thus doesn't bring thread safety issues via that means.
The user may well need to be concerned about thread safety with respect to memory allocation. If the user modifies containers from multiple threads, then allocators are going to be accessed from multiple threads. If an allocator is shared across multiple container instances (of the same type of container or not), then mutexes (as discussed above) the user uses to protect access to indivudual instances will not suffice to provide thread safety for allocators used across multiple instances. The conventional solution here is to use a mutex within the allocator if it is exected to be used by multiple threads.
EASTL uses neither static nor global variables and thus there are no inter-instance dependencies that would make thread safety difficult for the user to implement.
## Container Design
All EASTL containers follow a set of consistent conventions. Here we define the prototypical container which has the minimal functionality that all (non-adapter) containers must have. Some containers (e.g. stack) are explicitly adapter containers and thus wrap or inherit the properties of the wrapped container in a way that is implementation specific.
```cpp
template <class T, class Allocator =
EASTLAllocator>
class container
{
public:
typedef container<T, Allocator> this_type;
typedef
T
value_type;
typedef T*
pointer;
typedef const T*
const_pointer;
typedef
T& reference;
typedef const
T& const_reference;
typedef
ptrdiff_t difference_type;
typedef
impl_defined size_type;
typedef impl-defined
iterator;
typedef impl-defined
const_iterator;
typedef reverse_iterator<iterator> reverse_iterator;
typedef reverse_iterator<const_iterator> reverse_const_iterator;
typedef Allocator
allocator_type;
public:
container(const
allocator_type& allocator = allocator_type());
container(const this_type&
x);
this_type&
operator=(this_type& x);
void swap(this_type& x);
void reset();
allocator_type& get_allocator();
void set_allocator(allocator_type& allocator);
iterator begin();
const_iterator begin() const;
iterator end();
const_iterator end() const;
bool validate() const;
int validate_iterator(const_iterator i)
const;
protected:
allocator_type mAllocator;
};
template <class T, class
Allocator>
bool operator==(const container<T, Allocator>& a, const container<T, Allocator>& b);
template <class T, class
Allocator>
bool operator!=(const container<T, Allocator>& a, const
container<T, Allocator>&
b);
```
Notes:
* Swapped containers do not swap their allocators.
* Newly constructed empty containers do no memory allocation. Some STL and other container libraries allocate an initial node from the class memory allocator. EASTL containers by design never do this. If a container needs an initial node, that node should be made part of the container itself or be a static empty node object.
* Empty containers (new or otherwise) contain no constructed objects, including those that might be in an 'end' node. Similarly, no user object (e.g. of type T) should be constructed unless required by the design and unless documented in the cotainer/algorithm contract. 
* The reset function is a special extension function which unilaterally resets the container to an empty state without freeing the memory of the contained objects. This is useful for very quickly tearing down a container built into scratch memory. No memory is allocated by reset, and the container has no allocatedmemory after the reset is executed.
* The validate and validate_iterator functions provide explicit container and iterator validation. EASTL provides an option to do implicit automatic iterator and container validation, but full validation (which can be potentially extensive) has too much of a performance cost to execute implicitly, even in a debug build. So EASTL provides these explicit functions which can be called by the user at the appropriate time and in optimized builds as well as debug builds.
## Allocator Design
The most significant difference between EASTL and standard C++ STL is that standard STL containers are templated on an allocator class with the interface defined in std::allocator. std::allocator is defined in the C++ standard as this:
```cpp
// Standard C++ allocator
template <class T>
class allocator
{
public:
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef T&
reference;
typedef const
T& const_reference;
typedef T value_type;
template <class U>
struct rebind { typedef allocator<U> other; };
allocator() throw();
allocator(const allocator&) throw();
template <class U>
allocator(const allocator<U>&) throw();
~allocator()
throw();
pointer
address(reference x) const;
const_pointer address(const_reference x)
const;
pointer allocate(size_type, typename
allocator<void>::const_pointer hint = 0);
void deallocate(pointer p,
size_type n);
size_type max_size() const
throw();
void construct(pointer p,
const T& val);
void destroy(pointer
p);
};
```
Each STL container needs to have an allocator templated on container type T associated with it. The problem with this is that allocators for containers are defined at the class level and not the instance level. This makes it painful to define custom allocators for containers and adds to code bloat. Also, it turns out that the containers don't actually use allocator<T> but instead use allocator\<T>::rebind\<U>::other. Lastly, you cannot access this allocator after the container is constructed. There are some good academic reasons why the C++ standard works this way, but it results in a lot of unnecessary pain and makes concepts like memory tracking much harder to implement.
What EASTL does is use a more familiar memory allocation pattern whereby there is only one allocator class interface and it is used by all containers. Additionally EASTL containers let you access their allocators and query them, name them, change them, etc.
EASTL has chosen to make allocators not be copied between containers during container swap and assign operations. This means that if container A swaps its contents with container B, both containers retain their original allocators. Similarly, assigning container A to container B causes container B to retain its original allocator. Containers that are equivalent should report so via operator==; EASTL will do a smart swap if allocators are equal, and a brute-force swap otherwise.
```cpp
// EASTL allocator
class allocator
{
public:
    allocator(const char* pName = NULL);
    void* allocate(size_t n, int flags = 0);
    void* allocate(size_t n, size_t alignment, size_t offset, int flags = 0);
    void  deallocate(void* p, size_t n);
    const char* get_name() const;
    void        set_name(const char* pName);
};
allocator* GetDefaultAllocator();
```
## Fixed Size Container Design
EASTL supplies a set of fixed-size containers that the user can use, though the user can also implement their own versions. So in addition to class list there is class fixed_list. The fixed_list class implements a linked list via a fixed-size pool of contiguous memory which has no space overhead (unlike with a regular heap), doesn't cause fragmentation, and allocates very quickly.
EASTL implements fixed containers via subclasses of regular containers which set the regular container's allocator to point to themselves. Thus the implementation for fixed_list is very tiny and consists of little more than constructor and allocator functions. This design has some advantages but has one small disadvantage. The primary advantages are primarily that code bloat is reduced and that the implementation is simple and the user can easily extend it. The primary disadvantage is that the parent list class ends up with a pointer to itself and thus has 4 bytes that could arguably be saved if system was designed differently. That different design would be to make the list class have a policy template parameter which specifies that it is a fixed pool container. EASTL chose not to follow the policy design because it would complicate the implementation, make it harder for the user to extend the container, and would potentially waste more memory due to code bloat than it would save due to the 4 byte savings it achieves in container instances.
## Algorithm Design
EASTL algorithms very much follow the philosophy of standard C++ algorithms, as this philosophy is sound and efficient. One of the primary aspects of algorithms is that they work on iterators and not containers. You will note for example that the find algorithm takes a first and last iterator as arguments and not a container. This has two primary benefits: it allows the user to specify a subrange of the container to search within and it allows the user to apply the find algorithm to sequences that aren't containers (e.g. a C array).
EASTL algorithms are optimized at least as well as the best STL algorithms found in commercial libraries and are significantly optimized over the algorithms that come with the first-party STLs that come with compilers. Most significantly, EASTL algorithms take advantage of type traits of contained classes and take advantage of iterator types to optimize code generation. For example, if you resize an array of integers (or other "pod" type), EASTL will detect that this can be done with a memcpy instead of a slow object-by-object move as would Micrsoft STL.
The optimizations found in EASTL algorithms and the supporting code in EASTL type traits consistts of some fairly tricky advanced C++ and while it is fairly easy to read, it requires a C++ expert (language lawyer, really) to implement confidently. The result of this is that it takes more effort to develop and maintain EASTL than it would to maintain a simpler library. However, the performance advantages have been deemed worth the tradeoff.
## Smart Pointer Design
EASTL implements the following smart pointer types:
* shared_ptr
* shared_array
* weak_ptr
* instrusive_ptr
* scoped_ptr
* scoped_array
* linked_ptr
* linked_array
All but linked_ptr/linked_array are well-known smart pointers from the Boost library. The behaviour of these smart pointers is very similar to those from Boost with two exceptions:
* EASTL smart pointers allow you to assign an allocator to them.
* EASTL shared_ptr implements deletion via a templated parameter instead of a dynamically allocated virtual member object interface.
With respect to assigning an allocator, this gives EASTL more control over memory allocation and tracking, as Boost smart pointers unilaterally use global operator new to allocate memory from the global heap.
With respect to shared_ptr deletion, EASTL's current design of using a templated parameter is questionable, but does have some reason. The advantage is that EASTL avoids a heap allocation, avoids virtual function calls, and avoids templated class proliferation. The disadvantage is that EASTL shared_ptr containers which hold void pointers can't call the destructors of their contained objects unless the user manually specifies a custom deleter template parameter. This is case whereby EASTL is more efficient but less safe. We can revisit this topic in the future if it becomes an issue.
## list::size is O(n)
As of this writing, EASTL has three linked list classes: list, slist, and intrusive_list. In each of these classes, the size of the list is not cached in a member size variable. The result of this is that getting the size of a list is not a fast operation, as it requires traversing the list and counting the nodes. We could make the list::size function be fast by having a member mSize variable which tracks the size as we insert and delete items. There are reasons for having such functionality and reasons for not having such functionality. We currently choose to not have a member mSize variable as it would add four bytes to the class, add a tiny amount of processing to functions such as insert and erase, and would only serve to improve the size function, but no others. In the case of intrusive_list, it would do additional harm. The alternative argument is that the C++ standard states that std::list should be an O(1) operation (i.e. have a member size variable), that many C++ standard library list implementations do so, that the size is but an integer which is quick to update, and that many users expect to have a fast size function. In the final analysis, we are developing a library for game development and performance is paramount, so we choose to not cache the list size. The user can always implement a size cache himself.
## basic_string doesn't use copy-on-write
The primary benefit of CoW is that it allows for the sharing of string data between two string objects. Thus if you say this:
```cpp
string a("hello");
string b(a);
```
the "hello" will be shared between a and b. If you then say this:
```cpp
a = "world";
```
then `a` will release its reference to "hello" and leave b with the only reference to it. Normally this functionality is accomplished via reference counting and with atomic operations or mutexes.
The C++ standard does not say anything about basic_string and CoW. However, for a basic_string implementation to be standards-conforming, a number of issues arise which dictate some things about how one would have to implement a CoW string. The discussion of these issues will not be rehashed here, as you can read the references below for better detail than can be provided in the space we have here. However, we can say that the C++ standard is sensible and that anything we try to do here to allow for an efficient CoW implementation would result in a generally unacceptable string interface.
The disadvantages of CoW strings are:
* A reference count needs to exist with the string, which increases string memory usage.
* With thread safety, atomic operations and mutex locks are expensive, especially on weaker memory systems such as console gaming platforms.
* All non-const string accessor functions need to do a sharing check the the first such check needs to detach the string. Similarly, all string assignments need to do a sharing check as well. If you access the string before doing an assignment, the assignment doesn't result in a shared string, because the string has already been detached.
* String sharing doesn't happen the large majority of the time. In some cases, the total sum of the reference count memory can exceed any memory savings gained by the strings that share representations. 
The addition of a cow_string class is under consideration for EASTL. There are conceivably some systems which have string usage patterns which would benefit from CoW sharing. Such functionality is best saved for a separate string implementation so that the other string uses aren't penalized.
This is a good starting HTML reference on the topic:
> [http://www.gotw.ca/publications/optimizations.htm](http://www.gotw.ca/publications/optimizations.htm)
Here is a well-known Usenet discussion on the topic:
> [http://groups-beta.google.com/group/comp.lang.c++.moderated/browse_thread/thread/3dc6af5198d0bf7/886c8642cb06e03d](http://groups-beta.google.com/group/comp.lang.c++.moderated/browse_thread/thread/3dc6af5198d0bf7/886c8642cb06e03d)
----------------------------------------------
End of document

View File

@@ -1,207 +0,0 @@
****************************************************************************************
EASTL Benchmark test results
****************************************************************************************
EASTL version: 2.00.00
Platform: iPhone on ARM
Compiler: clang4.2 (clang-425.0.28)
Allocator: PPMalloc::GeneralAllocator. Thread safety enabled.
Build: Full optimization. Inlining enabled.
Values are ticks and time to complete tests; smaller values are better.
Test clang libc++ EASTL Ratio Difference?
---------------------------------------------------------------------------------------------------------------------
algorithm/adj_find/vector<TestObject> | 23905 996.0 us | 24693 1.0 ms | 0.97
algorithm/copy/vector<LargePOD> | 15740 655.8 us | 15556 648.2 us | 1.01
algorithm/copy/vector<uint32_t> | 13 541.0 ns | 481 20.0 us | 0.03 -
algorithm/copy_backward/vector<LargePOD> | 15799 658.3 us | 16415 684.0 us | 0.96
algorithm/copy_backward/vector<uint32_t> | 13 541.0 ns | 179 7.5 us | 0.07 -
algorithm/count/vector<uint64_t> | 20789 866.2 us | 20254 843.9 us | 1.03
algorithm/equal_range/vector<uint64_t> | 465548 19.4 ms | 1561757 65.1 ms | 0.30 -
algorithm/fill/bool[] | 131 5.5 us | 131 5.5 us | 1.00
algorithm/fill/char[]/'d' | 130 5.4 us | 131 5.5 us | 0.99
algorithm/fill/vector<char>/'d' | 130 5.4 us | 131 5.5 us | 0.99
algorithm/fill/vector<char>/0 | 130 5.4 us | 130 5.4 us | 1.00
algorithm/fill/vector<uint64_t> | 4385 182.7 us | 4389 182.9 us | 1.00
algorithm/fill/vector<void*> | 981 40.9 us | 967 40.3 us | 1.01
algorithm/fill_n/bool[] | 131 5.5 us | 130 5.4 us | 1.01
algorithm/fill_n/char[] | 131 5.5 us | 130 5.4 us | 1.01
algorithm/fill_n/vector<uint64_t> | 5642 235.1 us | 5641 235.0 us | 1.00
algorithm/find_end/string/end | 1516 63.2 us | 2482 103.4 us | 0.61 -
algorithm/find_end/string/middle | 11938 497.4 us | 19751 823.0 us | 0.60 -
algorithm/find_end/string/none | 24028 1.0 ms | 40080 1.7 ms | 0.60 -
algorithm/lex_cmp/schar[] | 13311 554.6 us | 1893 78.9 us | 7.03 +
algorithm/lex_cmp/vector<TestObject> | 26989 1.1 ms | 25381 1.1 ms | 1.06
algorithm/lex_cmp/vector<uchar> | 12589 524.5 us | 1897 79.0 us | 6.64 +
algorithm/lower_bound/vector<TestObject> | 942173 39.3 ms | 965947 40.2 ms | 0.98
algorithm/min_element/vector<TestObject> | 30456 1.3 ms | 28143 1.2 ms | 1.08
algorithm/rand_shuffle/vector<uint64_t> | 505834 21.1 ms | 484532 20.2 ms | 1.04
algorithm/reverse/list<TestObject> | 7400 308.3 us | 7685 320.2 us | 0.96
algorithm/reverse/vector<TestObject> | 7075 294.8 us | 7203 300.1 us | 0.98
algorithm/search/string<char> | 16694 695.6 us | 31344 1.3 ms | 0.53 -
algorithm/search_n/string<char> | 12285 511.9 us | 11817 492.4 us | 1.04
algorithm/unique/vector<TestObject> | 51594 2.1 ms | 53184 2.2 ms | 0.97
algorithm/unique/vector<uint32_t> | 12989 541.2 us | 10455 435.6 us | 1.24
algorithm/unique/vector<uint64_t> | 29810 1.2 ms | 29444 1.2 ms | 1.01
algorithm/upper_bound/vector<uint32_t> | 410610 17.1 ms | 461926 19.2 ms | 0.89
bitset<1500>/>>=/1 | 496931 20.7 ms | 433836 18.1 ms | 1.15
bitset<1500>/count | 652307 27.2 ms | 602283 25.1 ms | 1.08
bitset<1500>/flip | 342913 14.3 ms | 328031 13.7 ms | 1.05
bitset<1500>/reset | 89035 3.7 ms | 89004 3.7 ms | 1.00
bitset<1500>/set() | 90901 3.8 ms | 93871 3.9 ms | 0.97
bitset<1500>/set(i) | 15447 643.6 us | 15449 643.7 us | 1.00
bitset<1500>/test | 39038 1.6 ms | 22238 926.6 us | 1.76 +
bitset<15>/>>=/1 | 15865 661.0 us | 15447 643.6 us | 1.03
bitset<15>/count | 32115 1.3 ms | 32292 1.3 ms | 0.99
bitset<15>/flip | 17915 746.5 us | 17915 746.5 us | 1.00
bitset<15>/reset | 14829 617.9 us | 14829 617.9 us | 1.00
bitset<15>/set() | 14829 617.9 us | 14831 618.0 us | 1.00
bitset<15>/set(i) | 15449 643.7 us | 15447 643.6 us | 1.00
bitset<15>/test | 22239 926.6 us | 22336 930.7 us | 1.00
bitset<35>/>>=/1 | 53723 2.2 ms | 20386 849.4 us | 2.64 +
bitset<35>/count | 56498 2.4 ms | 42608 1.8 ms | 1.33 +
bitset<35>/flip | 35203 1.5 ms | 18995 791.5 us | 1.85 +
bitset<35>/reset | 16783 699.3 us | 16680 695.0 us | 1.01
bitset<35>/set() | 17144 714.3 us | 16681 695.0 us | 1.03
bitset<35>/set(i) | 15446 643.6 us | 15448 643.7 us | 1.00
bitset<35>/test | 37982 1.6 ms | 22236 926.5 us | 1.71 +
bitset<75>/>>=/1 | 64938 2.7 ms | 55576 2.3 ms | 1.17
bitset<75>/count | 69463 2.9 ms | 68630 2.9 ms | 1.01
bitset<75>/flip | 42611 1.8 ms | 45867 1.9 ms | 0.93
bitset<75>/reset | 16063 669.3 us | 16064 669.3 us | 1.00
bitset<75>/set() | 22239 926.6 us | 16681 695.0 us | 1.33 +
bitset<75>/set(i) | 15446 643.6 us | 15447 643.6 us | 1.00
bitset<75>/test | 37981 1.6 ms | 22237 926.5 us | 1.71 +
deque<ValuePair>/erase | 823387 34.3 ms | 608398 25.3 ms | 1.35 +
deque<ValuePair>/find | 38220 1.6 ms | 29603 1.2 ms | 1.29 +
deque<ValuePair>/insert | 676820 28.2 ms | 477143 19.9 ms | 1.42 +
deque<ValuePair>/iteration | 13879 578.3 us | 13058 544.1 us | 1.06
deque<ValuePair>/operator[] | 141669 5.9 ms | 38099 1.6 ms | 3.72 +
deque<ValuePair>/push_back | 78424 3.3 ms | 60230 2.5 ms | 1.30 +
deque<ValuePair>/push_front | 75580 3.1 ms | 59750 2.5 ms | 1.26
deque<ValuePair>/sort | 1326662 55.3 ms | 1294655 53.9 ms | 1.02
hash_map<string, uint32_t>/clear | 89848 3.7 ms | 141577 5.9 ms | 0.63 -
hash_map<string, uint32_t>/count | 57046 2.4 ms | 44314 1.8 ms | 1.29 +
hash_map<string, uint32_t>/erase pos | 15500 645.8 us | 16031 668.0 us | 0.97
hash_map<string, uint32_t>/erase range | 6066 252.8 us | 8387 349.5 us | 0.72 -
hash_map<string, uint32_t>/erase val | 83774 3.5 ms | 123408 5.1 ms | 0.68 -
hash_map<string, uint32_t>/find | 53005 2.2 ms | 43969 1.8 ms | 1.21
hash_map<string, uint32_t>/find_as/char* | 343339 14.3 ms | 44064 1.8 ms | 7.79 +
hash_map<string, uint32_t>/insert | 166099 6.9 ms | 377233 15.7 ms | 0.44 -
hash_map<string, uint32_t>/iteration | 26056 1.1 ms | 6280 261.7 us | 4.15 +
hash_map<string, uint32_t>/operator[] | 126748 5.3 ms | 45173 1.9 ms | 2.81 +
hash_map<uint32_t, TestObject>/clear | 76761 3.2 ms | 74166 3.1 ms | 1.03
hash_map<uint32_t, TestObject>/count | 5704 237.7 us | 6351 264.6 us | 0.90
hash_map<uint32_t, TestObject>/erase pos | 10105 421.0 us | 9233 384.7 us | 1.09
hash_map<uint32_t, TestObject>/erase range | 4647 193.6 us | 4379 182.5 us | 1.06
hash_map<uint32_t, TestObject>/erase val | 54657 2.3 ms | 54888 2.3 ms | 1.00
hash_map<uint32_t, TestObject>/find | 8769 365.4 us | 10320 430.0 us | 0.85
hash_map<uint32_t, TestObject>/insert | 78006 3.3 ms | 64780 2.7 ms | 1.20
hash_map<uint32_t, TestObject>/iteration | 10288 428.7 us | 4181 174.2 us | 2.46 +
hash_map<uint32_t, TestObject>/operator[] | 38152 1.6 ms | 11332 472.2 us | 3.37 +
heap (uint32_t[])/make_heap | 39956 1.7 ms | 37784 1.6 ms | 1.06
heap (uint32_t[])/pop_heap | 562846 23.5 ms | 555734 23.2 ms | 1.01
heap (uint32_t[])/push_heap | 96384 4.0 ms | 89646 3.7 ms | 1.08
heap (uint32_t[])/sort_heap | 427344 17.8 ms | 426115 17.8 ms | 1.00
heap (vector<TestObject>)/make_heap | 360942 15.0 ms | 279750 11.7 ms | 1.29 +
heap (vector<TestObject>)/pop_heap | 2174123 90.6 ms | 1860624 77.5 ms | 1.17
heap (vector<TestObject>)/push_heap | 318619 13.3 ms | 311454 13.0 ms | 1.02
heap (vector<TestObject>)/sort_heap | 1449815 60.4 ms | 1120718 46.7 ms | 1.29 +
list<TestObject>/ctor(it) | 1327323 55.3 ms | 1116544 46.5 ms | 1.19
list<TestObject>/ctor(n) | 137972 5.7 ms | 107749 4.5 ms | 1.28
list<TestObject>/erase | 7736645 322.4 ms | 7222498 300.9 ms | 1.07
list<TestObject>/find | 272828 11.4 ms | 98311 4.1 ms | 2.78 +
list<TestObject>/insert | 1443457 60.1 ms | 981364 40.9 ms | 1.47 +
list<TestObject>/push_back | 1327658 55.3 ms | 1037485 43.2 ms | 1.28
list<TestObject>/remove | 4542961 189.3 ms | 2113341 88.1 ms | 2.15 +
list<TestObject>/reverse | 247521 10.3 ms | 127275 5.3 ms | 1.94 +
list<TestObject>/size/1 | 2059 85.8 us | 1348 56.2 us | 1.53 +
list<TestObject>/size/10 | 10402 433.4 us | 1348 56.2 us | 7.72 +
list<TestObject>/size/100 | 60418 2.5 ms | 1347 56.1 us | 44.85 +
list<TestObject>/splice | 360181 15.0 ms | 149966 6.2 ms | 2.40 +
map<TestObject, uint32_t>/clear | 8441 351.7 us | 8964 373.5 us | 0.94
map<TestObject, uint32_t>/count | 52693 2.2 ms | 40627 1.7 ms | 1.30 +
map<TestObject, uint32_t>/equal_range | 92016 3.8 ms | 64816 2.7 ms | 1.42 +
map<TestObject, uint32_t>/erase/key | 107633 4.5 ms | 83653 3.5 ms | 1.29 +
map<TestObject, uint32_t>/erase/pos | 8392 349.7 us | 8031 334.6 us | 1.04
map<TestObject, uint32_t>/erase/range | 4574 190.6 us | 4626 192.8 us | 0.99
map<TestObject, uint32_t>/find | 55386 2.3 ms | 42534 1.8 ms | 1.30 +
map<TestObject, uint32_t>/insert | 115335 4.8 ms | 103705 4.3 ms | 1.11
map<TestObject, uint32_t>/iteration | 4347 181.1 us | 3724 155.2 us | 1.17
map<TestObject, uint32_t>/lower_bound | 54035 2.3 ms | 55225 2.3 ms | 0.98
map<TestObject, uint32_t>/operator[] | 61389 2.6 ms | 61771 2.6 ms | 0.99
map<TestObject, uint32_t>/upper_bound | 53119 2.2 ms | 52812 2.2 ms | 1.01
set<uint32_t>/clear | 8643 360.1 us | 8270 344.6 us | 1.05
set<uint32_t>/count | 46996 2.0 ms | 34758 1.4 ms | 1.35 +
set<uint32_t>/equal_range | 83769 3.5 ms | 59818 2.5 ms | 1.40 +
set<uint32_t>/erase range | 4561 190.0 us | 4928 205.3 us | 0.93
set<uint32_t>/erase/pos | 7686 320.3 us | 8154 339.8 us | 0.94
set<uint32_t>/erase/val | 97955 4.1 ms | 75812 3.2 ms | 1.29 +
set<uint32_t>/find | 46814 2.0 ms | 34819 1.5 ms | 1.34 +
set<uint32_t>/insert | 91932 3.8 ms | 89615 3.7 ms | 1.03
set<uint32_t>/iteration | 4026 167.8 us | 3679 153.3 us | 1.09
set<uint32_t>/lower_bound | 44198 1.8 ms | 44781 1.9 ms | 0.99
set<uint32_t>/upper_bound | 44681 1.9 ms | 44808 1.9 ms | 1.00
sort/q_sort/TestObject[] | 81575 3.4 ms | 82050 3.4 ms | 0.99
sort/q_sort/TestObject[]/sorted | 22862 952.6 us | 20965 873.5 us | 1.09
sort/q_sort/vector<TestObject> | 83253 3.5 ms | 85098 3.5 ms | 0.98
sort/q_sort/vector<TestObject>/sorted | 23191 966.3 us | 21261 885.9 us | 1.09
sort/q_sort/vector<ValuePair> | 40289 1.7 ms | 42528 1.8 ms | 0.95
sort/q_sort/vector<ValuePair>/sorted | 10738 447.4 us | 9978 415.8 us | 1.08
sort/q_sort/vector<uint32> | 32153 1.3 ms | 29938 1.2 ms | 1.07
sort/q_sort/vector<uint32>/sorted | 6683 278.5 us | 6232 259.7 us | 1.07
string<char16_t>/compare | 5012293 208.8 ms | 3732905 155.5 ms | 1.34 +
string<char16_t>/erase/pos,n | 11474 478.1 us | 11311 471.3 us | 1.01
string<char16_t>/find/p,pos,n | 9286309 386.9 ms | 3950594 164.6 ms | 2.35 +
string<char16_t>/find_first_not_of/p,pos,n | 803 33.5 us | 925 38.5 us | 0.87
string<char16_t>/find_first_of/p,pos,n | 82213 3.4 ms | 84770 3.5 ms | 0.97
string<char16_t>/find_last_of/p,pos,n | 14457 602.4 us | 11166 465.3 us | 1.29 +
string<char16_t>/insert/pos,p | 11879 495.0 us | 11839 493.3 us | 1.00
string<char16_t>/iteration | 6105186 254.4 ms | 4866198 202.8 ms | 1.25
string<char16_t>/operator[] | 11330 472.1 us | 3798 158.3 us | 2.98 +
string<char16_t>/push_back | 49159 2.0 ms | 33174 1.4 ms | 1.48 +
string<char16_t>/replace/pos,n,p,n | 17546 731.1 us | 17883 745.1 us | 0.98
string<char16_t>/reserve | 6556509 273.2 ms | 2148 89.5 us | 100.00 +
string<char16_t>/rfind/p,pos,n | 3230 134.6 us | 2870 119.6 us | 1.13
string<char16_t>/size | 186 7.8 us | 193 8.0 us | 0.96
string<char16_t>/swap | 3849 160.4 us | 4582 190.9 us | 0.84
string<char8_t>/compare | 840915 35.0 ms | 830604 34.6 ms | 1.01
string<char8_t>/erase/pos,n | 5060 210.8 us | 4933 205.5 us | 1.03
string<char8_t>/find/p,pos,n | 3874775 161.4 ms | 4561889 190.1 ms | 0.85
string<char8_t>/find_first_not_of/p,pos,n | 1187 49.5 us | 1046 43.6 us | 1.13
string<char8_t>/find_first_of/p,pos,n | 90512 3.8 ms | 84814 3.5 ms | 1.07
string<char8_t>/find_last_of/p,pos,n | 12115 504.8 us | 10461 435.9 us | 1.16
string<char8_t>/insert/pos,p | 4870 202.9 us | 4927 205.3 us | 0.99
string<char8_t>/iteration | 26095 1.1 ms | 20721 863.4 us | 1.26
string<char8_t>/operator[] | 11281 470.0 us | 6601 275.0 us | 1.71 +
string<char8_t>/push_back | 43759 1.8 ms | 33572 1.4 ms | 1.30 +
string<char8_t>/replace/pos,n,p,n | 11601 483.4 us | 11031 459.6 us | 1.05
string<char8_t>/reserve | 390865 16.3 ms | 977 40.7 us | 100.00 +
string<char8_t>/rfind/p,pos,n | 6273 261.4 us | 2898 120.8 us | 2.16 +
string<char8_t>/size | 186 7.8 us | 181 7.5 us | 1.03
string<char8_t>/swap | 3927 163.6 us | 4583 191.0 us | 0.86
vector<uint64>/erase | 293997 12.2 ms | 287042 12.0 ms | 1.02
vector<uint64>/insert | 300771 12.5 ms | 300785 12.5 ms | 1.00
vector<uint64>/iteration | 16491 687.1 us | 8643 360.1 us | 1.91 +
vector<uint64>/operator[] | 14059 585.8 us | 9137 380.7 us | 1.54 +
vector<uint64>/push_back | 48030 2.0 ms | 45529 1.9 ms | 1.05
vector<uint64>/sort | 575583 24.0 ms | 568422 23.7 ms | 1.01
sum | 67499027 2.81 s | 48028159 2.00 s | 1.41 +

2290
doc/FAQ.md Normal file

File diff suppressed because it is too large Load Diff

93
doc/Glossary.md Normal file
View File

@@ -0,0 +1,93 @@
# EASTL Glossary
This document provides definitions to various terms related to EASTL. Items that are capitalized are items that are used as template parameters.
| | |
|------|------|
| adapter | An adapter is something that encapsulates a component to provide another interface, such as a C++ class which makes a stack out of a list. |
| algorithm | Algorithms are standalone functions which manipulate data which usually but not necessarily comes from a container. Some algorithms change the data while others don't. Examples are reverse, sort, find, and remove. |
| associative container | An associative container is a variable-sized container that supports efficient retrieval of elements (values) based on keys. It supports insertion and removal of elements, but differs from a sequence in that it does not provide a mechanism for inserting an element at a specific position. Associative containers include map, multimap, set, multiset, hash_map, hash_multimap, hash_set, hash_multiset. |
| array | An array is a C++ container which directly implements a C-style fixed array but which adds STL container semantics to it. |
| basic_string | A templated string class which is usually used to store char or wchar_t strings. |
| begin | The function used by all conventional containers to return the first item in the container. |
| BidirectionalIterator | An input iterator which is like ForwardIterator except it can be read in a backward direction as well. |
| BinaryOperation  | A function which takes two arguments and returns a value (which will usually be assigned to a third object). |
| BinaryPredicate | A function which takes two arguments and returns true if some criteria is met (e.g. they are equal). |
| binder1st, binder2nd | These are function objects which convert one function object into another.  In particular, they implement a binary function whereby you can specify one of the arguments.This is a somewhat abstract concept but has its uses. |
| bit vector | A specialized container that acts like vector<bool> but is implemented via one bit per entry. STL vector<bool> is usually implemented as a bit vector but EASTL avoids this in favor of a specific bit vector container. |
| bitset | An extensible yet efficient implementation of bit flags. Not strictly a conventional STL container and not the same thing as vector<bool> or a bit_vector, both of which are formal iterate-able containers. |
| capacity | Refers to the amount of total storage available in an array-based container such as vector, string, and array. Capacity is always >= container size and is > size in order to provide extra space for a container to grow into. |
| const_iterator | An iterator whose iterated items are cannot be modified. A const_iterator is akin to a const pointer such as 'const char*'. |
| container | A container is an object that stores other objects (its elements), and that has methods for accessing its elements. In particular, every type that is a model of container has an associated iterator type that can be used to iterate through the container's elements. |
| copy constructor | A constructor for a type which takes another object of that type as its argument. For a hypothetical Widget class, the copy constructor is of the form Widget(const Widget& src); |
| Compare | A function which takes two arguments and returns the lesser of the two. |
| deque | The name deque is pronounced "deck" and stands for "double-ended queue."<br><br> A deque is very much like a vector: like vector, it is a sequence that supports random access to elements, constant time insertion and removal of elements at the end of the sequence, and linear time insertion and removal of elements in the middle.<br><br> The main way in which deque differs from vector is that deque also supports constant time insertion and removal of elements at the beginning of the sequence. Additionally, deque does not have any member functions analogous to vector's capacity() and reserve(), and does not provide the guarantees on iterator validity that are associated with those member functions. |
| difference_type | The typedef'd type used by all conventional containers and iterators to define the distance between two iterators. It is usually the same thing as the C/C++ ptrdiff_t data type. |
| empty | The function used by all conventional containers to tell if a container has a size of zero. In many cases empty is more efficient than checking for size() == 0. |
| element | An element refers to a member of a container. |
| end | The function used by all conventional containers to return one-past the last item in the container. |
| equal_range | equal_range is a version of binary search: it attempts to find the element value in an ordered range [first, last). The value returned by equal_range is essentially a combination of the values returned by lower_bound and upper_bound: it returns a pair of iterators i and j such that i is the first position where value could be inserted without violating the ordering and j is the last position where value could be inserted without violating the ordering. It follows that every element in the range [i, j) is equivalent to value, and that [i, j) is the largest subrange of [first, last) that has this property. |
| explicit instantiation | Explicit instantiation lets you create an instantiation of a templated class or function without actually using it in your code. Since this is useful when you are creating library files that use templates for distribution, uninstantiated template definitions are not put into object files. An example of the syntax for explicit instantiation is:<br> `template class vector<char>;`<br> `template void min<int>(int, int);`<br> `template void min(int, int);` |
| ForwardIterator | An input iterator which is like InputIterator except it can be reset back to the beginning. |
| Function | A function which takes one argument and applies some operation to the target. |
| function object, functor | A function object or functor is a class that has the function-call operator (<tt>operator()</tt>) defined. |
| Generator | A function which takes no arguments and returns a value (which will usually be assigned to an object). |
| hash_map, hash_multimap, hash_set, hash_multiset | The hash containers are implementations of map, multimap, set, and multiset via a hashtable instead of via a tree. Searches are O(1) (fast) but the container is not sorted. |
| heap | A heap is a data structure which is not necessarily sorted but is organized such that the highest priority item is at the top. A heap is synonymous with a priority queue and has numerous applications in computer science. |
| InputIterator | An input iterator (iterator you read from) which allows reading each element only once and only in a forward direction. |
| intrusive_list, intrusive_hash_map, etc. | Intrusive containers are containers which don't allocate memory but instead use their contained object to manage the container's memory. While list allocates nodes (with mpPrev/mpNext pointers) that contain the list items, intrusive_list doesn't allocate nodes but instead the container items have the mpPrev/mpNext pointers. |
| intrusive_ptr | intrusive_ptr is a smart pointer which doesn't allocate memory but instead uses the contained object to manage lifetime via addref and release functions. |
| iterator | An iterator is the fundamental entity of reading and enumerating values in a container. Much like a pointer can be used to walk through a character array, an iterator is used to walk through a linked list. |
| iterator category | An iterator category defines the functionality the iterator provides. The conventional iterator categories are InputIterator, ForwardIterator, BidirectionalIterator, RandomAccessIterator, and OutputIterator. See the definitions of each of these for more information.Iterator category is synonymous with <span style="font-style: italic;">iterator_tag</span>. |
| iterator_tag | See <span style="font-style: italic;">iterator category</span>. |
| key_type, Key | A Key or key_type is the identifier used by associative (a.k.a. dictionary) containers (e.g. map, hash_map) to identify the type used to index the mapped_type. If you have a dictionary of strings that you access by an integer id, the ids are the keys and the strings are the mapped types. |
| lexicographical compare | A lexicographical compare is a comparison of two containers that compares them element by element, much like the C strcmp function compares two strings. |
| linked_ptr | A linked_ptr is a shared smart pointer which implements object lifetime via a linked list of all linked_ptrs that are referencing the object. linked_ptr, like intrusive_ptr, is a non-memory-allocating alternative to shared_ptr. |
| list | A list is a doubly linked list. It is a sequence that supports both forward and backward traversal, and (amortized) constant time insertion and removal of elements at the beginning or the end, or in the middle. Lists have the important property that insertion and splicing do not invalidate iterators to list elements, and that even removal invalidates only the iterators that point to the elements that are removed. The ordering of iterators may be changed (that is, list<T>::iterator might have a different predecessor or successor after a list operation than it did before), but the iterators themselves will not be invalidated or made to point to different elements unless that invalidation or mutation is explicit. |
| lower_bound | lower_bound is a version of binary search: it attempts to find the element value in an ordered range [first, last). Specifically, it returns the first position where value could be inserted without violating the ordering. |
| map | Map is a sorted associative container that associates objects of type Key with objects of type T. Map is a pair associative container, meaning that its value type is pair<const Key, T>. It is also a unique associative container, meaning that no two elements have the same key. It is implemented with a tree structure. |
| mapped_type | A mapped_type is a typedef used by associative containers to identify the container object which is accessed by a key. If you have a dictionary of strings that you access by an integer id, the ids are the keys and the strings are the mapped types. |
| member template | A member template is a templated function of a templated class. Thus with a member template function there are two levels of templating -- the class and the function. |
| multimap,  | Multimap is a sorted associative container that associates objects of type Key with objects of type T. multimap is a pair associative container, meaning that its value type is pair<const Key, T>. It is also a multiple associative container, meaning that there is no limit on the number of elements with the same key.It is implemented with a tree structure. |
| multiset | Multiset is a sorted associative container that stores objects of type Key. Its value type, as well as its key type, is Key. It is also a multiple associative container, meaning that two or more elements may be identical. It is implemented with a tree structure. |
| node | A node is a little holder class used by many containers to hold the contained items. A linked-list, for example, defines a node which has three members: mpPrev, mpNext, and T (the contained object). |
| npos | npos is used by the string class to identify a non-existent index. Some string functions return npos to indicate that the function failed. |
| rel_ops | rel_ops refers to "relational operators" and is a set of templated functions which provide operator!= for classes that  have only operator== and provide operator > for classes that have only operator <, etc. Unfortunately, rel_ops have a habit of polluting the global operator space and creating conflicts. They must be used with discretion. |
| reverse_iterator | A reverse_iterator is an iterator which wraps a bidirectional or random access iterator and allows the iterator to be read in reverse direction. The difference between using reverse_iterators and just decrementing regular iterators is that reverse_iterators use operator++ to move backwards and thus work in any algorithm that calls ++ to move through a container. |
| OutputIterator | An output iterator (iterator you write to) which allows writing each element only once in only in a forward direction. |
| POD | POD means Plain Old Data. It refers to C++ classes which act like built-in types and C structs. These are useful to distinguish because some algorithms can be made more efficient when they can detect that they are working with PODs instead of regular classes.  |
| Predicate | A function which takes one argument returns true if the argument meets some criteria. |
| priority_queue | A priority_queue is an adapter container which implements a heap via a random access container such as vector or deque. |
| queue | A queue is an adapter container which implements a FIFO (first-in, first-out) container with which you can add items to the back and get items from the front. |
| RandomAccessIterator | An input iterator which can be addressed like an array. It is a superset of all other input iterators. |
| red-black tree | A red-black tree is a binary tree which has the property of being always balanced. The colors red and black are somewhat arbitrarily named monikers for nodes used to measure the balance of the tree. Red-black trees are considered the best all-around data structure for sorted containers. |
| scalar | A scalar is a data type which is implemented via a numerical value. In C++ this means integers, floating point values, enumerations, and pointers.  |
| scoped_ptr | A scoped_ptr is a smart pointer which is the same as C++ auto_ptr except that it cannot be copied. |
| set | Set is a sorted associative container that stores objects of type Key. Its value type, as well as its key type, is Key. It is also a unique associative container, meaning that no two elements are the same.It is implemented with a tree structure. |
| sequence | A sequence is a variable-sized container whose elements are arranged in a strict linear (though not necessarily contiguous) order. It supports insertion and removal of elements. Sequence containers include vector, deque, array, list, slist. |
| size | All conventional containers have a size member function which returns the count of elements in the container. The efficiency of the size function differs between containers. |
| size_type | The type that a container uses to define its size and counts. This is similar to the C/C++ size_t type but may be specialized for the container. |
| skip list | A skip-list is a type of container which is an alternative to a binary tree for finding data. |
| shared_ptr | A shared_ptr is a smart pointer which allows multiple references (via multiple shared_ptrs) to the same object. When the last shared_ptr goes away, the pointer is freed. shared_ptr is implemented via a shared count between all instances. |
| slist | An slist is like a list but is singly-linked instead of doubly-linked. It can only be iterated in a forward-direction. |
| smart pointer | Smart pointer is a term that identifies a family of utility classes which store pointers and free them when the class instance goes out of scope. Examples of smart pointers are shared_ptr, linked_ptr, intrusive_ptr, and scoped_ptr. |
| splice | Splicing refers to the moving of a subsequence of one Sequence into another Sequence. |
| stack | A stack is a adapter container which implements LIFO (last-in, first, out) access via another container such as a list or deque. |
| STL | Standard Template Library.  |
| StrictWeakOrdering | A BinaryPredicate that compares two objects, returning true if the first precedes the second. Like Compare but has additional requirements. Used for sorting routines.<br><br> This predicate must satisfy the standard mathematical definition of a strict weak ordering. A StrictWeakOrdering has to behave the way that "less than" behaves: if a is less than b then b is not less than a, if a is less than b and b is less than c then a is less than c, and so on. |
| string | See basic_string. |
| T | T is the template parameter name used by most containers to identify the contained element type.  |
| template parameter | A template parameter is the templated type used to define a template function or class. In the declaration 'template <typename T> class vector{ },'  T is a template parameter. |
| template specialization | A template specialization is a custom version of a template which overrides the default version and provides alternative functionality, often for the purpose of providing improved or specialized functionality. |
| treap | A tree-like structure implemented via a heap. This is an alternative to a binary tree (e.g. red-black tree), skip-list, and sorted array as a mechanism for a fast-access sorted container. |
| type traits | Type traits are properties of types. If you have a templated type T and you want to know if it is a pointer, you would use the is_pointer type trait. If you want to know if the type is a POD, you would use the is_pod type trait. Type traits are very useful for allowing the implementation of optimized generic algorithms and for asserting that types have properties expected by the function or class contract. For example, you can use type_traits to tell if a type can be copied via memcpy instead of a slower element-by-element copy. |
| typename | Typename is a C++ keyword used in templated function implementations which identifies to the compiler that the following expression is a type and not a value. It is used extensively in EASTL, particularly in the algorithms. |
| UnaryOperation | A function which takes one argument and returns a value (which will usually be assigned to second object). |
| upper_bound | upper_bound is a version of binary search: it attempts to find the element value in an ordered range [first, last). Specifically, it returns the last position where value could be inserted without violating the ordering. |
| value_type, Value | A value_type is a typedef used by all containers to identify the elements they contain. In most cases value_type is simply the same thing as the user-supplied T template parameter. The primary exception is the associative containers whereby value_type is the pair of key_type and mapped_type. |
| vector | A vector is a Sequence that supports random access to elements, constant time insertion and removal of elements at the end, and linear time insertion and removal of elements at the beginning or in the middle. The number of elements in a vector may vary dynamically; memory management is automatic. Vector is the simplest of the container classes, and in many cases the most efficient. |
| vector_map, vector_multimap, vector_set, vector_multiset | These are containers that implement the functionality of map, multimap, set, and multiset via a vector or deque instead of a tree. They use less memory and find items faster, but are slower to modify and modification invalidates iterators. |
| weak_ptr | A weak_ptr is an adjunct to shared_ptr which doesn't increment the reference on the contained object but can safely tell you if the object still exists and access it if so. It has uses in preventing circular references in shared_ptrs. |
----------------------------------------------
End of document

134
doc/Gotchas.md Normal file
View File

@@ -0,0 +1,134 @@
# EASTL Gotchas
There are some cases where the EASTL design results in "gotchas" or behavior that isn't necessarily what the new user would expect. These are all situations in which this behavior may be undesirable. One might ask, "Why not change EASTL to make these gotchas go away?" The answer is that in each case making the gotchas go away would either be impossible or would compromise the functionality of the library.
## Summary
The descriptions here are intentionally terse; this is to make them easier to visually scan.
1. [map::operator[] can create elements.](#mapoperator-can-create-elements)
2. [char* converts to string silently.](#char-converts-to-string-silently)
3. [char* is compared by ptr and not by contents.](#char-is-compared-by-ptr-and-not-by-contents)
4. [Iterators can be invalidated by container mutations.](#iterators-can-be-invalidated-by-container-mutations)
5. [Vector resizing may cause ctor/dtor cascades.](#vector-resizing-may-cause-ctordtor-cascades)
6. [Vector and string insert/push_back/resize can reallocate.](#vector-and-string-insertpush_backresize-can-reallocate)
7. [Deriving from containers may not work.](#deriving-from-containers-may-not-work)
8. [set::iterator is const_iterator.](#setiterator-is-const_iterator)
9. [Inserting elements means copying by value.](#inserting-elements-means-copying-by-value)
10. [Containers of pointers can leak if you aren't careful.](#containers-of-pointers-can-leak-if-you-arent-careful)
11. [Containers of auto_ptrs can crash.](#containers-of-auto_ptrs-can-crash)
12. [Remove algorithms don't actually remove elements.](#remove-algorithms-dont-actually-remove-elements)
13. [list::size() is O(n).](#listsize-is-on)
14. [vector and deque::size() may incur integer division.](#vector-and-dequesize-may-incur-integer-division)
15. [Be careful making custom Compare functions.](#be-careful-making-custom-compare-functions)
16. [Comparisons involving floating point are dangerous.](#comparisons-involving-floating-point-are-dangerous)
17. [Writing beyond string::size and vector::size is dangerous.](#writing-beyond-stringsize-and-vectorsize-is-dangerous)
18. [Container operator=() doesn't copy allocators.](#container-operator-doesnt-copy-allocators)
## Detail
### map::operator[] can create elements.
By design, map operator[] creates a value for you if it isn't already present. The reason for this is that the alternative behavior would be to throw an exception, and such behavior isn't desirable. The resolution is to simply use the map::find function instead of operator[].
### char* converts to string silently.
The string class has a non-explicit constructor that takes char* as an argument. Thus if you pass char* to a function that takes a string object, a temporary string will be created. In some cases this is undesirable behavior but the user may not notice it right away, as the compiler gives no warnings. The reason that the string constructor from char* is not declared explicit is that doing so would prevent the user from expressions such as: string s = "hello". In this example, no temporary string object is created, but the syntax is not possible if the char* constructor is declared explicit. Thus a decision to make the string char* constructor explicit involves tradeoffs.
There is an EASTL configuration option called EASTL_STRING_EXPLICIT which makes the string char* ctor explicit and avoids the behaviour described above.
### char* is compared by ptr and not by contents.
If you have a set of strings declared as set<char*>, the find function will compare via the pointer value and not the string contents. The workaround is to make a set of string objects or, better, to supply a custom string comparison function to the set. The workaround is not to declare a global operator< for type char*, as that could cause other systems to break.
### Iterators can be invalidated by container mutations
With some containers, modifications of them may invalidate iterators into them. With other containers, modifications of them only an iterator if the modification involves the element that iterator refers to. Containers in the former category include vector, deque, basic_string (string), vector_map, vector_multimap, vector_set, and vector_multiset. Containers in the latter category include list, slist, map, multimap, multiset, all hash containers, and all intrusive containers.
### Vector resizing may cause ctor/dtor cascades.
If elements are inserted into a vector in middle of the sequence, the elements from the insertion point to the end will be copied upward. This will necessarily cause a series of element constructions and destructions as the elements are copied upward. Similarly, if an element is appended to a vector but the vector capacity is exhausted and needs to be reallocated, the entire vector will undergo a construction and destruction pass as the values are copied to the new storage. This issue exists for deque as well, though to a lesser degree. For vector, the resolution is to reserve enough space in your vector to prevent such reallocation. For deque the resolution is to set its subarray size to enough to prevent such reallocation. Another solution that can often be used is to take advantage of the has_trivial_relocate type trait, which can cause such moves to happen via memcpy instead of via ctor/dtor calls. If your class can be safely memcpy'd, you can use EASTL_DECLARE_TRIVIAL_RELOCATE to tell the compiler it can be memcpy'd. Note that built-in scalars (e.g. int) already are automatically memcpy'd by EASTL.
### Vector and string insert/push_back/resize can reallocate.
If you create an empty vector and use push_back to insert 100 elements, the vector will reallocate itself at least three or four times during the operation. This can be an undesirable thing. The best thing to do if possible is to reserve the size you will need up front in the vector constructor or before you add any elements.
### Deriving from containers may not work.
EASTL containers are not designed with the guarantee that they can be arbitrarily subclassed. This is by design and is done for performance reasons, as such guarantees would likely involve making containers use virtual functions. However, some types of subclassing can be successful and EASTL does such subclassing internally to its advantage. The primary problem with subclassing results when a parent class function calls a function that the user wants to override. The parent class cannot see the overridden function and silent unpredictable behavior will likely occur. If your derived container acts strictly as a wrapper for the container then you will likely be able to successfully subclass it.
### set::iterator is const_iterator.
The reason this is so is that a set is an ordered container and changing the value referred to by an iterator could make the set be out of order. Thus, set and multiset iterators are always const_iterators. If you need to change the value and are sure the change will not alter the container order, use const_cast or declare mutable member variables for your contained object. This resolution is the one blessed by the C++ standardization committee. This issue is addressed in more detail in the EASTL FAQ.
### Inserting elements means copying by value.
When you insert an element into a (non-intrusive) container, the container makes a copy of the element. There is no provision to take over ownership of an object from the user. The exception to this is of course when you use a container of pointers instead of a container of values. See the entry below regarding containers of pointers. Intrusive containers (e.g. intrusive_list) do in fact take over the user-provided value, and thus provide another advantage over regular containers in addition to avoiding memory allocation.
### Containers of pointers can leak if you aren't careful.
Containers of points don't know or care about the possibility that the pointer may have been allocated and need to be freed. Thus if you erase such elements from a container they are not freed. The resolution is to manually free the pointers when removing them or to instead use a container of smart pointers (shared smart pointers, in particular). This issue is addressed in more detail in the EASTL FAQ and the auto_ptr-related entry below.
### Containers of auto_ptrs can crash
We suggested above that the user can use a container of smart pointers to automatically manage contained pointers. However, you don't want to use auto_ptr, as auto_ptrs cannot be safely assigned to each other; doing so results in a stale pointer and most likely a crash.
### Remove algorithms don't actually remove elements.
Algorithms such as remove, remove_if, remove_heap, and unique do not erase elements from the sequences they work on. Instead, they return an iterator to the new end of the sequence and the user must call erase with that iterator in order to actually remove the elements from the container. This behavior exists because algorithms work on sequences via iterators and don't know how to work with containers. Only the container can know how to best erase its own elements. In each case, the documentation for the algorithm reminds the user of this behavior. Similarly, the copy algorithm copies elements from one sequence to another and doesn't modify the size of the destination sequence. So the destination must hold at least as many items as the source, and if it holds more items, you may want to erase the items at the end after the copy.
### list::size() is O(n).
By this we mean that calling size() on a list will iterate the list and add the size as it goes. Thus, getting the size of a list is not a fast operation, as it requires traversing the list and counting the nodes. We could make list::size() be fast by having a member mSize variable. There are reasons for having such functionality and reasons for not having such functionality. We currently choose to not have a member mSize variable as it would add four bytes to the class, add processing to functions such as insert and erase, and would only serve to improve the size function, but no other function. The alternative argument is that the C++ standard states that std::list should be an O(1) operation (i.e. have a member size variable), most C++ standard library list implementations do so, the size is but an integer which is quick to update, and many users expect to have a fast size function. All of this applies to slist and intrusive_list as well.
Note that EASTL's config.h file has an option in it to cause list and slist to cache their size with an mSize variable and thus make size() O(1). This option is disabled by default.
### vector and deque::size() may incur integer division.
Some containers (vector and deque in particular) calculate their size by pointer subtraction. For example, the implementation of vector::size() is 'return mpEnd - mpBegin'. This looks like a harmless subtraction, but if the size of the contained object is not an even power of two then the compiler will likely need to do an integer division to calculate the value of the subtracted pointers. One might suggest that vector use mpBegin and mnSize as member variables instead of mpBegin and mpEnd, but that would incur costs in other vector operations. The suggested workaround is to iterate a vector instead of using a for loop and operator[] and for those cases where you do use a for loop and operator[], get the size once at the beginning of the loop instead of repeatedly during the condition test.
### Be careful making custom Compare functions.
A Compare function compares two values and returns true if the first is less than the second. This is easy to understand for integers and strings, but harder to get right for more complex structures. Many a time have people decided to come up with a fancy mechanism for comparing values and made mistakes. The FAQ has a couple entries related to this. See http://blogs.msdn.com/oldnewthing/archive/2003/10/23/55408.aspx for a story about how this can go wrong by being overly clever.
### Comparisons involving floating point are dangerous.
Floating point comparisons between two values that are very nearly equal can result in inconsistent results. Similarly, floating point comparisons between NaN values will always generate inconsistent results, as NaNs by definition always compare as non-equal. You thus need to be careful when using comparison functions that work with floating point values. Conversions to integral values may help the problem, but not necessarily.
### Writing beyond string::size and vector::size is dangerous.
A trick that often comes to mind when working with strings is to set the string capacity to some maximum value, strcpy data into it, and then resize the string when done. This can be done with EASTL, but only if you resize the string to the maximum value and not reserve the string to the maximum value. The reason is that when you resize a string from size (n) to size (n + count), the count characters are zeroed and overwrite the characters that you strcpyd.
The following code is broken:
```cpp
string mDataDir;
mDataDir.reserve(kMaxPathLength); // reserve
strcpy(&mDataDir[0], "blah/blah/blah");
mDataDir.resize(strlen(&mDataDir[0])); // Overwrites your blah/... with 00000...
```
This following code is OK:
```cpp
string mDataDir;
mDataDir.resize(kMaxPathLength); // resize
strcpy(&mDataDir[0], "blah/blah/blah");
mDataDir.resize(strlen(&mDataDir[0]));
```
### Container operator=() doesn't copy allocators.
EASTL container assignment (e.g. vector::operator=(const vector&)) doesn't copy the allocator. There are good and bad reasons for doing this, but that's how it acts. So you need to beware that you need to assign the allocator separately or make a container subclass which overrides opeator=() and does this.
----------------------------------------------
End of document

18
doc/Introduction.md Normal file
View File

@@ -0,0 +1,18 @@
# EASTL Introduction
EASTL stands for Electronic Arts Standard Template Library. It is a C++ template library of containers, algorithms, and iterators useful for runtime and tool development across multiple platforms. It is a fairly extensive and robust implementation of such a library and has an emphasis on high performance above all other considerations.
## Intended Audience
This is a short document intended to provide a basic introduction to EASTL for those new to the concept of EASTL or STL. If you are familiar with the C++ STL or have worked with other templated container/algorithm libraries, you probably don't need to read this. If you have no familiarity with C++ templates at all, then you probably will need more than this document to get you up to speed. In this case you need to understand that templates, when used properly, are powerful vehicles for the ease of creation of optimized C++ code. A description of C++ templates is outside the scope of this documentation, but there is plenty of such documentation on the Internet. See the EASTL FAQ.html document for links to information related to learning templates and STL.
## EASTL Modules
EASTL consists primarily of containers, algorithms, and iterators. An example of a container is a linked list, while an example of an algorithm is a sort function; iterators are the entities of traversal for containers and algorithms. EASTL containers a fairly large number of containers and algorithms, each of which is a very clean, efficient, and unit-tested implementation. We can say with some confidence that you are not likely to find better implementations of these (commercial or otherwise), as these are the result of years of wisdom and diligent work. For a detailed list of EASTL modules, see EASTL Modules.html.
## EASTL Suitability
What uses are EASTL suitable for? Essentially any situation in tools and shipping applications where the functionality of EASTL is useful. Modern compilers are capable of producing good code with templates and many people are using them in both current generation and future generation applications on multiple platforms from embedded systems to servers and mainframes.
----------------------------------------------
End of document

195
doc/Maintenance.md Normal file
View File

@@ -0,0 +1,195 @@
# EASTL Maintenance
## Introduction
The purpose of this document is to provide some necessary background for anybody who might do work on EASTL. Writing generic templated systems like EASTL can be surprisingly tricky. There are numerous details of the C++ language that you need to understand which don't usually come into play during the day-to-day C++ coding that many people do. It is easy to make a change to some function that seems proper and works for your test case but either violates the design expectations or simply breaks under other circumstances.
It may be useful to start with an example. Here we provide an implementation of the count algorithm which is seems simple enough. Except it is wrong and while it will compile in some cases it won't compile in others:
```cpp
int count(InputIterator first, InputIterator last, const T& value)
{
    int result = 0;
    for(; first < last; ++first){
        if(*first == value)
            ++result;
    }
    return result;
}
```
The problem is with the comparison 'first < last'. The count algorithm takes an InputIterator and operator< is not guaranteed to exist for any given InputIterator (and indeed while operator< exists for vector::iterator, it doesn't exist for list::iterator). The comparison in the above algorithm must instead be implemented as 'first != last'. If we were working with a RandomAccessIterator then 'first < last' would be valid.
In the following sections we cover various topics of interest regarding the development and maintentance of EASTL. Unfortunately, this document can't cover every aspect of EASTL maintenance issues, but at least it should give you a sense of the kinds of issues.
## C++ Language Standard
First and foremost, you need to be familiar with the C++ standard. In particular, the sections of the standard related to containers, algorithms, and iterators are of prime significance. We'll talk about some of this in more detail below. Similarly, a strong understanding of the basic data types is required. What is the difference between ptrdiff_t and intptr_t; unsigned int and size_t; char and signed char?
In addition to the C++ language standard, you'll want to be familiar with the C++ Defect Report. This is a continuously updated document which lists flaws in the original C++ language specification and the current thinking as the resolutions of those flaws. You will notice various references to the Defect Report in EASTL source code.
Additionally, you will want to be familiar with the C++ Technical Report 1 (as of this writing there is only one). This document is the evolving addendum to the C++ standard based on both the Defect Report and based on desired additions to the C++ language and standard library.
Additionally, you will probably want to have some familiarity with Boost. It also helps to keep an eye on comp.std.c++ Usenet discussions. However, watch out for what people say on Usenet. They tend to defend GCC, Unix, std STL, and C++ to a sometimes unreasonable degree. Many discussions ignore performance implications and concentrate only on correctness and sometimes academic correctness above usability.
## Language Use
Macros are (almost) not allowed in EASTL. A prime directive of EASTL is to be easier to read by users and most of the time macros are an impedence to this. So we avoid macros at all costs, even if it ends up making our development and maintenance more difficult. That being said, you will notice that the EASTL config.h file uses macros to control various options. This is an exception to the rule; when we talk about not using macros, we mean with the EASTL implementation itself.
EASTL assumes a compliant and intelligent C++ compiler, and thus all language facilities are usable. However, we nevertheless choose to stay away from some language functionality. The primary language features we avoid are:
* RTTI (run-time-type-identification) (this is deemed too costly)
* Template export (few compilers support this)
* Exception specifications (most compilers ignore them)
Use of per-platform or per-compiler code should be avoided when possible but where there is a significant advantage to be gained it can and indeed should be used. An example of this is the GCC __builtin_expect feature, which allows the user to give the compiler a hint about whether an expression is true or false. This allows for the generation of code that executes faster due to more intelligent branch prediction.
## Prime Directives
The implementation of EASTL is guided foremost by the following directives which are listed in order of importance.
1. Efficiency (speed and memory usage)
2. Correctness (doesn't have bugs)
3. Portability (works on all required platforms with minimal specialized code)
4. Readability (code is legible and comments are present and useful)
Note that unlike commercial STL implementations which must put correctness above all, we put a higher value on efficiency. As a result, some functionality may have some usage limitation that is not present in other similar systems but which allows for more efficient operation, especially on the platforms of significance to us.
Portability is significant, but not critical. Yes, EASTL must compile and run on all platforms that we will ship games for. But we don't take that to mean under all compilers that could be conceivably used for such platforms. For example, Microsoft VC6 can be used to compile Windows programs, but VC6's C++ support is too weak for EASTL and so you simply cannot use EASTL under VC6.
Readability is something that EASTL achieves better than many other templated libraries, particularly Microsoft STL and STLPort. We make every attempt to make EASTL code clean and sensible. Sometimes our need to provide optimizations (particularly related to type_traits and iterator types) results in less simple code, but efficiency happens to be our prime directive and so it overrides all other considerations.
## Coding Conventions
Here we provide a list of coding conventions to follow when maintaining or adding to EASTL, starting with the three language use items from above:
* No RTTI use.
* No use of exception specifications (e.g. appending the 'throw' declarator to a function).
* No use of exception handling itself except where explicitly required by the implementation (e.g. vector::at).
* Exception use needs to savvy to EASTL_EXCEPTIONS_ENABLED.
* No use of macros (outside of config.h). Macros make things more difficult for the user.
* No use of static or global variables.
* No use of global new, delete, malloc, or free. All memory must be user-specifyable via an Allocator parameter (default-specified or explicitly specified).
* Containers use protected member data and functions as opposed to private. This is because doing so allows subclasses to extend the container without the creation of intermediary functions. Recall from our [prime directives](#Prime_Directives) above that performance and simplicity overrule all.
* No use of multithreading primitives. 
* No use of the export keyword.
* We don't have a rule about C-style casts vs. C++ static_cast<>, etc. We would always use static_cast except that debuggers can't evaluate them and so in practice they can get in the way of debugging and tracing. However, if the cast is one that users don't tend to need to view in a debugger, C++ casts are preferred.
* No external library dependencies whatsoever, including standard STL. EASTL is dependent on only EABase and the C++ compiler. 
* All code must be const-correct. This isn't just for readability -- compilation can fail unless const-ness is used correctly everywhere. 
* Algorithms do not refer to containers; they refer only to iterators.
* Algorithms in general do not allocate memory. If such a situation arises, there should be a version of the algorithm which allows the user to provide the allocator.
* No inferior implementations. No facility should be added to EASTL unless it is of professional quality.
* The maintainer should emulate the EASTL style of code layout, regardless of the maintainer's personal preferences. When in Rome, do as the Romans do. EASTL uses 4 spaces for indents, which is how the large majority of code within EA is written.
* No major changes should be done without consulting a peer group.
## Compiler Issues
Historically, templates are the feature of C++ that has given C++ compilers the most fits. We are still working with compilers that don't completely and properly support templates. Luckily, most compilers are now good enough to handle what EASTL requires. Nevertheless, there are precautions we must take.
It turns out that the biggest problem in writing portable EASTL code is that VC++ allows you to make illegal statements which are not allowed by other compilers. For example, VC++ will allow you to neglect using the typename keyword in template references, whereas GCC (especially 3.4+) requires it.
In order to feel comfortable that your EASTL code is C++ correct and is portable, you must do at least these two things:
* Test under at least VS2005, GCC 3.4+, GCC 4.4+, EDG, and clang.
* Test all functions that you write, as compilers will often skip the compilation of a template function if it isn't used.
The two biggest issues to watch out for are 'typename' and a concept called "dependent names". In both cases VC++ will accept non-conforming syntax whereas most other compilers will not. Whenever you reference a templated type (and not a templated value) in a template, you need to prefix it by 'typename'. Whenever your class function refers to a base class member (data or function), you need to refer to it by "this->", "base_type::", or by placing a "using" statement in your class to declare that you will be referencing the given base class member.
## Iterator Issues
The most important thing to understand about iterators is the concept of iterator types and their designated properties. In particular, we need to understand the difference between InputIterator, ForwardIterator, BidirectionalIterator, RandomAccessIterator, and OutputIterator. These differences dictate both how we implement our algorithms and how we implement our optimizations. Please read the C++ standard for a reasonably well-implemented description of these iterator types.
Here's an example from EASTL/algorithm.h which demonstrates how we use iterator types to optimize the reverse algorithm based on the kind of iterator passed to it:
```cpp
template <class BidirectionalIterator>
inline void reverse_impl(BidirectionalIterator first, BidirectionalIterator last, bidirectional_iterator_tag)
{
for(; (first != last) && (first != --last); ++first) // We are not allowed to use operator <, <=, >, >= with
iter_swap(first, last); // a generic (bidirectional or otherwise) iterator.
}
template <typename RandomAccessIterator>
inline void reverse_impl(RandomAccessIterator first, RandomAccessIterator last, random_access_iterator_tag)
{
for(; first < --last; ++first) // With a random access iterator, we can use operator < to more efficiently implement
iter_swap(first, last); // this algorithm. A generic iterator doesn't necessarily have an operator < defined.
}
template <class BidirectionalIterator>
inline void reverse(BidirectionalIterator first, BidirectionalIterator last)
{
typedef typename iterator_traits<BidirectionalIterator>::iterator_category IC;
reverse_impl(first, last, IC());
}
```
## Exception Handling
You will notice that EASTL uses try/catch in some places (particularly in containers) and uses the EASTL_EXCEPTIONS_ENABLED define. For starters, any EASTL code that uses try/catch should always be wrapped within #if EASTL_EXCEPTIONS_ENABLED (note: #if, not #ifdef).
This is simple enough, but what you may be wondering is how it is that EASTL decides to use try/catch for some sections of code and not for others. EASTL follows the C++ standard library conventions with respect to exception handling, and you will see similar exception handling in standard STL. The code that you need to wrap in try/catch is code that can throw a C++ exception (not to be confused with CPU exception) and needs to have something unwound (or fixed) as a result. The important thing is that the container be in a valid state after encountering such exceptions. In general the kinds of things that require such try/catch are:
* Memory allocation failures (which throw exceptions)
* Constructor exceptions
Take a look at the cases in EASTL where try/catch is used and see what it is doing.
## Type Traits
EASTL provides a facility called type_traits which is very similar to the type_traits being proposed by the C++ TR1 (see above). type_traits are useful because they tell you about properties of types at compile time. This allows you to do things such as assert that a data type is scalar or that a data type is const. The way we put them to use in EASTL is to take advantage of them to implement different pathways for functions based on types. For example, we can copy a contiguous array of scalars much faster via memcpy than we can via a for loop, though we could not safely employ the for loop for a non-trivial C++ class.
As mentioned in the GeneralOptimizations section below, EASTL should take advantage of type_traits information to the extent possible to achive maximum effiiciency.
## General Optimizations
One of the primary goals of EASTL is to achieve the highest possible efficiency. In cases where EASTL functionality overlaps standard C++ STL functionality, standard STL implementations provided by compiler vendors are a benchmark upon which EASTL strives to beat. Indeed EASTL is more efficient than all other current STL implementations (with some exception in the case of some Metrowerks STL facilities). Here we list some of the things to look for when considering optimization of EASTL code These items can be considered general optimization suggestions for any code, but this particular list applies to EASTL:
* Take advantage of type_traits to the extent possible (e.g. to use memcpy to move data instead of a for loop when possible).
* Take advantage of iterator types to the extent possible.
* Take advantage of the compiler's expectation that if statements are expected to evaluate as true and for loop conditions are expected to evaluate as false.
* Make inline-friendly code. This often means avoiding temporaries to the extent possible.
* Minimize branching (i.e. minimize 'if' statements). Where branching is used, make it so that 'if' statements execute as true.
* Use EASTL_LIKELY/EASTL_UNLIKELY to give branch hints to the compiler when you are confident it will be beneficial.
* Use restricted pointers (EABase's EA_RESTRICT or various compiler-specific versions of __restrict).
* Compare unsigned values to < max instead of comparing signed values to >= 0 && < max.
* Employ power of 2 integer math instead of math with any kind of integer.
* Use template specialization where possible to implement improved functionality.
* Avoid function calls when the call does something trivial. This improves debug build speed (which matters) and sometimes release build speed as well, though sometimes makes the code intent less clear. A comment next to the code saying what call it is replacing makes the intent clear without sacrificing performance.
## Unit Tests
Writing robust templated containers and algorithms is difficult or impossible without a heavy unit test suite in place. EASTL has a pretty extensive set of unit tests for all containers and algorithms. While the successful automated unit testing of shipping application programs may be a difficult thing to pull off, unit testing of libraries such as this is of huge importance and cannot be understated.
* When making a new unit test, start by copying one of the existing unit tests and follow its conventions.
* Test containers of both scalars and classes.
* Test algorithms on both container iterators (e.g. vector.begin()) and pointer iterators (e.g. int*).
* Make sure that algorithm or container member functions which take iterators work with the type of iterator they claim to (InputIterator, ForwardIterator, BidirectionalIterator, RandomAccessIterator). 
* Test for const-correctness. If a user is allowed to modify something that is supposed to be const, silent errors can go undetected.
* Make sure that unit tests cover all functions and all pathways of the tested code. This means that in writing the unit test you need to look at the source code to understand all the pathways.
* Consider using a random number generator (one is provided in the test library) to do 'monkey' testing whereby unexpected input is given to a module being tested. When doing so, make sure you seed the generator in a way that problems can be reproduced.
* While we avoid macros in EASTL user code, macros to assist in unit tests aren't considered a problem. However, consider that a number of macros could be replaced by templated functions and thus be easier to work with.
* Unit tests don't need to be efficient; feel free to take up all the CPU power and time you need to test a module sufficiently.
* EASTL containers are not thread-safe, by design. Thus there is no need to do multithreading tests as long as you stay away from the usage of static and global variables.
* Unit tests must succeed with no memory leaks and of course no memory corruption. The heap system should be configured to test for this, and heap validation functions are available to the unit tests while in the middle of runs.
## Things to Keep in Mind
* When referring to EASTL functions and types from EASTL code, make sure to preface the type with the EASTL namespace. If you don't do this you can get collisions due to the compiler not knowing if it should use the EASTL namespace or the namespace of the templated type for the function or type.
* Newly constructed empty containers do no memory allocation. Some STL and other container libraries allocate an initial node from the class memory allocator. EASTL containers by design never do this. If a container needs an initial node, that node should be made part of the container itself or be a static empty node object.
* Empty containers (new or otherwise) contain no constructed objects, including those that might be in an 'end' node. Similarly, no user object (e.g. of type T) should be constructed unless required by the design and unless documented in the cotainer/algorithm contract. 
* When creating a new container class, it's best to copy from an existing similar class to the extent possible. This helps keep the library consistent and resolves subtle problems that can happen in the construction of containers.
* Be very careful about tweaking the code. It's easy to think (for example) that a > could be switch to a >= where instead it is a big deal. Just about every line of code in EASTL has been thought through and has a purpose. Unit tests may or may not currently test every bit of EASTL, so you can't necessarily rely on them to give you 100% confidence in changes. If you are not sure about something, contact the original author and he will tell you for sure.
* Algorithm templates always work with iterators and not containers. A given container may of course implement an optimized form or an algorithm itself.
* Make sure everything is heavily unit tested. If somebody finds a bug, fix the bug and make a unit test to make sure the bug doesn't happen again.
* It's easy to get iterator categories confused or forgotten while implementing algorithms and containers.
* Watch out for the strictness of GCC 3.4+. There is a bit of syntax — especially related to templates — that other compilers accept but GCC 3.4+ will not.
* Don't forget to update the config.h EASTL_VERSION define before publishing.
* The vector and string classes define iterator to be T*. We want to always leave this so — at least in release builds — as this gives some algorithms an advantage that optimizers cannot get around.
----------------------------------------------
End of document

89
doc/Modules.md Normal file
View File

@@ -0,0 +1,89 @@
# EASTL Modules
## Introduction
We provide here a list of all top-level modules present or planned for future presence in EASTL. In some cases (e.g. algorithm), the module consists of many smaller submodules which are not described in detail here. In those cases you should consult the source code for those modules or consult the detailed documentation for those modules. This document is a high level overview and not a detailed document.
## Module List
| Module | Description |
|------|------|
| config | Configuration header. Allows for changing some compile-time options. |
| slist <br>fixed_slist | Singly-linked list.<br> fixed_slist is a version which is implemented via a fixed block of contiguous memory.|
| list<br> fixed_list | Doubly-linked list. |
| intrusive_list<br> intrusive_slist | List whereby the contained item provides the node implementation. |
| array | Wrapper for a C-style array which extends it to act like an STL container. |
| vector<br> fixed_vector | Resizable array container.
| vector_set<br> vector_multiset | Set implemented via a vector instead of a tree. Speed and memory use is improved but resizing is slower. |
| vector_map<br> vector_multimap | Map implemented via a vector instead of a tree. Speed and memory use is improved but resizing is slower. |
| deque | Double-ended queue, but also with random access. Acts like a vector but insertions and removals are efficient. |
| bit_vector | Implements a vector of bool, but the actual storage is done with one bit per bool. Not the same thing as a bitset. |
| bitset | Implements an efficient arbitrarily-sized bitfield. Note that this is not strictly the same thing as a vector of bool (bit_vector), as it is optimized to act like an arbitrary set of flags and not to be a generic container which can be iterated, inserted, removed, etc. |
| set<br> multiset<br> fixed_set<br> fixed_multiset | A set is a sorted unique collection, multiset is sorted but non-unique collection. |
| map<br> multimap<br> fixed_map<br> fixed_multimap | A map is a sorted associative collection implemented via a tree. It is also known as dictionary. |
| hash_map<br> hash_multimap<br> fixed_hash_map<br> fixed_hash_multimap | Map implemented via a hash table. |
| intrusive_hash_map<br> intrusive_hash_multimap<br> intrusive_hash_set<br> intrusive_hash_multiset | hash_map whereby the contained item provides the node implementation, much like intrusive_list. |
| hash_set<br> hash_multiset<br> fixed_hash_set<br> fixed_hash_map | Set implemented via a hash table.
| basic_string<br> fixed_string<br> fixed_substring | basic_string is a character string/array.<br> fixed_substring is a string which is a reference to a range within another string or character array.<br> cow_string is a string which implements copy-on-write. |
| algorithm | min/max, find, binary_search, random_shuffle, reverse, etc. |
| sort | Sorting functionality, including functionality not in STL. quick_sort, heap_sort, merge_sort, shell_sort, insertion_sort, etc. |
| numeric | Numeric algorithms: accumulate, inner_product, partial_sum, adjacent_difference, etc. |
| heap | Heap structure functionality: make_heap, push_heap, pop_heap, sort_heap, is_heap, remove_heap, etc. |
| stack | Adapts any container into a stack. |
| queue | Adapts any container into a queue. |
| priority_queue | Implements a conventional priority queue via a heap structure. |
| type_traits | Type information, useful for writing optimized and robust code. Also used for implementing optimized containers and algorithms. |
| utility | pair, make_pair, rel_ops, etc. |
| functional | Function objects. |
| iterator | Iteration for containers and algorithms. |
| smart_ptr | Smart pointers: shared_ptr, shared_array, weak_ptr, scoped_ptr, scoped_array, linked_ptr, linked_array, intrusive_ptr. |
 
## Module Behaviour
The overhead sizes listed here refer to an optimized release build; debug builds may add some additional overhead. Some of the overhead sizes may be off by a little bit (usually at most 4 bytes). This is because the values reported here are those that refer to when EASTL's container optimizations have been complete. These optimizations may not have been completed as you are reading this.
| Container |Stores | Container Overhead (32 bit) | Container Overhead (64 bit) | Node Overhead (32 bit) | Node Overhead (64 bit) | Iterator category | size() efficiency | operator[] efficiency | Insert efficiency | Erase via Iterator efficiency | Find efficiency | Sort efficiency |
|------|------|------|------|------|------|------|------|------|------|------|------|------|
| slist | T | 8 | 16 | 4 | 8 | f | n | - | 1 | 1 | n | n+ |
| list | T | 12 | 24 | 8 | 16 | b | n | - | 1 | 1 | n | n log(n) |
| intrusive_slist | T | 4 | 8 | 4 | 8 | f | n | - | 1 | 1 | 1 | n+ |
| intrusive_list | T | 8 | 16 | 8 | 16 | b | n | - | 1 | 1 | 1 | n log(n) |
| array | T | 0 | 0 | 0 | 0 | r | 1 | 1 | - | - | n | n log(n) |
| vector | T | 16 | 32 | 0 | 0 | r | 1 | 1 | 1 at end, else n | 1 at end, else n | n | n log(n) |
| vector_set | T | 16 | 32 | 0 | 0 | r | 1 | 1 | 1 at end, else n | 1 at end, else n | log(n) | 1 |
| vector_multiset | T | 16 | 32 | 0 | 0 | r | 1 | 1 | 1 at end, else n | 1 at end, else n | log(n) | 1 |
| vector_map | Key, T | 16 | 32 | 0 | 0 | r | 1 | 1 | 1 at end, else n | 1 at end, else n | log(n) | 1 |
| vector_multimap | Key, T | 16 | 32 | 0 | 0 | r | 1 | 1 | 1 at end, else n | 1 at end, else n | log(n) | 1 |
| deque | T | 44 | 84 | 0 | 0 | r | 1 | 1 | 1 at begin or end, else n / 2 | 1 at begin or end, else n / 2 | n | n log(n) |
| bit_vector | bool | 8 | 16 | 0 | 0 | r | 1 | 1 | 1 at end, else n | 1 at end, else n | n | n log(n) |
| string (all types) | T | 16 | 32 | 0 | 0 | r | 1 | 1 | 1 at end, else n | 1 at end, else n | n | n log(n) |
| set | T | 24 | 44 | 16 | 28 | b | 1 | - | log(n) | log(n) | log(n) | 1 |
| multiset | T | 24 | 44 | 16 | 28 | b | 1 | - | log(n) | log(n) | log(n) | 1 |
| map | Key, T | 24 | 44 | 16 | 28 | b | 1 | log(n) | log(n) | log(n) | log(n) | 1 |
| multimap | Key, T | 24 | 44 | 16 | 28 | b | 1 | - | log(n) | log(n) | log(n) | 1 |
| hash_set | T | 16 | 20 | 4 | 8 | b | 1 | - | 1 | 1 | 1 | - |
| hash_multiset | T | 16 | 20 | 4 | 8 | b | 1 | - | 1 | 1 | 1 | - |
| hash_map | Key, T | 16 | 20 | 4 | 8 | b | 1 | - | 1 | 1 | 1 | - |
| hash_multimap | Key, T | 16 | 20 | 4 | 8 | b | 1 | - | 1 | 1 | 1 | - |
| intrusive_hash_set | T | 16 | 20 | 4 | 8 | b | 1 | - | 1 | 1 | 1 | - |
| intrusive_hash_multiset | T | 16 | 20 | 4 | 8 | b | 1 | - | 1 | 1 | 1 | - |
| intrusive_hash_map | T <small>(Key == T)</small> | 16 | 20 | 4 | 8 | b | 1 | - | 1 | 1 | 1 | - |
| intrusive_hash_multimap | T <small>(Key == T) </small> | 16 | 20 | 4 | 8 | b | 1 | - | 1 | 1 | 1 | - |
* \- means that the operation does not exist.
* 1 means amortized constant time. Also known as O(1)
* n means time proportional to the container size. Also known as O(n)
* log(n) means time proportional to the natural logarithm of the container size. Also known as O(log(n))
* n log(n) means time proportional to log(n) times the size of the container. Also known as O(n log(n))
* n+ means that the time is at least n, and possibly higher.
* Iterator meanings are: f = forward iterator; b = bidirectional iterator, r = random iterator.
* Overhead indicates approximate per-element overhead memory required in bytes. Overhead doesn't include possible additional overhead that may be imposed by the memory heap used to allocate nodes. General heaps tend to have between 4 and 16 bytes of overhead per allocation, depending on the heap.
* Some overhead values are dependent on the structure alignment characteristics in effect. The values reported here are those that would be in effect for a system that requires pointers to be aligned on boundaries of their size and allocations with a minimum of 4 bytes (thus one byte values get rounded up to 4).
* Some overhead values are dependent on the size_type used by containers. We assume a size_type of 4 bytes, even for 64 bit machines, as this is the EASTL default.
* 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.
* 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).
* Some containers (e.g. deque, hash*) have unusual data structures that make per-container and per-node overhead calculations not quite account for all memory.
----------------------------------------------
End of document

31
doc/OpenSource.md Normal file
View File

@@ -0,0 +1,31 @@
=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
HowTo Create the EASTL Open Source repository
=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
This doc outlines how to update the EASTL open source repository on Github.
https://github.com/electronicarts/EASTL/
=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
1) Goto scripts/make_public.bat and update the OPENSOURCE and CODESTRIPPER settings.
* OPENSOURCE: is the directory that will contain the eastl.template folder and it will generate the EASTL open source folder here.
* set OPENSOURCE=e:\p4\opensource\
* CODESTRIPPER: is the directory of the CodeStripper package obtained from perforce
* set CODESTRIPPER=e:\p4\packages\CodeStripper\dev
* NANT_EXE: the complete path to the nant.exe you would like to use.
* set NANT_EXE=E:\p4\packages\Framework\dev\bin\nant.exe
2) Sync the opensource folder from EAOS to the "OPENSOURCE" location
* //EAOS_SB/rparolin/opensource/
3) Download cmake. EASTL requires version at least 3.4.
* https://cmake.org/download/
4) Update the test.bat batch file with the cmake binary folder location
* set CMAKE_BIN=%~dp0/../cmake/cmake-3.4.1-win32-x86/bin
* test.bat is located in the opensouce/east.template/test folder
5) Run the make_public.bat
6) Ensure the grep commands do not find any NDA information.
* grep command found in "grep_for_keywords.bat"
Once the make_public.bat script completes the open source version of EASTL will be located at '%OPENSOURCE%/eastl'

View File

@@ -1,80 +0,0 @@
/////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////
#include <EABase/eabase.h>
#include <stddef.h>
#include <new>
///////////////////////////////////////////////////////////////////////////////
// throw specification wrappers, which allow for portability.
///////////////////////////////////////////////////////////////////////////////
#if defined(EA_COMPILER_NO_EXCEPTIONS) && (!defined(__MWERKS__) || defined(_MSL_NO_THROW_SPECS)) && !defined(EA_COMPILER_RVCT)
#define THROW_SPEC_0 // Throw 0 arguments
#define THROW_SPEC_1(x) // Throw 1 argument
#else
#define THROW_SPEC_0 throw()
#define THROW_SPEC_1(x) throw(x)
#endif
///////////////////////////////////////////////////////////////////////////////
// operator new used by EASTL
///////////////////////////////////////////////////////////////////////////////
void* operator new[](size_t size, const char* /*name*/, int /*flags*/,
unsigned /*debugFlags*/, const char* /*file*/, int /*line*/) THROW_SPEC_1(std::bad_alloc)
{
return malloc(size);
}
void* operator new[](size_t size, size_t alignment, size_t alignmentOffset, const char* /*name*/,
int flags, unsigned /*debugFlags*/, const char* /*file*/, int /*line*/) THROW_SPEC_1(std::bad_alloc)
{
// Substitute your aligned malloc.
return malloc_aligned(size, alignment, alignmentOffset);
}
///////////////////////////////////////////////////////////////////////////////
// Other operator new as typically required by applications.
///////////////////////////////////////////////////////////////////////////////
void* operator new(size_t size) THROW_SPEC_1(std::bad_alloc)
{
return malloc(size);
}
void* operator new[](size_t size) THROW_SPEC_1(std::bad_alloc)
{
return malloc(size);
}
///////////////////////////////////////////////////////////////////////////////
// Operator delete, which is shared between operator new implementations.
///////////////////////////////////////////////////////////////////////////////
void operator delete(void* p) THROW_SPEC_0
{
if(p) // The standard specifies that 'delete NULL' is a valid operation.
free(p);
}
void operator delete[](void* p) THROW_SPEC_0
{
if(p)
free(p);
}

View File

@@ -444,50 +444,15 @@ namespace eastl
}
template <typename T>
inline typename eastl::enable_if<!eastl::is_scalar<T>::value, const T&>::type
inline EA_CONSTEXPR typename eastl::enable_if<!eastl::is_scalar<T>::value, const T&>::type
min(const T& a, const T& b)
{
return b < a ? b : a;
}
#if defined(_MSC_VER) && defined(EA_PROCESSOR_POWERPC)
inline float
min(float a, float b)
{
return (float)__fsel(a - b, b, a);
}
inline double
min(double a, double b)
{
return (double)__fsel(a - b, b, a);
}
#elif defined(_MSC_VER) && defined(EA_PROCESSOR_X86)
// We used to have x86 asm here, but it didn't improve performance.
#elif defined(__GNUC__) && defined(EA_PROCESSOR_POWERPC)
inline float
min(float a, float b)
{
float result, test(a - b);
__asm__ ("fsel %0, %1, %2, %3" : "=f" (result) : "f" (test), "f" (b), "f" (a));
return result;
}
inline double
min(double a, double b)
{
double result, test(a - b);
__asm__ ("fsel %0, %1, %2, %3" : "=f" (result) : "f" (test), "f" (b), "f" (a));
return result;
}
#else
inline EA_CONSTEXPR float min(float a, float b) { return b < a ? b : a; }
inline EA_CONSTEXPR double min(double a, double b) { return b < a ? b : a; }
inline EA_CONSTEXPR long double min(long double a, long double b) { return b < a ? b : a; }
#endif
inline EA_CONSTEXPR float min(float a, float b) { return b < a ? b : a; }
inline EA_CONSTEXPR double min(double a, double b) { return b < a ? b : a; }
inline EA_CONSTEXPR long double min(long double a, long double b) { return b < a ? b : a; }
#endif // EASTL_MINMAX_ENABLED
@@ -513,48 +478,13 @@ namespace eastl
return b < a ? b : a;
}
#if defined(_MSC_VER) && defined(EA_PROCESSOR_POWERPC)
inline float
min_alt(float a, float b)
{
return (float)__fsel(a - b, b, a);
}
inline double
min_alt(double a, double b)
{
return (double)__fsel(a - b, b, a);
}
#elif defined(_MSC_VER) && defined(EA_PROCESSOR_X86)
// We used to have x86 asm here, but it didn't improve performance.
#elif defined(__GNUC__) && defined(EA_PROCESSOR_POWERPC)
inline float
min_alt(float a, float b)
{
float result, test(a - b);
__asm__ ("fsel %0, %1, %2, %3" : "=f" (result) : "f" (test), "f" (b), "f" (a));
return result;
}
inline double
min_alt(double a, double b)
{
double result, test(a - b);
__asm__ ("fsel %0, %1, %2, %3" : "=f" (result) : "f" (test), "f" (b), "f" (a));
return result;
}
#else
inline EA_CONSTEXPR float min_alt(float a, float b) { return b < a ? b : a; }
inline EA_CONSTEXPR double min_alt(double a, double b) { return b < a ? b : a; }
inline EA_CONSTEXPR long double min_alt(long double a, long double b) { return b < a ? b : a; }
#endif
inline EA_CONSTEXPR float min_alt(float a, float b) { return b < a ? b : a; }
inline EA_CONSTEXPR double min_alt(double a, double b) { return b < a ? b : a; }
inline EA_CONSTEXPR long double min_alt(long double a, long double b) { return b < a ? b : a; }
#if EASTL_MINMAX_ENABLED
/// min
///
/// Min returns the lesser of its two arguments; it returns the first
@@ -605,6 +535,7 @@ namespace eastl
#if EASTL_MINMAX_ENABLED
/// max
///
/// Max returns the greater of its two arguments; it returns the first
@@ -627,51 +558,15 @@ namespace eastl
}
template <typename T>
inline typename eastl::enable_if<!eastl::is_scalar<T>::value, const T&>::type
inline EA_CONSTEXPR typename eastl::enable_if<!eastl::is_scalar<T>::value, const T&>::type
max(const T& a, const T& b)
{
return a < b ? b : a;
}
#if defined(_MSC_VER) && defined(EA_PROCESSOR_POWERPC)
inline float
max(float a, float b)
{
return (float)__fsel(a - b, a, b);
}
inline double
max(double a, double b)
{
return (double)__fsel(a - b, a, b);
}
#elif defined(_MSC_VER) && defined(EA_PROCESSOR_X86)
// We used to have x86 asm here, but it didn't improve performance.
#elif defined(__GNUC__) && defined(EA_PROCESSOR_POWERPC)
inline float
max(float a, float b)
{
float result, test(a - b);
__asm__ ("fsel %0, %1, %2, %3" : "=f" (result) : "f" (test), "f" (a), "f" (b));
return result;
}
inline double
max(double a, double b)
{
double result, test(a - b);
__asm__ ("fsel %0, %1, %2, %3" : "=f" (result) : "f" (test), "f" (a), "f" (b));
return result;
}
#else
inline EA_CONSTEXPR float max(float a, float b) { return a < b ? b : a; }
inline EA_CONSTEXPR double max(double a, double b) { return a < b ? b : a; }
inline EA_CONSTEXPR long double max(long double a, long double b) { return a < b ? b : a; }
#endif
inline EA_CONSTEXPR float max(float a, float b) { return a < b ? b : a; }
inline EA_CONSTEXPR double max(double a, double b) { return a < b ? b : a; }
inline EA_CONSTEXPR long double max(long double a, long double b) { return a < b ? b : a; }
#endif // EASTL_MINMAX_ENABLED
@@ -689,50 +584,15 @@ namespace eastl
}
template <typename T>
inline typename eastl::enable_if<!eastl::is_scalar<T>::value, const T&>::type
inline EA_CONSTEXPR typename eastl::enable_if<!eastl::is_scalar<T>::value, const T&>::type
max_alt(const T& a, const T& b)
{
return a < b ? b : a;
}
#if defined(_MSC_VER) && defined(EA_PROCESSOR_POWERPC)
inline float
max_alt(float a, float b)
{
return (float)__fsel(a - b, a, b);
}
inline double
max_alt(double a, double b)
{
return (double)__fsel(a - b, a, b);
}
#elif defined(_MSC_VER) && defined(EA_PROCESSOR_X86)
// We used to have x86 asm here, but it didn't improve performance.
#elif defined(__GNUC__) && defined(EA_PROCESSOR_POWERPC)
inline float
max_alt(float a, float b)
{
float result, test(a - b);
__asm__ ("fsel %0, %1, %2, %3" : "=f" (result) : "f" (test), "f" (a), "f" (b));
return result;
}
inline double
max_alt(double a, double b)
{
double result, test(a - b);
__asm__ ("fsel %0, %1, %2, %3" : "=f" (result) : "f" (test), "f" (a), "f" (b));
return result;
}
#else
inline EA_CONSTEXPR float max_alt(float a, float b) { return a < b ? b : a; }
inline EA_CONSTEXPR double max_alt(double a, double b) { return a < b ? b : a; }
inline EA_CONSTEXPR long double max_alt(long double a, long double b) { return a < b ? b : a; }
#endif
inline EA_CONSTEXPR float max_alt(float a, float b) { return a < b ? b : a; }
inline EA_CONSTEXPR double max_alt(double a, double b) { return a < b ? b : a; }
inline EA_CONSTEXPR long double max_alt(long double a, long double b) { return a < b ? b : a; }
#if EASTL_MINMAX_ENABLED

View File

@@ -501,16 +501,20 @@ namespace eastl
m_handler = tmp.m_handler;
tmp.m_handler(storage_operation::MOVE, &tmp, this);
}
else if (m_handler == nullptr)
else if (m_handler == nullptr && other.m_handler)
{
eastl::swap(m_handler, other.m_handler);
m_handler(storage_operation::MOVE, &other, this);
}
else if(other.m_handler == nullptr)
else if(m_handler && other.m_handler == nullptr)
{
eastl::swap(m_handler, other.m_handler);
other.m_handler(storage_operation::MOVE, this, &other);
}
//else if (m_handler == nullptr && other.m_handler == nullptr)
//{
// // nothing to swap
//}
}
// 20.7.3.4, observers

View File

@@ -157,7 +157,7 @@ struct TupleRecurser<>
static EA_CONSTEXPR size_type GetTotalAllocationSize(size_type capacity, size_type offset)
{
(void)capacity;
EA_UNUSED(capacity);
return offset;
}

View File

@@ -13,9 +13,13 @@
namespace eastl
{
#define EASTL_INTERNAL_FIXED_FUNCTION_STATIC_ASSERT(TYPE) \
static_assert(sizeof(TYPE) <= sizeof(typename Base::FunctorStorageType), \
"fixed_function local buffer is not large enough to hold the callable object.")
#define EASTL_INTERNAL_FIXED_FUNCTION_STATIC_ASSERT(TYPE) \
static_assert(sizeof(TYPE) <= sizeof(typename Base::FunctorStorageType), "fixed_function local buffer is not large enough to hold the callable object.")
#define EASTL_INTERNAL_FIXED_FUNCTION_NEW_SIZE_STATIC_ASSERT(NEW_SIZE_IN_BYTES) \
static_assert(SIZE_IN_BYTES >= NEW_SIZE_IN_BYTES, \
"fixed_function local buffer is not large enough to hold the new fixed_function type.")
template <int, typename>
class fixed_function;
@@ -23,8 +27,8 @@ namespace eastl
template <int SIZE_IN_BYTES, typename R, typename... Args>
class fixed_function<SIZE_IN_BYTES, R(Args...)> : public internal::function_detail<SIZE_IN_BYTES, R(Args...)>
{
private:
using Base = internal::function_detail<SIZE_IN_BYTES, R(Args...)>;
public:
using typename Base::result_type;
@@ -50,6 +54,20 @@ namespace eastl
{
EASTL_INTERNAL_FIXED_FUNCTION_STATIC_ASSERT(Functor);
}
template<int NEW_SIZE_IN_BYTES>
fixed_function(const fixed_function<NEW_SIZE_IN_BYTES, R(Args...)>& other)
: Base(other)
{
EASTL_INTERNAL_FIXED_FUNCTION_NEW_SIZE_STATIC_ASSERT(NEW_SIZE_IN_BYTES);
}
template<int NEW_SIZE_IN_BYTES>
fixed_function(fixed_function<NEW_SIZE_IN_BYTES, R(Args...)>&& other)
: Base(eastl::move(other))
{
EASTL_INTERNAL_FIXED_FUNCTION_NEW_SIZE_STATIC_ASSERT(NEW_SIZE_IN_BYTES);
}
~fixed_function() EA_NOEXCEPT = default;
@@ -71,6 +89,24 @@ namespace eastl
return *this;
}
template<int NEW_SIZE_IN_BYTES>
fixed_function& operator=(const fixed_function<NEW_SIZE_IN_BYTES, R(Args...)>& other)
{
EASTL_INTERNAL_FIXED_FUNCTION_NEW_SIZE_STATIC_ASSERT(NEW_SIZE_IN_BYTES);
Base::operator=(other);
return *this;
}
template<int NEW_SIZE_IN_BYTES>
fixed_function& operator=(fixed_function<NEW_SIZE_IN_BYTES, R(Args...)>&& other)
{
EASTL_INTERNAL_FIXED_FUNCTION_NEW_SIZE_STATIC_ASSERT(NEW_SIZE_IN_BYTES);
Base::operator=(eastl::move(other));
return *this;
}
template <typename Functor, typename = EASTL_INTERNAL_FUNCTION_VALID_FUNCTION_ARGS(Functor, R, Args..., Base, fixed_function)>
fixed_function& operator=(Functor&& functor)
{
@@ -103,7 +139,6 @@ namespace eastl
}
#if EASTL_RTTI_ENABLED
const std::type_info& target_type() const EA_NOEXCEPT
{
return Base::target_type();
@@ -120,7 +155,6 @@ namespace eastl
{
return Base::target();
}
#endif
};

View File

@@ -89,7 +89,7 @@
///////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_VERSION
#define EASTL_VERSION "3.13.05"
#define EASTL_VERSION "3.13.06"
#define EASTL_VERSION_N 31305
#endif

View File

@@ -101,6 +101,9 @@ namespace eastl
(eastl::alignment_of_v<functor_storage<SIZE_IN_BYTES>> % eastl::alignment_of_v<Functor>) == 0;
};
/// function_base_detail
///
template <int SIZE_IN_BYTES>
class function_base_detail
{
@@ -328,6 +331,9 @@ namespace eastl
#define EASTL_INTERNAL_FUNCTION_DETAIL_VALID_FUNCTION_ARGS(FUNCTOR, RET, ARGS, MYSELF) \
EASTL_INTERNAL_FUNCTION_VALID_FUNCTION_ARGS(FUNCTOR, RET, ARGS, MYSELF, MYSELF)
/// function_detail
///
template <int, typename>
class function_detail;

View File

@@ -985,7 +985,7 @@ namespace eastl
EA_CPP14_CONSTEXPR auto data(const Container& c) -> decltype(c.data())
{ return c.data(); }
template <class T, std::size_t N>
template <class T, size_t N>
EA_CPP14_CONSTEXPR T* data(T(&array)[N]) EA_NOEXCEPT
{ return array; }
@@ -1002,11 +1002,28 @@ namespace eastl
EA_CPP14_CONSTEXPR auto size(const C& c) -> decltype(c.size())
{ return c.size(); }
template <class T, std::size_t N>
EA_CPP14_CONSTEXPR std::size_t size(const T (&)[N]) EA_NOEXCEPT
template <class T, size_t N>
EA_CPP14_CONSTEXPR size_t size(const T (&)[N]) EA_NOEXCEPT
{ return N; }
// eastl::ssize
//
// https://en.cppreference.com/w/cpp/iterator/size
//
template <class T, ptrdiff_t N>
EA_CPP14_CONSTEXPR ptrdiff_t ssize(const T(&)[N]) EA_NOEXCEPT
{ return N; }
template <class C>
EA_CPP14_CONSTEXPR auto ssize(const C& c)
-> eastl::common_type_t<ptrdiff_t, eastl::make_signed_t<decltype(c.size())>>
{
using R = eastl::common_type_t<ptrdiff_t, eastl::make_signed_t<decltype(c.size())>>;
return static_cast<R>(c.size());
}
// eastl::empty
//
// http://en.cppreference.com/w/cpp/iterator/empty
@@ -1015,7 +1032,7 @@ namespace eastl
EA_CPP14_CONSTEXPR auto empty(const Container& c) -> decltype(c.empty())
{ return c.empty(); }
template <class T, std::size_t N>
template <class T, size_t N>
EA_CPP14_CONSTEXPR bool empty(const T (&)[N]) EA_NOEXCEPT
{ return false; }

View File

@@ -393,14 +393,24 @@ namespace eastl
template <class... Args>
void emplace(Args&&... args)
{
construct_value(eastl::move(T(eastl::forward<Args>(args)...)));
if (engaged)
{
destruct_value();
engaged = false;
}
construct_value(eastl::forward<Args>(args)...);
engaged = true;
}
template <class U, class... Args>
void emplace(std::initializer_list<U> ilist, Args&&... args)
{
construct_value(eastl::move(T(ilist, eastl::forward<Args>(args)...)));
if (engaged)
{
destruct_value();
engaged = false;
}
construct_value(ilist, eastl::forward<Args>(args)...);
engaged = true;
}
@@ -440,11 +450,9 @@ namespace eastl
private:
inline void construct_value(const value_type& v)
{ ::new (eastl::addressof(val)) value_type(v); }
inline void construct_value(value_type&& v)
{ ::new (eastl::addressof(val)) value_type(eastl::move(v)); }
template <class... Args>
inline void construct_value(Args&&... args)
{ ::new (eastl::addressof(val)) value_type(eastl::forward<Args>(args)...); }
inline T* get_value_address() EASTL_OPTIONAL_NOEXCEPT
{

View File

@@ -780,6 +780,7 @@
#define EA_DISABLE_CLANG_WARNING(w) \
_Pragma("clang diagnostic push") \
_Pragma(EACLANGWHELP2(-Wunknown-warning-option))\
_Pragma(EACLANGWHELP2(w))
#else
#define EA_DISABLE_CLANG_WARNING(w)
@@ -1524,7 +1525,7 @@
#else
#define EA_SSE 0
#endif
#elif (defined(EA_SSE3) && EA_SSE3) || defined EA_PLATFORM_CAPILANO
#elif (defined(EA_SSE3) && EA_SSE3) || defined EA_PLATFORM_XBOXONE
#define EA_SSE 3
#elif defined(EA_SSE2) && EA_SSE2
#define EA_SSE 2
@@ -1563,28 +1564,28 @@
#endif
#endif
#ifndef EA_SSSE3
#if defined __SSSE3__ || defined EA_PLATFORM_CAPILANO
#if defined __SSSE3__ || defined EA_PLATFORM_XBOXONE
#define EA_SSSE3 1
#else
#define EA_SSSE3 0
#endif
#endif
#ifndef EA_SSE4_1
#if defined __SSE4_1__ || defined EA_PLATFORM_CAPILANO
#if defined __SSE4_1__ || defined EA_PLATFORM_XBOXONE
#define EA_SSE4_1 1
#else
#define EA_SSE4_1 0
#endif
#endif
#ifndef EA_SSE4_2
#if defined __SSE4_2__ || defined EA_PLATFORM_CAPILANO
#if defined __SSE4_2__ || defined EA_PLATFORM_XBOXONE
#define EA_SSE4_2 1
#else
#define EA_SSE4_2 0
#endif
#endif
#ifndef EA_SSE4A
#if defined __SSE4A__ || defined EA_PLATFORM_CAPILANO
#if defined __SSE4A__ || defined EA_PLATFORM_XBOXONE
#define EA_SSE4A 1
#else
#define EA_SSE4A 0
@@ -1602,7 +1603,7 @@
#ifndef EA_AVX
#if defined __AVX2__
#define EA_AVX 2
#elif defined __AVX__ || defined EA_PLATFORM_CAPILANO
#elif defined __AVX__ || defined EA_PLATFORM_XBOXONE
#define EA_AVX 1
#else
#define EA_AVX 0
@@ -1619,7 +1620,7 @@
// EA_FP16C may be used to determine the existence of float <-> half conversion operations on an x86 CPU.
// (For example to determine if _mm_cvtph_ps or _mm_cvtps_ph could be used.)
#ifndef EA_FP16C
#if defined __F16C__ || defined EA_PLATFORM_CAPILANO
#if defined __F16C__ || defined EA_PLATFORM_XBOXONE
#define EA_FP16C 1
#else
#define EA_FP16C 0
@@ -1630,7 +1631,7 @@
// but has support by some implementations of clang (__FLOAT128__)
// PS4 does not support __float128 as of SDK 5.500 https://ps4.siedev.net/resources/documents/SDK/5.500/CPU_Compiler_ABI-Overview/0003.html
#ifndef EA_FP128
#if (defined __FLOAT128__ || defined _GLIBCXX_USE_FLOAT128) && !defined(EA_PLATFORM_KETTLE)
#if (defined __FLOAT128__ || defined _GLIBCXX_USE_FLOAT128) && !defined(EA_PLATFORM_PS4)
#define EA_FP128 1
#else
#define EA_FP128 0
@@ -1671,7 +1672,7 @@
#ifndef EA_BMI
#if defined(__BMI2__)
#define EA_BMI 2
#elif defined(__BMI__) || defined(EA_PLATFORM_CAPILANO)
#elif defined(__BMI__) || defined(EA_PLATFORM_XBOXONE)
#define EA_BMI 1
#else
#define EA_BMI 0

View File

@@ -125,7 +125,7 @@
#endif
#elif defined(EA_PLATFORM_XBOXONE) || defined(_DURANGO) || defined(EA_PLATFORM_CAPILANO)
#elif defined(EA_PLATFORM_XBOXONE) || defined(_DURANGO) || defined(EA_PLATFORM_CAPILANO) || (defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_GAMES || WINAPI_FAMILY == WINAPI_FAMILY_TV_TITLE))
// XBox One
// Durango was Microsoft's code-name for the platform, which is now obsolete.
// Microsoft uses _DURANGO instead of some variation of _XBOX, though it's not natively defined by the compiler.
@@ -166,6 +166,7 @@
#define EA_WINAPI_FAMILY_PHONE_APP 1002
#define EA_WINAPI_FAMILY_TV_APP 1003
#define EA_WINAPI_FAMILY_TV_TITLE 1004
#define EA_WINAPI_FAMILY_GAMES 1006
#if defined(WINAPI_FAMILY)
#include <winapifamily.h>
@@ -173,6 +174,8 @@
#define EA_WINAPI_FAMILY EA_WINAPI_FAMILY_TV_TITLE
#elif WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP
#define EA_WINAPI_FAMILY EA_WINAPI_FAMILY_DESKTOP_APP
#elif WINAPI_FAMILY == WINAPI_FAMILY_GAMES
#define EA_WINAPI_FAMILY EA_WINAPI_FAMILY_GAMES
#else
#error Unsupported WINAPI_FAMILY
#endif
@@ -191,6 +194,7 @@
#define EA_WIANPI_PARTITION_PHONE 0
#define EA_WINAPI_PARTITION_TV_APP 0
#define EA_WINAPI_PARTITION_TV_TITLE 0
#define EA_WINAPI_PARTITION_GAMES 0
#elif EA_WINAPI_FAMILY == EA_WINAPI_FAMILY_TV_TITLE
#define EA_WINAPI_PARTITION_CORE 1
#define EA_WINAPI_PARTITION_DESKTOP 0
@@ -199,6 +203,16 @@
#define EA_WIANPI_PARTITION_PHONE 0
#define EA_WINAPI_PARTITION_TV_APP 0
#define EA_WINAPI_PARTITION_TV_TITLE 1
#define EA_WINAPI_PARTITION_GAMES 0
#elif EA_WINAPI_FAMILY == EA_WINAPI_FAMILY_GAMES
#define EA_WINAPI_PARTITION_CORE 1
#define EA_WINAPI_PARTITION_DESKTOP 0
#define EA_WINAPI_PARTITION_APP 0
#define EA_WINAPI_PARTITION_PC_APP 0
#define EA_WIANPI_PARTITION_PHONE 0
#define EA_WINAPI_PARTITION_TV_APP 0
#define EA_WINAPI_PARTITION_TV_TITLE 0
#define EA_WINAPI_PARTITION_GAMES 1
#else
#error Unsupported WINAPI_FAMILY
#endif
@@ -547,10 +561,8 @@
#define EA_PLATFORM_MICROSOFT 1
// WINAPI_FAMILY defines to support Windows 8 Metro Apps - mirroring winapifamily.h in the Windows 8 SDK
#define EA_WINAPI_PARTITION_DESKTOP 0x00000001
#define EA_WINAPI_PARTITION_APP 0x00000002
#define EA_WINAPI_FAMILY_APP EA_WINAPI_PARTITION_APP
#define EA_WINAPI_FAMILY_DESKTOP_APP (EA_WINAPI_PARTITION_DESKTOP | EA_WINAPI_PARTITION_APP)
#define EA_WINAPI_FAMILY_APP 1000
#define EA_WINAPI_FAMILY_DESKTOP_APP 1001
#if defined(WINAPI_FAMILY)
#if defined(_MSC_VER)
@@ -571,7 +583,10 @@
#define EA_WINAPI_FAMILY EA_WINAPI_FAMILY_DESKTOP_APP
#endif
#define EA_WINAPI_FAMILY_PARTITION(Partition) ((EA_WINAPI_FAMILY & Partition) == Partition)
#define EA_WINAPI_PARTITION_DESKTOP 1
#define EA_WINAPI_PARTITION_APP 1
#define EA_WINAPI_FAMILY_PARTITION(Partition) (Partition)
// EA_PLATFORM_WINRT
// This is a subset of Windows which is used for tablets and the "Metro" (restricted) Windows user interface.

View File

@@ -34,7 +34,7 @@
// not standards-compliant in this respect, so we need an additional include.
// The case is similar with wchar_t under C++.
#if defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_MSVC) || defined(EA_WCHAR_T_NON_NATIVE) || defined(EA_PLATFORM_KETTLE)
#if defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_MSVC) || defined(EA_WCHAR_T_NON_NATIVE) || defined(EA_PLATFORM_PS4)
#if defined(EA_COMPILER_MSVC)
#pragma warning(push, 0)
#pragma warning(disable: 4265 4365 4836 4574)

View File

@@ -234,7 +234,7 @@
// #include <sys/signal.h>
#if !defined(EA_HAVE_SYS_SIGNAL_H) && !defined(EA_NO_HAVE_SYS_SIGNAL_H)
#if defined(EA_PLATFORM_BSD) || defined(EA_PLATFORM_KETTLE)
#if defined(EA_PLATFORM_BSD) || defined(EA_PLATFORM_PS4)
#define EA_HAVE_SYS_SIGNAL_H 1
#else
#define EA_NO_HAVE_SYS_SIGNAL_H 1
@@ -270,7 +270,7 @@
// #include <alloca.h>
#if !defined(EA_HAVE_ALLOCA_H) && !defined(EA_NO_HAVE_ALLOCA_H)
#if !defined(EA_HAVE_MALLOC_H) && !defined(EA_PLATFORM_KETTLE)
#if !defined(EA_HAVE_MALLOC_H) && !defined(EA_PLATFORM_PS4)
#define EA_HAVE_ALLOCA_H 1
#else
#define EA_NO_HAVE_ALLOCA_H 1
@@ -592,7 +592,7 @@
#endif
#if !defined(EA_HAVE_nanosleep_DECL) && !defined(EA_NO_HAVE_nanosleep_DECL)
#if (defined(EA_PLATFORM_UNIX) && !defined(EA_PLATFORM_SONY)) || defined(EA_PLATFORM_IPHONE) || defined(EA_PLATFORM_OSX) || defined(EA_PLATFORM_KETTLE)
#if (defined(EA_PLATFORM_UNIX) && !defined(EA_PLATFORM_SONY)) || defined(EA_PLATFORM_IPHONE) || defined(EA_PLATFORM_OSX) || defined(EA_PLATFORM_PS4)
#define EA_HAVE_nanosleep_DECL 1
#else
#define EA_NO_HAVE_nanosleep_DECL 1

View File

@@ -29,8 +29,8 @@
///////////////////////////////////////////////////////////////////////////////
#ifndef EABASE_VERSION
#define EABASE_VERSION "2.09.03"
#define EABASE_VERSION_N 20903
#define EABASE_VERSION "2.09.04"
#define EABASE_VERSION_N 20904
#endif
#endif

View File

@@ -111,7 +111,7 @@
#define EATEST_DEBUG_BREAK() __debugbreak() // This is a compiler intrinsic which will map to appropriate inlined asm for the platform.
#elif defined(EA_PLATFORM_SONY) && defined(EA_PROCESSOR_X86_64)
#define EATEST_DEBUG_BREAK() do { { __asm volatile ("int $0x41"); } } while(0)
#elif defined(EA_PROCESSOR_ARM) && (defined(__APPLE__) || defined(CS_UNDEFINED_STRING))
#elif defined(EA_PROCESSOR_ARM) && defined(__APPLE__)
#include <signal.h>
#include <unistd.h>
#define EATEST_DEBUG_BREAK() kill(getpid(), SIGINT) // This lets you continue execution.

View File

@@ -35,170 +35,8 @@
///////////////////////////////////////////////////////////////////////////////
#ifndef EATEST_VERSION
#define EATEST_VERSION "2.08.05"
#define EATEST_VERSION_N 20805
#endif
///////////////////////////////////////////////////////////////////////////////
// EA_PLATFORM_MOBILE
//
// Defined as 1 or undefined.
// Implements support for the definition of EA_PLATFORM_MOBILE for the case
// of using EABase versions prior to the addition of its EA_PLATFORM_MOBILE support.
//
#if (EABASE_VERSION_N < 20022) && !defined(EA_PLATFORM_MOBILE) // If using an older EABase package which doesn't yet support this... implement our own version.
#if defined(EA_PLATFORM_IPHONE) || defined(EA_PLATFORM_ANDROID) || defined(CS_UNDEFINED_STRING) || \
defined(CS_UNDEFINED_STRING) || defined(CS_UNDEFINED_STRING) || defined(EA_PLATFORM_WINCE)
#define EA_PLATFORM_MOBILE 1
#endif
#endif
///////////////////////////////////////////////////////////////////////////////
// EA_PLATFORM_MICROSOFT
//
// Defined as 1 or undefined.
// Implements support for the definition of EA_PLATFORM_MICROSOFT for the case
// of using EABase versions prior to the addition of its EA_PLATFORM_MICROSOFT support.
//
#if (EABASE_VERSION_N < 20022) && !defined(EA_PLATFORM_MICROSOFT) // If using an older EABase package which doesn't yet support this... implement our own version.
#if defined(EA_PLATFORM_WINDOWS) || defined(CS_UNDEFINED_STRING)
#define EA_PLATFORM_MICROSOFT 1
#endif
#endif
///////////////////////////////////////////////////////////////////////////////
// EA_COMPILER_NO_VARIADIC_MACROS
//
// If defined, the compiler doesn't support C99/C++0x variadic macros.
// With a variadic macro, you can do this:
// #define MY_PRINTF(format, ...) printf(format, __VA_ARGS__)
//
#if (EABASE_VERSION_N < 20024) // If using an older EABase package which doesn't yet support this... implement our own version.
#if !defined(EA_COMPILER_NO_VARIADIC_MACROS)
#if defined(_MSC_VER) && (_MSC_VER < 1500) // If earlier than VS2008..
#define EA_COMPILER_NO_VARIADIC_MACROS
#endif
#endif
#endif
///////////////////////////////////////////////////////////////////////////////
// EA_WINAPI_FAMILY_PARTITION / EA_WINAPI_PARTITION
//
// Provides the EA_WINAPI_FAMILY_PARTITION macro for testing API support under
// Microsoft platforms, plus associated API identifiers for this macro.
//
// Current API identifiers:
// EA_WINAPI_PARTITION_NONE
// EA_WINAPI_PARTITION_DESKTOP
//
// Example usage:
// #if defined(EA_PLATFORM_MICROSOFT)
// #if EA_WINAPI_FAMILY_PARTITION(EA_WINAPI_PARTITION_DESKTOP)
// GetEnvironmentVariableA("PATH", env, sizeof(env));
// #else
// // not supported.
// #endif
// #endif
//
#if !defined(EA_WINAPI_FAMILY_PARTITION)
#define EA_WINAPI_FAMILY_PARTITION(partition) (partition)
#endif
#if !defined(EA_WINAPI_PARTITION_NONE) && !defined(EA_WINAPI_PARTITION_DESKTOP) && !defined(CS_UNDEFINED_STRING)
#if defined(EA_PLATFORM_MICROSOFT)
#if defined(EA_PLATFORM_WINDOWS)
#define EA_WINAPI_PARTITION_DESKTOP 1
#else
// Nothing defined. Future values (e.g. Windows Phone) would go here.
#endif
#else
#define EA_WINAPI_PARTITION_NONE 1
#endif
#endif
#if !defined(EA_WINAPI_PARTITION_NONE)
#define EA_WINAPI_PARTITION_NONE 0
#endif
#if !defined(EA_WINAPI_PARTITION_DESKTOP)
#define EA_WINAPI_PARTITION_DESKTOP 0
#endif
#define CS_UNDEFINED_STRING 0
///////////////////////////////////////////////////////////////////////////////
// EA_DISABLE_ALL_VC_WARNINGS / EA_RESTORE_ALL_VC_WARNINGS
//
// Disable and re-enable all warning(s) within code.
//
// Example usage:
// EA_DISABLE_ALL_VC_WARNINGS()
// <code>
// EA_RESTORE_ALL_VC_WARNINGS()
//
#ifndef EA_DISABLE_ALL_VC_WARNINGS
#if defined(_MSC_VER)
#define EA_DISABLE_ALL_VC_WARNINGS() \
__pragma(warning(push, 0))
#else
#define EA_DISABLE_ALL_VC_WARNINGS()
#endif
#endif
#ifndef EA_RESTORE_ALL_VC_WARNINGS
#if defined(_MSC_VER)
#define EA_RESTORE_ALL_VC_WARNINGS() \
__pragma(warning(pop))
#else
#define EA_RESTORE_ALL_VC_WARNINGS()
#endif
#endif
///////////////////////////////////////////////////////////////////////////////
// EA_UNUSED
//
// Makes compiler warnings about unused variables go away.
//
// Example usage:
// void Function(int x)
// {
// int y;
// EA_UNUSED(x);
// EA_UNUSED(y);
// }
//
#ifndef EA_UNUSED // Recent versions of EABase now define this.
// The EDG solution below is pretty weak and needs to be augmented or replaced.
// It can't handle the C language, is limited to places where template declarations
// can be used, and requires the type x to be usable as a functions reference argument.
#if defined(__cplusplus) && defined(__EDG__) && !defined(CS_UNDEFINED_STRING) && !defined(CS_UNDEFINED_STRING) // All EDG variants allows usage of (void)x;
template <typename T>
inline void EABaseUnused(T const volatile & x) { (void)x; }
#define EA_UNUSED(x) EABaseUnused(x)
#else
#define EA_UNUSED(x) (void)x
#endif
#endif
///////////////////////////////////////////////////////////////////////////////
// EA_COMPILER_VA_COPY_REQUIRED
//
// This is already present in EABase version >= 2.00.40
// See EABase for documentation.
//
#ifndef EA_COMPILER_VA_COPY_REQUIRED
#if (EABASE_VERSION_N < 20040) // If not already handled by EABase...
#if ((defined(__GNUC__) && (__GNUC__ >= 3)) || defined(__clang__)) && (!defined(__i386__) || defined(__x86_64__)) && !defined(__ppc__) && !defined(__PPC__) && !defined(__PPC64__)
#define EA_COMPILER_VA_COPY_REQUIRED 1
#endif
#endif
#define EATEST_VERSION "2.08.06"
#define EATEST_VERSION_N 20806
#endif
@@ -216,8 +54,6 @@
#endif
///////////////////////////////////////////////////////////////////////////////
// EATEST_ALIGNMENT_EXCEPTION_DETECTION_CALLED
//

View File

@@ -30,11 +30,11 @@
#include <stdarg.h>
#if defined(EA_PLATFORM_MICROSOFT)
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <Windows.h>
extern "C" WINBASEAPI BOOL WINAPI IsDebuggerPresent();
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <Windows.h>
extern "C" WINBASEAPI BOOL WINAPI IsDebuggerPresent();
#if EA_WINAPI_FAMILY_PARTITION(EA_WINAPI_PARTITION_DESKTOP) && !defined(EA_COMPILER_CLANG)
#pragma comment(lib, "Advapi32.lib"); // For CheckTokenMembership and friends.
@@ -47,14 +47,11 @@
#include <sys/sysctl.h>
#import <mach/mach.h>
#import <mach/mach_host.h>
#elif defined(EA_PLATFORM_KETTLE)
#elif defined(EA_PLATFORM_PS4)
#include <unistd.h>
#include <sys/types.h>
#include <sdk_version.h>
#if (SCE_ORBIS_SDK_VERSION >= 0x00930000u) // SDK 930+
#include <libdbg.h>
#endif
#include <libdbg.h>
#elif defined(EA_PLATFORM_BSD)
#include <sys/types.h>
#include <sys/ptrace.h>
@@ -273,9 +270,9 @@ EATEST_API int& WriteToEnsureFunctionCalled()
EATEST_API bool IsDebuggerPresent()
{
#if defined(EA_PLATFORM_MICROSOFT)
return ::IsDebuggerPresent() != 0;
return ::IsDebuggerPresent() != 0;
#elif defined(EA_PLATFORM_KETTLE) && (SCE_ORBIS_SDK_VERSION >= 0x00930000u)
#elif defined(EA_PLATFORM_PS4)
return (sceDbgIsDebuggerAttached() != 0);
#elif defined(__APPLE__) // OS X, iPhone, iPad, etc.

View File

@@ -125,6 +125,34 @@ static int TestMinMax()
EA::UnitTest::Rand rng(EA::UnitTest::GetRandSeed());
{
// NOTE(rparolin): This compiles but it should not. We provide explicit eastl::max overloads for float, double,
// and long double which enable this behaviour. It is not standards compliant and it will be removed in a
// future release.
{
struct Foo
{
operator float() const { return 0; }
};
Foo f1;
float f2{};
eastl::max(f1, f2);
}
// NOTE(rparolin): This will not compile because we lack explicit eastl::max overloads for 'int'.
// {
// struct Foo
// {
// operator int() const { return 0; }
// };
// Foo f1;
// int f2{};
// eastl::max(f1, f2);
// }
}
{
// const T& min(const T& a, const T& b);
// const T& min(const T& a, const T& b, Compare compare)

View File

@@ -428,6 +428,44 @@ int TestAny()
VERIFY((*r) == 3);
}
// user regression when calling the assignment operator
{
{
eastl::any a1;
eastl::any a2;
VERIFY(a1.has_value() == false);
VERIFY(a2.has_value() == false);
a1 = a2;
VERIFY(a1.has_value() == false);
VERIFY(a2.has_value() == false);
}
{
eastl::any a1 = 42;
eastl::any a2;
VERIFY(a1.has_value() == true);
VERIFY(a2.has_value() == false);
a1 = a2;
VERIFY(a1.has_value() == false);
VERIFY(a2.has_value() == false);
}
{
eastl::any a1;
eastl::any a2 = 42;
VERIFY(a1.has_value() == false);
VERIFY(a2.has_value() == true);
a1 = a2;
VERIFY(a1.has_value() == true);
VERIFY(a2.has_value() == true);
VERIFY(any_cast<int>(a1) == 42);
VERIFY(any_cast<int>(a2) == 42);
}
}
return nErrorCount;
}

View File

@@ -541,6 +541,37 @@ int TestFixedFunctionBasic()
nErrorCount += TestFixedFunctionCaptureless<ff_4096>();
}
// Verify conversions to fixed_function<N> for sizes greater or equal to the source size.
{
uint32_t v0 = 130480, v1 = 936780302;
const uint32_t result = v0 + v1;
eastl::fixed_function<8, uint32_t(void)> ff8 = [v0, v1]
{ return v0 + v1; };
{
eastl::fixed_function<16, uint32_t(void)> ff16(ff8);
VERIFY(result == ff16());
}
{
eastl::fixed_function<16, uint32_t(void)> ff16 = ff8;
VERIFY(result == ff16());
}
{
auto ff8Copy = ff8;
eastl::fixed_function<16, uint32_t(void)> ff16(eastl::move(ff8Copy));
VERIFY(result == ff16());
}
{
auto ff8Copy = ff8;
eastl::fixed_function<16, uint32_t(void)> ff16 = eastl::move(ff8Copy);
VERIFY(result == ff16());
}
}
return nErrorCount;
}

View File

@@ -280,6 +280,18 @@ int TestIterator()
EATEST_VERIFY(eastl::size(intCArray) == 34);
}
// eastl::ssize
{
eastl::vector<int> intVector;
intVector.push_back();
intVector.push_back();
intVector.push_back();
EATEST_VERIFY(eastl::ssize(intVector) == (signed)3);
int intCArray[34];
EATEST_VERIFY(eastl::ssize(intCArray) == (signed)34);
}
// eastl::empty
{
eastl::vector<int> intVector;

View File

@@ -367,6 +367,35 @@ int TestOptional()
o.emplace(42);
VERIFY(*o == 42);
}
struct nonCopyableNonMovable
{
nonCopyableNonMovable(int v) : val(v) {}
nonCopyableNonMovable(const nonCopyableNonMovable&) = delete;
nonCopyableNonMovable(nonCopyableNonMovable&&) = delete;
nonCopyableNonMovable& operator=(const nonCopyableNonMovable&) = delete;
int val = 0;
};
{
optional<nonCopyableNonMovable> o;
o.emplace(42);
VERIFY(o->val == 42);
}
{
// Verify emplace will destruct object if it has been engaged.
destructor_test::reset();
optional<destructor_test> o;
o.emplace();
VERIFY(!destructor_test::destructor_ran);
destructor_test::reset();
o.emplace();
VERIFY(destructor_test::destructor_ran);
}
}
#endif

View File

@@ -34,12 +34,10 @@ EA_RESTORE_ALL_VC_WARNINGS()
return EA::StdC::Vsnprintf(pDestination, n, pFormat, arguments);
}
#if (EASTDC_VERSION_N >= 10600)
int Vsnprintf32(char32_t* pDestination, size_t n, const char32_t* pFormat, va_list arguments)
{
return EA::StdC::Vsnprintf(pDestination, n, pFormat, arguments);
}
#endif
int Vsnprintf32(char32_t* pDestination, size_t n, const char32_t* pFormat, va_list arguments)
{
return EA::StdC::Vsnprintf(pDestination, n, pFormat, arguments);
}
#if defined(EA_WCHAR_UNIQUE) && EA_WCHAR_UNIQUE
int VsnprintfW(wchar_t* pDestination, size_t n, const wchar_t* pFormat, va_list arguments)