• Main Page
  • Related Pages
  • Namespaces
  • Data Structures
  • Files
  • File List
  • Globals

Map.h

Go to the documentation of this file.
00001 /** @file
00002 
00003   A set of Map templates.
00004 
00005   @section license License
00006 
00007   Licensed to the Apache Software Foundation (ASF) under one
00008   or more contributor license agreements.  See the NOTICE file
00009   distributed with this work for additional information
00010   regarding copyright ownership.  The ASF licenses this file
00011   to you under the Apache License, Version 2.0 (the
00012   "License"); you may not use this file except in compliance
00013   with the License.  You may obtain a copy of the License at
00014 
00015       http://www.apache.org/licenses/LICENSE-2.0
00016 
00017   Unless required by applicable law or agreed to in writing, software
00018   distributed under the License is distributed on an "AS IS" BASIS,
00019   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00020   See the License for the specific language governing permissions and
00021   limitations under the License.
00022 */
00023 
00024 #ifndef _map_H_
00025 #define _map_H_
00026 
00027 #include <stdlib.h>
00028 #include <string.h>
00029 #include "ink_assert.h"
00030 #include "List.h"
00031 #include "Vec.h"
00032 
00033 #define MAP_INTEGRAL_SIZE               (1 << (2))
00034 //#define MAP_INITIAL_SHIFT               ((2)+1)
00035 //#define MAP_INITIAL_SIZE                (1 << MAP_INITIAL_SHIFT)
00036 
00037 typedef const char cchar;
00038 
00039 template<class A>
00040 static inline char *
00041 _dupstr(cchar *s, cchar *e = 0) {
00042   int l = e ? e-s : strlen(s);
00043   char *ss = (char*)A::alloc(l+1);
00044   memcpy(ss, s, l);
00045   ss[l] = 0;
00046   return ss;
00047 }
00048 
00049 // Simple direct mapped Map (pointer hash table) and Environment
00050 
00051 template <class K, class C> class MapElem {
00052  public:
00053   K     key;
00054   C     value;
00055   bool operator==(MapElem &e) { return e.key == key; }
00056   operator uintptr_t(void) { return (uintptr_t)(uintptr_t)key; }
00057   MapElem(uintptr_t x) { ink_assert(!x); key = 0; }
00058   MapElem(K akey, C avalue) : key(akey), value(avalue) {}
00059   MapElem(MapElem &e) : key(e.key), value(e.value) {}
00060   MapElem() : key(0) {}
00061 };
00062 
00063 template <class K, class C, class A = DefaultAlloc> class Map : public Vec<MapElem<K,C>, A> {
00064  public:
00065   typedef MapElem<K,C> ME;
00066   typedef Vec<ME,A> PType;
00067   using PType::n;
00068   using PType::i;
00069   using PType::v;
00070   ME *put(K akey, C avalue);
00071   ME *put(K akey);
00072   C get(K akey);
00073   C *getp(K akey);
00074   void get_keys(Vec<K> &keys);
00075   void get_keys_set(Vec<K> &keys);
00076   void get_values(Vec<C> &values);
00077   void map_union(Map<K,C> &m);
00078   bool some_disjunction(Map<K,C> &m) const;
00079 };
00080 
00081 template <class C> class HashFns {
00082  public:
00083   static uintptr_t hash(C a);
00084   static int equal(C a, C b);
00085 };
00086 
00087 template <class K, class C> class HashSetFns {
00088  public:
00089   static uintptr_t hash(C a);
00090   static uintptr_t hash(K a);
00091   static int equal(C a, C b);
00092   static int equal(K a, C b);
00093 };
00094 
00095 template <class K, class AHashFns, class C, class A = DefaultAlloc> class HashMap : public Map<K,C,A> {
00096  public:
00097   typedef MapElem<K,C> value_type; ///< What's stored in the table.
00098   using Map<K,C,A>::n;
00099   using Map<K,C,A>::i;
00100   using Map<K,C,A>::v;
00101   using Map<K,C,A>::e;
00102   MapElem<K,C> *get_internal(K akey);
00103   C get(K akey);
00104   value_type* put(K akey, C avalue);
00105   void get_keys(Vec<K> &keys);
00106   void get_values(Vec<C> &values);
00107 };
00108 
00109 #define form_Map(_c, _p, _v) if ((_v).n) for (_c *qq__##_p = (_c*)0, *_p = &(_v).v[0]; \
00110              ((uintptr_t)(qq__##_p) < (_v).n) && ((_p = &(_v).v[(uintptr_t)qq__##_p]) || 1); \
00111              qq__##_p = (_c*)(((uintptr_t)qq__##_p) + 1)) \
00112           if ((_p)->key)
00113 
00114 
00115 template <class K, class AHashFns, class C, class A = DefaultAlloc> class HashSet : public Vec<C,A> {
00116  public:
00117   typedef Vec<C,A> V;
00118   using V::n;
00119   using V::i;
00120   using V::v;
00121   using V::e;
00122   C get(K akey);
00123   C *put( C avalue);
00124 };
00125 
00126 class StringHashFns {
00127  public:
00128   static uintptr_t hash(cchar *s) { 
00129     uintptr_t h = 0; 
00130     // 31 changed to 27, to avoid prime2 in vec.cpp
00131     while (*s) h = h * 27 + (unsigned char)*s++;  
00132     return h;
00133   }
00134   static int equal(cchar *a, cchar *b) { return !strcmp(a, b); }
00135 };
00136 
00137 class CaseStringHashFns {
00138  public:
00139   static uintptr_t hash(cchar *s) { 
00140     uintptr_t h = 0; 
00141     // 31 changed to 27, to avoid prime2 in vec.cpp
00142     while (*s) h = h * 27 + (unsigned char)toupper(*s++);
00143     return h;
00144   }
00145   static int equal(cchar *a, cchar *b) { return !strcasecmp(a, b); }
00146 };
00147 
00148 class PointerHashFns {
00149  public:
00150   static uintptr_t hash(void *s) { return (uintptr_t)(uintptr_t)s; }
00151   static int equal(void *a, void *b) { return a == b; }
00152 };
00153 
00154 template <class C, class AHashFns, class A = DefaultAlloc> class ChainHash : public Map<uintptr_t, List<C,A>,A> {
00155  public:
00156   using Map<uintptr_t, List<C,A>,A>::n;
00157   using Map<uintptr_t, List<C,A>,A>::v;
00158   typedef ConsCell<C, A> ChainCons;
00159   C put(C c);
00160   C get(C c);
00161   C put_bag(C c);
00162   int get_bag(C c,Vec<C> &v);
00163   int del(C avalue);
00164   void get_elements(Vec<C> &elements);
00165 };
00166 
00167 template <class K, class AHashFns, class C, class A = DefaultAlloc> class ChainHashMap : 
00168   public Map<uintptr_t, List<MapElem<K,C>,A>,A> {
00169  public:
00170   using Map<uintptr_t, List<MapElem<K,C>,A>,A>::n;
00171   using Map<uintptr_t, List<MapElem<K,C>,A>,A>::v;
00172   MapElem<K,C> *put(K akey, C avalue);
00173   C get(K akey);
00174   int del(K akey);
00175   MapElem<K,C> *put_bag(K akey, C c);
00176   int get_bag(K akey, Vec<C> &v);
00177   void get_keys(Vec<K> &keys);
00178   void get_values(Vec<C> &values);
00179 };
00180 
00181 template<class F = StringHashFns, class A = DefaultAlloc>
00182 class StringChainHash : public ChainHash<cchar *, F, A> {
00183  public:
00184   cchar *canonicalize(cchar *s, cchar *e);
00185   cchar *canonicalize(cchar *s) { return canonicalize(s, s + strlen(s)); }
00186 };
00187 
00188 template <class C, class AHashFns, int N, class A = DefaultAlloc> class NBlockHash {
00189  public:
00190   int n;
00191   int i;
00192   C *v;
00193   C e[N];
00194 
00195   C* end() { return last(); }
00196   int length() { return N * n; }
00197   C *first();
00198   C *last();
00199   C put(C c);
00200   C get(C c);
00201   C* assoc_put(C *c);
00202   C* assoc_get(C *c);
00203   int del(C c);
00204   void clear();
00205   void reset();
00206   int count();
00207   void size(int p2);
00208   void copy(const NBlockHash<C,AHashFns,N,A> &hh);
00209   void move(NBlockHash<C,AHashFns,N,A> &hh);
00210   NBlockHash();
00211   NBlockHash(NBlockHash<C,AHashFns,N,A> &hh) { v = e; copy(hh); }
00212 };
00213 
00214 /* use forv_Vec on BlockHashes */
00215 
00216 #define DEFAULT_BLOCK_HASH_SIZE 4
00217 template <class C, class ABlockHashFns> class BlockHash : 
00218   public NBlockHash<C, ABlockHashFns, DEFAULT_BLOCK_HASH_SIZE> {};
00219 typedef BlockHash<cchar *, StringHashFns> StringBlockHash;
00220 
00221 template <class K, class C, class A = DefaultAlloc> class Env {
00222  public:
00223   typedef ConsCell<C, A> EnvCons;
00224   void put(K akey, C avalue);
00225   C get(K akey);
00226   void push();
00227   void pop();
00228   void clear() { store.clear(); scope.clear(); }
00229 
00230   Env() {}
00231   Map<K,List<C> *, A> store;
00232   List<List<K>, A> scope;
00233   List<C, A> *get_bucket(K akey);
00234 };
00235 
00236 /* IMPLEMENTATION */
00237 
00238 template <class K, class C, class A> inline C 
00239 Map<K,C,A>::get(K akey) {
00240   MapElem<K,C> e(akey, (C)0);
00241   MapElem<K,C> *x = this->set_in(e);
00242   if (x)
00243     return x->value;
00244   return (C)0;
00245 }
00246 
00247 template <class K, class C, class A> inline C *
00248 Map<K,C,A>::getp(K akey) {
00249   MapElem<K,C> e(akey, (C)0);
00250   MapElem<K,C> *x = this->set_in(e);
00251   if (x)
00252     return &x->value;
00253   return 0;
00254 }
00255 
00256 template <class K, class C, class A> inline MapElem<K,C> *
00257 Map<K,C,A>::put(K akey, C avalue) {
00258   MapElem<K,C> e(akey, avalue);
00259   MapElem<K,C> *x = this->set_in(e);
00260   if (x) {
00261     x->value = avalue;
00262     return x;
00263   } else
00264     return this->set_add(e);
00265 }
00266 
00267 template <class K, class C, class A> inline MapElem<K,C> *
00268 Map<K,C,A>::put(K akey) {
00269   MapElem<K,C> e(akey, 0);
00270   MapElem<K,C> *x = this->set_in(e);
00271   if (x)
00272     return x;
00273   else
00274     return this->set_add(e);
00275 }
00276 
00277 template <class K, class C, class A> inline void
00278 Map<K,C,A>::get_keys(Vec<K> &keys) {
00279   for (int i = 0; i < n; i++)
00280     if (v[i].key)
00281       keys.add(v[i].key);
00282 }
00283 
00284 template <class K, class C, class A> inline void
00285 Map<K,C,A>::get_keys_set(Vec<K> &keys) {
00286   for (int i = 0; i < n; i++)
00287     if (v[i].key)
00288       keys.set_add(v[i].key);
00289 }
00290 
00291 template <class K, class C, class A> inline void
00292 Map<K,C,A>::get_values(Vec<C> &values) {
00293   for (int i = 0; i < n; i++)
00294     if (v[i].key)
00295       values.set_add(v[i].value);
00296   values.set_to_vec();
00297 }
00298 
00299 template <class K, class C, class A> inline void
00300 Map<K,C,A>::map_union(Map<K,C> &m) {
00301   for (int i = 0; i < m.n; i++)
00302     if (m.v[i].key)
00303       put(m.v[i].key, m.v[i].value);
00304 }
00305 
00306 template <class K, class C, class A> inline bool
00307 Map<K,C,A>::some_disjunction(Map<K,C> &m) const {
00308   for (size_t i = 0; i < m.n; i++) {
00309     if (m.v[i].key && get(m.v[i].key) != m.v[i].value) {
00310       return true;
00311     }
00312   }
00313   for (size_t i = 0; i < n; i++) {
00314     if (v[i].key && m.get(v[i].key) != v[i].value) {
00315       return true;
00316     }
00317   }
00318   return false;
00319 }
00320 
00321 template <class K, class C, class A> inline void
00322 map_set_add(Map<K,Vec<C,A>*,A> &m, K akey, C avalue) {
00323   Vec<C,A> *v = m.get(akey);
00324   if (!v)
00325     m.put(akey, (v = new Vec<C,A>));
00326   v->set_add(avalue);
00327 }
00328 
00329 template <class K, class C, class A> inline void
00330 map_set_add(Map<K,Vec<C,A>*,A> &m, K akey, Vec<C> *madd) {
00331   Vec<C,A> *v = m.get(akey);
00332   if (!v)
00333     m.put(akey, (v = new Vec<C,A>));
00334   v->set_union(*madd);
00335 }
00336 
00337 template <class K, class AHashFns, class C, class A> inline C
00338 HashSet<K, AHashFns, C, A>::get(K akey) {
00339   if (!n)
00340     return 0;
00341   if (n <= MAP_INTEGRAL_SIZE) {
00342     for (C *c = v; c < v + n; c++)
00343       if (c)
00344         if (AHashFns::equal(akey, *c))
00345           return *c;
00346     return 0;
00347   }
00348   uintptr_t h = AHashFns::hash(akey);
00349   h = h % n;
00350   for (int k = h, j = 0; j < i + 3;j++) {
00351     if (!v[k])
00352       return 0;
00353     else if (AHashFns::equal(akey, v[k]))
00354       return v[k];
00355     k = (k + open_hash_primes[j]) % n;
00356   }
00357   return 0;
00358 }
00359 
00360 template <class K, class AHashFns, class C, class A> inline C *
00361 HashSet<K, AHashFns, C, A>::put(C avalue) {
00362   if (n < MAP_INTEGRAL_SIZE) {
00363     if (!v)
00364       v = e;
00365     for (int i = 0; i < n; i++)
00366       if (AHashFns::equal(avalue, v[i]))
00367         return &v[i];
00368     v[n] = avalue;
00369     n++;
00370     return &v[n-1];
00371   }
00372   if (n > MAP_INTEGRAL_SIZE) {
00373     uintptr_t h = AHashFns::hash(avalue);
00374     h = h % n;
00375     for (int k = h, j = 0; j < i + 3; j++) {
00376       if (!v[k]) {
00377         v[k] = avalue;
00378         return &v[k];
00379       }
00380       k = (k + open_hash_primes[j]) % n;
00381     }
00382   } else
00383     i = SET_INITIAL_INDEX-1; // will be incremented in set_expand
00384   HashSet<K,AHashFns,C,A> vv(*this);
00385   Vec<C,A>::set_expand();
00386   for (int i = 0; i < vv.n; i++)
00387     if (vv.v[i])
00388       put(vv.v[i]);
00389   return put(avalue);
00390 }
00391 
00392 template <class K, class AHashFns, class C, class A> inline MapElem<K,C> * 
00393 HashMap<K,AHashFns,C,A>::get_internal(K akey) {
00394   if (!n)
00395     return 0;
00396   if (n <= MAP_INTEGRAL_SIZE) {
00397     for (MapElem<K,C> *c = v; c < v + n; c++)
00398       if (c->key)
00399         if (AHashFns::equal(akey, c->key))
00400           return c;
00401     return 0;
00402   }
00403   uintptr_t h = AHashFns::hash(akey);
00404   h = h % n;
00405   for (size_t k = h, j = 0; j < i + 3;j++) {
00406     if (!v[k].key)
00407       return 0;
00408     else if (AHashFns::equal(akey, v[k].key))
00409       return &v[k];
00410     k = (k + open_hash_primes[j]) % n;
00411   }
00412   return 0;
00413 }
00414 
00415 template <class K, class AHashFns, class C, class A> inline C 
00416 HashMap<K,AHashFns,C,A>::get(K akey) {
00417   MapElem<K,C> *x = get_internal(akey);
00418   if (!x)
00419     return 0;
00420   return x->value;
00421 }
00422 
00423 template <class K, class AHashFns, class C, class A> inline MapElem<K,C> *
00424 HashMap<K,AHashFns,C,A>::put(K akey, C avalue) {
00425   MapElem<K,C> *x = get_internal(akey);
00426   if (x) {
00427     x->value = avalue;
00428     return x;
00429   } else {
00430     if (n < MAP_INTEGRAL_SIZE) {
00431       if (!v)
00432         v = e;
00433       v[n].key = akey;
00434       v[n].value = avalue;
00435       n++;
00436       return &v[n-1];
00437     }
00438     if (n > MAP_INTEGRAL_SIZE) {
00439       uintptr_t h = AHashFns::hash(akey);
00440       h = h % n;
00441       for (size_t k = h, j = 0; j < i + 3; j++) {
00442         if (!v[k].key) {
00443           v[k].key = akey;
00444           v[k].value = avalue;
00445           return &v[k];
00446         }
00447         k = (k + open_hash_primes[j]) % n;
00448       }
00449     } else
00450       i = SET_INITIAL_INDEX-1; // will be incremented in set_expand
00451   }
00452   HashMap<K,AHashFns,C,A> vv(*this);
00453   Map<K,C,A>::set_expand();
00454   for (size_t i = 0; i < vv.n; i++)
00455     if (vv.v[i].key)
00456       put(vv.v[i].key, vv.v[i].value);
00457   return put(akey, avalue);
00458 }
00459 
00460 template <class K, class AHashFns, class C, class A> inline void
00461 HashMap<K,AHashFns,C,A>::get_keys(Vec<K> &keys) { Map<K,C,A>::get_keys(keys); }
00462 
00463 template <class K, class AHashFns, class C, class A> inline void
00464 HashMap<K,AHashFns,C,A>::get_values(Vec<C> &values) { Map<K,C,A>::get_values(values); }
00465 
00466 template <class C, class AHashFns, class A> C
00467 ChainHash<C, AHashFns, A>::put(C c) {
00468   uintptr_t h = AHashFns::hash(c);
00469   List<C,A> *l;
00470   MapElem<uintptr_t,List<C,A> > e(h, (C)0);
00471   MapElem<uintptr_t,List<C,A> > *x = this->set_in(e);
00472   if (x)
00473     l = &x->value;
00474   else {
00475     l = &Map<uintptr_t, List<C,A>, A>::put(h, c)->value;
00476     return l->head->car;
00477   }
00478   forc_List(ChainCons, x, *l)
00479     if (AHashFns::equal(c, x->car))
00480       return x->car;
00481   l->push(c);
00482   return (C)0;
00483 }
00484 
00485 template <class C, class AHashFns, class A> C
00486 ChainHash<C, AHashFns, A>::get(C c) {
00487   uintptr_t h = AHashFns::hash(c);
00488   List<C> empty;
00489   MapElem<uintptr_t,List<C,A> > e(h, empty);
00490   MapElem<uintptr_t,List<C,A> > *x = this->set_in(e);
00491   if (!x)
00492     return 0;
00493   List<C> *l = &x->value;
00494   forc_List(ChainCons, x, *l)
00495     if (AHashFns::equal(c, x->car))
00496       return x->car;
00497   return 0;
00498 }
00499 
00500 template <class C, class AHashFns, class A> C
00501 ChainHash<C, AHashFns, A>::put_bag(C c) {
00502   uintptr_t h = AHashFns::hash(c);
00503   List<C, A> *l;
00504   MapElem<uintptr_t,List<C,A> > e(h, (C)0);
00505   MapElem<uintptr_t,List<C,A> > *x = this->set_in(e);
00506   if (x)
00507     l = &x->value;
00508   else {
00509     l = &Map<uintptr_t, List<C,A> >::put(h, c)->value;
00510     return l->head->car;
00511   }
00512   l->push(c);
00513   return (C)0;
00514 }
00515 
00516 template <class C, class AHashFns, class A> int
00517 ChainHash<C, AHashFns, A>::get_bag(C c, Vec<C> &v) {
00518   uintptr_t h = AHashFns::hash(c);
00519   List<C,A> empty;
00520   MapElem<uintptr_t,List<C,A> > e(h, empty);
00521   MapElem<uintptr_t,List<C,A> > *x = this->set_in(e);
00522   if (!x)
00523     return 0;
00524   List<C,A> *l = &x->value;
00525   forc_List(C, x, *l)
00526     if (AHashFns::equal(c, x->car))
00527       v.add(x->car);
00528   return v.n;
00529 }
00530 
00531 template <class C, class AHashFns, class A> void
00532 ChainHash<C, AHashFns, A>::get_elements(Vec<C> &elements) {
00533   for (int i = 0; i < n; i++) {
00534     List<C, A> *l = &v[i].value;
00535     forc_List(C, x, *l)
00536       elements.add(x);
00537   }
00538 }
00539 
00540 template <class C, class AHashFns, class A> int
00541 ChainHash<C, AHashFns, A>::del(C c) {
00542   uintptr_t h = AHashFns::hash(c);
00543   List<C> *l;
00544   MapElem<uintptr_t,List<C,A> > e(h, (C)0);
00545   MapElem<uintptr_t,List<C,A> > *x = this->set_in(e);
00546   if (x)
00547     l = &x->value;
00548   else
00549     return 0;
00550   ConsCell<C> *last = 0;
00551   forc_List(ConsCell<C>, x, *l) {
00552     if (AHashFns::equal(c, x->car)) {
00553       if (!last)
00554         l->head = x->cdr;
00555       else
00556         last->cdr = x->cdr;
00557       A::free(x);
00558       return 1;
00559     }
00560     last = x;
00561   }
00562   return 0;
00563 }
00564 
00565 template <class K, class AHashFns, class C, class A>  MapElem<K,C> *
00566 ChainHashMap<K, AHashFns, C, A>::put(K akey, C avalue) {
00567   uintptr_t h = AHashFns::hash(akey);
00568   List<MapElem<K,C>,A> empty;
00569   List<MapElem<K,C>,A> *l;
00570   MapElem<K, C> c(akey, avalue);
00571   MapElem<uintptr_t,List<MapElem<K,C>,A> > e(h, empty);
00572   MapElem<uintptr_t,List<MapElem<K,C>,A> > *x = this->set_in(e);
00573   if (x)
00574     l = &x->value;
00575   else {
00576     l = &Map<uintptr_t, List<MapElem<K,C>,A>,A>::put(h, c)->value;
00577     return &l->head->car;
00578   }
00579   for (ConsCell<MapElem<K,C>,A> *p  = l->head; p; p = p->cdr)
00580     if (AHashFns::equal(akey, p->car.key)) {
00581       p->car.value = avalue;
00582       return &p->car;
00583     }
00584   l->push(c);
00585   return 0;
00586 }
00587 
00588 template <class K, class AHashFns, class C, class A> C
00589 ChainHashMap<K, AHashFns, C, A>::get(K akey) {
00590   uintptr_t h = AHashFns::hash(akey);
00591   List<MapElem<K,C>, A> empty;
00592   MapElem<uintptr_t,List<MapElem<K,C>,A> > e(h, empty);
00593   MapElem<uintptr_t,List<MapElem<K,C>,A> > *x = this->set_in(e);
00594   if (!x)
00595     return 0;
00596   List<MapElem<K,C>,A> *l = &x->value;
00597   if (l->head) 
00598     for (ConsCell<MapElem<K,C>,A> *p  = l->head; p; p = p->cdr)
00599       if (AHashFns::equal(akey, p->car.key))
00600         return p->car.value;
00601   return 0;
00602 }
00603 
00604 template <class K, class AHashFns, class C, class A> MapElem<K,C> *
00605 ChainHashMap<K, AHashFns, C, A>::put_bag(K akey, C avalue) {
00606   uintptr_t h = AHashFns::hash(akey);
00607   List<MapElem<K,C>,A> empty;
00608   List<MapElem<K,C>,A> *l;
00609   MapElem<K, C> c(akey, avalue);
00610   MapElem<uintptr_t,List<MapElem<K,C>,A> > e(h, empty);
00611   MapElem<uintptr_t,List<MapElem<K,C>,A> > *x = this->set_in(e);
00612   if (x)
00613     l = &x->value;
00614   else {
00615     l = &Map<uintptr_t, List<MapElem<K,C>,A>,A>::put(h, c)->value;
00616     return &l->head->car;
00617   }
00618   for (ConsCell<MapElem<K,C>,A> *p  = l->head; p; p = p->cdr)
00619     if (AHashFns::equal(akey, p->car.key) && AHashFns::equal_value(avalue, p->car.value))
00620       return &p->car;
00621   l->push(c);
00622   return 0;
00623 }
00624 
00625 template <class K, class AHashFns, class C, class A> int
00626 ChainHashMap<K, AHashFns, C, A>::get_bag(K akey, Vec<C> &v) {
00627   uintptr_t h = AHashFns::hash(akey);
00628   List<MapElem<K,C>,A> empty;
00629   MapElem<uintptr_t,List<MapElem<K,C>,A> > e(h, empty);
00630   MapElem<uintptr_t,List<MapElem<K,C>,A> > *x = this->set_in(e);
00631   if (!x)
00632     return 0;
00633   List<MapElem<K,C>,A> *l = &x->value;
00634   for (ConsCell<MapElem<K,C>,A> *p  = l->head; p; p = p->cdr)
00635     if (AHashFns::equal(akey, p->car.key))
00636       return v.add(x->car);
00637   return v.n;
00638 }
00639 
00640 template <class K, class AHashFns, class C, class A> int
00641 ChainHashMap<K, AHashFns, C, A>::del(K akey) {
00642   uintptr_t h = AHashFns::hash(akey);
00643   List<MapElem<K,C>,A> empty;
00644   List<MapElem<K,C>,A> *l;
00645   MapElem<uintptr_t,List<MapElem<K,C>,A> > e(h, empty);
00646   MapElem<uintptr_t,List<MapElem<K,C>,A> > *x = this->set_in(e);
00647   if (x)
00648     l = &x->value;
00649   else
00650     return 0;
00651   ConsCell<MapElem<K,C>,A> *last = 0;
00652   for (ConsCell<MapElem<K,C>,A> *p = l->head; p; p = p->cdr) {
00653     if (AHashFns::equal(akey, p->car.key)) {
00654       if (!last)
00655         l->head = p->cdr;
00656       else
00657         last->cdr = p->cdr;
00658       return 1;
00659     }
00660     last = p;
00661   }
00662   return 0;
00663 }
00664 
00665 template <class K, class AHashFns, class C, class A> void
00666 ChainHashMap<K, AHashFns, C, A>::get_keys(Vec<K> &keys) {
00667   for (size_t i = 0; i < n; i++) {
00668     List<MapElem<K,C> > *l = &v[i].value;
00669     if (l->head) 
00670       for (ConsCell<MapElem<K,C>,A> *p  = l->head; p; p = p->cdr)
00671         keys.add(p->car.key);
00672   }
00673 }
00674 
00675 template <class K, class AHashFns, class C, class A> void
00676 ChainHashMap<K, AHashFns, C, A>::get_values(Vec<C> &values) {
00677   for (size_t i = 0; i < n; i++) {
00678     List<MapElem<K,C>,A> *l = &v[i].value;
00679     if (l->head) 
00680       for (ConsCell<MapElem<K,C>,A> *p  = l->head; p; p = p->cdr)
00681         values.add(p->car.value);
00682   }
00683 }
00684 
00685 template <class F, class A> inline cchar *
00686 StringChainHash<F,A>::canonicalize(cchar *s, cchar *e) {
00687   uintptr_t h = 0;
00688   cchar *a = s;
00689   // 31 changed to 27, to avoid prime2 in vec.cpp
00690   if (e)
00691     while (a != e) h = h * 27 + (unsigned char)*a++;  
00692   else
00693     while (*a) h = h * 27 + (unsigned char)*a++;  
00694   MapElem<uintptr_t,List<cchar*, A> > me(h, (char*)0);
00695   MapElem<uintptr_t,List<cchar*, A> > *x = this->set_in(me);
00696   if (x) {
00697     List<cchar*, A> *l = &x->value;
00698     typedef ConsCell<cchar *, A> TT;
00699     forc_List(TT, x, *l) {
00700       a = s;
00701       cchar *b = x->car;
00702       while (1) {
00703         if (!*b) {
00704           if (a == e)
00705             return x->car;
00706           break;
00707         }
00708         if (a >= e || *a != *b)
00709           break;
00710         a++; b++;
00711       }
00712     }
00713   }
00714   s = _dupstr<A>(s, e);
00715   cchar *ss = ChainHash<cchar *, F, A>::put(s);
00716   if (ss)
00717     return ss;
00718   return s;
00719 }
00720 
00721 template <class K, class C, class A> inline C 
00722 Env<K,C,A>::get(K akey) {
00723   MapElem<K,List<C, A> *> e(akey, 0);
00724   MapElem<K,List<C, A> *> *x = store.set_in(e);
00725   if (x)
00726     return x->value->first();
00727   return (C)0;
00728 }
00729 
00730 template <class K, class C, class A> inline List<C, A> *
00731 Env<K,C,A>::get_bucket(K akey) {
00732   List<C, A> *bucket = store.get(akey);
00733   if (bucket)
00734     return bucket;
00735   bucket = new List<C>();
00736   store.put(akey, bucket);
00737   return bucket;
00738 }
00739 
00740 template <class K, class C, class A> inline void
00741 Env<K,C,A>::put(K akey, C avalue) {
00742   scope.head->car.push(akey);
00743   get_bucket(akey)->push(avalue);
00744 }
00745 
00746 template <class K, class C, class A> inline void
00747 Env<K,C,A>::push() {
00748   scope.push();
00749 }
00750 
00751 template <class K, class C, class A> inline void
00752 Env<K,C,A>::pop() {
00753   forc_List(EnvCons, e, scope.first())
00754     get_bucket(e->car)->pop();
00755 }
00756 
00757 template <class C, class AHashFns, int N, class A> inline 
00758 NBlockHash<C, AHashFns, N, A>::NBlockHash() : n(1), i(0) {
00759   memset(&e[0], 0, sizeof(e));
00760   v = e;
00761 }
00762 
00763 template <class C, class AHashFns, int N, class A> inline C*
00764 NBlockHash<C, AHashFns, N, A>::first() {
00765   return &v[0];
00766 }
00767 
00768 template <class C, class AHashFns, int N, class A> inline C*
00769 NBlockHash<C, AHashFns, N, A>::last() {
00770   return &v[n * N];
00771 }
00772 
00773 template <class C, class AHashFns, int N, class A> inline C
00774 NBlockHash<C, AHashFns, N, A>::put(C c) {
00775   int a;
00776   uintptr_t h = AHashFns::hash(c);
00777   C *x = &v[(h % n) * N];
00778   for (a = 0; a < N; a++) {
00779     if (!x[a])
00780       break;
00781     if (AHashFns::equal(c, x[a]))
00782       return x[a];
00783   }
00784   if (a < N) {
00785     x[a] = c;
00786     return (C)0;
00787   }
00788   C *vv = first(), *ve = last();
00789   C *old_v = v;
00790   i = i + 1;
00791   size(i);
00792   for (;vv < ve; vv++)
00793     if (*vv)
00794       put(*vv);
00795   if (old_v != &e[0])
00796     A::free(old_v);
00797   return put(c);
00798 }
00799 
00800 template <class C, class AHashFns, int N, class A> inline void
00801 NBlockHash<C, AHashFns, N, A>::size(int p2) {
00802   n = prime2[p2];
00803   v = (C*)A::alloc(n * sizeof(C) * N);
00804   memset(v, 0, n * sizeof(C) * N);
00805 }
00806 
00807 template <class C, class AHashFns, int N, class A> inline C
00808 NBlockHash<C, AHashFns, N, A>::get(C c) {
00809   if (!n)
00810     return (C)0;
00811   uintptr_t h = AHashFns::hash(c);
00812   C *x = &v[(h % n) * N];
00813   for (int a = 0; a < N; a++) {
00814     if (!x[a])
00815       return (C)0;
00816     if (AHashFns::equal(c, x[a]))
00817       return x[a];
00818   }
00819   return (C)0;
00820 }
00821 
00822 template <class C, class AHashFns, int N, class A> inline C*
00823 NBlockHash<C, AHashFns, N, A>::assoc_get(C *c) {
00824   if (!n)
00825     return (C*)0;
00826   uintptr_t h = AHashFns::hash(*c);
00827   C *x = &v[(h % n) * N];
00828   int a = 0;
00829   if (c >= x && c < x + N)
00830     a = c - x + 1;
00831   for (; a < N; a++) {
00832     if (!x[a])
00833       return (C*)0;
00834     if (AHashFns::equal(*c, x[a]))
00835       return &x[a];
00836   }
00837   return (C*)0;
00838 }
00839 
00840 template <class C, class AHashFns, int N, class A> inline C*
00841 NBlockHash<C, AHashFns, N, A>::assoc_put(C *c) {
00842   int a;
00843   uintptr_t h = AHashFns::hash(*c);
00844   C *x = &v[(h % n) * N];
00845   for (a = 0; a < N; a++) {
00846     if (!x[a])
00847       break;
00848   }
00849   if (a < N) {
00850     x[a] = *c;
00851     return  &x[a];
00852   }
00853   x[i % N] = *c;
00854   i++;
00855   return &x[i % N];
00856 }
00857 
00858 template <class C, class AHashFns, int N, class A> inline int
00859 NBlockHash<C, AHashFns, N, A>::del(C c) {
00860   int a, b;
00861   if (!n)
00862     return 0;
00863   uintptr_t h = AHashFns::hash(c);
00864   C *x = &v[(h % n) * N];
00865   for (a = 0; a < N; a++) {
00866     if (!x[a])
00867       return 0;
00868     if (AHashFns::equal(c, x[a])) {
00869       if (a < N - 1) {
00870         for (b = a + 1; b < N; b++) {
00871           if (!x[b])
00872             break;
00873         }
00874         if (b != a + 1)
00875           x[a] = x[b - 1];
00876         x[b - 1] = (C)0;
00877         return 1;
00878       } else {
00879         x[N - 1] = (C)0;
00880         return 1;
00881       }
00882     }
00883   }
00884   return 0;
00885 }
00886 
00887 template <class C, class AHashFns, int N, class A> inline void
00888 NBlockHash<C, AHashFns, N, A>::clear() {
00889   if (v && v != e) A::free(v);
00890   v = e;
00891   n = 1;
00892 }
00893 
00894 template <class C, class AHashFns, int N, class A> inline void
00895 NBlockHash<C, AHashFns, N, A>::reset() {
00896   if (v)
00897     memset(v, 0, n * N * sizeof(C));
00898 }
00899 
00900 template <class C, class AHashFns, int N, class A> inline int
00901 NBlockHash<C, AHashFns, N, A>::count() {
00902   int nelements = 0;
00903   C *l = last();
00904   for (C *xx = first(); xx < l; xx++) 
00905     if (*xx)
00906       nelements++;
00907   return nelements;
00908 }
00909 
00910 template <class C, class AHashFns, int N, class A> inline void 
00911 NBlockHash<C, AHashFns, N, A>::copy(const NBlockHash<C, AHashFns, N, A> &hh) {
00912   clear();
00913   n = hh.n;
00914   i = hh.i;
00915   if (hh.v == &hh.e[0]) { 
00916     memcpy(e, &hh.e[0], sizeof(e));
00917     v = e;
00918   } else {
00919     if (hh.v) {
00920       v = (C*)A::alloc(n * sizeof(C) * N);
00921       memcpy(v, hh.v, n * sizeof(C) * N);
00922     } else
00923       v = 0;
00924   }
00925 }
00926 
00927 template <class C, class AHashFns, int N, class A> inline void 
00928 NBlockHash<C, AHashFns, N, A>::move(NBlockHash<C, AHashFns, N, A> &hh) {
00929   clear();
00930   n = hh.n;
00931   i = hh.i;
00932   v = hh.v;
00933   if (hh.v == &hh.e[0]) { 
00934     memcpy(e, &hh.e[0], sizeof(e));
00935     v = e;
00936   }
00937   hh.clear();
00938 }
00939 
00940 void test_map();
00941 
00942 /* ---------------------------------------------------------------------------------------------- */
00943 /** A hash map usable by ATS core.
00944 
00945     This class depends on the @c DLL class from @c List.h. It assumes it can uses instances of that
00946     class to store chains of elements.
00947 
00948     Values stored in this container are not destroyed when the container is destroyed. These must be
00949     released by the client.
00950 
00951     Duplicate keys are allowed. Clients must walk the list for multiple entries.
00952     @see @c Location::operator++()
00953 
00954     By default the table automatically expands to limit the average chain length. This can be tuned. If set
00955     to @c MANUAL then the table will expand @b only when explicitly requested to do so by the client.
00956     @see @c ExpansionPolicy
00957     @see @c setExpansionPolicy()
00958     @see @c setExpansionLimit()
00959     @see @c expand()
00960 
00961     All the parameters for the hash map are passed via the template argument @a H. This is a struct
00962     that contains both type definitions and static methods. It must have
00963 
00964     - No state (cheap and risk free to copy).
00965 
00966     - All required methods are static methods.
00967 
00968     @a ID is a @c typedef for the hash type. This is the type of the value produced by the hash function. It must be
00969     a numeric type.
00970 
00971     @a Key is a @c typedef for the key type. This is passed to the @a hash function and used for equality
00972     checking of elements. It is presumed cheap to copy. If the underlying key is not a simple type
00973     then @a Key should be declared as a constant pointer or a constant reference. The hash table
00974     will never attempt to modify a key.
00975 
00976     @a Value is a @c typedef for the value type, the type of the element stored in the hash table.
00977 
00978     @a ListHead is @c typedef for the @c DLL compatible class that can serve as the anchor for a chain of
00979     @a Value instances. This is use both as data to be stored in a bucket and for access to next and
00980     previous pointers from instances of @a Value.
00981 
00982     Method @c hash converts a @c Key to a hash value. The key argument can be by value or by constant reference.
00983     @code
00984     ID hash(Key key);
00985     @endcode
00986 
00987     Method @c key extracts the key from a @c Value instance.
00988     @code
00989     Key key(Value const*);
00990     @endcode
00991 
00992     Method @c equal checks for equality between a @c Key and a @c Value. The key argument can be a
00993     constant reference or by value. The arguments should be @c const if not by value.
00994 
00995     @code
00996     bool equal (Key lhs, Key rhs);
00997     bool equal (Key key, Value const* value);
00998     @endcode
00999 
01000     Example for @c HttpServerSession keyed by the origin server IP address.
01001 
01002     @code
01003     struct Hasher {
01004       typedef uint32_t ID;
01005       typedef sockaddr const* Key;
01006       typedef HttpServerSession Value;
01007       typedef DList(HttpServerSession, ip_hash_link) ListHead;
01008 
01009       static uint32_t hash(sockaddr const* key) { return ats_ip_hash(key); }
01010       static sockaddr const* key(HttpServerSession const* value) { return &value->ip.sa }
01011       static bool equal(sockaddr const* lhs, sockaddr const* rhs) { return ats_ip_eq(lhs, rhs); }
01012       // Alternatively
01013       // static ID hash(Key* key);
01014       // static Key key(Value* value);
01015       // static bool equal(Key lhs, Key rhs);
01016     @endcode
01017 
01018     In @c HttpServerSession is the definition
01019 
01020     @code
01021     LINK(HttpServerSession, ip_hash_link);
01022     @endcode
01023 
01024     which creates the internal links used by @c TSHashTable.
01025 
01026  */
01027 template <
01028   typename H ///< Hashing utility class.
01029 >
01030 class TSHashTable {
01031 public:
01032   typedef TSHashTable self; ///< Self reference type.
01033 
01034   // Make embedded types easier to use by importing them to the class namespace.
01035   typedef H Hasher; ///< Rename and promote.
01036   typedef typename Hasher::ID ID; ///< ID type.
01037   typedef typename Hasher::Key Key; ///< Key type.
01038   typedef typename Hasher::Value Value; ///< Stored value (element) type.
01039   typedef typename Hasher::ListHead ListHead; ///< Anchor for chain.
01040 
01041   /// When the hash table is expanded.
01042   enum ExpansionPolicy {
01043     MANUAL, ///< Client must explicitly expand the table.
01044     AVERAGE, ///< Table expands if average chain length exceeds limit. [default]
01045     MAXIMUM ///< Table expands if any chain length exceeds limit.
01046   };
01047 
01048   /** Hash bucket.
01049       This is stored in the base array, anchoring the open chaining.
01050 
01051       @internal The default values are selected so that zero initialization is correct. Be careful if you
01052       change that.
01053   */
01054   struct Bucket {
01055     ListHead m_chain; ///< Chain of elements.
01056     size_t m_count; ///< # of elements in chain.
01057 
01058     /** Internal chain for iteration.
01059 
01060         Iteration is tricky because it needs to skip over empty buckets and detect end of buckets.
01061         Both of these are difficult inside the iterator without excess data. So we chain the
01062         non-empty buckets and let the iterator walk that. This makes end detection easy and
01063         iteration on sparse data fast. If we make it a doubly linked list adding and removing buckets
01064         is very fast as well.
01065     */
01066     LINK(Bucket, m_link);
01067 
01068     /** Do the values in this bucket have different keys?
01069         
01070         @internal This can have a false positive, but that's OK, better than the expense of being
01071         exact.  What we want is to avoid expanding to shorten the chain if it won't help, which it
01072         won't if all the keys are the same.
01073 
01074         @internal Because we've selected the default to be @c false so we can use @c Vec which zero fills empty elements.
01075     */
01076     bool m_mixed_p;
01077 
01078     /// Default constructor - equivalent to zero filled.
01079     Bucket() : m_count(0), m_mixed_p(false) { ink_zero(m_link); }
01080   };
01081 
01082   /** Information about locating a value in the hash table.
01083       
01084       An instance of this returned when searching for a key in the table. It can then be used to
01085       check if a matching key was found, and to iterate over equivalent keys. Note this iterator
01086       will touch only values which have a matching key.
01087 
01088       @internal It's not really an iterator, although similar.
01089       @internal we store the ID (hashed key value) for efficiency - we can get the actual key via the
01090       @a m_value member.
01091    */
01092   struct Location {
01093     Value* m_value; ///< The value located.
01094     Bucket* m_bucket; ///< Containing bucket of value.
01095     ID m_id; ///< ID (hashed key).
01096     size_t m_distance; ///< How many values in the chain we've gone past to get here.
01097 
01098     /// Default constructor - empty location.
01099     Location() : m_value(NULL), m_bucket(NULL), m_id(0), m_distance(0) {}
01100 
01101     /// Check for location being valid (referencing a value).
01102     bool isValid() const { return NULL != m_value; }
01103 
01104     /// Automatically cast to a @c Value* for convenience.
01105     /// @note This lets you assign the return of @c find to a @c Value*.
01106     /// @note This also permits the use of this class directly as a boolean expression.
01107     operator Value* () const { return m_value; }
01108 
01109     /// Dereference.
01110     Value& operator * () const { return *m_value; }
01111     /// Dereference.
01112     Value* operator -> () const { return m_value; }
01113 
01114     /// Find next value with matching key (prefix).
01115     Location& operator ++ () { if (m_value) this->advance(); return *this; }
01116     /// Find next value with matching key (postfix).
01117     Location& operator ++ (int) {
01118       Location zret(*this);
01119       if (m_value) this->advance();
01120       return zret;
01121     }
01122 
01123   protected:
01124     /// Move to next matching value, no checks.
01125     void advance();
01126 
01127     friend class TSHashTable;
01128   };
01129 
01130   /** Standard iterator for walking the table.
01131       This iterates over all elements.
01132       @internal Iterator is end if m_value is NULL.
01133    */
01134   struct iterator {
01135     Value* m_value; ///< Current location.
01136     Bucket* m_bucket; ///< Current bucket;
01137 
01138     iterator() : m_value(0), m_bucket(0) {}
01139     iterator& operator ++ ();
01140     Value& operator * () { return *m_value; }
01141     Value* operator -> () { return m_value; }
01142     bool operator == (iterator const& that) { return m_bucket == that.m_bucket && m_value == that.m_value; }
01143     bool operator != (iterator const& that) { return !(*this == that); }
01144 
01145   protected:
01146     /// Internal iterator constructor.
01147     iterator(Bucket* b, Value* v) : m_value(v), m_bucket(b) {}
01148     friend class TSHashTable;
01149   };
01150 
01151   iterator begin(); ///< First element.
01152   iterator end(); ///< Past last element.
01153 
01154   /// The default starting number of buckets.
01155   static size_t const DEFAULT_BUCKET_COUNT = 7; ///< POOMA.
01156   /// The default expansion policy limit.
01157   static size_t const DEFAULT_EXPANSION_LIMIT = 4; ///< Value from previous version.
01158 
01159   /** Constructor (also default).
01160       Constructs an empty table with at least @a nb buckets.
01161   */
01162   TSHashTable(size_t nb = DEFAULT_BUCKET_COUNT);
01163 
01164   /** Insert a value in to the table.
01165       The @a value must @b NOT already be in a table of this type.
01166       @note The value itself is put in the table, @b not a copy.
01167   */
01168   void insert(Value* value);
01169 
01170   /** Find a value that matches @a key.
01171 
01172       @note This finds the first value with a matching @a key. No other properties
01173       of the value are examined.
01174 
01175       @return The @c Location of the value. Use @c Location::isValid() to check for success.
01176   */
01177   Location find(Key key);
01178 
01179   /** Get a @c Location for @a value.
01180 
01181       This is a bit obscure but needed in certain cases. It should only be used on a @a value that
01182       is already known to be in the table. It just does the bucket lookup and uses that and the @a
01183       value to construct a @c Location that can be used with other methods. The @a m_distance value
01184       is not set in this case for performance reasons.
01185    */
01186   Location find(Value* value);
01187 
01188   /** Remove the value at @a location from the table.
01189 
01190       This method assumes a @a location is consistent. Be very careful if you modify a @c Location.
01191 
01192       @return @c true if the value was removed, @c false otherwise.
01193   */
01194   bool remove(Location const& location);
01195 
01196   /** Remove @b all values with @a key.
01197 
01198       @note This does @b not clean up the removed elements. Use carefully to avoid leaks.
01199 
01200       @return @c true if any value was removed, @c false otherwise.
01201   */
01202   bool remove(Key key);
01203 
01204   /** Remove all values from the table.
01205 
01206       The values are not cleaned up. The values are not touched in this method, therefore it is safe
01207       to destroy them first and then @c clear this table.
01208   */
01209   void clear();
01210 
01211   /// Get the number of elements in the table.
01212   size_t count() const { return m_count; }
01213 
01214   /// Get the number of buckets in the table.
01215   size_t bucketCount() const { return m_array.n; }
01216 
01217   /// Enable or disable expanding the table when chains are long.
01218   void setExpansionPolicy(ExpansionPolicy p) { m_expansion_policy = p; }
01219   /// Get the current expansion policy.
01220   void expansionPolicy() const { return m_expansion_policy; }
01221   /// Set the limit value for the expansion policy.
01222   void setExpansionLimit(size_t n) { m_expansion_limit = n; }
01223   /// Set the limit value for the expansion policy.
01224   size_t expansionLimit() const { return m_expansion_limit; }
01225 
01226   /** Expand the hash.
01227 
01228       Useful primarily when the expansion policy is set to @c MANUAL.
01229    */
01230   void expand();
01231 
01232 protected:
01233   typedef Vec<Bucket, DefaultAlloc, 0> Array; ///< Bucket array.
01234 
01235   size_t m_count; ///< # of elements stored in the table.
01236   ExpansionPolicy m_expansion_policy; ///< When to exand the table.
01237   size_t m_expansion_limit; ///< Limit value for expansion.
01238   Array m_array; ///< Bucket storage.
01239   /// Make available to nested classes statically.
01240   // We must reach inside the link hackery because we're in a template and
01241   // must use typename. Older compilers don't handle typename outside of
01242   // template context so if we put typename in the base definition it won't
01243   // work in non-template classes.
01244   typedef DLL<Bucket, typename Bucket::Link_m_link> BucketChain;
01245   /// List of non-empty buckets.
01246   BucketChain m_bucket_chain;
01247 
01248   /** Get the ID and bucket for key.
01249       Fills @a m_id and @a m_bucket in @a location from @a key.
01250   */
01251   void findBucket(Key key, Location& location);
01252 };
01253 
01254 template < typename H > typename TSHashTable<H>::iterator
01255 TSHashTable<H>::begin() {
01256   // Get the first non-empty bucket, if any.
01257   Bucket* b = m_bucket_chain.head;
01258   return b && b->m_chain.head
01259     ? iterator(b, b->m_chain.head)
01260     : this->end()
01261     ;
01262 }
01263 
01264 template < typename H > typename TSHashTable<H>::iterator
01265 TSHashTable<H>::end() {
01266   return iterator(0,0);
01267 }
01268 
01269 template < typename H > typename TSHashTable<H>::iterator&
01270 TSHashTable<H>::iterator::operator ++ () {
01271   if (m_value) {
01272     if (NULL == (m_value = ListHead::next(m_value))) { // end of bucket, next bucket.
01273       if (NULL != (m_bucket = BucketChain::next(m_bucket))) { // found non-empty next bucket.
01274         m_value = m_bucket->m_chain.head;
01275         ink_assert(m_value); // if bucket is in chain, must be non-empty.
01276       }
01277     }
01278   }
01279   return *this;
01280 }
01281 
01282 template < typename H > TSHashTable<H>::TSHashTable(size_t nb)
01283   : m_count(0), m_expansion_policy(AVERAGE), m_expansion_limit(DEFAULT_EXPANSION_LIMIT) {
01284   if (nb) {
01285     int idx = 1;
01286     while (prime2[idx] < nb) ++idx;
01287     m_array.n = 1; // anything non-zero.
01288     m_array.i = idx - 1;
01289   }
01290   m_array.set_expand();
01291 }
01292 
01293 template < typename H > void
01294 TSHashTable<H>::Location::advance() {
01295   Key key = Hasher::key(m_value);
01296   // assumes valid location with correct key, advance to next matching key or make location invalid.
01297   do {
01298     ++m_distance;
01299     m_value = ListHead::next(m_value);
01300   } while (m_value && ! Hasher::equal(key, Hasher::key(m_value)));
01301 }
01302 
01303 template < typename H > void
01304 TSHashTable<H>::findBucket(Key key, Location& location) {
01305   location.m_id = Hasher::hash(key);
01306   location.m_bucket = &(m_array[location.m_id % m_array.n]);
01307 }
01308 
01309 template < typename H > typename TSHashTable<H>::Location
01310 TSHashTable<H>::find(Key key) {
01311   Location zret;
01312   Value* v;
01313 
01314   this->findBucket(key, zret); // zret gets updated to match the bucket.
01315   v = zret.m_bucket->m_chain.head;
01316   // Search for first matching key.
01317   while (0 != v && ! Hasher::equal(key, Hasher::key(v)))
01318     v = ListHead::next(v);
01319   zret.m_value = v;
01320   return zret;
01321 }
01322 
01323 template < typename H > typename TSHashTable<H>::Location
01324 TSHashTable<H>::find(Value* value) {
01325   Location zret;
01326   this->findBucket(Hasher::key(value), zret);
01327   if (zret.m_bucket->m_chain.in(value)) // just checks value links and chain head.
01328     zret.m_value = value;
01329   return zret;
01330 }
01331 
01332 template < typename H > void
01333 TSHashTable<H>::insert(Value* value) {
01334   Key key = Hasher::key(value);
01335   Bucket* bucket = &(m_array[Hasher::hash(key) % m_array.n]);
01336 
01337   // Bad client if already in a list!
01338   ink_assert(! bucket->m_chain.in(value));
01339 
01340   // Mark mixed if not already marked and we're adding a different key.
01341   if (!bucket->m_mixed_p && !bucket->m_chain.empty() && ! Hasher::equal(key, Hasher::key(bucket->m_chain.head)))
01342     bucket->m_mixed_p = true;
01343 
01344   bucket->m_chain.push(value);
01345   ++m_count;
01346   if (1 == ++(bucket->m_count)) // not empty, put it on the non-empty list.
01347     m_bucket_chain.push(bucket);
01348   // auto expand if appropriate.
01349   if ((AVERAGE == m_expansion_policy && (m_count / m_array.n) > m_expansion_limit)
01350       || (MAXIMUM == m_expansion_policy && bucket->m_count > m_expansion_limit && bucket->m_mixed_p))
01351     this->expand();
01352 }
01353 
01354 template < typename H > bool
01355 TSHashTable<H>::remove(Location const& l) {
01356   bool zret = false;
01357   if (l.isValid()) {
01358     ink_assert(l.m_bucket->m_count);
01359     ink_assert(l.m_bucket->m_chain.head);
01360     l.m_bucket->m_chain.remove(l.m_value);
01361     --m_count;
01362     --(l.m_bucket->m_count);
01363     if (0 == l.m_bucket->m_count)  // if it's now empty, take it out of the non-empty bucket chain.
01364       m_bucket_chain.remove(l.m_bucket);
01365     else if (1 == l.m_bucket->m_count) // if count drops to 1, then it's not mixed any more.
01366       l.m_bucket->m_mixed_p = false;
01367     zret = true;
01368   }
01369   return zret;
01370 }
01371 
01372 template < typename H > bool
01373 TSHashTable<H>::remove(Key key) {
01374   Location loc = this->find(key);
01375   bool zret = loc.isValid();
01376   while (loc.isValid()) {
01377     Location target(loc);
01378     loc.advance();
01379     this->remove(target);
01380   }
01381   return zret;
01382 }
01383 
01384 template < typename H > void
01385 TSHashTable<H>::clear() {
01386   Bucket null_bucket;
01387   // Remove the values but not the actual buckets.
01388   for ( size_t i = 0 ; i < m_array.n ; ++i ) {
01389     m_array[i] = null_bucket;
01390   }
01391   // Clear container data.
01392   m_count = 0;
01393   m_bucket_chain.clear();
01394 }
01395 
01396 template < typename H > void
01397 TSHashTable<H>::expand() {
01398   Bucket* b = m_bucket_chain.head; // stash before reset.
01399   ExpansionPolicy org_expansion_policy = m_expansion_policy;
01400   Array tmp;
01401   tmp.move(m_array); // stash the current array here.
01402   // Reset to empty state.
01403   m_count = 0;
01404   m_bucket_chain.clear();
01405 
01406   // Because we moved the array, we have to copy back a couple of things to make
01407   // the expansion actually expand. How this is supposed to work without leaks or
01408   // mucking about in the internal is unclear to me.
01409   m_array.n = 1; // anything non-zero.
01410   m_array.i = tmp.i;  // set the base index.
01411   m_array.set_expand(); // bumps array size up to next index value.
01412 
01413   m_expansion_policy = MANUAL; // disable any auto expand while we're expanding.
01414   // Move the values from the stashed array to the expanded hash.
01415   while (b) {
01416     Value* v = b->m_chain.head;
01417     while (v) {
01418       b->m_chain.remove(v); // clear local pointers to be safe.
01419       this->insert(v);
01420       v = b->m_chain.head; // next value, because previous was removed.
01421     }
01422     b = BucketChain::next(b); // these buckets are in the stashed array so pointers are still valid.
01423   }
01424   // stashed array gets cleaned up when @a tmp goes out of scope.
01425   m_expansion_policy = org_expansion_policy; // reset to original value.
01426 }
01427 
01428 /* ---------------------------------------------------------------------------------------------- */
01429 
01430 #endif

Generated by  doxygen 1.7.1