core/set: Add new struct to act as a set

The glib library doesn't have a dedicated "set" container, so I need to
create a wrapper around a hash table to accomplish the same results.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This commit is contained in:
Anna Schumaker 2015-11-07 10:38:48 -05:00
parent 9e0c4404fc
commit 4d065508cd
4 changed files with 129 additions and 12 deletions

70
include/core/set.h Normal file
View File

@ -0,0 +1,70 @@
/*
* Copyright 2015 (c) Anna Schumaker.
*/
#ifndef OCARINA_CORE_SET_H
#define OCARINA_CORE_SET_H
#include <glib.h>
#include <stdbool.h>
struct set {
GHashTable *s_set;
};
struct set_iter {
unsigned int it_val;
GHashTableIter it_iter;
};
#define SET_INIT() \
{ \
.s_set = g_hash_table_new(g_direct_hash, g_direct_equal), \
}
static inline void set_deinit(struct set *set)
{
g_hash_table_destroy(set->s_set);
}
static inline void set_insert(struct set *set, unsigned int value)
{
g_hash_table_add(set->s_set, GUINT_TO_POINTER(value));
}
static inline void set_remove(struct set *set, unsigned int value)
{
g_hash_table_remove(set->s_set, GUINT_TO_POINTER(value));
}
static inline bool set_has(const struct set *set, unsigned int value)
{
return g_hash_table_contains(set->s_set, GUINT_TO_POINTER(value));
}
static inline unsigned int set_size(struct set *set)
{
return g_hash_table_size(set->s_set);
}
static inline bool set_iter_next(struct set_iter *it)
{
gpointer key;
bool ret = g_hash_table_iter_next(&it->it_iter, &key, NULL);
it->it_val = GPOINTER_TO_INT(key);
return ret;
}
static inline void set_iter_init(const struct set *set, struct set_iter *it)
{
g_hash_table_iter_init(&it->it_iter, set->s_set);
}
#define set_for_each(set, it) \
for (set_iter_init(set, it); set_iter_next(it); )
#endif /* OCARINA_CORE_SET_H */

25
tests/core/.gitignore vendored
View File

@ -1,15 +1,16 @@
version audio
string
file
date
database database
index date
filter
idle
random
queue
library
playlist
deck deck
driver driver
audio file
filter
idle
index
library
playlist
queue
random
set
string
version

View File

@ -18,6 +18,7 @@ res += [ CoreTest("string", "string.c") ]
res += [ CoreTest("random", "random.c") ] res += [ CoreTest("random", "random.c") ]
res += [ CoreTest("file", "file.c") ] res += [ CoreTest("file", "file.c") ]
res += [ CoreTest("date", "date.c") ] res += [ CoreTest("date", "date.c") ]
res += [ CoreTest("set", "set.c") ]
res += [ CoreTest("database", "database.cpp") ] res += [ CoreTest("database", "database.cpp") ]
res += [ CoreTest("index", "index.cpp") ] res += [ CoreTest("index", "index.cpp") ]
res += [ CoreTest("filter", "filter.cpp") ] res += [ CoreTest("filter", "filter.cpp") ]

45
tests/core/set.c Normal file
View File

@ -0,0 +1,45 @@
/*
* Copyright 2015 (c) Anna Schumaker.
*/
#include <core/set.h>
#include <tests/test.h>
void test_set()
{
struct set set = SET_INIT();
unsigned int i, N = 10;
struct set_iter it;
/* Insert N items. */
for (i = 0; i < N; i++) {
set_insert(&set, i);
set_insert(&set, i);
test_loop_equal(set_size(&set), i + 1, i);
test_loop_equal(set_has(&set, i), (bool)true, i);
} test_loop_passed();
set_insert(&set, 0);
test_equal(set_size(&set), N);
/* Remove even items. */
for (i = 0; i < N; i += 2) {
set_remove(&set, i);
set_remove(&set, i);
test_loop_equal(set_has(&set, i), (bool)false, i);
} test_loop_passed();
test_equal(set_size(&set), N / 2);
/* Test iterating. */
i = 1;
set_for_each(&set, &it) {
test_loop_equal(it.it_val, i, i);
i += 2;
} test_loop_passed();
set_deinit(&set);
}
DECLARE_UNIT_TESTS(
UNIT_TEST("Set", test_set),
);