treewide: restucture source tree per project
Signed-off-by: Max Regan <mgregan2@gmail.com>
This commit is contained in:
10
src/common/common.c
Normal file
10
src/common/common.c
Normal file
@@ -0,0 +1,10 @@
|
||||
#include "common/common.h"
|
||||
|
||||
void downcase(char *str)
|
||||
{
|
||||
for (int i = 0; str[i] != '\0'; i++) {
|
||||
if (str[i] >= 'A' && str[i] <= 'Z') {
|
||||
str[i] += 'a' - 'A';
|
||||
}
|
||||
}
|
||||
}
|
||||
54
src/common/common.h
Normal file
54
src/common/common.h
Normal file
@@ -0,0 +1,54 @@
|
||||
#ifndef _COMMON_H_
|
||||
#define _COMMON_H_
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define MIN(a,b) ((a) > (b) ? (b) : (a))
|
||||
#define MAX(a,b) ((a) < (b) ? (b) : (a))
|
||||
|
||||
#define ARRAY_SIZE(x) (sizeof((x)) / (sizeof((x)[0])))
|
||||
|
||||
/*
|
||||
* Replaces any characters from A-Z with their lowercase counterpart.
|
||||
* All other characters preceding '\0' are ignored
|
||||
*/
|
||||
void downcase(char *str);
|
||||
|
||||
#ifdef DEBUG
|
||||
#define DEBUG_ON 1
|
||||
#else
|
||||
#define DEBUG_ON 0
|
||||
#endif
|
||||
|
||||
#define QUOTE(...) #__VA_ARGS__
|
||||
|
||||
#define ASSERT(x) \
|
||||
if (!(x) && DEBUG_ON) { \
|
||||
printf("Assert at: %s:%d <%s> : %s\n", \
|
||||
__FILE__, __LINE__, \
|
||||
__func__, #x); \
|
||||
exit(1); \
|
||||
}
|
||||
|
||||
#define ASSERT_MSG(x,...) \
|
||||
if(!(x) && DEBUG_ON) { \
|
||||
printf("Assert at: %s:%d <%s> : %s\n", \
|
||||
__FILE__, __LINE__, \
|
||||
__func__, #x); \
|
||||
printf(__VA_ARGS__); \
|
||||
exit(1); \
|
||||
}
|
||||
|
||||
#define DEBUG_LOG(...) \
|
||||
do { \
|
||||
if (DEBUG_ON) { \
|
||||
printf("DEBUG: %s:%d <%s> : ", \
|
||||
__FILE__, __LINE__, \
|
||||
__func__); \
|
||||
printf(__VA_ARGS__); \
|
||||
printf("\n"); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
124
src/common/tests/test.c
Normal file
124
src/common/tests/test.c
Normal file
@@ -0,0 +1,124 @@
|
||||
#include "common/tri.h"
|
||||
#include "common/common.h"
|
||||
|
||||
#include <glib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define TO_PTR(x) ((void *) (uintptr_t) (x))
|
||||
#define TO_INT(x) ((int) (uintptr_t) (x))
|
||||
|
||||
static void test_tri_get_string(void)
|
||||
{
|
||||
struct tri tri;
|
||||
|
||||
tri_init(&tri);
|
||||
|
||||
g_assert_cmpint(tri_add_string(&tri, "a", TO_PTR(1)), ==, 0);
|
||||
g_assert_cmpint(tri_add_string(&tri, "ab", TO_PTR(2)), ==, 0);
|
||||
g_assert_cmpint(tri_add_string(&tri, "abc", TO_PTR(3)), ==, 0);
|
||||
g_assert_cmpint(tri_add_string(&tri, "af", TO_PTR(4)), ==, 0);
|
||||
g_assert_cmpint(tri_add_string(&tri, "abd", TO_PTR(5)), ==, 0);
|
||||
g_assert_cmpint(tri_add_string(&tri, "$a!0123~&.`", TO_PTR(6)), ==, 0);
|
||||
|
||||
g_assert_cmpint(TO_INT(tri_get_string(&tri, "a")), ==, 1);
|
||||
g_assert_cmpint(TO_INT(tri_get_string(&tri, "ab")), ==, 2);
|
||||
g_assert_cmpint(TO_INT(tri_get_string(&tri, "abc")), ==, 3);
|
||||
g_assert_cmpint(TO_INT(tri_get_string(&tri, "af")), ==, 4);
|
||||
g_assert_cmpint(TO_INT(tri_get_string(&tri, "abd")), ==, 5);
|
||||
g_assert_cmpint(TO_INT(tri_get_string(&tri, "abz")), ==, 0);
|
||||
g_assert_cmpint(TO_INT(tri_get_string(&tri, "ag")), ==, 0);
|
||||
g_assert_cmpint(TO_INT(tri_get_string(&tri, "$a!0123~&.`")), ==, 6);
|
||||
|
||||
tri_free(&tri);
|
||||
}
|
||||
|
||||
static void test_tri_prefix_match(void)
|
||||
{
|
||||
struct tri tri;
|
||||
|
||||
tri_init(&tri);
|
||||
|
||||
g_assert_cmpint(tri_add_string(&tri, "pr", TO_PTR(1)), ==, 0);
|
||||
g_assert_cmpint(tri_add_string(&tri, "pref", TO_PTR(2)), ==, 0);
|
||||
g_assert_cmpint(tri_add_string(&tri, "Z", TO_PTR(3)), ==, 0);
|
||||
g_assert_cmpint(tri_add_string(&tri, "prefix", TO_PTR(4)), ==, 0);
|
||||
g_assert_cmpint(tri_add_string(&tri, "blah", TO_PTR(5)), ==, 0);
|
||||
|
||||
g_assert_cmpint(TO_INT(tri_prefix_match(&tri, "p")), ==, 0);
|
||||
g_assert_cmpint(TO_INT(tri_prefix_match(&tri, "pr")), ==, 1);
|
||||
g_assert_cmpint(TO_INT(tri_prefix_match(&tri, "pre")), ==, 1);
|
||||
g_assert_cmpint(TO_INT(tri_prefix_match(&tri, "pref")), ==, 2);
|
||||
g_assert_cmpint(TO_INT(tri_prefix_match(&tri, "prefix10")), ==, 4);
|
||||
g_assert_cmpint(TO_INT(tri_prefix_match(&tri, "asdfasdf")), ==, 0);
|
||||
|
||||
tri_free(&tri);
|
||||
}
|
||||
|
||||
static void test_tri_autocomplete(void)
|
||||
{
|
||||
struct tri tri;
|
||||
bool ambiguous;
|
||||
|
||||
tri_init(&tri);
|
||||
|
||||
g_assert_cmpint(tri_add_string(&tri, "pr", TO_PTR(1)), ==, 0);
|
||||
g_assert_cmpint(tri_add_string(&tri, "pref", TO_PTR(2)), ==, 0);
|
||||
g_assert_cmpint(tri_add_string(&tri, "Z", TO_PTR(3)), ==, 0);
|
||||
g_assert_cmpint(tri_add_string(&tri, "prefix", TO_PTR(4)), ==, 0);
|
||||
g_assert_cmpint(tri_add_string(&tri, "blah", TO_PTR(5)), ==, 0);
|
||||
|
||||
|
||||
g_assert_null(tri_get_string_autocomplete(&tri, "p", &ambiguous));
|
||||
g_assert_true(ambiguous);
|
||||
|
||||
g_assert_null(tri_get_string_autocomplete(&tri, "pr", &ambiguous));
|
||||
g_assert_true(ambiguous);
|
||||
|
||||
g_assert_null(tri_get_string_autocomplete(&tri, "pre", &ambiguous));
|
||||
g_assert_true(ambiguous);
|
||||
|
||||
g_assert_null(tri_get_string_autocomplete(&tri, "pref", &ambiguous));
|
||||
g_assert_true(ambiguous);
|
||||
|
||||
g_assert_null(tri_get_string_autocomplete(&tri, "prefix10", &ambiguous));
|
||||
g_assert_false(ambiguous);
|
||||
|
||||
g_assert_null(tri_get_string_autocomplete(&tri, "asdfasdf", &ambiguous));
|
||||
g_assert_false(ambiguous);
|
||||
|
||||
g_assert_cmpint(TO_INT(tri_get_string_autocomplete(&tri, "bla", &ambiguous)), ==, 5);
|
||||
g_assert_false(ambiguous);
|
||||
|
||||
g_assert_cmpint(TO_INT(tri_get_string_autocomplete(&tri, "prefi", &ambiguous)), ==, 4);
|
||||
g_assert_false(ambiguous);
|
||||
|
||||
g_assert_cmpint(TO_INT(tri_get_string_autocomplete(&tri, "prefix", &ambiguous)), ==, 4);
|
||||
g_assert_false(ambiguous);
|
||||
|
||||
g_assert_cmpint(TO_INT(tri_get_string_autocomplete(&tri, "Z", &ambiguous)), ==, 3);
|
||||
g_assert_false(ambiguous);
|
||||
|
||||
tri_free(&tri);
|
||||
}
|
||||
|
||||
static void test_tri_null(void)
|
||||
{
|
||||
struct tri tri;
|
||||
|
||||
tri_init(&tri);
|
||||
|
||||
g_assert_cmpint(tri_add_string(&tri, NULL, TO_PTR(1)), ==, -1);
|
||||
g_assert_null(tri_prefix_match(&tri, NULL));
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
|
||||
g_test_add_func("/tri/get_string", test_tri_get_string);
|
||||
g_test_add_func("/tri/prefix_match", test_tri_prefix_match);
|
||||
g_test_add_func("/tri/autocomplete", test_tri_autocomplete);
|
||||
g_test_add_func("/tri/null", test_tri_null);
|
||||
|
||||
return g_test_run();
|
||||
}
|
||||
170
src/common/tri.c
Normal file
170
src/common/tri.c
Normal file
@@ -0,0 +1,170 @@
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "common/tri.h"
|
||||
#include "common/common.h"
|
||||
|
||||
static size_t char_to_idx(char c)
|
||||
{
|
||||
unsigned char c2 = c;
|
||||
return (size_t) c2;
|
||||
}
|
||||
|
||||
void tri_init(struct tri *tri)
|
||||
{
|
||||
tri->head = malloc(sizeof(struct tri_node));
|
||||
memset(tri->head, 0, sizeof(*tri->head));
|
||||
}
|
||||
|
||||
static void tri_free_node(struct tri_node *node)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (node == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(node->nodes); i++) {
|
||||
tri_free_node(node->nodes[i]);
|
||||
}
|
||||
|
||||
free(node);
|
||||
}
|
||||
|
||||
void tri_free(struct tri *tri) {
|
||||
tri_free_node(tri->head);
|
||||
}
|
||||
|
||||
int tri_add_string(struct tri *tri, const char *string, void *value)
|
||||
{
|
||||
struct tri_node *node = NULL;
|
||||
int i = 0;
|
||||
|
||||
if (string == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (value == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
node = tri->head;
|
||||
|
||||
for (i = 0; i < strlen(string); i++) {
|
||||
int idx = char_to_idx(string[i]);
|
||||
|
||||
if (node->nodes[idx] == NULL) {
|
||||
node->nodes[idx] = malloc(sizeof(struct tri_node));
|
||||
memset(node->nodes[idx], 0, sizeof(struct tri_node));
|
||||
}
|
||||
node = node->nodes[idx];
|
||||
}
|
||||
|
||||
node->value = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *tri_get_string(struct tri *tri, const char *string)
|
||||
{
|
||||
struct tri_node *node = NULL;
|
||||
int i = 0;
|
||||
|
||||
if (string == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
node = tri->head;
|
||||
|
||||
for (i = 0; i < strlen(string); i++) {
|
||||
int idx = char_to_idx(string[i]);
|
||||
|
||||
if (node->nodes[idx] == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
node = node->nodes[idx];
|
||||
}
|
||||
|
||||
return node->value;
|
||||
}
|
||||
|
||||
void *tri_get_string_autocomplete(struct tri *tri, const char *string, bool *ambiguous)
|
||||
{
|
||||
struct tri_node *node = NULL;
|
||||
int i = 0, j = 0;
|
||||
|
||||
*ambiguous = false;
|
||||
|
||||
if (string == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
node = tri->head;
|
||||
|
||||
for (i = 0; i < strlen(string); i++) {
|
||||
int idx = char_to_idx(string[i]);
|
||||
|
||||
if (node->nodes[idx] == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
node = node->nodes[idx];
|
||||
}
|
||||
|
||||
while(1) {
|
||||
struct tri_node *next_node = NULL;
|
||||
int num_paths = 0;
|
||||
for (j = 0; j < ARRAY_SIZE(node->nodes); j++) {
|
||||
if (node->nodes[j] != NULL) {
|
||||
next_node = node->nodes[j];
|
||||
num_paths++;
|
||||
if (num_paths > 1) {
|
||||
*ambiguous = true;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (next_node == NULL) {
|
||||
return node->value;
|
||||
} else if (node->value != NULL && next_node != NULL) {
|
||||
*ambiguous = true;
|
||||
return NULL;
|
||||
} else {
|
||||
node = next_node;
|
||||
}
|
||||
}
|
||||
|
||||
return node->value;
|
||||
}
|
||||
|
||||
void *tri_prefix_match(struct tri *tri, const char *string)
|
||||
{
|
||||
struct tri_node *node = NULL;
|
||||
void *value = NULL;
|
||||
int i = 0;
|
||||
|
||||
if (string == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
node = tri->head;
|
||||
|
||||
for (i = 0; i < strlen(string); i++) {
|
||||
int idx = char_to_idx(string[i]);
|
||||
|
||||
if (node->nodes[idx] == NULL) {
|
||||
return value;
|
||||
}
|
||||
|
||||
node = node->nodes[idx];
|
||||
if (node->value != NULL) {
|
||||
value = node->value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
58
src/common/tri.h
Normal file
58
src/common/tri.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* An implementation of tries.
|
||||
*/
|
||||
|
||||
#ifndef _TRI_H_
|
||||
#define _TRI_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#define NUM_ALPHA_CHARS (256)
|
||||
|
||||
struct tri_node {
|
||||
struct tri_node *nodes[NUM_ALPHA_CHARS];
|
||||
void *value;
|
||||
};
|
||||
|
||||
struct tri {
|
||||
struct tri_node *head;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Initialize a tri and set its maximum depth.
|
||||
*/
|
||||
void tri_init(struct tri *tri);
|
||||
|
||||
/**
|
||||
* Destroys an initialized tri and frees its internal structures.
|
||||
*/
|
||||
void tri_free(struct tri *tri);
|
||||
|
||||
/**
|
||||
* Add a string as a key, and a value to the tri.
|
||||
*/
|
||||
int tri_add_string(struct tri *tri, const char *string, void * value);
|
||||
|
||||
/**
|
||||
* Returns the value cooresponding to string. If the string is not in the tri, return
|
||||
* NULL.
|
||||
*/
|
||||
void *tri_get_string(struct tri *tri, const char *string);
|
||||
|
||||
/**
|
||||
* Returns the value cooresponding to the longest matching prefix
|
||||
*/
|
||||
void *tri_prefix_match(struct tri *tri, const char *string);
|
||||
|
||||
/**
|
||||
* Using 'string' as a prefix, returns the value of the cooresponding string if there
|
||||
* is only one that matches.
|
||||
*
|
||||
* If there are multiple possible matches, return NULL and set 'ambiguous' to true. If
|
||||
* there are no possible matches, return NULL and set 'ambiguous' to false.
|
||||
*/
|
||||
void *tri_get_string_autocomplete(struct tri *tri, const char *string, bool *ambiguous);
|
||||
|
||||
|
||||
#endif
|
||||
24
src/common/util.h
Normal file
24
src/common/util.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#ifndef _COMMON_H_
|
||||
#define _COMMON_H_
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define ARRAY_SIZE(x) (sizeof((x)) / (sizeof((x)[0]))
|
||||
|
||||
#define ASSERT(x) \
|
||||
if (!(x)) { \
|
||||
printf("Assert failed at: %s:%d <%s>\n", \
|
||||
__FILE__, __LINE__, __FUNC__); \
|
||||
exit(1); \
|
||||
}
|
||||
|
||||
#define ASSERT_MSG(x, msg) \
|
||||
if(!(x)) { \
|
||||
printf("Assert failed at: %s:%d <%s>\n", \
|
||||
__FILE__, __LINE__, __FUNC__); \
|
||||
printf("%s", msg); \
|
||||
exit(1); \
|
||||
} \
|
||||
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user