// bslalg_bidirectionallink.h                                         -*-C++-*-
#ifndef INCLUDED_BSLALG_BIDIRECTIONALLINK
#define INCLUDED_BSLALG_BIDIRECTIONALLINK

#include <bsls_ident.h>
BSLS_IDENT("$Id: $")

//@PURPOSE: Provide a basic link type for building doubly-linked lists.
//
//@CLASSES:
//   bslalg::BidirectionalLink : A node in a doubly-linked list
//
//@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>
//  class MyNode : public bslalg::BidirectionalLink {
//    public:
//      // PUBLIC TYPES
//      typedef PAYLOAD  ValueType;
//
//    private:
//      // DATA
//      ValueType     d_value;
//
//    private:
//      // NOT IMPLEMENTED
//      MyNode();
//      MyNode(const MyNode&);
//      MyNode& operator=(const MyNode&);
//
//    public:
//      // CREATOR
//      ~MyNode() {}
//          // Destroy this object.
//
//      // MANIPULATOR
//      ValueType& value() { return d_value; }
//          // Return a reference to the modifiable value stored in this node.
//
//      // ACCESSOR
//      const ValueType& value() const { return d_value; }
//          // Return a reference to the non-modifiable value stored in this
//          // node.
//  };
//..
// Next, we create the iterator helper class, which will eventually be
// defined as a nested type within the 'MyList' class.
//..
//                              // ===============
//                              // MyList_Iterator
//                              // ===============
//
//  template <class PAYLOAD>
//  class MyList_Iterator {
//      // PRIVATE TYPES
//      typedef MyNode<PAYLOAD> Node;
//
//      // DATA
//      Node *d_node;
//
//      // FRIENDS
//      template <class PL>
//      friend bool operator==(MyList_Iterator<PL>,
//                             MyList_Iterator<PL>);
//
//    public:
//      // CREATORS
//      MyList_Iterator() : d_node(0) {}
//      explicit
//      MyList_Iterator(Node *node) : d_node(node) {}
//      //! MyList_Iterator(const MyList_Iterator& original) = default;
//      //! MyList_Iterator& operator=(const MyList_Iterator& other) = default;
//      //! ~MyList_Iterator() = default;
//
//      // MANIPULATORS
//      MyList_Iterator operator++();
//
//      // ACCESSORS
//      PAYLOAD& operator*() const { return d_node->value(); }
//  };
//..
// 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.
//..
//                                  // ======
//                                  // MyList
//                                  // ======
//
//  template <class PAYLOAD>
//  class MyList {
//      // PRIVATE TYPES
//      typedef MyNode<PAYLOAD> Node;
//
//    public:
//      // PUBLIC TYPES
//      typedef PAYLOAD                            ValueType;
//      typedef MyList_Iterator<ValueType>         Iterator;
//
//    private:
//      // DATA
//      Node             *d_begin;
//      Node             *d_end;
//      bslma::Allocator *d_allocator_p;
//
//    public:
//      // CREATORS
//      explicit
//      MyList(bslma::Allocator *basicAllocator = 0)
//      : d_begin(0)
//      , d_end(0)
//      , d_allocator_p(bslma::Default::allocator(basicAllocator))
//      {}
//
//      ~MyList();
//
//      // MANIPULATORS
//      Iterator begin();
//      Iterator end();
//      void pushBack(const ValueType& value);
//      void popBack();
//  };
//..
// Next, we implement the functions for the iterator type.
//..
//                              // ---------------
//                              // MyList_Iterator
//                              // ---------------
//
//  // MANIPULATORS
//  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
//  bool operator!=(MyList_Iterator<PAYLOAD> lhs,
//                  MyList_Iterator<PAYLOAD> rhs)
//  {
//      return !(lhs == rhs);
//  }
//..
// Then, we implement the functions for the 'MyList' class:
//..
//                                  // ------
//                                  // MyList
//                                  // ------
//
//  // CREATORS
//  template <class PAYLOAD>
//  MyList<PAYLOAD>::~MyList()
//  {
//      for (Node *p = d_begin; p; ) {
//          Node *toDelete = p;
//          p = (Node *) p->nextLink();
//
//          d_allocator_p->deleteObjectRaw(toDelete);
//      }
//  }
//
//  // MANIPULATORS
//  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);
//      bslalg::ScalarPrimitives::copyConstruct(&node->value(),
//                                              value,
//                                              d_allocator_p);
//
//      if (d_end) {
//          BSLS_ASSERT_SAFE(d_begin);
//
//          d_end->setNextLink(node);
//          d_end = node;
//      }
//      else {
//          BSLS_ASSERT_SAFE(0 == d_begin);
//
//          d_begin = d_end = node;
//      }
//  }
//
//  template <class PAYLOAD>
//  void MyList<PAYLOAD>::popBack()
//  {
//      BSLS_ASSERT_SAFE(d_begin && d_end);
//
//      Node *toDelete = d_end;
//      d_end = (Node *) d_end->previousLink();
//
//      if (d_begin != toDelete) {
//          BSLS_ASSERT_SAFE(0 != d_end);
//          d_end->setNextLink(0);
//      }
//      else {
//          BSLS_ASSERT_SAFE(0 == d_end);
//          d_begin = 0;
//      }
//
//      d_allocator_p->deleteObject(toDelete);
//  }
//..
// Next, in 'main', we use our 'MyList' class to store a list of ints:
//..
//  MyList<int> intList;
//..
// 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);
//..

