// bslstl_hashtablebucketiterator.h -*-C++-*- #ifndef INCLUDED_BSLSTL_HASHTABLEBUCKETITERATOR #define INCLUDED_BSLSTL_HASHTABLEBUCKETITERATOR #include <bsls_ident.h> BSLS_IDENT("$Id: $") //@PURPOSE: Provide an STL compliant iterator over hash table buckets. // //@CLASSES: // bslstl::HashBucketIterator: iterator to walk a hash-table bucket // //@SEE_ALSO: bslstl_unorderedmultimap, bslstl_unorderedmultiset // //@DESCRIPTION: This component provides a standard-conforming forward iterator, // 'bslstl::HashTableBucketIterator', over a list of elements (of // 'bslalg::BidirectionalLinkList' type) in a single bucket (of // 'bslalg::HashTableBucket' type) of 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::HashTableBucketIterator' // 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 Bucket Using 'HashTableIterator' /// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // In the following example we create a simple hashtable and then use a // 'HashTableBucketIterator' to iterate through the elements in one of its // buckets. // // 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("scratch", veryVeryVeryVerbose); // // 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 // 'HashTableBucketIterator' that can traverse buckets in a hash table holding // integer values. //.. // typedef bslstl::HashTableBucketIterator<int, ptrdiff_t> Iter; //.. // Now, we create two iterators: one pointing to the start the second bucket in // the hash table, and the other representing the end sentinel. We use the // iterators to navigate and print the elements in the hash table bucket: //.. // Iter iter(&hashTable.bucketArrayAddress()[1]); // Iter end(0, &hashTable.bucketArrayAddress()[1]); // for (;iter != end; ++iter) { // printf("%d\n", *iter); // } //.. // Then, we observe the following output: //.. // 1 // 3 //.. // 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 <bslalg_hashtablebucket.h> #include <bslmf_removecv.h> #include <bsls_assert.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 HashTableBucketIterator // ============================= #if defined(BSLS_LIBRARYFEATURES_STDCPP_LIBCSTD) // On Solaris just to keep studio12-v4 happy, since algorithms takes only // iterators inheriting from 'std::iterator'. template <class VALUE_TYPE, class DIFFERENCE_TYPE> class HashTableBucketIterator : public std::iterator<std::forward_iterator_tag, VALUE_TYPE> { #else template <class VALUE_TYPE, class DIFFERENCE_TYPE> class HashTableBucketIterator { #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 referred to by a single // 'bslalg::HashTableBucket' object. A 'HashTableBucketIterator' object // provides access to values of the (template parameter) 'VALUE_TYPE', // stored in a bucket of a hash table. 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 NonConstType; typedef HashTableBucketIterator<NonConstType, DIFFERENCE_TYPE> NonConstIter; public: // PUBLIC TYPES typedef NonConstType value_type; typedef DIFFERENCE_TYPE difference_type; typedef VALUE_TYPE *pointer; typedef VALUE_TYPE& reference; typedef std::forward_iterator_tag iterator_category; // Standard iterator defined types [24.4.2]. private: // DATA bslalg::BidirectionalLink *d_node_p; const bslalg::HashTableBucket *d_bucket_p; private: // PRIVATE MANIPULATORS void advance(); // Advance to the next element. public: // CREATORS HashTableBucketIterator(); // 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 HashTableBucketIterator(const bslalg::HashTableBucket *bucket); // Create an iterator referring to the specified 'bucket', initially // pointing to the first node in that 'bucket', or a past-the-end value // if the 'bucket' is empty. Note that this constructor is an // implementation detail and is not part of the C++ standard. explicit HashTableBucketIterator(bslalg::BidirectionalLink *node, const bslalg::HashTableBucket *bucket); // Create an iterator referring to the specified 'bucket', initially // pointing to the specified 'node' in that bucket. The behavior is // undefined unless 'node' is part of 'bucket', or 'node' is 0. Note // that this constructor is an implementation detail and is not part of // the C++ standard. HashTableBucketIterator(const NonConstIter& 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. // HashTableBucketIterator(const HashTableBucketIterator& original) // = default; // Create an iterator having the same value as the specified // 'original'. Note that this operation is either defined by the // constructor taking 'NonConstIter' (if 'NonConstType' 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 // 'NonConstType' is the same as 'VALUE_TYPE'. //~HashTableBucketIterator() = default; // MANIPULATORS //HashTableBucketIterator& operator=(const HashTableBucketIterator&) // = default; HashTableBucketIterator& operator=(const NonConstIter& rhs); // Copy the value of the specified 'rhs' of another (compatible) // 'HashTableBucketIterator' type, (e.g., a mutable iterator of the // same type) to this iterator. Return a reference to this modifiable // object. Note that this method may be the copy-assignment operator // (inhibiting the implicit declaration of a copy-assignment operator // above), or may be an additional overload. HashTableBucketIterator& operator++(); // Move this iterator to the next element in the hash table bucket and // return a reference providing modifiable access to this iterator. // The behavior is undefined unless the iterator refers to a valid (not // yet erased) element in a bucket. Note that this iterator is // invalidated when the underlying hash table is rehashed. // ACCESSORS reference operator*() const; // Return a reference providing modifiable access to the element (of // the template parameter 'VALUE_TYPE') at which this iterator is // positioned. The behavior is undefined unless the iterator refers to // a valid (not yet erased) element in a hash table bucket. Note that // this iterator is invalidated when the underlying hash table is // rehashed. pointer operator->() const; // Return the address of the element (of the template parameter // 'VALUE_TYPE') at which this iterator is positioned. The behavior is // undefined unless the iterator refers to a valid (not yet erased) // element a hash table bucket. Note that this iterator is invalidated // when the underlying hash table is rehashed. bslalg::BidirectionalLink *node() const; // Return the address of the node holding the element at which this // iterator is positioned, or 0 if this iterator is positioned after // the end of a bucket. Note that this method is an implementation // detail and is not part of the C++ standard. const bslalg::HashTableBucket *bucket() const; // Return the address of the hash table bucket referred to by this // iterator. Note that this method is an implementation detail // intended for debugging purposes only, and is not part of the C++ // standard. }; // FREE FUNCTIONS AND OPERATORS template <class VALUE_TYPE, class DIFFERENCE_TYPE> bool operator==( const HashTableBucketIterator<VALUE_TYPE, DIFFERENCE_TYPE>& lhs, const HashTableBucketIterator<VALUE_TYPE, DIFFERENCE_TYPE>& rhs); template <class VALUE_TYPE, class DIFFERENCE_TYPE> bool operator==( const HashTableBucketIterator< VALUE_TYPE, DIFFERENCE_TYPE>& lhs, const HashTableBucketIterator<const VALUE_TYPE, DIFFERENCE_TYPE>& rhs); template <class VALUE_TYPE, class DIFFERENCE_TYPE> bool operator==( const HashTableBucketIterator<const VALUE_TYPE, DIFFERENCE_TYPE>& lhs, const HashTableBucketIterator< VALUE_TYPE, DIFFERENCE_TYPE>& rhs); template <class VALUE_TYPE, class DIFFERENCE_TYPE> bool operator==( const HashTableBucketIterator<const VALUE_TYPE, DIFFERENCE_TYPE>& lhs, const HashTableBucketIterator<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 element in the same hash table, or if // both iterators are positioned after the end of a hash table bucket. template <class VALUE_TYPE, class DIFFERENCE_TYPE> bool operator!=( const HashTableBucketIterator<VALUE_TYPE, DIFFERENCE_TYPE>& lhs, const HashTableBucketIterator<VALUE_TYPE, DIFFERENCE_TYPE>& rhs); template <class VALUE_TYPE, class DIFFERENCE_TYPE> bool operator!=( const HashTableBucketIterator< VALUE_TYPE, DIFFERENCE_TYPE>& lhs, const HashTableBucketIterator<const VALUE_TYPE, DIFFERENCE_TYPE>& rhs); template <class VALUE_TYPE, class DIFFERENCE_TYPE> bool operator!=( const HashTableBucketIterator<const VALUE_TYPE, DIFFERENCE_TYPE>& lhs, const HashTableBucketIterator< VALUE_TYPE, DIFFERENCE_TYPE>& rhs); template <class VALUE_TYPE, class DIFFERENCE_TYPE> bool operator!=( const HashTableBucketIterator<const VALUE_TYPE, DIFFERENCE_TYPE>& lhs, const HashTableBucketIterator<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 elements in the same // hash table, or if either (but not both) of the iterators are positioned // after the end of a hash table bucket. template <class VALUE_TYPE, class DIFFERENCE_TYPE> HashTableBucketIterator<VALUE_TYPE, DIFFERENCE_TYPE> operator++(HashTableBucketIterator<VALUE_TYPE, DIFFERENCE_TYPE>& iterator, int); // Move the specified 'iter' to the next element in the hash table bucket // and return the value of 'iter' prior to this call. The behavior is // undefined unless 'iter' refers to a valid (not yet erased) element in a // bucket. Note that 'iter' is invalidated when the underlying hash table // is rehashed. // ============================================================================ // INLINE FUNCTION DEFINITIONS // ============================================================================ //------------------------------ // class HashTableBucketIterator //------------------------------ //CREATORS template <class VALUE_TYPE, class DIFFERENCE_TYPE> inline HashTableBucketIterator<VALUE_TYPE, DIFFERENCE_TYPE>:: HashTableBucketIterator() : d_node_p() , d_bucket_p() { } template <class VALUE_TYPE, class DIFFERENCE_TYPE> inline HashTableBucketIterator<VALUE_TYPE, DIFFERENCE_TYPE>:: HashTableBucketIterator(const bslalg::HashTableBucket *bucket) : d_node_p(bucket ? bucket->first() : 0) , d_bucket_p(bucket) { } template <class VALUE_TYPE, class DIFFERENCE_TYPE> inline HashTableBucketIterator<VALUE_TYPE, DIFFERENCE_TYPE>:: HashTableBucketIterator(bslalg::BidirectionalLink *node, const bslalg::HashTableBucket *bucket) : d_node_p(node) , d_bucket_p(bucket) { } template <class VALUE_TYPE, class DIFFERENCE_TYPE> inline HashTableBucketIterator<VALUE_TYPE, DIFFERENCE_TYPE>:: HashTableBucketIterator(const NonConstIter& original) : d_node_p(original.node()) , d_bucket_p(original.bucket()) { } // MANIPULATORS template <class VALUE_TYPE, class DIFFERENCE_TYPE> inline HashTableBucketIterator<VALUE_TYPE, DIFFERENCE_TYPE> & HashTableBucketIterator<VALUE_TYPE, DIFFERENCE_TYPE>::operator=( const NonConstIter& rhs) { d_node_p = rhs.node(); d_bucket_p = rhs.bucket(); return *this; } template <class VALUE_TYPE, class DIFFERENCE_TYPE> inline void HashTableBucketIterator<VALUE_TYPE, DIFFERENCE_TYPE>:: advance() { BSLS_ASSERT_SAFE(this->d_node_p); BSLS_ASSERT_SAFE(this->d_bucket_p); if (this->d_bucket_p->last() == this->d_node_p) { this->d_node_p = 0; } else { this->d_node_p = this->d_node_p->nextLink(); } } template <class VALUE_TYPE, class DIFFERENCE_TYPE> inline HashTableBucketIterator<VALUE_TYPE, DIFFERENCE_TYPE>& HashTableBucketIterator<VALUE_TYPE, DIFFERENCE_TYPE>:: operator++() { BSLS_ASSERT_SAFE(this->d_node_p); BSLS_ASSERT_SAFE(this->d_bucket_p); this->advance(); return *this; } // ACCESSORS template <class VALUE_TYPE, class DIFFERENCE_TYPE> inline typename HashTableBucketIterator<VALUE_TYPE, DIFFERENCE_TYPE>::reference HashTableBucketIterator<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 HashTableBucketIterator<VALUE_TYPE, DIFFERENCE_TYPE>::pointer HashTableBucketIterator<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 * HashTableBucketIterator<VALUE_TYPE, DIFFERENCE_TYPE>::node() const { return this->d_node_p; } template <class VALUE_TYPE, class DIFFERENCE_TYPE> inline const bslalg::HashTableBucket * HashTableBucketIterator<VALUE_TYPE, DIFFERENCE_TYPE>::bucket() const { return this->d_bucket_p; } template <class VALUE_TYPE, class DIFFERENCE_TYPE> inline bool operator==( const HashTableBucketIterator<VALUE_TYPE, DIFFERENCE_TYPE >& lhs, const HashTableBucketIterator<VALUE_TYPE, DIFFERENCE_TYPE >& rhs) { BSLS_ASSERT_SAFE(lhs.bucket() == rhs.bucket() ); return lhs.node() == rhs.node(); } template <class VALUE_TYPE, class DIFFERENCE_TYPE> inline bool operator==( const HashTableBucketIterator<VALUE_TYPE, DIFFERENCE_TYPE >& lhs, const HashTableBucketIterator<const VALUE_TYPE, DIFFERENCE_TYPE >& rhs) { BSLS_ASSERT_SAFE(lhs.bucket() == rhs.bucket() ); return lhs.node() == rhs.node(); } template <class VALUE_TYPE, class DIFFERENCE_TYPE> inline bool operator==( const HashTableBucketIterator<const VALUE_TYPE, DIFFERENCE_TYPE >& lhs, const HashTableBucketIterator<VALUE_TYPE, DIFFERENCE_TYPE >& rhs) { BSLS_ASSERT_SAFE(lhs.bucket() == rhs.bucket() ); return lhs.node() == rhs.node(); } template <class VALUE_TYPE, class DIFFERENCE_TYPE> inline bool operator==( const HashTableBucketIterator<const VALUE_TYPE, DIFFERENCE_TYPE >& lhs, const HashTableBucketIterator<const VALUE_TYPE, DIFFERENCE_TYPE >& rhs) { BSLS_ASSERT_SAFE(lhs.bucket() == rhs.bucket() ); return lhs.node() == rhs.node(); } template <class VALUE_TYPE, class DIFFERENCE_TYPE> inline bool operator!=( const HashTableBucketIterator<VALUE_TYPE, DIFFERENCE_TYPE >& lhs, const HashTableBucketIterator<VALUE_TYPE, DIFFERENCE_TYPE >& rhs) { BSLS_ASSERT_SAFE(lhs.bucket() == rhs.bucket() ); return lhs.node() != rhs.node(); } template <class VALUE_TYPE, class DIFFERENCE_TYPE> inline bool operator!=( const HashTableBucketIterator<VALUE_TYPE, DIFFERENCE_TYPE >& lhs, const HashTableBucketIterator<const VALUE_TYPE, DIFFERENCE_TYPE >& rhs) { BSLS_ASSERT_SAFE(lhs.bucket() == rhs.bucket() ); return lhs.node() != rhs.node(); } template <class VALUE_TYPE, class DIFFERENCE_TYPE> inline bool operator!=( const HashTableBucketIterator<const VALUE_TYPE, DIFFERENCE_TYPE >& lhs, const HashTableBucketIterator<VALUE_TYPE, DIFFERENCE_TYPE >& rhs) { BSLS_ASSERT_SAFE(lhs.bucket() == rhs.bucket() ); return lhs.node() != rhs.node(); } template <class VALUE_TYPE, class DIFFERENCE_TYPE> inline bool operator!=( const HashTableBucketIterator<const VALUE_TYPE, DIFFERENCE_TYPE >& lhs, const HashTableBucketIterator<const VALUE_TYPE, DIFFERENCE_TYPE >& rhs) { BSLS_ASSERT_SAFE(lhs.bucket() == rhs.bucket() ); return lhs.node() != rhs.node(); } template <class VALUE_TYPE, class DIFFERENCE_TYPE> inline HashTableBucketIterator<VALUE_TYPE, DIFFERENCE_TYPE> operator++(HashTableBucketIterator<VALUE_TYPE, DIFFERENCE_TYPE> &iter, int) { BSLS_ASSERT_SAFE(iter.node()); BSLS_ASSERT_SAFE(iter.bucket()); HashTableBucketIterator<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 ----------------------------------