mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-21 11:35:53 +00:00
Tidy up List documentation
This commit is contained in:
@@ -17,289 +17,291 @@
|
|||||||
*/
|
*/
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
||||||
#ifndef BEAST_LIST_BEASTHEADER
|
#ifndef BEAST_LIST_H_INCLUDED
|
||||||
#define BEAST_LIST_BEASTHEADER
|
#define BEAST_LIST_H_INCLUDED
|
||||||
|
|
||||||
struct ListDefaultTag;
|
/** Intrusive Containers
|
||||||
|
|
||||||
/*============================================================================*/
|
# Introduction
|
||||||
/**
|
|
||||||
Intrusive Containers
|
|
||||||
|
|
||||||
# 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
|
While intrusive containers were and are widely used in C, they became more
|
||||||
and exception safety guarantees than non-intrusive containers (like the
|
and more forgotten in C++ due to the presence of the standard containers
|
||||||
STL containers). They are useful building blocks for high performance
|
which don't support intrusive techniques. VFLib not only reintroduces this
|
||||||
concurrent systems or other purposes where allocations are restricted
|
technique to C++ for lists, it also encapsulates the implementation in a
|
||||||
(such as the AudioIODeviceCallback object), because intrusive list
|
mostly compliant STL interface. Hence anyone familiar with standard
|
||||||
operations do not allocate or free memory.
|
containers can easily use them.
|
||||||
|
|
||||||
While intrusive containers were and are widely used in C, they became more
|
# Interface
|
||||||
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
|
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
|
Summary of intrusive container differences:
|
||||||
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:
|
- 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
|
@code
|
||||||
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
|
struct Object; // Forward declaration
|
||||||
|
|
||||||
class Object; // Forward declaration
|
List <Object> list; // Doubly-linked list of Object
|
||||||
|
|
||||||
List <Object> 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
|
@code
|
||||||
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
|
struct Object : public List <Object>::Node // Required for List
|
||||||
|
{
|
||||||
|
void performAction ();
|
||||||
|
};
|
||||||
|
|
||||||
class Object : public List <Object>::Node // Required for List
|
@endcode
|
||||||
{
|
|
||||||
public:
|
|
||||||
void performAction ();
|
|
||||||
};
|
|
||||||
|
|
||||||
@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
|
@code
|
||||||
arguments but requires a forward declaration. The following code is
|
|
||||||
equivalent.
|
|
||||||
|
|
||||||
@code
|
struct Object; // Forward declaration
|
||||||
|
|
||||||
class Object; // Forward declaration
|
// Specify template parameters just once
|
||||||
|
typedef List <Object> ListType;
|
||||||
|
|
||||||
// Specify template parameters just once
|
struct Object : public ListType::Node
|
||||||
typedef List <Object> ListType;
|
{
|
||||||
|
void performAction ();
|
||||||
|
};
|
||||||
|
|
||||||
class Object : public ListType::Node
|
ListType::Node list;
|
||||||
{
|
|
||||||
void performAction ();
|
|
||||||
};
|
|
||||||
|
|
||||||
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
|
@code
|
||||||
the list, and perform operations:
|
|
||||||
|
|
||||||
@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
|
// Call a method on each list
|
||||||
for (i = 0; i < 5; ++i)
|
for (ListType::iterator iter = list.begin(); iter != list.end (); ++iter)
|
||||||
list.push_back (*new Object);
|
iter->performAction ();
|
||||||
|
|
||||||
// Call a method on each list
|
@endcode
|
||||||
for (ListType::iterator iter = list.begin(); iter != list.end (); ++iter)
|
|
||||||
iter->performAction ();
|
|
||||||
|
|
||||||
@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
|
To support objects existing in multiple containers, templates variations
|
||||||
node cannot exist in more than one instance of that list at a time. This is
|
are instantiated by distinguishing them with an empty structure, called a
|
||||||
because the bookkeeping information for maintaining the list is kept in
|
tag. The object is derived from multiple instances of Node, where each
|
||||||
the object rather than the list.
|
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
|
This declaration example shows the usage of tags to allow an object to exist
|
||||||
are instantiated by distinguishing them with an empty structure, called a
|
simultaneously in two separate lists:
|
||||||
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
|
@code
|
||||||
simultaneously in two separate lists:
|
|
||||||
|
|
||||||
@code
|
struct GlobalListTag { }; // list of all objects
|
||||||
|
struct ActiveListTag { }; // subset of all objects that are active
|
||||||
|
|
||||||
struct GlobalListTag { }; // list of all objects
|
class Object : public List <Object, GlobalListTag>
|
||||||
struct ActiveListTag { }; // subset of all objects that are active
|
, public List <Object, ActiveListTag>
|
||||||
|
{
|
||||||
class Object : public List <Object, GlobalListTag>
|
public:
|
||||||
, public List <Object, ActiveListTag>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Object () : m_isActive (false)
|
Object () : m_isActive (false)
|
||||||
{
|
{
|
||||||
// Add ourselves to the global list
|
// Add ourselves to the global list
|
||||||
s_globalList.push_front (*this);
|
s_globalList.push_front (*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
~Object ()
|
~Object ()
|
||||||
{
|
{
|
||||||
deactivate ();
|
deactivate ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void becomeActive ()
|
void becomeActive ()
|
||||||
{
|
{
|
||||||
// Add ourselves to the active list
|
// Add ourselves to the active list
|
||||||
if (!m_isActive)
|
if (!m_isActive)
|
||||||
{
|
{
|
||||||
s_activeList.push_front (*this);
|
s_activeList.push_front (*this);
|
||||||
m_isActive = true;
|
m_isActive = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void deactivate ()
|
void deactivate ()
|
||||||
{
|
{
|
||||||
if (m_isActive)
|
if (m_isActive)
|
||||||
{
|
{
|
||||||
// Doesn't delete the object
|
// Doesn't delete the object
|
||||||
s_activeList.erase (s_activeList.iterator_to (this));
|
s_activeList.erase (s_activeList.iterator_to (this));
|
||||||
|
|
||||||
m_isActive = false;
|
m_isActive = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_isActive;
|
bool m_isActive;
|
||||||
|
|
||||||
static List <Object, GlobalListTag> s_globalList;
|
static List <Object, GlobalListTag> s_globalList;
|
||||||
static List <Object, ActiveListTag> s_activeList;
|
static List <Object, ActiveListTag> s_activeList;
|
||||||
}
|
}
|
||||||
|
|
||||||
@endcode
|
@endcode
|
||||||
|
|
||||||
@defgroup intrusive intrusive
|
@defgroup intrusive intrusive
|
||||||
@ingroup beast_core
|
@ingroup beast_core
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*============================================================================*/
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** Default tag for List.
|
||||||
|
|
||||||
|
@ingroup beast_core intrusive
|
||||||
|
*/
|
||||||
|
struct ListDefaultTag;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Intrusive doubly linked list.
|
Intrusive doubly linked list.
|
||||||
|
|
||||||
This intrusive List is a container similar in operation to std::list in the
|
This intrusive List is a container similar in operation to std::list in the
|
||||||
Standard Template Library (STL). Like all @ref intrusive containers, List
|
Standard Template Library (STL). Like all @ref intrusive containers, List
|
||||||
requires you to first derive your class from List<>::Node:
|
requires you to first derive your class from List<>::Node:
|
||||||
|
|
||||||
@code
|
@code
|
||||||
|
|
||||||
struct Object : List <Object>::Node
|
struct Object : List <Object>::Node
|
||||||
{
|
|
||||||
Object (int value) : m_value (value)
|
|
||||||
{
|
{
|
||||||
}
|
explicit Object (int value) : m_value (value)
|
||||||
|
{
|
||||||
int m_value;
|
}
|
||||||
};
|
|
||||||
|
int m_value;
|
||||||
@endcode
|
};
|
||||||
|
|
||||||
Now we define the list, and add a couple of items.
|
@endcode
|
||||||
|
|
||||||
@code
|
Now we define the list, and add a couple of items.
|
||||||
|
|
||||||
List <Object> list;
|
@code
|
||||||
|
|
||||||
list.push_back (* (new Object (1)));
|
List <Object> list;
|
||||||
list.push_back (* (new Object (2)));
|
|
||||||
|
list.push_back (* (new Object (1)));
|
||||||
@endcode
|
list.push_back (* (new Object (2)));
|
||||||
|
|
||||||
For compatibility with the standard containers, push_back() expects a
|
@endcode
|
||||||
reference to the object. Unlike the standard container, however, push_back()
|
|
||||||
places the actual object in the list and not a copy-constructed duplicate.
|
For compatibility with the standard containers, push_back() expects a
|
||||||
|
reference to the object. Unlike the standard container, however, push_back()
|
||||||
Iterating over the list follows the same idiom as the STL:
|
places the actual object in the list and not a copy-constructed duplicate.
|
||||||
|
|
||||||
@code
|
Iterating over the list follows the same idiom as the STL:
|
||||||
|
|
||||||
for (List <Object>::iterator iter = list.begin(); iter != list.end; ++iter)
|
@code
|
||||||
std::cout << iter->m_value;
|
|
||||||
|
for (List <Object>::iterator iter = list.begin(); iter != list.end; ++iter)
|
||||||
@endcode
|
std::cout << iter->m_value;
|
||||||
|
|
||||||
You can even use BOOST_FOREACH, or range based for loops:
|
@endcode
|
||||||
|
|
||||||
@code
|
You can even use BOOST_FOREACH, or range based for loops:
|
||||||
|
|
||||||
BOOST_FOREACH (Object& object, list) // boost only
|
@code
|
||||||
std::cout << object.m_value;
|
|
||||||
|
BOOST_FOREACH (Object& object, list) // boost only
|
||||||
for (Object& object : list) // C++11 only
|
std::cout << object.m_value;
|
||||||
std::cout << object.m_value;
|
|
||||||
|
for (Object& object : list) // C++11 only
|
||||||
@endcode
|
std::cout << object.m_value;
|
||||||
|
|
||||||
Because List is mostly STL compliant, it can be passed into STL algorithms:
|
@endcode
|
||||||
e.g. `std::for_each()` or `std::find_first_of()`.
|
|
||||||
|
Because List is mostly STL compliant, it can be passed into STL algorithms:
|
||||||
In general, objects placed into a List should be dynamically allocated
|
e.g. `std::for_each()` or `std::find_first_of()`.
|
||||||
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
|
In general, objects placed into a List should be dynamically allocated
|
||||||
object. An object still exists after being removed from a List, until the
|
although this cannot be enforced at compile time. Since the caller provides
|
||||||
caller deletes it. This means an element can be moved from one List to
|
the storage for the object, the caller is also responsible for deleting the
|
||||||
another with practically no overhead.
|
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
|
||||||
Unlike the standard containers, an object may only exist in one list at a
|
another with practically no overhead.
|
||||||
time, unless special preparations are made. The Tag template parameter is
|
|
||||||
used to distinguish between different list types for the same object,
|
Unlike the standard containers, an object may only exist in one list at a
|
||||||
allowing the object to exist in more than one list simultaneously.
|
time, unless special preparations are made. The Tag template parameter is
|
||||||
|
used to distinguish between different list types for the same object,
|
||||||
For example, consider an actor system where a global list of actors is
|
allowing the object to exist in more than one list simultaneously.
|
||||||
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
|
For example, consider an actor system where a global list of actors is
|
||||||
a domain-dependent update. To achieve this, we declare two tags, the
|
maintained, so that they can each be periodically receive processing
|
||||||
associated list types, and the list element thusly:
|
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
|
||||||
@code
|
associated list types, and the list element thusly:
|
||||||
|
|
||||||
struct Actor; // Forward declaration required
|
@code
|
||||||
|
|
||||||
struct ProcessTag { };
|
struct Actor; // Forward declaration required
|
||||||
struct UpdateTag { };
|
|
||||||
|
struct ProcessTag { };
|
||||||
typedef List <Actor, ProcessTag> ProcessList;
|
struct UpdateTag { };
|
||||||
typedef List <Actor, UpdateTag> UpdateList;
|
|
||||||
|
typedef List <Actor, ProcessTag> ProcessList;
|
||||||
// Derive from both node types so we can be in each list at once.
|
typedef List <Actor, UpdateTag> UpdateList;
|
||||||
//
|
|
||||||
struct Actor : ProcessList::Node, UpdateList::Node
|
// Derive from both node types so we can be in each list at once.
|
||||||
{
|
//
|
||||||
bool process (); // returns true if we need an update
|
struct Actor : ProcessList::Node, UpdateList::Node
|
||||||
void update ();
|
{
|
||||||
};
|
bool process (); // returns true if we need an update
|
||||||
|
void update ();
|
||||||
@endcode
|
};
|
||||||
|
|
||||||
@tparam Element The base type of element which the list will store
|
@endcode
|
||||||
pointers to.
|
|
||||||
|
@tparam Element The base type of element which the list will store
|
||||||
@tparam Tag An optional unique type name used to distinguish lists and nodes,
|
pointers to.
|
||||||
when the object can exist in multiple lists simultaneously.
|
|
||||||
|
@tparam Tag An optional unique type name used to distinguish lists and nodes,
|
||||||
@ingroup beast_core intrusive
|
when the object can exist in multiple lists simultaneously.
|
||||||
|
|
||||||
|
@ingroup beast_core intrusive
|
||||||
*/
|
*/
|
||||||
template <class Element, class Tag = ListDefaultTag>
|
template <class Element, class Tag = ListDefaultTag>
|
||||||
class List : Uncopyable
|
class List : Uncopyable
|
||||||
@@ -786,11 +788,4 @@ private:
|
|||||||
Node m_tail;
|
Node m_tail;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
Default tag for List.
|
|
||||||
|
|
||||||
@ingroup beast_core intrusive
|
|
||||||
*/
|
|
||||||
struct ListDefaultTag { };
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user