From 02f137ace879491d6e14b318037bb80d9a48bd9c Mon Sep 17 00:00:00 2001 From: Vinnie Falco Date: Sun, 30 Jun 2013 09:41:01 -0700 Subject: [PATCH] Tidy up List documentation --- .../beast_core/containers/beast_List.h | 449 +++++++++--------- 1 file changed, 222 insertions(+), 227 deletions(-) diff --git a/Subtrees/beast/modules/beast_core/containers/beast_List.h b/Subtrees/beast/modules/beast_core/containers/beast_List.h index 00e90912f4..38c9493281 100644 --- a/Subtrees/beast/modules/beast_core/containers/beast_List.h +++ b/Subtrees/beast/modules/beast_core/containers/beast_List.h @@ -17,289 +17,291 @@ */ //============================================================================== -#ifndef BEAST_LIST_BEASTHEADER -#define BEAST_LIST_BEASTHEADER +#ifndef BEAST_LIST_H_INCLUDED +#define BEAST_LIST_H_INCLUDED -struct ListDefaultTag; +/** Intrusive Containers -/*============================================================================*/ -/** - Intrusive Containers + # Introduction - # Introduction + Intrusive containers are special containers that offer better performance + and exception safety guarantees than non-intrusive containers (like the + STL containers). They are useful building blocks for high performance + concurrent systems or other purposes where allocations are restricted + (such as the AudioIODeviceCallback object), because intrusive list + operations do not allocate or free memory. - Intrusive containers are special containers that offer better performance - and exception safety guarantees than non-intrusive containers (like the - STL containers). They are useful building blocks for high performance - concurrent systems or other purposes where allocations are restricted - (such as the AudioIODeviceCallback object), because intrusive list - operations do not allocate or free memory. + While intrusive containers were and are widely used in C, they became more + and more forgotten in C++ due to the presence of the standard containers + which don't support intrusive techniques. VFLib not only reintroduces this + technique to C++ for lists, it also encapsulates the implementation in a + mostly compliant STL interface. Hence anyone familiar with standard + containers can easily use them. - While intrusive containers were and are widely used in C, they became more - and more forgotten in C++ due to the presence of the standard containers - which don't support intrusive techniques. VFLib not only reintroduces this - technique to C++ for lists, it also encapsulates the implementation in a - mostly compliant STL interface. Hence anyone familiar with standard - containers can easily use them. + # Interface - # Interface + The interface for intrusive elements in this library is unified for all + containers. Unlike STL containers, objects placed into intrusive containers + are not copied. Instead, a pointer to the object is stored. All + responsibility for object lifetime is the responsibility of the caller; + the intrusive container just keeps track of what is in it. - The interface for intrusive elements in this library is unified for all - containers. Unlike STL containers, objects placed into intrusive containers - are not copied. Instead, a pointer to the object is stored. All - responsibility for object lifetime is the responsibility of the caller; - the intrusive container just keeps track of what is in it. + Summary of intrusive container differences: - Summary of intrusive container differences: + - Holds pointers to existing objects instead of copies. - - Holds pointers to existing objects instead of copies. + - Does not allocate or free any objects. - - Does not allocate or free any objects. + - Requires a element's class declaration to be modified. - - Requires a element's class declaration to be modified. + - Methods never throw exceptions when called with valid arguments. - - Methods never throw exceptions when called with valid arguments. + # Usage - # Usage + Like STL containers, intrusive containers are all template based, where the + template argument specifies the type of object that the container will hold. + These declarations specify a doubly linked list where each element points + to a user defined class: - Like STL containers, intrusive containers are all template based, where the - template argument specifies the type of object that the container will hold. - These declarations specify a doubly linked list where each element points - to a user defined class: + @code - @code + struct Object; // Forward declaration - class Object; // Forward declaration + List list; // Doubly-linked list of Object - List list; // Doubly-linked list of Object + @endcode - @endcode + Because intrusive containers allocate no memory, allowing objects to be + placed inside requires a modification to their class declaration. Each + intrusive container declares a nested class `Node` which elements must be + derived from, using the Curiously Recurring Template Pattern (CRTP). We + will continue to fully declare the Object type from the previous example + to support emplacement into an intrusive container: - Because intrusive containers allocate no memory, allowing objects to be - placed inside requires a modification to their class declaration. Each - intrusive container declares a nested class `Node` which elements must be - derived from, using the Curiously Recurring Template Pattern (CRTP). We - will continue to fully declare the Object type from the previous example - to support emplacement into an intrusive container: + @code - @code + struct Object : public List ::Node // Required for List + { + void performAction (); + }; - class Object : public List ::Node // Required for List - { - public: - void performAction (); - }; + @endcode - @endcode + Usage of a typedef eliminates redundant specification of the template + arguments but requires a forward declaration. The following code is + equivalent. - Usage of a typedef eliminates redundant specification of the template - arguments but requires a forward declaration. The following code is - equivalent. + @code - @code + struct Object; // Forward declaration - class Object; // Forward declaration + // Specify template parameters just once + typedef List ListType; - // Specify template parameters just once - typedef List ListType; + struct Object : public ListType::Node + { + void performAction (); + }; - class Object : public ListType::Node - { - void performAction (); - }; + ListType::Node list; - ListType::Node list; + @endcode - @endcode + With these declarations we may proceed to create our objects, add them to + the list, and perform operations: - With these declarations we may proceed to create our objects, add them to - the list, and perform operations: + @code - @code + // Create a few objects and put them in the list + for (i = 0; i < 5; ++i) + list.push_back (*new Object); - // Create a few objects and put them in the list - for (i = 0; i < 5; ++i) - list.push_back (*new Object); + // Call a method on each list + for (ListType::iterator iter = list.begin(); iter != list.end (); ++iter) + iter->performAction (); - // Call a method on each list - for (ListType::iterator iter = list.begin(); iter != list.end (); ++iter) - iter->performAction (); + @endcode - @endcode + Unlike regular STL containers, an object derived from an intrusive container + node cannot exist in more than one instance of that list at a time. This is + because the bookkeeping information for maintaining the list is kept in + the object rather than the list. - Unlike regular STL containers, an object derived from an intrusive container - node cannot exist in more than one instance of that list at a time. This is - because the bookkeeping information for maintaining the list is kept in - the object rather than the list. + To support objects existing in multiple containers, templates variations + are instantiated by distinguishing them with an empty structure, called a + tag. The object is derived from multiple instances of Node, where each + instance specifies a unique tag. The tag is passed as the second template + argument. When the second argument is unspecified, the default tag is used. - To support objects existing in multiple containers, templates variations - are instantiated by distinguishing them with an empty structure, called a - tag. The object is derived from multiple instances of Node, where each - instance specifies a unique tag. The tag is passed as the second template - argument. When the second argument is unspecified, the default tag is used. + This declaration example shows the usage of tags to allow an object to exist + simultaneously in two separate lists: - This declaration example shows the usage of tags to allow an object to exist - simultaneously in two separate lists: + @code - @code + struct GlobalListTag { }; // list of all objects + struct ActiveListTag { }; // subset of all objects that are active - struct GlobalListTag { }; // list of all objects - struct ActiveListTag { }; // subset of all objects that are active - - class Object : public List - , public List - { - public: + class Object : public List + , public List + { + public: Object () : m_isActive (false) { - // Add ourselves to the global list - s_globalList.push_front (*this); + // Add ourselves to the global list + s_globalList.push_front (*this); } ~Object () { - deactivate (); + deactivate (); } void becomeActive () { - // Add ourselves to the active list - if (!m_isActive) - { - s_activeList.push_front (*this); - m_isActive = true; - } + // Add ourselves to the active list + if (!m_isActive) + { + s_activeList.push_front (*this); + m_isActive = true; + } } void deactivate () { - if (m_isActive) - { - // Doesn't delete the object - s_activeList.erase (s_activeList.iterator_to (this)); + if (m_isActive) + { + // Doesn't delete the object + s_activeList.erase (s_activeList.iterator_to (this)); - m_isActive = false; - } + m_isActive = false; + } } - private: - bool m_isActive; + private: + bool m_isActive; - static List s_globalList; - static List s_activeList; - } + static List s_globalList; + static List s_activeList; + } - @endcode + @endcode - @defgroup intrusive intrusive - @ingroup beast_core + @defgroup intrusive intrusive + @ingroup beast_core */ -/*============================================================================*/ +//------------------------------------------------------------------------------ + +/** Default tag for List. + + @ingroup beast_core intrusive +*/ +struct ListDefaultTag; + /** - Intrusive doubly linked list. - - This intrusive List is a container similar in operation to std::list in the - Standard Template Library (STL). Like all @ref intrusive containers, List - requires you to first derive your class from List<>::Node: - - @code - - struct Object : List ::Node - { - Object (int value) : m_value (value) + Intrusive doubly linked list. + + This intrusive List is a container similar in operation to std::list in the + Standard Template Library (STL). Like all @ref intrusive containers, List + requires you to first derive your class from List<>::Node: + + @code + + struct Object : List ::Node { - } - - int m_value; - }; - - @endcode - - Now we define the list, and add a couple of items. - - @code - - List list; - - list.push_back (* (new Object (1))); - list.push_back (* (new Object (2))); - - @endcode - - For compatibility with the standard containers, push_back() expects a - reference to the object. Unlike the standard container, however, push_back() - places the actual object in the list and not a copy-constructed duplicate. - - Iterating over the list follows the same idiom as the STL: - - @code - - for (List ::iterator iter = list.begin(); iter != list.end; ++iter) - std::cout << iter->m_value; - - @endcode - - You can even use BOOST_FOREACH, or range based for loops: - - @code - - BOOST_FOREACH (Object& object, list) // boost only - std::cout << object.m_value; - - for (Object& object : list) // C++11 only - std::cout << object.m_value; - - @endcode - - Because List is mostly STL compliant, it can be passed into STL algorithms: - e.g. `std::for_each()` or `std::find_first_of()`. - - In general, objects placed into a List should be dynamically allocated - although this cannot be enforced at compile time. Since the caller provides - the storage for the object, the caller is also responsible for deleting the - object. An object still exists after being removed from a List, until the - caller deletes it. This means an element can be moved from one List to - another with practically no overhead. - - Unlike the standard containers, an object may only exist in one list at a - time, unless special preparations are made. The Tag template parameter is - used to distinguish between different list types for the same object, - allowing the object to exist in more than one list simultaneously. - - For example, consider an actor system where a global list of actors is - maintained, so that they can each be periodically receive processing - time. We wish to also maintain a list of the subset of actors that require - a domain-dependent update. To achieve this, we declare two tags, the - associated list types, and the list element thusly: - - @code - - struct Actor; // Forward declaration required - - struct ProcessTag { }; - struct UpdateTag { }; - - typedef List ProcessList; - typedef List UpdateList; - - // Derive from both node types so we can be in each list at once. - // - struct Actor : ProcessList::Node, UpdateList::Node - { - bool process (); // returns true if we need an update - void update (); - }; - - @endcode - - @tparam Element The base type of element which the list will store - pointers to. - - @tparam Tag An optional unique type name used to distinguish lists and nodes, - when the object can exist in multiple lists simultaneously. - - @ingroup beast_core intrusive + explicit Object (int value) : m_value (value) + { + } + + int m_value; + }; + + @endcode + + Now we define the list, and add a couple of items. + + @code + + List list; + + list.push_back (* (new Object (1))); + list.push_back (* (new Object (2))); + + @endcode + + For compatibility with the standard containers, push_back() expects a + reference to the object. Unlike the standard container, however, push_back() + places the actual object in the list and not a copy-constructed duplicate. + + Iterating over the list follows the same idiom as the STL: + + @code + + for (List ::iterator iter = list.begin(); iter != list.end; ++iter) + std::cout << iter->m_value; + + @endcode + + You can even use BOOST_FOREACH, or range based for loops: + + @code + + BOOST_FOREACH (Object& object, list) // boost only + std::cout << object.m_value; + + for (Object& object : list) // C++11 only + std::cout << object.m_value; + + @endcode + + Because List is mostly STL compliant, it can be passed into STL algorithms: + e.g. `std::for_each()` or `std::find_first_of()`. + + In general, objects placed into a List should be dynamically allocated + although this cannot be enforced at compile time. Since the caller provides + the storage for the object, the caller is also responsible for deleting the + object. An object still exists after being removed from a List, until the + caller deletes it. This means an element can be moved from one List to + another with practically no overhead. + + Unlike the standard containers, an object may only exist in one list at a + time, unless special preparations are made. The Tag template parameter is + used to distinguish between different list types for the same object, + allowing the object to exist in more than one list simultaneously. + + For example, consider an actor system where a global list of actors is + maintained, so that they can each be periodically receive processing + time. We wish to also maintain a list of the subset of actors that require + a domain-dependent update. To achieve this, we declare two tags, the + associated list types, and the list element thusly: + + @code + + struct Actor; // Forward declaration required + + struct ProcessTag { }; + struct UpdateTag { }; + + typedef List ProcessList; + typedef List UpdateList; + + // Derive from both node types so we can be in each list at once. + // + struct Actor : ProcessList::Node, UpdateList::Node + { + bool process (); // returns true if we need an update + void update (); + }; + + @endcode + + @tparam Element The base type of element which the list will store + pointers to. + + @tparam Tag An optional unique type name used to distinguish lists and nodes, + when the object can exist in multiple lists simultaneously. + + @ingroup beast_core intrusive */ template class List : Uncopyable @@ -786,11 +788,4 @@ private: Node m_tail; }; -/** - Default tag for List. - - @ingroup beast_core intrusive -*/ -struct ListDefaultTag { }; - #endif