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.38 2010/10/27 17:04:22 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 template <class T, class LOCK, class K> class w_hash_t;
00068 template <class T, class LOCK, class K> class w_hash_i;
00069 
00070 BIND_FRIEND_OPERATOR_PART_1B(T,LOCK,K,w_hash_t<T,LOCK,K>)
00071 
00072 
00073 /**\brief Templated hash table. Not particularly sophisticated.
00074  *
00075  * The hash function used here is :
00076  * - w_hash(key) & _mask
00077  *
00078  * Thus, to make this work, your key type needs to be a class containing
00079  * a public method 
00080  * w_base_t::uint4_t hash() const;
00081  * (This is somewhat inconvenient if you want the key to be an atomic type,
00082  * but it's a lot easier to find locate the hash functions this way and
00083  * we don't have to worry about any implicit construction of types by
00084  * the compiler this way.)
00085  *
00086  * Note that since the hash function uses the _mask to collect the lower
00087  * bits of the result of w_hash, the key.hash() function should be sensitive
00088  * to the way hash-table uses it, and the hash tables 
00089  * should be aware of the likely bit distribution
00090  * of the result of key.hash().
00091  *
00092  */
00093 template <class T, class LOCK, class K>
00094 class w_hash_t : public w_base_t {
00095 public:
00096     /**\brief Construct hash table 
00097      * @param[in] sz Number of bits in result values. 
00098      * @param[in] key_offset Offset in object of type T where key K is found
00099      * @param[in] link_offset Offset in object of type T where w_link_t is found
00100      *            This w_link_t is used to hold the object in a hash table bucket
00101      * @param[in] lock Pointer to a lock used to protect the table.
00102      *
00103      * The size determines a mask used to restrict the resulting 
00104      * hash values to a desired size.
00105      *
00106      * The lock passed in is not used.  There is no enforcement of
00107      * locking these structures. The template contains the lock type
00108      * so that it is relatively easy to tell what structures are
00109      * unprotected by perusing the code.
00110      *
00111      * See \ref #W_HASH_ARG(class,key,link)
00112      */
00113     NORET                        w_hash_t(
00114         uint4_t                     sz,
00115         uint4_t                     key_offset,
00116         uint4_t                     link_offset,
00117         const LOCK *                lock);
00118     NORET                        ~w_hash_t();
00119 
00120 private:
00121     uint4_t                     bucket_for(K const &k) const;
00122     uint4_t                     bucket_for(T const *t) const;
00123 
00124 public:
00125     /// Insert an element in the table at the front of its bucket.
00126     w_hash_t&                   push(T* t);
00127     /// Insert an element in the table at the tail of its bucket.
00128     w_hash_t&                   append(T* t);
00129     /// Find an element in the table.
00130     T*                          lookup(const K& k) const;
00131     /// True if element is in the table.
00132     bool                        member(T const *t) const;
00133     /// Remove the (single) element with the given key 
00134     T*                          remove(const K& k);
00135     /// Remove the given element that is in the table.
00136     void                        remove(T* t);
00137     /// Total number of elements in the table.
00138     uint4_t                     num_members() const { return _cnt; }
00139 
00140     /// Standard ostream operator, despite the macro here (in \ref w_workaround.h)
00141     friend ostream&             operator<< 
00142                                      BIND_FRIEND_OPERATOR_PART_2B(T,LOCK,K) (
00143         ostream&                     o,
00144         const w_hash_t<T,LOCK,K>&        obj);
00145     
00146 
00147 private:
00148     friend class w_hash_i<T,LOCK,K>;
00149     uint4_t                        _top;
00150     uint4_t                        _mask;
00151     uint4_t                        _cnt;
00152     uint4_t                        _key_offset;
00153     uint4_t                        _link_offset;
00154     w_list_t<T, LOCK>*             _tab;
00155 
00156     const K&                       _keyof(const T& t) const  {
00157         return * (K*) (((const char*)&t) + _key_offset);
00158     }
00159     w_link_t&                       _linkof(T& t) const  {
00160         return * (w_link_t*) (((char*)&t) + _link_offset);
00161     }
00162 
00163     // disabled
00164     NORET                           w_hash_t(const w_hash_t&)
00165     ;
00166     w_hash_t&                       operator=(const w_hash_t&)
00167     ;
00168 };
00169 
00170 // XXX They are the same for now, avoids offsetof duplication
00171 /**\def W_HASH_ARG(class,key,link)
00172  * \brief Idiom for creating constructor argument for \ref #w_hash_t.
00173  *
00174  * This macro produces the last two arguments of the w_hash_t constructor.
00175  * Example :
00176  * \code
00177  * class key_t;
00178  * class entry_t {
00179  *    ...
00180  *    public:
00181  *       key_t    hashkey;
00182  *       w_link_t hashlink;
00183  * };
00184  *
00185  * w_hash_t<entry_t,key_t>(16, W_HASH_ARG(entry_t,hashkey,hashlink)) hashtable;
00186  * \endcode
00187  *
00188  */
00189 #define        W_HASH_ARG(class,key,link)  W_KEYED_ARG(class, key, link)
00190 
00191 
00192 /**\brief Iterate over hash table (for debugging)
00193  *
00194  * \note Not for general use.  Helper for w_hash_t,
00195  * and useful for writing debugging / dump-table code.
00196  *
00197  * Example:
00198  * \code
00199  * w_hash_t<entry_t,key_t>(16, W_HASH_ARG(entry_t,hashkey,hashlink)) hashtable;
00200  *
00201  * w_hash_i<entry_t,key_t> iter(hashtable);
00202  * entry_t *entry = NULL;
00203  * while( ( entry = iter.next()) != NULL) {
00204  *    ...
00205  * }
00206  * \endcode
00207  *
00208  * Since the w_hash_t is built of w_list_t, the same comments go for
00209  * next() and curr() here.  You can remove items from the table in
00210  * an iteration but you cannot insert.
00211  */
00212 template <class T, class LOCK, class K>
00213 class w_hash_i : public w_base_t {
00214 public:
00215     NORET           w_hash_i(const w_hash_t<T,LOCK, K>& t) : _bkt(uint4_max), 
00216                                                     _htab(t) {};
00217         
00218     NORET           ~w_hash_i()        {};
00219     
00220     T*              next();
00221     T*              curr()                { return _iter.curr(); }
00222 
00223 private:
00224     uint4_t                   _bkt;
00225     w_list_i<T,LOCK>         _iter;
00226     const w_hash_t<T,LOCK, K>&     _htab;
00227     
00228     NORET           w_hash_i(w_hash_i&);
00229 
00230     w_hash_i&       operator=(w_hash_i&)
00231     ;
00232 };
00233 
00234 
00235 template <class T, class LOCK, class K>
00236 ostream& operator<<(
00237     ostream&                        o,
00238     const w_hash_t<T,LOCK, K>&        h)
00239 {
00240     for (int i = 0; i < h._top; i++)  {
00241         o << '[' << i << "] ";
00242         w_list_i<T,LOCK> iter(h._tab[i]);
00243         while (iter.next())  {
00244             o << h._keyof(*iter.curr()) << " ";
00245         }
00246         o << endl;
00247     }
00248     return o;
00249 }
00250 
00251 /**\cond skip */
00252 template <class T, class LOCK, class K>
00253 NORET
00254 w_hash_t<T,LOCK, K>::w_hash_t(
00255     w_base_t::uint4_t        sz,
00256     w_base_t::uint4_t        key_offset,
00257     w_base_t::uint4_t        link_offset,
00258     const LOCK *)
00259 : _top(0), _cnt(0), _key_offset(key_offset),
00260   _link_offset(link_offset), _tab(0)
00261 {
00262     for (_top = 1; _top < sz; _top <<= 1) ;
00263     _mask = _top - 1;
00264     
00265     w_assert1(!_tab); // just to check space
00266     _tab = new w_list_t<T,LOCK>[_top];
00267     w_assert1(_tab);
00268     for (unsigned i = 0; i < _top; i++)  {
00269         _tab[i].set_offset(_link_offset);
00270     }
00271 }
00272 
00273 template <class T, class LOCK, class K>
00274 NORET
00275 w_hash_t<T,LOCK, K>::~w_hash_t()
00276 {
00277     w_assert1(_cnt == 0);
00278     delete[] _tab;
00279 }
00280 /**\endcond skip */
00281 
00282 template<class T, class LOCK, class K>
00283 w_base_t::uint4_t w_hash_t<T,LOCK, K>::bucket_for(T const* t) const {
00284     return bucket_for(_keyof(*t));
00285 }
00286 
00287 template<class T, class LOCK, class K>
00288 w_base_t::uint4_t w_hash_t<T,LOCK, K>::bucket_for(K const &k) const {
00289     return k.hash() & _mask;
00290 }
00291 
00292 template <class T, class LOCK, class K>
00293 w_hash_t<T,LOCK, K>&
00294 w_hash_t<T,LOCK, K>::push(T* t)
00295 {
00296     _tab[bucket_for(t)].push(t);
00297     ++_cnt;
00298     w_assert1(int(_cnt) > 0);
00299     return *this;
00300 }
00301 
00302 template <class T, class LOCK, class K>
00303 w_hash_t<T,LOCK, K>& w_hash_t<T,LOCK, K>::append(T* t)
00304 {
00305     _tab[bucket_for(t)].append(t);
00306     ++_cnt;
00307     w_assert1(int(_cnt) > 0);
00308     return *this;
00309 }
00310 
00311 template <class T, class LOCK, class K>
00312 T*
00313 w_hash_t<T,LOCK, K>::lookup(const K& k) const
00314 {
00315     w_list_t<T,LOCK>& list = _tab[bucket_for(k)];
00316     w_list_i<T,LOCK> i( list );
00317     register T* t;
00318     int4_t count;
00319     for (count = 0; (t = i.next()) && ! (_keyof(*t) == k); ++count) ;
00320     /* FRJ: disable move-to-front because (a) it's expensive and (b)
00321        lists should be short and (c) read-only operations can't go in
00322        parallel if they insist on messing with the data structure
00323      */
00324     if (0 && t && count) {
00325         w_link_t& link = _linkof(*t);
00326         link.detach();
00327         list.push(t);
00328     }
00329         
00330     return t;
00331 }
00332 template <class T, class LOCK, class K>
00333 bool
00334 w_hash_t<T,LOCK, K>::member(T const* t) const
00335 {
00336     w_list_base_t* list = &_tab[bucket_for(t)];
00337     return t->link.member_of() == list;
00338 }
00339 
00340 template <class T, class LOCK, class K>
00341 T*
00342 w_hash_t<T,LOCK, K>::remove(const K& k)
00343 {
00344     w_list_i<T,LOCK> i(_tab[bucket_for(k)]);
00345     while (i.next() && ! (_keyof(*i.curr()) == k)) ;
00346 
00347     T *tmp = i.curr();
00348     if (tmp) {
00349         --_cnt;
00350         w_assert1(int(_cnt) >= 0);
00351         _linkof(*tmp).detach();
00352     }
00353     return tmp;
00354 }
00355 
00356 template <class T, class LOCK, class K>
00357 void
00358 w_hash_t<T,LOCK, K>::remove(T* t)
00359 {
00360     w_assert1(_linkof(*t).member_of() ==
00361               &_tab[bucket_for(t)]);
00362     _linkof(*t).detach();
00363     --_cnt;
00364     w_assert1(int(_cnt) >= 0);
00365 }
00366 
00367 template <class T, class LOCK, class K>
00368 T* w_hash_i<T,LOCK, K>::next()
00369 {
00370     if (_bkt == uint4_max)  {
00371         _bkt = 0;
00372         _iter.reset(_htab._tab[_bkt++]);
00373     }
00374 
00375     if (! _iter.next())  {
00376         while (_bkt < _htab._top)  {
00377             
00378             _iter.reset( _htab._tab[ _bkt++ ] );
00379             if (_iter.next())  break;
00380         }
00381     }
00382     return _iter.curr();
00383 }
00384 
00385 /*<std-footer incl-file-exclusion='W_HASH_H'>  -- do not edit anything below this line -- */
00386 
00387 #endif          /*</std-footer>*/

Generated on Thu Dec 9 08:42:27 2010 for Shore Storage Manager by  doxygen 1.4.7