Add token list struct

This commit is contained in:
c9s 2014-05-15 11:52:45 +08:00
parent ff1800cd4a
commit f8539fd950
9 changed files with 298 additions and 12 deletions

1
.gitignore vendored
View file

@ -6,3 +6,4 @@ cmake_install.cmake
install_manifest.txt install_manifest.txt
*.a *.a
Testing Testing
tags

View file

@ -1,13 +1,22 @@
Related Articles Related Articles
===================== =====================
Judy Array
------------
- A 10-MINUTE DESCRIPTION OF HOW JUDY ARRAYS WORK AND WHY THEY ARE SO FAST <http://judy.sourceforge.net/doc/10minutes.htm> - A 10-MINUTE DESCRIPTION OF HOW JUDY ARRAYS WORK AND WHY THEY ARE SO FAST <http://judy.sourceforge.net/doc/10minutes.htm>
- Hashtables vs Judy Arrays, Round 1 <http://rusty.ozlabs.org/?p=153> - Hashtables vs Judy Arrays, Round 1 <http://rusty.ozlabs.org/?p=153>
- This Hash Table Is Faster Than a Judy Array <http://preshing.com/20130107/this-hash-table-is-faster-than-a-judy-array/> - This Hash Table Is Faster Than a Judy Array <http://preshing.com/20130107/this-hash-table-is-faster-than-a-judy-array/>
- A Performance Comparison of Judy to Hash Tables <http://www.nothings.org/computer/judy/> - A Performance Comparison of Judy to Hash Tables <http://www.nothings.org/computer/judy/>
- Faster (sometimes) Associative Arrays with Node.js <http://legitimatesounding.com/blog/Faster_sometimes_Associative_Arrays_with_Node_js.html> - Faster (sometimes) Associative Arrays with Node.js <http://legitimatesounding.com/blog/Faster_sometimes_Associative_Arrays_with_Node_js.html>
Jemalloc
------------
https://github.com/jemalloc/jemalloc/wiki/Getting-Started
Prefix Tree / Radix Tree
-------------------------
- Radix Tree: <http://en.wikipedia.org/wiki/Radix_tree>
- Radix Tree in Linux Kernel: <http://blog.csdn.net/walkland/article/details/4006121>
- Radix Tree in Linux Kernel (source code): <https://github.com/torvalds/linux/blob/master/include/linux/radix-tree.h>

35
include/list.h Normal file
View file

@ -0,0 +1,35 @@
/*
* list.h
* Copyright (C) 2014 c9s <c9s@c9smba.local>
*
* Distributed under terms of the MIT license.
*/
#ifndef LIST_H
#define LIST_H
#include <pthread.h>
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 */

32
include/token.h Normal file
View file

@ -0,0 +1,32 @@
/*
* token.h
* Copyright (C) 2014 c9s <c9s@c9smba.local>
*
* 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 */

View file

@ -2,7 +2,7 @@
include_directories("${PROJECT_SOURCE_DIR}/include") include_directories("${PROJECT_SOURCE_DIR}/include")
# install(TARGETS swiftnav-static DESTINATION lib${LIB_SUFFIX}) # 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") set(CMAKE_CFLAGS "-Wall -pipe -g3 -funroll-loops")
# add_library(r3-static STATIC ${libr3_SRCS}) # add_library(r3-static STATIC ${libr3_SRCS})

128
src/list.c Normal file
View file

@ -0,0 +1,128 @@
/*
* list.c
* Copyright (C) 2014 c9s <c9s@c9smba.local>
*
* Distributed under terms of the MIT license.
*/
#include <stdlib.h>
#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));
}

View file

@ -21,6 +21,7 @@
* Split "/blog/{id}" into [ "/blog" , "/{id}" ] * Split "/blog/{id}" into [ "/blog" , "/{id}" ]
* Split "/blog" into [ "/blog" ] * Split "/blog" into [ "/blog" ]
* Split "/b" into [ "/b" ] * Split "/b" into [ "/b" ]
* Split "/{id}" into [ "/{id}" ]
* *
* @param char* pattern * @param char* pattern
* @param int pattern_len * @param int pattern_len
@ -28,24 +29,43 @@
* @return char** * @return char**
*/ */
char** split_route_pattern(char *pattern, int pattern_len) { 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 // a slug
if ( *p == '{' ) { if ( *p == '{' ) {
char *s1 = p;
char *s2;
while (*(p++) != '}') { while (*(p++) != '}') {
if ( p - pattern > pattern_len ) { if ( p - pattern > pattern_len ) {
// XXX: unexpected error (unclosed slug) // 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; return NULL;
} }

49
src/token.c Normal file
View file

@ -0,0 +1,49 @@
/*
* token.c
* Copyright (C) 2014 c9s <c9s@c9smba.local>
*
* Distributed under terms of the MIT license.
*/
#include <stdlib.h>
#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);
}

View file

@ -2,16 +2,28 @@
#include <check.h> #include <check.h>
#include "str.h" #include "str.h"
#include "node.h" #include "node.h"
#include "token.h"
START_TEST (test_route) 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 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 END_TEST
@ -20,7 +32,7 @@ Suite* r3_suite (void) {
TCase *tcase = tcase_create("testcase"); TCase *tcase = tcase_create("testcase");
tcase_add_test(tcase, test_route); tcase_add_test(tcase, test_route);
tcase_add_test(tcase, test_route2); tcase_add_test(tcase, test_token_list);
suite_add_tcase(suite, tcase); suite_add_tcase(suite, tcase);