#pragma once #include "int.qh" // Databases (hash tables) const int DB_BUCKETS = 8192; void db_save(int db, string filename) { int fh = fopen(filename, FILE_WRITE); if (fh < 0) { LOG_WARNF("^1Can't write DB to %s", filename); return; } fputs(fh, strcat(ftos(DB_BUCKETS), "\n")); for (int i = 0, n = buf_getsize(db); i < n; ++i) fputs(fh, strcat(bufstr_get(db, i), "\n")); fclose(fh); } USING(HashMap, int); int db_create() { return buf_create(); } #define HM_NEW(this) (this = db_create()) void db_put(int db, string key, string value); int db_load(string filename) { int db = buf_create(); if (db < 0) return -1; int fh = fopen(filename, FILE_READ); if (fh < 0) return db; string l = fgets(fh); if (stoi(l) == DB_BUCKETS) { for (int i = 0; (l = fgets(fh)); ++i) { if (l != "") bufstr_set(db, i, l); } } else { // different count of buckets, or a dump? // need to reorganize the database then (SLOW) // // note: we also parse the first line (l) in case the DB file is // missing the bucket count do { int n = tokenizebyseparator(l, "\\"); for (int j = 2; j < n; j += 2) db_put(db, argv(j - 1), uri_unescape(argv(j))); } while ((l = fgets(fh))); } fclose(fh); return db; } void db_dump(int db, string filename) { int fh = fopen(filename, FILE_WRITE); if (fh < 0) LOG_FATALF("Can't dump DB to %s"); fputs(fh, "0\n"); for (int i = 0, n = buf_getsize(db); i < n; ++i) { int m = tokenizebyseparator(bufstr_get(db, i), "\\"); for (int j = 2; j < m; j += 2) fputs(fh, strcat("\\", argv(j - 1), "\\", argv(j), "\n")); } fclose(fh); } void db_close(int db) { buf_del(db); } #define HM_DELETE(this) db_close(this) string db_get(int db, string key) { int h = crc16(false, key) % DB_BUCKETS; return uri_unescape(infoget(bufstr_get(db, h), key)); } #define HM_gets(this, k) db_get(this, k) #define db_remove(db, key) db_put(db, key, "") void db_put(int db, string key, string value) { int h = crc16(false, key) % DB_BUCKETS; bufstr_set(db, h, infoadd(bufstr_get(db, h), key, uri_escape(value))); } #define HM_sets(this, key, val) db_put(this, key, val) void db_test() { LOG_INFO("LOAD...\n"); int db = db_load("foo.db"); LOG_INFO("LOADED. FILL...\n"); for (int i = 0; i < DB_BUCKETS; ++i) db_put(db, ftos(random()), "X"); LOG_INFO("FILLED. SAVE...\n"); db_save(db, "foo.db"); LOG_INFO("SAVED. CLOSE...\n"); db_close(db); LOG_INFO("CLOSED.\n"); }