From 38c20e9b5992fff9239fb17ee8cd8cc262d2d439 Mon Sep 17 00:00:00 2001 From: Joseph Botosh Date: Mon, 13 Jun 2016 15:31:44 +0300 Subject: add hashtable functions htnew, htdelete, htput, htget, htclear, htsize htiterator, htinextkey, hticheck, htidelete --- src/Makefile.am | 2 + src/emap/hashtable.c | 209 +++++++++++++++++++++++++++++++++++++++++++++ src/emap/hashtable.h | 43 ++++++++++ src/emap/init.c | 14 +++ src/emap/script_buildins.c | 181 +++++++++++++++++++++++++++++++++++++++ src/emap/script_buildins.h | 10 +++ 6 files changed, 459 insertions(+) create mode 100644 src/emap/hashtable.c create mode 100644 src/emap/hashtable.h diff --git a/src/Makefile.am b/src/Makefile.am index a440726..b9812f2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -42,6 +42,8 @@ MAP_SRC = emap/atcommand.c \ emap/craft.h \ emap/craftconf.c \ emap/craftconf.h \ + emap/hashtable.c \ + emap/hashtable.h \ emap/horse.c \ emap/horse.h \ emap/init.c \ diff --git a/src/emap/hashtable.c b/src/emap/hashtable.c new file mode 100644 index 0000000..9d2908d --- /dev/null +++ b/src/emap/hashtable.c @@ -0,0 +1,209 @@ +// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL. +// Copyright (c) 2015 - 2016 Evol developers + +#include "common/hercules.h" + +#include "common/db.h" +#include "common/memmgr.h" +#include "emap/hashtable.h" + +struct htreg_interface htreg_s; +struct htreg_interface *htreg; + +int64 htreg_new_hashtable(void) +{ + int64 id = htreg->last_id++; + struct DBMap *ht = strdb_alloc(DB_OPT_DUP_KEY|DB_OPT_RELEASE_DATA, + HT_MAX_KEY_LEN); + i64db_put(htreg->htables, id, ht); + return id; +} + +bool htreg_destroy_hashtable(int64 id) +{ + struct DBMap *ht = i64db_get(htreg->htables, id); + if (ht) + { + db_destroy(ht); + i64db_remove(htreg->htables, id); + return true; + } + return false; +} + +bool htreg_hashtable_exists(int64 id) +{ + return i64db_exists(htreg->htables, id); +} + +int64 htreg_hashtable_size(int64 id) +{ + struct DBMap *ht = i64db_get(htreg->htables, id); + if (ht) + return db_size(ht); + return 0; +} + +bool htreg_clear_hashtable(int64 id) +{ + struct DBMap *ht = i64db_get(htreg->htables, id); + if (ht) + { + db_clear(ht); + return true; + } + return false; +} + +const struct DBData* htreg_hashtable_getvalue(int64 id, const char *key, + const struct DBData *defval) +{ + struct DBMap *ht = i64db_get(htreg->htables, id); + if (ht) + { + struct DBData *val = ht->get(ht, DB->str2key(key)); + return val ? val : defval; + } + return NULL; +} + +bool htreg_hashtable_setvalue(int64 id, const char *key, + struct DBData value) +{ + struct DBMap *ht = i64db_get(htreg->htables, id); + if (!ht) + return false; + + bool keep = true; + + switch(value.type) + { + case DB_DATA_INT: + case DB_DATA_UINT: + keep = value.u.i; + break; + case DB_DATA_PTR: + keep = value.u.ptr && *(char*)value.u.ptr; + break; + } + + if (keep) + ht->put(ht, DB->str2key(key), value, NULL); + else + strdb_remove(ht, key); + + return true; +} + +/** + * Iterators + */ +int64 htreg_create_iterator(int64 htId) +{ + struct DBMap *ht = i64db_get(htreg->htables, htId); + if (ht) + { + int64 id = htreg->last_iterator_id++; + struct DBIterator *it = db_iterator(ht); + i64db_put(htreg->iterators, id, it); + return id; + } + return 0; +} + +bool htreg_destroy_iterator(int64 id) +{ + struct DBIterator *it = i64db_get(htreg->iterators, id); + if (it) + { + dbi_destroy(it); + return true; + } + return false; +} + +bool htreg_iterator_check(int64 id) +{ + struct DBIterator *it = i64db_get(htreg->iterators, id); + return it ? dbi_exists(it) : false; +} + +bool htreg_iterator_exists(int64 id) +{ + return i64db_exists(htreg->iterators, id); +} + +const char* htreg_iterator_nextkey(int64 id) +{ + struct DBIterator *it = i64db_get(htreg->iterators, id); + if (it) + { + union DBKey key; + it->next(it, &key); + if (dbi_exists(it)) + return key.str; + } + return NULL; +} + +/** + * Initializer. + */ +void htreg_init(void) +{ + htreg->htables = i64db_alloc(DB_OPT_BASE); + htreg->iterators = i64db_alloc(DB_OPT_BASE); +} + +/** + * Finalizer. + */ +void htreg_final(void) +{ + struct DBIterator *iter = db_iterator(htreg->htables); + struct DBMap *ht; + + for(ht=dbi_first(iter); dbi_exists(iter); ht=dbi_next(iter)) + db_destroy(ht); + + dbi_destroy(iter); + db_destroy(htreg->htables); + + // NOTE: maybe I should destroy iteratos before hashtables + struct DBIterator *it; + iter = db_iterator(htreg->iterators); + + for (it=dbi_first(iter); dbi_exists(iter); it=dbi_next(iter)) + dbi_destroy(it); + + dbi_destroy(iter); + db_destroy(htreg->iterators); +} + +/** + * Interface defaults initializer. + */ +void htreg_defaults(void) +{ + htreg = &htreg_s; + + htreg->last_id = 1; + htreg->htables = NULL; + htreg->init = htreg_init; + htreg->final = htreg_final; + htreg->new_hashtable = htreg_new_hashtable; + htreg->destroy_hashtable = htreg_destroy_hashtable; + htreg->hashtable_exists = htreg_hashtable_exists; + htreg->hashtable_size = htreg_hashtable_size; + htreg->clear_hashtable = htreg_clear_hashtable; + htreg->hashtable_getvalue = htreg_hashtable_getvalue; + htreg->hashtable_setvalue = htreg_hashtable_setvalue; + + htreg->last_iterator_id = 1; + htreg->iterators = NULL; + htreg->create_iterator = htreg_create_iterator; + htreg->destroy_iterator = htreg_destroy_iterator; + htreg->iterator_check = htreg_iterator_check; + htreg->iterator_exists = htreg_iterator_exists; + htreg->iterator_nextkey = htreg_iterator_nextkey; +} diff --git a/src/emap/hashtable.h b/src/emap/hashtable.h new file mode 100644 index 0000000..44712cd --- /dev/null +++ b/src/emap/hashtable.h @@ -0,0 +1,43 @@ +// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL. +// Copyright (c) 2015 - 2016 Evol developers + +#ifndef EVOL_HASH_TABLE +#define EVOL_HASH_TABLE + +#include "common/hercules.h" +#include "common/db.h" + +#define HT_MAX_KEY_LEN 32 + +struct htreg_interface +{ + int64 last_id; + int64 last_iterator_id; + struct DBMap *htables; + struct DBMap *iterators; + void (*init) (void); + void (*final) (void); + int64 (*new_hashtable) (void); + bool (*destroy_hashtable) (int64 id); + bool (*hashtable_exists) (int64 id); + int64 (*hashtable_size) (int64 id); + bool (*clear_hashtable) (int64 id); + const struct DBData* (*hashtable_getvalue) (int64 id, const char *key, + const struct DBData *defval); + bool (*hashtable_setvalue) (int64 id, const char *key, + const struct DBData value); + + int64 (*create_iterator) (int64 id); + bool (*destroy_iterator) (int64 id); + bool (*iterator_check) (int64 id); + bool (*iterator_exists) (int64 id); + const char* (*iterator_nextkey) (int64 id); +}; + +void htreg_defaults(void); +void htreg_init(void); +void htreg_final(void); + +HPShared struct htreg_interface *htreg; + +#endif // EVOL_HASH_TABLE diff --git a/src/emap/init.c b/src/emap/init.c index d75f2c2..3a586dd 100644 --- a/src/emap/init.c +++ b/src/emap/init.c @@ -49,6 +49,7 @@ #include "emap/config.h" #include "emap/craft.h" #include "emap/craftconf.h" +#include "emap/hashtable.h" #include "emap/itemdb.h" #include "emap/lang.h" #include "emap/mail.h" @@ -84,6 +85,7 @@ HPExport void plugin_init (void) { isInit = false; status_init(); + htreg_init(); addAtcommand("setskill", setSkill); addAtcommand("slide", slide); @@ -155,6 +157,16 @@ HPExport void plugin_init (void) addScriptCommand("setskin", "s", setSkin); addScriptCommand("emotion", "i??", emotion); addScriptCommand("setlook", "ii", setLook); + addScriptCommand("htnew", "", htNew); + addScriptCommand("htget", "is?", htGet); + addScriptCommand("htput", "isv", htPut); + addScriptCommand("htclear", "i", htClear); + addScriptCommand("htdelete", "i", htDelete); + addScriptCommand("htsize", "i", htSize); + addScriptCommand("htiterator", "i", htIterator); + addScriptCommand("htinextkey", "i", htiNextKey); + addScriptCommand("hticheck", "i", htiCheck); + addScriptCommand("htidelete", "i", htiDelete); do_init_langs(); @@ -276,6 +288,7 @@ HPExport void plugin_init (void) HPExport void server_preinit (void) { interfaces_init_common(); + htreg_defaults(); setDefaultMap(); addMapInterConf("default_map", config_default_map); @@ -301,5 +314,6 @@ HPExport void plugin_final (void) do_final_craft(); do_final_craftconf(); commonClean(); + htreg_final(); isInit = false; } diff --git a/src/emap/script_buildins.c b/src/emap/script_buildins.c index e37026d..a7b51fb 100644 --- a/src/emap/script_buildins.c +++ b/src/emap/script_buildins.c @@ -22,6 +22,7 @@ #include "emap/craft.h" #include "emap/lang.h" #include "emap/map.h" +#include "emap/hashtable.h" #include "emap/scriptdefines.h" #include "emap/send.h" #include "emap/data/bgd.h" @@ -1803,3 +1804,183 @@ BUILDIN(setLook) send_changelook2(sd, &sd->bl, sd->bl.id, type, val, 0, NULL, 0, AREA); return true; } + +#define checkHashTableExists(id) \ + if (!htreg->hashtable_exists(id)) \ + { \ + ShowError("%s: hashtable with id=%ld does not exist\n", __func__, id); \ + script_pushint(st, 0); \ + return false; \ + } + +BUILDIN(htNew) +{ + int64 id = htreg->new_hashtable(); + script_pushint(st, id); + return true; +} + +BUILDIN(htGet) +{ + int64 id = script_getnum(st, 2); + checkHashTableExists(id); + + struct DBData defval_s; + struct DBData *defval = &defval_s; + const char * key = script_getstr(st, 3); + + if (script_hasdata(st, 4)) + { + if (script_isstringtype(st, 4)) + { + defval->type = DB_DATA_PTR; + defval->u.ptr = (void*)script_getstr(st, 4); + } + else if (script_isinttype(st, 4)) + { + defval->type = DB_DATA_INT; + defval->u.i = script_getnum(st, 4); + } + else + { + ShowError("usage: htget(, [ ,])\n"); + return false; + } + } + else + { + defval = NULL; + } + + const struct DBData *result = htreg->hashtable_getvalue(id, key, defval); + if (result) + { + switch(result->type) + { + case DB_DATA_INT: + case DB_DATA_UINT: + script_pushint(st, result->u.i); + break; + case DB_DATA_PTR: + script_pushstrcopy(st, result->u.ptr); + break; + } + } + else + { + script_pushint(st, 0); + } + + return true; +} + +BUILDIN(htPut) +{ + int64 id = script_getnum(st, 2); + checkHashTableExists(id); + + struct DBData value; + const char * key = script_getstr(st, 3); + + if (script_isstringtype(st, 4)) + { + value.type = DB_DATA_PTR; + value.u.ptr = (void*)aStrdup(script_getstr(st, 4)); + } + else if (script_isinttype(st, 4)) + { + value.type = DB_DATA_INT; + value.u.i = script_getnum(st, 4); + } + else + { + ShowError("usage: htput(, , )\n"); + return false; + } + + htreg->hashtable_setvalue(id, key, value); + return true; +} + +BUILDIN(htClear) +{ + int64 id = script_getnum(st, 2); + checkHashTableExists(id); + + htreg->clear_hashtable(id); + return true; +} + +BUILDIN(htDelete) +{ + int64 id = script_getnum(st, 2); + checkHashTableExists(id); + + htreg->destroy_hashtable(id); + return true; +} + +BUILDIN(htSize) +{ + int64 id = script_getnum(st, 2); + checkHashTableExists(id); + + script_pushint(st, htreg->hashtable_size(id)); + return true; +} + +BUILDIN(htIterator) +{ + int64 id = script_getnum(st, 2); + checkHashTableExists(id); + + script_pushint(st, htreg->create_iterator(id)); + return true; +} + +#undef checkHashTableExists + +#define checkHtIteratorExists(id) \ + if (!htreg->iterator_exists(id)) \ + { \ + ShowError("%s: htIterator with id=%ld does not exist\n", __func__, id); \ + script_pushint(st, 0); \ + return false; \ + } + +BUILDIN(htiNextKey) +{ + int64 id = script_getnum(st, 2); + checkHtIteratorExists(id); + + const char * key = htreg->iterator_nextkey(id); + if (key) + script_pushstrcopy(st, key); + else + script_pushstrcopy(st, ""); + return true; +} + +BUILDIN(htiCheck) +{ + int64 id = script_getnum(st, 2); + checkHtIteratorExists(id); + + if (htreg->iterator_check(id)) + script_pushint(st, 1); + else + script_pushint(st, 0); + + return true; +} + +BUILDIN(htiDelete) +{ + int64 id = script_getnum(st, 2); + checkHtIteratorExists(id); + + htreg->destroy_iterator(id); + return true; +} + +#undef checkHtIteratorExists diff --git a/src/emap/script_buildins.h b/src/emap/script_buildins.h index 1d83813..6eb109b 100644 --- a/src/emap/script_buildins.h +++ b/src/emap/script_buildins.h @@ -71,5 +71,15 @@ BUILDIN(findCraftEntry); BUILDIN(useCraft); BUILDIN(getCraftCode); BUILDIN(setLook); +BUILDIN(htNew); +BUILDIN(htGet); +BUILDIN(htPut); +BUILDIN(htClear); +BUILDIN(htDelete); +BUILDIN(htSize); +BUILDIN(htIterator); +BUILDIN(htiNextKey); +BUILDIN(htiCheck); +BUILDIN(htiDelete); #endif // EVOL_MAP_SCRIPT_BUILDINS -- cgit v1.2.3-60-g2f50