patterncMinor
Creating a common interface
Viewed 0 times
creatinginterfacecommon
Problem
I have a sort of database with a many-to-many association between tags and files. For various reasons, I decided to forgo a junction table in favor of having the left and right tables store the associated values in the tables themselves. However I've ended up writing code like this:
Where only a few identifiers change, but basically the same thing happens, just on different sides. Is there a simpler, less error prone way to do this in c? Maybe with macros?
GHashTable *tagdb_get_tag_files (tagdb *db, int tag_code)
{
return g_hash_table_lookup(db->reverse, GINT_TO_POINTER(tag_code));
}
GHashTable *tagdb_get_file_tags (tagdb *db, int file_id)
{
return g_hash_table_lookup(db->forward, GINT_TO_POINTER(file_id));
}
void tagdb_remove_tag (tagdb *db, int id)
{
GHashTable *its_files = g_hash_table_lookup(db->reverse, GINT_TO_POINTER(id));
if (its_files == NULL)
{
return;
}
GHashTableIter it;
gpointer key, value;
g_hash_table_iter_init(&it, its_files);
if (g_hash_table_iter_next(&it, &key, &value))
{
tagdb_remove_tag_from_file(db, id, key);
}
g_hash_table_remove(db->reverse, GINT_TO_POINTER(id));
}
void tagdb_remove_file(tagdb *db, int id)
{
GHashTable *its_tags = g_hash_table_lookup(db->forward, GINT_TO_POINTER(id));
if (its_tags == NULL)
{
return;
}
GHashTableIter it;
gpointer key, value;
g_hash_table_iter_init(&it, its_tags);
if (g_hash_table_iter_next(&it, &key, &value))
{
tagdb_remove_file_from_tag(db, id, key);
}
g_hash_table_remove(db->forward, GINT_TO_POINTER(id));
}Where only a few identifiers change, but basically the same thing happens, just on different sides. Is there a simpler, less error prone way to do this in c? Maybe with macros?
Solution
You can pass a function that gets the correct object from tagdb.
AKA Service Locator pattern
Edit for clarity:
The old functions can now be implanted like this:
AKA Service Locator pattern
typedef HashTable* (*ITEM_GETTER)(tagdb*);
HashTable* getTag(tagdb *db) { return db->reverse;}
HashTable* getFile(tagdb *db) { return db->forward;}
GHashTable *tagdb_get_item_files (tagdb *db, int itemId, ITEM_GETTER getter)
{
return g_hash_table_lookup(getter(db), GINT_TO_POINTER(itemId));
}
void tagdb_remove_item (tagdb *db, int id, ITEM_GETTER getter)
{
GHashTable *its_files = g_hash_table_lookup(getter(db), GINT_TO_POINTER(id));
if (its_files == NULL)
{
return;
}
GHashTableIter it;
gpointer key, value;
g_hash_table_iter_init(&it, its_files);
if (g_hash_table_iter_next(&it, &key, &value))
{
tagdb_remove_tag_from_file(db, id, key);
}
g_hash_table_remove(getter(db), GINT_TO_POINTER(id));
}Edit for clarity:
The old functions can now be implanted like this:
GHashTable *tagdb_get_tag_files (tagdb *db, int tag_code)
{
return tagdb_get_item_files(db, tag_code, getTag);
}
GHashTable *tagdb_get_file_tags (tagdb *db, int file_id)
{
return return tagdb_get_item_files(db, file_id, getFile);
}
void tagdb_remove_tag (tagdb *db, int id)
{
tagdb_remove_item(db, id, getTag);
}
void tagdb_remove_file(tagdb *db, int id)
{
tagdb_remove_item(db, id, getFile);
}Code Snippets
typedef HashTable* (*ITEM_GETTER)(tagdb*);
HashTable* getTag(tagdb *db) { return db->reverse;}
HashTable* getFile(tagdb *db) { return db->forward;}
GHashTable *tagdb_get_item_files (tagdb *db, int itemId, ITEM_GETTER getter)
{
return g_hash_table_lookup(getter(db), GINT_TO_POINTER(itemId));
}
void tagdb_remove_item (tagdb *db, int id, ITEM_GETTER getter)
{
GHashTable *its_files = g_hash_table_lookup(getter(db), GINT_TO_POINTER(id));
if (its_files == NULL)
{
return;
}
GHashTableIter it;
gpointer key, value;
g_hash_table_iter_init(&it, its_files);
if (g_hash_table_iter_next(&it, &key, &value))
{
tagdb_remove_tag_from_file(db, id, key);
}
g_hash_table_remove(getter(db), GINT_TO_POINTER(id));
}GHashTable *tagdb_get_tag_files (tagdb *db, int tag_code)
{
return tagdb_get_item_files(db, tag_code, getTag);
}
GHashTable *tagdb_get_file_tags (tagdb *db, int file_id)
{
return return tagdb_get_item_files(db, file_id, getFile);
}
void tagdb_remove_tag (tagdb *db, int id)
{
tagdb_remove_item(db, id, getTag);
}
void tagdb_remove_file(tagdb *db, int id)
{
tagdb_remove_item(db, id, getFile);
}Context
StackExchange Code Review Q#9681, answer score: 3
Revisions (0)
No revisions yet.