// Copyright (c) 2010, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // // This implements a uniform interface for all 6 hash implementations: // dense_hashtable, dense_hash_map, dense_hash_set // sparse_hashtable, sparse_hash_map, sparse_hash_set // This is intended to be used for testing, to provide a single routine // that can easily test all 6 implementations. // // The main reasons to specialize are to (1) provide dummy // implementations for methods that are only needed for some of the // implementations (for instance, set_empty_key()), and (2) provide a // uniform interface to just the keys -- for instance, we provide // wrappers around the iterators that define it.key, which gives the // "key" part of the bucket (*it or it->first, depending on the class). #ifndef UTIL_GTL_HASH_TEST_INTERFACE_H_ #define UTIL_GTL_HASH_TEST_INTERFACE_H_ #include #include // for equal_to<> #include #include #include #include #include #include #include HASH_FUN_H // for hash<> _START_GOOGLE_NAMESPACE_ // This is the "default" interface, which just passes everything // through to the underlying hashtable. You'll need to subclass it to // specialize behavior for an individual hashtable. template class BaseHashtableInterface { public: virtual ~BaseHashtableInterface() {} typedef typename HT::key_type key_type; typedef typename HT::value_type value_type; typedef typename HT::hasher hasher; typedef typename HT::key_equal key_equal; typedef typename HT::allocator_type allocator_type; typedef typename HT::size_type size_type; typedef typename HT::difference_type difference_type; typedef typename HT::pointer pointer; typedef typename HT::const_pointer const_pointer; typedef typename HT::reference reference; typedef typename HT::const_reference const_reference; class const_iterator; class iterator : public HT::iterator { public: iterator() : parent_(NULL) { } // this allows code like "iterator it;" iterator(typename HT::iterator it, const BaseHashtableInterface* parent) : HT::iterator(it), parent_(parent) { } key_type key() { return parent_->it_to_key(*this); } private: friend class BaseHashtableInterface::const_iterator; // for its ctor const BaseHashtableInterface* parent_; }; class const_iterator : public HT::const_iterator { public: const_iterator() : parent_(NULL) { } const_iterator(typename HT::const_iterator it, const BaseHashtableInterface* parent) : HT::const_iterator(it), parent_(parent) { } const_iterator(typename HT::iterator it, BaseHashtableInterface* parent) : HT::const_iterator(it), parent_(parent) { } // The parameter type here *should* just be "iterator", but MSVC // gets confused by that, so I'm overly specific. const_iterator(typename BaseHashtableInterface::iterator it) : HT::const_iterator(it), parent_(it.parent_) { } key_type key() { return parent_->it_to_key(*this); } private: const BaseHashtableInterface* parent_; }; class const_local_iterator; class local_iterator : public HT::local_iterator { public: local_iterator() : parent_(NULL) { } local_iterator(typename HT::local_iterator it, const BaseHashtableInterface* parent) : HT::local_iterator(it), parent_(parent) { } key_type key() { return parent_->it_to_key(*this); } private: friend class BaseHashtableInterface::const_local_iterator; // for its ctor const BaseHashtableInterface* parent_; }; class const_local_iterator : public HT::const_local_iterator { public: const_local_iterator() : parent_(NULL) { } const_local_iterator(typename HT::const_local_iterator it, const BaseHashtableInterface* parent) : HT::const_local_iterator(it), parent_(parent) { } const_local_iterator(typename HT::local_iterator it, BaseHashtableInterface* parent) : HT::const_local_iterator(it), parent_(parent) { } const_local_iterator(local_iterator it) : HT::const_local_iterator(it), parent_(it.parent_) { } key_type key() { return parent_->it_to_key(*this); } private: const BaseHashtableInterface* parent_; }; iterator begin() { return iterator(ht_.begin(), this); } iterator end() { return iterator(ht_.end(), this); } const_iterator begin() const { return const_iterator(ht_.begin(), this); } const_iterator end() const { return const_iterator(ht_.end(), this); } local_iterator begin(size_type i) { return local_iterator(ht_.begin(i), this); } local_iterator end(size_type i) { return local_iterator(ht_.end(i), this); } const_local_iterator begin(size_type i) const { return const_local_iterator(ht_.begin(i), this); } const_local_iterator end(size_type i) const { return const_local_iterator(ht_.end(i), this); } hasher hash_funct() const { return ht_.hash_funct(); } hasher hash_function() const { return ht_.hash_function(); } key_equal key_eq() const { return ht_.key_eq(); } allocator_type get_allocator() const { return ht_.get_allocator(); } BaseHashtableInterface(size_type expected_max_items_in_table, const hasher& hf, const key_equal& eql, const allocator_type& alloc) : ht_(expected_max_items_in_table, hf, eql, alloc) { } // Not all ht_'s support this constructor: you should only call it // from a subclass if you know your ht supports it. Otherwise call // the previous constructor, followed by 'insert(f, l);'. template BaseHashtableInterface(InputIterator f, InputIterator l, size_type expected_max_items_in_table, const hasher& hf, const key_equal& eql, const allocator_type& alloc) : ht_(f, l, expected_max_items_in_table, hf, eql, alloc) { } // This is the version of the constructor used by dense_*, which // requires an empty key in the constructor. template BaseHashtableInterface(InputIterator f, InputIterator l, key_type empty_k, size_type expected_max_items_in_table, const hasher& hf, const key_equal& eql, const allocator_type& alloc) : ht_(f, l, empty_k, expected_max_items_in_table, hf, eql, alloc) { } // This is the constructor appropriate for {dense,sparse}hashtable. template BaseHashtableInterface(size_type expected_max_items_in_table, const hasher& hf, const key_equal& eql, const ExtractKey& ek, const SetKey& sk, const allocator_type& alloc) : ht_(expected_max_items_in_table, hf, eql, ek, sk, alloc) { } void clear() { ht_.clear(); } void swap(BaseHashtableInterface& other) { ht_.swap(other.ht_); } // Only part of the API for some hashtable implementations. void clear_no_resize() { clear(); } size_type size() const { return ht_.size(); } size_type max_size() const { return ht_.max_size(); } bool empty() const { return ht_.empty(); } size_type bucket_count() const { return ht_.bucket_count(); } size_type max_bucket_count() const { return ht_.max_bucket_count(); } size_type bucket_size(size_type i) const { return ht_.bucket_size(i); } size_type bucket(const key_type& key) const { return ht_.bucket(key); } float load_factor() const { return ht_.load_factor(); } float max_load_factor() const { return ht_.max_load_factor(); } void max_load_factor(float grow) { ht_.max_load_factor(grow); } float min_load_factor() const { return ht_.min_load_factor(); } void min_load_factor(float shrink) { ht_.min_load_factor(shrink); } void set_resizing_parameters(float shrink, float grow) { ht_.set_resizing_parameters(shrink, grow); } void resize(size_type hint) { ht_.resize(hint); } void rehash(size_type hint) { ht_.rehash(hint); } iterator find(const key_type& key) { return iterator(ht_.find(key), this); } const_iterator find(const key_type& key) const { return const_iterator(ht_.find(key), this); } // Rather than try to implement operator[], which doesn't make much // sense for set types, we implement two methods: bracket_equal and // bracket_assign. By default, bracket_equal(a, b) returns true if // ht[a] == b, and false otherwise. (Note that this follows // operator[] semantics exactly, including inserting a if it's not // already in the hashtable, before doing the equality test.) For // sets, which have no operator[], b is ignored, and bracket_equal // returns true if key is in the set and false otherwise. // bracket_assign(a, b) is equivalent to ht[a] = b. For sets, b is // ignored, and bracket_assign is equivalent to ht.insert(a). template bool bracket_equal(const key_type& key, const AssignValue& expected) { return ht_[key] == expected; } template void bracket_assign(const key_type& key, const AssignValue& value) { ht_[key] = value; } size_type count(const key_type& key) const { return ht_.count(key); } std::pair equal_range(const key_type& key) { std::pair r = ht_.equal_range(key); return std::pair(iterator(r.first, this), iterator(r.second, this)); } std::pair equal_range(const key_type& key) const { std::pair r = ht_.equal_range(key); return std::pair( const_iterator(r.first, this), const_iterator(r.second, this)); } const_iterator random_element(class ACMRandom* r) const { return const_iterator(ht_.random_element(r), this); } iterator random_element(class ACMRandom* r) { return iterator(ht_.random_element(r), this); } std::pair insert(const value_type& obj) { std::pair r = ht_.insert(obj); return std::pair(iterator(r.first, this), r.second); } template void insert(InputIterator f, InputIterator l) { ht_.insert(f, l); } void insert(typename HT::const_iterator f, typename HT::const_iterator l) { ht_.insert(f, l); } iterator insert(typename HT::iterator, const value_type& obj) { return iterator(insert(obj).first, this); } // These will commonly need to be overridden by the child. void set_empty_key(const key_type& k) { ht_.set_empty_key(k); } void clear_empty_key() { ht_.clear_empty_key(); } key_type empty_key() const { return ht_.empty_key(); } void set_deleted_key(const key_type& k) { ht_.set_deleted_key(k); } void clear_deleted_key() { ht_.clear_deleted_key(); } key_type deleted_key() const { return ht_.deleted_key(); } size_type erase(const key_type& key) { return ht_.erase(key); } void erase(typename HT::iterator it) { ht_.erase(it); } void erase(typename HT::iterator f, typename HT::iterator l) { ht_.erase(f, l); } bool operator==(const BaseHashtableInterface& other) const { return ht_ == other.ht_; } bool operator!=(const BaseHashtableInterface& other) const { return ht_ != other.ht_; } template bool serialize(ValueSerializer serializer, OUTPUT *fp) { return ht_.serialize(serializer, fp); } template bool unserialize(ValueSerializer serializer, INPUT *fp) { return ht_.unserialize(serializer, fp); } template bool write_metadata(OUTPUT *fp) { return ht_.write_metadata(fp); } template bool read_metadata(INPUT *fp) { return ht_.read_metadata(fp); } template bool write_nopointer_data(OUTPUT *fp) { return ht_.write_nopointer_data(fp); } template bool read_nopointer_data(INPUT *fp) { return ht_.read_nopointer_data(fp); } // low-level stats int num_table_copies() const { return ht_.num_table_copies(); } // Not part of the hashtable API, but is provided to make testing easier. virtual key_type get_key(const value_type& value) const = 0; // All subclasses should define get_data(value_type) as well. I don't // provide an abstract-virtual definition here, because the return type // differs between subclasses (not all subclasses define data_type). //virtual data_type get_data(const value_type& value) const = 0; //virtual data_type default_data() const = 0; // These allow introspection into the interface. "Supports" means // that the implementation of this functionality isn't a noop. virtual bool supports_clear_no_resize() const = 0; virtual bool supports_empty_key() const = 0; virtual bool supports_deleted_key() const = 0; virtual bool supports_brackets() const = 0; // has a 'real' operator[] virtual bool supports_readwrite() const = 0; virtual bool supports_num_table_copies() const = 0; virtual bool supports_serialization() const = 0; protected: HT ht_; // These are what subclasses have to define to get class-specific behavior virtual key_type it_to_key(const iterator& it) const = 0; virtual key_type it_to_key(const const_iterator& it) const = 0; virtual key_type it_to_key(const local_iterator& it) const = 0; virtual key_type it_to_key(const const_local_iterator& it) const = 0; }; // --------------------------------------------------------------------- template , class EqualKey = std::equal_to, class Alloc = libc_allocator_with_realloc > > class HashtableInterface_SparseHashMap : public BaseHashtableInterface< sparse_hash_map > { private: typedef sparse_hash_map ht; typedef BaseHashtableInterface p; // parent public: explicit HashtableInterface_SparseHashMap( typename p::size_type expected_max_items = 0, const typename p::hasher& hf = typename p::hasher(), const typename p::key_equal& eql = typename p::key_equal(), const typename p::allocator_type& alloc = typename p::allocator_type()) : BaseHashtableInterface(expected_max_items, hf, eql, alloc) { } template HashtableInterface_SparseHashMap( InputIterator f, InputIterator l, typename p::size_type expected_max_items = 0, const typename p::hasher& hf = typename p::hasher(), const typename p::key_equal& eql = typename p::key_equal(), const typename p::allocator_type& alloc = typename p::allocator_type()) : BaseHashtableInterface(f, l, expected_max_items, hf, eql, alloc) { } typename p::key_type get_key(const typename p::value_type& value) const { return value.first; } typename ht::data_type get_data(const typename p::value_type& value) const { return value.second; } typename ht::data_type default_data() const { return typename ht::data_type(); } bool supports_clear_no_resize() const { return false; } bool supports_empty_key() const { return false; } bool supports_deleted_key() const { return true; } bool supports_brackets() const { return true; } bool supports_readwrite() const { return true; } bool supports_num_table_copies() const { return false; } bool supports_serialization() const { return true; } void set_empty_key(const typename p::key_type&) { } void clear_empty_key() { } typename p::key_type empty_key() const { return typename p::key_type(); } int num_table_copies() const { return 0; } typedef typename ht::NopointerSerializer NopointerSerializer; protected: template friend void swap(HashtableInterface_SparseHashMap& a, HashtableInterface_SparseHashMap& b); typename p::key_type it_to_key(const typename p::iterator& it) const { return it->first; } typename p::key_type it_to_key(const typename p::const_iterator& it) const { return it->first; } typename p::key_type it_to_key(const typename p::local_iterator& it) const { return it->first; } typename p::key_type it_to_key(const typename p::const_local_iterator& it) const { return it->first; } }; template void swap(HashtableInterface_SparseHashMap& a, HashtableInterface_SparseHashMap& b) { swap(a.ht_, b.ht_); } // --------------------------------------------------------------------- template , class EqualKey = std::equal_to, class Alloc = libc_allocator_with_realloc > class HashtableInterface_SparseHashSet : public BaseHashtableInterface< sparse_hash_set > { private: typedef sparse_hash_set ht; typedef BaseHashtableInterface p; // parent public: // Bizarrely, MSVC 8.0 has trouble with the (perfectly fine) // typename's in this constructor, and this constructor alone, out // of all the ones in the file. So for MSVC, we take some typenames // out, which is technically invalid C++, but MSVC doesn't seem to // mind. #ifdef _MSC_VER explicit HashtableInterface_SparseHashSet( typename p::size_type expected_max_items = 0, const typename p::hasher& hf = p::hasher(), const typename p::key_equal& eql = p::key_equal(), const typename p::allocator_type& alloc = p::allocator_type()) : BaseHashtableInterface(expected_max_items, hf, eql, alloc) { } #else explicit HashtableInterface_SparseHashSet( typename p::size_type expected_max_items = 0, const typename p::hasher& hf = typename p::hasher(), const typename p::key_equal& eql = typename p::key_equal(), const typename p::allocator_type& alloc = typename p::allocator_type()) : BaseHashtableInterface(expected_max_items, hf, eql, alloc) { } #endif template HashtableInterface_SparseHashSet( InputIterator f, InputIterator l, typename p::size_type expected_max_items = 0, const typename p::hasher& hf = typename p::hasher(), const typename p::key_equal& eql = typename p::key_equal(), const typename p::allocator_type& alloc = typename p::allocator_type()) : BaseHashtableInterface(f, l, expected_max_items, hf, eql, alloc) { } template bool bracket_equal(const typename p::key_type& key, const AssignValue&) { return this->ht_.find(key) != this->ht_.end(); } template void bracket_assign(const typename p::key_type& key, const AssignValue&) { this->ht_.insert(key); } typename p::key_type get_key(const typename p::value_type& value) const { return value; } // For sets, the only 'data' is that an item is actually inserted. bool get_data(const typename p::value_type&) const { return true; } bool default_data() const { return true; } bool supports_clear_no_resize() const { return false; } bool supports_empty_key() const { return false; } bool supports_deleted_key() const { return true; } bool supports_brackets() const { return false; } bool supports_readwrite() const { return true; } bool supports_num_table_copies() const { return false; } bool supports_serialization() const { return true; } void set_empty_key(const typename p::key_type&) { } void clear_empty_key() { } typename p::key_type empty_key() const { return typename p::key_type(); } int num_table_copies() const { return 0; } typedef typename ht::NopointerSerializer NopointerSerializer; protected: template friend void swap(HashtableInterface_SparseHashSet& a, HashtableInterface_SparseHashSet& b); typename p::key_type it_to_key(const typename p::iterator& it) const { return *it; } typename p::key_type it_to_key(const typename p::const_iterator& it) const { return *it; } typename p::key_type it_to_key(const typename p::local_iterator& it) const { return *it; } typename p::key_type it_to_key(const typename p::const_local_iterator& it) const { return *it; } }; template void swap(HashtableInterface_SparseHashSet& a, HashtableInterface_SparseHashSet& b) { swap(a.ht_, b.ht_); } // --------------------------------------------------------------------- template class HashtableInterface_SparseHashtable : public BaseHashtableInterface< sparse_hashtable > { private: typedef sparse_hashtable ht; typedef BaseHashtableInterface p; // parent public: explicit HashtableInterface_SparseHashtable( typename p::size_type expected_max_items = 0, const typename p::hasher& hf = typename p::hasher(), const typename p::key_equal& eql = typename p::key_equal(), const typename p::allocator_type& alloc = typename p::allocator_type()) : BaseHashtableInterface(expected_max_items, hf, eql, ExtractKey(), SetKey(), alloc) { } template HashtableInterface_SparseHashtable( InputIterator f, InputIterator l, typename p::size_type expected_max_items = 0, const typename p::hasher& hf = typename p::hasher(), const typename p::key_equal& eql = typename p::key_equal(), const typename p::allocator_type& alloc = typename p::allocator_type()) : BaseHashtableInterface(expected_max_items, hf, eql, ExtractKey(), SetKey(), alloc) { this->insert(f, l); } float max_load_factor() const { float shrink, grow; this->ht_.get_resizing_parameters(&shrink, &grow); return grow; } void max_load_factor(float new_grow) { float shrink, grow; this->ht_.get_resizing_parameters(&shrink, &grow); this->ht_.set_resizing_parameters(shrink, new_grow); } float min_load_factor() const { float shrink, grow; this->ht_.get_resizing_parameters(&shrink, &grow); return shrink; } void min_load_factor(float new_shrink) { float shrink, grow; this->ht_.get_resizing_parameters(&shrink, &grow); this->ht_.set_resizing_parameters(new_shrink, grow); } template bool bracket_equal(const typename p::key_type&, const AssignValue&) { return false; } template void bracket_assign(const typename p::key_type&, const AssignValue&) { } typename p::key_type get_key(const typename p::value_type& value) const { return extract_key(value); } typename p::value_type get_data(const typename p::value_type& value) const { return value; } typename p::value_type default_data() const { return typename p::value_type(); } bool supports_clear_no_resize() const { return false; } bool supports_empty_key() const { return false; } bool supports_deleted_key() const { return true; } bool supports_brackets() const { return false; } bool supports_readwrite() const { return true; } bool supports_num_table_copies() const { return true; } bool supports_serialization() const { return true; } void set_empty_key(const typename p::key_type&) { } void clear_empty_key() { } typename p::key_type empty_key() const { return typename p::key_type(); } // These tr1 names aren't defined for sparse_hashtable. typename p::hasher hash_function() { return this->hash_funct(); } void rehash(typename p::size_type hint) { this->resize(hint); } // TODO(csilvers): also support/test destructive_begin()/destructive_end()? typedef typename ht::NopointerSerializer NopointerSerializer; protected: template friend void swap( HashtableInterface_SparseHashtable& a, HashtableInterface_SparseHashtable& b); typename p::key_type it_to_key(const typename p::iterator& it) const { return extract_key(*it); } typename p::key_type it_to_key(const typename p::const_iterator& it) const { return extract_key(*it); } typename p::key_type it_to_key(const typename p::local_iterator& it) const { return extract_key(*it); } typename p::key_type it_to_key(const typename p::const_local_iterator& it) const { return extract_key(*it); } private: ExtractKey extract_key; }; template void swap(HashtableInterface_SparseHashtable& a, HashtableInterface_SparseHashtable& b) { swap(a.ht_, b.ht_); } // --------------------------------------------------------------------- // Unlike dense_hash_map, the wrapper class takes an extra template // value saying what the empty key is. template , class EqualKey = std::equal_to, class Alloc = libc_allocator_with_realloc > > class HashtableInterface_DenseHashMap : public BaseHashtableInterface< dense_hash_map > { private: typedef dense_hash_map ht; typedef BaseHashtableInterface p; // parent public: explicit HashtableInterface_DenseHashMap( typename p::size_type expected_max_items = 0, const typename p::hasher& hf = typename p::hasher(), const typename p::key_equal& eql = typename p::key_equal(), const typename p::allocator_type& alloc = typename p::allocator_type()) : BaseHashtableInterface(expected_max_items, hf, eql, alloc) { this->set_empty_key(EMPTY_KEY); } template HashtableInterface_DenseHashMap( InputIterator f, InputIterator l, typename p::size_type expected_max_items = 0, const typename p::hasher& hf = typename p::hasher(), const typename p::key_equal& eql = typename p::key_equal(), const typename p::allocator_type& alloc = typename p::allocator_type()) : BaseHashtableInterface(f, l, EMPTY_KEY, expected_max_items, hf, eql, alloc) { } void clear_no_resize() { this->ht_.clear_no_resize(); } typename p::key_type get_key(const typename p::value_type& value) const { return value.first; } typename ht::data_type get_data(const typename p::value_type& value) const { return value.second; } typename ht::data_type default_data() const { return typename ht::data_type(); } bool supports_clear_no_resize() const { return true; } bool supports_empty_key() const { return true; } bool supports_deleted_key() const { return true; } bool supports_brackets() const { return true; } bool supports_readwrite() const { return false; } bool supports_num_table_copies() const { return false; } bool supports_serialization() const { return true; } typedef typename ht::NopointerSerializer NopointerSerializer; template bool write_metadata(OUTPUT *) { return false; } template bool read_metadata(INPUT *) { return false; } template bool write_nopointer_data(OUTPUT *) { return false; } template bool read_nopointer_data(INPUT *) { return false; } int num_table_copies() const { return 0; } protected: template friend void swap(HashtableInterface_DenseHashMap& a, HashtableInterface_DenseHashMap& b); typename p::key_type it_to_key(const typename p::iterator& it) const { return it->first; } typename p::key_type it_to_key(const typename p::const_iterator& it) const { return it->first; } typename p::key_type it_to_key(const typename p::local_iterator& it) const { return it->first; } typename p::key_type it_to_key(const typename p::const_local_iterator& it) const { return it->first; } }; template void swap(HashtableInterface_DenseHashMap& a, HashtableInterface_DenseHashMap& b) { swap(a.ht_, b.ht_); } // --------------------------------------------------------------------- // Unlike dense_hash_set, the wrapper class takes an extra template // value saying what the empty key is. template , class EqualKey = std::equal_to, class Alloc = libc_allocator_with_realloc > class HashtableInterface_DenseHashSet : public BaseHashtableInterface< dense_hash_set > { private: typedef dense_hash_set ht; typedef BaseHashtableInterface p; // parent public: explicit HashtableInterface_DenseHashSet( typename p::size_type expected_max_items = 0, const typename p::hasher& hf = typename p::hasher(), const typename p::key_equal& eql = typename p::key_equal(), const typename p::allocator_type& alloc = typename p::allocator_type()) : BaseHashtableInterface(expected_max_items, hf, eql, alloc) { this->set_empty_key(EMPTY_KEY); } template HashtableInterface_DenseHashSet( InputIterator f, InputIterator l, typename p::size_type expected_max_items = 0, const typename p::hasher& hf = typename p::hasher(), const typename p::key_equal& eql = typename p::key_equal(), const typename p::allocator_type& alloc = typename p::allocator_type()) : BaseHashtableInterface(f, l, EMPTY_KEY, expected_max_items, hf, eql, alloc) { } void clear_no_resize() { this->ht_.clear_no_resize(); } template bool bracket_equal(const typename p::key_type& key, const AssignValue&) { return this->ht_.find(key) != this->ht_.end(); } template void bracket_assign(const typename p::key_type& key, const AssignValue&) { this->ht_.insert(key); } typename p::key_type get_key(const typename p::value_type& value) const { return value; } bool get_data(const typename p::value_type&) const { return true; } bool default_data() const { return true; } bool supports_clear_no_resize() const { return true; } bool supports_empty_key() const { return true; } bool supports_deleted_key() const { return true; } bool supports_brackets() const { return false; } bool supports_readwrite() const { return false; } bool supports_num_table_copies() const { return false; } bool supports_serialization() const { return true; } typedef typename ht::NopointerSerializer NopointerSerializer; template bool write_metadata(OUTPUT *) { return false; } template bool read_metadata(INPUT *) { return false; } template bool write_nopointer_data(OUTPUT *) { return false; } template bool read_nopointer_data(INPUT *) { return false; } int num_table_copies() const { return 0; } protected: template friend void swap(HashtableInterface_DenseHashSet& a, HashtableInterface_DenseHashSet& b); typename p::key_type it_to_key(const typename p::iterator& it) const { return *it; } typename p::key_type it_to_key(const typename p::const_iterator& it) const { return *it; } typename p::key_type it_to_key(const typename p::local_iterator& it) const { return *it; } typename p::key_type it_to_key(const typename p::const_local_iterator& it) const { return *it; } }; template void swap(HashtableInterface_DenseHashSet& a, HashtableInterface_DenseHashSet& b) { swap(a.ht_, b.ht_); } // --------------------------------------------------------------------- // Unlike dense_hashtable, the wrapper class takes an extra template // value saying what the empty key is. template class HashtableInterface_DenseHashtable : public BaseHashtableInterface< dense_hashtable > { private: typedef dense_hashtable ht; typedef BaseHashtableInterface p; // parent public: explicit HashtableInterface_DenseHashtable( typename p::size_type expected_max_items = 0, const typename p::hasher& hf = typename p::hasher(), const typename p::key_equal& eql = typename p::key_equal(), const typename p::allocator_type& alloc = typename p::allocator_type()) : BaseHashtableInterface(expected_max_items, hf, eql, ExtractKey(), SetKey(), alloc) { this->set_empty_key(EMPTY_KEY); } template HashtableInterface_DenseHashtable( InputIterator f, InputIterator l, typename p::size_type expected_max_items = 0, const typename p::hasher& hf = typename p::hasher(), const typename p::key_equal& eql = typename p::key_equal(), const typename p::allocator_type& alloc = typename p::allocator_type()) : BaseHashtableInterface(expected_max_items, hf, eql, ExtractKey(), SetKey(), alloc) { this->set_empty_key(EMPTY_KEY); this->insert(f, l); } void clear_no_resize() { this->ht_.clear_no_resize(); } float max_load_factor() const { float shrink, grow; this->ht_.get_resizing_parameters(&shrink, &grow); return grow; } void max_load_factor(float new_grow) { float shrink, grow; this->ht_.get_resizing_parameters(&shrink, &grow); this->ht_.set_resizing_parameters(shrink, new_grow); } float min_load_factor() const { float shrink, grow; this->ht_.get_resizing_parameters(&shrink, &grow); return shrink; } void min_load_factor(float new_shrink) { float shrink, grow; this->ht_.get_resizing_parameters(&shrink, &grow); this->ht_.set_resizing_parameters(new_shrink, grow); } template bool bracket_equal(const typename p::key_type&, const AssignValue&) { return false; } template void bracket_assign(const typename p::key_type&, const AssignValue&) { } typename p::key_type get_key(const typename p::value_type& value) const { return extract_key(value); } typename p::value_type get_data(const typename p::value_type& value) const { return value; } typename p::value_type default_data() const { return typename p::value_type(); } bool supports_clear_no_resize() const { return true; } bool supports_empty_key() const { return true; } bool supports_deleted_key() const { return true; } bool supports_brackets() const { return false; } bool supports_readwrite() const { return false; } bool supports_num_table_copies() const { return true; } bool supports_serialization() const { return true; } typedef typename ht::NopointerSerializer NopointerSerializer; template bool write_metadata(OUTPUT *) { return false; } template bool read_metadata(INPUT *) { return false; } template bool write_nopointer_data(OUTPUT *) { return false; } template bool read_nopointer_data(INPUT *) { return false; } // These tr1 names aren't defined for dense_hashtable. typename p::hasher hash_function() { return this->hash_funct(); } void rehash(typename p::size_type hint) { this->resize(hint); } protected: template friend void swap( HashtableInterface_DenseHashtable& a, HashtableInterface_DenseHashtable& b); typename p::key_type it_to_key(const typename p::iterator& it) const { return extract_key(*it); } typename p::key_type it_to_key(const typename p::const_iterator& it) const { return extract_key(*it); } typename p::key_type it_to_key(const typename p::local_iterator& it) const { return extract_key(*it); } typename p::key_type it_to_key(const typename p::const_local_iterator& it) const { return extract_key(*it); } private: ExtractKey extract_key; }; template void swap(HashtableInterface_DenseHashtable& a, HashtableInterface_DenseHashtable& b) { swap(a.ht_, b.ht_); } _END_GOOGLE_NAMESPACE_ #endif // UTIL_GTL_HASH_TEST_INTERFACE_H_