// bslalg_hashtablebucket.h                                           -*-C++-*-
#ifndef INCLUDED_BSLALG_HASHTABLEBUCKET
#define INCLUDED_BSLALG_HASHTABLEBUCKET

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

//@PURPOSE: Provide a bucket representation for hash table data structures.
//
//@CLASSES:
//   bslalg::HashTableBucket : hash-table, manages externally allocated nodes
//
//@SEE_ALSO: bslalg_hashtableimputil, bslalg_bidirectionallink,
//           bslalg_bidirectionalnode
//
//@DESCRIPTION: This component provides an ability to keep track of a segment
// of a linked list of 'bslalg::BidirectionalLink' objects.  It contains
// pointers to the first and last elements of the list segment in question, or
// two null pointers for an empty list.
//
///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 iterator helper class, which will eventually be
// defined as a nested type within the 'MyList' class.
//..
//                              // ===============
//                              // MyList_Iterator
//                              // ===============
//
//  template <class PAYLOAD>
//  class MyList_Iterator {
//      // 'Iterator' type for class 'MyList'.  This class will be typedef'ed
//      // to be a nested class within 'MyList'.
//
//      // PRIVATE TYPES
//      typedef bslalg::BidirectionalNode<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() = default;
//
//      // MANIPULATORS
//      //! MyList_Iterator& operator=(const MyList_Iterator& other) = default;
//
//      MyList_Iterator operator++();
//
//      // ACCESSORS
//      PAYLOAD& operator*() const { return d_node->value(); }
//  };
//..
// Then, we define our 'MyList' class, which will inherit from
// 'bslalg::HashTableBucket'.  'MyList::Iterator' will be 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 : public bslalg::HashTableBucket {
//      // This class stores a doubly-linked list containing objects of type
//      // 'PAYLOAD'.
//
//      // PRIVATE TYPES
//      typedef bslalg::BidirectionalNode<PAYLOAD> Node;
//
//    public:
//      // PUBLIC TYPES
//      typedef PAYLOAD                            ValueType;
//      typedef MyList_Iterator<ValueType>         Iterator;
//
//      // DATA
//      bslma::Allocator *d_allocator_p;
//
//    public:
//      // CREATORS
//      explicit
//      MyList(bslma::Allocator *basicAllocator = 0)
//      : d_allocator_p(bslma::Default::allocator(basicAllocator))
//      {
//          reset();
//      }
//      ~MyList();
//
//      // MANIPULATORS
//      Iterator begin() { return Iterator((Node *) first()); }
//      Iterator end()   { return Iterator(0); }
//      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()
//  {
//      typedef bslalg::BidirectionalLink BDL;
//
//      for (Node *p = (Node *) first(); p; ) {
//          Node *toDelete = p;
//          p = (Node *) p->nextLink();
//
//          toDelete->value().~ValueType();
//          d_allocator_p->deleteObjectRaw(static_cast<BDL *>(toDelete));
//      }
//
//      reset();
//  }
//
//  // MANIPULATORS
//  template <class PAYLOAD>
//  void MyList<PAYLOAD>::pushBack(const PAYLOAD& value)
//  {
//      Node *node = (Node *) d_allocator_p->allocate(sizeof(Node));
//      node->setNextLink(0);
//      node->setPreviousLink(last());
//      bslalg::ScalarPrimitives::copyConstruct(&node->value(),
//                                              value,
//                                              d_allocator_p);
//
//      if (0 == last()) {
//          BSLS_ASSERT_SAFE(0 == first());
//
//          setFirstAndLast(node, node);
//      }
//      else {
//          last()->setNextLink(node);
//          setLast(node);
//      }
//  }
//
//  template <class PAYLOAD>
//  void MyList<PAYLOAD>::popBack()
//  {
//      BSLS_ASSERT_SAFE(first() && last());
//
//      Node *toDelete = (Node *) last();
//
//      if (first() != toDelete) {
//          BSLS_ASSERT_SAFE(0 != last());
//          setLast(last()->previousLink());
//          last()->setNextLink(0);
//      }
//      else {
//          reset();
//      }
//
//      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>

#include <bslalg_bidirectionallink.h>

#include <bslmf_istriviallycopyable.h>
#include <bslmf_nestedtraitdeclaration.h>

#include <bsls_assert.h>

#include <cstddef>

#ifndef BDE_DONT_ALLOW_TRANSITIVE_INCLUDES
#include <bsls_nativestd.h>
#endif // BDE_DONT_ALLOW_TRANSITIVE_INCLUDES

