diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c24ea1b --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/test/*.o diff --git a/LICENSE b/LICENSE index 03b6555..be79db9 100644 --- a/LICENSE +++ b/LICENSE @@ -1,20 +1,20 @@ -Copyright (c) 2014 rxi - - -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. +Copyright (c) 2014 rxi + + +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. diff --git a/README.md b/README.md index 805b425..aae5b5a 100644 --- a/README.md +++ b/README.md @@ -1,109 +1,120 @@ -# map -A type-safe generic hashmap implementation for C. - -## Installation -The [map.c](src/map.c?raw=1) and [map.h](src/map.h?raw=1) files can be dropped -into an existing C project and compiled along with it. - - -## Usage -Before using a map it should first be initialised using the `map_init()` -function. -```c -map_int_t m; -map_init(&m); -``` - -Values can added to a map using the `map_set()` function. -```c -map_set(&m, "testkey", 123); -``` - -To retrieve a value from a map, the `map_get()` function can be used. -`map_get()` will return a pointer to the key's value, or `NULL` if no mapping -for that key exists. -```c -int *val = map_get(&m, "testkey"); -if (val) { - printf("value: %d\n", *val); -} else { - printf("value not found\n"); -} -``` - -When you are done with a map the `map_deinit()` function should be called on -it. This will free any memory the map allocated during use. -```c -map_deinit(&m); -``` - - -## Types -map.h provides the following predefined map types: - -Contained Type | Type name -----------------|---------------------------------- -void* | map_void_t -char* | map_str_t -int | map_int_t -char | map_char_t -float | map_float_t -double | map_double_t - -To define a new map type the `map_t()` macro should be used: -```c -/* Creates the type uint_map_t for storing unsigned ints */ -typedef map_t(unsigned int) uint_map_t; -``` - -## Functions -All map functions are macro functions. The parameter `m` in each function -should be a pointer to the map struct which the operation is to be performed -on. The `key` parameter should always be a string value. - -### map\_t(T) -Creates a map struct for containing values of type `T`. -```c -/* Typedefs the struct `fp_map_t` as a container for type FILE* */ -typedef map_t(FILE*) fp_map_t; -``` - -### map\_init(m) -Initialises the map, this must be called before the map can be used. - -### map\_deinit(m) -Deinitialises the map, freeing the memory the map allocated during use; -this should be called when we're finished with a map. - -### map\_get(m, key) -Returns a pointer to the value of the given `key`. If no mapping for the `key` -exists then `NULL` will be returned. - -### map\_set(m, key, value) -Sets the given `key` to the given `value`. Returns `0` on success, otherwise -`-1` is returned and the map remains unchanged. - -### map\_remove(m, key) -Removes the mapping of the given `key` from the map. If the `key` does not -exist in the map then the function has no effect. - -### map\_iter(m) -Returns a `map_iter_t` which can be used with `map_next()` to iterate all the -keys in the map. - -### map\_next(m, iter) -Uses the `map_iter_t` returned by `map_iter()` to iterate all the keys in the -map. `map_next()` returns a key with each call and returns `NULL` when there -are no more keys. -```c -const char *key; -map_iter_t iter = map_iter(&m); - -while ((key = map_next(&m, &iter))) { - printf("%s -> %d", key, *map_get(&m, key)); -} -``` - -## License -This library is free software; you can redistribute it and/or modify it under -the terms of the MIT license. See [LICENSE](LICENSE) for details. +# map +A type-safe generic hashmap implementation for C. + +## Installation +The [map.c](src/map.c?raw=1) and [map.h](src/map.h?raw=1) files can be dropped +into an existing C project and compiled along with it. + + +## Usage +Before using a map it should first be initialised using the `map_init()` +function. +```c +map_int_t m; +map_init(&m); +``` + +Values can added to a map using the `map_set()` function. +```c +map_set(&m, "testkey", 123); +``` + +To retrieve a value from a map, the `map_get()` function can be used. +`map_get()` will return a pointer to the key's value, or `NULL` if no mapping +for that key exists. +```c +int *val = map_get(&m, "testkey"); +if (val) { + printf("value: %d\n", *val); +} else { + printf("value not found\n"); +} +``` + +When you are done with a map the `map_deinit()` function should be called on +it. This will free any memory the map allocated during use. +```c +map_deinit(&m); +``` + + +## Types +map.h provides the following predefined map types: + +Contained Type | Type name +----------------|---------------------------------- +void* | map_void_t +char* | map_str_t +int | map_int_t +char | map_char_t +float | map_float_t +double | map_double_t + +To define a new map type the `map_t()` macro should be used: +```c +/* Creates the type uint_map_t for storing unsigned ints */ +typedef map_t(unsigned int) uint_map_t; +``` + +## Functions +All map functions are macro functions. The parameter `m` in each function +should be a pointer to the map struct which the operation is to be performed +on. The `key` parameter should always be a string value. + +### map\_t(T) +Creates a map struct for containing values of type `T`. +```c +/* Typedefs the struct `fp_map_t` as a container for type FILE* */ +typedef map_t(FILE*) fp_map_t; +``` + +### map\_init(m) +Initialises the map, this must be called before the map can be used. + +### map\_deinit(m) +Deinitialises the map, freeing the memory the map allocated during use; +this should be called when we're finished with a map. + +### map\_get(m, key) +Returns a pointer to the value of the given `key`. If no mapping for the `key` +exists then `NULL` will be returned. + +### map\_set(m, key, value) +Sets the given `key` to the given `value`. Returns `0` on success, otherwise +`-1` is returned and the map remains unchanged. + +### map\_remove(m, key) +Removes the mapping of the given `key` from the map. If the `key` does not +exist in the map then the function has no effect. + +### map\_iter(m) +Returns a `map_iter_t` which can be used with `map_next()` to iterate all the +keys in the map. + +### map\_next(m, iter) +Uses the `map_iter_t` returned by `map_iter()` to iterate all the keys in the +map. `map_next()` returns a key with each call and returns `NULL` when there +are no more keys. +```c +const char *key; +map_iter_t iter = map_iter(&m); + +while ((key = map_next(&m, &iter))) { + printf("%s -> %d", key, *map_get(&m, key)); +} +``` + +## Update 2016/12/04 +1. Build Compatible with C++(-Wall -Werror) + + windows _MSC_VER >= 1600(VS2010) + + clang(support but not test) + + gcc(tested gcc>=4.0.0) + +2. Add test code + +## License +This library is free software; you can redistribute it and/or modify it under +the terms of the MIT license. See [LICENSE](LICENSE) for details. diff --git a/package.json b/package.json index 7b5115b..af8c08a 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,9 @@ -{ - "name": "map", - "version": "0.1.0", - "repo": "rxi/map", - "description": "Type-safe generic hash map", - "keywords": ["hashmap", "map", "table", "hashtable", "dict", "dictionary"], - "license": "MIT", - "src": ["src/map.c", "src/map.h"] -} +{ + "name": "map", + "version": "0.1.0", + "repo": "rxi/map", + "description": "Type-safe generic hash map", + "keywords": ["hashmap", "map", "table", "hashtable", "dict", "dictionary"], + "license": "MIT", + "src": ["src/map.c", "src/map.h"] +} diff --git a/src/map.h b/src/map.h index 71af710..8a01800 100644 --- a/src/map.h +++ b/src/map.h @@ -1,4 +1,4 @@ -/** +/** * Copyright (c) 2014 rxi * * This library is free software; you can redistribute it and/or modify it @@ -12,6 +12,8 @@ #define MAP_VERSION "0.1.0" + + struct map_node_t; typedef struct map_node_t map_node_t; @@ -58,6 +60,22 @@ typedef struct { #define map_next(m, iter)\ map_next_(&(m)->base, iter) +#ifdef __cplusplus +extern "C"{ + #undef map_get + #ifdef __clang__ + #define ___TYPEOF_ __typeof__ + #elif defined(__GNUC__) + #define ___TYPEOF_ typeof + #elif defined(_MSC_VER) && _MSC_VER>=1600 + #define ___TYPEOF_ decltype + #else + #warning "C++ build need typeof" + #endif /*endof clang*/ + #define map_get(m, key)\ + ( (m)->ref = (___TYPEOF_((m)->ref)) map_get_(&(m)->base, key) ) +#endif /*endof __cplusplus*/ + void map_deinit_(map_base_t *m); void *map_get_(map_base_t *m, const char *key); @@ -74,4 +92,8 @@ typedef map_t(char) map_char_t; typedef map_t(float) map_float_t; typedef map_t(double) map_double_t; +#ifdef __cplusplus +} +#endif + #endif diff --git a/src/map.o b/src/map.o new file mode 100644 index 0000000..d70e181 Binary files /dev/null and b/src/map.o differ diff --git a/test/Makefile b/test/Makefile new file mode 100644 index 0000000..8fb33c3 --- /dev/null +++ b/test/Makefile @@ -0,0 +1,7 @@ +all: + make -C c + make -C cpp + +clean: + make -C c clean + make -C cpp clean diff --git a/test/c/Makefile b/test/c/Makefile new file mode 100644 index 0000000..33e6d02 --- /dev/null +++ b/test/c/Makefile @@ -0,0 +1,46 @@ +CC = gcc +CXX = g++ +LINK = g++ + +CFLAGS_D = $(COMPILER_FLAGS) -c -g -O0 -Wall -Werror +CFLAGS_R = $(COMPILER_FLAGS) -c -g -O2 -Werror +CXXFLAGS_D = $(COMPILER_FLAGS) -c -g -O0 -Werror +CXXFLAGS_R = $(COMPILER_FLAGS) -c -g -O2 -Werror + +INC+= -I. -I../../src +LIBS += +RELEASE = 0 + +TARGET = c_test +CCFLAGS = $(CFLAGS_R) + +ifeq ($(RELEASE),0) + # debug + CFLAGS = $(CFLAGS_D) + CXXFLAGS = $(CXXFLAGS_D) +else + # release + CFLAGS = $(CFLAGS_R) + CXXFLAGS = $(CXXFLAGS_R) +endif + + +CFILES = ../../src/map.c main.c + +OBJFILE = $(CFILES:.c=.o) $(CXXFILES:.cpp=.o) +all:$(TARGET) + + +$(TARGET): $(OBJFILE) + $(LINK) $^ $(LIBS) -Wall -o $@ + +%.o: %.c + $(CC) -o $@ $(CCFLAGS) $< $(INC) + +%.o: %.cpp + $(CXX) -o $@ $(CXXFLAGS) $< $(INC) + +clean: + rm -f *.o *~ httpsniff + rm -rf $(TARGET) + rm -rf $(OBJFILE) diff --git a/test/c/main.c b/test/c/main.c new file mode 100644 index 0000000..998b381 --- /dev/null +++ b/test/c/main.c @@ -0,0 +1,17 @@ +#include +#include + +int main(void) +{ + int *val = NULL; + map_int_t m; + map_init(&m); + map_set(&m, "testkey", 123); + val = (int*)(map_get(&m, "testkey")); + if (val) { + printf("value: %d\n", *val); + } else { + printf("value not found\n"); + } + return 0; +} diff --git a/test/cpp/Makefile b/test/cpp/Makefile new file mode 100644 index 0000000..1a769f2 --- /dev/null +++ b/test/cpp/Makefile @@ -0,0 +1,46 @@ +CC = gcc +CXX = g++ +LINK = g++ + +CFLAGS_D = $(COMPILER_FLAGS) -c -g -O0 -Wall -Werror +CFLAGS_R = $(COMPILER_FLAGS) -c -g -O2 -Werror +CXXFLAGS_D = $(COMPILER_FLAGS) -c -g -O0 -Werror +CXXFLAGS_R = $(COMPILER_FLAGS) -c -g -O2 -Werror + +INC+= -I. -Iini -I../../src +LIBS += +RELEASE = 0 + +TARGET = cpp_test +CCFLAGS = $(CFLAGS_R) + +ifeq ($(RELEASE),0) + # debug + CFLAGS = $(CFLAGS_D) + CXXFLAGS = $(CXXFLAGS_D) +else + # release + CFLAGS = $(CFLAGS_R) + CXXFLAGS = $(CXXFLAGS_R) +endif + +CXXFILES = main.cpp +CFILES = ../../src/map.c + +OBJFILE = $(CFILES:.c=.o) $(CXXFILES:.cpp=.o) +all:$(TARGET) + + +$(TARGET): $(OBJFILE) + $(LINK) $^ $(LIBS) -Wall -o $@ + +%.o: %.c + $(CC) -o $@ $(CCFLAGS) $< $(INC) + +%.o: %.cpp + $(CXX) -o $@ $(CXXFLAGS) $< $(INC) + +clean: + rm -f *.o *~ httpsniff + rm -rf $(TARGET) + rm -rf $(OBJFILE) diff --git a/test/cpp/Makefile.nmake b/test/cpp/Makefile.nmake new file mode 100644 index 0000000..f29d9ba --- /dev/null +++ b/test/cpp/Makefile.nmake @@ -0,0 +1,17 @@ +# compile +map.obj: ../../src/map.c + cl -c -DWIN32 -D_DEBUG -D_CONSOLE -I../../src ../../src/map.c + +main.obj: main.cpp + cl -c -DWIN32 -D_DEBUG -D_CONSOLE -I../../src main.cpp + +# link +cpp_test.exe: main.obj map.obj + link /NOLOGO /subsystem:console /out:cpp_test.exe main.obj map.obj kernel32.lib + +all: cpp_test.exe + + +clean: + del *.obj + del *.exe \ No newline at end of file diff --git a/test/cpp/main.cpp b/test/cpp/main.cpp new file mode 100644 index 0000000..39fbdbc --- /dev/null +++ b/test/cpp/main.cpp @@ -0,0 +1,16 @@ +#include +#include + +int main(void) +{ + map_int_t m; + map_init(&m); + map_set(&m, "testkey", 123); + int *val = (int*)(map_get(&m, "testkey")); + if (val) { + printf("value: %d\n", *val); + } else { + printf("value not found\n"); + } + return 0; +}