Outline
Purpose
Provide a basic link type for building doubly-linked lists.
Classes
- See also
- bslalg_bidirectionallinklistutil, bslalg_hashtableimputil
Description
This component provides a single POD-like class, BidirectionalLink
, used to represent a node in a doubly-linked list. A BidirectionalLink
provides the address to its preceding node, and the address of its successor node. A null-pointer value for either address signifies the end of the list. BidirectionalLink
does not, however, contain "payload" data (e.g., a value), as it is intended to work with generalized list operations (see bslalg_bidirectionallinklistutil ). Clients creating a doubly-linked list must define their own node type that incorporates BidirectionalLink
(generally via inheritance), and that maintains the "value" stored in that node.
Usage
This section illustrates intended usage of this component.
Example 1: Creating and Using a List Template Class
Suppose we want to create a linked list template class, it will be called MyList
.
First, we create the MyNode
class, which derives from the BidirectionalLink class to carry a PAYLOAD
object.
template <class PAYLOAD>
public:
typedef PAYLOAD ValueType;
private:
ValueType d_value;
private:
MyNode();
MyNode(const MyNode&);
public:
~MyNode() {}
ValueType& value() { return d_value; }
const ValueType& value() const { return d_value; }
};
Definition bslalg_bidirectionallink.h:346
BidirectionalLink & operator=(const BidirectionalLink &rhs)=default
Next, we create the iterator helper class, which will eventually be defined as a nested type within the MyList
class.
template <class PAYLOAD>
class MyList_Iterator {
typedef MyNode<PAYLOAD> Node;
Node *d_node;
template <class PL>
friend bool operator==(MyList_Iterator<PL>,
MyList_Iterator<PL>);
public:
MyList_Iterator() : d_node(0) {}
explicit
MyList_Iterator(Node *node) : d_node(node) {}
};
DecimalImpUtil::ValueType32 value() const
Return the value of the underlying implementation.
Definition bdldfp_decimal.h:5706
FunctionOutputIterator< FUNCTION > & operator++(FunctionOutputIterator< FUNCTION > &iterator)
Do nothing and return specified iterator.
Definition bdlb_functionoutputiterator.h:405
Decimal32 operator*(Decimal32 lhs, Decimal32 rhs)
Then, we define our MyList
class, with MyList::Iterator
being a public typedef of MyList_Iterator
. For brevity, we will omit a lot of functionality that a full, general-purpose list class would have, implementing only what we will need for this example.
template <class PAYLOAD>
class MyList {
typedef MyNode<PAYLOAD> Node;
public:
typedef PAYLOAD ValueType;
typedef MyList_Iterator<ValueType> Iterator;
private:
Node *d_begin;
Node *d_end;
public:
explicit
: d_begin(0)
, d_end(0)
, d_allocator_p(
bslma::Default::allocator(basicAllocator))
{}
~MyList();
Iterator begin();
Iterator end();
void pushBack(const ValueType& value);
void popBack();
};
Definition bslma_allocator.h:457
Definition balxml_encoderoptions.h:68
Next, we implement the functions for the iterator type.
template <class PAYLOAD>
MyList_Iterator<PAYLOAD> MyList_Iterator<PAYLOAD>::operator++()
{
d_node = (Node *) d_node->nextLink();
return *this;
}
template <class PAYLOAD>
inline
bool operator==(MyList_Iterator<PAYLOAD> lhs,
MyList_Iterator<PAYLOAD> rhs)
{
return lhs.d_node == rhs.d_node;
}
template <class PAYLOAD>
inline
MyList_Iterator<PAYLOAD> rhs)
{
return !(lhs == rhs);
}
bool operator!=(const FileCleanerConfiguration &lhs, const FileCleanerConfiguration &rhs)
Then, we implement the functions for the MyList
class:
template <class PAYLOAD>
MyList<PAYLOAD>::~MyList()
{
for (Node *p = d_begin; p; ) {
Node *toDelete = p;
p = (Node *) p->nextLink();
d_allocator_p->deleteObjectRaw(toDelete);
}
}
template <class PAYLOAD>
typename MyList<PAYLOAD>::Iterator MyList<PAYLOAD>::begin()
{
return Iterator(d_begin);
}
template <class PAYLOAD>
typename MyList<PAYLOAD>::Iterator MyList<PAYLOAD>::end()
{
return Iterator(0);
}
template <class PAYLOAD>
void MyList<PAYLOAD>::pushBack(const PAYLOAD& value)
{
Node *node = (Node *) d_allocator_p->allocate(sizeof(Node));
node->setNextLink(0);
node->setPreviousLink(d_end);
value,
d_allocator_p);
if (d_end) {
d_end->setNextLink(node);
d_end = node;
}
else {
d_begin = d_end = node;
}
}
template <class PAYLOAD>
void MyList<PAYLOAD>::popBack()
{
Node *toDelete = d_end;
d_end = (Node *) d_end->previousLink();
if (d_begin != toDelete) {
d_end->setNextLink(0);
}
else {
d_begin = 0;
}
d_allocator_p->deleteObject(toDelete);
}
#define BSLS_ASSERT_SAFE(X)
Definition bsls_assert.h:1762
static void copyConstruct(TARGET_TYPE *address, const TARGET_TYPE &original, bslma::Allocator *allocator)
Definition bslalg_scalarprimitives.h:1599
Next, in main
, we use our MyList
class to store a list of ints:
Then, we declare an array of ints to populate it with:
int intArray[] = { 8, 2, 3, 5, 7, 2 };
enum { NUM_INTS = sizeof intArray / sizeof *intArray };
Now, we iterate, pushing ints to the list:
for (const int *pInt = intArray; pInt < intArray + NUM_INTS; ++pInt) {
intList.pushBack(*pInt);
}
Finally, we use our Iterator
type to traverse the list and observe its values:
MyList<int>::Iterator it = intList.begin();
assert(8 == *it);
assert(2 == *++it);
assert(3 == *++it);
assert(5 == *++it);
assert(7 == *++it);
assert(2 == *++it);
assert(intList.end() == ++it);