aboutsummaryrefslogtreecommitdiff
path: root/libxsde/xsde/cxx/hashmap.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'libxsde/xsde/cxx/hashmap.cxx')
-rw-r--r--libxsde/xsde/cxx/hashmap.cxx210
1 files changed, 210 insertions, 0 deletions
diff --git a/libxsde/xsde/cxx/hashmap.cxx b/libxsde/xsde/cxx/hashmap.cxx
new file mode 100644
index 0000000..c5d9079
--- /dev/null
+++ b/libxsde/xsde/cxx/hashmap.cxx
@@ -0,0 +1,210 @@
+// file : xsde/cxx/hashmap.cxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC
+// license : GNU GPL v2 + exceptions; see accompanying LICENSE file
+
+#include <string.h> // memset, memcpy, strlen, strcmp, strncmp
+
+#include <xsde/cxx/hashmap.hxx>
+
+namespace xsde
+{
+ namespace cxx
+ {
+ // const_iterator
+ //
+ hashmap_const_iterator::
+ hashmap_const_iterator (const hashmap& map, size_t b)
+ : map_ (&map), bucket_ (b), element_ (0)
+ {
+ // Get it to the first actual element if any.
+ //
+ for (; bucket_ < map_->bcount_; ++bucket_)
+ {
+ hashmap::bucket* p = map_->buckets_[bucket_];
+ if (p && p->size_)
+ break;
+ }
+ }
+
+ const void* hashmap_const_iterator::
+ operator* () const
+ {
+ typedef hashmap::bucket bucket;
+ typedef hashmap::element element;
+
+ bucket* p = map_->buckets_[bucket_];
+ const char* b = reinterpret_cast<const char*> (p) + sizeof (bucket);
+ b += element_ * (sizeof (element) + map_->esize_);
+ return b + sizeof (element);
+ }
+
+ hashmap_const_iterator& hashmap_const_iterator::
+ operator++ ()
+ {
+ if (bucket_ < map_->bcount_)
+ {
+ hashmap::bucket* p = map_->buckets_[bucket_];
+
+ if (p->size_ > element_ + 1)
+ ++element_;
+ else
+ {
+ element_ = 0;
+
+ for (++bucket_; bucket_ < map_->bcount_; ++bucket_)
+ {
+ p = map_->buckets_[bucket_];
+ if (p && p->size_)
+ break;
+ }
+ }
+ }
+
+ return *this;
+ }
+
+ // hashmap
+ //
+ hashmap::
+ ~hashmap ()
+ {
+#ifndef XSDE_EXCEPTIONS
+ if (buckets_ != 0)
+ {
+#endif
+ for (size_t i = 0; i < bcount_; ++i)
+ {
+ if (buckets_[i])
+ operator delete (buckets_[i]);
+ }
+
+ delete[] buckets_;
+
+#ifndef XSDE_EXCEPTIONS
+ }
+#endif
+ }
+
+
+ hashmap::
+ hashmap (size_t bcount, size_t esize)
+ : esize_ (esize), ecount_ (0), bcount_ (bcount), buckets_ (0)
+ {
+#ifndef XSDE_EXCEPTIONS
+ error_ = error_none;
+#endif
+
+ buckets_ = new bucket*[bcount_];
+
+#ifndef XSDE_EXCEPTIONS
+ if (buckets_ == 0)
+ {
+ error_ = error_no_memory;
+ return;
+ }
+#endif
+ memset (buckets_, 0, sizeof (bucket*) * bcount_);
+ }
+
+ void hashmap::
+ insert (const char* key, void* value)
+ {
+ size_t h = hash (key);
+ bucket*& p = *(buckets_ + h % bcount_);
+
+ if (p == 0)
+ {
+ // No elements in this bucket yet. Start with capacity for 2
+ // elements.
+ //
+ p = static_cast<bucket*> (
+ operator new (sizeof (bucket) + 2 * (sizeof (element) + esize_)));
+
+#ifndef XSDE_EXCEPTIONS
+ if (p == 0)
+ {
+ error_ = error_no_memory;
+ return;
+ }
+#endif
+ p->size_ = 0;
+ p->capacity_ = 2;
+ }
+
+ if (p->size_ == p->capacity_)
+ {
+ // No more space in this bucket. Create a bigger bucket.
+ //
+ size_t c = p->size_ * 2;
+ bucket* n = static_cast<bucket*> (
+ operator new (sizeof (bucket) + c * (sizeof (element) + esize_)));
+
+#ifndef XSDE_EXCEPTIONS
+ if (n == 0)
+ {
+ error_ = error_no_memory;
+ return;
+ }
+#endif
+ n->size_ = p->size_;
+ n->capacity_ = c;
+
+ char* src = reinterpret_cast<char*> (p) + sizeof (bucket);
+ char* dst = reinterpret_cast<char*> (n) + sizeof (bucket);
+
+ memcpy (dst, src, p->size_ * (sizeof (element) + esize_));
+
+ operator delete (p);
+ p = n;
+ }
+
+ char* data = reinterpret_cast<char*> (p) + sizeof (bucket) +
+ p->size_ * (sizeof (element) + esize_);
+
+ element* e = reinterpret_cast<element*> (data);
+ e->hash_ = h;
+ e->key_ = key;
+
+ memcpy (data + sizeof (element), value, esize_);
+
+ p->size_++;
+ ecount_++;
+ }
+
+ const void* hashmap::
+ find (const char* key) const
+ {
+ size_t h = hash (key);
+ const bucket* p = *(buckets_ + h % bcount_);
+
+ if (p)
+ {
+ const char* b = reinterpret_cast<const char*> (p) + sizeof (bucket);
+ const char* e = b + p->size_ * (sizeof (element) + esize_);
+
+ for (; b < e; b += sizeof (element) + esize_)
+ {
+ const element* e = reinterpret_cast<const element*> (b);
+
+ if (e->hash_ == h && strcmp (e->key_, key) == 0)
+ return b + sizeof (element);
+ }
+ }
+
+ return 0;
+ }
+
+ size_t hashmap::
+ max_bucket_size () const
+ {
+ size_t r = 0;
+ for (size_t i = 0; i < bcount_; ++i)
+ {
+ if (buckets_[i] != 0 && buckets_[i]->size_ > r)
+ r = buckets_[i]->size_;
+ }
+ return r;
+ }
+ }
+}