#include <bslscm_version.h>

namespace BloombergLP {
namespace bslalg {

                          // =======================
                          // class BidirectionalLink
                          // =======================

class BidirectionalLink {
    // This POD-like 'class' describes a node suitable for use in a doubly-
    // linked (bidirectional) list, holding the addresses of the preceding and
    // succeeding nodes, either or both of which may be 0.  This class is
    // "POD-like" to facilitate efficient allocation and use in the context of
    // a container implementations.  In order to meet the essential
    // requirements of a POD type, this 'class' does not declare a constructor
    // or destructor.  However its data members are private.  It satisfies the
    // requirements of a *trivial* type and a *standard* *layout* type defined
    // by the C++11 standard.  Note that this type does not contain any
    // "payload" member data: Clients creating a doubly-linked list of data
    // must define an appropriate node type that incorporates
    // 'BidirectionalLink' (generally via inheritance), and that holds the
    // "value" of any data stored in that node.

  private:
    // DATA
    BidirectionalLink *d_next_p;  // The next node in a list traversal
    BidirectionalLink *d_prev_p;  // The preceding node in a list traversal

  public:
    // CREATORS
    //! BidirectionalLink() = default;
        // Create a 'BidirectionalLink' object having uninitialized values,
        // or zero-initialized values if value-initialized.

    //! BidirectionalLink(const BidirectionalLink& original) = default;
        // Create a 'BidirectionalLink' object having the same data member
        // values as the specified 'original' object.

    //! ~BidirectionalLink() = default;
        // Destroy this object.

    // MANIPULATORS
    //! BidirectionalLink& operator= (const BidirectionalLink& rhs) = default;
        // Assign to the data members of this object the values of the data
        // members of the specified 'rhs' object, and return a reference
        // providing modifiable access to this object.

    void setNextLink(BidirectionalLink *next);
        // Set the successor of this node to be the specified 'next' link.

    void setPreviousLink(BidirectionalLink *previous);
        // Set the predecessor of this node to be the specified 'prev' link.

    void reset();
        // Set the 'nextLink' and 'previousLink' attributes of this value to 0.

    // ACCESSORS
    BidirectionalLink *nextLink() const;
        // Return the address of the next node linked from this node.

    BidirectionalLink *previousLink() const;
        // Return the address of the preceding node linked from this node.

};

// ============================================================================
//                  TEMPLATE AND INLINE FUNCTION DEFINITIONS
// ============================================================================

                        //------------------------
                        // class BidirectionalLink
                        //------------------------

// MANIPULATORS
inline
void BidirectionalLink::setNextLink(BidirectionalLink *next)
{
    d_next_p = next;
}

inline
void BidirectionalLink::setPreviousLink(BidirectionalLink *previous)
{
    d_prev_p = previous;
}

inline
void BidirectionalLink::reset()
{
    d_prev_p = 0;
    d_next_p = 0;
}

// ACCESSORS
inline
BidirectionalLink *BidirectionalLink::nextLink() const
{
    return d_next_p;
}

inline
BidirectionalLink *BidirectionalLink::previousLink() const
{
    return d_prev_p;
}

}  // close package namespace
}  // close enterprise namespace

#endif

// ----------------------------------------------------------------------------
// Copyright 2013 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------