00001
00002
00003
00004
00005
00006
00007
00008
00009 #ifndef __WVONDISKHASH_H
00010 #define __WVONDISKHASH_H
00011
00012 #include "wvautoconf.h"
00013 #include "wvhashtable.h"
00014 #include "wvserialize.h"
00015 #include "wverror.h"
00016
00028
00029 #ifdef WITH_QDBM
00030 class WvQdbmHash;
00031 typedef WvQdbmHash DefaultHash;
00032 #else
00033 # ifdef WITH_BDB
00034 class WvBdbHash;
00035 typedef WvBdbHash DefaultHash;
00036 # else
00037 # error No supported database found!
00038 # endif
00039 #endif
00040
00041 template <class K, class D, class Backend = DefaultHash>
00042 class WvOnDiskHash : public Backend
00043 {
00044 typedef WvOnDiskHash<K, D, Backend> MyType;
00045 typedef typename Backend::IterBase BackendIterBase;
00046 typedef typename Backend::Datum datum;
00047
00048 public:
00049
00050
00051
00052 template <typename T>
00053 class datumize : public datum
00054 {
00055 private:
00056 void init(const T &t)
00057 {
00058 wv_serialize(buf, t);
00059 this->dsize = buf.used();
00060 this->dptr = (char *)buf.peek(0, buf.used());
00061 }
00062
00063 protected:
00064 datumize(const datumize<T> &);
00065
00066 #if defined __GNUC__ && __GNUC__ < 3
00067
00068
00069 #else
00070
00071
00072
00073
00074
00075
00076 friend class WvOnDiskHash<K, D, Backend>;
00077 friend class WvOnDiskHash<K, D, Backend>::Iter;
00078 #endif
00079
00080 public:
00081 WvDynBuf buf;
00082
00083 datumize(const T &t)
00084 { init(t); }
00085
00086 datumize(const T *t)
00087 {
00088 if (t)
00089 init(*t);
00090 else
00091 {
00092 this->dsize = 0;
00093 this->dptr = 0;
00094 }
00095 }
00096
00097 };
00098
00099 template <typename T>
00100 static T undatumize(datum &data)
00101 {
00102 WvConstInPlaceBuf buf(data.dptr, data.dsize);
00103 return wv_deserialize<T>(buf);
00104 }
00105
00106 protected:
00107 D *saveddata;
00108
00109 public:
00110 WvOnDiskHash(WvStringParm dbfile = WvString::null, bool persist = true) :
00111 Backend(dbfile, persist)
00112 { saveddata = NULL; }
00113
00114 ~WvOnDiskHash()
00115 { delete saveddata; }
00116
00117 void add(const K &key, const D &data, bool replace = false)
00118 { Backend::add(datumize<K>(key), datumize<D>(data), replace); }
00119
00120 void remove(const K &key)
00121 { Backend::remove(datumize<K>(key)); }
00122
00123 D &find(const K &key)
00124 {
00125 delete saveddata;
00126 datum s = Backend::find(datumize<K>(key));
00127 saveddata = undatumize<D *>(s);
00128 return *saveddata;
00129 }
00130
00131 D &operator[] (const K &key)
00132 { return find(key); }
00133
00134 bool exists(const K &key)
00135 { return Backend::exists(datumize<K>(key)); }
00136
00137 size_t count()
00138 {
00139 int res = 0;
00140 Iter i(*this);
00141 for (i.rewind(); i.next(); )
00142 res++;
00143 return res;
00144 }
00145
00146 bool isempty()
00147 {
00148 Iter i(*this);
00149 i.rewind();
00150 return !i.next();
00151 }
00152
00153 D &first()
00154 {
00155 Iter i(*this);
00156 i.rewind(); i.next();
00157 return i();
00158 }
00159
00160 class Iter : public BackendIterBase
00161 {
00162 K *k;
00163 D *d;
00164
00165 public:
00166 Iter(MyType &hash) : BackendIterBase(hash)
00167 { k = NULL; d = NULL; }
00168 ~Iter()
00169 {
00170 delete k;
00171 delete d;
00172 }
00173
00174 void rewind()
00175 {
00176 BackendIterBase::rewind();
00177 delete k; k = NULL;
00178 delete d; d = NULL;
00179 }
00180
00181 void rewind(const K &firstkey)
00182 {
00183 typename MyType::template datumize<K> key(k);
00184 typename MyType::template datumize<D> data(d);
00185
00186 BackendIterBase::rewind(typename MyType::template datumize<K>(
00187 firstkey), key, data);
00188 delete k;
00189 delete d;
00190 if (data.dptr)
00191 {
00192 k = undatumize<K *>(key);
00193 d = undatumize<D *>(data);
00194 }
00195 else
00196 {
00197 k = NULL;
00198 d = NULL;
00199 }
00200 }
00201
00202 bool next()
00203 {
00204 typename MyType::template datumize<K> key(k);
00205 datum data = { 0, 0 };
00206 BackendIterBase::next(key, data);
00207 delete k;
00208 delete d;
00209 if (data.dptr)
00210 {
00211 k = undatumize<K *>(key);
00212 d = undatumize<D *>(data);
00213 return true;
00214 }
00215 k = NULL;
00216 d = NULL;
00217 return false;
00218 }
00219
00220 void unlink()
00221 { xunlink(); next(); }
00222
00223 void xunlink()
00224 {
00225 BackendIterBase::xunlink(typename MyType::template datumize<K>(k));
00226 }
00227
00228 void save()
00229 {
00230 BackendIterBase::update(typename MyType::template datumize<K>(k),
00231 typename MyType::template datumize<D>(d));
00232 }
00233
00234 bool cur()
00235 { return d; }
00236
00237 K &key() const
00238 { assert(k); return *k; }
00239
00240 D *ptr() const
00241 { return d; }
00242
00243 WvIterStuff(D);
00244 };
00245
00246 };
00247
00248 template <class Parent, class Datum>
00249 class WvOnDiskHashIterBase
00250 {
00251 public:
00252 WvOnDiskHashIterBase(Parent &_parent) : parent(_parent)
00253 {
00254 rewindto.dsize = 0;
00255 rewindto.dptr = NULL;
00256 }
00257 ~WvOnDiskHashIterBase() { free((void *)rewindto.dptr); }
00258 void rewind()
00259 {
00260 free((void*)rewindto.dptr);
00261 rewindto.dptr = NULL;
00262 }
00263 void rewind(const Datum &firstkey, Datum &curkey, Datum &curdata)
00264 {
00265
00266 free((void*)rewindto.dptr);
00267 rewindto.dsize = firstkey.dsize;
00268 rewindto.dptr = (typeof(rewindto.dptr))malloc(rewindto.dsize);
00269 memcpy((void*)rewindto.dptr, firstkey.dptr, rewindto.dsize);
00270 curkey.dptr = curdata.dptr = NULL;
00271 }
00272 void xunlink(const Datum &curkey) { parent.remove(curkey); }
00273 void update(const Datum &curkey, const Datum &data)
00274 { parent.add(curkey, data, true); }
00275
00276 protected:
00277 Datum rewindto;
00278 Parent &parent;
00279 };
00280
00281 #ifdef WITH_BDB
00282
00286 class WvBdbHash : public WvErrorBase
00287 {
00288 WvString dbfile;
00289 bool persist_dbfile;
00290
00291 public:
00292 struct datum
00293 {
00294 void *dptr;
00295 size_t dsize;
00296 };
00297 typedef datum Datum;
00298
00299 WvBdbHash(WvStringParm _dbfile = WvString::null, bool persist = true);
00300 ~WvBdbHash();
00301
00316 void opendb(WvStringParm _dbfile = WvString::null, bool persist = true);
00317
00326 void closedb();
00327
00328 void add(const datum &key, const datum &data, bool replace);
00329 void remove(const datum &key);
00330 datum find(const datum &key);
00331 bool exists(const datum &key);
00332
00337 void zap();
00338
00339 class IterBase : public WvOnDiskHashIterBase<WvBdbHash, Datum>
00340 {
00341 public:
00342 IterBase(WvBdbHash &bdbhash)
00343 : WvOnDiskHashIterBase<WvBdbHash, Datum>(bdbhash) {};
00344
00345 void next(datum &key, datum &data);
00346 };
00347
00348 private:
00349 friend class IterBase;
00350 struct __db *dbf;
00351 };
00352 #endif // WITH_BDB
00353
00354 #ifdef WITH_QDBM
00355
00356
00357
00358
00359 class WvQdbmHash : public WvErrorBase
00360 {
00361 bool persist_dbfile;
00362
00363 public:
00364 struct datum
00365 {
00366 const char *dptr;
00367 int dsize;
00368 };
00369 typedef datum Datum;
00370
00371 WvQdbmHash(WvStringParm dbfile = WvString::null, bool persist = true);
00372 ~WvQdbmHash();
00373
00374 void opendb(WvStringParm dbfile = WvString::null, bool persist = true);
00375 void closedb();
00376
00377 void add(const Datum &key, const Datum &data, bool replace);
00378 void remove(const Datum &key);
00379 Datum find(const Datum &key);
00380 bool exists(const Datum &key);
00381 void zap();
00382
00383 class IterBase : public WvOnDiskHashIterBase<WvQdbmHash, Datum>
00384 {
00385 public:
00386 IterBase(WvQdbmHash &qdbmhash)
00387 : WvOnDiskHashIterBase<WvQdbmHash, Datum>(qdbmhash) {};
00388
00389 void next(Datum &key, Datum &data);
00390 };
00391 private:
00392 Datum saveddata;
00393 friend class IterBase;
00394 void *dbf;
00395
00396 void dperr();
00397 };
00398 #endif // WITH_QDBM
00399
00400 #endif // __WVONDISKHASH_H