aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/basetypes/MCHashMap.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/basetypes/MCHashMap.cpp')
-rw-r--r--src/core/basetypes/MCHashMap.cpp331
1 files changed, 331 insertions, 0 deletions
diff --git a/src/core/basetypes/MCHashMap.cpp b/src/core/basetypes/MCHashMap.cpp
new file mode 100644
index 00000000..046aad90
--- /dev/null
+++ b/src/core/basetypes/MCHashMap.cpp
@@ -0,0 +1,331 @@
+#include "MCWin32.h" // should be first include.
+
+#include "MCHashMap.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "MCDefines.h"
+#include "MCArray.h"
+#include "MCString.h"
+#include "MCUtils.h"
+#include "MCLog.h"
+#include "MCIterator.h"
+#include "MCAssert.h"
+
+using namespace mailcore;
+
+namespace mailcore {
+ struct HashMapCell {
+ unsigned int func;
+ Object * key;
+ Object * value;
+ HashMapCell * next;
+ };
+
+}
+
+#define CHASH_DEFAULTSIZE 13
+#define CHASH_MAXDEPTH 3
+
+void HashMap::init()
+{
+ mCount = 0;
+ mCells = (void **) (HashMapCell **) calloc(CHASH_DEFAULTSIZE, sizeof(HashMapCell *));
+ mAllocated = CHASH_DEFAULTSIZE;
+}
+
+HashMap::HashMap()
+{
+ init();
+}
+
+HashMap::HashMap(HashMap * other)
+{
+ init();
+ Array * keys = other->allKeys();
+ for(unsigned int i = 0 ; i < keys->count() ; i ++) {
+ Object * key = keys->objectAtIndex(i);
+ Object * value = other->objectForKey(key);
+ setObjectForKey(key, value);
+ }
+}
+
+HashMap::~HashMap()
+{
+ for(unsigned int indx = 0; indx < mAllocated; indx++) {
+ HashMapIter * iter, * next;
+ iter = (HashMapIter *) mCells[indx];
+ while (iter) {
+ next = iter->next;
+ iter->key->release();
+ iter->value->release();
+ free(iter);
+ iter = next;
+ }
+ }
+ free(mCells);
+}
+
+void HashMap::allocate(unsigned int size)
+{
+ HashMapCell ** cells;
+ unsigned int indx, nindx;
+ HashMapIter * iter, * next;
+
+ if (mAllocated == size)
+ return;
+
+ cells = (HashMapCell **) calloc(size, sizeof(HashMapCell *));
+ /* iterate over initial hash and copy items in second hash */
+ for(indx = 0 ; indx < mAllocated ; indx ++) {
+ iter = (HashMapIter *) mCells[indx];
+ while (iter) {
+ next = iter->next;
+ nindx = iter->func % size;
+ iter->next = cells[nindx];
+ cells[nindx] = iter;
+ iter = next;
+ }
+ }
+ free(mCells);
+ mAllocated = size;
+ mCells = (void **) cells;
+}
+
+HashMap * HashMap::hashMap()
+{
+ HashMap * result = new HashMap();
+ return (HashMap *) result->autorelease();
+}
+
+String * HashMap::description()
+{
+ String * result = String::string();
+ Array * keys = allKeys();
+ result->appendUTF8Characters("{");
+ for(unsigned int i = 0 ; i < keys->count() ; i ++) {
+ Object * key = keys->objectAtIndex(i);
+ if (i != 0) {
+ result->appendUTF8Characters(",");
+ }
+ result->appendString(key->description());
+ result->appendUTF8Characters(":");
+ Object * value = objectForKey(key);
+ result->appendString(value->description());
+ }
+ result->appendUTF8Characters("}");
+
+ return result;
+}
+
+Object * HashMap::copy()
+{
+ return new HashMap(this);
+}
+
+unsigned int HashMap::count()
+{
+ return mCount;
+}
+
+void HashMap::setObjectForKey(Object * key, Object * value)
+{
+ unsigned int func, indx;
+ HashMapIter * iter, * cell;
+
+ if (mCount > mAllocated * CHASH_MAXDEPTH) {
+ allocate((mCount / CHASH_MAXDEPTH) * 2 + 1);
+ }
+
+ func = key->hash();
+ indx = func % mAllocated;
+
+ /* look for the key in existing cells */
+ iter = (HashMapIter *) mCells[indx];
+ while (iter) {
+ if (iter->func == func && iter->key->isEqual(key)) {
+ /* found, replacing entry */
+ value->retain();
+ iter->value->release();
+ iter->value = value;
+ return;
+ }
+ iter = iter->next;
+ }
+
+ /* not found, adding entry */
+ cell = (HashMapCell *) malloc(sizeof(HashMapCell));
+ cell->key = key->copy();
+ cell->value = value->retain();
+ cell->func = func;
+ cell->next = (HashMapCell *) mCells[indx];
+ mCells[indx] = cell;
+ mCount ++;
+}
+
+void HashMap::removeObjectForKey(Object * key)
+{
+ unsigned int func, indx;
+ HashMapIter * iter, * old;
+
+ func = key->hash();;
+ indx = func % mAllocated;
+
+ /* look for the key in existing cells */
+ old = NULL;
+ iter = (HashMapIter *) mCells[indx];
+ while (iter) {
+ if (iter->func == func && iter->key->isEqual(key)) {
+ /* found, deleting */
+ if (old)
+ old->next = iter->next;
+ else
+ mCells[indx] = iter->next;
+ iter->key->release();
+ iter->value->release();
+ free(iter);
+ mCount --;
+ return;
+ }
+ old = iter;
+ iter = iter->next;
+ }
+ // Not found.
+}
+
+Object * HashMap::objectForKey(Object * key)
+{
+ unsigned int func;
+ HashMapIter * iter;
+
+ func = key->hash();
+
+ /* look for the key in existing cells */
+ iter = (HashMapIter *) mCells[func % mAllocated];
+ while (iter) {
+ if (iter->func == func && key->isEqual(iter->key)) {
+ return iter->value; /* found */
+ }
+ iter = iter->next;
+ }
+ return NULL;
+}
+
+HashMapIter * HashMap::iteratorBegin()
+{
+ HashMapIter * iter;
+ unsigned int indx = 0;
+
+ iter = (HashMapIter *) mCells[0];
+ while (!iter) {
+ indx ++;
+ if (indx >= mAllocated)
+ return NULL;
+ iter = (HashMapIter *) mCells[indx];
+ }
+ return iter;
+}
+
+HashMapIter * HashMap::iteratorNext(HashMapIter * iter)
+{
+ unsigned int indx;
+
+ if (!iter)
+ return NULL;
+
+ indx = iter->func % mAllocated;
+ iter = iter->next;
+
+ while(!iter) {
+ indx++;
+ if (indx >= mAllocated)
+ return NULL;
+ iter = (HashMapIter *) mCells[indx];
+ }
+ return iter;
+}
+
+Array * HashMap::allKeys()
+{
+ Array * keys = Array::array();
+ for(HashMapIter * iter = iteratorBegin() ; iter != NULL ; iter = iteratorNext(iter)) {
+ keys->addObject(iter->key);
+ }
+ return keys;
+}
+
+Array * HashMap::allValues()
+{
+ Array * values = Array::array();
+ for(HashMapIter * iter = iteratorBegin() ; iter != NULL ; iter = iteratorNext(iter)) {
+ values->addObject(iter->value);
+ }
+ return values;
+}
+
+void HashMap::removeAllObjects()
+{
+ for(unsigned int indx = 0 ; indx < mAllocated ; indx++) {
+ HashMapIter * iter, * next;
+ iter = (HashMapIter *) mCells[indx];
+ while (iter) {
+ next = iter->next;
+ iter->key->release();
+ iter->value->release();
+ free(iter);
+ iter = next;
+ }
+ }
+ memset(mCells, 0, mAllocated * sizeof(* mCells));
+ mCount = 0;
+}
+
+HashMap * HashMap::serializable()
+{
+ HashMap * result = Object::serializable();
+ Array * keys = Array::array();
+ Array * values = Array::array();
+ mc_foreachhashmapKeyAndValue(Object, key, Object, value, this) {
+ if (MCISKINDOFCLASS(key, String)) {
+ keys->addObject(key);
+ }
+ else {
+ keys->addObject(key->serializable());
+ }
+ values->addObject(value->serializable());
+ }
+ result->setObjectForKey(MCSTR("keys"), keys);
+ result->setObjectForKey(MCSTR("values"), values);
+ return result;
+}
+
+void HashMap::importSerializable(HashMap * serializable)
+{
+ Array * keys = (Array *) serializable->objectForKey(MCSTR("keys"));
+ Array * values = (Array *) serializable->objectForKey(MCSTR("values"));
+ unsigned int count = keys->count();
+ MCAssert(count == values->count());
+ for(unsigned int i = 0 ; i < count ; i ++) {
+ Object * serializedKey = keys->objectAtIndex(i);
+ Object * key;
+ if (MCISKINDOFCLASS(serializedKey, String)) {
+ key = serializedKey;
+ }
+ else {
+ key = Object::objectWithSerializable((HashMap *) serializedKey);
+ }
+ Object * value = Object::objectWithSerializable((HashMap *) values->objectAtIndex(i));
+ setObjectForKey(key, value);
+ }
+}
+
+static void * createObject()
+{
+ return new HashMap();
+}
+
+INITIALIZE(HashMap)
+{
+ Object::registerObjectConstructor("mailcore::HashMap", &createObject);
+}