From f8539fd95010ec91daf5bd2cc4c87951f44de348 Mon Sep 17 00:00:00 2001 From: c9s Date: Thu, 15 May 2014 11:52:45 +0800 Subject: [PATCH] Add token list struct --- .gitignore | 1 + HACKING.md | 13 ++++- include/list.h | 35 +++++++++++++ include/token.h | 32 ++++++++++++ src/CMakeLists.txt | 2 +- src/list.c | 128 +++++++++++++++++++++++++++++++++++++++++++++ src/str.c | 34 +++++++++--- src/token.c | 49 +++++++++++++++++ tests/test_tree.c | 16 +++++- 9 files changed, 298 insertions(+), 12 deletions(-) create mode 100644 include/list.h create mode 100644 include/token.h create mode 100644 src/list.c create mode 100644 src/token.c diff --git a/.gitignore b/.gitignore index 41390ca..e8e48ed 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ cmake_install.cmake install_manifest.txt *.a Testing +tags diff --git a/HACKING.md b/HACKING.md index b709242..dbd4cc6 100644 --- a/HACKING.md +++ b/HACKING.md @@ -1,13 +1,22 @@ Related Articles ===================== +Judy Array +------------ + - A 10-MINUTE DESCRIPTION OF HOW JUDY ARRAYS WORK AND WHY THEY ARE SO FAST - Hashtables vs Judy Arrays, Round 1 - This Hash Table Is Faster Than a Judy Array - A Performance Comparison of Judy to Hash Tables - Faster (sometimes) Associative Arrays with Node.js +Jemalloc +------------ +https://github.com/jemalloc/jemalloc/wiki/Getting-Started - - +Prefix Tree / Radix Tree +------------------------- +- Radix Tree: +- Radix Tree in Linux Kernel: +- Radix Tree in Linux Kernel (source code): diff --git a/include/list.h b/include/list.h new file mode 100644 index 0000000..40f0c96 --- /dev/null +++ b/include/list.h @@ -0,0 +1,35 @@ +/* + * list.h + * Copyright (C) 2014 c9s + * + * Distributed under terms of the MIT license. + */ + +#ifndef LIST_H +#define LIST_H + +#include + +typedef struct _list_item { + void *value; + struct _list_item *prev; + struct _list_item *next; +} list_item; + +typedef struct { + int count; + list_item *head; + list_item *tail; + pthread_mutex_t mutex; +} list; + +list *list_create(); +void list_free(list *l); + +list_item *list_add_element(list *l, void *ptr); +int list_remove_element(list *l, void *ptr); +void list_each_element(list *l, int (*func)(list_item *)); + + + +#endif /* !LIST_H */ diff --git a/include/token.h b/include/token.h new file mode 100644 index 0000000..d78f6c3 --- /dev/null +++ b/include/token.h @@ -0,0 +1,32 @@ +/* + * token.h + * Copyright (C) 2014 c9s + * + * Distributed under terms of the MIT license. + */ + +#ifndef TOKEN_H +#define TOKEN_H + +typedef unsigned char bool; +#define FALSE 0 +#define TRUE 1 + +typedef struct _token_list { + char **tokens; + int len; + int cap; +} token_list; + +token_list * token_list_create(int cap); + + +bool token_list_is_full(token_list * l); + +bool token_list_resize(token_list *l, int new_cap); + +bool token_list_append(token_list * list, char * token); + +void token_list_free(token_list *l); + +#endif /* !TOKEN_H */ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9dd603e..635c079 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -2,7 +2,7 @@ include_directories("${PROJECT_SOURCE_DIR}/include") # install(TARGETS swiftnav-static DESTINATION lib${LIB_SUFFIX}) -set(libr3_SRCS node.c str.c) +set(libr3_SRCS node.c str.c list.c token.c) set(CMAKE_CFLAGS "-Wall -pipe -g3 -funroll-loops") # add_library(r3-static STATIC ${libr3_SRCS}) diff --git a/src/list.c b/src/list.c new file mode 100644 index 0000000..f69cf21 --- /dev/null +++ b/src/list.c @@ -0,0 +1,128 @@ +/* + * list.c + * Copyright (C) 2014 c9s + * + * Distributed under terms of the MIT license. + */ +#include +#include "list.h" + +/* Naive linked list implementation */ + +list * +list_create() +{ + list *l = (list *) malloc(sizeof(list)); + l->count = 0; + l->head = NULL; + l->tail = NULL; + pthread_mutex_init(&(l->mutex), NULL); + return l; +} + +void +list_free(l) + list *l; +{ + list_item *li, *tmp; + + pthread_mutex_lock(&(l->mutex)); + + if (l != NULL) { + li = l->head; + while (li != NULL) { + tmp = li->next; + free(li); + li = tmp; + } + } + + pthread_mutex_unlock(&(l->mutex)); + pthread_mutex_destroy(&(l->mutex)); + free(l); +} + +list_item * +list_add_element(l, ptr) + list *l; + void *ptr; +{ + list_item *li; + + pthread_mutex_lock(&(l->mutex)); + + li = (list_item *) malloc(sizeof(list_item)); + li->value = ptr; + li->next = NULL; + li->prev = l->tail; + + if (l->tail == NULL) { + l->head = l->tail = li; + } + else { + l->tail = li; + } + l->count++; + + pthread_mutex_unlock(&(l->mutex)); + + return li; +} + +int +list_remove_element(l, ptr) + list *l; + void *ptr; +{ + int result = 0; + list_item *li = l->head; + + pthread_mutex_lock(&(l->mutex)); + + while (li != NULL) { + if (li->value == ptr) { + if (li->prev == NULL) { + l->head = li->next; + } + else { + li->prev->next = li->next; + } + + if (li->next == NULL) { + l->tail = li->prev; + } + else { + li->next->prev = li->prev; + } + l->count--; + free(li); + result = 1; + break; + } + li = li->next; + } + + pthread_mutex_unlock(&(l->mutex)); + + return result; +} + +void +list_each_element(l, func) + list *l; + int (*func)(list_item *); +{ + list_item *li; + + pthread_mutex_lock(&(l->mutex)); + + li = l->head; + while (li != NULL) { + if (func(li) == 1) { + break; + } + li = li->next; + } + + pthread_mutex_unlock(&(l->mutex)); +} diff --git a/src/str.c b/src/str.c index 0d4d8d2..49994ab 100644 --- a/src/str.c +++ b/src/str.c @@ -21,6 +21,7 @@ * Split "/blog/{id}" into [ "/blog" , "/{id}" ] * Split "/blog" into [ "/blog" ] * Split "/b" into [ "/b" ] + * Split "/{id}" into [ "/{id}" ] * * @param char* pattern * @param int pattern_len @@ -28,24 +29,43 @@ * @return char** */ char** split_route_pattern(char *pattern, int pattern_len) { + char *s1, *p = pattern; - char *p = pattern; + char ** list; + unsigned int list_idx = 0; + unsigned int list_size = 20; + + list = malloc( sizeof(char**) * list_size ); // default token list size + + s1 = p; + while (*p && (p - pattern) < pattern_len ) { - while (*p) { // a slug if ( *p == '{' ) { - char *s1 = p; - char *s2; while (*(p++) != '}') { if ( p - pattern > pattern_len ) { // XXX: unexpected error (unclosed slug) } } - s2 = p; + list[list_idx] = strndup(s1, p-s1); + printf("%d -> %s\n", list_idx, list[list_idx]); + list_idx++; + + s1 = p; } + else if ( *p == '/' ) { + char *s2; + while (*(++p) != '/'); + // printf("-> %s\n", strndup(s1, p-s1) ); + + list[list_idx] = strndup(s1, p-s1); + printf("%d -> %s\n", list_idx, list[list_idx]); + list_idx++; + + s1 = p; + } + p++; } - - return NULL; } diff --git a/src/token.c b/src/token.c new file mode 100644 index 0000000..2de7c63 --- /dev/null +++ b/src/token.c @@ -0,0 +1,49 @@ +/* + * token.c + * Copyright (C) 2014 c9s + * + * Distributed under terms of the MIT license. + */ +#include +#include "token.h" + + +token_list * token_list_create(int cap) { + token_list * list = (token_list*) malloc( sizeof(token_list) ); + list->len = 0; + list->cap = cap; + list->tokens = (char**) malloc( sizeof(char*) * cap); + return list; +} + +bool token_list_is_full(token_list * l) { + return l->len >= l->cap; +} + +bool token_list_resize(token_list *l, int new_cap) { + l->tokens = realloc(l->tokens, sizeof(char**) * new_cap); + l->cap = new_cap; + return l->tokens != NULL; +} + +bool token_list_append(token_list * l, char * token) { + if ( token_list_is_full(l) ) { + bool ret = token_list_resize(l, l->cap + 20); + if (ret == FALSE ) { + return FALSE; + } + } + l->tokens[ ++(l->len) ] = token; + return TRUE; +} + +void token_list_free(token_list *l) { + for ( int i = 0; i < l->len ; i++ ) { + char * t = l->tokens[ i ]; + free(t); + } + free(l); +} + + + diff --git a/tests/test_tree.c b/tests/test_tree.c index 6251c4a..3b393d5 100644 --- a/tests/test_tree.c +++ b/tests/test_tree.c @@ -2,16 +2,28 @@ #include #include "str.h" #include "node.h" +#include "token.h" START_TEST (test_route) { + split_route_pattern("/blog", strlen("/blog") ); + split_route_pattern("/foo/{id}", strlen("/foo/{id}") ); + split_route_pattern("/{title}", strlen("/{title}") ); } END_TEST -START_TEST (test_route2) +START_TEST (test_token_list) { + token_list * l = token_list_create(10); + fail_if( l == NULL ); + fail_if( FALSE == token_list_resize(l, l->cap * 2) ); + fail_if( FALSE == token_list_append(l, strdup("abc") ) ); + fail_if( FALSE == token_list_append(l, strdup("foo") ) ); + fail_if( FALSE == token_list_append(l, strdup("bar") ) ); + + token_list_free(l); } END_TEST @@ -20,7 +32,7 @@ Suite* r3_suite (void) { TCase *tcase = tcase_create("testcase"); tcase_add_test(tcase, test_route); - tcase_add_test(tcase, test_route2); + tcase_add_test(tcase, test_token_list); suite_add_tcase(suite, tcase);