// bslstl_hashtableiterator.h -*-C++-*- #ifndef INCLUDED_BSLSTL_HASHTABLEITERATOR #define INCLUDED_BSLSTL_HASHTABLEITERATOR #include <bsls_ident.h> BSLS_IDENT("$Id: $") //@PURPOSE: Provide an STL compliant iterator for hash tables. // //@CLASSES: // bslstl::HashTableIterator: an STL compliant forward iterator // //@SEE_ALSO: bslalg_bidirectionallink, bslstl_unorderedmap, bslstl_unorderedset // //@DESCRIPTION: This component provides a standard-conforming forward iterator, // 'bslstl::HashTableIterator', over a list of elements (of type // 'bslalg::BidirectionalLink') in a hashtable. The requirements of a forward // iterator are outlined in the C++11 standard in section [24.2.5] under the // tag [forward.iterators]. The 'bslstl::HashTableIterator' class template has // two template parameters: 'VALUE_TYPE', and 'DIFFERENCE_TYPE'. 'VALUE_TYPE' // indicates the type of the value to which this iterator provides references, // and may be const-qualified for constant iterators. 'DIFFERENCE_TYPE' // determines the (standard mandated) 'difference_type' for the iterator, and // will typically be supplied by the allocator used by the hash-table being // iterated over. // ///Usage ///----- // This section illustrates intended use of this component. // ///Example 1: Iterating a Hash Table Using 'HashTableIterator' ///- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // In the following example we create a simple hashtable and then use a // 'HashTableIterator' to iterate through its elements. // // First, we define a typedef, 'Node', prepresenting a bidirectional node // holding an integer value: //.. // typedef bslalg::BidirectionalNode<int> Node; //.. // Then, we construct a test allocator, and we use it to allocate an array of // 'Node' objects, each holding a unique integer value: //.. // bslma::TestAllocator scratch; // // const int NUM_NODES = 5; // const int NUM_BUCKETS = 3; // // Node *nodes[NUM_NODES]; // for (int i = 0; i < NUM_NODES; ++i) { // nodes[i] = static_cast<Node *>(scratch.allocate(sizeof(Node))); // nodes[i]->value() = i; // } //.. // Next, we create an array of 'HashTableBuckets' objects, and we use the array // to construct an empty hash table characterized by a 'HashTableAnchor' // object: //.. // bslalg::HashTableBucket buckets[NUM_BUCKETS]; // for (int i = 0; i < NUM_BUCKETS; ++i) { // buckets[i].reset(); // } // bslalg::HashTableAnchor hashTable(buckets, NUM_BUCKETS, 0); //.. // Then, we insert each node in the array of nodes into the hash table using // 'bslalg::HashTableImpUtil', supplying the integer value held by each node as // its hash value: //.. // for (int i = 0; i < NUM_NODES; ++i) { // bslalg::HashTableImpUtil::insertAtFrontOfBucket(&hashTable, // nodes[i], // nodes[i]->value()); // } //.. // Next, we define a 'typedef' that is an alias an instance of // 'HashTableIterator' that can traverse hash tables holding integer values. //.. // typedef bslstl::HashTableIterator<int, ptrdiff_t> Iter; //.. // Now, we create two iterators: one pointing to the start of the bidirectional // linked list held by the hash table, and the other representing the end // sentinel. We use them to navigate and print the elements of the hash table: //.. // Iter iter(hashTable.listRootAddress()); // Iter end; // for (;iter != end; ++iter) { // printf("%d\n", *iter); // } //.. // Then, we observe the following output: //.. // 2 // 4 // 1 // 3 // 0 //.. // Finally, we deallocate the memory used by the hash table: //.. // for (int i = 0; i < NUM_NODES; ++i) { // scratch.deallocate(nodes[i]); // } //.. #include <bslscm_version.h> #include <bslstl_iterator.h> #include <bslalg_bidirectionallink.h> #include <bslalg_bidirectionalnode.h> #include <bslmf_removecv.h> #include <bsls_assert.h> #include <bsls_compilerfeatures.h> #include <bsls_libraryfeatures.h> #include <bsls_util.h> #ifndef BDE_DONT_ALLOW_TRANSITIVE_INCLUDES #include <bslmf_removecvq.h> #include <bsls_nativestd.h> #endif // BDE_DONT_ALLOW_TRANSITIVE_INCLUDES namespace BloombergLP { namespace bslstl { // ======================= // class HashTableIterator // ======================= #if defined(BSLS_LIBRARYFEATURES_STDCPP_LIBCSTD) // On Solaris just to keep studio12-v4 happy, since algorithms take only // iterators inheriting from 'std::iterator'. template <class VALUE_TYPE, class DIFFERENCE_TYPE> class HashTableIterator : public std::iterator<std::forward_iterator_tag, VALUE_TYPE> { #else template <class VALUE_TYPE, class DIFFERENCE_TYPE> class HashTableIterator { #endif // This class template implements an in-core value-semantic type that is an // standard-conforming forward iterator (see section 24.2.5 // [forward.iterators] of the C++11 standard) over a list of // 'bslalg::BidirectionalLink' objects. A 'HashTableIterator' object // provides access to values of the (template parameter) 'VALUE_TYPE', // stored in a hash table composed of 'bslalg::BidirectionalLink' nodes. // The (template parameter) 'DIFFERENCE_TYPE' determines the standard // mandated 'difference_type' of the iterator, without requiring access to // the allocator-traits for the node. // PRIVATE TYPES typedef typename bsl::remove_cv<VALUE_TYPE>::type NcType; typedef HashTableIterator<NcType, DIFFERENCE_TYPE> NcIter; public: // PUBLIC TYPES typedef NcType value_type; typedef DIFFERENCE_TYPE difference_type; typedef VALUE_TYPE *pointer; typedef VALUE_TYPE& reference; typedef bsl::forward_iterator_tag iterator_category; // Standard iterator defined types [24.4.2]. private: // DATA bslalg::BidirectionalLink *d_node_p; // pointer to the node referred to by // this iterator private: // PRIVATE MANIPULATORS void advance(); // Move this iterator to refer to the next node in the list. public: // CREATORS HashTableIterator(); // Create a default-constructed iterator referring to an empty list of // nodes. All default-constructed iterators are non-dereferenceable // and refer to the same empty list. explicit HashTableIterator(bslalg::BidirectionalLink *node); // Create an iterator referring to the specified 'node'. The behavior // is undefined unless 'node' is of the type // 'bslalg::BidirectionalNode<VALUE_TYPE>', which is derived from // 'bslalg::BidirectionalLink'. Note that this constructor is an // implementation detail and is not part of the C++ standard. HashTableIterator(const NcIter& original); // IMPLICIT // Create an iterator at the same position as the specified 'original' // iterator. Note that this constructor enables converting from // modifiable to 'const' iterator types. //! HashTableIterator(const HashTableIterator& original) = default; // Create an iterator having the same value as the specified // 'original'. Note that this operation is either defined by the // constructor taking 'NcIter' (if 'NcType' is the same as // 'VALUE_TYPE'), or generated automatically by the compiler. Also // note that this constructor cannot be defined explicitly (without // using 'bsls::enableif') to avoid a duplicate declaration when // 'NcType' is the same as 'VALUE_TYPE'. #if defined(BSLS_COMPILERFEATURES_SUPPORT_DEFAULTED_FUNCTIONS) ~HashTableIterator() = default; // Destroy this object. // MANIPULATORS HashTableIterator& operator=(const HashTableIterator& rhs) = default; // Assign to this object the value of the specified 'rhs' object, and // a return a reference providing modifiable access to this object. #endif HashTableIterator& operator++(); // Move this iterator to the next node in the list and return a // reference providing modifiable access to this iterator. The // behavior is undefined unless the iterator refers to a valid (not yet // erased) node in the list. // ACCESSORS reference operator*() const; // Return a reference providing modifiable access to the value (of the // template parameter 'VALUE_TYPE') of the node at which this iterator // is positioned. The behavior is undefined unless the iterator refers // to a valid (not yet erased) node the list. pointer operator->() const; // Return the address of the value (of the template parameter // 'VALUE_TYPE') of the element at which this iterator is positioned. // The behavior is undefined unless the iterator refers to a valid (not // yet erased) node the list. bslalg::BidirectionalLink *node() const; // Return the address of the node at which this iterator is positioned // in the list, or 0 if this iterator is positioned after the end of a // list. Note that this method is an implementation detail and is not // part of the C++ standard. }; // FREE OPERATORS template <class VALUE_TYPE, class DIFFERENCE_TYPE> bool operator==(const HashTableIterator<VALUE_TYPE, DIFFERENCE_TYPE>& lhs, const HashTableIterator<VALUE_TYPE, DIFFERENCE_TYPE>& rhs); template <class VALUE_TYPE, class DIFFERENCE_TYPE> bool operator==( const HashTableIterator<VALUE_TYPE, DIFFERENCE_TYPE>& lhs, const HashTableIterator<const VALUE_TYPE, DIFFERENCE_TYPE>& rhs); template <class VALUE_TYPE, class DIFFERENCE_TYPE> bool operator==( const HashTableIterator<const VALUE_TYPE, DIFFERENCE_TYPE>& lhs, const HashTableIterator<VALUE_TYPE, DIFFERENCE_TYPE>& rhs); template <class VALUE_TYPE, class DIFFERENCE_TYPE> bool operator==( const HashTableIterator<const VALUE_TYPE, DIFFERENCE_TYPE>& lhs, const HashTableIterator<const VALUE_TYPE, DIFFERENCE_TYPE>& rhs); // Return 'true' if the specified 'lhs' and the specified 'rhs' iterators // have the same value and 'false' otherwise. Two iterators have the same // value if they refer to the same node in the same list, or if both // iterators are at the past-the-end position of the tree. template <class VALUE_TYPE, class DIFFERENCE_TYPE> bool operator!=(const HashTableIterator<VALUE_TYPE, DIFFERENCE_TYPE>& lhs, const HashTableIterator<VALUE_TYPE, DIFFERENCE_TYPE>& rhs); template <class VALUE_TYPE, class DIFFERENCE_TYPE> bool operator!=( const HashTableIterator<VALUE_TYPE, DIFFERENCE_TYPE>& lhs, const HashTableIterator<const VALUE_TYPE, DIFFERENCE_TYPE>& rhs); template <class VALUE_TYPE, class DIFFERENCE_TYPE> bool operator!=( const HashTableIterator<const VALUE_TYPE, DIFFERENCE_TYPE>& lhs, const HashTableIterator<VALUE_TYPE, DIFFERENCE_TYPE>& rhs); template <class VALUE_TYPE, class DIFFERENCE_TYPE> bool operator!=( const HashTableIterator<const VALUE_TYPE, DIFFERENCE_TYPE>& lhs, const HashTableIterator<const VALUE_TYPE, DIFFERENCE_TYPE>& rhs); // Return 'true' if the specified 'lhs' and the specified 'rhs' iterators // do not have the same value and 'false' otherwise. Two iterators do not // have the same value if they refer to the different nodes in the same // list, or if either (but not both) of the iterators are at the // past-the-end position of the tree. template <class VALUE_TYPE, class DIFFERENCE_TYPE> HashTableIterator<VALUE_TYPE, DIFFERENCE_TYPE> operator++(HashTableIterator<VALUE_TYPE, DIFFERENCE_TYPE>& iter, int); // Move the specified 'iter' to the next node in the list and return // value of 'iter' prior to this call. The behavior is undefined // unless 'iter' refers to a valid (not yet erased) node a the list. // ============================================================================ // TEMPLATE AND INLINE FUNCTION DEFINITIONS // ============================================================================ // ----------------------- // class HashTableIterator // ----------------------- // CREATORS template <class VALUE_TYPE, class DIFFERENCE_TYPE> inline HashTableIterator<VALUE_TYPE, DIFFERENCE_TYPE>:: HashTableIterator() : d_node_p() { } template <class VALUE_TYPE, class DIFFERENCE_TYPE> inline HashTableIterator<VALUE_TYPE, DIFFERENCE_TYPE>:: HashTableIterator(bslalg::BidirectionalLink *node) : d_node_p(node) { } template <class VALUE_TYPE, class DIFFERENCE_TYPE> inline HashTableIterator<VALUE_TYPE, DIFFERENCE_TYPE>:: HashTableIterator(const NcIter& original) : d_node_p(original.node()) { } template <class VALUE_TYPE, class DIFFERENCE_TYPE> inline void HashTableIterator<VALUE_TYPE, DIFFERENCE_TYPE>::advance() { BSLS_ASSERT_SAFE(d_node_p); this->d_node_p = this->d_node_p->nextLink(); } template <class VALUE_TYPE, class DIFFERENCE_TYPE> inline HashTableIterator<VALUE_TYPE, DIFFERENCE_TYPE>& HashTableIterator<VALUE_TYPE, DIFFERENCE_TYPE>::operator++() { BSLS_ASSERT_SAFE(this->d_node_p); this->advance(); return *this; } // ACCESSORS template <class VALUE_TYPE, class DIFFERENCE_TYPE> inline typename HashTableIterator<VALUE_TYPE, DIFFERENCE_TYPE>::reference HashTableIterator<VALUE_TYPE, DIFFERENCE_TYPE>::operator*() const { BSLS_ASSERT_SAFE(this->d_node_p); return static_cast<bslalg::BidirectionalNode<VALUE_TYPE> *>( d_node_p)->value(); } template <class VALUE_TYPE, class DIFFERENCE_TYPE> inline typename HashTableIterator<VALUE_TYPE, DIFFERENCE_TYPE>::pointer HashTableIterator<VALUE_TYPE, DIFFERENCE_TYPE>::operator->() const { BSLS_ASSERT_SAFE(this->d_node_p); return bsls::Util::addressOf( static_cast<bslalg::BidirectionalNode<VALUE_TYPE> *>( d_node_p)->value()); } template <class VALUE_TYPE, class DIFFERENCE_TYPE> inline bslalg::BidirectionalLink * HashTableIterator<VALUE_TYPE, DIFFERENCE_TYPE>::node() const { return d_node_p; } // FREE OPERATORS template <class VALUE_TYPE, class DIFFERENCE_TYPE> inline bool operator==(const HashTableIterator<VALUE_TYPE, DIFFERENCE_TYPE>& lhs, const HashTableIterator<VALUE_TYPE, DIFFERENCE_TYPE>& rhs) { return lhs.node() == rhs.node(); } template <class VALUE_TYPE, class DIFFERENCE_TYPE> inline bool operator==( const HashTableIterator<VALUE_TYPE, DIFFERENCE_TYPE>& lhs, const HashTableIterator<const VALUE_TYPE, DIFFERENCE_TYPE>& rhs) { return lhs.node() == rhs.node(); } template <class VALUE_TYPE, class DIFFERENCE_TYPE> inline bool operator==( const HashTableIterator<const VALUE_TYPE, DIFFERENCE_TYPE>& lhs, const HashTableIterator<VALUE_TYPE, DIFFERENCE_TYPE>& rhs) { return lhs.node() == rhs.node(); } template <class VALUE_TYPE, class DIFFERENCE_TYPE> inline bool operator==( const HashTableIterator<const VALUE_TYPE, DIFFERENCE_TYPE>& lhs, const HashTableIterator<const VALUE_TYPE, DIFFERENCE_TYPE>& rhs) { return lhs.node() == rhs.node(); } template <class VALUE_TYPE, class DIFFERENCE_TYPE> inline bool operator!=(const HashTableIterator<VALUE_TYPE, DIFFERENCE_TYPE>& lhs, const HashTableIterator<VALUE_TYPE, DIFFERENCE_TYPE>& rhs) { return lhs.node() != rhs.node(); } template <class VALUE_TYPE, class DIFFERENCE_TYPE> inline bool operator!=( const HashTableIterator<VALUE_TYPE, DIFFERENCE_TYPE>& lhs, const HashTableIterator<const VALUE_TYPE, DIFFERENCE_TYPE>& rhs) { return lhs.node() != rhs.node(); } template <class VALUE_TYPE, class DIFFERENCE_TYPE> inline bool operator!=( const HashTableIterator<const VALUE_TYPE, DIFFERENCE_TYPE>& lhs, const HashTableIterator<VALUE_TYPE, DIFFERENCE_TYPE>& rhs) { return lhs.node() != rhs.node(); } template <class VALUE_TYPE, class DIFFERENCE_TYPE> inline bool operator!=( const HashTableIterator<const VALUE_TYPE, DIFFERENCE_TYPE>& lhs, const HashTableIterator<const VALUE_TYPE, DIFFERENCE_TYPE>& rhs) { return lhs.node() != rhs.node(); } template <class VALUE_TYPE, class DIFFERENCE_TYPE> inline HashTableIterator<VALUE_TYPE, DIFFERENCE_TYPE> operator++(HashTableIterator<VALUE_TYPE, DIFFERENCE_TYPE>& iter, int) { BSLS_ASSERT_SAFE(iter.node()); HashTableIterator<VALUE_TYPE, DIFFERENCE_TYPE> temp(iter); ++iter; return temp; } } // close package namespace } // close enterprise namespace #endif // ---------------------------------------------------------------------------- // Copyright 2019 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 ----------------------------------