First
This commit is contained in:
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,424 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<title>EASTL Design</title>
|
||||
<meta content="text/html; charset=us-ascii" http-equiv="content-type">
|
||||
<meta name="author" content="Paul Pedriana">
|
||||
<meta name="description" content="Discusses various design aspects of EASTL.">
|
||||
<link type="text/css" rel="stylesheet" href="EASTLDoc.css">
|
||||
</head>
|
||||
<body>
|
||||
<h1>EASTL Design</h1>
|
||||
<h2> Introduction</h2>
|
||||
<p>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:</p>
|
||||
<ul>
|
||||
<li>EASTL has a simplified and more flexible custom allocation scheme.</li>
|
||||
<li>EASTL has significantly easier to read code.</li>
|
||||
<li>EASTL has extension containers and algorithms.</li>
|
||||
<li>EASTL has optimizations designed for game development.</li>
|
||||
</ul>
|
||||
<p>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.</p>
|
||||
<h2>Motivations</h2>
|
||||
<p>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:
|
||||
</p>
|
||||
<ul>
|
||||
<li><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></li>
|
||||
<li>The STL is sometimes hard to debug, as most STL implementations use cryptic variable names and unusual data
|
||||
structures.</li>
|
||||
<li>STL allocators are sometimes painful to work with, as they have many requirements and cannot be modified once bound
|
||||
to a container.</li>
|
||||
<li>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.</li>
|
||||
<li>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.</li>
|
||||
<li>The STL doesn't support alignment of contained objects.</li>
|
||||
<li>STL containers won't let you insert an entry into a container without supplying an entry to copy from. This can be
|
||||
inefficient.</li>
|
||||
<li>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.<br></li>
|
||||
<li>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.</li>
|
||||
<li>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.</li>
|
||||
<li>The STL puts an emphasis on correctness before performance, whereas sometimes you can get significant performance
|
||||
gains by making things less academcially pure.</li>
|
||||
<li>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).</li>
|
||||
<li>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.</li>
|
||||
<li>The STL is slow to compile, as most modern STL implementations are very large.<br></li>
|
||||
<li>There are legal issues that make it hard for us to freely use portable STL implementations such as STLPort.</li>
|
||||
<li>We have no say in the design and implementation of the STL and so are unable to change it to work for our
|
||||
needs.</li>
|
||||
</ul>
|
||||
<h2>Prime Directives</h2>
|
||||
<p>The implementation of EASTL is guided foremost by the
|
||||
following directives which are listed in order of importance.</p>
|
||||
<ol>
|
||||
<li>Efficiency (speed and memory usage)</li>
|
||||
<li>Correctness</li>
|
||||
<li>Portability</li>
|
||||
<li>Readability</li>
|
||||
</ol>
|
||||
<p>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.</p>
|
||||
<p>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.</p>
|
||||
<p>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.</p>
|
||||
<h2> Thread Safety</h2>
|
||||
<p>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.</p>
|
||||
<p>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.</p>
|
||||
<p>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.</p>
|
||||
<p>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.</p>
|
||||
<p>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.</p>
|
||||
<h2> Container Design</h2>
|
||||
<p>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.<br>
|
||||
</p>
|
||||
<div class="code-example" style="margin-left: 40px;"><small><span style="font-family: Courier New;">template <class T, class Allocator =
|
||||
EASTLAllocator><br>
|
||||
class container<br>
|
||||
{<br>
|
||||
public:<br>
|
||||
typedef container<T, Allocator> this_type;<br>
|
||||
typedef
|
||||
T
|
||||
value_type;<br>
|
||||
typedef T*
|
||||
pointer;<br>
|
||||
typedef const T*
|
||||
const_pointer;<br>
|
||||
typedef
|
||||
T& reference;<br>
|
||||
|
||||
typedef const
|
||||
T& const_reference;<br>
|
||||
|
||||
typedef
|
||||
ptrdiff_t difference_type;<br>
|
||||
|
||||
typedef
|
||||
impl_defined size_type;<br>
|
||||
|
||||
typedef impl-defined
|
||||
iterator;<br>
|
||||
typedef impl-defined
|
||||
const_iterator;<br>
|
||||
typedef reverse_iterator<iterator> reverse_iterator;<br>
|
||||
typedef reverse_iterator<const_iterator> reverse_const_iterator;<br>
|
||||
typedef Allocator
|
||||
allocator_type;<br>
|
||||
<br>
|
||||
public:<br>
|
||||
container(</span></small><small><span style="font-family: Courier New;">const</span></small>
|
||||
<small><span style="font-family: Courier New;">allocator_type& allocator = allocator_type());<br>
|
||||
container(const</span></small> <small><span style=
|
||||
"font-family: Courier New;">this_type</span></small><small><span style="font-family: Courier New;">&
|
||||
x</span></small><small><span style="font-family: Courier New;">);<br>
|
||||
<br>
|
||||
</span></small><small><span style=
|
||||
"font-family: Courier New;">this_type</span></small><small><span style="font-family: Courier New;">&
|
||||
operator=(</span></small><small><span style="font-family: Courier New;">this_type</span></small><small><span style=
|
||||
"font-family: Courier New;">& x);<br>
|
||||
void swap(</span></small><small><span style=
|
||||
"font-family: Courier New;">this_type</span></small><small><span style="font-family: Courier New;">& x);<br>
|
||||
void reset();<br>
|
||||
<br>
|
||||
allocator_type& get_allocator();<br>
|
||||
void set_allocator(allocator_type& allocator);<br>
|
||||
<br>
|
||||
iterator begin();<br>
|
||||
const_iterator begin() const;<br>
|
||||
iterator end();<br>
|
||||
const_iterator end() const;<br>
|
||||
<br>
|
||||
bool validate() const;<br></span></small> <small><span style=
|
||||
"font-family: Courier New;"> int validate_iterator(const_iterator i)
|
||||
const;<br></span></small><br>
|
||||
<small><span style="font-family: Courier New;">protected:<br>
|
||||
allocator_type mAllocator;<br>
|
||||
};<br>
|
||||
<br>
|
||||
template <class T,</span></small> <small><span style="font-family: Courier New;">class
|
||||
Allocator</span></small><small><span style="font-family: Courier New;">><br>
|
||||
bool operator==(const container<T, Allocator>& a, const container<T,</span></small> <small><span style=
|
||||
"font-family: Courier New;">Allocator</span></small><small><span style="font-family: Courier New;">>& b);<br>
|
||||
<br>
|
||||
template <class T,</span></small> <small><span style="font-family: Courier New;">class
|
||||
Allocator</span></small><small><span style="font-family: Courier New;">><br>
|
||||
bool operator!=(const container<T,</span></small> <small><span style=
|
||||
"font-family: Courier New;">Allocator</span></small><small><span style="font-family: Courier New;">>& a, const
|
||||
container<T,</span></small> <small><span style=
|
||||
"font-family: Courier New;">Allocator</span></small><small><span style="font-family: Courier New;">>&
|
||||
b);</span></small></div>
|
||||
<br>
|
||||
Notes:
|
||||
<ul>
|
||||
<li>Swapped containers do not swap their allocators.</li>
|
||||
<li>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.</li>
|
||||
<li>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. </li>
|
||||
<li>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.</li>
|
||||
<li>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. </li>
|
||||
</ul>
|
||||
<h2>Allocator Design</h2>
|
||||
<p>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:<br>
|
||||
</p>
|
||||
<div class="code-example" style="margin-left: 40px;"><small><span style="font-family: Courier New;">// Standard C++ allocator<br>
|
||||
<br>
|
||||
template <class T><br>
|
||||
class allocator</span><br style="font-family: Courier New;">
|
||||
<span style="font-family: Courier New;">{</span><br style="font-family: Courier New;">
|
||||
<span style="font-family: Courier New;">public:</span><br style="font-family: Courier New;">
|
||||
<span style="font-family: Courier New;"> typedef size_t size_type;</span><br style=
|
||||
"font-family: Courier New;">
|
||||
<span style="font-family: Courier New;"> typedef ptrdiff_t difference_type;</span><br style=
|
||||
"font-family: Courier New;">
|
||||
<span style="font-family: Courier New;"> typedef T* pointer;</span><br style="font-family: Courier New;">
|
||||
<span style="font-family: Courier New;"> typedef const T* const_pointer;</span><br style=
|
||||
"font-family: Courier New;">
|
||||
<span style="font-family: Courier New;"> typedef T&
|
||||
reference;</span><br style="font-family: Courier New;">
|
||||
<span style="font-family: Courier New;"> typedef const
|
||||
T& const_reference;</span><br style="font-family: Courier New;">
|
||||
<span style="font-family: Courier New;"> typedef T value_type;</span><br style="font-family: Courier New;">
|
||||
<br style="font-family: Courier New;">
|
||||
<span style="font-family: Courier New;"> template <class U><br>
|
||||
struct rebind { typedef allocator<U> other; };</span><br style="font-family: Courier New;">
|
||||
<br style="font-family: Courier New;">
|
||||
<span style="font-family: Courier New;"> allocator() throw();</span><br style=
|
||||
"font-family: Courier New;">
|
||||
<span style="font-family: Courier New;"> allocator(const allocator&) throw();</span><br style=
|
||||
"font-family: Courier New;">
|
||||
<span style="font-family: Courier New;"> template <class U><br>
|
||||
allocator(const allocator<U>&) throw();<br>
|
||||
<br style="font-family: Courier New;">
|
||||
</span> <span style="font-family: Courier New;"> ~allocator()
|
||||
throw();<br>
|
||||
<br style="font-family: Courier New;">
|
||||
</span> <span style="font-family: Courier New;"> pointer
|
||||
address(reference x) const;</span><br style="font-family: Courier New;">
|
||||
<span style="font-family: Courier New;"> const_pointer address(const_reference x)
|
||||
const;</span><br style="font-family: Courier New;">
|
||||
<span style="font-family: Courier New;"> pointer allocate(size_type, typename
|
||||
allocator<void>::const_pointer hint = 0);</span><br style="font-family: Courier New;">
|
||||
<span style="font-family: Courier New;"> void deallocate(pointer p,
|
||||
size_type n);</span><br style="font-family: Courier New;">
|
||||
<span style="font-family: Courier New;"> size_type max_size() const
|
||||
throw();</span><br style="font-family: Courier New;">
|
||||
<span style="font-family: Courier New;"> void construct(pointer p,
|
||||
const T& val);</span><br style="font-family: Courier New;">
|
||||
<span style="font-family: Courier New;"> void destroy(pointer
|
||||
p);</span><br style="font-family: Courier New;">
|
||||
<span style="font-family: Courier New;">};</span></small></div>
|
||||
<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.</p>
|
||||
<p>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.</p>
|
||||
<p>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.<br>
|
||||
</p>
|
||||
<div class="code-example" style="margin-left: 40px;"><small><span style="font-family: Courier New;">// EASTL allocator<br>
|
||||
<br>
|
||||
class allocator<br>
|
||||
{<br>
|
||||
public:<br>
|
||||
allocator(const char* pName = NULL);<br>
|
||||
<br>
|
||||
void* allocate(size_t n, int flags = 0);<br>
|
||||
void* allocate(size_t n, size_t alignment, size_t offset, int flags = 0);<br>
|
||||
void deallocate(void* p, size_t n);<br>
|
||||
<br>
|
||||
const char* get_name() const;<br>
|
||||
void set_name(const char* pName);<br>
|
||||
};<br>
|
||||
<br>
|
||||
allocator* GetDefaultAllocator();</span></small></div>
|
||||
<h2>Fixed Size Container Design</h2>
|
||||
<p>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.</p>
|
||||
<p>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.</p>
|
||||
<h2>Algorithm Design</h2>
|
||||
<p>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).</p>
|
||||
<p>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.</p>
|
||||
<p>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.</p>
|
||||
<h2>Smart Pointer Design</h2>
|
||||
<p>EASTL implements the following smart pointer types:</p>
|
||||
<ul>
|
||||
<li>shared_ptr</li>
|
||||
<li>shared_array</li>
|
||||
<li>weak_ptr</li>
|
||||
<li>instrusive_ptr</li>
|
||||
<li>scoped_ptr</li>
|
||||
<li>scoped_array</li>
|
||||
<li>linked_ptr</li>
|
||||
<li>linked_array</li>
|
||||
</ul>
|
||||
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:
|
||||
<ul>
|
||||
<li>EASTL smart pointers allow you to assign an allocator to them.</li>
|
||||
<li>EASTL shared_ptr implements deletion via a templated parameter instead of a dynamically allocated virtual
|
||||
member object interface.</li>
|
||||
</ul>
|
||||
<p>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.</p>
|
||||
<p>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.</p>
|
||||
<h2>list::size is O(n)</h2>
|
||||
<p>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.</p>
|
||||
<h2>basic_string doesn't use copy-on-write</h2>
|
||||
<p>The primary benefit of CoW is that it allows for the sharing of string data between two string objects. Thus if you say
|
||||
this:</p>
|
||||
<p class="code-example"> string a("hello");<br style=
|
||||
"font-family: Courier New;">
|
||||
string b(a);</p>
|
||||
<p>the "hello" will be shared between a and b. If you then say this:</p>
|
||||
<p class="code-example"> a = "world";</p>
|
||||
<p>then <span style="font-family: Courier New;">a</span> 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.</p>
|
||||
<p> 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.</p>
|
||||
<p>The disadvantages of CoW strings are:</p>
|
||||
<ul>
|
||||
<li>A reference count needs to exist with the string, which increases string memory usage.</li>
|
||||
<li>With thread safety, atomic operations and mutex locks are expensive, especially on weaker memory systems such
|
||||
as console gaming platforms.</li>
|
||||
<li>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.</li>
|
||||
<li>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. </li>
|
||||
</ul>
|
||||
<p>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.</p>
|
||||
<p>This is a good starting HTML reference on the topic:</p>
|
||||
<blockquote>
|
||||
<p>
|
||||
<a href=
|
||||
"http://www.gotw.ca/publications/optimizations.htm">http://www.gotw.ca/publications/optimizations.htm</a></p>
|
||||
</blockquote>
|
||||
<p>Here is a well-known Usenet discussion on the topic:</p>
|
||||
<blockquote>
|
||||
<p><a href=
|
||||
"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</a></p>
|
||||
</blockquote>
|
||||
<hr style="width: 100%; height: 2px;">
|
||||
End of document<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
</body>
|
||||
</html>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,490 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<title>EASTL Glossary</title>
|
||||
<meta content="text/html; charset=us-ascii" http-equiv="content-type">
|
||||
<meta name="author" content="Paul Pedriana">
|
||||
<meta name="description" content="Definitions of common terms related to EASTL.">
|
||||
<link type="text/css" rel="stylesheet" href="EASTLDoc.css">
|
||||
</head>
|
||||
<body>
|
||||
<h1>EASTL Glossary</h1>
|
||||
<p>This document provides definitions to various terms related to EASTL. Items that are capitalized are items that are
|
||||
used as template parameters.</p>
|
||||
<table style="width: 100%; text-align: left;" border="1" cellpadding="2" cellspacing="2">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>adapter</td>
|
||||
<td>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.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="width: 150px; vertical-align: top;">algorithm<br></td>
|
||||
<td style="vertical-align: top;">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.<br></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>associative container</td>
|
||||
<td>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.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>array</td>
|
||||
<td>An array is a C++ container which directly implements a C-style fixed array but which adds STL container semantics
|
||||
to it.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>basic_string</td>
|
||||
<td>A templated string class which is usually used to store char or wchar_t strings.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>begin</td>
|
||||
<td>The function used by all conventional containers to return the first item in the container.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>BidirectionalIterator</td>
|
||||
<td>An input iterator which is like ForwardIterator except it can be read in a backward direction as well.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>BinaryOperation </td>
|
||||
<td>A function which takes two arguments and returns a value (which will usually be assigned to a third object).</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>BinaryPredicate</td>
|
||||
<td>A function which takes two arguments and returns true if some criteria is met (e.g. they are equal).</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>binder1st, binder2nd</td>
|
||||
<td>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.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>bit vector</td>
|
||||
<td>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.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>bitset</td>
|
||||
<td>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.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>capacity</td>
|
||||
<td>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.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>const_iterator</td>
|
||||
<td>An iterator whose iterated items are cannot be modified. A const_iterator is akin to a const pointer such as 'const
|
||||
char*'.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>container</td>
|
||||
<td>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.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>copy constructor</td>
|
||||
<td>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);</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Compare</td>
|
||||
<td>A function which takes two arguments and returns the lesser of the two.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>deque</td>
|
||||
<td>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.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>difference_type</td>
|
||||
<td>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.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>empty</td>
|
||||
<td>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.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>element</td>
|
||||
<td>An element refers to a member of a container.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>end</td>
|
||||
<td>The function used by all conventional containers to return one-past the last item in the container.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>equal_range</td>
|
||||
<td>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.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>explicit instantiation</td>
|
||||
<td>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>
|
||||
<small><span style="font-family: Courier New;"> </span></small> <small><span style=
|
||||
"font-family: Courier New;">template class vector<char>;<br>
|
||||
template void min<int>(int, int);<br>
|
||||
template void min(int, int);</span></small></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ForwardIterator</td>
|
||||
<td>An input iterator which is like InputIterator except it can be reset back to the beginning.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Function</td>
|
||||
<td>A function which takes one argument and applies some operation to the target.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>function object, functor</td>
|
||||
<td>A function object or functor is a class that has the function-call operator (<tt>operator()</tt>)
|
||||
defined.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Generator</td>
|
||||
<td>A function which takes no arguments and returns a value (which will usually be assigned to an object).</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>hash_map, hash_multimap, hash_set, hash_multiset</td>
|
||||
<td>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.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>heap</td>
|
||||
<td>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.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>InputIterator</td>
|
||||
<td>An input iterator (iterator you read from) which allows reading each element only once and only in a forward
|
||||
direction.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>intrusive_list, intrusive_hash_map, etc.</td>
|
||||
<td>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.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>intrusive_ptr</td>
|
||||
<td>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.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>iterator</td>
|
||||
<td>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.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>iterator category</td>
|
||||
<td>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>.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>iterator_tag</td>
|
||||
<td>See <span style="font-style: italic;">iterator category</span>.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>key_type, Key</td>
|
||||
<td>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.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>lexicographical compare</td>
|
||||
<td>A lexicographical compare is a comparison of two containers that compares them element by element, much like the C
|
||||
strcmp function compares two strings.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>linked_ptr</td>
|
||||
<td>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.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>list</td>
|
||||
<td>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.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>lower_bound</td>
|
||||
<td>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.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>map</td>
|
||||
<td>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.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>mapped_type</td>
|
||||
<td>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.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>member template</td>
|
||||
<td>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.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>multimap, </td>
|
||||
<td>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.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>multiset</td>
|
||||
<td>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.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>node</td>
|
||||
<td>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).</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>npos</td>
|
||||
<td>npos is used by the string class to identify a non-existent index. Some string functions return npos to indicate
|
||||
that the function failed.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>rel_ops</td>
|
||||
<td>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.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>reverse_iterator</td>
|
||||
<td>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.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>OutputIterator</td>
|
||||
<td>An output iterator (iterator you write to) which allows writing each element only once in only in a forward
|
||||
direction.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>POD</td>
|
||||
<td>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. </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Predicate</td>
|
||||
<td>A function which takes one argument returns true if the argument meets some criteria.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>priority_queue</td>
|
||||
<td>A priority_queue is an adapter container which implements a heap via a random access container such as vector or
|
||||
deque.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>queue</td>
|
||||
<td>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.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>RandomAccessIterator</td>
|
||||
<td>An input iterator which can be addressed like an array. It is a superset of all other input iterators.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>red-black tree</td>
|
||||
<td>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.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>scalar</td>
|
||||
<td>A scalar is a data type which is implemented via a numerical value. In C++ this means integers, floating point
|
||||
values, enumerations, and pointers. </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>scoped_ptr</td>
|
||||
<td>A scoped_ptr is a smart pointer which is the same as C++ auto_ptr except that it cannot be copied.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>set</td>
|
||||
<td>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.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>sequence</td>
|
||||
<td>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.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>size</td>
|
||||
<td>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.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>size_type</td>
|
||||
<td>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. It defaults to size_t, but it is possible to force it to be 4 bytes for 64 bit machines by defining EASTL_SIZE_T_32BIT.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>skip list</td>
|
||||
<td>A skip-list is a type of container which is an alternative to a binary tree for finding data.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>shared_ptr</td>
|
||||
<td>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.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>slist</td>
|
||||
<td>An slist is like a list but is singly-linked instead of doubly-linked. It can only be iterated in a
|
||||
forward-direction.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>smart pointer</td>
|
||||
<td>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.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>splice</td>
|
||||
<td>Splicing refers to the moving of a subsequence of one Sequence into another Sequence.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>stack</td>
|
||||
<td>A stack is a adapter container which implements LIFO (last-in, first, out) access via another container such as a
|
||||
list or deque.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>STL</td>
|
||||
<td>Standard Template Library. </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>StrictWeakOrdering</td>
|
||||
<td>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.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>string</td>
|
||||
<td>See basic_string.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>T</td>
|
||||
<td>T is the template parameter name used by most containers to identify the contained element type. </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>template parameter</td>
|
||||
<td>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.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>template specialization</td>
|
||||
<td>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.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>treap</td>
|
||||
<td>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.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>type traits</td>
|
||||
<td>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.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>typename</td>
|
||||
<td>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.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>UnaryOperation</td>
|
||||
<td>A function which takes one argument and returns a value (which will usually be assigned to second object).</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>upper_bound</td>
|
||||
<td>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.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>value_type, Value</td>
|
||||
<td>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.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>vector</td>
|
||||
<td>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.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>vector_map, vector_multimap, vector_set, vector_multiset</td>
|
||||
<td>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.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>weak_ptr</td>
|
||||
<td>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.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<br>
|
||||
|
||||
<hr style="width: 100%; height: 2px;">
|
||||
End of document<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,175 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<title>EASTL Gotchas</title>
|
||||
<meta content="text/html; charset=us-ascii" http-equiv="content-type">
|
||||
<meta name="author" content="Paul Pedriana">
|
||||
<meta name="description" content="Desciptions of potential pitfalls that exist in EASTL.">
|
||||
<link type="text/css" rel="stylesheet" href="EASTLDoc.css">
|
||||
<style type="text/css">
|
||||
<!--
|
||||
.style1 {color: #FF0000}
|
||||
.style2 {color: #009933}
|
||||
-->
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>EASTL Gotchas</h1>
|
||||
<p> 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.</p>
|
||||
<h2>Summary</h2>
|
||||
<p>The descriptions here are intentionally terse; this is to make them easier to visually scan.</p>
|
||||
<table style="text-align: left; width: 100%;" border="0" cellpadding="1" cellspacing="1">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="width: 28px;">1</td>
|
||||
<td><a href="#Gotchas.1">map::operator[] can create elements.</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="width: 28px;">2</td>
|
||||
<td><a href="#Gotchas.2">char* converts to string silently.</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="width: 28px;">3</td>
|
||||
<td><a href="#Gotchas.3">char* is compared by ptr and not by contents.</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="width: 28px;">4</td>
|
||||
<td><a href="#Gotchas.4">Iterators can be invalidated by container mutations.</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="width: 28px;">5</td>
|
||||
<td><a href="#Gotchas.5">Vector resizing may cause ctor/dtor cascades.</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="width: 28px;">6</td>
|
||||
<td><a href="#Gotchas.6">Vector and string insert/push_back/resize can reallocate.</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="width: 28px;">7</td>
|
||||
<td><a href="#Gotchas.7">Deriving from containers may not work.</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="width: 28px;">8</td>
|
||||
<td><a href="#Gotchas.8">set::iterator is const_iterator.</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="width: 28px;">9</td>
|
||||
<td><a href="#Gotchas.9">Inserting elements means copying by value.</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="width: 28px;">10</td>
|
||||
<td><a href="#Gotchas.10">Containers of pointers can leak if you aren't careful.</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="width: 28px;">11</td>
|
||||
<td><a href="#Gotchas.11">Containers of auto_ptrs can crash.</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="width: 28px;">12</td>
|
||||
<td><a href="#Gotchas.12">Remove algorithms don't actually remove elements.</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="width: 28px;">13</td>
|
||||
<td><a href="#Gotchas.13">list::size() is O(n).</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="width: 28px;">14</td>
|
||||
<td><a href="#Gotchas.14">vector and deque::size() may incur integer division.</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="width: 28px;">15</td>
|
||||
<td><a href="#Gotchas.15">Be careful making custom Compare functions.</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="width: 28px;">16</td>
|
||||
<td><a href="#Gotchas.16">Comparisons involving floating point are dangerous.</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="width: 28px;">17</td>
|
||||
<td><a href="#Gotchas.17">Writing beyond string::size and vector::size is dangerous. </a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="width: 28px;">18</td>
|
||||
<td><a href="#Gotchas.18">Container operator=() doesn't copy allocators. </a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h2> Detail</h2>
|
||||
<p class="faq-question"><a name="Gotchas.1"></a>1
|
||||
map::operator[] can create elements.</p>
|
||||
<p class="faq-answer">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[].</p>
|
||||
<p class="faq-question"><a name="Gotchas.2"></a>2
|
||||
char* converts to string silently.</p>
|
||||
<p class="faq-answer">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.</p>
|
||||
<p class="faq-answer">There is an EASTL configuration option called EASTL_STRING_EXPLICIT which makes the string char* ctor explicit and avoids the behaviour described above.</p>
|
||||
<p class="faq-question"><a name="Gotchas.3"></a>3
|
||||
char* is compared by ptr and not by contents.</p>
|
||||
<p class="faq-answer">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.</p>
|
||||
<p class="faq-question"><a name="Gotchas.4"></a>4 Iterators can be invalidated by container mutations</p>
|
||||
<p class="faq-answer">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.</p>
|
||||
<p class="faq-question"><a name="Gotchas.5"></a>5 Vector resizing may cause ctor/dtor cascades.</p>
|
||||
<p>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.</p>
|
||||
<p class="faq-question"><a name="Gotchas.6"></a>6
|
||||
Vector and string insert/push_back/resize can reallocate.</p>
|
||||
<p>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.</p>
|
||||
<p class="faq-question"><a name="Gotchas.7"></a>7
|
||||
Deriving from containers may not work.</p>
|
||||
<p>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.</p>
|
||||
<p class="faq-question"><a name="Gotchas.8"></a>8
|
||||
set::iterator is const_iterator.</p>
|
||||
<p class="faq-answer">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.</p>
|
||||
<p class="faq-question"><a name="Gotchas.9"></a>9
|
||||
Inserting elements means copying by value.</p>
|
||||
<p class="faq-answer">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.</p>
|
||||
<p class="faq-question"><a name="Gotchas.10"></a>10
|
||||
Containers of pointers can leak if you aren't careful.</p>
|
||||
<p class="faq-answer">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.</p>
|
||||
<p class="faq-question"><a name="Gotchas.11"></a>11
|
||||
Containers of auto_ptrs can crash</p>
|
||||
<p class="faq-answer">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.</p>
|
||||
<p class="faq-question"><a name="Gotchas.12"></a>12
|
||||
Remove algorithms don't actually remove elements.</p>
|
||||
<p class="faq-answer">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.</p>
|
||||
<p class="faq-question"><a name="Gotchas.13"></a>13
|
||||
list::size() is O(n).</p>
|
||||
<p class="faq-answer">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.</p>
|
||||
<p class="faq-answer">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.</p>
|
||||
<p class="faq-question"> <a name="Gotchas.14"></a>14
|
||||
vector and deque::size() may incur integer division.</p>
|
||||
<p class="faq-answer">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.</p>
|
||||
<p class="faq-question"><a name="Gotchas.15"></a>15
|
||||
Be careful making custom Compare functions.
|
||||
</p>
|
||||
<p class="faq-answer">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.</p>
|
||||
<p class="faq-question"> <a name="Gotchas.16"></a>16
|
||||
Comparisons involving floating point are dangerous.</p>
|
||||
<p class="faq-answer">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.</p>
|
||||
<p class="faq-question"><a name="Gotchas.17" id="Gotchas.17"></a>17 Writing beyond string::size and vector::size is dangerous.</p>
|
||||
<p>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. </p>
|
||||
<p class="faq-answer">The following code is broken: </p>
|
||||
<p class="code-example">string mDataDir;<br>
|
||||
<br>
|
||||
mDataDir.<span class="style1">reserve</span>(kMaxPathLength);<br>
|
||||
strcpy(&mDataDir[0], "blah/blah/blah");<br>
|
||||
mDataDir.resize(strlen(&mDataDir[0])); // Overwrites your blah/... with 00000...</p>
|
||||
<p class="faq-answer">This following code is OK: </p>
|
||||
<p class="code-example">string mDataDir;<br>
|
||||
<br>
|
||||
mDataDir.<span class="style2">resize</span>(kMaxPathLength);<br>
|
||||
strcpy(&mDataDir[0], "blah/blah/blah");<br>
|
||||
mDataDir.resize(strlen(&mDataDir[0]));</p>
|
||||
<p class="faq-question"><a name="Gotchas.18" id="Gotchas.18"></a>18 Container operator=() doesn't copy allocators.
|
||||
</p>
|
||||
<p class="faq-answer">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. </p>
|
||||
<br>
|
||||
<hr style="width: 100%; height: 2px;">
|
||||
End of document<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,47 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<title>EASTL Introduction</title>
|
||||
<meta content="text/html; charset=us-ascii" http-equiv="content-type">
|
||||
<meta name="author" content="Paul Pedriana">
|
||||
<meta name="description" content="Basic introduction to EASTL.">
|
||||
<link type="text/css" rel="stylesheet" href="EASTLDoc.css">
|
||||
</head>
|
||||
<body>
|
||||
<h1>EASTL Introduction</h1>
|
||||
<p>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.</p>
|
||||
<h2>Intended Audience</h2>
|
||||
<p>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 <a href="EASTL%20FAQ.html">EASTL FAQ.html</a>
|
||||
document for links to information related to learning templates and STL.</p>
|
||||
<h2>EASTL Modules</h2>
|
||||
<p>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 <a href="EASTL%20Modules.html">EASTL Modules.html</a>.</p>
|
||||
<h2>EASTL Suitability</h2>
|
||||
<p>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.</p>
|
||||
<hr style="width: 100%; height: 2px;">
|
||||
End of document<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,292 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<title>EASTL Maintenance</title>
|
||||
<meta content="text/html; charset=us-ascii" http-equiv="content-type">
|
||||
<meta name="author" content="Paul Pedriana">
|
||||
<meta name="description" content="Information for the EASTL maintainer.">
|
||||
<link type="text/css" rel="stylesheet" href="EASTLDoc.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1>EASTL Maintenance</h1>
|
||||
<h2><span style="font-style: italic;"><a name="Introduction" id="Introduction"></a></span>Introduction</h2>
|
||||
<p>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.<br>
|
||||
<br>
|
||||
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:</p>
|
||||
<pre class="code-example">template <class InputIterator, class T>
|
||||
int count(InputIterator first, InputIterator last, const T& value)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
for(; first < last; ++first){
|
||||
if(*first == value)
|
||||
++result;
|
||||
}
|
||||
|
||||
return result;
|
||||
} </pre>
|
||||
<p>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.</p>
|
||||
<p>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.</p>
|
||||
|
||||
<h2> <a name="Language_Standard" id="Language_Standard"></a>C++ Language Standard</h2>
|
||||
<p>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?</p>
|
||||
<p>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.</p>
|
||||
<p>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.</p>
|
||||
<p>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.</p>
|
||||
<h2> <a name="Langauge_Use" id="Langauge_Use"></a>Language Use</h2>
|
||||
<p>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.</p>
|
||||
<p>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:</p>
|
||||
<ul>
|
||||
<li>RTTI (run-time-type-identification) (this is deemed too costly)</li>
|
||||
<li>Template export (few compilers support this)</li>
|
||||
<li>Exception specifications (most compilers ignore them)</li>
|
||||
</ul>
|
||||
<p>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.</p>
|
||||
<h2> <a name="Prime_Directives" id="Prime_Directives"></a>Prime Directives</h2>
|
||||
<p>The
|
||||
implementation of EASTL is guided foremost by the following directives which are listed in order of importance.</p>
|
||||
<ol>
|
||||
<li>Efficiency (speed and memory usage)</li>
|
||||
<li>Correctness (doesn't have bugs)</li>
|
||||
<li>Portability (works on all required platforms with minimal specialized code)</li>
|
||||
<li>Readability (code is legible and comments are present and useful)</li>
|
||||
</ol>
|
||||
<p>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.</p>
|
||||
<p>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.</p>
|
||||
<p>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.</p>
|
||||
|
||||
<h2> <a name="Coding_Conventions" id="Coding_Conventions"></a>Coding Conventions</h2>
|
||||
<p>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:</p>
|
||||
<ul>
|
||||
<li>No RTTI use.</li>
|
||||
<li>No use of exception specifications (e.g. appending the 'throw' declarator to a function).</li>
|
||||
<li>No use of exception handling itself except where explicitly required by the implementation (e.g. vector::at).</li>
|
||||
<li>Exception use needs to savvy to EASTL_EXCEPTIONS_ENABLED.</li>
|
||||
<li>No use of macros (outside of config.h). Macros make things more difficult for the user.</li>
|
||||
<li>No use of static or global variables.</li>
|
||||
<li>No use of global new, delete, malloc, or free. All memory must be user-specifyable via an Allocator parameter
|
||||
(default-specified or explicitly specified).</li>
|
||||
<li>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 <a href="#Prime_Directives">prime directives</a> above that performance and simplicity overrule all.</li>
|
||||
<li>No use of multithreading primitives. </li>
|
||||
<li>No use of the export keyword.</li>
|
||||
<li>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.</li>
|
||||
<li>No external library dependencies whatsoever, including standard STL. EASTL is dependent on only EABase and the
|
||||
C++ compiler. </li>
|
||||
<li>All code must be const-correct. This isn't just for readability -- compilation can fail unless const-ness is used
|
||||
correctly everywhere. </li>
|
||||
<li>Algorithms do not refer to containers; they refer only to iterators.</li>
|
||||
<li>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.</li>
|
||||
<li>No inferior implementations. No facility should be added to EASTL unless it is of professional
|
||||
quality.</li>
|
||||
<li>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.</li>
|
||||
<li>No major changes should be done without consulting a peer group.</li>
|
||||
</ul>
|
||||
|
||||
<h2><a name="Compiler_Issues" id="Compiler_Issues"></a>Compiler Issues</h2>
|
||||
<p>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.</p>
|
||||
<p>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.</p>
|
||||
<p>In order to feel comfortable that your EASTL code is C++ correct and is portable, you must do at least these two
|
||||
things:</p>
|
||||
<ul>
|
||||
<li>Test under at least VS2005, GCC 3.4+, GCC 4.4+, EDG, and clang. </li>
|
||||
<li>Test all functions that you write, as compilers will often skip the compilation of a template function if it isn't
|
||||
used.</li>
|
||||
</ul>
|
||||
<p>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.</p>
|
||||
|
||||
<h2> <a name="Iterator_Issues" id="Iterator_Issues"></a>Iterator Issues</h2>
|
||||
<p>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.</p>
|
||||
<p>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:</p>
|
||||
<pre class="code-example">template <class BidirectionalIterator>
|
||||
inline void reverse_impl(BidirectionalIterator first, BidirectionalIterator last, bidirectional_iterator_tag)<br>{
|
||||
for(; (first != last) && (first != --last); ++first) <span class="code-example-comment">// We are not allowed to use operator <, <=, >, >= with</span>
|
||||
iter_swap(first, last); <span class="code-example-comment">// a generic (bidirectional or otherwise) iterator.</span>
|
||||
}<br>
|
||||
|
||||
template <typename RandomAccessIterator>
|
||||
inline void reverse_impl(RandomAccessIterator first, RandomAccessIterator last, random_access_iterator_tag)
|
||||
{
|
||||
for(; first < --last; ++first) <span class="code-example-comment">// With a random access iterator, we can use operator < to more efficiently implement</span>
|
||||
iter_swap(first, last); <span class="code-example-comment">// this algorithm. A generic iterator doesn't necessarily have an operator < defined.</span>
|
||||
}<br><br>
|
||||
template <class BidirectionalIterator>
|
||||
inline void reverse(BidirectionalIterator first, BidirectionalIterator last)
|
||||
{
|
||||
typedef typename iterator_traits<BidirectionalIterator>::iterator_category IC;
|
||||
reverse_impl(first, last, IC());
|
||||
}</pre>
|
||||
|
||||
<h2> <a name="Exception_Handling" id="Exception_Handling"></a>Exception Handling</h2>
|
||||
<p>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).</p>
|
||||
<p>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:</p>
|
||||
<ul>
|
||||
<li>Memory allocation failures (which throw exceptions)</li>
|
||||
<li>Constructor exceptions</li>
|
||||
</ul>
|
||||
<p>Take a look at the cases in EASTL where try/catch is used and see what it is doing.</p>
|
||||
<h2> <a name="Type_Traits" id="Type_Traits"></a>Type Traits </h2>
|
||||
<p>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.</p>
|
||||
<p>As mentioned in the GeneralOptimizations section below, EASTL should take advantage of type_traits information to the
|
||||
extent possible to achive maximum effiiciency.</p>
|
||||
<h2> <a name="General_Optimizations" id="General_Optimizations"></a>General
|
||||
Optimizations</h2>
|
||||
<p>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:</p>
|
||||
<ul>
|
||||
<li>Take advantage of type_traits to the extent possible (e.g. to use memcpy to move data instead of a for loop when
|
||||
possible).</li>
|
||||
<li>Take advantage of iterator types to the extent possible.</li>
|
||||
<li>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.</li>
|
||||
<li>Make inline-friendly code. This often means avoiding temporaries to the extent possible.</li>
|
||||
<li>Minimize branching (i.e. minimize 'if' statements). Where branching is used, make it so that 'if' statements
|
||||
execute as true.</li>
|
||||
<li>Use EASTL_LIKELY/EASTL_UNLIKELY to give branch hints to the compiler when you are confident it will be
|
||||
beneficial.</li>
|
||||
<li>Use restricted pointers (EABase's EA_RESTRICT or various compiler-specific versions of __restrict).</li>
|
||||
<li>Compare unsigned values to < max instead of comparing signed values to >= 0 && < max.</li>
|
||||
<li>Employ power of 2 integer math instead of math with any kind of integer.</li>
|
||||
<li>Use template specialization where possible to implement improved functionality.</li>
|
||||
<li>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.</li>
|
||||
</ul>
|
||||
<h2><a name="Unit_Tests" id="Unit_Tests"></a>Unit Tests</h2>
|
||||
<p>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. </p>
|
||||
<ul>
|
||||
<li>When making a new unit test, start by copying one of the existing unit tests and follow its conventions.</li>
|
||||
<li>Test containers of both scalars and classes.</li>
|
||||
<li>Test algorithms on both container iterators (e.g. vector.begin()) and pointer iterators (e.g. int*).</li>
|
||||
<li>Make sure that algorithm or container member functions which take iterators work with the type of iterator they
|
||||
claim to (InputIterator, ForwardIterator, BidirectionalIterator, RandomAccessIterator). </li>
|
||||
<li>Test for const-correctness. If a user is allowed to modify something that is supposed to be const, silent errors
|
||||
can go undetected.</li>
|
||||
<li>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.</li>
|
||||
<li>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.</li>
|
||||
<li>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.</li>
|
||||
<li>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.</li>
|
||||
<li>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.</li>
|
||||
<li>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.</li>
|
||||
</ul>
|
||||
|
||||
<h2><a name="Things_to_Keep_in_Mind" id="Things_to_Keep_in_Mind"></a>Things to Keep in Mind</h2>
|
||||
<ul>
|
||||
<li>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.</li>
|
||||
<li>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.</li>
|
||||
<li>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. </li>
|
||||
<li>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.</li>
|
||||
<li>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.</li>
|
||||
<li>Algorithm templates always work with iterators and not containers. A given container may of course implement an
|
||||
optimized form or an algorithm itself.</li>
|
||||
<li>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.</li>
|
||||
<li>It's easy to get iterator categories confused or forgotten while implementing algorithms and containers.</li>
|
||||
<li>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.</li>
|
||||
<li>Don't forget to update the config.h EASTL_VERSION define before publishing.</li>
|
||||
<li>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.</li>
|
||||
</ul>
|
||||
<hr style="width: 100%; height: 2px;">
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,666 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<title>EASTL Modules</title>
|
||||
<meta content="text/html; charset=us-ascii" http-equiv="content-type">
|
||||
<meta name="author" content="Paul Pedriana">
|
||||
<meta name="description" content="Lists the top-level modules present in EASTL.">
|
||||
<link type="text/css" rel="stylesheet" href="EASTLDoc.css">
|
||||
<style type="text/css">
|
||||
<!--
|
||||
.style1 {font-size: 10pt}
|
||||
-->
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1><font size="+3">EASTL Modules</font></h1>
|
||||
<h2> Introduction</h2>
|
||||
<p>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.</p>
|
||||
<h2>Module List</h2>
|
||||
<table style="text-align: left; width: 100%;" border="1" cellpadding="2" cellspacing="2">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="font-weight: bold;"> Module</td>
|
||||
<td style="font-weight: bold;">Description</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>config</td>
|
||||
<td>Configuration header. Allows for changing some compile-time options.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>slist<br>
|
||||
fixed_slist</td>
|
||||
<td>Singly-linked list.<br>
|
||||
fixed_slist is a version which is implemented via a fixed block of contiguous memory.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>list<br>
|
||||
fixed_list</td>
|
||||
<td>Doubly-linked list.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>intrusive_list<br>
|
||||
intrusive_slist</td>
|
||||
<td>List whereby the contained item provides the node implementation.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>array</td>
|
||||
<td>Wrapper for a C-style array which extends it to act like an STL container.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>vector<br>
|
||||
fixed_vector</td>
|
||||
<td>Resizable array container.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>vector_set<br>
|
||||
vector_multiset<br></td>
|
||||
<td>Set implemented via a vector instead of a tree. Speed and memory use is improved but resizing is slower.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>vector_map<br>
|
||||
vector_multimap<br></td>
|
||||
<td>Map implemented via a vector instead of a tree. Speed and memory use is improved but resizing is slower.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="vertical-align: top;">deque<br></td>
|
||||
<td style="vertical-align: top;">Double-ended queue, but also with random access. Acts like a vector but insertions and
|
||||
removals are efficient.<br></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>bit_vector</td>
|
||||
<td>Implements a vector of bool, but the actual storage is done with one bit per bool. Not the same thing as a
|
||||
bitset.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>bitset</td>
|
||||
<td>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.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>set<br>
|
||||
multiset<br>
|
||||
fixed_set<br>
|
||||
fixed_multiset<br></td>
|
||||
<td>A set is a sorted unique collection, multiset is sorted but non-unique collection.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>map<br>
|
||||
multimap<br>
|
||||
fixed_map<br>
|
||||
fixed_multimap</td>
|
||||
<td>A map is a sorted associative collection implemented via a tree. It is also known as dictionary.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>hash_map<br>
|
||||
hash_multimap<br>
|
||||
fixed_hash_map<br>
|
||||
fixed_hash_multimap</td>
|
||||
<td>Map implemented via a hash table.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>intrusive_hash_map<br>
|
||||
intrusive_hash_multimap<br>
|
||||
intrusive_hash_set<br>
|
||||
intrusive_hash_multiset</td>
|
||||
<td>hash_map whereby the contained item provides the node implementation, much like intrusive_list.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>hash_set<br>
|
||||
hash_multiset<br>
|
||||
fixed_hash_set<br>
|
||||
fixed_hash_map<br></td>
|
||||
<td>Set implemented via a hash table.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>basic_string<br>
|
||||
fixed_string<br>
|
||||
fixed_substring</td>
|
||||
<td>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.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>algorithm</td>
|
||||
<td>min/max, find, binary_search, random_shuffle, reverse, etc. </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="vertical-align: top;">sort<br></td>
|
||||
<td style="vertical-align: top;">Sorting functionality, including functionality not in STL. quick_sort, heap_sort,
|
||||
merge_sort, shell_sort, insertion_sort, etc.<br></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>numeric</td>
|
||||
<td>Numeric algorithms: accumulate, inner_product, partial_sum, adjacent_difference, etc.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="vertical-align: top;">heap<br></td>
|
||||
<td style="vertical-align: top;">Heap structure functionality: make_heap, push_heap, pop_heap, sort_heap, is_heap,
|
||||
remove_heap, etc.<br></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="vertical-align: top;">stack<br></td>
|
||||
<td style="vertical-align: top;">Adapts any container into a stack.<br></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="vertical-align: top;">queue<br></td>
|
||||
<td style="vertical-align: top;">Adapts any container into a queue.<br></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="vertical-align: top;">priority_queue<br></td>
|
||||
<td style="vertical-align: top;">Implements a conventional priority queue via a heap structure.<br></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>type_traits</td>
|
||||
<td>Type information, useful for writing optimized and robust code. Also used for implementing optimized containers and
|
||||
algorithms.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="vertical-align: top;">utility<br></td>
|
||||
<td style="vertical-align: top;">pair, make_pair, rel_ops, etc.<br></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="vertical-align: top;">functional<br></td>
|
||||
<td style="vertical-align: top;">Function objects.<br></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="vertical-align: top;">iterator<br></td>
|
||||
<td style="vertical-align: top;">Iteration for containers and algorithms.<br></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>smart_ptr</td>
|
||||
<td>Smart pointers: shared_ptr, shared_array, weak_ptr, scoped_ptr, scoped_array, linked_ptr, linked_array,
|
||||
intrusive_ptr.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p> </p>
|
||||
<h2>Module Behaviour</h2>
|
||||
<p>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.</p>
|
||||
<table style="width: 100%;" border="1" cellpadding="1" cellspacing="1">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="width: 15%; vertical-align: top; height: 13px; font-weight: bold;">
|
||||
<p>Container</p>
|
||||
</td>
|
||||
<td style="font-weight: bold; text-align: center;" height="13" valign="top" width="10%">
|
||||
<p>Stores</p>
|
||||
</td>
|
||||
<td style="font-weight: bold; text-align: center;">Container Overhead (32 bit)</td>
|
||||
<td style="font-weight: bold; text-align: center;">Container Overhead (64 bit)</td>
|
||||
<td style="font-weight: bold; text-align: center;" height="13" valign="top" width="10%">
|
||||
<p>Node Overhead (32 bit)</p>
|
||||
</td>
|
||||
<td style="font-weight: bold; text-align: center;">Node Overhead (64 bit)</td>
|
||||
<td style="font-weight: bold; text-align: center;" height="13" valign="top" width="9%">
|
||||
<p>Iterator category</p>
|
||||
</td>
|
||||
<td style="text-align: center; font-weight: bold;">size() efficiency</td>
|
||||
<td style="text-align: center; font-weight: bold;">operator[] efficiency</td>
|
||||
<td style="font-weight: bold; text-align: center;" height="13" valign="top" width="16%">
|
||||
<p>Insert efficiency</p>
|
||||
</td>
|
||||
<td style="font-weight: bold; text-align: center;" height="13" valign="top" width="16%">
|
||||
<p>Erase via Iterator efficiency</p>
|
||||
</td>
|
||||
<td style="font-weight: bold; text-align: center;" height="13" valign="top" width="7%">
|
||||
<p>Find efficiency</p>
|
||||
</td>
|
||||
<td style="font-weight: bold; text-align: center;" height="13" valign="top" width="10%">
|
||||
<p>Sort efficiency</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>slist</td>
|
||||
<td style="text-align: center;">T</td>
|
||||
<td style="text-align: center;">8</td>
|
||||
<td style="text-align: center;">16</td>
|
||||
<td style="text-align: center;">4</td>
|
||||
<td style="text-align: center;">8</td>
|
||||
<td style="text-align: center;">f</td>
|
||||
<td style="text-align: center;">n</td>
|
||||
<td style="text-align: center;">-</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td style="text-align: center;">n</td>
|
||||
<td style="text-align: center;">n+</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td height="13" valign="top" width="15%">
|
||||
<p>list</p>
|
||||
</td>
|
||||
<td style="text-align: center;" height="13" valign="top" width="10%">
|
||||
<p>T</p>
|
||||
</td>
|
||||
<td style="text-align: center;">12</td>
|
||||
<td style="text-align: center;">24</td>
|
||||
<td style="text-align: center;" height="13" valign="top" width="10%">
|
||||
<p>8</p>
|
||||
</td>
|
||||
<td style="text-align: center;">16</td>
|
||||
<td style="text-align: center;" height="13" valign="top" width="9%">
|
||||
<p>b</p>
|
||||
</td>
|
||||
<td style="text-align: center;">n</td>
|
||||
<td style="text-align: center;">-</td>
|
||||
<td style="text-align: center;" height="13" valign="top" width="16%">
|
||||
<p>1</p>
|
||||
</td>
|
||||
<td style="text-align: center;" height="13" valign="top" width="16%">
|
||||
<p>1</p>
|
||||
</td>
|
||||
<td style="text-align: center;" height="13" valign="top" width="7%">
|
||||
<p>n</p>
|
||||
</td>
|
||||
<td style="text-align: center;" height="13" valign="top" width="10%">
|
||||
<p>n log(n)</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>intrusive_slist</td>
|
||||
<td style="text-align: center;">T</td>
|
||||
<td style="text-align: center;">4</td>
|
||||
<td style="text-align: center;">8</td>
|
||||
<td style="text-align: center;">4</td>
|
||||
<td style="text-align: center;">8</td>
|
||||
<td style="text-align: center;">f</td>
|
||||
<td style="text-align: center;">n</td>
|
||||
<td style="text-align: center;">-</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td style="text-align: center;">n</td>
|
||||
<td style="text-align: center;">n+</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>intrusive_list</td>
|
||||
<td style="text-align: center;">T</td>
|
||||
<td style="text-align: center;">8</td>
|
||||
<td style="text-align: center;">16</td>
|
||||
<td style="text-align: center;">8</td>
|
||||
<td style="text-align: center;">16</td>
|
||||
<td style="text-align: center;">b</td>
|
||||
<td style="text-align: center;">n</td>
|
||||
<td style="text-align: center;">-</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td style="text-align: center;">n</td>
|
||||
<td style="text-align: center;">n log(n)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>array</td>
|
||||
<td style="text-align: center;">T</td>
|
||||
<td style="text-align: center;">0</td>
|
||||
<td style="text-align: center;">0</td>
|
||||
<td style="text-align: center;">0</td>
|
||||
<td style="text-align: center;">0</td>
|
||||
<td style="text-align: center;">r</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td style="text-align: center;">-</td>
|
||||
<td style="text-align: center;">-</td>
|
||||
<td style="text-align: center;">n</td>
|
||||
<td style="text-align: center;">n log(n)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>vector</td>
|
||||
<td style="text-align: center;">T</td>
|
||||
<td style="text-align: center;">16</td>
|
||||
<td style="text-align: center;">32</td>
|
||||
<td style="text-align: center;">0</td>
|
||||
<td style="text-align: center;">0</td>
|
||||
<td style="text-align: center;">r</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td style="text-align: center;">1 at end, else n</td>
|
||||
<td style="text-align: center;">1 at end, else n</td>
|
||||
<td style="text-align: center;">n</td>
|
||||
<td style="text-align: center;">n log(n)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>vector_set</td>
|
||||
<td style="text-align: center;">T</td>
|
||||
<td style="text-align: center;">16</td>
|
||||
<td style="text-align: center;">32</td>
|
||||
<td style="text-align: center;">0</td>
|
||||
<td style="text-align: center;">0</td>
|
||||
<td style="text-align: center;">r</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td style="text-align: center;">1 at end, else n</td>
|
||||
<td style="text-align: center;">1 at end, else n</td>
|
||||
<td style="text-align: center;">log(n)</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>vector_multiset</td>
|
||||
<td style="text-align: center;">T</td>
|
||||
<td style="text-align: center;">16</td>
|
||||
<td style="text-align: center;">32</td>
|
||||
<td style="text-align: center;">0</td>
|
||||
<td style="text-align: center;">0</td>
|
||||
<td style="text-align: center;">r</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td style="text-align: center;">1 at end, else n</td>
|
||||
<td style="text-align: center;">1 at end, else n</td>
|
||||
<td style="text-align: center;">log(n)</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>vector_map</td>
|
||||
<td style="text-align: center;">Key, T</td>
|
||||
<td style="text-align: center;">16</td>
|
||||
<td style="text-align: center;">32</td>
|
||||
<td style="text-align: center;">0</td>
|
||||
<td style="text-align: center;">0</td>
|
||||
<td style="text-align: center;">r</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td style="text-align: center;">1 at end, else n</td>
|
||||
<td style="text-align: center;">1 at end, else n</td>
|
||||
<td style="text-align: center;">log(n)</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>vector_multimap</td>
|
||||
<td style="text-align: center;">Key, T</td>
|
||||
<td style="text-align: center;">16</td>
|
||||
<td style="text-align: center;">32</td>
|
||||
<td style="text-align: center;">0</td>
|
||||
<td style="text-align: center;">0</td>
|
||||
<td style="text-align: center;">r</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td style="text-align: center;">1 at end, else n</td>
|
||||
<td style="text-align: center;">1 at end, else n</td>
|
||||
<td style="text-align: center;">log(n)</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>deque</td>
|
||||
<td style="text-align: center;">T</td>
|
||||
<td style="text-align: center;">44</td>
|
||||
<td style="text-align: center;">84</td>
|
||||
<td style="text-align: center;">0</td>
|
||||
<td style="text-align: center;">0</td>
|
||||
<td style="text-align: center;">r</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td style="text-align: center;">1 at begin or end,<br>
|
||||
else n / 2</td>
|
||||
<td style="text-align: center;">1 at begin or end,<br>
|
||||
else n / 2</td>
|
||||
<td style="text-align: center;">n</td>
|
||||
<td style="text-align: center;">n log(n)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>bit_vector</td>
|
||||
<td style="text-align: center;">bool</td>
|
||||
<td style="text-align: center;">8</td>
|
||||
<td style="text-align: center;">16</td>
|
||||
<td style="text-align: center;">0</td>
|
||||
<td style="text-align: center;">0</td>
|
||||
<td style="text-align: center;">r</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td style="text-align: center;">1 at end, else n</td>
|
||||
<td style="text-align: center;">1 at end, else n</td>
|
||||
<td style="text-align: center;">n</td>
|
||||
<td style="text-align: center;">n log(n)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>string (all types)</td>
|
||||
<td style="text-align: center;">T</td>
|
||||
<td style="text-align: center;">16</td>
|
||||
<td style="text-align: center;">32</td>
|
||||
<td style="text-align: center;">0</td>
|
||||
<td style="text-align: center;">0</td>
|
||||
<td style="text-align: center;">r</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td style="text-align: center;">1 at end, else n</td>
|
||||
<td style="text-align: center;">1 at end, else n</td>
|
||||
<td style="text-align: center;">n</td>
|
||||
<td style="text-align: center;">n log(n)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>set</td>
|
||||
<td style="text-align: center;">T</td>
|
||||
<td style="text-align: center;">24</td>
|
||||
<td style="text-align: center;">44</td>
|
||||
<td style="text-align: center;">16</td>
|
||||
<td style="text-align: center;">28</td>
|
||||
<td style="text-align: center;">b</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td style="text-align: center;">-</td>
|
||||
<td style="text-align: center;">log(n)</td>
|
||||
<td style="text-align: center;">log(n)</td>
|
||||
<td style="text-align: center;">log(n)</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>multiset</td>
|
||||
<td style="text-align: center;">T</td>
|
||||
<td style="text-align: center;">24</td>
|
||||
<td style="text-align: center;">44</td>
|
||||
<td style="text-align: center;">16</td>
|
||||
<td style="text-align: center;">28</td>
|
||||
<td style="text-align: center;">b</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td style="text-align: center;">-</td>
|
||||
<td style="text-align: center;">log(n)</td>
|
||||
<td style="text-align: center;">log(n)</td>
|
||||
<td style="text-align: center;">log(n)</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>map</td>
|
||||
<td style="text-align: center;">Key, T</td>
|
||||
<td style="text-align: center;">24</td>
|
||||
<td style="text-align: center;">44</td>
|
||||
<td style="text-align: center;">16</td>
|
||||
<td style="text-align: center;">28</td>
|
||||
<td style="text-align: center;">b</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td style="text-align: center;">log(n)</td>
|
||||
<td style="text-align: center;">log(n)</td>
|
||||
<td style="text-align: center;">log(n)</td>
|
||||
<td style="text-align: center;">log(n)</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>multimap</td>
|
||||
<td style="text-align: center;">Key, T</td>
|
||||
<td style="text-align: center;">24</td>
|
||||
<td style="text-align: center;">44</td>
|
||||
<td style="text-align: center;">16</td>
|
||||
<td style="text-align: center;">28</td>
|
||||
<td style="text-align: center;">b</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td style="text-align: center;">-</td>
|
||||
<td style="text-align: center;">log(n)</td>
|
||||
<td style="text-align: center;">log(n)</td>
|
||||
<td style="text-align: center;">log(n)</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>hash_set</td>
|
||||
<td style="text-align: center;">T</td>
|
||||
<td style="text-align: center;">16</td>
|
||||
<td style="text-align: center;">20</td>
|
||||
<td style="text-align: center;">4</td>
|
||||
<td style="text-align: center;">8</td>
|
||||
<td style="text-align: center;">b</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td style="text-align: center;">-</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td style="text-align: center;">-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>hash_multiset</td>
|
||||
<td style="text-align: center;">T</td>
|
||||
<td style="text-align: center;">16</td>
|
||||
<td style="text-align: center;">20</td>
|
||||
<td style="text-align: center;">4</td>
|
||||
<td style="text-align: center;">8</td>
|
||||
<td style="text-align: center;">b</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td style="text-align: center;">-</td>
|
||||
<td style="text-align: center;">1<br></td>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td style="text-align: center;">-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>hash_map</td>
|
||||
<td style="text-align: center;">Key, T</td>
|
||||
<td style="text-align: center;">16</td>
|
||||
<td style="text-align: center;">20</td>
|
||||
<td style="text-align: center;">4</td>
|
||||
<td style="text-align: center;">8</td>
|
||||
<td style="text-align: center;">b</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td style="text-align: center;">-</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td style="text-align: center;">-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>hash_multimap</td>
|
||||
<td style="text-align: center;">Key, T</td>
|
||||
<td style="text-align: center;">16</td>
|
||||
<td style="text-align: center;">20</td>
|
||||
<td style="text-align: center;">4</td>
|
||||
<td style="text-align: center;">8</td>
|
||||
<td style="text-align: center;">b</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td style="text-align: center;">-</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td style="text-align: center;">-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>intrusive_hash_set</td>
|
||||
<td style="text-align: center;">T</td>
|
||||
<td style="text-align: center;">16</td>
|
||||
<td style="text-align: center;">20</td>
|
||||
<td style="text-align: center;">4</td>
|
||||
<td style="text-align: center;">8</td>
|
||||
<td style="text-align: center;">b</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td style="text-align: center;">-</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td style="text-align: center;">-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>intrusive_hash_multiset</td>
|
||||
<td style="text-align: center;">T</td>
|
||||
<td style="text-align: center;">16</td>
|
||||
<td style="text-align: center;">20</td>
|
||||
<td style="text-align: center;">4</td>
|
||||
<td style="text-align: center;">8</td>
|
||||
<td style="text-align: center;">b</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td style="text-align: center;">-</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td style="text-align: center;">-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>intrusive_hash_map</td>
|
||||
<td style="text-align: center;">T <small>(Key == T)</small></td>
|
||||
<td style="text-align: center;">16</td>
|
||||
<td style="text-align: center;">20</td>
|
||||
<td style="text-align: center;">4</td>
|
||||
<td style="text-align: center;">8</td>
|
||||
<td style="text-align: center;">b</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td style="text-align: center;">-</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td style="text-align: center;">-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>intrusive_hash_multimap</td>
|
||||
<td style="text-align: center;">T <small>(Key == T) </small></td>
|
||||
<td style="text-align: center;">16</td>
|
||||
<td style="text-align: center;">20</td>
|
||||
<td style="text-align: center;">4</td>
|
||||
<td style="text-align: center;">8</td>
|
||||
<td style="text-align: center;">b</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td style="text-align: center;">-</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td style="text-align: center;">-</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<ul>
|
||||
<li>- means that the operation does not exist.</li>
|
||||
<li>1 means amortized constant time. Also known as O(1)</li>
|
||||
<li>n means time proportional to the container size. Also known as O(n)</li>
|
||||
<li>log(n) means time proportional to the natural logarithm of the container size. Also known as O(log(n))</li>
|
||||
<li>n log(n) means time proportional to log(n) times the size of the container. Also known as O(n log(n))</li>
|
||||
<li>n+ means that the time is at least n, and possibly higher.</li>
|
||||
<li>Iterator meanings are: f = forward iterator; b = bidirectional iterator, r = random iterator.</li>
|
||||
<li>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.</li>
|
||||
<li>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).</li>
|
||||
<li>Some overhead values are dependent on the size_type used by containers. size_type defaults to size_t, but it is possible to force it to be 4 bytes for 64 bit machines by defining EASTL_SIZE_T_32BIT.</li>
|
||||
<li>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.</li>
|
||||
<li>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).</li>
|
||||
<li>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.</li>
|
||||
</ul>
|
||||
<hr style="width: 100%; height: 2px;">
|
||||
End of document<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,86 @@
|
||||
body
|
||||
{
|
||||
font-family: Georgia, "Times New Roman", Times, serif;
|
||||
font-size: 12pt;
|
||||
}
|
||||
|
||||
h1
|
||||
{
|
||||
font-family: Verdana, Arial, Helvetica, sans-serif;
|
||||
display: block;
|
||||
background-color: #BBCCDD;
|
||||
border: 2px solid #000000;
|
||||
font-size: 16pt;
|
||||
font-weight: bold;
|
||||
padding: 6px;
|
||||
}
|
||||
|
||||
h2
|
||||
{
|
||||
font-size: 14pt;
|
||||
font-family: Verdana;
|
||||
border-bottom: 2px solid black;
|
||||
}
|
||||
|
||||
h3
|
||||
{
|
||||
font-family: Verdana;
|
||||
font-size: 13pt;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.code-example
|
||||
{
|
||||
display: block;
|
||||
background-color: #D1DDE9;
|
||||
margin-left: 3em;
|
||||
margin-right: 3em;
|
||||
margin-top: 1em;
|
||||
margin-bottom: 1em;
|
||||
padding: 8px;
|
||||
border: 2px solid #7993C8;
|
||||
font-family: "Courier New", Courier, mono;
|
||||
font-size: 10pt;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
.code-example-span
|
||||
{
|
||||
font-family: "Courier New", Courier, mono;
|
||||
font-size: 10pt;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
.code-example-comment
|
||||
{
|
||||
background-color: #e0e0f0;
|
||||
padding: 0px 0px;
|
||||
font-family: "Courier New", Courier, mono;
|
||||
font-size: 10pt;
|
||||
white-space: pre;
|
||||
color: #999999;
|
||||
margin: auto auto;
|
||||
}
|
||||
|
||||
|
||||
.faq-question
|
||||
{
|
||||
background-color: #D9E2EC;
|
||||
font-size: 12pt;
|
||||
font-weight: bold;
|
||||
margin-top: 0em;
|
||||
padding-left:5px;
|
||||
padding-right:8px;
|
||||
padding-top:2px;
|
||||
padding-bottom:3px;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
.faq-answer
|
||||
{
|
||||
display: block;
|
||||
margin: 4pt 1em 0.8em;
|
||||
}
|
||||
.indented {
|
||||
margin-left: 50px;
|
||||
}
|
||||
Reference in New Issue
Block a user