diff --git a/llvm/docs/ProgrammersManual.html b/llvm/docs/ProgrammersManual.html index 9ecafe5dc5fa..e2ee74eff947 100644 --- a/llvm/docs/ProgrammersManual.html +++ b/llvm/docs/ProgrammersManual.html @@ -44,6 +44,20 @@ option
LLVM has a plethora of datastructures in the llvm/ADT/ directory, + and we commonly use STL datastructures. This section describes the tradeoffs + you should consider when you pick one.
+ ++The first step is a choose your own adventure: do you want a sequential +container, a set-like container, or a map-like container? The most important +thing when choosing a container is the algorithmic properties of how you plan to +access the container. Based on that, you should use:
+ ++Once the proper catagory of container is determined, you can fine tune the +memory use, constant factors, and cache behaviors of access by intelligently +picking a member of the catagory. Note that constant factors and cache behavior +can be a big deal. If you have a vector that usually only contains a few +elements (but could contain many), for example, it's much better to use +SmallVector than vector +. Doing so avoids (relatively) expensive malloc/free calls, which dwarf the +cost of adding the elements to the container.
+ +Fixed size arrays are very simple and very fast. They are good if you know +exactly how many elements you have, or you have a (low) upper bound on how many +you have.
+Heap allocated arrays (new[] + delete[]) are also simple. They are good if +the number of elements is variable, if you know how many elements you will need +before the array is allocated, and if the array is usually large (if not, +consider a SmallVector). The cost of a heap +allocated array is the cost of the new/delete (aka malloc/free). Also note that +if you are allocating an array of a type with a constructor, the constructor and +destructors will be run for every element in the array (resizable vectors only +construct those elements actually used).
+SmallVector<Type, N> is a simple class that looks and smells +just like vector<Type>: +it supports efficient iteration, lays out elements in memory order (so you can +do pointer arithmetic between elements), supports efficient push_back/pop_back +operations, supports efficient random access to its elements, etc.
+ +The advantage of SmallVector is that it allocates space for +some number of elements (N) in the object itself. Because of this, if +the SmallVector is dynamically smaller than N, no malloc is performed. This can +be a big win in cases where the malloc/free call is far more expensive than the +code that fiddles around with the elements.
+ +This is good for vectors that are "usually small" (e.g. the number of +predecessors/successors of a block is usually less than 8). On the other hand, +this makes the size of the SmallVector itself large, so you don't want to +allocate lots of them (doing so will waste a lot of space). As such, +SmallVectors are most useful when on the stack.
+ +SmallVector also provides a nice portable and efficient replacement for +alloca.
+ ++std::vector is well loved and respected. It is useful when SmallVector isn't: +when the size of the vector is often large (thus the small optimization will +rarely be a benefit) or if you will be allocating many instances of the vector +itself (which would waste space for elements that aren't in the container). +vector is also useful when interfacing with code that expects vectors :). +
+std::list is an extremely inefficient class that is rarely useful. +It performs a heap allocation for every element inserted into it, thus having an +extremely high constant factor, particularly for small data types. std::list +also only supports bidirectional iteration, not random access iteration.
+ +In exchange for this high cost, std::list supports efficient access to both +ends of the list (like std::deque, but unlike std::vector or SmallVector). In +addition, the iterator invalidation characteristics of std::list are stronger +than that of a vector class: inserting or removing an element into the list does +not invalidate iterator or pointers to other elements in the list.
+ilist<T> implements an 'intrusive' doubly-linked list. It is +intrusive, because it requires the element to store and provide access to the +prev/next pointers for the list.
+ +ilist has the same drawbacks as std::list, and additionally requires an +ilist_traits implementation for the element type, but it provides some novel +characteristics. In particular, it can efficiently store polymorphic objects, +the traits class is informed when an element is inserted or removed from the +list, and ilists are guaranteed to support a constant-time splice operation. +
+ +These properties are exactly what we want for things like Instructions and +basic blocks, which is why these are implemented with ilists.
+Other STL containers are available, such as std::deque (which has similar +characteristics to std::vector, but has higher constant factors and provides +efficient push_front/pop_front methods) and std::string.
+ +There are also various STL adapter classes such as std::queue, +std::priority_queue, std::stack, etc. These provide simplified access to an +underlying container but don't affect the cost of the container itself.
+ ++SmallPtrSet +SmallSet +sorted vector +FoldingSet +hash_set +UniqueVector +SetVector +
+ +