From a03afa6a829e6d219e9021d7d5fe00584eaa2a5e Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Thu, 19 Jan 2012 21:36:13 +0900 Subject: [PATCH] Added spdylay_map. Added missing tests/main.c --- lib/Makefile.am | 4 +- lib/includes/spdylay/spdylay.h | 3 +- lib/spdylay_int.h | 6 + lib/spdylay_map.c | 196 +++++++++++++++++++++++++++++++++ lib/spdylay_map.h | 63 +++++++++++ tests/Makefile.am | 4 +- tests/main.c | 70 ++++++++++++ tests/spdylay_map_test.c | 55 +++++++++ tests/spdylay_map_test.h | 30 +++++ 9 files changed, 426 insertions(+), 5 deletions(-) create mode 100644 lib/spdylay_map.c create mode 100644 lib/spdylay_map.h create mode 100644 tests/main.c create mode 100644 tests/spdylay_map_test.c create mode 100644 tests/spdylay_map_test.h diff --git a/lib/Makefile.am b/lib/Makefile.am index 61b3ebc5..3b93f7c1 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -31,9 +31,9 @@ DISTCLEANFILES = $(pkgconfig_DATA) lib_LTLIBRARIES = libspdylay.la -OBJECTS = spdylay_pq.c +OBJECTS = spdylay_pq.c spdylay_map.c -HFILES = spdylay_pq.h spdylay_int.h +HFILES = spdylay_pq.h spdylay_int.h spdylay_map.h libspdylay_la_SOURCES = $(HFILES) $(OBJECTS) libspdylay_la_LDFLAGS = -no-undefined \ diff --git a/lib/includes/spdylay/spdylay.h b/lib/includes/spdylay/spdylay.h index 1d522748..f2b50ede 100644 --- a/lib/includes/spdylay/spdylay.h +++ b/lib/includes/spdylay/spdylay.h @@ -32,7 +32,8 @@ extern "C" { #include enum spdylay_error { - SPDYLAY_ERR_NOMEM = -500 + SPDYLAY_ERR_NOMEM = -500, + SPDYLAY_ERR_INVALID_ARGUMENT = -501 }; #ifdef __cplusplus diff --git a/lib/spdylay_int.h b/lib/spdylay_int.h index e23d9ffe..1f7924af 100644 --- a/lib/spdylay_int.h +++ b/lib/spdylay_int.h @@ -25,6 +25,12 @@ #ifndef SPDYLAY_INT_H #define SPDYLAY_INT_H +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include + /* Macros, types and constants for internal use */ typedef int (*spdylay_compar)(const void *lhs, const void *rhs); diff --git a/lib/spdylay_map.c b/lib/spdylay_map.c new file mode 100644 index 00000000..e84dcd96 --- /dev/null +++ b/lib/spdylay_map.c @@ -0,0 +1,196 @@ +/* + * Spdylay - SPDY Library + * + * Copyright (c) 2012 Tatsuhiro Tsujikawa + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#include "spdylay_map.h" + +int spdylay_map_init(spdylay_map *map) +{ + map->root = NULL; + return 0; +} + +static void spdylay_map_entry_free(spdylay_map_entry *entry) +{ + if(entry != NULL) { + free(entry); + } +} + +static void spdylay_map_entry_free_recur(spdylay_map_entry *entry) +{ + if(entry != NULL) { + spdylay_map_entry_free(entry->left); + spdylay_map_entry_free(entry->right); + } +} + +void spdylay_map_free(spdylay_map *map) +{ + spdylay_map_entry_free_recur(map->root); + map->root = NULL; +} + +/* + * 32 bit Mix Functions by Thomas Wang + * + * http://www.concentric.net/~Ttwang/tech/inthash.htm + */ +static uint32_t hash32shift(uint32_t key) +{ + key = ~key + (key << 15); /* key = (key << 15) - key - 1; */ + key = key ^ (key >> 12); + key = key + (key << 2); + key = key ^ (key >> 4); + key = key * 2057; /* key = (key + (key << 3)) + (key << 11); */ + key = key ^ (key >> 16); + return key; +} + +static spdylay_map_entry* spdylay_map_entry_new(key_type key, void *val) +{ + spdylay_map_entry *entry = + (spdylay_map_entry*)malloc(sizeof(spdylay_map_entry)); + if(entry != NULL) { + entry->key = key; + entry->val = val; + entry->left = entry->right = NULL; + entry->priority = hash32shift(key); + } + return entry; +} + +static spdylay_map_entry* rotate_left(spdylay_map_entry *entry) +{ + spdylay_map_entry *root = entry->right; + entry->right = root->left; + root->left = entry; + return root; +} + +static spdylay_map_entry* rotate_right(spdylay_map_entry* entry) +{ + spdylay_map_entry *root = entry->left; + entry->left = root->right; + root->right = entry; + return root; +} + +static spdylay_map_entry* insert_recur(spdylay_map_entry *entry, + key_type key, void *val, + int *error) +{ + if(entry == NULL) { + entry = spdylay_map_entry_new(key, val); + if(entry == NULL) { + *error = SPDYLAY_ERR_NOMEM; + } + } else if(key == entry->key) { + *error = SPDYLAY_ERR_INVALID_ARGUMENT; + } else if(key < entry->key) { + entry->left = insert_recur(entry->left, key, val, error); + } else { + entry->right = insert_recur(entry->right, key, val, error); + } + if(entry->left != NULL && entry->priority > entry->left->priority) { + entry = rotate_right(entry); + } else if(entry->right != NULL && entry->priority > entry->right->priority) { + entry = rotate_left(entry); + } + return entry; +} + +int spdylay_map_insert(spdylay_map *map, key_type key, void *val) +{ + int error = 0; + map->root = insert_recur(map->root, key, val, &error); + return error; +} + +void* spdylay_map_find(spdylay_map *map, key_type key) +{ + spdylay_map_entry *entry = map->root; + while(entry != NULL) { + if(key < entry->key) { + entry = entry->left; + } else if(key > entry->key) { + entry = entry->right; + } else { + return entry->val; + } + } + return NULL; +} + +static spdylay_map_entry* erase_rotate_recur(spdylay_map_entry *entry) +{ + if(entry->left == NULL) { + spdylay_map_entry *right = entry->right; + spdylay_map_entry_free(entry); + return right; + } else if(entry->right == NULL) { + spdylay_map_entry *left = entry->left; + spdylay_map_entry_free(entry); + return left; + } else if(entry->left->priority < entry->right->priority) { + entry = rotate_right(entry); + return erase_rotate_recur(entry->right); + } else { + entry = rotate_left(entry); + return erase_rotate_recur(entry->left); + } +} + +static spdylay_map_entry* erase_recur(spdylay_map_entry *entry, key_type key) +{ + if(key < entry->key) { + entry->left = erase_recur(entry->left, key); + } else if(key > entry->key) { + entry->right = erase_recur(entry->right, key); + } else { + entry = erase_rotate_recur(entry); + } + return entry; +} + +void spdylay_map_erase(spdylay_map *map, key_type key) +{ + if(map->root != NULL) { + map->root = erase_recur(map->root, key); + } +} + +static void for_each(spdylay_map_entry *entry, + void (*func)(key_type key, void *val)) +{ + if(entry != NULL) { + for_each(entry->left, func); + func(entry->key, entry->val); + for_each(entry->right, func); + } +} + +void spdylay_map_each(spdylay_map *map, void (*func)(key_type key, void *val)) +{ + for_each(map->root, func); +} diff --git a/lib/spdylay_map.h b/lib/spdylay_map.h new file mode 100644 index 00000000..d95dceb3 --- /dev/null +++ b/lib/spdylay_map.h @@ -0,0 +1,63 @@ +/* + * Spdylay - SPDY Library + * + * Copyright (c) 2012 Tatsuhiro Tsujikawa + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef SPDYLAY_MAP_H +#define SPDYLAY_MAP_H + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include "spdylay_int.h" + +/* Implementation of ordered map */ + +typedef uint32_t key_type; +typedef uint32_t pri_type; + +typedef struct spdylay_map_entry { + key_type key; + void *val; + struct spdylay_map_entry *left, *right; + pri_type priority; +} spdylay_map_entry; + +typedef struct { + spdylay_map_entry *root; +} spdylay_map; + +int spdylay_map_init(spdylay_map *map); + +void spdylay_map_free(spdylay_map *map); + +int spdylay_map_insert(spdylay_map *map, key_type key, void *val); + +void* spdylay_map_find(spdylay_map *map, key_type key); + +void spdylay_map_erase(spdylay_map *map, key_type key); + +void spdylay_map_each(spdylay_map *map, void (*func)(key_type key, void *val)); + +#endif /* SPDYLAY_MAP_H */ diff --git a/tests/Makefile.am b/tests/Makefile.am index a362faa7..24518acd 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -25,9 +25,9 @@ if HAVE_CUNIT check_PROGRAMS = main -OBJECTS = main.c spdylay_pq_test.c +OBJECTS = main.c spdylay_pq_test.c spdylay_map_test.c -HFILES = spdylay_pq_test.h +HFILES = spdylay_pq_test.h spdylay_map_test.h main_SOURCES = $(HFILES) $(OBJECTS) diff --git a/tests/main.c b/tests/main.c new file mode 100644 index 00000000..9adee554 --- /dev/null +++ b/tests/main.c @@ -0,0 +1,70 @@ +/* + * Spdylay - SPDY Library + * + * Copyright (c) 2012 Tatsuhiro Tsujikawa + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#include +#include +#include +/* include test cases' include files here */ +#include "spdylay_pq_test.h" +#include "spdylay_map_test.h" + +int init_suite1(void) +{ + return 0; +} + +int clean_suite1(void) +{ + return 0; +} + + +int main() +{ + CU_pSuite pSuite = NULL; + + /* initialize the CUnit test registry */ + if (CUE_SUCCESS != CU_initialize_registry()) + return CU_get_error(); + + /* add a suite to the registry */ + pSuite = CU_add_suite("libspdylay_TestSuite", init_suite1, clean_suite1); + if (NULL == pSuite) { + CU_cleanup_registry(); + return CU_get_error(); + } + + /* add the tests to the suite */ + if(!CU_add_test(pSuite, "pq", test_spdylay_pq) || + !CU_add_test(pSuite, "map", test_spdylay_map)) { + CU_cleanup_registry(); + return CU_get_error(); + } + + /* Run all tests using the CUnit Basic interface */ + CU_basic_set_mode(CU_BRM_VERBOSE); + CU_basic_run_tests(); + CU_cleanup_registry(); + return CU_get_error(); +} diff --git a/tests/spdylay_map_test.c b/tests/spdylay_map_test.c new file mode 100644 index 00000000..49481133 --- /dev/null +++ b/tests/spdylay_map_test.c @@ -0,0 +1,55 @@ +/* + * Spdylay - SPDY Library + * + * Copyright (c) 2012 Tatsuhiro Tsujikawa + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#include "spdylay_map_test.h" + +#include + +#include "spdylay_map.h" + +void test_spdylay_map() +{ + spdylay_map map; + int i; + CU_ASSERT(0 == spdylay_map_init(&map)); + CU_ASSERT(0 == spdylay_map_insert(&map, 1, "foo")); + CU_ASSERT(strcmp("foo", spdylay_map_find(&map, 1)) == 0); + CU_ASSERT(SPDYLAY_ERR_INVALID_ARGUMENT == spdylay_map_insert(&map, 1, "FOO")); + CU_ASSERT(strcmp("foo", spdylay_map_find(&map, 1)) == 0); + CU_ASSERT(0 == spdylay_map_insert(&map, 2, "bar")); + CU_ASSERT(0 == spdylay_map_insert(&map, 3, "baz")); + CU_ASSERT(0 == spdylay_map_insert(&map, 4, "shrubbery")); + CU_ASSERT(strcmp("baz", spdylay_map_find(&map, 3)) == 0); + + spdylay_map_erase(&map, 3); + CU_ASSERT(NULL == spdylay_map_find(&map, 3)); + spdylay_map_erase(&map, 1); + CU_ASSERT(NULL == spdylay_map_find(&map, 1)); + + CU_ASSERT(strcmp("bar", spdylay_map_find(&map, 2)) == 0); + CU_ASSERT(strcmp("shrubbery", spdylay_map_find(&map, 4)) == 0); + + spdylay_map_free(&map); +} + diff --git a/tests/spdylay_map_test.h b/tests/spdylay_map_test.h new file mode 100644 index 00000000..65900a92 --- /dev/null +++ b/tests/spdylay_map_test.h @@ -0,0 +1,30 @@ +/* + * Spdylay - SPDY Library + * + * Copyright (c) 2012 Tatsuhiro Tsujikawa + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef SPDYLAY_MAP_TEST_H +#define SPDYLAY_MAP_TEST_H + +void test_spdylay_map(); + +#endif /* SPDYLAY_MAP_TEST_H */