w_hash.h

Go to the documentation of this file.
00001 /* -*- mode:C++; c-basic-offset:4 -*-
00002      Shore-MT -- Multi-threaded port of the SHORE storage manager
00003    
00004                        Copyright (c) 2007-2009
00005       Data Intensive Applications and Systems Labaratory (DIAS)
00006                Ecole Polytechnique Federale de Lausanne
00007    
00008                          All Rights Reserved.
00009    
00010    Permission to use, copy, modify and distribute this software and
00011    its documentation is hereby granted, provided that both the
00012    copyright notice and this permission notice appear in all copies of
00013    the software, derivative works or modified versions, and any
00014    portions thereof, and that both notices appear in supporting
00015    documentation.
00016    
00017    This code is distributed in the hope that it will be useful, but
00018    WITHOUT ANY WARRANTY; without even the implied warranty of
00019    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS
00020    DISCLAIM ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER
00021    RESULTING FROM THE USE OF THIS SOFTWARE.
00022 */
00023 
00024 // -*- mode:c++; c-basic-offset:4 -*-
00025 /*<std-header orig-src='shore' incl-file-exclusion='W_HASH_H'>
00026 
00027  $Id: w_hash.h,v 1.37 2010/09/15 18:35:40 nhall Exp $
00028 
00029 SHORE -- Scalable Heterogeneous Object REpository
00030 
00031 Copyright (c) 1994-99 Computer Sciences Department, University of
00032                       Wisconsin -- Madison
00033 All Rights Reserved.
00034 
00035 Permission to use, copy, modify and distribute this software and its
00036 documentation is hereby granted, provided that both the copyright
00037 notice and this permission notice appear in all copies of the
00038 software, derivative works or modified versions, and any portions
00039 thereof, and that both notices appear in supporting documentation.
00040 
00041 THE AUTHORS AND THE COMPUTER SCIENCES DEPARTMENT OF THE UNIVERSITY
00042 OF WISCONSIN - MADISON ALLOW FREE USE OF THIS SOFTWARE IN ITS
00043 "AS IS" CONDITION, AND THEY DISCLAIM ANY LIABILITY OF ANY KIND
00044 FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
00045 
00046 This software was developed with support by the Advanced Research
00047 Project Agency, ARPA order number 018 (formerly 8230), monitored by
00048 the U.S. Army Research Laboratory under contract DAAB07-91-C-Q518.
00049 Further funding for this work was provided by DARPA through
00050 Rome Research Laboratory Contract No. F30602-97-2-0247.
00051 
00052 */
00053 
00054 #ifndef W_HASH_H
00055 #define W_HASH_H
00056 
00057 #include "w_defines.h"
00058 
00059 /*  -- do not edit anything above this line --   </std-header>*/
00060 
00061 /**\file w_hash.h
00062  */
00063 
00064 #include <w_base.h>
00065 #include <w_list.h>
00066 
00067 
00068 template <class T, class LOCK, class K> class w_hash_t;
00069 template <class T, class LOCK, class K> class w_hash_i;
00070 
00071 #if DEAD
00072 inline w_base_t::uint4_t w_hash(long l)
00073 {
00074     return (w_base_t::uint4_t) l;
00075 }
00076 
00077 inline w_base_t::uint4_t w_hash(unsigned long l)
00078 {
00079     return (w_base_t::uint4_t) l;
00080 }
00081 
00082 inline w_base_t::uint4_t w_hash(w_base_t::uint4_t i)  {
00083     return i;
00084 }
00085 
00086 inline w_base_t::uint4_t w_hash(w_base_t::int4_t i)   {
00087     return CAST(w_base_t::uint4_t,i);
00088 }
00089 
00090 inline w_base_t::uint4_t w_hash(w_base_t::uint2_t i)  {
00091     return i;
00092 }
00093 
00094 inline w_base_t::uint4_t w_hash(w_base_t::int2_t i)   {
00095     return CAST(w_base_t::int2_t, i);
00096 }
00097 #endif
00098 
00099 BIND_FRIEND_OPERATOR_PART_1B(T,LOCK,K,w_hash_t<T,LOCK,K>)
00100 
00101 
00102 /**\brief Templated hash table. Not particularly sophisticated.
00103  *
00104  * The hash function used here is :
00105  * - w_hash(key) & _mask
00106  *
00107  * Thus, to make this work, your key type needs to be a class containing
00108  * a public method 
00109  * w_base_t::uint4_t hash() const;
00110  * (This is somewhat inconvenient if you want the key to be an atomic type,
00111  * but it's a lot easier to find locate the hash functions this way and
00112  * we don't have to worry about any implicit construction of types by
00113  * the compiler this way.)
00114  *
00115  * Note that since the hash function uses the _mask to collect the lower
00116  * bits of the result of w_hash, the key.hash() function should be sensitive
00117  * to the way hash-table uses it, and the hash tables 
00118  * should be aware of the likely bit distribution
00119  * of the result of key.hash().
00120  *
00121  */
00122 template <class T, class LOCK, class K>
00123 class w_hash_t : public w_base_t {
00124 public:
00125     /**\brief Construct hash table 
00126      * @param[in] sz Number of bits in result values. 
00127      * @param[in] key_offset Offset in object of type T where key K is found
00128      * @param[in] link_offset Offset in object of type T where w_link_t is found
00129      *            This w_link_t is used to hold the object in a hash table bucket
00130      * @param[in] lock Pointer to a lock used to protect the table.
00131      *
00132      * The size determines a mask used to restrict the resulting 
00133      * hash values to a desired size.
00134      *
00135      * The lock passed in is not used.  There is no enforcement of
00136      * locking these structures. The template contains the lock type
00137      * so that it is relatively easy to tell what structures are
00138      * unprotected by perusing the code.
00139      *
00140      * See \ref #W_HASH_ARG(class,key,link)
00141      */
00142     NORET                        w_hash_t(
00143         uint4_t                     sz,
00144         uint4_t                     key_offset,
00145         uint4_t                     link_offset,
00146         const LOCK *                lock);
00147     NORET                        ~w_hash_t();
00148 
00149 private:
00150     uint4_t                     bucket_for(K const &k) const;
00151     uint4_t                     bucket_for(T const *t) const;
00152 
00153 public:
00154     /// Insert an element in the table at the front of its bucket.
00155     w_hash_t&                   push(T* t);
00156     /// Insert an element in the table at the tail of its bucket.
00157     w_hash_t&                   append(T* t);
00158     /// Find an element in the table.
00159     T*                          lookup(const K& k) const;
00160     /// True if element is in the table.
00161     bool                        member(T const *t) const;
00162     /// Remove the (single) element with the given key 
00163     T*                          remove(const K& k);
00164     /// Remove the given element that is in the table.
00165     void                        remove(T* t);
00166     /// Total number of elements in the table.
00167     uint4_t                     num_members() const { return _cnt; }
00168 
00169     /// Standard ostream operator, despite the macro here (in \ref w_workaround.h)
00170     friend ostream&             operator<< 
00171                                      BIND_FRIEND_OPERATOR_PART_2B(T,LOCK,K) (
00172         ostream&                     o,
00173         const w_hash_t<T,LOCK,K>&        obj);
00174     
00175 
00176 private:
00177     friend class w_hash_i<T,LOCK,K>;
00178     uint4_t                        _top;
00179     uint4_t                        _mask;
00180     uint4_t                        _cnt;
00181     uint4_t                        _key_offset;
00182     uint4_t                        _link_offset;
00183     w_list_t<T, LOCK>*             _tab;
00184 
00185     const K&                       _keyof(const T& t) const  {
00186         return * (K*) (((const char*)&t) + _key_offset);
00187     }
00188     w_link_t&                       _linkof(T& t) const  {
00189         return * (w_link_t*) (((char*)&t) + _link_offset);
00190     }
00191 
00192     // disabled
00193     NORET                           w_hash_t(const w_hash_t&)
00194     ;
00195     w_hash_t&                       operator=(const w_hash_t&)
00196     ;
00197 };
00198 
00199 // XXX They are the same for now, avoids offsetof duplication
00200 /**\def W_HASH_ARG(class,key,link)
00201  * \brief Idiom for creating constructor argument for \ref #w_hash_t.
00202  *
00203  * This macro produces the last two arguments of the w_hash_t constructor.
00204  * Example :
00205  * \code
00206  * class key_t;
00207  * class entry_t {
00208  *    ...
00209  *    public:
00210  *       key_t    hashkey;
00211  *       w_link_t hashlink;
00212  * };
00213  *
00214  * w_hash_t<entry_t,key_t>(16, W_HASH_ARG(entry_t,hashkey,hashlink)) hashtable;
00215  * \endcode
00216  *
00217  */
00218 #define        W_HASH_ARG(class,key,link)  W_KEYED_ARG(class, key, link)
00219 
00220 
00221 /**\brief Iterate over hash table (for debugging)
00222  *
00223  * \note Not for general use.  Helper for w_hash_t,
00224  * and useful for writing debugging / dump-table code.
00225  *
00226  * Example:
00227  * \code
00228  * w_hash_t<entry_t,key_t>(16, W_HASH_ARG(entry_t,hashkey,hashlink)) hashtable;
00229  *
00230  * w_hash_i<entry_t,key_t> iter(hashtable);
00231  * entry_t *entry = NULL;
00232  * while( ( entry = iter.next()) != NULL) {
00233  *    ...
00234  * }
00235  * \endcode
00236  *
00237  * Since the w_hash_t is built of w_list_t, the same comments go for
00238  * next() and curr() here.  You can remove items from the table in
00239  * an iteration but you cannot insert.
00240  */
00241 template <class T, class LOCK, class K>
00242 class w_hash_i : public w_base_t {
00243 public:
00244     NORET           w_hash_i(const w_hash_t<T,LOCK, K>& t) : _bkt(uint4_max), 
00245                                                     _htab(t) {};
00246         
00247     NORET           ~w_hash_i()        {};
00248     
00249     T*              next();
00250     T*              curr()                { return _iter.curr(); }
00251 
00252 private:
00253     uint4_t                   _bkt;
00254     w_list_i<T,LOCK>         _iter;
00255     const w_hash_t<T,LOCK, K>&     _htab;
00256     
00257     NORET           w_hash_i(w_hash_i&);
00258 
00259     w_hash_i&       operator=(w_hash_i&)
00260     ;
00261 };
00262 
00263 
00264 template <class T, class LOCK, class K>
00265 ostream& operator<<(
00266     ostream&                        o,
00267     const w_hash_t<T,LOCK, K>&        h)
00268 {
00269     for (int i = 0; i < h._top; i++)  {
00270         o << '[' << i << "] ";
00271         w_list_i<T,LOCK> iter(h._tab[i]);
00272         while (iter.next())  {
00273             o << h._keyof(*iter.curr()) << " ";
00274         }
00275         o << endl;
00276     }
00277     return o;
00278 }
00279 
00280 /**\cond skip */
00281 template <class T, class LOCK, class K>
00282 NORET
00283 w_hash_t<T,LOCK, K>::w_hash_t(
00284     w_base_t::uint4_t        sz,
00285     w_base_t::uint4_t        key_offset,
00286     w_base_t::uint4_t        link_offset,
00287     const LOCK *)
00288 : _top(0), _cnt(0), _key_offset(key_offset),
00289   _link_offset(link_offset), _tab(0)
00290 {
00291     for (_top = 1; _top < sz; _top <<= 1) ;
00292     _mask = _top - 1;
00293     
00294     w_assert1(!_tab); // just to check space
00295     _tab = new w_list_t<T,LOCK>[_top];
00296     w_assert1(_tab);
00297     for (unsigned i = 0; i < _top; i++)  {
00298         _tab[i].set_offset(_link_offset);
00299     }
00300 }
00301 
00302 template <class T, class LOCK, class K>
00303 NORET
00304 w_hash_t<T,LOCK, K>::~w_hash_t()
00305 {
00306     w_assert1(_cnt == 0);
00307     delete[] _tab;
00308 }
00309 /**\endcond skip */
00310 
00311 template<class T, class LOCK, class K>
00312 w_base_t::uint4_t w_hash_t<T,LOCK, K>::bucket_for(T const* t) const {
00313     return bucket_for(_keyof(*t));
00314 }
00315 
00316 template<class T, class LOCK, class K>
00317 w_base_t::uint4_t w_hash_t<T,LOCK, K>::bucket_for(K const &k) const {
00318     return k.hash() & _mask;
00319 }
00320 
00321 template <class T, class LOCK, class K>
00322 w_hash_t<T,LOCK, K>&
00323 w_hash_t<T,LOCK, K>::push(T* t)
00324 {
00325     _tab[bucket_for(t)].push(t);
00326     ++_cnt;
00327     w_assert1(int(_cnt) > 0);
00328     return *this;
00329 }
00330 
00331 template <class T, class LOCK, class K>
00332 w_hash_t<T,LOCK, K>& w_hash_t<T,LOCK, K>::append(T* t)
00333 {
00334     _tab[bucket_for(t)].append(t);
00335     ++_cnt;
00336     w_assert1(int(_cnt) > 0);
00337     return *this;
00338 }
00339 
00340 template <class T, class LOCK, class K>
00341 T*
00342 w_hash_t<T,LOCK, K>::lookup(const K& k) const
00343 {
00344     w_list_t<T,LOCK>& list = _tab[bucket_for(k)];
00345     w_list_i<T,LOCK> i( list );
00346     register T* t;
00347     int4_t count;
00348     for (count = 0; (t = i.next()) && ! (_keyof(*t) == k); ++count) ;
00349     /* FRJ: disable move-to-front because (a) it's expensive and (b)
00350        lists should be short and (c) read-only operations can't go in
00351        parallel if they insist on messing with the data structure
00352      */
00353     if (0 && t && count) {
00354         w_link_t& link = _linkof(*t);
00355         link.detach();
00356         list.push(t);
00357     }
00358         
00359     return t;
00360 }
00361 template <class T, class LOCK, class K>
00362 bool
00363 w_hash_t<T,LOCK, K>::member(T const* t) const
00364 {
00365     w_list_base_t* list = &_tab[bucket_for(t)];
00366     return t->link.member_of() == list;
00367 }
00368 
00369 template <class T, class LOCK, class K>
00370 T*
00371 w_hash_t<T,LOCK, K>::remove(const K& k)
00372 {
00373     w_list_i<T,LOCK> i(_tab[bucket_for(k)]);
00374     while (i.next() && ! (_keyof(*i.curr()) == k)) ;
00375 
00376     T *tmp = i.curr();
00377     if (tmp) {
00378         --_cnt;
00379         w_assert1(int(_cnt) >= 0);
00380         _linkof(*tmp).detach();
00381     }
00382     return tmp;
00383 }
00384 
00385 template <class T, class LOCK, class K>
00386 void
00387 w_hash_t<T,LOCK, K>::remove(T* t)
00388 {
00389     w_assert1(_linkof(*t).member_of() ==
00390               &_tab[bucket_for(t)]);
00391     _linkof(*t).detach();
00392     --_cnt;
00393     w_assert1(int(_cnt) >= 0);
00394 }
00395 
00396 template <class T, class LOCK, class K>
00397 T* w_hash_i<T,LOCK, K>::next()
00398 {
00399     if (_bkt == uint4_max)  {
00400         _bkt = 0;
00401         _iter.reset(_htab._tab[_bkt++]);
00402     }
00403 
00404     if (! _iter.next())  {
00405         while (_bkt < _htab._top)  {
00406             
00407             _iter.reset( _htab._tab[ _bkt++ ] );
00408             if (_iter.next())  break;
00409         }
00410     }
00411     return _iter.curr();
00412 }
00413 
00414 /*<std-footer incl-file-exclusion='W_HASH_H'>  -- do not edit anything below this line -- */
00415 
00416 #endif          /*</std-footer>*/

Generated on Wed Oct 27 08:48:36 2010 for Shore Storage Manager by  doxygen 1.4.7