diff --git a/config b/config index d58d2cb7..cb6e9362 100644 --- a/config +++ b/config @@ -39,7 +39,6 @@ class Config: self.FILTER = False self.GROUP = False self.IDLE = False - self.INDEX = False self.LIBRARY = False self.TEST = TEST self.reconfigure() diff --git a/design/database.txt b/design/database.txt index 296a8975..ebb74aa3 100644 --- a/design/database.txt +++ b/design/database.txt @@ -46,7 +46,7 @@ Database: (lib/database.cpp) class IndexEntry : public DatabaseEntry { public: string key; - vector values; + set values; const std::string &primary_key(); void write(File &); @@ -71,6 +71,7 @@ Database: (lib/database.cpp) void save(); void clear(); void print(); + void print_keys(); unsigned int insert(T); void delete(unsigned int); @@ -80,7 +81,8 @@ Database: (lib/database.cpp) unsigned int first(); unsigned int last(); unsigned int next(unsigned int &); - unsigned int find(const std::string &); + unsigned int find_index(const std::string &); + T &find(const std::string &); T &operator[](unsigned int); }; @@ -110,6 +112,10 @@ Database: (lib/database.cpp) Following a similar format for writing to disk, print the database to the console in a human-readable format. + void Database :: print_keys() + This function exists only if CONFIG_DEBUG is enabled. + Print out the collected primary keys in the database. + template unsigned int Database :: insert(T &); Adds a new item to the db and marks it as valid. A reverse diff --git a/include/database.h b/include/database.h index 186e3e98..75e68651 100644 --- a/include/database.h +++ b/include/database.h @@ -8,6 +8,7 @@ #include #include +#include #include @@ -25,6 +26,23 @@ public: }; +class IndexEntry : public DatabaseEntry { +public: + std::string key; + std::set values; + + IndexEntry(); + IndexEntry(const std::string &, unsigned int); + ~IndexEntry(); + const std::string &primary_key(); + void write(File &); + void read(File &); + void print(); + void insert(unsigned int); + void remove(unsigned int); +}; + + template class Database { private: @@ -41,6 +59,7 @@ public: #ifdef CONFIG_DEBUG void clear(); void print(); + void print_keys(); #endif /* CONFIG_DEBUG */ unsigned int insert(T); @@ -51,9 +70,32 @@ public: unsigned int first(); unsigned int last(); unsigned int next(unsigned int); + unsigned int find_index(const std::string &); + T &find(const std::string &); T &operator[](unsigned int); }; +static inline void index_insert(Database &db, + const std::string &key, + unsigned int val) +{ + try { + db.find(key).insert(val); + } catch (...) { + db.insert(IndexEntry(key, val)); + } +} + +static inline void index_remove(Database &db, + const std::string &key, + unsigned int val) +{ + unsigned int i = db.find_index(key); + db[i].remove(val); + if (db[i].values.size() == 0) + db.remove(db.find_index(key)); +} + #include "database.hpp" #endif /* OCARINA_DATABASE_H */ diff --git a/include/database.hpp b/include/database.hpp index 6188d2e2..05380c32 100644 --- a/include/database.hpp +++ b/include/database.hpp @@ -48,6 +48,7 @@ void Database :: load() file >> db[i].valid; if (db[i].valid == true) { db[i].read(file); + keys.insert(std::pair(db[i].primary_key(), i)); _size++; } } @@ -76,6 +77,16 @@ void Database :: print() } } } + +template +void Database :: print_keys() +{ + std::map::iterator it; + :: print("Found keys:"); + for (it = keys.begin(); it != keys.end(); it++) + :: print(" %s", it->first.c_str()); + :: print("\n"); +} #endif /* CONFIG_DEBUG */ template @@ -102,6 +113,7 @@ unsigned int Database :: insert(T val) template void Database :: remove(unsigned int id) { + keys.erase(db[id].primary_key()); db[id].valid = false; _size--; } @@ -154,6 +166,22 @@ unsigned int Database :: next(unsigned int id) return db.size(); } +template +unsigned int Database :: find_index(const std::string &key) +{ + std::map::iterator it; + it = keys.find(key); + if (it == keys.end()) + throw 0; + return it->second; +} + +template +T &Database :: find(const std::string &key) +{ + return db[find_index(key)]; +} + template T &Database :: operator[](unsigned int id) { diff --git a/include/filter.h b/include/filter.h index d16c8bf7..1ec2061a 100644 --- a/include/filter.h +++ b/include/filter.h @@ -4,7 +4,7 @@ #ifndef OCARINA_FILTER_H #define OCARINA_FILTER_H -#include +#include #include namespace filter { @@ -15,7 +15,7 @@ namespace filter { void print_cache_stats(); #ifdef CONFIG_TEST - Index &get_index(); + Database &get_index(); #endif /* CONFIG_TEST */ }; diff --git a/include/index.h b/include/index.h deleted file mode 100644 index 5c66bda0..00000000 --- a/include/index.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2013 (c) Anna Schumaker. - */ -#ifndef OCARINA_INDEX_H -#define OCARINA_INDEX_H - -#include -#include - -#include -#include -#include - -class Index { -private: - std::map > index; - std::set keys; - File file; - -public: - Index(std::string); - void save(); - void load(); -#ifdef CONFIG_DEBUG - void print(); - void print_keys(); -#endif /* CONFIG_DEBUG */ - - void insert(std::string, unsigned int); - void remove(std::string); - void remove(std::string, unsigned int); - - const std::set::iterator keys_begin(); - const std::set::iterator keys_end(); - const std::set &operator[](const std::string &); -}; - -#endif /* OCARINA_INDEX_H */ diff --git a/lib/Sconscript b/lib/Sconscript index 52690be8..a77d6888 100644 --- a/lib/Sconscript +++ b/lib/Sconscript @@ -17,10 +17,9 @@ modules = { "DATABASE" : Module("database.cpp", depends = [ "FILE" ]), "FILE" : Module("file.cpp", package = "glib-2.0"), - "FILTER" : Module("filter.cpp", depends = [ "INDEX" ]), + "FILTER" : Module("filter.cpp", depends = [ "DATABASE" ]), "GROUP" : Module("group.cpp", depends = [ "INDEX" ]), "IDLE" : Module("idle.cpp"), - "INDEX" : Module("index.cpp", depends = [ "FILE" ]), "LIBRARY" : Module("library.cpp", package = "taglib", depends = [ "DATABASE", "IDLE" ]), ########################### diff --git a/lib/database.cpp b/lib/database.cpp index 05f4f071..4cde2e0c 100644 --- a/lib/database.cpp +++ b/lib/database.cpp @@ -7,3 +7,65 @@ DatabaseEntry :: DatabaseEntry() : valid(false) { } + + + +IndexEntry :: IndexEntry() +{ +} + +IndexEntry :: IndexEntry(const std::string &k, unsigned int v) + : key(k) +{ + insert(v); +} + +IndexEntry :: ~IndexEntry() +{ +} + +const std::string &IndexEntry :: primary_key() +{ + return key; +} + +void IndexEntry :: write(File &f) +{ + std::set::iterator it; + f << key << std::endl << values.size() << " "; + for (it = values.begin(); it != values.end(); it++) + f << *it << " "; +} + +void IndexEntry :: read(File &f) +{ + unsigned int num, val; + + f >> key >> num; + for (unsigned int i = 0; i < num; i++) { + f >> val; + values.insert(val); + } +} + +void IndexEntry :: print() +{ + std::set::iterator it; + :: print("{"); + for (it = values.begin(); it != values.end(); it++) { + if (it != values.begin()) + :: print(" "); + :: print("%d", *it); + } + :: print("}"); +} + +void IndexEntry :: insert(unsigned int val) +{ + values.insert(val); +} + +void IndexEntry :: remove(unsigned int val) +{ + values.erase(val); +} diff --git a/lib/filter.cpp b/lib/filter.cpp index 4cc9a756..64bd62e2 100644 --- a/lib/filter.cpp +++ b/lib/filter.cpp @@ -3,7 +3,6 @@ */ #include -#include #include #include @@ -11,7 +10,7 @@ #include #include -static Index filter_index(""); +static Database filter_index(""); static std::map lowercase_cache; static unsigned int lowercase_cache_hits = 0; @@ -89,8 +88,15 @@ static void parse_text(const std::string &text, std::list &ret) static void add_substrings(const std::string &text, unsigned int track_id) { - for (unsigned int i = 1; i <= text.size(); i++) - filter_index.insert(text.substr(0, i), track_id); + std::string substr; + for (unsigned int i = 1; i <= text.size(); i++) { + substr = text.substr(0, i); + try { + filter_index.find(substr).insert(track_id); + } catch (...) { + filter_index.insert(IndexEntry(substr, track_id)); + } + } } void filter :: add(const std::string &text, unsigned int track_id) @@ -137,7 +143,7 @@ void filter :: print_cache_stats() } #ifdef CONFIG_TEST -Index &filter :: get_index() +Database &filter :: get_index() { return filter_index; } diff --git a/lib/index.cpp b/lib/index.cpp deleted file mode 100644 index 8144f986..00000000 --- a/lib/index.cpp +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright 2013 (c) Anna Schumaker. - */ - -#include - -Index :: Index(std::string filepath) - : file(filepath, FILE_TYPE_DATA) -{ - -} - -void Index :: save() -{ - std::set::iterator k_it; - std::set::iterator u_it; - - if (file.open(OPEN_WRITE) == false) - return; - - file << keys.size(); - for (k_it = keys.begin(); k_it != keys.end(); k_it++) { - file << *k_it << std::endl; - file << index[*k_it].size() << " "; - - for (u_it = index[*k_it].begin(); u_it != index[*k_it].end(); u_it++) - file << *u_it << " "; - - file << std::endl; - } - - file.close(); -} - -void Index :: load() -{ - std::string key; - unsigned int num_keys, num_values, value; - - if (file.open(OPEN_READ) == false) - return; - - file >> num_keys; - for (unsigned int i = 0; i < num_keys; i++) { - file >> key >> num_values; - for (unsigned int j = 0; j < num_values; j++) { - file >> value; - insert(key, value); - } - } - - file.close(); -} - -void Index :: print() -{ - std::set::iterator s_it; - std::set::iterator u_it; - - for (s_it = keys.begin(); s_it != keys.end(); s_it++) { - std::string key = *s_it; - :: print("index[%s] = {", key.c_str()); - - for (u_it = index[key].begin(); u_it != index[key].end(); u_it++) { - if (u_it != index[key].begin()) - :: print(" "); - :: print("%d", *u_it); - } - - :: print("}\n"); - } - :: print("\n"); -} - -void Index :: print_keys() -{ - std::set::iterator it; - - :: print("Keys:"); - for (it = keys.begin(); it != keys.end(); it++) - :: print(" %s", it->c_str()); - :: print("\n"); -} - -void Index :: insert(std::string key, unsigned int value) -{ - if (index.find(key) == index.end()) { - index[key] = std::set(); - keys.insert(key); - } - index[key].insert(value); -} - -void Index :: remove(std::string key) -{ - index.erase(key); - keys.erase(key); -} - -void Index :: remove(std::string key, unsigned int value) -{ - index[key].erase(value); - if (index[key].size() == 0) - remove(key); -} - -const std::set::iterator Index :: keys_begin() -{ - return keys.begin(); -} - -const std::set::iterator Index :: keys_end() -{ - return keys.end(); -} - -const std::set &Index :: operator[](const std::string &key) -{ - return index[key]; -} diff --git a/tests/index/Sconscript b/tests/index/Sconscript index c5b0360d..e80c209d 100644 --- a/tests/index/Sconscript +++ b/tests/index/Sconscript @@ -1,6 +1,6 @@ #!/usr/bin/python Import("Test", "CONFIG") -CONFIG.INDEX = True +CONFIG.DATABASE = True Test("index", "index.cpp") diff --git a/tests/index/index.cpp b/tests/index/index.cpp index 66a11719..f9534a5a 100644 --- a/tests/index/index.cpp +++ b/tests/index/index.cpp @@ -1,74 +1,56 @@ /* * Copyright 2013 (c) Anna Schumaker. */ -#include +#include #include -void print_keys(Index &index) -{ - std::set::iterator it; - - print("Found keys:"); - for (it = index.keys_begin(); it != index.keys_end(); it++) - print(" %s", it->c_str()); - print("\n"); -} - -void print_index(Index &index) +void print_index(Database &index) { std::set::iterator s_it; std::set::iterator u_it; print("=== Printing index ===\n"); - print_keys(index); + index.print_keys(); - for (s_it = index.keys_begin(); s_it != index.keys_end(); s_it++) { - std::string key = *s_it; - print("index[%s] = {", key.c_str()); - - for (u_it = index[key].begin(); u_it != index[key].end(); u_it++) { - if (u_it != index[key].begin()) - print(" "); - print("%d", *u_it); - } - - print("}\n"); + for (unsigned int i = index.first(); i != index.num_rows(); i = index.next(i)) { + print("index[%s] = ", index[i].key.c_str()); + index[i].print(); + print("\n"); } + print("\n"); } -void populate_index(Index &index) +void populate_index(Database &index) { std::string key_str; for (char key = 'a'; key <= 'z'; key++) { key_str = key; - for (unsigned int value = 0; value < 10; value++) { - index.insert(key_str, value); - } + for (unsigned int value = 0; value < 10; value++) + index_insert(index, key_str, value); } } -void remove_keys(Index &index) +void remove_keys(Database &index) { std::string key_str; for (char key = 'a'; key <= 'z'; key+=2) { key_str = key; - index.remove(key_str); + index.remove(index.find_index(key_str)); } } -void remove_values(Index &index) +void remove_values(Database &index) { std::string key_str; unsigned int limit = 0; for (char key = 'a'; key <= 'z'; key++) { key_str = key; - for (unsigned int i = 0; i < limit; i++) { - index.remove(key_str, i); - } + for (unsigned int i = 0; i < limit; i++) + index_remove(index, key_str, i); limit++; if (limit == 11) limit = 0; @@ -81,7 +63,7 @@ void remove_values(Index &index) void test_0() { print("Test 0\n"); - Index index(""); + Database index(""); populate_index(index); print_index(index); @@ -93,7 +75,7 @@ void test_0() void test_1() { print("Test 1\n"); - Index index(""); + Database index(""); populate_index(index); remove_keys(index); @@ -106,7 +88,7 @@ void test_1() void test_2() { print("Test 2\n"); - Index index(""); + Database index(""); populate_index(index); remove_values(index); @@ -119,7 +101,7 @@ void test_2() void test_3() { print("Test 3\n"); - Index index("test.idx"); + Database index("test.idx"); populate_index(index); remove_values(index); @@ -132,7 +114,7 @@ void test_3() void test_4() { print("Test 4\n"); - Index index("test.idx"); + Database index("test.idx"); index.load(); print_index(index); @@ -144,21 +126,13 @@ void test_4() void test_5() { print("Test 5\n"); - Index index(""); - print("index[nokey].size() = %u\n", index["nokey"].size()); -} - -/* - * Test the print() function - */ -void test_6() -{ - print("Test 6\n"); - Index index(""); - - populate_index(index); - index.print_keys(); - index.print(); + Database index(""); + print("index[nokey].size() = "); + try { + print("%u\n", index.find("nokey").values.size()); + } catch (...) { + print("0\n"); + } } int main(int argc, char **argv) @@ -169,6 +143,5 @@ int main(int argc, char **argv) test_3(); test_4(); test_5(); - test_6(); return 0; } diff --git a/tests/index/index.good b/tests/index/index.good index f004a297..d6c4e5fa 100644 --- a/tests/index/index.good +++ b/tests/index/index.good @@ -104,32 +104,3 @@ index[z] = {3 4 5 6 7 8 9} Test 5 index[nokey].size() = 0 -Test 6 -Keys: a b c d e f g h i j k l m n o p q r s t u v w x y z -index[a] = {0 1 2 3 4 5 6 7 8 9} -index[b] = {0 1 2 3 4 5 6 7 8 9} -index[c] = {0 1 2 3 4 5 6 7 8 9} -index[d] = {0 1 2 3 4 5 6 7 8 9} -index[e] = {0 1 2 3 4 5 6 7 8 9} -index[f] = {0 1 2 3 4 5 6 7 8 9} -index[g] = {0 1 2 3 4 5 6 7 8 9} -index[h] = {0 1 2 3 4 5 6 7 8 9} -index[i] = {0 1 2 3 4 5 6 7 8 9} -index[j] = {0 1 2 3 4 5 6 7 8 9} -index[k] = {0 1 2 3 4 5 6 7 8 9} -index[l] = {0 1 2 3 4 5 6 7 8 9} -index[m] = {0 1 2 3 4 5 6 7 8 9} -index[n] = {0 1 2 3 4 5 6 7 8 9} -index[o] = {0 1 2 3 4 5 6 7 8 9} -index[p] = {0 1 2 3 4 5 6 7 8 9} -index[q] = {0 1 2 3 4 5 6 7 8 9} -index[r] = {0 1 2 3 4 5 6 7 8 9} -index[s] = {0 1 2 3 4 5 6 7 8 9} -index[t] = {0 1 2 3 4 5 6 7 8 9} -index[u] = {0 1 2 3 4 5 6 7 8 9} -index[v] = {0 1 2 3 4 5 6 7 8 9} -index[w] = {0 1 2 3 4 5 6 7 8 9} -index[x] = {0 1 2 3 4 5 6 7 8 9} -index[y] = {0 1 2 3 4 5 6 7 8 9} -index[z] = {0 1 2 3 4 5 6 7 8 9} -