index: Remove the index class

This patch updates the design so indexes are built upon databases using
a special IndexEntry.  I also updated the tests/index/ test to match
the new system, but I have not updated filter or group tests yet.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
This commit is contained in:
Anna Schumaker 2013-12-01 22:31:35 -05:00 committed by Anna Schumaker
parent f0533ef663
commit 97d889531a
13 changed files with 183 additions and 255 deletions

1
config
View File

@ -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()

View File

@ -46,7 +46,7 @@ Database: (lib/database.cpp)
class IndexEntry : public DatabaseEntry {
public:
string key;
vector<unsigned int> values;
set<unsigned int> 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 <class T>
unsigned int Database :: insert(T &);
Adds a new item to the db and marks it as valid. A reverse

View File

@ -8,6 +8,7 @@
#include <print.h>
#include <map>
#include <set>
#include <vector>
@ -25,6 +26,23 @@ public:
};
class IndexEntry : public DatabaseEntry {
public:
std::string key;
std::set<unsigned int> 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 T>
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<IndexEntry> &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<IndexEntry> &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 */

View File

@ -48,6 +48,7 @@ void Database<T> :: load()
file >> db[i].valid;
if (db[i].valid == true) {
db[i].read(file);
keys.insert(std::pair<std::string, unsigned int>(db[i].primary_key(), i));
_size++;
}
}
@ -76,6 +77,16 @@ void Database<T> :: print()
}
}
}
template <class T>
void Database<T> :: print_keys()
{
std::map<const std::string, unsigned int>::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 <class T>
@ -102,6 +113,7 @@ unsigned int Database<T> :: insert(T val)
template <class T>
void Database<T> :: remove(unsigned int id)
{
keys.erase(db[id].primary_key());
db[id].valid = false;
_size--;
}
@ -154,6 +166,22 @@ unsigned int Database<T> :: next(unsigned int id)
return db.size();
}
template <class T>
unsigned int Database<T> :: find_index(const std::string &key)
{
std::map<std::string, unsigned int>::iterator it;
it = keys.find(key);
if (it == keys.end())
throw 0;
return it->second;
}
template <class T>
T &Database<T> :: find(const std::string &key)
{
return db[find_index(key)];
}
template <class T>
T &Database<T> :: operator[](unsigned int id)
{

View File

@ -4,7 +4,7 @@
#ifndef OCARINA_FILTER_H
#define OCARINA_FILTER_H
#include <index.h>
#include <database.h>
#include <string>
namespace filter {
@ -15,7 +15,7 @@ namespace filter {
void print_cache_stats();
#ifdef CONFIG_TEST
Index &get_index();
Database<IndexEntry> &get_index();
#endif /* CONFIG_TEST */
};

View File

@ -1,38 +0,0 @@
/*
* Copyright 2013 (c) Anna Schumaker.
*/
#ifndef OCARINA_INDEX_H
#define OCARINA_INDEX_H
#include <file.h>
#include <print.h>
#include <map>
#include <set>
#include <string>
class Index {
private:
std::map<std::string, std::set<unsigned int> > index;
std::set<std::string> 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<std::string>::iterator keys_begin();
const std::set<std::string>::iterator keys_end();
const std::set<unsigned int> &operator[](const std::string &);
};
#endif /* OCARINA_INDEX_H */

View File

@ -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" ]),
###########################

View File

@ -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<unsigned int>::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<unsigned int>::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);
}

View File

@ -3,7 +3,6 @@
*/
#include <filter.h>
#include <index.h>
#include <print.h>
#include <algorithm>
@ -11,7 +10,7 @@
#include <map>
#include <set>
static Index filter_index("");
static Database<IndexEntry> filter_index("");
static std::map<std::string, std::string> lowercase_cache;
static unsigned int lowercase_cache_hits = 0;
@ -89,8 +88,15 @@ static void parse_text(const std::string &text, std::list<std::string> &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<IndexEntry> &filter :: get_index()
{
return filter_index;
}

View File

@ -1,120 +0,0 @@
/*
* Copyright 2013 (c) Anna Schumaker.
*/
#include <index.h>
Index :: Index(std::string filepath)
: file(filepath, FILE_TYPE_DATA)
{
}
void Index :: save()
{
std::set<std::string>::iterator k_it;
std::set<unsigned int>::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<std::string>::iterator s_it;
std::set<unsigned int>::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<std::string>::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<unsigned int>();
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<std::string>::iterator Index :: keys_begin()
{
return keys.begin();
}
const std::set<std::string>::iterator Index :: keys_end()
{
return keys.end();
}
const std::set<unsigned int> &Index :: operator[](const std::string &key)
{
return index[key];
}

View File

@ -1,6 +1,6 @@
#!/usr/bin/python
Import("Test", "CONFIG")
CONFIG.INDEX = True
CONFIG.DATABASE = True
Test("index", "index.cpp")

View File

@ -1,74 +1,56 @@
/*
* Copyright 2013 (c) Anna Schumaker.
*/
#include <index.h>
#include <database.h>
#include <print.h>
void print_keys(Index &index)
{
std::set<std::string>::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<IndexEntry> &index)
{
std::set<std::string>::iterator s_it;
std::set<unsigned int>::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<IndexEntry> &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<IndexEntry> &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<IndexEntry> &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<IndexEntry> index("");
populate_index(index);
print_index(index);
@ -93,7 +75,7 @@ void test_0()
void test_1()
{
print("Test 1\n");
Index index("");
Database<IndexEntry> index("");
populate_index(index);
remove_keys(index);
@ -106,7 +88,7 @@ void test_1()
void test_2()
{
print("Test 2\n");
Index index("");
Database<IndexEntry> 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<IndexEntry> 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<IndexEntry> 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<IndexEntry> 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;
}

View File

@ -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}