www.pudn.com > EasySoap++-0.6.1.rar > SOAPHashMap.h
/* * EasySoap++ - A C++ library for SOAP (Simple Object Access Protocol) * Copyright (C) 2001 David Crowley; SciTegic, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Id: SOAPHashMap.h,v 1.3 2002/04/10 07:03:41 dcrowley Exp $ */ #ifndef __SOAPHASHMAP_H__ #define __SOAPHASHMAP_H__ #ifdef _MSC_VER #pragma warning(disable: 4284) #endif // _MSC_VER BEGIN_EASYSOAP_NAMESPACE /** * Functor used by SOAPHashMap class to generate * a hashcode for an object of type T. * * It must be specialized for your own class. * * Specialized only for SOAPString. */ templatestruct SOAPHashCodeFunctor; /** * Functor used by SOAPHashMap class to compare * for equality two objects of type T. * * It can be specialized for your own class, by * default it simply uses operator==. */ template struct SOAPEqualsFunctor { bool operator()(const T& a, const T& b) const { return a == b; } }; /** * Functor to be specialized for use with SOAPHashMapNoCase. * Specialized only for SOAPString. */ template struct SOAPHashCodeFunctorNoCase; /** * Functor to be specialized for use with SOAPHashMapNoCase. * Specialized only for SOAPString. */ template struct SOAPEqualsFunctorNoCase; END_EASYSOAP_NAMESPACE #include #include BEGIN_EASYSOAP_NAMESPACE /** * SOAPHashMap is a general purpose templated hash table class. */ template , typename E = SOAPEqualsFunctor > class SOAPHashMap { private: // structure for keeping a linked-list of elements struct HashElement { HashElement(): m_next(0), m_hash(0) { } HashElement *m_next; size_t m_hash; K m_key; I m_item; }; H hashcode; E equals; typedef SOAPArray Elements; Elements m_elements; SOAPPool m_pool; size_t m_numElements; float m_fillfactor; size_t m_resizeThreshold; /** * Iterator class for SOAPHashMap */ class ForwardHashMapIterator { private: const SOAPHashMap *m_map; Elements::Iterator m_index; HashElement *m_he; friend class SOAPHashMap ; // private constuctor that can only be called by SOAPHashMap ForwardHashMapIterator(const SOAPHashMap *map, Elements::Iterator index) : m_map(map), m_index(index), m_he(0) { if (m_map) { // Find first bucket with an element while (m_index != m_map->m_elements.End() && !(m_he = *m_index)) ++m_index; } } ForwardHashMapIterator(const SOAPHashMap *map, Elements::Iterator index, HashElement *he) : m_map(map), m_index(index), m_he(he) { } public: /** * Default constructor for the SOAPHashMap iterator. */ ForwardHashMapIterator() : m_map(0), m_index(0) { } /** * Copy constructor for the SOAPHashMap iterator. */ ForwardHashMapIterator(const ForwardHashMapIterator& r) : m_map(r.m_map), m_index(r.m_index), m_he(r.m_he) { } /** * Assignment operator for the SOAPHashMap iterator. */ ForwardHashMapIterator& operator=(const ForwardHashMapIterator& r) { m_map = r.m_map; m_index = r.m_index; m_he = r.m_he; return *this; } /** * Equals operator for the SOAPHashMap iterator. * * Returns true iff the two iterators point at the * same object in the same hash table. */ bool operator==(const ForwardHashMapIterator& r) const { // make sure we're pointing to the exact same element return m_he == r.m_he; } /** * Not equals operator for the SOAPHashMap iterator. * * Returns false iff the two iterators point at the * same object in the same hash table. */ bool operator!=(const ForwardHashMapIterator& r) const { // can't be pointing to the same element... return m_he != r.m_he; } /** * Increment iterator to point at the next element * in the SOAPHashMap. */ ForwardHashMapIterator& Next() { if (m_index != m_map->m_elements.End() && !(m_he = m_he->m_next)) while (++m_index != m_map->m_elements.End() && !(m_he = *m_index)) ; return *this; } /** * Pre-increment */ ForwardHashMapIterator& operator++() { return Next(); } /** * Post-increment */ ForwardHashMapIterator operator++(int) { // copy our current position ForwardHashMapIterator ret(*this); // move to the next item Next(); // return the old position return ret; } /** * operator bool returns true if the iterator * points to a valid element in the SOAPHashMap * * This is so you can do tests like this: * * SOAPHashMap ::Iterator i = map.Find("Hello"); * if (i) * { * // we found the element * } */ operator bool() { return m_index != m_map->m_elements.End(); } /** * operator ! returns true if the iterator * does not point to a valid element in the SOAPHashMap. * * This is so you can do tests like this: * * SOAPHashMap ::Iterator i = map.Find("Hello"); * if (!i) * { * // We didn't find the element * } */ bool operator!() { return m_index == m_map->m_elements.End(); } /** * The iterator can be used like a pointer * which points to the value portion of * the element. Thus *i returns a reference * to the value and i->member can be used to * access a member of the value. */ I& operator*() { return m_he->m_item; } const I& operator*() const { return m_he->m_item; } I* operator->() { return &m_he->m_item; } const I* operator->() const { return &m_he->m_item; } /** * * Explicit method used to access the value * portion of the current element pointed to * by the iterator. */ const I& Item() const { return m_he->m_item; } I& Item() { return m_he->m_item; } /** * Explicit method to access the key portion of the current * element. The key cannot be modified! */ const K& Key() const { return m_he->m_key; } }; public: typedef ForwardHashMapIterator Iterator; /** * Destructor */ ~SOAPHashMap() { Empty(); } /** * Default constructor * * @param s Initial number of buckets in the hash table. * @param fillfactor As a percentage how full hash table must * become before the size is increased. */ SOAPHashMap(size_t s = 31, float fillfactor = 0.75) : m_numElements(0), m_fillfactor(fillfactor), m_resizeThreshold(0) { Resize(s); // this sets m_resizeThreshold } /** * Copy constructor */ template SOAPHashMap(const SOAPHashMap& r) : m_numElements(0), m_fillfactor(r.GetFillFactor()), m_resizeThreshold(0) { Resize(r.GetNumBuckets()); // this sets m_resizeThreshold *this = r; } /** * Copy constructor */ SOAPHashMap(const SOAPHashMap& r) : m_numElements(0), m_fillfactor(r.GetFillFactor()), m_resizeThreshold(0) { Resize(r.GetNumBuckets()); // this sets m_resizeThreshold *this = r; } /** * Assignment operator. */ template SOAPHashMap& operator=(const SOAPHashMap& r) { if ((void *)this != (void *)&r) { Clear(); Resize(r.GetNumBuckets()); SOAPHashMap::Iterator e = r.End(); for (SOAPHashMap::Iterator it = r.Begin(); it != e; ++it) Add(it.Key(), it.Item()); } return *this; } /** * Assignment operator. */ SOAPHashMap& operator=(const SOAPHashMap& r) { if (this != &r) { Clear(); Resize(r.GetNumBuckets()); Iterator e = r.End(); for (Iterator it = r.Begin(); it != e; ++it) Add(it.Key(), it.Item()); } return *this; } /** * Returns an iterator which points to the * first element in the hash table. As the * iterator is incremented elements are returned * in hash order, not sorted like an STL map. */ Iterator Begin() const { return Iterator(this, (Elements::Iterator)m_elements.Begin()); } /** * Returns an iterator which points to * an invalid element, one past the last * valid element. */ Iterator End() const { return Iterator(this, (Elements::Iterator)m_elements.End()); } /** * Adds an element to the SOAPHashMap with the * given key and value. If an element with the * given key already exists then the value is * changed to the given value. * * @param key The key lookup value. * @param item The value associated with the key. */ template I& Add(const X& key, const Y& item) { // see if we can find it size_t hash = hashcode(key); Iterator found = Find(key, hash); if (found) return *found = item; return Put(hash, key, item); } /** * Returns a reference to the the value in the * SOAPHashMap with the give key. If the key * value does not exist then one is inserted * and a (potentially) uninitialized value * is returned. * * @param key The key lookup value. */ template I& operator[](const X& key) { // see if we can find it size_t hash = hashcode(key); Iterator found = Find(key, hash); if (found) return *found; return Put(hash, key); } /** * Removes the value with the give key * from the SOAPHashMap and returns true * or returns false if no value with the * given key was found. */ template bool Remove(const X& key) { if (m_elements.Size() > 0) { size_t hash = hashcode(key); // we use ** here so we can treat the first element the // same was as the other elements in the linked list HashElement **he = &m_elements[hash % m_elements.Size()]; while (*he) { if ((*he)->m_hash == hash && equals((*he)->m_key, key)) { HashElement *temp = (*he)->m_next; PutBackHashElement(*he); *he = temp; return true; } he = &((*he)->m_next); } } return false; } /** * Clears out the SOAPHashTable and * all values are removed. * * Actual instances of objects are NOT * deleted but saved to be reused later. */ void Clear() { for (Elements::Iterator i = m_elements.Begin(); i != m_elements.End(); ++i) { HashElement *he = *i; while (he) { HashElement *next = he->m_next; PutBackHashElement(he); he = next; } *i = 0; } } /** * Clears out the SOAPHashTable and * all values are removed. * * Actual instances of objects are deleted. */ void Empty() { Elements::Iterator i; for (i = m_elements.Begin(); i != m_elements.End(); ++i) { HashElement *he = *i; while (he) { HashElement *next = he->m_next; delete he; he = next; } } m_pool.Empty(); } /** * Returns the number of elements in the SOAPHashTable. */ size_t Size() const { return m_numElements; } /** * Finds and returns an iterator which points * to the element with the given key value. * If no element with the given key is found * then the value of End() is returned. */ template Iterator Find(const X& key) const { size_t hash = hashcode(key); return Find(key, hash); } /** * Returns how many internal hash buckets * are being used. */ size_t GetNumBuckets() const {return m_elements.Size();} /** * Returns the fill factor. */ float GetFillFactor() const {return m_fillfactor;} /** * These typedefs are supplied to make * the SOAPHashMap class more STL friendly. */ typedef K key_type; typedef Iterator iterator; typedef Iterator const_iterator; /** * These methods are supplied to make * the SOAPHashMap class more STL friendly. */ iterator begin() const {return Begin();} iterator end() const {return End();} private: // Does the actual find. We pass in the hashcode so we don't have // to recompute it since it is used in other places. template Iterator Find(const X& key, size_t hash) const { if (m_elements.Size() > 0) { size_t index = hash % m_elements.Size(); HashElement *he = m_elements[index]; while (he) { if (he->m_hash == hash && equals(he->m_key, key)) return Iterator(this, (Elements::Iterator)m_elements.Begin() + index, he); he = he->m_next; } } return End(); } // resize only if it makes the table bigger void Resize(size_t newsize) { if (newsize <= m_elements.Size()) return; Elements newelements; newelements.Resize(newsize); Elements::Iterator i; for (i = newelements.Begin(); i != newelements.End(); ++i) *i = 0; for (i = m_elements.Begin(); i != m_elements.End(); ++i) { HashElement *he = *i; while (he) { HashElement *next = he->m_next; size_t index = he->m_hash % newsize; he->m_next = newelements[index]; newelements[index] = he; he = next; } } m_resizeThreshold = (size_t)(m_fillfactor * newsize); m_elements.AttachTo(newelements); } void PutBackHashElement(HashElement *he) { m_pool.Return(he); --m_numElements; } HashElement *GetNextHashElement(size_t hash) { HashElement *he = m_pool.Get(); he->m_hash = hash; ++m_numElements; return he; } // This method actually puts an object into the hashtable. template I& Put(size_t hash, const X& key, const Y& item) { // check for resize if (m_numElements >= m_resizeThreshold) Resize(m_elements.Size() * 2 + 1); size_t index = hash % m_elements.Size(); HashElement *he = GetNextHashElement(hash); he->m_key = key; he->m_item = item; he->m_next = m_elements[index]; m_elements[index] = he; return he->m_item; } // This method actually puts an object into the hashtable. template I& Put(size_t hash, const X& key) { // check for resize if (m_numElements >= m_resizeThreshold) Resize(m_elements.Size() * 2 + 1); size_t index = hash % m_elements.Size(); HashElement *he = GetNextHashElement(hash); he->m_key = key; he->m_next = m_elements[index]; m_elements[index] = he; return he->m_item; } friend class ForwardHashMapIterator; }; /** * This class is used to easily create a case insensitive * SOAPHashMap container. * * This class overides the the default hashcode functor (template * parameter H) and equals functor (template parameter E) which * of the SOAPHashMap class to SOAPHashCodeFunctorNoCase and * SOAPEqualsFunctorNoCase respectively. * * These functors are only implemented for the SOAPString class. * * @see SOAPHashCodeFunctorNoCase * @see SOAPEqualsFunctorNoCase * */ template class SOAPHashMapNoCase : public SOAPHashMap , SOAPEqualsFunctorNoCase > { private: typedef SOAPHashMap , SOAPEqualsFunctorNoCase > super; public: SOAPHashMapNoCase(size_t s = 31, float fillfactor = 0.75) : super(s, fillfactor) { } }; END_EASYSOAP_NAMESPACE #endif // __SOAPHASHMAP_H__