namespace BloombergLP {
namespace bslalg {

                          // =====================
                          // class HashTableBucket
                          // =====================

struct HashTableBucket {
  public:
    // DATA
    BidirectionalLink *d_first_p;
    BidirectionalLink *d_last_p;

    // TRAITS
    BSLMF_NESTED_TRAIT_DECLARATION(HashTableBucket,
                                   bsl::is_trivially_copyable);

  public:
    // No creators -- must be a POD so that aggregate initialization can be
    // done.

    // MANIPULATORS
    void setFirst(BidirectionalLink *node);
        // Set the 'first' element of this bucket to the specified 'node'.  The
        // behavior is undefined unless 'node' is an element from the same
        // bidirectional list as the 'last' element in this bucket, and 'node'
        // either precedes 'last' in that list, or is the same node, or this
        // bucket is empty and 'node' has a null pointer value.

    void setLast(BidirectionalLink *node);
        // Set the 'last' element of this bucket to the specified 'node'.  The
        // behavior is undefined unless 'node' is an element from the same
        // bidirectional list as the 'first' element in this bucket, and 'node'
        // either follows 'first' in that list, or is the same node, or this
        // bucket is empty and 'node' has a null pointer value.

    void setFirstAndLast(BidirectionalLink *first, BidirectionalLink *last);
        // Set 'first' and 'last' to the specified values.  Behavior is
        // undefined unless unless 'first == last', or unless 'first' and
        // 'last' are links from the same list, where 'first' precedes 'last'
        // in the list.  Note that 'first' and 'last' may both have a null
        // pointer value, indicating an empty bucket.

    void reset();
        // Set 'first' and 'last' to a null pointer value.

    // ACCESSORS
    BidirectionalLink *end() const;
        // Return the next node after the end of this bucket, or 0 if
        // '0 == last()', so the range to traverse to traverse all nodes in the
        // bucket is always '[ first(), end() )' regardless of whether the
        // bucket is empty.

    BidirectionalLink *first() const;
        // Return the address of the first element in this hash bucket, or a
        // null pointer value if the bucket is empty.

    BidirectionalLink *last() const;
        // Return the address of the last element in this hash bucket, or a
        // null pointer value if the bucket is empty.

    std::size_t countElements() const;
        // Return the number of nodes in this hash bucket.
};

// ============================================================================
//                               FREE OPERATORS
// ============================================================================

bool operator==(const HashTableBucket& lhs, const HashTableBucket& rhs);
    // Return 'true' if the specified hash table buckets 'lhs' and 'rhs' are
    // equivalent and 'false' otherwise.

bool operator!=(const HashTableBucket& lhs, const HashTableBucket& rhs);
    // Return 'true' if the specified hash table buckets 'lhs' and 'rhs' are
    // not equivalent and 'false' otherwise.

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

                        //----------------------
                        // class HashTableBucket
                        //----------------------

// MANIPULATORS
inline
void HashTableBucket::setFirst(BidirectionalLink *node)
{
    BSLS_ASSERT_SAFE(!d_first_p == !node);

    d_first_p = node;
}

inline
void HashTableBucket::setLast(BidirectionalLink *node)
{
    BSLS_ASSERT_SAFE(!d_last_p == !node);

    d_last_p = node;
}

inline
void HashTableBucket::setFirstAndLast(BidirectionalLink *first,
                                      BidirectionalLink *last)
{
    BSLS_ASSERT_SAFE(!first == !last);

    d_first_p = first;
    d_last_p  = last;
}

inline
void HashTableBucket::reset()
{
    d_first_p = d_last_p = 0;
}

// ACCESSORS
inline
BidirectionalLink *HashTableBucket::end() const
{
    return d_last_p ? d_last_p->nextLink() : 0;
}

inline
BidirectionalLink *HashTableBucket::first() const
{
    return d_first_p;
}

inline
BidirectionalLink *HashTableBucket::last() const
{
    return d_last_p;
}

}  // close package namespace

// FREE OPERATORS
inline
bool bslalg::operator==(const bslalg::HashTableBucket& lhs,
                        const bslalg::HashTableBucket& rhs)
{
    return lhs.first() == rhs.first() && lhs.last() == rhs.last();
}

inline
bool bslalg::operator!=(const bslalg::HashTableBucket& lhs,
                        const bslalg::HashTableBucket& rhs)
{
    return lhs.first() != rhs.first() || lhs.last() != rhs.last();
}


}  // 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 ----------------------------------