├── .clang-format
├── .gitignore
├── .travis.yml
├── LICENSE-BSD2
├── Makefile
├── README
├── VERSION
├── bench
├── .ycm_extra_conf.py
├── Makefile
├── bench.c
├── bench.h
├── buf_bench.c
├── dict_bench.c
├── heap_bench.c
├── log_bench.c
├── map_bench.c
├── skiplist_bench.c
└── strings_bench.c
├── example
├── .ycm_extra_conf.py
├── Makefile
├── buf_example.c
├── cfg_example.c
├── cfg_example.cfg
├── datetime_example.c
├── dict_example.c
├── event_example.c
├── event_timer_example.c
├── heap_example.c
├── ketama_example.c
├── list_example.c
├── log_example.c
├── map_example.c
├── md5_example.c
├── queue_example.c
├── signals_example.c
├── skiplist_example.c
├── stack_example.c
└── strings_example.c
├── lint.py
├── src
├── buf.c
├── buf.h
├── cfg.c
├── cfg.h
├── datetime.c
├── datetime.h
├── dict.c
├── dict.h
├── event.c
├── event.h
├── event_epoll.c
├── event_kqueue.c
├── event_timer.c
├── heap.c
├── heap.h
├── ketama.c
├── ketama.h
├── list.c
├── list.h
├── log.c
├── log.h
├── map.c
├── map.h
├── md5.c
├── md5.h
├── queue.c
├── queue.h
├── signals.h
├── skiplist.c
├── skiplist.h
├── stack.c
├── stack.h
├── strings.c
├── strings.h
└── utils.h
└── test
├── .ycm_extra_conf.py
├── Makefile
├── buf_test.c
├── cfg_test.c
├── datetime_test.c
├── dict_test.c
├── event_test.c
├── heap_test.c
├── ketama_test.c
├── list_test.c
├── log_test.c
├── map_test.c
├── queue_test.c
├── skiplist_test.c
├── stack_test.c
├── strings_test.c
├── test.c
├── test.h
└── utils_test.c
/.clang-format:
--------------------------------------------------------------------------------
1 | ---
2 | Language: Cpp
3 | AccessModifierOffset: -1
4 | ConstructorInitializerIndentWidth: 4
5 | AlignEscapedNewlinesLeft: true
6 | AlignTrailingComments: true
7 | AllowAllParametersOfDeclarationOnNextLine: true
8 | AllowShortBlocksOnASingleLine: false
9 | AllowShortIfStatementsOnASingleLine: true
10 | AllowShortLoopsOnASingleLine: true
11 | AllowShortFunctionsOnASingleLine: All
12 | AlwaysBreakTemplateDeclarations: true
13 | AlwaysBreakBeforeMultilineStrings: true
14 | BreakBeforeBinaryOperators: false
15 | BreakBeforeTernaryOperators: true
16 | BreakConstructorInitializersBeforeComma: false
17 | BinPackParameters: true
18 | ColumnLimit: 80
19 | ConstructorInitializerAllOnOneLineOrOnePerLine: true
20 | DerivePointerAlignment: true
21 | ExperimentalAutoDetectBinPacking: false
22 | IndentCaseLabels: true
23 | IndentWrappedFunctionNames: false
24 | IndentFunctionDeclarationAfterType: false
25 | MaxEmptyLinesToKeep: 1
26 | KeepEmptyLinesAtTheStartOfBlocks: false
27 | NamespaceIndentation: None
28 | ObjCSpaceAfterProperty: false
29 | ObjCSpaceBeforeProtocolList: false
30 | PenaltyBreakBeforeFirstCallParameter: 1
31 | PenaltyBreakComment: 300
32 | PenaltyBreakString: 1000
33 | PenaltyBreakFirstLessLess: 120
34 | PenaltyExcessCharacter: 1000000
35 | PenaltyReturnTypeOnItsOwnLine: 200
36 | PointerAlignment: Right
37 | SpacesBeforeTrailingComments: 2
38 | Cpp11BracedListStyle: true
39 | Standard: Auto
40 | IndentWidth: 4
41 | TabWidth: 8
42 | UseTab: Never
43 | BreakBeforeBraces: Attach
44 | SpacesInParentheses: false
45 | SpacesInAngles: false
46 | SpaceInEmptyParentheses: false
47 | SpacesInCStyleCastParentheses: false
48 | SpacesInContainerLiterals: true
49 | SpaceBeforeAssignmentOperators: true
50 | ContinuationIndentWidth: 4
51 | CommentPragmas: '^ IWYU pragma:'
52 | ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
53 | SpaceBeforeParens: ControlStatements
54 | DisableFormat: false
55 | ...
56 |
57 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.log
2 | *.o
3 | *.out
4 | *.so
5 | *.h.gch
6 | .*.sw[opn]
7 | *.pyc
8 | src/test
9 | test.log.*
10 | test/test
11 | example/*_example
12 | bench/bench
13 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: required
2 | dist: trusty
3 | language: c
4 | install:
5 | - sudo apt-get install -qq gcc-4.8
6 | - sudo apt-get install -qq clang-format-3.5
7 | script: make lint && make runtests && make runbench
8 |
--------------------------------------------------------------------------------
/LICENSE-BSD2:
--------------------------------------------------------------------------------
1 | Copyright (c) 2016, hit9
2 |
3 | All rights reserved.
4 |
5 | Redistribution and use in source and binary forms, with or without modification,
6 | are permitted provided that the following conditions are met:
7 |
8 | * Redistributions of source code must retain the above copyright notice,
9 | this list of conditions and the following disclaimer.
10 | * Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
18 | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
22 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | # vim:set noet:
2 |
3 | runtests:
4 | make runtests -C test
5 |
6 | examples:
7 | make example -C example
8 |
9 | runbench:
10 | make runbench -C bench
11 |
12 | lint:
13 | python lint.py
14 |
15 | lintfix:
16 | python lint.py fix
17 |
18 | clean:
19 | rm -f src/*.o
20 | make clean -C test
21 | make clean -C example
22 | make clean -C bench
23 |
--------------------------------------------------------------------------------
/README:
--------------------------------------------------------------------------------
1 | buf alpha
2 | cfg alpha
3 | datetime alpha
4 | dict alpha
5 | event alpha
6 | heap alpha
7 | ketama alpha
8 | list alpha
9 | log alpha
10 | map alpha
11 | queue alpha
12 | skiplist alpha
13 | stack alpha
14 | strings alpha
15 |
--------------------------------------------------------------------------------
/VERSION:
--------------------------------------------------------------------------------
1 | 0.3.1
2 |
--------------------------------------------------------------------------------
/bench/.ycm_extra_conf.py:
--------------------------------------------------------------------------------
1 | # This file is NOT licensed under the GPLv3, which is the license for the rest
2 | # of YouCompleteMe.
3 | #
4 | # Here's the license text for this file:
5 | #
6 | # This is free and unencumbered software released into the public domain.
7 | #
8 | # Anyone is free to copy, modify, publish, use, compile, sell, or
9 | # distribute this software, either in source code form or as a compiled
10 | # binary, for any purpose, commercial or non-commercial, and by any
11 | # means.
12 | #
13 | # In jurisdictions that recognize copyright laws, the author or authors
14 | # of this software dedicate any and all copyright interest in the
15 | # software to the public domain. We make this dedication for the benefit
16 | # of the public at large and to the detriment of our heirs and
17 | # successors. We intend this dedication to be an overt act of
18 | # relinquishment in perpetuity of all present and future rights to this
19 | # software under copyright law.
20 | #
21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
24 | # IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
25 | # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
26 | # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27 | # OTHER DEALINGS IN THE SOFTWARE.
28 | #
29 | # For more information, please refer to
30 |
31 | import os
32 | import ycm_core
33 |
34 | flags = [
35 | # INSERT FLAGS HERE
36 | '-Wall',
37 | '-I../src',
38 | '-std=c99',
39 | '-D_GNU_SOURCE',
40 | '-pthread',
41 | ]
42 |
43 |
44 | # Set this to the absolute path to the folder (NOT the file!) containing the
45 | # compile_commands.json file to use that instead of 'flags'. See here for
46 | # more details: http://clang.llvm.org/docs/JSONCompilationDatabase.html
47 | #
48 | # You can get CMake to generate this file for you by adding:
49 | # set( CMAKE_EXPORT_COMPILE_COMMANDS 1 )
50 | # to your CMakeLists.txt file.
51 | #
52 | # Most projects will NOT need to set this to anything; you can just change the
53 | # 'flags' list of compilation flags. Notice that YCM itself uses that approach.
54 | compilation_database_folder = ''
55 |
56 | if os.path.exists(compilation_database_folder):
57 | database = ycm_core.CompilationDatabase(compilation_database_folder)
58 | else:
59 | database = None
60 |
61 | SOURCE_EXTENSIONS = ['.cpp', '.cxx', '.cc', '.c', '.m', '.mm']
62 |
63 |
64 | def DirectoryOfThisScript():
65 | return os.path.dirname(os.path.abspath(__file__))
66 |
67 |
68 | def MakeRelativePathsInFlagsAbsolute(flags, working_directory):
69 | if not working_directory:
70 | return list(flags)
71 | new_flags = []
72 | make_next_absolute = False
73 | path_flags = ['-isystem', '-I', '-iquote', '--sysroot=']
74 | for flag in flags:
75 | new_flag = flag
76 |
77 | if make_next_absolute:
78 | make_next_absolute = False
79 | if not flag.startswith('/'):
80 | new_flag = os.path.join(working_directory, flag)
81 |
82 | for path_flag in path_flags:
83 | if flag == path_flag:
84 | make_next_absolute = True
85 | break
86 |
87 | if flag.startswith(path_flag):
88 | path = flag[len(path_flag):]
89 | new_flag = path_flag + os.path.join(working_directory, path)
90 | break
91 |
92 | if new_flag:
93 | new_flags.append(new_flag)
94 | return new_flags
95 |
96 |
97 | def IsHeaderFile(filename):
98 | extension = os.path.splitext(filename)[1]
99 | return extension in ['.h', '.hxx', '.hpp', '.hh']
100 |
101 |
102 | def GetCompilationInfoForFile(filename):
103 | if IsHeaderFile(filename):
104 | basename = os.path.splitext(filename)[0]
105 | for extension in SOURCE_EXTENSIONS:
106 | replacement_file = basename + extension
107 | if os.path.exists(replacement_file):
108 | compilation_info = database.GetCompilationInfoForFile(
109 | replacement_file)
110 | if compilation_info.compiler_flags_:
111 | return compilation_info
112 | return None
113 | return database.GetCompilationInfoForFile(filename)
114 |
115 |
116 | def FlagsForFile(filename, **kwargs):
117 | if database:
118 | # Bear in mind that compilation_info.compiler_flags_ does NOT return a
119 | # python list, but a "list-like" StringVec object
120 | compilation_info = GetCompilationInfoForFile(filename)
121 | if not compilation_info:
122 | return None
123 |
124 | final_flags = MakeRelativePathsInFlagsAbsolute(
125 | compilation_info.compiler_flags_,
126 | compilation_info.compiler_working_dir_)
127 |
128 | else:
129 | relative_to = DirectoryOfThisScript()
130 | final_flags = MakeRelativePathsInFlagsAbsolute(flags, relative_to)
131 |
132 | return {
133 | 'flags': final_flags,
134 | 'do_cache': True
135 | }
136 |
--------------------------------------------------------------------------------
/bench/Makefile:
--------------------------------------------------------------------------------
1 | # vim:set noet:
2 |
3 | default: runbench
4 |
5 | NAME=bench
6 | CC=cc -std=c99
7 | OPTIMIZATION?=-O2
8 | CFLAGS=-Wall $(OPTIMIZATION) -D_GNU_SOURCE -g -I../src
9 | LDFLAGS=-Wall -pthread
10 | BIN=$(NAME)
11 | SRC:=$(wildcard ../src/*.c) $(wildcard *.c)
12 | EV_EPOLL:=$(wildcard ../src/event_epoll.c)
13 | EV_KQUEUE:=$(wildcard ../src/event_kqueue.c)
14 | EV_TIMER:=$(wildcard ../src/event_timer.c)
15 | SRC:=$(filter-out $(EV_EPOLL), $(SRC))
16 | SRC:=$(filter-out $(EV_KQUEUE), $(SRC))
17 | SRC:=$(filter-out $(EV_TIMER), $(SRC))
18 | OBJ:=$(SRC:c=o)
19 |
20 | $(BIN): $(OBJ)
21 |
22 | runbench: $(BIN)
23 | ./$(BIN)
24 |
25 | clean:
26 | rm -f $(BIN) $(OBJ)
27 |
--------------------------------------------------------------------------------
/bench/bench.c:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015, Chao Wang
3 | */
4 |
5 | #include
6 | #include
7 |
8 | #include "bench.h"
9 | #include "datetime.h"
10 |
11 | /**
12 | * buf_bench
13 | */
14 | void case_buf_puts(struct bench_ctx *ctx);
15 | static struct bench_case buf_bench_cases[] = {
16 | {"buf_puts", &case_buf_puts, 10000},
17 | {"buf_puts", &case_buf_puts, 1000000},
18 | {NULL, NULL, 0},
19 | };
20 |
21 | /**
22 | * dict_bench
23 | */
24 | void case_dict_set(struct bench_ctx *ctx);
25 | void case_dict_get(struct bench_ctx *ctx);
26 | void case_dict_pop(struct bench_ctx *ctx);
27 | static struct bench_case dict_bench_cases[] = {
28 | {"dict_set", &case_dict_set, 10000},
29 | {"dict_set", &case_dict_set, 1000000},
30 | {"dict_get", &case_dict_get, 10000},
31 | {"dict_get", &case_dict_get, 1000000},
32 | {"dict_pop", &case_dict_pop, 10000},
33 | {"dict_pop", &case_dict_pop, 1000000},
34 | {NULL, NULL, 0},
35 | };
36 |
37 | /**
38 | * heap_bench
39 | */
40 | void case_heap_push(struct bench_ctx *ctx);
41 | void case_heap_pop(struct bench_ctx *ctx);
42 | void case_heap_top(struct bench_ctx *ctx);
43 | static struct bench_case heap_bench_cases[] = {
44 | {"heap_push", &case_heap_push, 10000},
45 | {"heap_push", &case_heap_push, 1000000},
46 | {"heap_pop", &case_heap_pop, 10000},
47 | {"heap_pop", &case_heap_pop, 1000000},
48 | {"heap_top", &case_heap_top, 10000},
49 | {"heap_top", &case_heap_top, 1000000},
50 | {NULL, NULL, 0},
51 | };
52 |
53 | /**
54 | * log_bench
55 | */
56 | void case_log_devnull(struct bench_ctx *ctx);
57 | static struct bench_case log_bench_cases[] = {
58 | {"log_devnull", &case_log_devnull, 1000000}, {NULL, NULL, 0},
59 | };
60 |
61 | /**
62 | * map_bench
63 | */
64 | void case_map_set(struct bench_ctx *ctx);
65 | void case_map_get(struct bench_ctx *ctx);
66 | void case_map_pop(struct bench_ctx *ctx);
67 | static struct bench_case map_bench_cases[] = {
68 | {"map_set", &case_map_set, 10000},
69 | {"map_set", &case_map_set, 1000000},
70 | {"map_get", &case_map_get, 10000},
71 | {"map_get", &case_map_get, 1000000},
72 | {"map_pop", &case_map_pop, 10000},
73 | {"map_pop", &case_map_pop, 1000000},
74 | {NULL, NULL, 0},
75 | };
76 |
77 | /**
78 | * skiplist_bench
79 | */
80 | void case_skiplist_push(struct bench_ctx *ctx);
81 | void case_skiplist_get(struct bench_ctx *ctx);
82 | void case_skiplist_pop(struct bench_ctx *ctx);
83 | void case_skiplist_popfirst(struct bench_ctx *ctx);
84 | void case_skiplist_first(struct bench_ctx *ctx);
85 | static struct bench_case skiplist_bench_cases[] = {
86 | {"skiplist_push", &case_skiplist_push, 10000},
87 | {"skiplist_push", &case_skiplist_push, 1000000},
88 | {"skiplist_get", &case_skiplist_get, 10000},
89 | {"skiplist_get", &case_skiplist_get, 1000000},
90 | {"skiplist_pop", &case_skiplist_pop, 10000},
91 | {"skiplist_pop", &case_skiplist_pop, 1000000},
92 | {"skiplist_first", &case_skiplist_first, 10000},
93 | {"skiplist_first", &case_skiplist_first, 1000000},
94 | {"skiplist_popfirst", &case_skiplist_popfirst, 10000},
95 | {"skiplist_popfirst", &case_skiplist_popfirst, 1000000},
96 | {NULL, NULL, 0},
97 | };
98 |
99 | /**
100 | * strings_bench
101 | */
102 | void case_strings_search(struct bench_ctx *ctx);
103 | void case_strings_replace(struct bench_ctx *ctx);
104 | void case_strings_rand(struct bench_ctx *ctx);
105 | static struct bench_case strings_bench_cases[] = {
106 | {"strings_search", &case_strings_search, 1000000},
107 | {"strings_replace", &case_strings_replace, 1000000},
108 | {"strings_rand", &case_strings_rand, 1000000},
109 | {NULL, NULL, 0},
110 | };
111 |
112 | /**
113 | * bench
114 | */
115 | void bench_ctx_reset_start_at(struct bench_ctx *ctx) {
116 | assert(ctx != NULL);
117 | ctx->start_at = datetime_stamp_now();
118 | }
119 |
120 | void bench_ctx_reset_end_at(struct bench_ctx *ctx) {
121 | assert(ctx != NULL);
122 | ctx->end_at = datetime_stamp_now();
123 | }
124 |
125 | static void run_cases(const char *name, struct bench_case cases[]) {
126 | int idx = 0;
127 |
128 | while (1) {
129 | struct bench_case c = cases[idx];
130 | if (c.name == NULL || c.fn == NULL) break;
131 | fprintf(stderr, "%-17s %-20s ", name, c.name);
132 | struct bench_ctx ctx = {datetime_stamp_now(), -1, c.n};
133 | (c.fn)(&ctx);
134 | double start_at = ctx.start_at;
135 | double end_at = ctx.end_at;
136 | if (end_at < 0) end_at = datetime_stamp_now();
137 | idx += 1;
138 | fprintf(stderr, "%10ld%10ldns/op\n", c.n,
139 | (long)(1000000.0 * (end_at - start_at) / (double)c.n));
140 | }
141 | }
142 |
143 | int main(int argc, const char *argv[]) {
144 | run_cases("buf_bench", buf_bench_cases);
145 | run_cases("dict_bench", dict_bench_cases);
146 | run_cases("heap_bench", heap_bench_cases);
147 | run_cases("log_stderr", log_bench_cases);
148 | run_cases("map_bench", map_bench_cases);
149 | run_cases("skiplist_bench", skiplist_bench_cases);
150 | run_cases("strings_bench", strings_bench_cases);
151 | return 0;
152 | }
153 |
--------------------------------------------------------------------------------
/bench/bench.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015, Chao Wang
3 | */
4 |
5 | struct bench_ctx {
6 | double start_at; /* bench start_at */
7 | double end_at; /* bench end_at */
8 | long n; /* bench times */
9 | };
10 |
11 | struct bench_case {
12 | const char *name; /* bench case name */
13 | void (*fn)(struct bench_ctx *ctx); /* bench function */
14 | long n; /* bench times */
15 | };
16 |
17 | void bench_ctx_reset_start_at(struct bench_ctx *ctx);
18 | void bench_ctx_reset_end_at(struct bench_ctx *ctx);
19 |
--------------------------------------------------------------------------------
/bench/buf_bench.c:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015, Chao Wang
3 | */
4 |
5 | #include "bench.h"
6 | #include "buf.h"
7 |
8 | void case_buf_puts(struct bench_ctx *ctx) {
9 | struct buf *buf = buf(NULL);
10 | int i;
11 | bench_ctx_reset_start_at(ctx);
12 | for (i = 0; i < ctx->n; i++) {
13 | buf_puts(buf, "abcdefg");
14 | }
15 | bench_ctx_reset_end_at(ctx);
16 | buf_free(buf);
17 | }
18 |
--------------------------------------------------------------------------------
/bench/dict_bench.c:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015, Chao Wang
3 | */
4 |
5 | #include
6 | #include "bench.h"
7 | #include "dict.h"
8 |
9 | void case_dict_set(struct bench_ctx *ctx) {
10 | struct dict *dict = dict();
11 | /* keys suite */
12 | int i;
13 | char keys[ctx->n][4];
14 | for (i = 0; i < ctx->n; i++) sprintf(keys[i], "%d", i & 999);
15 | /* bench */
16 | bench_ctx_reset_start_at(ctx);
17 | for (i = 0; i < ctx->n; i++) {
18 | dict_set(dict, keys[i], "val");
19 | }
20 | bench_ctx_reset_end_at(ctx);
21 | dict_free(dict);
22 | }
23 |
24 | void case_dict_get(struct bench_ctx *ctx) {
25 | struct dict *dict = dict();
26 | /* suite */
27 | int i;
28 | char keys[ctx->n][4];
29 | for (i = 0; i < ctx->n; i++) {
30 | sprintf(keys[i], "%d", i & 999);
31 | dict_set(dict, keys[i], "val");
32 | }
33 | /* bench */
34 | bench_ctx_reset_start_at(ctx);
35 | for (i = 0; i < ctx->n; i++) {
36 | dict_get(dict, keys[i]);
37 | }
38 | bench_ctx_reset_end_at(ctx);
39 | dict_free(dict);
40 | }
41 |
42 | void case_dict_pop(struct bench_ctx *ctx) {
43 | struct dict *dict = dict();
44 | /* suite */
45 | int i;
46 | char keys[ctx->n][4];
47 | for (i = 0; i < ctx->n; i++) {
48 | sprintf(keys[i], "%d", i & 999);
49 | dict_set(dict, keys[i], "val");
50 | }
51 | /* bench */
52 | bench_ctx_reset_start_at(ctx);
53 | for (i = 0; i < ctx->n; i++) {
54 | dict_pop(dict, keys[i]);
55 | }
56 | bench_ctx_reset_end_at(ctx);
57 | dict_free(dict);
58 | }
59 |
--------------------------------------------------------------------------------
/bench/heap_bench.c:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015, Chao Wang
3 | */
4 |
5 | #include
6 | #include "bench.h"
7 | #include "heap.h"
8 |
9 | int heap_bench_cmp(void *a, void *b) { return *(int *)a - *(int *)b; }
10 | void case_heap_push(struct bench_ctx *ctx) {
11 | struct heap *heap = heap(&heap_bench_cmp);
12 | int i;
13 | bench_ctx_reset_start_at(ctx);
14 | for (i = 0; i < ctx->n; i++) {
15 | heap_push(heap, &i);
16 | }
17 | bench_ctx_reset_end_at(ctx);
18 | heap_free(heap);
19 | }
20 |
21 | void case_heap_pop(struct bench_ctx *ctx) {
22 | struct heap *heap = heap(&heap_bench_cmp);
23 | int i;
24 | for (i = 0; i < ctx->n; i++) {
25 | heap_push(heap, &i);
26 | }
27 | bench_ctx_reset_start_at(ctx);
28 | for (i = 0; i < ctx->n; i++) {
29 | heap_pop(heap);
30 | }
31 | bench_ctx_reset_end_at(ctx);
32 | heap_free(heap);
33 | }
34 |
35 | void case_heap_top(struct bench_ctx *ctx) {
36 | struct heap *heap = heap(&heap_bench_cmp);
37 | int i;
38 | for (i = 0; i < ctx->n; i++) {
39 | heap_push(heap, &i);
40 | }
41 | bench_ctx_reset_start_at(ctx);
42 | for (i = 0; i < ctx->n; i++) {
43 | heap_top(heap);
44 | }
45 | bench_ctx_reset_end_at(ctx);
46 | heap_free(heap);
47 | }
48 |
--------------------------------------------------------------------------------
/bench/log_bench.c:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015, Chao Wang
3 | */
4 |
5 | #include
6 |
7 | #include "bench.h"
8 | #include "log.h"
9 |
10 | void case_log_devnull(struct bench_ctx *ctx) {
11 | log_open("bench", "/dev/null", 0);
12 | bench_ctx_reset_start_at(ctx);
13 | int i;
14 | for (i = 0; i < ctx->n; i++) {
15 | log_info("hello %s", "world");
16 | }
17 | bench_ctx_reset_end_at(ctx);
18 | }
19 |
--------------------------------------------------------------------------------
/bench/map_bench.c:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015, Chao Wang
3 | */
4 |
5 | #include
6 |
7 | #include "bench.h"
8 | #include "map.h"
9 |
10 | void case_map_set(struct bench_ctx *ctx) {
11 | struct map *m = map();
12 | /* keys suite */
13 | int i;
14 | char keys[ctx->n][4];
15 | for (i = 0; i < ctx->n; i++) sprintf(keys[i], "%d", i & 999);
16 | /* bench */
17 | bench_ctx_reset_start_at(ctx);
18 | for (i = 0; i < ctx->n; i++) {
19 | map_set(m, keys[i], "val");
20 | }
21 | bench_ctx_reset_end_at(ctx);
22 | map_free(m);
23 | }
24 |
25 | void case_map_get(struct bench_ctx *ctx) {
26 | struct map *m = map();
27 | /* suite */
28 | int i;
29 | char keys[ctx->n][4];
30 | for (i = 0; i < ctx->n; i++) {
31 | sprintf(keys[i], "%d", i & 999);
32 | map_set(m, keys[i], "val");
33 | }
34 | /* bench */
35 | bench_ctx_reset_start_at(ctx);
36 | for (i = 0; i < ctx->n; i++) {
37 | map_get(m, keys[i]);
38 | }
39 | bench_ctx_reset_end_at(ctx);
40 | map_free(m);
41 | }
42 |
43 | void case_map_pop(struct bench_ctx *ctx) {
44 | struct map *m = map();
45 | /* suite */
46 | int i;
47 | char keys[ctx->n][4];
48 | for (i = 0; i < ctx->n; i++) {
49 | sprintf(keys[i], "%d", i & 999);
50 | map_set(m, keys[i], "val");
51 | }
52 | /* bench */
53 | bench_ctx_reset_start_at(ctx);
54 | for (i = 0; i < ctx->n; i++) {
55 | map_pop(m, keys[i]);
56 | }
57 | bench_ctx_reset_end_at(ctx);
58 | map_free(m);
59 | }
60 |
--------------------------------------------------------------------------------
/bench/skiplist_bench.c:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015, Chao Wang
3 | */
4 |
5 | #include
6 | #include
7 |
8 | #include "bench.h"
9 | #include "skiplist.h"
10 |
11 | void case_skiplist_push(struct bench_ctx *ctx) {
12 | struct skiplist *sl = skiplist(NULL);
13 |
14 | int i;
15 | bench_ctx_reset_start_at(ctx);
16 | for (i = 0; i < ctx->n; i++) {
17 | skiplist_push(sl, i, "v");
18 | }
19 | bench_ctx_reset_end_at(ctx);
20 | skiplist_free(sl);
21 | }
22 |
23 | void case_skiplist_get(struct bench_ctx *ctx) {
24 | struct skiplist *sl = skiplist(NULL);
25 |
26 | int i;
27 | for (i = 0; i < ctx->n; i++) {
28 | skiplist_push(sl, i, "v");
29 | }
30 | bench_ctx_reset_start_at(ctx);
31 | for (i = 0; i < ctx->n; i++) {
32 | skiplist_get(sl, i);
33 | }
34 | bench_ctx_reset_end_at(ctx);
35 | skiplist_free(sl);
36 | }
37 |
38 | void case_skiplist_pop(struct bench_ctx *ctx) {
39 | struct skiplist *sl = skiplist(NULL);
40 |
41 | int i;
42 | for (i = 0; i < ctx->n; i++) {
43 | skiplist_push(sl, i, "v");
44 | }
45 | bench_ctx_reset_start_at(ctx);
46 | for (i = 0; i < ctx->n; i++) {
47 | skiplist_pop(sl, i);
48 | }
49 | bench_ctx_reset_end_at(ctx);
50 | skiplist_free(sl);
51 | }
52 |
53 | void case_skiplist_popfirst(struct bench_ctx *ctx) {
54 | struct skiplist *sl = skiplist(NULL);
55 |
56 | int i;
57 | for (i = 0; i < ctx->n; i++) {
58 | skiplist_push(sl, i, "v");
59 | }
60 | bench_ctx_reset_start_at(ctx);
61 | for (i = 0; i < ctx->n; i++) {
62 | skiplist_popfirst(sl);
63 | }
64 | bench_ctx_reset_end_at(ctx);
65 | skiplist_free(sl);
66 | }
67 |
68 | void case_skiplist_first(struct bench_ctx *ctx) {
69 | struct skiplist *sl = skiplist(NULL);
70 |
71 | int i;
72 | for (i = 0; i < ctx->n; i++) {
73 | skiplist_push(sl, i, "v");
74 | }
75 | bench_ctx_reset_start_at(ctx);
76 | for (i = 0; i < ctx->n; i++) {
77 | skiplist_first(sl);
78 | }
79 | bench_ctx_reset_end_at(ctx);
80 | skiplist_free(sl);
81 | }
82 |
--------------------------------------------------------------------------------
/bench/strings_bench.c:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015, Chao Wang
3 | */
4 |
5 | #include
6 |
7 | #include "bench.h"
8 | #include "strings.h"
9 |
10 | void case_strings_search(struct bench_ctx *ctx) {
11 | /* suite */
12 | int i;
13 | char strs[ctx->n][32];
14 | char subs[ctx->n][4];
15 | for (i = 0; i < ctx->n; i++) {
16 | sprintf(strs[i], "%d", i);
17 | sprintf(subs[i], "%d", i & 999);
18 | }
19 | /* bench */
20 | bench_ctx_reset_start_at(ctx);
21 | for (i = 0; i < ctx->n; i++) {
22 | strings_search(strs[i], subs[i], 0);
23 | }
24 | bench_ctx_reset_end_at(ctx);
25 | }
26 |
27 | void case_strings_replace(struct bench_ctx *ctx) {
28 | /* suite */
29 | int i;
30 | char strs[ctx->n][32];
31 | char subs[ctx->n][4];
32 | for (i = 0; i < ctx->n; i++) {
33 | sprintf(strs[i], "%d", i);
34 | sprintf(subs[i], "%d", i & 999);
35 | }
36 | /* bench */
37 | bench_ctx_reset_start_at(ctx);
38 | for (i = 0; i < ctx->n; i++) {
39 | char dst[100];
40 | strings_replace(dst, strs[i], subs[i], "rep");
41 | }
42 | bench_ctx_reset_end_at(ctx);
43 | }
44 |
45 | void case_strings_rand(struct bench_ctx *ctx) {
46 | int i;
47 | for (i = 0; i < ctx->n; i++) {
48 | char s[32];
49 | strings_rand(s, 32);
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/example/.ycm_extra_conf.py:
--------------------------------------------------------------------------------
1 | # This file is NOT licensed under the GPLv3, which is the license for the rest
2 | # of YouCompleteMe.
3 | #
4 | # Here's the license text for this file:
5 | #
6 | # This is free and unencumbered software released into the public domain.
7 | #
8 | # Anyone is free to copy, modify, publish, use, compile, sell, or
9 | # distribute this software, either in source code form or as a compiled
10 | # binary, for any purpose, commercial or non-commercial, and by any
11 | # means.
12 | #
13 | # In jurisdictions that recognize copyright laws, the author or authors
14 | # of this software dedicate any and all copyright interest in the
15 | # software to the public domain. We make this dedication for the benefit
16 | # of the public at large and to the detriment of our heirs and
17 | # successors. We intend this dedication to be an overt act of
18 | # relinquishment in perpetuity of all present and future rights to this
19 | # software under copyright law.
20 | #
21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
24 | # IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
25 | # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
26 | # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27 | # OTHER DEALINGS IN THE SOFTWARE.
28 | #
29 | # For more information, please refer to
30 |
31 | import os
32 | import ycm_core
33 |
34 | flags = [
35 | # INSERT FLAGS HERE
36 | '-Wall',
37 | '-I../src',
38 | '-std=c99',
39 | '-D_GNU_SOURCE',
40 | '-pthread',
41 | ]
42 |
43 |
44 | # Set this to the absolute path to the folder (NOT the file!) containing the
45 | # compile_commands.json file to use that instead of 'flags'. See here for
46 | # more details: http://clang.llvm.org/docs/JSONCompilationDatabase.html
47 | #
48 | # You can get CMake to generate this file for you by adding:
49 | # set( CMAKE_EXPORT_COMPILE_COMMANDS 1 )
50 | # to your CMakeLists.txt file.
51 | #
52 | # Most projects will NOT need to set this to anything; you can just change the
53 | # 'flags' list of compilation flags. Notice that YCM itself uses that approach.
54 | compilation_database_folder = ''
55 |
56 | if os.path.exists(compilation_database_folder):
57 | database = ycm_core.CompilationDatabase(compilation_database_folder)
58 | else:
59 | database = None
60 |
61 | SOURCE_EXTENSIONS = ['.cpp', '.cxx', '.cc', '.c', '.m', '.mm']
62 |
63 |
64 | def DirectoryOfThisScript():
65 | return os.path.dirname(os.path.abspath(__file__))
66 |
67 |
68 | def MakeRelativePathsInFlagsAbsolute(flags, working_directory):
69 | if not working_directory:
70 | return list(flags)
71 | new_flags = []
72 | make_next_absolute = False
73 | path_flags = ['-isystem', '-I', '-iquote', '--sysroot=']
74 | for flag in flags:
75 | new_flag = flag
76 |
77 | if make_next_absolute:
78 | make_next_absolute = False
79 | if not flag.startswith('/'):
80 | new_flag = os.path.join(working_directory, flag)
81 |
82 | for path_flag in path_flags:
83 | if flag == path_flag:
84 | make_next_absolute = True
85 | break
86 |
87 | if flag.startswith(path_flag):
88 | path = flag[len(path_flag):]
89 | new_flag = path_flag + os.path.join(working_directory, path)
90 | break
91 |
92 | if new_flag:
93 | new_flags.append(new_flag)
94 | return new_flags
95 |
96 |
97 | def IsHeaderFile(filename):
98 | extension = os.path.splitext(filename)[1]
99 | return extension in ['.h', '.hxx', '.hpp', '.hh']
100 |
101 |
102 | def GetCompilationInfoForFile(filename):
103 | if IsHeaderFile(filename):
104 | basename = os.path.splitext(filename)[0]
105 | for extension in SOURCE_EXTENSIONS:
106 | replacement_file = basename + extension
107 | if os.path.exists(replacement_file):
108 | compilation_info = database.GetCompilationInfoForFile(
109 | replacement_file)
110 | if compilation_info.compiler_flags_:
111 | return compilation_info
112 | return None
113 | return database.GetCompilationInfoForFile(filename)
114 |
115 |
116 | def FlagsForFile(filename, **kwargs):
117 | if database:
118 | # Bear in mind that compilation_info.compiler_flags_ does NOT return a
119 | # python list, but a "list-like" StringVec object
120 | compilation_info = GetCompilationInfoForFile(filename)
121 | if not compilation_info:
122 | return None
123 |
124 | final_flags = MakeRelativePathsInFlagsAbsolute(
125 | compilation_info.compiler_flags_,
126 | compilation_info.compiler_working_dir_)
127 |
128 | else:
129 | relative_to = DirectoryOfThisScript()
130 | final_flags = MakeRelativePathsInFlagsAbsolute(flags, relative_to)
131 |
132 | return {
133 | 'flags': final_flags,
134 | 'do_cache': True
135 | }
136 |
--------------------------------------------------------------------------------
/example/Makefile:
--------------------------------------------------------------------------------
1 | # vim:set noet:
2 |
3 | default: example
4 |
5 | CC?=cc -std=c99
6 | CFLAGS?=-Wall -I../src -D_GNU_SOURCE
7 | LDFLAGS?=-Wall
8 |
9 | buf_example: buf_example.c ../src/buf.c
10 | cfg_example: cfg_example.c ../src/buf.c ../src/cfg.c
11 | datetime_example: datetime_example.c ../src/datetime.c
12 | dict_example: dict_example.c ../src/dict.c
13 | event_example: event_example.c ../src/event.c
14 | event_timer_example: event_timer_example.c ../src/event.c
15 | heap_example: heap_example.c ../src/heap.c
16 | ketama_example: ketama_example.c ../src/md5.c ../src/ketama.c
17 | list_example: list_example.c ../src/list.c
18 | log_example: log_example.c ../src/log.c
19 | map_example: map_example.c ../src/map.c
20 | md5_example: md5_example.c ../src/md5.c
21 | queue_example: queue_example.c ../src/queue.c
22 | signals_example: signals_example.c ../src/event.c
23 | skiplist_example: skiplist_example.c ../src/skiplist.c
24 | stack_example: stack_example.c ../src/stack.c
25 | strings_example: strings_example.c ../src/strings.c
26 |
27 | example: buf_example\
28 | cfg_example\
29 | datetime_example\
30 | dict_example\
31 | event_example\
32 | event_timer_example\
33 | heap_example\
34 | ketama_example\
35 | list_example\
36 | log_example\
37 | map_example\
38 | md5_example\
39 | queue_example\
40 | signals_example\
41 | skiplist_example\
42 | stack_example\
43 | strings_example
44 |
45 | clean:
46 | rm -f *_example
47 |
--------------------------------------------------------------------------------
/example/buf_example.c:
--------------------------------------------------------------------------------
1 | // cc buf_example.c buf.c
2 |
3 | #include
4 | #include
5 |
6 | #include "buf.h"
7 |
8 | int main(int argc, const char *argv[]) {
9 | struct buf *buf = buf("example");
10 | /* test if buffer is empty or NULL */
11 | assert(buf != NULL && !buf_isempty(buf));
12 | /* put string to buffer */
13 | assert(buf_puts(buf, "abc") == BUF_OK);
14 | /* put char to buffer */
15 | assert(buf_putc(buf, 'd') == BUF_OK);
16 | /* format data into buffer */
17 | assert(buf_sprintf(buf, "%s%d", "efg", 123) == BUF_OK);
18 | /* print buffer, should be "exampleabcdefg123" */
19 | printf("%s\n", str(buf));
20 | /* get buffer length */
21 | printf("current buffer length is %zu, capacity is %zu\n", buf_len(buf),
22 | buf_cap(buf));
23 | /* free buffer */
24 | buf_free(buf);
25 | return 0;
26 | }
27 |
--------------------------------------------------------------------------------
/example/cfg_example.c:
--------------------------------------------------------------------------------
1 | // cc cfg_example.c cfg.c buf.c
2 |
3 | #include
4 | #include
5 |
6 | #include "buf.h"
7 | #include "cfg.h"
8 |
9 | #define READ_UNIT 1024
10 |
11 | int read_file_into_buffer(const char *filename, struct buf *buf);
12 |
13 | int main(int argc, const char *argv[]) {
14 | /* Read file into buffer */
15 | struct buf *buf = buf_new(NULL);
16 | if (read_file_into_buffer("cfg_example.cfg", buf) != BUF_OK) return -1;
17 |
18 | /* Parse config */
19 | struct cfg cfg = {buf->data, buf->len, 1};
20 | int err = 0;
21 | cfg_each(cfg, err) {
22 | printf("%.*s => %.*s\n", (int)(cfg.key_len), cfg.key,
23 | (int)(cfg.val_len), cfg.val);
24 | }
25 |
26 | if (err == CFG_EBADFMT) {
27 | printf("bad format on line %zd\n", cfg.lineno);
28 | return -2;
29 | }
30 |
31 | buf_free(buf);
32 | return 0;
33 | }
34 |
35 | int read_file_into_buffer(const char *filename, struct buf *buf) {
36 | int nread;
37 | FILE *fp = fopen(filename, "r");
38 |
39 | if (fp == NULL) return -1;
40 |
41 | while (1) {
42 | if (buf_grow(buf, buf->len + READ_UNIT) != BUF_OK) return BUF_ENOMEM;
43 |
44 | if ((nread = fread(buf->data + buf->len, sizeof(char),
45 | buf->cap - buf->len, fp)) <= 0)
46 | break;
47 |
48 | buf->len += nread;
49 | }
50 | return BUF_OK;
51 | }
52 |
--------------------------------------------------------------------------------
/example/cfg_example.cfg:
--------------------------------------------------------------------------------
1 | port 8125 # port to bind
2 |
3 | # all backend nodes
4 | node 127.0.0.1:8126
5 | node 127.0.0.1:8127
6 | node 127.0.0.1:8128
7 |
--------------------------------------------------------------------------------
/example/datetime_example.c:
--------------------------------------------------------------------------------
1 | // cc datetime_example.c datetime.c
2 |
3 | #include
4 |
5 | #include "datetime.h"
6 |
7 | int main(int argc, const char *argv[]) {
8 | /* get current timstamp (in milliseconds) */
9 | printf("timstamp (ms) for now is: %.3f ms\n", datetime_stamp_now());
10 | return 0;
11 | }
12 |
--------------------------------------------------------------------------------
/example/dict_example.c:
--------------------------------------------------------------------------------
1 | // cc dict_example.c dict.c
2 |
3 | #include
4 | #include
5 | #include
6 |
7 | #include "dict.h"
8 |
9 | int main(int argc, const char *argv[]) {
10 | /* allocate a new dict */
11 | struct dict *dict = dict();
12 | /* set key and values to dict */
13 | char *key1 = "key1";
14 | char *key2 = "key2";
15 | char *val1 = "val1";
16 | char *val2 = "val2";
17 | assert(dict_set(dict, key1, val1) == DICT_OK);
18 | assert(dict_set(dict, key2, val2) == DICT_OK);
19 | /* get dict length */
20 | assert(dict_len(dict) == 2);
21 | /* get data by key */
22 | assert(dict_get(dict, key1) == val1);
23 | assert(dict_get(dict, key2) == val2);
24 | /* iterate dict */
25 | struct dict_iter iter = {dict};
26 | struct dict_node *node = NULL;
27 | dict_each(&iter, node) {
28 | printf("%s => %s\n", node->key, (char *)node->val);
29 | }
30 | /* free the dict */
31 | dict_free(dict);
32 | return 0;
33 | }
34 |
--------------------------------------------------------------------------------
/example/event_example.c:
--------------------------------------------------------------------------------
1 | // cc event_example.c event.c
2 |
3 | #include
4 | #include
5 | #include
6 |
7 | #include "event.h"
8 |
9 | void echo(struct event_loop *loop, int fd, int mask, void *data) {
10 | char s[256];
11 |
12 | if (fd == STDIN_FILENO) {
13 | scanf("%s", s);
14 |
15 | if (strcmp(s, "exit") == 0) {
16 | /* stop the event loop on message "exit" */
17 | printf("bye!\n");
18 | event_loop_stop(loop);
19 | } else {
20 | printf("your input is: %s\n", s);
21 | }
22 | }
23 | }
24 |
25 | void heartbeat(struct event_loop *loop, int id, void *data) {
26 | printf("heartbeat every 1000ms\n");
27 | }
28 |
29 | int main(int argc, const char *argv[]) {
30 | /* allocate a new event loop with events number limitation 1024 */
31 | struct event_loop *loop = event_loop(1024);
32 | /* call `echo()` when stdin is readable (on data coming in) */
33 | event_add_in(loop, STDIN_FILENO, &echo, NULL);
34 | /* call `heartbeat` every 1 second */
35 | event_add_timer(loop, 1000, &heartbeat, NULL);
36 | /* start event loop */
37 | printf("start event loop, type 'exit' to exit.. \n");
38 | event_loop_start(loop);
39 | /* free event loop */
40 | event_loop_free(loop);
41 | return 0;
42 | }
43 |
--------------------------------------------------------------------------------
/example/event_timer_example.c:
--------------------------------------------------------------------------------
1 | // cc event_timer_example.c event.c
2 |
3 | #include
4 | #include
5 | #include
6 |
7 | #include "event.h"
8 |
9 | void beat1000(struct event_loop *loop, int id, void *data) {
10 | printf("heartbeat every 1s\n");
11 | }
12 |
13 | void beat2000(struct event_loop *loop, int id, void *data) {
14 | printf("heartbeat every 2s\n");
15 | }
16 |
17 | void beat3000(struct event_loop *loop, int id, void *data) {
18 | printf("heartbeat every 3s\n");
19 | }
20 |
21 | void beatonce(struct event_loop *loop, int id, void *data) {
22 | printf("heartbeat only once after 5s\n");
23 | /* stop this timer */
24 | event_del_timer(loop, id);
25 | }
26 |
27 | int main(int argc, const char *argv[]) {
28 | /* allocate a new event loop with no fire events */
29 | struct event_loop *loop = event_loop(0);
30 | /* add some timer events */
31 | event_add_timer(loop, 1000, &beat1000, NULL);
32 | event_add_timer(loop, 2000, &beat2000, NULL);
33 | event_add_timer(loop, 3000, &beat3000, NULL);
34 | event_add_timer(loop, 5000, &beatonce, NULL);
35 | /* start event loop */
36 | event_loop_start(loop);
37 | /* stop event loop */
38 | event_loop_stop(loop);
39 | /* free event loop */
40 | event_loop_free(loop);
41 | return 0;
42 | }
43 |
--------------------------------------------------------------------------------
/example/heap_example.c:
--------------------------------------------------------------------------------
1 | // cc heap_example.c heap.c
2 |
3 | #include
4 | #include
5 |
6 | #include "heap.h"
7 |
8 | /* heap node comparator type, return negative if arg#0 < arg#1 */
9 | int cmp(void *a, void *b) { return *(int *)a - *(int *)b; }
10 | int main(int argc, const char *argv[]) {
11 | /* allocate empty heap with comparator */
12 | struct heap *heap = heap(cmp);
13 | /* push data into heap */
14 | int a = 4, b = 1, c = 3, d = 2, e = 5;
15 | assert(heap_push(heap, &a) == HEAP_OK);
16 | assert(heap_push(heap, &b) == HEAP_OK);
17 | assert(heap_push(heap, &c) == HEAP_OK);
18 | assert(heap_push(heap, &d) == HEAP_OK);
19 | assert(heap_push(heap, &e) == HEAP_OK);
20 | /* get current heap memory capacity (or memory allocated) */
21 | printf("current heap allocated memory: %zu\n", heap_cap(heap));
22 | printf("current heap length: %zu\n", heap_len(heap));
23 | /* get current smallest data */
24 | printf("smallest: %d\n", *(int *)heap_top(heap));
25 | /* pop and print all data (should be in order) */
26 | while (heap_len(heap) != 0) printf("%d\n", *(int *)heap_pop(heap));
27 | /* free heap */
28 | heap_free(heap);
29 | return 0;
30 | }
31 |
--------------------------------------------------------------------------------
/example/ketama_example.c:
--------------------------------------------------------------------------------
1 | // cc ketama_example.c ketama.c md5.c
2 |
3 | #include
4 | #include
5 |
6 | #include "ketama.h"
7 |
8 | int main(int argc, const char *argv[]) {
9 | /* ketama node array */
10 | struct ketama_node nodes[4] = {
11 | {"127.0.0.1:8000", 1, "server a"},
12 | {"127.0.0.1:8001", 1, "server b"},
13 | {"127.0.0.1:8002", 1, "server c"},
14 | {"127.0.0.1:8003", 1, "server d"},
15 | };
16 | /* create a ketama ring of 4 nodes */
17 | struct ketama_ring *ring = ketama_ring(nodes, 4);
18 | /* get node by null-terminated key */
19 | struct ketama_node *node = ketama_node_get(ring, "key");
20 | printf("get a node by 'key': %s %s\n", node->key, (char *)node->data);
21 | /* get again, consistence hashing */
22 | node = ketama_node_get(ring, "key");
23 | printf("get again by 'key': %s %s\n", node->key, (char *)node->data);
24 | /* free the ring */
25 | ketama_ring_free(ring);
26 | return 0;
27 | }
28 |
--------------------------------------------------------------------------------
/example/list_example.c:
--------------------------------------------------------------------------------
1 | // cc list_example.c list.c
2 |
3 | #include
4 | #include
5 |
6 | #include "list.h"
7 |
8 | int main(int argc, const char *argv[]) {
9 | /* allocate a empty list */
10 | struct list *list = list();
11 | /* push data to the list (on the right)*/
12 | assert(list_push(list, "a") == LIST_OK);
13 | assert(list_push(list, "b") == LIST_OK);
14 | assert(list_push(list, "c") == LIST_OK);
15 | assert(list_push(list, "d") == LIST_OK);
16 | /* get list current length */
17 | assert(list_len(list) == 4);
18 | /* pop a node from list (on the left) */
19 | assert(list_pop(list) != NULL);
20 | /* iterate the list and print the nodes */
21 | struct list_node *node;
22 | list_each(list, node) { printf("%s ", (char *)node->data); }
23 | /* free the list */
24 | list_free(list);
25 | return 0;
26 | }
27 |
--------------------------------------------------------------------------------
/example/log_example.c:
--------------------------------------------------------------------------------
1 | // cc log_example.c log.c -rdynamic
2 |
3 | #include "log.h"
4 |
5 | char make_segmentfault() {
6 | char *s = NULL;
7 | char ch = s[1]; // segment fault
8 | return ch;
9 | }
10 |
11 | int main(int argc, const char *argv[]) {
12 | /* open global logger to stderr (by setting filename to NULL) */
13 | log_open("example", NULL, 0);
14 | /* set log level to info, also the default level */
15 | log_setlevel(LOG_INFO);
16 | /* debug mesage won't be seen */
17 | log_debug("debug message");
18 | /* but info and warn, error message can be seen */
19 | log_info("info message");
20 | log_warn("warn message");
21 | log_error("error message: %s", "someting wrong");
22 | /* will log trace back on segmentfault automatically */
23 | make_segmentfault();
24 | return 0;
25 | }
26 |
--------------------------------------------------------------------------------
/example/map_example.c:
--------------------------------------------------------------------------------
1 | // cc map_example.c map.c
2 |
3 | #include
4 | #include
5 | #include
6 |
7 | #include "map.h"
8 |
9 | int main(int argc, const char *argv[]) {
10 | /* allocate a new map */
11 | struct map *m = map();
12 | /* set key and values to map */
13 | char *key1 = "key1";
14 | char *key2 = "key2";
15 | char *val1 = "val1";
16 | char *val2 = "val2";
17 | assert(map_set(m, key1, val1) == MAP_OK);
18 | assert(map_set(m, key2, val2) == MAP_OK);
19 | /* get map length */
20 | assert(map_len(m) == 2);
21 | /* get data by key */
22 | assert(map_get(m, key1) == val1);
23 | assert(map_get(m, key2) == val2);
24 | /* set some key values more */
25 | assert(map_set(m, "key3", "val3") == MAP_OK);
26 | assert(map_set(m, "key4", "val4") == MAP_OK);
27 | assert(map_set(m, "key5", "val5") == MAP_OK);
28 | assert(map_set(m, "key6", "val6") == MAP_OK);
29 | assert(map_set(m, "key7", "val7") == MAP_OK);
30 | /* iterate the map */
31 | struct map_iter iter = {m};
32 | struct map_node *node = NULL;
33 | map_each(&iter, node) {
34 | printf("%s => %s\n", node->key, (char *)node->val);
35 | }
36 | /* free the map */
37 | map_free(m);
38 | return 0;
39 | }
40 |
--------------------------------------------------------------------------------
/example/md5_example.c:
--------------------------------------------------------------------------------
1 | // cc md5_example.c md5.c
2 |
3 | #include
4 | #include
5 |
6 | #include "md5.h"
7 |
8 | int main(int argc, const char *argv[]) {
9 | char *key = "key";
10 | unsigned long len = strlen(key);
11 | /* get hashing number by key */
12 | printf("md5 hash for 'key': %u\n", hash_md5(key, len));
13 | /* get md5 signatures (16) */
14 | unsigned char results[16];
15 | md5_signature((unsigned char *)key, len, results);
16 | int i;
17 | for (i = 0; i < 16; i++) printf("%x", results[i]);
18 | return 0;
19 | }
20 |
--------------------------------------------------------------------------------
/example/queue_example.c:
--------------------------------------------------------------------------------
1 | // cc queue_example.c queue.c
2 |
3 | #include
4 | #include
5 |
6 | #include "queue.h"
7 |
8 | int main(int argc, const char *argv[]) {
9 | /* allocate a new empty queue */
10 | struct queue *queue = queue();
11 | /* push data to queue */
12 | char *val1 = "val1";
13 | char *val2 = "val2";
14 | char *val3 = "val3";
15 | assert(queue_push(queue, val1) == QUEUE_OK);
16 | assert(queue_push(queue, val2) == QUEUE_OK);
17 | assert(queue_push(queue, val3) == QUEUE_OK);
18 | /* get queue len */
19 | printf("current queue length: %zu\n", queue_len(queue));
20 | /* pop data from queue, the order is the same with push */
21 | void *data;
22 | while ((data = queue_pop(queue)) != NULL)
23 | printf("pop data: %s\n", (char *)data);
24 | /* free queue */
25 | queue_free(queue);
26 | return 0;
27 | }
28 |
--------------------------------------------------------------------------------
/example/signals_example.c:
--------------------------------------------------------------------------------
1 | // cc signals_example.c event.c
2 | #include
3 |
4 | #include "event.h"
5 | #include "signals.h"
6 |
7 | void on_keyboardinterrupt(int signal) { printf("keyboardinterrupt!\n"); }
8 | void on_signalterm(int signal) { printf("signal term received!\n"); }
9 | void beat1000(struct event_loop *loop, int id, void *data) {
10 | printf("heartbeat every 1s\n");
11 | }
12 |
13 | int main(int argc, const char *argv[]) {
14 | signals_register(SIGINT, &on_keyboardinterrupt);
15 | signals_register(SIGTERM, &on_signalterm);
16 | /* forever event loop to heart-beat every 10s */
17 | struct event_loop *loop = event_loop(0);
18 | event_add_timer(loop, 1000, &beat1000, NULL);
19 | event_loop_start(loop);
20 | event_loop_free(loop);
21 | return 0;
22 | }
23 |
--------------------------------------------------------------------------------
/example/skiplist_example.c:
--------------------------------------------------------------------------------
1 | // cc skiplist_example.c skiplist.c
2 |
3 | #include
4 | #include
5 |
6 | #include "skiplist.h"
7 |
8 | int main(int argc, const char *argv[]) {
9 | /* allocate a new empty skiplist (using default score comparator) */
10 | struct skiplist *skiplist = skiplist(NULL);
11 | /* push data into skiplist */
12 | unsigned long a = 4, b = 2, c = 3, d = 7, e = 5, f = 6, g = 9, h = 8, i = 1;
13 | assert(skiplist_push(skiplist, a, "a") == SKIPLIST_OK);
14 | assert(skiplist_push(skiplist, b, "b") == SKIPLIST_OK);
15 | assert(skiplist_push(skiplist, c, "c") == SKIPLIST_OK);
16 | assert(skiplist_push(skiplist, d, "d") == SKIPLIST_OK);
17 | assert(skiplist_push(skiplist, e, "e") == SKIPLIST_OK);
18 | assert(skiplist_push(skiplist, f, "f") == SKIPLIST_OK);
19 | assert(skiplist_push(skiplist, g, "g") == SKIPLIST_OK);
20 | assert(skiplist_push(skiplist, i, "i") == SKIPLIST_OK);
21 | assert(skiplist_push(skiplist, h, "h") == SKIPLIST_OK);
22 | /* get data by node */
23 | printf("score: %lu => data: %s\n", a, (char *)skiplist_get(skiplist, a));
24 | printf("score: %lu => data: %s\n", b, (char *)skiplist_get(skiplist, b));
25 | printf("score: %lu => data: %s\n", c, (char *)skiplist_get(skiplist, c));
26 | printf("score: %lu => data: %s\n", d, (char *)skiplist_get(skiplist, d));
27 | printf("score: %lu => data: %s\n", e, (char *)skiplist_get(skiplist, e));
28 | printf("score: %lu => data: %s\n", f, (char *)skiplist_get(skiplist, f));
29 | printf("score: %lu => data: %s\n", g, (char *)skiplist_get(skiplist, g));
30 | printf("score: %lu => data: %s\n", h, (char *)skiplist_get(skiplist, h));
31 | printf("score: %lu => data: %s\n", i, (char *)skiplist_get(skiplist, i));
32 | /* print current skiplist */
33 | skiplist_print(skiplist);
34 | /* iterate the skiplist */
35 | struct skiplist_node *node;
36 | skiplist_each(skiplist, node) { printf("%lu ", node->score); }
37 | printf("\n");
38 | /* get the first and last node */
39 | struct skiplist_node *first = skiplist_first(skiplist);
40 | struct skiplist_node *last = skiplist_last(skiplist);
41 | printf("first node => score: %ld, data: '%s'\n", first->score,
42 | (char *)first->data);
43 | printf("last node => score: %ld, data: '%s'\n", last->score,
44 | (char *)last->data);
45 | /* pop the first and last node */
46 | printf("pop first node, data: '%s'\n", (char *)skiplist_popfirst(skiplist));
47 | printf("pop last node, data: '%s'\n", (char *)skiplist_poplast(skiplist));
48 | /* print current skiplist length and height */
49 | printf("skiplist height: %d\n", skiplist_height(skiplist));
50 | printf("skiplist len: %zu\n", skiplist_len(skiplist));
51 | /* clear the skiplist */
52 | skiplist_clear(skiplist);
53 | printf("skiplist height after clear: %d\n", skiplist_height(skiplist));
54 | printf("skiplist len after clear: %zu\n", skiplist_len(skiplist));
55 | skiplist_print(skiplist);
56 | return 0;
57 | }
58 |
--------------------------------------------------------------------------------
/example/stack_example.c:
--------------------------------------------------------------------------------
1 | // cc stack_example.c stack.c
2 |
3 | #include
4 | #include
5 |
6 | #include "stack.h"
7 |
8 | int main(int argc, const char *argv[]) {
9 | /* allocate a new empty stack with memory capacity 1 */
10 | struct stack *stack = stack(1);
11 | /* push data to stack */
12 | char *val1 = "val1";
13 | char *val2 = "val2";
14 | char *val3 = "val3";
15 | assert(stack_push(stack, val1) == STACK_OK);
16 | assert(stack_push(stack, val2) == STACK_OK);
17 | assert(stack_push(stack, val3) == STACK_OK);
18 | /* current stack capacity (or allocated memory) */
19 | printf("current stack allocated memory: %zu\n", stack_cap(stack));
20 | /* get stack len */
21 | printf("current stack length: %zu\n", stack_len(stack));
22 | /* pop data from stack, the order is invse with push */
23 | void *data;
24 | while ((data = stack_pop(stack)) != NULL)
25 | printf("pop data: %s\n", (char *)data);
26 | /* free stack */
27 | stack_free(stack);
28 | return 0;
29 | }
30 |
--------------------------------------------------------------------------------
/example/strings_example.c:
--------------------------------------------------------------------------------
1 | // cc strings_example.c strings.c
2 | #include
3 |
4 | #include "strings.h"
5 |
6 | void example_search() {
7 | /* search string via Boyer Moore algorithm */
8 | char *s = "this is a simple example";
9 | char *sub = "mp";
10 | size_t first_idx = strings_search(s, sub, 0);
11 | size_t second_idx = strings_search(s, sub, first_idx + 1);
12 | printf("'%s' is seen in '%s' at index %zu\n", sub, s, first_idx);
13 | printf("'%s' is seen in '%s' again at index %zu\n", sub, s, second_idx);
14 | }
15 |
16 | void example_rand() {
17 | /* get some random strings (length 20) */
18 | char s[20];
19 | printf("random string with length 20: %s\n", strings_rand(s, 20));
20 | printf("random string with length 20: %s\n", strings_rand(s, 20));
21 | printf("random string with length 20: %s\n", strings_rand(s, 20));
22 | }
23 |
24 | void example_replace() {
25 | /* replace string example */
26 | char *src = "this is a simple example";
27 | char *sub = "mp";
28 | char *rep = "**";
29 | char dst[100] = {0};
30 | strings_replace(dst, src, sub, rep);
31 | printf("replace '%s' in '%s' with '%s': '%s'\n", sub, src, rep, dst);
32 | }
33 |
34 | int main(int argc, const char *argv[]) {
35 | example_search();
36 | example_rand();
37 | example_replace();
38 | return 0;
39 | }
40 |
--------------------------------------------------------------------------------
/lint.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | """
4 | Lint script via clang-format.
5 |
6 | Usage
7 |
8 | $ ./lint.py [fix]
9 | """
10 |
11 | import sys
12 | import os
13 | import subprocess
14 | import xml.etree.ElementTree as ET
15 |
16 | FILE_EXTENSIONS = ('.h', '.c')
17 | CLANGFOMART_NAMES = ['clang-format', 'clang-format-3.5', 'clang-format-3.6']
18 | CLANGFORMAT_LINT_OPTIONS = ['-output-replacements-xml', '-style=file']
19 | CLANGFORMAT_FIX_OPTIONS = ['-i', '-style=file']
20 |
21 |
22 | def print_usage():
23 | print "Usage: ./lint.py [fix]"
24 |
25 |
26 | def traverse_files():
27 | """Get file path list recursively.
28 | """
29 | paths = []
30 | for root, dirs, files in os.walk("./"):
31 | for filename in files:
32 | if filename.endswith(FILE_EXTENSIONS):
33 | paths.append(os.path.join(root, filename))
34 | return paths
35 |
36 |
37 | def get_clang_format_bin():
38 | for name in CLANGFOMART_NAMES:
39 | try:
40 | subprocess.check_output([name, "-version"])
41 | except OSError:
42 | continue
43 | else:
44 | return name
45 | raise Exception("No clang-format command available.")
46 |
47 |
48 | def lint(fix=False):
49 | num_errors = 0
50 | num_error_files = 0
51 | num_fixed_files = 0
52 | clangformat_bin = get_clang_format_bin()
53 | for path in traverse_files():
54 | cmd = [clangformat_bin, path]
55 | cmd.extend(CLANGFORMAT_LINT_OPTIONS)
56 | out = subprocess.check_output(cmd)
57 | root = ET.fromstring(out)
58 | has_error = False
59 | for tag in root.findall('replacement'):
60 | offset = tag.get('offset', None)
61 | length = tag.get("length", None)
62 | if offset is not None:
63 | has_error = True
64 | num_errors += 1
65 | print "{0}:{1},{2}".format(path, offset, length)
66 | if has_error:
67 | num_error_files += 1
68 | if fix:
69 | cmd = [clangformat_bin, path]
70 | cmd.extend(CLANGFORMAT_FIX_OPTIONS)
71 | if subprocess.call(cmd) == 0:
72 | num_fixed_files += 1
73 | if has_error:
74 | print "{} fixed".format(path)
75 | if num_errors > 0 and num_error_files != num_fixed_files:
76 | sys.exit(1)
77 |
78 |
79 | if __name__ == '__main__':
80 | if len(sys.argv) <= 1: # Case ./program
81 | lint(fix=False)
82 | elif sys.argv[1] == 'fix': # Case ./program fix
83 | lint(fix=True)
84 | else:
85 | print_usage()
86 |
--------------------------------------------------------------------------------
/src/buf.c:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015, Chao Wang
3 | */
4 |
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 |
12 | #include "buf.h"
13 |
14 | /* Create new buffer and init it with a C null-terminated
15 | * string if `s` is not NULL.
16 | */
17 | struct buf *buf_new(const char *s) {
18 | struct buf *buf = malloc(sizeof(struct buf));
19 |
20 | if (buf != NULL) {
21 | buf->len = 0;
22 | buf->cap = 0;
23 | buf->data = NULL;
24 |
25 | if (s != NULL) {
26 | if (buf_puts(buf, s) != BUF_OK) return NULL;
27 | }
28 | }
29 | return buf;
30 | }
31 |
32 | /* Create empty buffer */
33 | struct buf *buf_empty(void) {
34 | return buf_new(NULL);
35 | }
36 | /* Free a buffer and its data, no operation is performed
37 | * if the buffer is NULL. */
38 | void buf_free(struct buf *buf) {
39 | if (buf != NULL) {
40 | if (buf->data != NULL) free(buf->data);
41 | free(buf);
42 | }
43 | }
44 |
45 | /* Clear a buffer and the data memory will also be freed. */
46 | void buf_clear(struct buf *buf) {
47 | assert(buf != NULL);
48 |
49 | if (buf->data != NULL) free(buf->data);
50 | buf->data = NULL;
51 | buf->len = 0;
52 | buf->cap = 0;
53 | }
54 |
55 | /* Grow a buffer's capacity to given size, the new capacity is
56 | * calculated like k*unit>=cap, by default, the unit is current cap,
57 | * if the unit is large enough, use BUF_UNIT_MAX instead. */
58 | int buf_grow(struct buf *buf, size_t cap) {
59 | assert(buf != NULL);
60 |
61 | if (cap > BUF_CAP_MAX) return BUF_ENOMEM;
62 |
63 | if (cap <= buf->cap) return BUF_OK;
64 |
65 | size_t unit = buf->cap;
66 |
67 | if (unit > BUF_UNIT_MAX) unit = BUF_UNIT_MAX;
68 |
69 | if (unit < BUF_UNIT_MIN) unit = BUF_UNIT_MIN;
70 |
71 | size_t new_cap = buf->cap + unit;
72 | while (new_cap < cap) new_cap += unit;
73 |
74 | char *data = realloc(buf->data, new_cap * sizeof(char));
75 |
76 | if (data == NULL) return BUF_ENOMEM;
77 |
78 | buf->data = data;
79 | buf->cap = new_cap;
80 | return BUF_OK;
81 | }
82 |
83 | /* Put chars on the end of a buffer */
84 | int buf_put(struct buf *buf, char *data, size_t len) {
85 | int error = buf_grow(buf, buf->len + len);
86 |
87 | if (error == BUF_OK) {
88 | memcpy(buf->data + buf->len, data, len);
89 | buf->len += len;
90 | }
91 | return error;
92 | }
93 |
94 | /* Put null-terminated chars to the end of a buffer. */
95 | int buf_puts(struct buf *buf, const char *s) {
96 | return buf_put(buf, (char *)s, strlen(s));
97 | }
98 |
99 | /* Put a single char to the end of a buffer. */
100 | int buf_putc(struct buf *buf, char ch) {
101 | int error = buf_grow(buf, buf->len + 1);
102 |
103 | if (error == BUF_OK) {
104 | buf->data[buf->len] = ch;
105 | buf->len += 1;
106 | }
107 | return error;
108 | }
109 |
110 | /* Get buffer data as null-terminated chars */
111 | char *buf_str(struct buf *buf) {
112 | assert(buf != NULL);
113 |
114 | if (buf->len < buf->cap && buf->data[buf->len] == '\0') return buf->data;
115 |
116 | if (buf->len + 1 <= buf->cap || buf_grow(buf, buf->len + 1) == BUF_OK) {
117 | buf->data[buf->len] = '\0';
118 | return buf->data;
119 | }
120 |
121 | return NULL;
122 | }
123 |
124 | /* Return 1 if a buffer is empty, else 0 */
125 | int buf_isempty(struct buf *buf) {
126 | assert(buf != NULL);
127 | if (buf->len == 0) return 1;
128 | return 0;
129 | }
130 |
131 | /* Formatted printing to a buffer. */
132 | int buf_sprintf(struct buf *buf, const char *fmt, ...) {
133 | assert(buf != NULL);
134 |
135 | if (buf->len >= buf->cap && buf_grow(buf, buf->len + 1) != BUF_OK)
136 | return BUF_ENOMEM;
137 |
138 | va_list ap;
139 | int num;
140 |
141 | va_start(ap, fmt);
142 | num = vsnprintf(buf->data + buf->len, buf->cap - buf->len, fmt, ap);
143 | va_end(ap);
144 |
145 | if (num < 0) return BUF_EFAILED;
146 |
147 | size_t size = (size_t)num;
148 |
149 | if (size >= buf->cap - buf->len) {
150 | if (buf_grow(buf, buf->len + size + 1) != BUF_OK) return BUF_ENOMEM;
151 | va_start(ap, fmt);
152 | num = vsnprintf(buf->data + buf->len, buf->cap - buf->len, fmt, ap);
153 | va_end(ap);
154 | }
155 |
156 | if (num < 0) return BUF_EFAILED;
157 |
158 | buf->len += num;
159 | return BUF_OK;
160 | }
161 |
162 | /* Romve part of buf on the left. */
163 | void buf_lrm(struct buf *buf, size_t len) {
164 | assert(buf != NULL);
165 |
166 | if (len > buf->len) {
167 | buf->len = 0;
168 | return;
169 | }
170 |
171 | buf->len -= len;
172 | memmove(buf->data, buf->data + len, buf->len);
173 | }
174 |
175 | /* Get buf length. */
176 | size_t buf_len(struct buf *buf) {
177 | assert(buf != NULL);
178 | return buf->len;
179 | }
180 |
181 | /* Get buf capacity. */
182 | size_t buf_cap(struct buf *buf) {
183 | assert(buf != NULL);
184 | return buf->cap;
185 | }
186 |
--------------------------------------------------------------------------------
/src/buf.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015, Chao Wang
3 | *
4 | * Dynamic buffer implementation.
5 | * deps: None.
6 | */
7 |
8 | #ifndef __BUF_H__
9 | #define __BUF_H__
10 |
11 | #include
12 | #include
13 |
14 | #if defined(__cplusplus)
15 | extern "C" {
16 | #endif
17 |
18 | #define BUF_CAP_MAX 64 * 1024 * 1024 /* max buffer capacity: 64mb */
19 | #define BUF_UNIT_MIN 1 /* min buffer realloc unit: 1 */
20 | #define BUF_UNIT_MAX 1024 * 1024 /* max buffer realloc unit: 1mb */
21 |
22 | #define buf(s) buf_new(s)
23 | #define str(b) buf_str(b)
24 |
25 | enum {
26 | BUF_OK = 0, /* operation is ok */
27 | BUF_ENOMEM = 1, /* no memory error */
28 | BUF_EFAILED = 2, /* operation is failed */
29 | };
30 |
31 | struct buf {
32 | size_t len; /* buffer length */
33 | size_t cap; /* buffer capacity */
34 | char *data; /* real buffer pointer */
35 | };
36 |
37 | struct buf *buf_new(const char *s);
38 | struct buf *buf_empty(void);
39 | void buf_free(struct buf *buf);
40 | void buf_clear(struct buf *buf);
41 | int buf_grow(struct buf *buf, size_t cap);
42 | int buf_put(struct buf *buf, char *data, size_t len);
43 | int buf_puts(struct buf *buf, const char *s);
44 | int buf_putc(struct buf *buf, char ch);
45 | char *buf_str(struct buf *buf);
46 | int buf_isempty(struct buf *buf);
47 | int buf_sprintf(struct buf *buf, const char *fmt, ...);
48 | void buf_lrm(struct buf *buf, size_t len);
49 | size_t buf_len(struct buf *buf);
50 | size_t buf_cap(struct buf *buf);
51 |
52 | #if defined(__cplusplus)
53 | }
54 | #endif
55 |
56 | #endif
57 |
--------------------------------------------------------------------------------
/src/cfg.c:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015, Chao Wang
3 | */
4 |
5 | #include
6 | #include
7 |
8 | #include "cfg.h"
9 |
10 | /* Get key and val from cfg. */
11 | int cfg_get(struct cfg *cfg) {
12 | assert(cfg != NULL);
13 | assert(cfg->lineno > 0);
14 |
15 | if (cfg->data == NULL || cfg->len == 0) return CFG_EOF;
16 |
17 | char *data = cfg->data;
18 | size_t len = cfg->len;
19 | size_t idx = 0;
20 |
21 | cfg->key = NULL;
22 | cfg->val = NULL;
23 | cfg->key_len = 0;
24 | cfg->val_len = 0;
25 |
26 | while (idx < len) {
27 | switch (data[idx]) {
28 | case '\t':
29 | case ' ':
30 | if (cfg->key != NULL && cfg->key_len == 0) /* key end */
31 | cfg->key_len = data + idx - cfg->key;
32 | if (cfg->val != NULL && cfg->val_len == 0) /* val end */
33 | cfg->val_len = data + idx - cfg->val;
34 | break;
35 | case '\n':
36 | if (cfg->val != NULL && cfg->val_len == 0) /* val end */
37 | cfg->val_len = data + idx - cfg->val;
38 | if (cfg->key_len != 0 && cfg->val_len != 0)
39 | /* line end ok with key & val */
40 | return CFG_OK;
41 | if (cfg->key != NULL && cfg->val == NULL)
42 | /* line contains only one word */
43 | return CFG_EBADFMT;
44 | cfg->lineno++;
45 | break;
46 | case '#':
47 | if (cfg->val != NULL && cfg->val_len == 0) /* val end */
48 | cfg->val_len = data + idx - cfg->val;
49 |
50 | while (idx + 1 < len && data[idx + 1] != '\n') {
51 | idx++;
52 | cfg->data++;
53 | cfg->len--;
54 | }
55 | break;
56 | default:
57 | if (cfg->key == NULL) /* key start */
58 | cfg->key = data + idx;
59 | if (cfg->val == NULL && cfg->key_len != 0) /* val start */
60 | cfg->val = data + idx;
61 | if (cfg->key_len != 0 && cfg->val_len != 0)
62 | /* bad char after key and val */
63 | return CFG_EBADFMT;
64 | break;
65 | }
66 |
67 | idx++;
68 | cfg->data++;
69 | cfg->len--;
70 | };
71 |
72 | return CFG_EOF;
73 | }
74 |
--------------------------------------------------------------------------------
/src/cfg.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015, Chao Wang
3 | *
4 | * Simple configuration reader.
5 | * deps: None.
6 | *
7 | * example cfg string:
8 | *
9 | * # proxy port
10 | * port 8125
11 | * # proxy backend nodes
12 | * node 127.0.0.1:8126
13 | * node 127.0.0.1:8127
14 | * node 127.0.0.1:8128
15 | *
16 | * example usage:
17 | *
18 | * struct cfg cfg = {buf, buf_len, 1};
19 | * int err = 0;
20 | * cfg_each(cfg, err) {
21 | * cfg.key..
22 | * cfg.key_len..
23 | * cfg.val..
24 | * cfg.val_len..
25 | * }
26 | */
27 |
28 | #ifndef __CFG_H__
29 | #define __CFG_H__
30 |
31 | #include
32 |
33 | #if defined(__cplusplus)
34 | extern "C" {
35 | #endif
36 |
37 | #define cfg_each(cfg, err) while (((err) = cfg_get(&(cfg))) == CFG_OK)
38 |
39 | enum {
40 | CFG_OK = 0, /* operation is ok */
41 | CFG_EOF = 1, /* EOF reached */
42 | CFG_EBADFMT = 2, /* invalid format */
43 | };
44 |
45 | struct cfg {
46 | char *data; /* currnt cfg data */
47 | size_t len; /* currnt cfg data length */
48 | size_t lineno; /* cfg lineno */
49 | char *key; /* current key */
50 | size_t key_len; /* current key length */
51 | char *val; /* current val */
52 | size_t val_len; /* current val length */
53 | };
54 |
55 | int cfg_get(struct cfg *cfg);
56 |
57 | #if defined(__cplusplus)
58 | }
59 | #endif
60 |
61 | #endif
62 |
--------------------------------------------------------------------------------
/src/datetime.c:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015, Chao Wang
3 | */
4 |
5 | #include
6 | #include
7 | #include
8 |
9 | /* Get timestamp (in milliseconds) for now. */
10 | double datetime_stamp_now(void) {
11 | #if defined CLOCK_REALTIME
12 | struct timespec ts;
13 | int rc = clock_gettime(CLOCK_REALTIME, &ts);
14 | assert(rc == 0);
15 | return ts.tv_sec * 1000 + ts.tv_nsec / 1000000.0;
16 | #else
17 | struct timeval tv;
18 | gettimeofday(&tv, NULL);
19 | return (1000000 * tv.tv_sec + tv.tv_usec) / 1000.0;
20 | #endif
21 | }
22 |
--------------------------------------------------------------------------------
/src/datetime.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015, Chao Wang
3 | *
4 | * Datetime utils.
5 | * deps: None.
6 | */
7 |
8 | #ifndef __DATETIME_H__
9 | #define __DATETIME_H__
10 |
11 | #if defined(__cplusplus)
12 | extern "C" {
13 | #endif
14 |
15 | double datetime_stamp_now(void);
16 |
17 | #if defined(__cplusplus)
18 | }
19 | #endif
20 | #endif
21 |
--------------------------------------------------------------------------------
/src/dict.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015, Chao Wang
3 | *
4 | * Dynamic sized list-based hashtable implementation.
5 | * deps: None
6 | */
7 |
8 | #ifndef __DICT_H__
9 | #define __DICT_H__
10 |
11 | #include
12 | #include
13 |
14 | #if defined(__cplusplus)
15 | extern "C" {
16 | #endif
17 |
18 | #define DICT_LOAD_LIMIT 0.72 /* load factor */
19 | #define dict() dict_new()
20 | #define dict_iter(dict) dict_iter_new(dict)
21 | #define dict_each(iter, node) while (((node) = dict_iter_next((iter))) != NULL)
22 |
23 | enum {
24 | DICT_OK = 0, /* operation is ok */
25 | DICT_ENOMEM = 1, /* no memory error */
26 | };
27 |
28 | struct dict_node {
29 | char *key; /* key string */
30 | size_t len; /* key length will be set on `node_new` */
31 | void *val; /* value data */
32 | struct dict_node *next; /* next node */
33 | };
34 |
35 | struct dict {
36 | size_t idx; /* index in table sizes */
37 | size_t len; /* dict length */
38 | struct dict_node **table; /* node table */
39 | };
40 |
41 | struct dict_iter {
42 | struct dict *dict; /* dict to iterate */
43 | size_t index; /* current table index */
44 | struct dict_node *node; /* current dict node */
45 | };
46 |
47 | struct dict *dict_new(void);
48 | void dict_clear(struct dict *dict); /* O(N) */
49 | void dict_free(struct dict *dict);
50 | size_t dict_len(struct dict *dict); /* O(1) */
51 | size_t dict_cap(struct dict *dict); /* O(1) */
52 | int dict_set(struct dict *dict, char *key, void *val); /* O(1) */
53 | void *dict_get(struct dict *dict, char *key); /* O(1) */
54 | void *dict_pop(struct dict *dict, char *key); /* O(1) */
55 | int dict_has(struct dict *dict, char *key); /* O(1) */
56 | struct dict_iter *dict_iter_new(struct dict *dict);
57 | void dict_iter_free(struct dict_iter *iter);
58 | struct dict_node *dict_iter_next(struct dict_iter *iter);
59 | void dict_iter_rewind(struct dict_iter *iter);
60 | int dict_iset(struct dict *dict, char *key, size_t len, void *val); /* O(1) */
61 | void *dict_iget(struct dict *dict, char *key, size_t len); /* O(1) */
62 | void *dict_ipop(struct dict *dict, char *key, size_t len); /* O(1) */
63 | int dict_ihas(struct dict *dict, char *key, size_t len); /* O(1) */
64 |
65 | #if defined(__cplusplus)
66 | }
67 | #endif
68 |
69 | #endif
70 |
--------------------------------------------------------------------------------
/src/event.c:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015, Chao Wang
3 | */
4 |
5 | #include
6 | #include
7 |
8 | #include "event.h"
9 |
10 | #include "event_timer.c"
11 | #ifdef HAVE_KQUEUE
12 | #include "event_kqueue.c"
13 | #else
14 | #ifdef HAVE_EPOLL
15 | #include "event_epoll.c"
16 | #else
17 | #error "no event lib avaliable"
18 | #endif
19 | #endif
20 |
21 | /* Create an event loop. */
22 | struct event_loop *event_loop_new(int size) {
23 | assert(size >= 0);
24 |
25 | /* event numbers must be greater than RESERVED_FDS + FDSET_INCR */
26 | size += EVENT_FDSET_INCR + EVENT_MIN_RESERVED_FDS;
27 |
28 | struct event_loop *loop = malloc(sizeof(struct event_loop));
29 |
30 | if (loop == NULL) return NULL;
31 |
32 | loop->size = size;
33 | loop->events = NULL;
34 | loop->api = NULL;
35 | loop->num_timers = 0;
36 |
37 | /* events */
38 | loop->events = malloc(sizeof(struct event) * size);
39 | if (loop->events == NULL) {
40 | free(loop);
41 | return NULL;
42 | }
43 |
44 | /* event api */
45 | if (event_api_loop_new(loop) != EVENT_OK) {
46 | free(loop->events);
47 | free(loop);
48 | return NULL;
49 | }
50 |
51 | /* timer heap */
52 | loop->timer_heap = event_timer_heap_new();
53 | if (loop->timer_heap == NULL) {
54 | event_api_loop_free(loop);
55 | free(loop->events);
56 | free(loop);
57 | return NULL;
58 | }
59 |
60 | /* init all timers id to -1 */
61 | int i;
62 | for (i = 0; i < EVENT_TIMER_ID_MAX; i++) loop->timers[i].id = -1;
63 |
64 | /* init all events mask to NONE */
65 | for (i = 0; i < size; i++) loop->events[i].mask = EVENT_NONE;
66 | return loop;
67 | }
68 |
69 | /* Free an event loop. */
70 | void event_loop_free(struct event_loop *loop) {
71 | if (loop != NULL) {
72 | event_timer_heap_free(loop->timer_heap);
73 | event_api_loop_free(loop);
74 | if (loop->events != NULL) free(loop->events);
75 | free(loop);
76 | }
77 | }
78 |
79 | /* Wait for events. */
80 | int event_wait(struct event_loop *loop) {
81 | assert(loop != NULL);
82 |
83 | long time_now = event_time_now();
84 | long timeout = -1; /* block forever */
85 | struct event_timer *nearest_timer = event_nearest_timer(loop);
86 |
87 | if (nearest_timer != NULL) timeout = nearest_timer->fire_at - time_now;
88 |
89 | int result = event_api_wait(loop, timeout);
90 | event_process_timers(loop);
91 | return result;
92 | }
93 |
94 | /* Start event loop */
95 | int event_loop_start(struct event_loop *loop) {
96 | assert(loop != NULL);
97 |
98 | loop->state = EVENT_LOOP_RUNNING;
99 |
100 | int err;
101 |
102 | while (loop->state != EVENT_LOOP_STOPPED)
103 | if ((err = event_wait(loop)) != EVENT_OK) return err;
104 |
105 | return EVENT_OK;
106 | }
107 |
108 | /* Stop event loop */
109 | void event_loop_stop(struct event_loop *loop) {
110 | assert(loop != NULL);
111 | loop->state = EVENT_LOOP_STOPPED;
112 | }
113 |
114 | /* Add an event to event loop (mod if the fd already in set). */
115 | int event_add(struct event_loop *loop, int fd, int mask, event_cb_t cb,
116 | void *data) {
117 | assert(loop != NULL);
118 | assert(loop->api != NULL);
119 | assert(cb != NULL);
120 |
121 | if (fd > loop->size) return EVENT_ERANGE;
122 |
123 | int err = event_api_add(loop, fd, mask);
124 |
125 | if (err != EVENT_OK) return err;
126 |
127 | struct event *ev = &loop->events[fd];
128 | ev->mask |= mask;
129 |
130 | if (mask & EVENT_ERROR) ev->ecb = cb;
131 | if (mask & EVENT_READABLE) ev->rcb = cb;
132 | if (mask & EVENT_WRITABLE) ev->wcb = cb;
133 |
134 | ev->data = data;
135 | return EVENT_OK;
136 | }
137 |
138 | /* Delete an event from loop. */
139 | int event_del(struct event_loop *loop, int fd, int mask) {
140 | assert(loop != NULL);
141 |
142 | if (fd > loop->size) return EVENT_ERANGE;
143 |
144 | struct event *ev = &loop->events[fd];
145 |
146 | if (ev->mask == EVENT_NONE) return EVENT_OK;
147 |
148 | int err = event_api_del(loop, fd, mask);
149 |
150 | if (err != EVENT_OK) return err;
151 |
152 | ev->mask = ev->mask & (~mask);
153 | return EVENT_OK;
154 | }
155 |
156 | /* Add timer to event loop. (interval#ms) */
157 | int event_add_timer(struct event_loop *loop, long interval, event_timer_cb_t cb,
158 | void *data) {
159 | assert(loop != NULL && loop->timers != NULL && loop->timer_heap != NULL);
160 | assert(interval > 0);
161 |
162 | int id;
163 | struct event_timer *timer;
164 |
165 | /* find available id */
166 | for (id = 0; id < EVENT_TIMER_ID_MAX; id++) {
167 | timer = &loop->timers[id];
168 | if (timer->id < 0) break;
169 | }
170 |
171 | if (id >= EVENT_TIMER_ID_MAX) return EVENT_ERANGE;
172 |
173 | timer->id = id;
174 | timer->cb = cb;
175 | timer->interval = interval;
176 | timer->fire_at = event_time_now() + interval;
177 | timer->data = data;
178 | loop->num_timers += 1;
179 | /* push to heap */
180 | event_timer_heap_push(loop->timer_heap, timer);
181 | return EVENT_OK;
182 | }
183 |
184 | /* Delete timer from event loop. */
185 | int event_del_timer(struct event_loop *loop, int id) {
186 | assert(loop != NULL && loop->timers != NULL && loop->timer_heap != NULL);
187 |
188 | if (id < 0 || id >= EVENT_TIMER_ID_MAX) return EVENT_ERANGE;
189 |
190 | struct event_timer *timer = &loop->timers[id];
191 |
192 | if (timer->id < 0) return EVENT_ENOTFOUND;
193 |
194 | int error;
195 | if ((error = event_timer_heap_del(loop->timer_heap, id)) != EVENT_OK)
196 | return error;
197 |
198 | timer->id = -1;
199 | loop->num_timers -= 1;
200 | return EVENT_OK;
201 | }
202 |
--------------------------------------------------------------------------------
/src/event.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015, Chao Wang
3 | *
4 | * Event loop wrapper.
5 | * deps: event_epoll.c event_kqueue.c.
6 | */
7 |
8 | #ifndef __EVENT_H__
9 | #define __EVENT_H__
10 |
11 | #if defined(__cplusplus)
12 | extern "C" {
13 | #endif
14 |
15 | #include
16 |
17 | #define EVENT_MIN_RESERVED_FDS 32
18 | #define EVENT_FDSET_INCR 96
19 | #define EVENT_TIMER_ID_MAX 1024 * 10
20 |
21 | #define EVENT_NONE 0b000
22 | #define EVENT_READABLE 0b001
23 | #define EVENT_WRITABLE 0b010
24 | #define EVENT_ERROR 0b100
25 |
26 | #define EVENT_LOOP_RUNNING 0
27 | #define EVENT_LOOP_STOPPED 1
28 |
29 | #ifdef __linux__
30 | #define HAVE_EPOLL 1
31 | #endif
32 |
33 | #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || \
34 | defined(__OpenBSD__)
35 | #define HAVE_KQUEUE 1
36 | #endif
37 |
38 | #ifdef __sun
39 | #include
40 | #ifdef _dtrace_version
41 | #define HAVE_EVPORT 1
42 | #endif
43 | #endif
44 |
45 | #define event_loop(size) event_loop_new(size)
46 | #define event_add_in(loop, fd, cb, data) \
47 | event_add(loop, fd, EVENT_READABLE, cb, data);
48 | #define event_add_out(loop, fd, cb, data) \
49 | event_add(loop, fd, EVENT_WRITABLE, cb, data);
50 | #define event_del_in(loop, fd) event_del(loop, fd, EVENT_READABLE);
51 | #define event_del_out(loop, fd) event_del(loop, fd, EVENT_WRITABLE);
52 |
53 | enum {
54 | EVENT_OK = 0, /* operation is ok */
55 | EVENT_ENOMEM = 1, /* no memory error */
56 | EVENT_EFAILED = 2, /* operation is failed */
57 | EVENT_ERANGE = 3, /* range is invalid */
58 | EVENT_ENOTFOUND = 4, /* not found error */
59 | };
60 |
61 | struct event_loop;
62 | struct event_api;
63 |
64 | typedef void (*event_cb_t)(struct event_loop *loop, int fd, int mask,
65 | void *data);
66 | typedef void (*event_timer_cb_t)(struct event_loop *loop, int id, void *data);
67 |
68 | struct event {
69 | int mask; /* EVENT_(NONE|READABLE|WRITABLE..) */
70 | event_cb_t rcb; /* callback function on EVENT_READABLE */
71 | event_cb_t wcb; /* callback function on EVENT_WRITABLE */
72 | event_cb_t ecb; /* callback function on EVENT_ERROR */
73 | void *data; /* user defined data */
74 | };
75 |
76 | struct event_timer {
77 | int id; /* timer identifier [0, EVENT_TIMER_ID_MAX) */
78 | event_timer_cb_t cb; /* callback function on timer fired */
79 | long interval; /* periodicity interval to fire (ms) */
80 | long fire_at; /* the time for the next fire (ms) */
81 | void *data; /* user defined data */
82 | };
83 |
84 | struct event_timer_heap {
85 | struct event_timer *timers[EVENT_TIMER_ID_MAX];
86 | size_t len;
87 | };
88 |
89 | struct event_loop {
90 | int size; /* the max number of fds to track */
91 | int state; /* one of EVENT_LOOP_(STOPPED|RUNNING) */
92 | int num_timers; /* the number of timers */
93 | struct event *events; /* struct event[] */
94 | struct event_api *api; /* to be implemented */
95 | struct event_timer
96 | timers[EVENT_TIMER_ID_MAX]; /* struct event_timers[MAX] */
97 | struct event_timer_heap *timer_heap;
98 | };
99 |
100 | struct event_loop *event_loop_new(int size);
101 | void event_loop_free(struct event_loop *loop);
102 | int event_loop_start(struct event_loop *loop);
103 | void event_loop_stop(struct event_loop *loop);
104 | int event_add(struct event_loop *loop, int fd, int mask, event_cb_t cb,
105 | void *data); /* O(1) */
106 | int event_del(struct event_loop *loop, int fd, int mask);
107 | int event_wait(struct event_loop *loop);
108 | int event_add_timer(struct event_loop *loop, long interval, event_timer_cb_t cb,
109 | void *data); /* O(EVENT_TIMER_ID_MAX) */
110 | int event_del_timer(struct event_loop *loop, int id); /* O(1) */
111 |
112 | #if defined(__cplusplus)
113 | }
114 | #endif
115 |
116 | #endif
117 |
--------------------------------------------------------------------------------
/src/event_epoll.c:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015, Chao Wang
3 | */
4 |
5 | #include
6 | #include
7 | #include
8 | #include
9 |
10 | #include "event.h"
11 |
12 | #define EVENT_EPOLL_ALWAYS_ET 1
13 |
14 | struct event_api {
15 | int ep; /* epoll descriptor */
16 | struct epoll_event *
17 | events; /* struct epoll_events[], with size `loop->size` */
18 | };
19 |
20 | static int event_api_loop_new(struct event_loop *loop) {
21 | assert(loop != NULL);
22 | assert(loop->size > 0);
23 | assert(loop->api == NULL);
24 |
25 | struct event_api *api = malloc(sizeof(struct event_api));
26 |
27 | if (api == NULL) return EVENT_ENOMEM;
28 |
29 | api->ep = epoll_create(loop->size);
30 |
31 | if (api->ep < 0) {
32 | free(api);
33 | return EVENT_EFAILED;
34 | }
35 |
36 | api->events = malloc(sizeof(struct epoll_event) * loop->size);
37 |
38 | if (api->events == NULL) {
39 | close(api->ep);
40 | free(api);
41 | return EVENT_ENOMEM;
42 | }
43 |
44 | loop->api = api;
45 | return EVENT_OK;
46 | }
47 |
48 | void event_api_loop_free(struct event_loop *loop) {
49 | assert(loop != NULL);
50 |
51 | if (loop->api != NULL) {
52 | if (loop->api->ep > 0) close(loop->api->ep);
53 | if (loop->api->events != NULL) free(loop->api->events);
54 | free(loop->api);
55 | }
56 | }
57 |
58 | int event_api_add(struct event_loop *loop, int fd, int mask) {
59 | assert(loop != NULL);
60 | assert(loop->events != NULL);
61 | assert(loop->api != NULL);
62 |
63 | struct epoll_event ev;
64 |
65 | int op =
66 | loop->events[fd].mask == EVENT_NONE ? EPOLL_CTL_ADD : EPOLL_CTL_MOD;
67 |
68 | ev.events = 0;
69 | ev.data.fd = fd;
70 |
71 | mask |= loop->events[fd].mask; /* merge old events */
72 |
73 | if (EVENT_EPOLL_ALWAYS_ET) ev.events |= EPOLLET;
74 | if (mask & EVENT_READABLE) ev.events |= EPOLLIN;
75 | if (mask & EVENT_WRITABLE) ev.events |= EPOLLOUT;
76 | if (mask & EVENT_ERROR) ev.events |= EPOLLERR;
77 |
78 | if (epoll_ctl(loop->api->ep, op, fd, &ev) < 0) return EVENT_EFAILED;
79 |
80 | return EVENT_OK;
81 | }
82 |
83 | int event_api_del(struct event_loop *loop, int fd, int delmask) {
84 | assert(loop != NULL);
85 | assert(loop->events != NULL);
86 | assert(loop->api != NULL);
87 |
88 | struct epoll_event ev;
89 | int mask = loop->events[fd].mask & (~delmask);
90 |
91 | ev.events = 0;
92 |
93 | if (EVENT_EPOLL_ALWAYS_ET) ev.events |= EPOLLET;
94 | if (mask & EVENT_READABLE) ev.events |= EPOLLIN;
95 | if (mask & EVENT_WRITABLE) ev.events |= EPOLLOUT;
96 | if (mask & EVENT_ERROR) ev.events |= EPOLLERR;
97 |
98 | ev.data.fd = fd;
99 |
100 | if (mask != EVENT_NONE) {
101 | epoll_ctl(loop->api->ep, EPOLL_CTL_MOD, fd, &ev);
102 | } else {
103 | /* Note: kernel < 2.6.9 requires a non null event pointer even for
104 | * EPOLL_CTL_DEL. */
105 | epoll_ctl(loop->api->ep, EPOLL_CTL_DEL, fd, &ev);
106 | }
107 | return EVENT_OK;
108 | }
109 |
110 | int event_api_wait(struct event_loop *loop, int timeout) {
111 | assert(loop != NULL);
112 | assert(loop->events != NULL);
113 |
114 | struct event_api *api = loop->api;
115 |
116 | assert(api != NULL);
117 | assert(api->ep >= 0);
118 | assert(api->events != NULL);
119 |
120 | int i;
121 | int nfds = epoll_wait(api->ep, api->events, loop->size, timeout);
122 |
123 | if (nfds > 0) {
124 | for (i = 0; i < nfds; i++) {
125 | struct epoll_event ee = api->events[i];
126 | int fd = ee.data.fd;
127 | struct event ev = loop->events[fd];
128 |
129 | int mask = 0;
130 |
131 | if (ee.events & EPOLLERR) mask |= EVENT_ERROR;
132 | if (ee.events & EPOLLIN) mask |= EVENT_READABLE;
133 | if (ee.events & EPOLLOUT) mask |= EVENT_WRITABLE;
134 |
135 | if (mask & EVENT_ERROR && ev.ecb != NULL)
136 | (ev.ecb)(loop, fd, mask, ev.data);
137 | if (mask & EVENT_READABLE && ev.rcb != NULL)
138 | (ev.rcb)(loop, fd, mask, ev.data);
139 | if (mask & EVENT_WRITABLE && ev.wcb != NULL)
140 | (ev.wcb)(loop, fd, mask, ev.data);
141 | }
142 |
143 | return EVENT_OK;
144 | }
145 |
146 | if (nfds == 0) {
147 | if (timeout >= 0) return EVENT_OK;
148 | }
149 |
150 | return EVENT_EFAILED;
151 | }
152 |
--------------------------------------------------------------------------------
/src/event_kqueue.c:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015, Chao Wang
3 | */
4 |
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 |
12 | #include "event.h"
13 |
14 | #define EVENT_KQUEUE_ALWAYS_CLEAR 1
15 |
16 | struct event_api {
17 | int kp; /* kqueue descriptor */
18 | struct kevent *events; /* struct kevent[], with size `loop->size` */
19 | };
20 |
21 | static int event_api_loop_new(struct event_loop *loop) {
22 | assert(loop != NULL);
23 | assert(loop->size > 0);
24 | assert(loop->api == NULL);
25 |
26 | struct event_api *api = malloc(sizeof(struct event_api));
27 |
28 | if (api == NULL) return EVENT_ENOMEM;
29 |
30 | api->kp = kqueue();
31 |
32 | if (api->kp < 0) {
33 | free(api);
34 | return EVENT_EFAILED;
35 | }
36 |
37 | api->events = malloc(sizeof(struct kevent) * loop->size);
38 |
39 | if (api->events == NULL) {
40 | close(api->kp);
41 | free(api);
42 | return EVENT_ENOMEM;
43 | }
44 |
45 | loop->api = api;
46 | return EVENT_OK;
47 | }
48 |
49 | void event_api_loop_free(struct event_loop *loop) {
50 | assert(loop != NULL);
51 |
52 | if (loop->api != NULL) {
53 | if (loop->api->kp > 0) close(loop->api->kp);
54 | if (loop->api->events != NULL) free(loop->api->events);
55 | free(loop->api);
56 | }
57 | }
58 |
59 | int event_api_add(struct event_loop *loop, int fd, int mask) {
60 | assert(loop != NULL);
61 | assert(loop->api != NULL);
62 |
63 | struct kevent ev;
64 | struct event_api *api = loop->api;
65 |
66 | int op = EV_ADD;
67 |
68 | if (EVENT_KQUEUE_ALWAYS_CLEAR) op |= EV_CLEAR;
69 |
70 | if (mask & EVENT_READABLE) {
71 | EV_SET(&ev, fd, EVFILT_READ, op, 0, 0, NULL);
72 | if (kevent(api->kp, &ev, 1, NULL, 0, NULL) < 0) return EVENT_EFAILED;
73 | }
74 |
75 | if (mask & EVENT_WRITABLE) {
76 | EV_SET(&ev, fd, EVFILT_WRITE, op, 0, 0, NULL);
77 | if (kevent(api->kp, &ev, 1, NULL, 0, NULL) < 0) return EVENT_EFAILED;
78 | }
79 | return EVENT_OK;
80 | }
81 |
82 | int event_api_del(struct event_loop *loop, int fd, int mask) {
83 | assert(loop != NULL);
84 | assert(loop->api != NULL);
85 |
86 | struct kevent ev;
87 | struct event_api *api = loop->api;
88 |
89 | int op = EV_DELETE;
90 |
91 | if (EVENT_KQUEUE_ALWAYS_CLEAR) op |= EV_CLEAR;
92 |
93 | if (mask & EVENT_READABLE) {
94 | EV_SET(&ev, fd, EVFILT_READ, op, 0, 0, NULL);
95 | if (kevent(api->kp, &ev, 1, NULL, 0, NULL) < 0) return EVENT_EFAILED;
96 | }
97 |
98 | if (mask & EVENT_WRITABLE) {
99 | EV_SET(&ev, fd, EVFILT_WRITE, op, 0, 0, NULL);
100 | if (kevent(api->kp, &ev, 1, NULL, 0, NULL) < 0) return EVENT_EFAILED;
101 | }
102 |
103 | return EVENT_OK;
104 | }
105 |
106 | int event_api_wait(struct event_loop *loop, int timeout) {
107 | assert(loop != NULL);
108 |
109 | struct event_api *api = loop->api;
110 |
111 | assert(api != NULL);
112 | assert(api->kp >= 0);
113 |
114 | int nfds;
115 |
116 | if (timeout >= 0) {
117 | struct timespec tv;
118 | tv.tv_sec = timeout / 1000;
119 | tv.tv_nsec = (timeout - tv.tv_sec * 1000) * 1000000;
120 | nfds = kevent(api->kp, NULL, 0, api->events, loop->size, &tv);
121 | } else {
122 | nfds = kevent(api->kp, NULL, 0, api->events, loop->size, NULL);
123 | }
124 |
125 | int i;
126 |
127 | if (nfds > 0) {
128 | for (i = 0; i < nfds; i++) {
129 | struct kevent ke = api->events[i];
130 | int fd = ke.ident;
131 | struct event ev = loop->events[fd];
132 |
133 | int mask = 0;
134 |
135 | if (ke.flags & EV_ERROR) mask |= EVENT_ERROR;
136 | if (ke.filter == EVFILT_READ) mask |= EVENT_READABLE;
137 | if (ke.filter == EVFILT_WRITE) mask |= EVENT_WRITABLE;
138 |
139 | if (mask & EVENT_ERROR && ev.ecb != NULL)
140 | (ev.ecb)(loop, fd, mask, ev.data);
141 | if (mask & EVENT_READABLE && ev.rcb != NULL)
142 | (ev.rcb)(loop, fd, mask, ev.data);
143 | if (mask & EVENT_WRITABLE && ev.wcb != NULL)
144 | (ev.wcb)(loop, fd, mask, ev.data);
145 | }
146 |
147 | return EVENT_OK;
148 | }
149 |
150 | if (nfds == 0) {
151 | if (timeout >= 0) return EVENT_OK;
152 | }
153 |
154 | return EVENT_EFAILED;
155 | }
156 |
--------------------------------------------------------------------------------
/src/event_timer.c:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015, Chao Wang
3 | */
4 |
5 | #include
6 | #include
7 | #include
8 | #include
9 |
10 | #include "event.h"
11 |
12 | /* Get time now in milliseconds. */
13 | static long event_time_now(void) {
14 | struct timeval tv;
15 | gettimeofday(&tv, NULL);
16 | return (1000000 * tv.tv_sec + tv.tv_usec) / 1000;
17 | }
18 |
19 | /**
20 | * Event timer heap
21 | */
22 |
23 | /* Create a timer heap. */
24 | struct event_timer_heap *event_timer_heap_new(void) {
25 | struct event_timer_heap *heap = malloc(sizeof(struct event_timer_heap));
26 | if (heap != NULL) heap->len = 0;
27 | return heap;
28 | }
29 |
30 | /* Free a timer heap. */
31 | void event_timer_heap_free(struct event_timer_heap *heap) {
32 | if (heap != NULL) free(heap);
33 | }
34 |
35 | /* Sift down the timer heap. */
36 | void event_timer_heap_siftdown(struct event_timer_heap *heap, size_t start_idx,
37 | size_t idx) {
38 | assert(heap != NULL && heap->timers != NULL);
39 |
40 | size_t parent_idx;
41 | struct event_timer *parent;
42 | struct event_timer *timer = heap->timers[idx];
43 |
44 | while (idx > start_idx) {
45 | parent_idx = (idx - 1) >> 1;
46 | parent = heap->timers[parent_idx];
47 | if (timer->fire_at < parent->fire_at) {
48 | heap->timers[idx] = parent;
49 | idx = parent_idx;
50 | continue;
51 | }
52 | break;
53 | }
54 | heap->timers[idx] = timer;
55 | }
56 |
57 | /* Sift up the timer heap. */
58 | void event_timer_heap_siftup(struct event_timer_heap *heap, size_t idx) {
59 | assert(heap != NULL && heap->timers != NULL);
60 |
61 | size_t len = heap->len;
62 | size_t start_idx = idx;
63 | size_t child_idx = idx * 2 + 1;
64 | size_t right_idx;
65 | struct event_timer *timer = heap->timers[idx];
66 |
67 | while (child_idx < len) {
68 | right_idx = child_idx + 1;
69 | if (right_idx < len &&
70 | heap->timers[child_idx]->fire_at >=
71 | heap->timers[right_idx]->fire_at)
72 | child_idx = right_idx;
73 | heap->timers[idx] = heap->timers[child_idx];
74 | idx = child_idx;
75 | child_idx = idx * 2 + 1;
76 | }
77 |
78 | heap->timers[idx] = timer;
79 | event_timer_heap_siftdown(heap, start_idx, idx);
80 | }
81 |
82 | /* Push a timer into timer heap. */
83 | int event_timer_heap_push(struct event_timer_heap *heap,
84 | struct event_timer *timer) {
85 | assert(heap != NULL && heap->timers != NULL);
86 |
87 | if (heap->len >= EVENT_TIMER_ID_MAX) return EVENT_ERANGE;
88 |
89 | heap->timers[heap->len++] = timer;
90 | event_timer_heap_siftdown(heap, 0, heap->len - 1);
91 | return EVENT_OK;
92 | }
93 |
94 | /* Pop a timer from heap, NULL on empty. */
95 | struct event_timer *event_timer_heap_pop(struct event_timer_heap *heap) {
96 | assert(heap != NULL && heap->timers != NULL);
97 |
98 | if (heap->len == 0) return NULL;
99 |
100 | struct event_timer *tail = heap->timers[--heap->len];
101 | if (heap->len == 0) return tail;
102 | struct event_timer *head = heap->timers[0];
103 | heap->timers[0] = tail;
104 | event_timer_heap_siftup(heap, 0);
105 | return head;
106 | }
107 |
108 | /* Get the smallest timer from heap, NULL on empty. */
109 | struct event_timer *event_timer_heap_top(struct event_timer_heap *heap) {
110 | assert(heap != NULL && heap->timers != NULL);
111 |
112 | if (heap->len == 0) return NULL;
113 | return heap->timers[0];
114 | }
115 |
116 | /* Delete timer by id from heap. */
117 | int event_timer_heap_del(struct event_timer_heap *heap, int id) {
118 | assert(heap != NULL && heap->timers != NULL);
119 |
120 | if (id < 0 || id >= EVENT_TIMER_ID_MAX) return EVENT_ERANGE;
121 |
122 | if (heap->len == 0) return EVENT_ENOTFOUND;
123 |
124 | int i;
125 | for (i = 0; i < heap->len; i++) {
126 | if (heap->timers[i]->id == id) {
127 | heap->len -= 1;
128 | if (heap->len > 0) {
129 | heap->timers[i] = heap->timers[heap->len];
130 | event_timer_heap_siftup(heap, i);
131 | }
132 | return EVENT_OK;
133 | }
134 | }
135 | return EVENT_ENOTFOUND;
136 | }
137 |
138 | /* Replace the top item with another. */
139 | int event_timer_heap_replace(struct event_timer_heap *heap,
140 | struct event_timer *timer) {
141 | assert(heap != NULL && heap->timers != NULL);
142 |
143 | if (heap->len == 0) return EVENT_ERANGE;
144 | heap->timers[0] = timer;
145 | event_timer_heap_siftup(heap, 0);
146 | return EVENT_OK;
147 | }
148 |
149 | /**
150 | * Event loop.
151 | */
152 |
153 | /**
154 | * Get the nearest timer to fire from timer heap. O(1)
155 | */
156 | struct event_timer *event_nearest_timer(struct event_loop *loop) {
157 | assert(loop != NULL && loop->timers != NULL && loop->timer_heap != NULL);
158 | return event_timer_heap_top(loop->timer_heap);
159 | }
160 |
161 | /**
162 | * Fire timed out timers from heap and update their fire_at. O(log(N)).
163 | */
164 | void event_process_timers(struct event_loop *loop) {
165 | assert(loop != NULL && loop->timers != NULL && loop->timer_heap);
166 |
167 | struct event_timer *timer;
168 |
169 | while (1) {
170 | timer = event_timer_heap_top(loop->timer_heap);
171 | if (timer == NULL) /* no waiting timers to be processed */
172 | break;
173 | if (timer->fire_at <= event_time_now()) {
174 | /* fire this timeouted timer */
175 | if (timer->cb != NULL) (timer->cb)(loop, timer->id, timer->data);
176 | if (timer->id < 0) {
177 | continue; // won't push back if the timer is invalid now.
178 | }
179 | /* push back the timer */
180 | timer->fire_at += timer->interval;
181 | event_timer_heap_replace(loop->timer_heap, timer);
182 | continue;
183 | }
184 | /* the other timers are not ready now */
185 | break;
186 | }
187 | }
188 |
--------------------------------------------------------------------------------
/src/heap.c:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015, Chao Wang
3 | */
4 |
5 | #include
6 | #include
7 |
8 | #include "heap.h"
9 |
10 | /* Create an empty heap. */
11 | struct heap *heap_new(heap_cmp_t cmp) {
12 | struct heap *heap = malloc(sizeof(struct heap));
13 |
14 | if (heap != NULL) {
15 | heap->cap = 0;
16 | heap->len = 0;
17 | heap->cmp = cmp;
18 | heap->data = NULL;
19 | }
20 | return heap;
21 | }
22 |
23 | /* Free heap. */
24 | void heap_free(struct heap *heap) {
25 | if (heap != NULL) {
26 | if (heap->data != NULL) free(heap->data);
27 | free(heap);
28 | }
29 | }
30 |
31 | /* Clear a heap. */
32 | void heap_clear(struct heap *heap) {
33 | assert(heap != NULL);
34 | heap->len = 0;
35 | }
36 |
37 | /* Get heap length. */
38 | size_t heap_len(struct heap *heap) {
39 | assert(heap != NULL);
40 | return heap->len;
41 | }
42 |
43 | /* Get heap cap. */
44 | size_t heap_cap(struct heap *heap) {
45 | assert(heap != NULL);
46 | return heap->cap;
47 | }
48 |
49 | /* Grow a heap's memory capacity to given cap. */
50 | int heap_grow(struct heap *heap, size_t cap) {
51 | assert(heap != NULL);
52 |
53 | if (cap > HEAP_CAP_MAX) return HEAP_ENOMEM;
54 |
55 | if (cap <= heap->cap) return HEAP_OK;
56 |
57 | size_t unit = heap->cap;
58 |
59 | if (unit > HEAP_UNIT_MAX) unit = HEAP_UNIT_MAX;
60 |
61 | if (unit < HEAP_UNIT_MIN) unit = HEAP_UNIT_MIN;
62 |
63 | size_t new_cap = heap->cap + unit;
64 | while (new_cap < cap) new_cap += unit;
65 |
66 | void **data = realloc(heap->data, new_cap * sizeof(void *));
67 | if (data == NULL) return HEAP_ENOMEM;
68 |
69 | heap->data = data;
70 | heap->cap = new_cap;
71 |
72 | if (heap->len > new_cap) heap->len = new_cap;
73 | return HEAP_OK;
74 | }
75 |
76 | /* Push data to heap. */
77 | int heap_push(struct heap *heap, void *data) {
78 | assert(heap != NULL);
79 |
80 | if (heap->len <= heap->cap && heap_grow(heap, heap->len + 1) != HEAP_OK)
81 | return HEAP_ENOMEM;
82 |
83 | assert(heap->data != NULL);
84 | heap->data[heap->len++] = data;
85 | heap_siftdown(heap, 0, heap->len - 1);
86 | return HEAP_OK;
87 | }
88 |
89 | /* Pop data from heap, NULL on empty. */
90 | void *heap_pop(struct heap *heap) {
91 | assert(heap != NULL);
92 |
93 | if (heap->len == 0) return NULL;
94 |
95 | assert(heap->data != NULL && heap->len >= 1);
96 |
97 | void *tail = heap->data[--heap->len];
98 |
99 | if (heap->len == 0) return tail;
100 | void *head = heap->data[0];
101 | heap->data[0] = tail;
102 | heap_siftup(heap, 0);
103 | return head;
104 | }
105 |
106 | /* Push data to heap and pop the top, this runs more efficiently
107 | * than `heap_push` followed by a separate call to `heap_pop`. */
108 | void *heap_pushpop(struct heap *heap, void *data) {
109 | assert(heap != NULL);
110 |
111 | if (heap->len == 0) return data;
112 |
113 | assert(heap->data != NULL);
114 |
115 | void *head = heap->data[0];
116 |
117 | if ((heap->cmp)(head, data) < 0) {
118 | heap->data[0] = data;
119 | data = head;
120 | heap_siftup(heap, 0);
121 | }
122 | return data;
123 | }
124 |
125 | /* Get the smallest data from heap, NULL on empty. */
126 | void *heap_top(struct heap *heap) {
127 | assert(heap != NULL);
128 |
129 | if (heap->len == 0) return NULL;
130 |
131 | assert(heap->data != NULL && heap->len >= 1);
132 | return heap->data[0];
133 | }
134 |
135 | /* Delete node by index and return the data., NULL on not found. */
136 | void *heap_del(struct heap *heap, size_t idx) {
137 | assert(heap != NULL);
138 |
139 | if (heap->len == 0) return NULL;
140 |
141 | if (idx >= heap->len) return NULL;
142 |
143 | assert(heap->data != NULL && heap->len >= 1);
144 |
145 | void *tail = heap->data[--heap->len];
146 |
147 | if (heap->len == 0) return tail;
148 |
149 | void *data = heap->data[idx];
150 | heap->data[idx] = tail;
151 | heap_siftup(heap, idx);
152 | return data;
153 | }
154 |
155 | /* Replace the top item and returns the original data. */
156 | void *heap_replace(struct heap *heap, void *data) {
157 | assert(heap != NULL && heap->data != NULL);
158 | if (heap->len == 0) return NULL;
159 | void *orig = heap->data[0];
160 | heap->data[0] = data;
161 | heap_siftup(heap, 0);
162 | return orig;
163 | }
164 |
165 | /* Sift down the heap. */
166 | void heap_siftdown(struct heap *heap, size_t start_idx, size_t idx) {
167 | assert(heap != NULL && heap->data != NULL);
168 |
169 | size_t parent_idx;
170 | void *parent_data;
171 | void *data = heap->data[idx];
172 |
173 | while (idx > start_idx) {
174 | parent_idx = (idx - 1) >> 1;
175 | parent_data = heap->data[parent_idx];
176 |
177 | if ((heap->cmp)(data, parent_data) < 0) {
178 | heap->data[idx] = parent_data;
179 | idx = parent_idx;
180 | continue;
181 | }
182 | break;
183 | }
184 |
185 | heap->data[idx] = data;
186 | }
187 |
188 | /* Sift up the heap. */
189 | void heap_siftup(struct heap *heap, size_t idx) {
190 | assert(heap != NULL && heap->data != NULL);
191 |
192 | void *data = heap->data[idx];
193 |
194 | size_t len = heap->len;
195 | size_t start_idx = idx;
196 | size_t child_idx = idx * 2 + 1;
197 | size_t right_idx;
198 |
199 | while (child_idx < len) {
200 | right_idx = child_idx + 1;
201 |
202 | if (right_idx < len &&
203 | (heap->cmp)(heap->data[child_idx], heap->data[right_idx]) >= 0)
204 | child_idx = right_idx;
205 | heap->data[idx] = heap->data[child_idx];
206 | idx = child_idx;
207 | child_idx = idx * 2 + 1;
208 | }
209 |
210 | heap->data[idx] = data;
211 | heap_siftdown(heap, start_idx, idx);
212 | }
213 |
--------------------------------------------------------------------------------
/src/heap.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015, Chao Wang
3 | *
4 | * Array based binary heap (or priority queue) implementation.
5 | * deps: None.
6 | */
7 |
8 | #ifndef __HEAP_H__
9 | #define __HEAP_H__
10 |
11 | #include
12 |
13 | #if defined(__cplusplus)
14 | extern "C" {
15 | #endif
16 |
17 | #define HEAP_CAP_MAX 16 * 1024 * 1024 /* max memory capacity: 16mb */
18 | #define HEAP_UNIT_MIN 1 /* min heap realloc unit: 1 */
19 | #define HEAP_UNIT_MAX 1024 /* max heap realloc unit: 1kb */
20 |
21 | #define heap(cmp) heap_new(cmp)
22 |
23 | /* heap node comparator type, return negative if arg#0 < arg#1 */
24 | typedef int (*heap_cmp_t)(void *, void *);
25 |
26 | enum {
27 | HEAP_OK = 0, /* operation is ok */
28 | HEAP_ENOMEM = 1, /* no memory error */
29 | };
30 |
31 | struct heap {
32 | void **data; /* heap array data */
33 | size_t cap; /* heap capacity */
34 | size_t len; /* heap length */
35 | heap_cmp_t cmp; /* node data comparator */
36 | };
37 |
38 | struct heap *heap_new(heap_cmp_t cmp);
39 | void heap_free(struct heap *heap);
40 | void heap_clear(struct heap *heap); /* O(1). */
41 | size_t heap_len(struct heap *heap); /* O(1) */
42 | size_t heap_cap(struct heap *heap); /* O(1) */
43 | int heap_grow(struct heap *heap, size_t cap);
44 | void *heap_pop(struct heap *heap); /* O(logN) */
45 | int heap_push(struct heap *heap, void *data); /* O(logN) */
46 | void *heap_pushpop(struct heap *heap, void *data); /* O(logN) */
47 | void *heap_top(struct heap *heap); /* O(1) */
48 | void *heap_del(struct heap *heap, size_t idx); /* O(log(N)) */
49 | void *heap_replace(struct heap *heap, void *data); /* O(log(N)) */
50 | void heap_siftdown(struct heap *heap, size_t start_idx,
51 | size_t idx); /* O(logN) */
52 | void heap_siftup(struct heap *heap, size_t idx); /* O(logN) */
53 |
54 | #if defined(__cplusplus)
55 | }
56 | #endif
57 |
58 | #endif
59 |
--------------------------------------------------------------------------------
/src/ketama.c:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015, Chao Wang
3 | */
4 |
5 | #include
6 | #include
7 | #include
8 | #include
9 |
10 | #include "ketama.h"
11 | #include "md5.h"
12 |
13 | static uint32_t ketama_hash(char *key, size_t len, size_t align) {
14 | assert(align < 4);
15 | unsigned char results[16];
16 | md5_signature((unsigned char *)key, (unsigned long)len, results);
17 | return ((uint32_t)(results[3 + align * 4] & 0xff) << 24) |
18 | ((uint32_t)(results[2 + align * 4] & 0xff) << 16) |
19 | ((uint32_t)(results[1 + align * 4] & 0xff) << 8) |
20 | (results[0 + align * 4] & 0xff);
21 | }
22 |
23 | static int ketama_node_cmp(const void *node_a, const void *node_b) {
24 | uint32_t hash_a = ((struct ketama_node *)node_a)->hash;
25 | uint32_t hash_b = ((struct ketama_node *)node_b)->hash;
26 |
27 | if (hash_a > hash_b)
28 | return 1;
29 | else if (hash_a < hash_b)
30 | return -1;
31 | else
32 | return 0;
33 | }
34 |
35 | /* Create ketama hash ring from nodes array. */
36 | struct ketama_ring *ketama_ring_new(struct ketama_node *nodes, size_t len) {
37 | if (len > 0) assert(nodes != NULL);
38 |
39 | struct ketama_ring *ring = malloc(sizeof(struct ketama_ring));
40 |
41 | if (ring == NULL) return NULL;
42 |
43 | int i;
44 |
45 | for (i = 0, ring->len = 0; i < len; i++) ring->len += nodes[i].weight * 160;
46 |
47 | ring->nodes = malloc(sizeof(struct ketama_node) * ring->len);
48 |
49 | if (ring->nodes == NULL) {
50 | free(ring);
51 | return NULL;
52 | }
53 |
54 | int j, k, n, digits;
55 | struct ketama_node *node;
56 | unsigned int num;
57 | size_t key_len_max;
58 |
59 | for (i = 0, k = 0; i < len; i++) {
60 | node = &nodes[i];
61 |
62 | for (digits = 0, num = node->weight; num > 0; num /= 10, ++digits)
63 | ;
64 |
65 | assert(node->key != NULL);
66 | assert(node->hash == 0);
67 |
68 | key_len_max = strlen(node->key) + digits + 1;
69 | char key[key_len_max];
70 |
71 | for (j = 0; j < node->weight * 40; j++) {
72 | memset(key, 0, key_len_max);
73 | sprintf(key, "%s-%d", node->key, j);
74 | for (n = 0; n < 4; n++, k++) {
75 | ring->nodes[k].key = node->key;
76 | ring->nodes[k].weight = node->weight;
77 | ring->nodes[k].data = node->data;
78 | ring->nodes[k].idata = node->idata;
79 | ring->nodes[k].idx = i;
80 | ring->nodes[k].hash = ketama_hash(key, strlen(key), n);
81 | }
82 | }
83 | }
84 |
85 | qsort(ring->nodes, ring->len, sizeof(struct ketama_node), ketama_node_cmp);
86 | return ring;
87 | }
88 |
89 | /* Free ketama ring. */
90 | void ketama_ring_free(struct ketama_ring *ring) {
91 | if (ring != NULL) {
92 | if (ring->nodes != NULL) free(ring->nodes);
93 | free(ring);
94 | }
95 | }
96 |
97 | /* Get node by key from ring. */
98 | struct ketama_node *ketama_node_iget(struct ketama_ring *ring, char *key,
99 | size_t key_len) {
100 | assert(ring != NULL);
101 | assert(key != NULL);
102 | assert(ring->nodes != NULL);
103 |
104 | struct ketama_node *nodes = ring->nodes;
105 | size_t len = ring->len;
106 |
107 | if (len == 0) return NULL;
108 |
109 | if (len == 1) return &nodes[0];
110 |
111 | int left = 0, right = len, mid;
112 | uint32_t hash = ketama_hash(key, key_len, 0);
113 | uint32_t mval, pval;
114 |
115 | while (1) {
116 | mid = (left + right) / 2;
117 |
118 | if (mid == len) return &nodes[0];
119 |
120 | mval = nodes[mid].hash;
121 | pval = mid == 0 ? 0 : nodes[mid - 1].hash;
122 |
123 | if (hash <= mval && hash > pval) return &nodes[mid];
124 |
125 | if (mval < hash) {
126 | left = mid + 1;
127 | } else {
128 | right = mid - 1;
129 | }
130 |
131 | if (left > right) return &nodes[0];
132 | }
133 | }
134 |
135 | struct ketama_node *ketama_node_get(struct ketama_ring *ring, char *key) {
136 | return ketama_node_iget(ring, key, strlen(key));
137 | }
138 |
--------------------------------------------------------------------------------
/src/ketama.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015, Chao Wang
3 | *
4 | * Ketama consistent hashing implementation.
5 | * deps: None.
6 | */
7 |
8 | #ifndef __KETAMA_H__
9 | #define __KETAMA_H__
10 |
11 | #include
12 | #include
13 |
14 | #if defined(__cplusplus)
15 | extern "C" {
16 | #endif
17 |
18 | #define ketama_ring(nodes, size) ketama_ring_new(nodes, size)
19 |
20 | /* Note ketama ring's `nodes` and its `length` is not the orignal parameter
21 | * passed in. */
22 | struct ketama_ring {
23 | size_t len; /* hash ring nodes array length */
24 | struct ketama_node *nodes; /* hash ring nodes array */
25 | };
26 |
27 | struct ketama_node {
28 | char *key; /* node key */
29 | unsigned int weight; /* node weight */
30 | void *data; /* user data */
31 | long idata; /* user long typed data */
32 | size_t idx; /* node idx in origin array */
33 | uint32_t hash; /* hash value in the ring */
34 | };
35 |
36 | struct ketama_ring *ketama_ring_new(struct ketama_node *nodes, size_t len);
37 | void ketama_ring_free(struct ketama_ring *ring);
38 | struct ketama_node *ketama_node_iget(struct ketama_ring *ring, char *key,
39 | size_t key_len); /* O(logN) */
40 | struct ketama_node *ketama_node_get(struct ketama_ring *ring,
41 | char *key); /* O(logN) */
42 |
43 | #if defined(__cplusplus)
44 | }
45 | #endif
46 | #endif
47 |
--------------------------------------------------------------------------------
/src/list.c:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015, Chao Wang
3 | */
4 |
5 | #include
6 | #include
7 |
8 | #include "list.h"
9 |
10 | /* Create list node with data. */
11 | struct list_node *list_node_new(void *data) {
12 | struct list_node *node = malloc(sizeof(struct list_node));
13 |
14 | if (node != NULL) {
15 | node->data = data;
16 | node->prev = NULL;
17 | node->next = NULL;
18 | }
19 | return node;
20 | }
21 |
22 | /* Free list node. */
23 | void list_node_free(struct list_node *node) {
24 | if (node != NULL) free(node);
25 | }
26 |
27 | /* Create an empty list. */
28 | struct list *list_new(void) {
29 | struct list *list = malloc(sizeof(struct list));
30 |
31 | if (list != NULL) {
32 | list->head = NULL;
33 | list->tail = NULL;
34 | list->len = 0;
35 | }
36 | return list;
37 | }
38 |
39 | /* Free list. */
40 | void list_free(struct list *list) {
41 | if (list != NULL) {
42 | list_clear(list);
43 | free(list);
44 | }
45 | }
46 |
47 | /* Clear list. */
48 | void list_clear(struct list *list) {
49 | assert(list != NULL);
50 |
51 | while (list_len(list) != 0) list_lpop(list);
52 | }
53 |
54 | /* Get list length. */
55 | size_t list_len(struct list *list) {
56 | assert(list != NULL);
57 | return list->len;
58 | }
59 |
60 | /* Push an item to list on the left. */
61 | int list_lpush(struct list *list, void *data) {
62 | assert(list != NULL);
63 |
64 | struct list_node *node = list_node_new(data);
65 |
66 | if (node == NULL) return LIST_ENOMEM;
67 |
68 | if (list->len == 0) {
69 | assert(list->head == NULL && list->tail == NULL);
70 | list->head = node;
71 | list->tail = node;
72 | } else {
73 | assert(list->head != NULL && list->tail != NULL);
74 | struct list_node *head = list->head;
75 | assert(head->prev == NULL && node->prev == NULL);
76 | head->prev = node;
77 | node->next = head;
78 | list->head = node;
79 | }
80 |
81 | list->len += 1;
82 | return LIST_OK;
83 | }
84 |
85 | /* Push an item to list on the right. */
86 | int list_rpush(struct list *list, void *data) {
87 | assert(list != NULL);
88 |
89 | struct list_node *node = list_node_new(data);
90 |
91 | if (node == NULL) return LIST_ENOMEM;
92 |
93 | if (list->len == 0) {
94 | assert(list->head == NULL && list->tail == NULL);
95 | list->head = node;
96 | list->tail = node;
97 | } else {
98 | assert(list->head != NULL && list->tail != NULL);
99 | struct list_node *tail = list->tail;
100 | assert(tail->next == NULL && node->next == NULL);
101 | tail->next = node;
102 | node->prev = tail;
103 | list->tail = node;
104 | }
105 |
106 | list->len += 1;
107 | return LIST_OK;
108 | }
109 |
110 | /* Pop an item from list on the left. */
111 | void *list_lpop(struct list *list) {
112 | assert(list != NULL);
113 |
114 | if (list->len == 0) {
115 | assert(list->head == NULL && list->tail == NULL);
116 | return NULL;
117 | }
118 |
119 | assert(list->head != NULL && list->tail != NULL);
120 |
121 | struct list_node *head = list->head;
122 | struct list_node *node = head->next;
123 |
124 | if (node == NULL) {
125 | assert(list->len == 1);
126 | list->tail = NULL;
127 | } else {
128 | assert(list->len >= 2);
129 | node->prev = NULL;
130 | }
131 |
132 | list->head = node;
133 | list->len -= 1;
134 |
135 | void *data = head->data;
136 | list_node_free(head);
137 | return data;
138 | }
139 |
140 | /* Pop an item from list on the right. */
141 | void *list_rpop(struct list *list) {
142 | assert(list != NULL);
143 |
144 | if (list->len == 0) {
145 | assert(list->head == NULL && list->tail == NULL);
146 | return NULL;
147 | }
148 |
149 | assert(list->head != NULL && list->tail != NULL);
150 |
151 | struct list_node *tail = list->tail;
152 | struct list_node *node = tail->prev;
153 |
154 | if (node == NULL) {
155 | assert(list->len == 1);
156 | list->head = NULL;
157 | } else {
158 | assert(list->len >= 2);
159 | node->next = NULL;
160 | }
161 |
162 | list->tail = node;
163 | list->len -= 1;
164 |
165 | void *data = tail->data;
166 | list_node_free(tail);
167 | return data;
168 | }
169 |
170 | /* Get the head node data, NULL on empty list. */
171 | void *list_head(struct list *list) {
172 | assert(list != NULL);
173 |
174 | if (list->len == 0) {
175 | assert(list->head == NULL && list->tail == NULL);
176 | return NULL;
177 | }
178 |
179 | assert(list->head != NULL && list->tail != NULL);
180 | return list->head->data;
181 | }
182 |
183 | /* Get the tail node data, NULL on empty list. */
184 | void *list_tail(struct list *list) {
185 | assert(list != NULL);
186 |
187 | if (list->len == 0) {
188 | assert(list->head == NULL && list->tail == NULL);
189 | return NULL;
190 | }
191 |
192 | assert(list->head != NULL && list->tail != NULL);
193 | return list->tail->data;
194 | }
195 |
196 | /* Create list iter, example:
197 | *
198 | * struct list_iter *iter = list_iter_new(list)
199 | * void *data;
200 | *
201 | * while ((data = list_iter_next(iter)) != NULL) {
202 | * ...
203 | * }
204 | * list_iter_free(iter);
205 | *
206 | * Or use it like this:
207 | *
208 | * struct list_iter iter = {list, NULL};
209 | * void *data;
210 | *
211 | * while ((data = list_iter_next(&iter)) != NULL) {
212 | * ...
213 | * }
214 | *
215 | * Or use macro `list_each`:
216 | *
217 | * struct list_node *node;
218 | * list_each(list, node) {
219 | * node.data..
220 | * }
221 | */
222 | struct list_iter *list_iter_new(struct list *list) {
223 | assert(list != NULL);
224 |
225 | struct list_iter *iter = malloc(sizeof(struct list_iter));
226 |
227 | if (iter != NULL) {
228 | iter->list = list;
229 | iter->node = list->head;
230 | }
231 | return iter;
232 | }
233 |
234 | /* Free list iter. */
235 | void list_iter_free(struct list_iter *iter) {
236 | if (iter != NULL) free(iter);
237 | }
238 |
239 | /* Get current node data and seek next, NULL on tail. */
240 | void *list_iter_next(struct list_iter *iter) {
241 | assert(iter != NULL);
242 |
243 | struct list_node *node = iter->node;
244 |
245 | if (node == NULL) return NULL;
246 |
247 | iter->node = node->next;
248 | return node->data;
249 | }
250 |
251 | /* Get current node data and seek prev, NULL on head. */
252 | void *list_iter_prev(struct list_iter *iter) {
253 | assert(iter != NULL);
254 |
255 | struct list_node *node = iter->node;
256 |
257 | if (node == NULL) return NULL;
258 |
259 | iter->node = node->prev;
260 | return node->data;
261 | }
262 |
263 | /* Seek iter to list's head. */
264 | void list_iter_seek_head(struct list_iter *iter) {
265 | assert(iter != NULL && iter->list != NULL);
266 | iter->node = iter->list->head;
267 | }
268 |
269 | /* Seek iter to list's tail. */
270 | void list_iter_seek_tail(struct list_iter *iter) {
271 | assert(iter != NULL && iter->list != NULL);
272 | iter->node = iter->list->tail;
273 | }
274 |
--------------------------------------------------------------------------------
/src/list.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015, Chao Wang
3 | *
4 | * Double-linked list implementation.
5 | * deps: None.
6 | */
7 |
8 | #ifndef __LIST_H__
9 | #define __LIST_H__
10 |
11 | #include
12 |
13 | #if defined(__cplusplus)
14 | extern "C" {
15 | #endif
16 |
17 | #define list() list_new()
18 | #define list_iter(list) list_iter_new(list)
19 | #define list_push(list, data) list_rpush(list, data)
20 | #define list_pop(list) list_lpop(list)
21 | #define list_each(list, node) \
22 | for ((node) = (list)->head; (node) != NULL; (node) = (node)->next)
23 |
24 | enum {
25 | LIST_OK = 0, /* operation is ok */
26 | LIST_ENOMEM = 1, /* no memory error */
27 | };
28 |
29 | struct list_node {
30 | struct list_node *prev; /* prev node */
31 | struct list_node *next; /* next node */
32 | void *data; /* node data */
33 | };
34 |
35 | struct list {
36 | struct list_node *head; /* head node */
37 | struct list_node *tail; /* last node */
38 | size_t len; /* list length */
39 | };
40 |
41 | struct list_iter {
42 | struct list *list; /* list to iterate */
43 | struct list_node *node; /* current list node */
44 | };
45 |
46 | struct list_node *list_node_new(void *data);
47 | void list_node_free(struct list_node *node);
48 | struct list *list_new(void);
49 | void list_free(struct list *list);
50 | void list_clear(struct list *list);
51 | size_t list_len(struct list *list); /* O(1) */
52 | int list_lpush(struct list *list, void *data); /* O(1) */
53 | int list_rpush(struct list *list, void *data); /* O(1) */
54 | void *list_lpop(struct list *list); /* O(1) */
55 | void *list_rpop(struct list *list); /* O(1) */
56 | void *list_head(struct list *list); /* O(1) */
57 | void *list_tail(struct list *list); /* O(1) */
58 | struct list_iter *list_iter_new(struct list *list);
59 | void list_iter_free(struct list_iter *iter);
60 | void *list_iter_next(struct list_iter *iter);
61 | void *list_iter_prev(struct list_iter *iter);
62 | void list_iter_seek_head(struct list_iter *iter);
63 | void list_iter_seek_tail(struct list_iter *iter);
64 |
65 | #if defined(__cplusplus)
66 | }
67 | #endif
68 |
69 | #endif
70 |
--------------------------------------------------------------------------------
/src/log.c:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015, Chao Wang
3 | */
4 |
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 |
20 | #include "log.h"
21 |
22 | static struct logger logger;
23 | static long log_pid;
24 |
25 | static void on_sigsegv(int signal) {
26 | if (signal == SIGSEGV) {
27 | log_critical("Segmentfault received!");
28 | log_trace();
29 | exit(1);
30 | }
31 | }
32 |
33 | /* Open global logger, if `filename` is NULL, use stderr.
34 | * The `rotate_size` only works when logging to a file,
35 | * and `rotate_size==0` means no rotation. */
36 | int log_open(char *name, char *filename, size_t rotate_size) {
37 | assert(name != NULL);
38 |
39 | struct logger *l = &logger;
40 |
41 | l->name = name;
42 | l->level = LOG_INFO;
43 | l->filename = NULL;
44 |
45 | if (filename == NULL) {
46 | l->fd = STDERR_FILENO;
47 | l->rotate_size = 0;
48 | l->fsize = 0;
49 | } else {
50 | assert(strlen(filename) <= LOG_FILENAME_LEN_MAX);
51 | l->filename = filename;
52 | l->rotate_size = rotate_size;
53 | l->fd = open(filename, LOG_FILE_PERM, LOG_FILE_MODE);
54 |
55 | if (l->fd < 0) {
56 | return LOG_EOPEN;
57 | }
58 |
59 | struct stat st;
60 | if (fstat(l->fd, &st) != 0) return LOG_ESTAT;
61 | l->fsize = st.st_size;
62 | }
63 | /* Initialize global log_pid */
64 | #ifdef __linux__
65 | /* using syacall to get tid, or `pid` on system view */
66 | log_pid = (long)syscall(SYS_gettid);
67 | #else
68 | /* I can't find a way to get tid from system view, only print the pid */
69 | log_pid = getpid();
70 | #endif
71 | /* register traceback handler on segmentation fault. */
72 | struct sigaction signal_action;
73 | sigemptyset(&signal_action.sa_mask);
74 | signal_action.sa_flags = 0;
75 | signal_action.sa_handler = &on_sigsegv;
76 | sigaction(SIGSEGV, &signal_action, NULL);
77 |
78 | if (LOG_THREAD_SAFE) pthread_mutex_init(&(l->lock), NULL);
79 | return LOG_OK;
80 | }
81 |
82 | /* Close global logger. */
83 | void log_close(void) {
84 | struct logger *l = &logger;
85 |
86 | if (LOG_THREAD_SAFE) pthread_mutex_destroy(&(l->lock));
87 |
88 | if (l->fd < 0 || l->fd == STDERR_FILENO) return;
89 | close(l->fd);
90 | }
91 |
92 | /* Reopen logging file. */
93 | int log_reopen(void) {
94 | struct logger *l = &logger;
95 |
96 | if (l->fd < 0 || l->fd == STDERR_FILENO) return LOG_OK;
97 |
98 | close(l->fd);
99 |
100 | assert(l->filename != NULL);
101 |
102 | l->fd = open(l->filename, LOG_FILE_PERM, LOG_FILE_MODE);
103 |
104 | if (l->fd < 0) return LOG_EOPEN;
105 | return LOG_OK;
106 | }
107 |
108 | /* Set logger's level. */
109 | void log_setlevel(int level) {
110 | struct logger *l = &logger;
111 |
112 | if (level > LOG_CRITICAL) {
113 | l->level = LOG_CRITICAL;
114 | } else if (level < LOG_DEBUG) {
115 | l->level = LOG_DEBUG;
116 | } else {
117 | l->level = level;
118 | }
119 | }
120 |
121 | /* Rotate log file. */
122 | int log_rotate(void) {
123 | struct logger *l = &logger;
124 |
125 | assert(l->name != NULL);
126 | assert(l->fd > 0 && l->fd != STDERR_FILENO);
127 | assert(l->filename != NULL);
128 |
129 | char buf[LOG_FILENAME_LEN_MAX];
130 | time_t sec;
131 | struct timeval tv;
132 | struct tm *tm;
133 | gettimeofday(&tv, NULL);
134 | sec = tv.tv_sec;
135 | tm = localtime(&sec);
136 | sprintf(buf, "%s.%04d%02d%02d-%02d%02d%03d", l->filename,
137 | tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour,
138 | tm->tm_min, tm->tm_sec);
139 |
140 | if (rename(l->filename, buf)) return LOG_ERENAME;
141 | l->fsize = 0;
142 | return log_reopen();
143 | }
144 |
145 | /* Format logging message to file/stderr. */
146 | int log_log(int level, char *levelname, const char *fmt, ...) {
147 | struct logger *l = &logger;
148 |
149 | assert(levelname != NULL);
150 | assert(l->name != NULL);
151 | assert(l->fd == STDERR_FILENO || l->fd > 0);
152 |
153 | if (level < l->level) return LOG_OK;
154 |
155 | int len = 0, size = LOG_LINE_LEN_MAX;
156 |
157 | char buf[size + 1];
158 |
159 | /* Format time and name, level, pid */
160 | struct timeval tv;
161 | gettimeofday(&tv, NULL);
162 | len += strftime(buf + len, size - len, "%Y-%m-%d %H:%M:%S.",
163 | localtime(&tv.tv_sec));
164 | len += snprintf(buf + len, size - len, "%03ld %-5s %s[%ld] ",
165 | (long)tv.tv_usec / 1000, levelname, l->name, log_pid);
166 | /* Format message with args */
167 | va_list args;
168 | va_start(args, fmt);
169 | len += vsnprintf(buf + len, size - len, fmt, args);
170 | va_end(args);
171 |
172 | /* log line long */
173 | if (len > LOG_LINE_LEN_MAX) {
174 | log_error("the log is too large");
175 | return LOG_ELINESIZE;
176 | }
177 |
178 | buf[len++] = '\n';
179 | return log_write(buf, len);
180 | }
181 |
182 | int log_trace(void) {
183 | void *stack[32];
184 | size_t size = backtrace(stack, 32);
185 | char **symbols = backtrace_symbols(stack, size);
186 |
187 | if (symbols == NULL || size <= 0) return LOG_OK;
188 |
189 | size_t len_max = 1024 * size;
190 | char buf[len_max];
191 | size_t len = 0, i;
192 |
193 | for (i = 0; i < size; i++)
194 | len += snprintf(buf + len, 1024, " [%zu] %s\n", i, symbols[i]);
195 |
196 | free(symbols);
197 | return log_write(buf, len);
198 | }
199 |
200 | int log_write(char *buf, size_t len) {
201 | assert(buf != NULL);
202 | if (len == 0) return LOG_OK;
203 |
204 | struct logger *l = &logger;
205 |
206 | if (LOG_THREAD_SAFE) pthread_mutex_lock(&(l->lock));
207 |
208 | if (write(l->fd, buf, len) < 0) {
209 | return LOG_EWRITE;
210 | } else if (l->filename != NULL) {
211 | l->fsize += len;
212 | if (l->rotate_size != 0) {
213 | if (l->fsize > l->rotate_size) log_rotate();
214 | }
215 | }
216 |
217 | if (LOG_THREAD_SAFE) pthread_mutex_unlock(&(l->lock));
218 | return LOG_OK;
219 | }
220 |
--------------------------------------------------------------------------------
/src/log.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015, Chao Wang
3 | *
4 | * Logging implementation.
5 | * deps: None.
6 | */
7 |
8 | #ifndef __LOG_H__
9 | #define __LOG_H__
10 |
11 | #include
12 | #include
13 | #include
14 |
15 | #if defined(__cplusplus)
16 | extern "C" {
17 | #endif
18 |
19 | #define LOG_LINE_LEN_MAX 1024 * 1024 // 1mb
20 | #define LOG_FILENAME_LEN_MAX 1024 // 1kb
21 | #define LOG_FILE_MODE 0644
22 | #define LOG_FILE_PERM O_WRONLY | O_APPEND | O_CREAT
23 | #define LOG_THREAD_SAFE 1
24 |
25 | #define LOG_DEBUG_S "DEBUG"
26 | #define LOG_INFO_S "INFO"
27 | #define LOG_WARN_S "WARN"
28 | #define LOG_ERROR_S "ERROR"
29 | #define LOG_CRITICAL_S "CRIT"
30 |
31 | enum {
32 | LOG_DEBUG = 10,
33 | LOG_INFO = 20,
34 | LOG_WARN = 30,
35 | LOG_ERROR = 40,
36 | LOG_CRITICAL = 50,
37 | };
38 |
39 | enum {
40 | LOG_OK = 0, /* operation is ok */
41 | LOG_EOPEN = 1, /* failed to open file */
42 | LOG_EWRITE = 2, /* failed to write to file */
43 | LOG_ESTAT = 3, /* failed to stat file */
44 | LOG_ERENAME = 4, /* failed to rename file */
45 | LOG_ELINESIZE = 5, /* log line is too large */
46 | };
47 |
48 | struct logger {
49 | char *name; /* logger name */
50 | char *filename; /* filename to log */
51 | size_t rotate_size; /* rotate size, in bytes (0 for no rotation) */
52 | int level; /* logging level */
53 | int fd; /* fd to write */
54 | size_t fsize; /* original file size + number of bytes written) */
55 | pthread_mutex_t lock; /* lock on logging */
56 | };
57 |
58 | #define log_debug(...) log_log(LOG_DEBUG, LOG_DEBUG_S, __VA_ARGS__)
59 | #define log_info(...) log_log(LOG_INFO, LOG_INFO_S, __VA_ARGS__)
60 | #define log_warn(...) log_log(LOG_WARN, LOG_WARN_S, __VA_ARGS__)
61 | #define log_error(...) log_log(LOG_ERROR, LOG_ERROR_S, __VA_ARGS__)
62 | #define log_critical(...) log_log(LOG_CRITICAL, LOG_CRITICAL_S, __VA_ARGS__)
63 |
64 | int log_open(char *name, char *filename, size_t rotate_size);
65 | void log_close(void);
66 | int log_reopen(void);
67 | void log_setlevel(int level);
68 | int log_rotate(void);
69 | int log_log(int level, char *levelname, const char *fmt, ...);
70 | int log_trace(void);
71 | int log_write(char *buf, size_t len);
72 |
73 | #if defined(__cplusplus)
74 | }
75 | #endif
76 |
77 | #endif
78 |
--------------------------------------------------------------------------------
/src/map.c:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015, Chao Wang
3 | */
4 |
5 | #include
6 | #include
7 | #include
8 | #include
9 |
10 | #include "map.h"
11 |
12 | /* Hash function. */
13 | static uint32_t map_hash(char *key, size_t len) {
14 | /* DJBX33A hash function from PHP */
15 | register int hash = 5381;
16 | for (; len >= 8; len -= 8) {
17 | hash = ((hash << 5) + hash) + *key++;
18 | hash = ((hash << 5) + hash) + *key++;
19 | hash = ((hash << 5) + hash) + *key++;
20 | hash = ((hash << 5) + hash) + *key++;
21 | hash = ((hash << 5) + hash) + *key++;
22 | hash = ((hash << 5) + hash) + *key++;
23 | hash = ((hash << 5) + hash) + *key++;
24 | hash = ((hash << 5) + hash) + *key++;
25 | }
26 | switch (len) {
27 | case 7:
28 | hash = ((hash << 5) + hash) + *key++;
29 | case 6:
30 | hash = ((hash << 5) + hash) + *key++;
31 | case 5:
32 | hash = ((hash << 5) + hash) + *key++;
33 | case 4:
34 | hash = ((hash << 5) + hash) + *key++;
35 | case 3:
36 | hash = ((hash << 5) + hash) + *key++;
37 | case 2:
38 | hash = ((hash << 5) + hash) + *key++;
39 | case 1:
40 | hash = ((hash << 5) + hash) + *key++;
41 | break;
42 | case 0:
43 | break;
44 | }
45 | return hash;
46 | }
47 |
48 | /* If two key equals. */
49 | int map_keycmp(char *key1, size_t len1, char *key2, size_t len2) {
50 | if (len1 == len2 && (memcmp(key1, key2, len1) == 0)) return 1;
51 | return 0;
52 | }
53 |
54 | /* Create a map. */
55 | struct map *map_new(void) {
56 | struct map *m = malloc(sizeof(struct map));
57 |
58 | if (m != NULL) {
59 | m->cap = 0;
60 | m->len = 0;
61 | m->table = NULL;
62 | }
63 | return m;
64 | }
65 |
66 | /* Free map. */
67 | void map_free(struct map *m) {
68 | if (m != NULL) {
69 | if (m->table != NULL) free(m->table);
70 | free(m);
71 | }
72 | }
73 |
74 | /* Clear map. */
75 | void map_clear(struct map *m) {
76 | assert(m != NULL);
77 | if (m->table != NULL) free(m->table);
78 | m->cap = 0;
79 | m->len = 0;
80 | m->table = NULL;
81 | }
82 |
83 | /* Resize and rehash map. */
84 | int map_resize(struct map *m) {
85 | assert(m != NULL);
86 |
87 | /* double sized cap */
88 | size_t cap = m->cap * 2;
89 |
90 | /* validate new cap */
91 | if (cap < 1) cap = MAP_CAP_INIT;
92 |
93 | if (cap > MAP_CAP_MAX) return MAP_ENOMEM;
94 |
95 | /* create new table */
96 | struct map_node *table = malloc(cap * sizeof(struct map_node));
97 |
98 | if (table == NULL) return MAP_ENOMEM;
99 |
100 | /* init all keys to NULL */
101 | int i;
102 | for (i = 0; i < cap; i++) table[i].key = NULL;
103 |
104 | /* rehash old into new table */
105 | int mask = cap - 1;
106 | for (i = 0; i < m->cap; i++) {
107 | struct map_node *node = &m->table[i];
108 |
109 | if (node->key == NULL) continue;
110 |
111 | int j = map_hash(node->key, node->len) & mask;
112 | for (;; j = (j + 1) & mask) {
113 | if (table[j].key != NULL) continue;
114 | table[j].key = node->key;
115 | table[j].len = node->len;
116 | table[j].val = node->val;
117 | break;
118 | }
119 | }
120 | free(m->table);
121 | m->table = table;
122 | m->cap = cap;
123 | return MAP_OK;
124 | }
125 |
126 | /* Get map length. */
127 | size_t map_len(struct map *m) {
128 | assert(m != NULL);
129 | return m->len;
130 | }
131 |
132 | /* Get map capacity. */
133 | size_t map_cap(struct map *m) {
134 | assert(m != NULL);
135 | return m->cap;
136 | }
137 |
138 | /* Set a key into map. */
139 | int map_iset(struct map *m, char *key, size_t len, void *val) {
140 | assert(m != NULL);
141 | assert(key != NULL);
142 |
143 | /* if require resize */
144 | if ((m->cap * MAP_LOAD_LIMIT < m->len || m->cap < MAP_CAP_INIT) &&
145 | map_resize(m) != MAP_OK)
146 | return MAP_ENOMEM;
147 |
148 | /* try to find this key */
149 | int mask = m->cap - 1;
150 | size_t i = map_hash(key, len) & mask;
151 |
152 | for (;; i = (i + 1) & mask) {
153 | struct map_node *node = &m->table[i];
154 | if (node->key == NULL) {
155 | node->key = key;
156 | node->len = len;
157 | node->val = val;
158 | m->len++;
159 | return MAP_OK;
160 | }
161 | if (map_keycmp(node->key, node->len, key, len)) {
162 | node->val = val;
163 | return MAP_OK;
164 | }
165 | }
166 | }
167 |
168 | /* Set a NULL-terminated key into map. */
169 | int map_set(struct map *m, char *key, void *val) {
170 | return map_iset(m, key, strlen(key), val);
171 | }
172 |
173 | /* Get map node by key. */
174 | struct map_node *map_get_node(struct map *m, char *key, size_t len) {
175 | int mask = m->cap - 1;
176 | size_t i = map_hash(key, len) & mask;
177 | struct map_node *node = &m->table[i];
178 |
179 | for (; node->key != NULL; i = (i + 1) & mask, node = &m->table[i])
180 | if (map_keycmp(node->key, node->len, key, len)) return node;
181 | return NULL;
182 | }
183 |
184 | /* Get val by key from map, NULL on not found. */
185 | void *map_iget(struct map *m, char *key, size_t len) {
186 | assert(m != NULL);
187 | assert(key != NULL);
188 |
189 | struct map_node *node = map_get_node(m, key, len);
190 | if (node != NULL) return node->val;
191 | return NULL;
192 | }
193 |
194 | /* Get val by NULL-terminated key from map, NULL on not found. */
195 | void *map_get(struct map *m, char *key) {
196 | return map_iget(m, key, strlen(key));
197 | }
198 |
199 | /* Test if a key is in map. */
200 | int map_ihas(struct map *m, char *key, size_t len) {
201 | assert(m != NULL);
202 | assert(key != NULL);
203 |
204 | struct map_node *node = map_get_node(m, key, len);
205 | if (node != NULL) return 1;
206 | return 0;
207 | }
208 |
209 | /* Test if a key is in map by a NULL-terminated key. */
210 | int map_has(struct map *m, char *key) { return map_ihas(m, key, strlen(key)); }
211 | /* Pop a key from map, NULL on not found. */
212 | void *map_ipop(struct map *m, char *key, size_t len) {
213 | assert(m != NULL);
214 | assert(key != NULL);
215 |
216 | struct map_node *node = map_get_node(m, key, len);
217 | if (node != NULL) {
218 | node->key = NULL;
219 | m->len--;
220 | return node->val;
221 | }
222 | return NULL;
223 | }
224 |
225 | /* Pop a key from map by NULL-terminated key, NULL on not found. */
226 | void *map_pop(struct map *m, char *key) {
227 | return map_ipop(m, key, strlen(key));
228 | }
229 |
230 | /* Create map iter. */
231 | struct map_iter *map_iter_new(struct map *m) {
232 | assert(m != NULL);
233 | struct map_iter *iter = malloc(sizeof(struct map_iter));
234 |
235 | if (iter != NULL) {
236 | iter->m = m;
237 | iter->i = 0;
238 | }
239 | return iter;
240 | }
241 |
242 | /* Free map iter. */
243 | void map_iter_free(struct map_iter *iter) {
244 | if (iter != NULL) free(iter);
245 | }
246 |
247 | /* Get next. */
248 | struct map_node *map_iter_next(struct map_iter *iter) {
249 | assert(iter != NULL && iter->m != NULL);
250 |
251 | struct map *m = iter->m;
252 |
253 | if (m->table == NULL) return NULL;
254 |
255 | for (; iter->i < m->cap; iter->i++) {
256 | struct map_node *node = &m->table[iter->i];
257 | if (node->key != NULL) {
258 | iter->i++;
259 | return node;
260 | }
261 | }
262 | return NULL;
263 | }
264 |
265 | /* Rewind map iter. */
266 | void map_iter_rewind(struct map_iter *iter) {
267 | assert(iter != NULL);
268 | iter->i = 0;
269 | }
270 |
--------------------------------------------------------------------------------
/src/map.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015, Chao Wang
3 | *
4 | * Dynamic sized simple open-addressing hashtable implementation.
5 | * deps: None
6 | */
7 |
8 | #ifndef __MAP_H__
9 | #define __MAP_H__
10 |
11 | #include
12 | #include
13 |
14 | #if defined(__cplusplus)
15 | extern "C" {
16 | #endif
17 |
18 | #define MAP_LOAD_LIMIT 0.72 /* load factor */
19 | #define MAP_CAP_MAX 1024 * 1024 * 1024 /* 1GB */
20 | #define MAP_CAP_INIT 16 /* init table size: must be 2** */
21 |
22 | #define map() map_new()
23 | #define map_iter(m) map_iter_new(m)
24 | #define map_each(iter, node) while (((node) = map_iter_next((iter))) != NULL)
25 |
26 | enum {
27 | MAP_OK = 0, /* operation is ok */
28 | MAP_ENOMEM = 1, /* no memory error */
29 | };
30 |
31 | struct map_node {
32 | char *key; /* key string */
33 | size_t len; /* key length */
34 | void *val; /* value data*/
35 | };
36 |
37 | struct map {
38 | size_t cap; /* map capacity */
39 | size_t len; /* map length */
40 | struct map_node *table; /* node table */
41 | };
42 |
43 | struct map_iter {
44 | struct map *m; /* map to iterate */
45 | size_t i; /* current table index */
46 | };
47 |
48 | struct map *map_new(void);
49 | void map_free(struct map *m);
50 | void map_clear(struct map *m); /* O(1) */
51 | size_t map_len(struct map *m); /* O(1) */
52 | size_t map_cap(struct map *m); /* O(1) */
53 | int map_set(struct map *m, char *key, void *val); /* O(1) */
54 | void *map_get(struct map *m, char *key); /* O(1) */
55 | int map_has(struct map *m, char *key); /* O(1) */
56 | void *map_pop(struct map *m, char *key); /* O(1) */
57 | int map_iset(struct map *m, char *key, size_t len, void *val); /* O(1) */
58 | void *map_iget(struct map *m, char *key, size_t len); /* O(1) */
59 | int map_ihas(struct map *m, char *key, size_t len); /* O(1) */
60 | void *map_ipop(struct map *m, char *key, size_t len); /* O(1) */
61 | struct map_iter *map_iter_new(struct map *m);
62 | void map_iter_free(struct map_iter *iter);
63 | struct map_node *map_iter_next(struct map_iter *iter);
64 | void map_iter_rewind(struct map_iter *iter);
65 |
66 | #if defined(__cplusplus)
67 | }
68 | #endif
69 |
70 | #endif
71 |
--------------------------------------------------------------------------------
/src/md5.c:
--------------------------------------------------------------------------------
1 | /*
2 | * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
3 | * MD5 Message-Digest Algorithm (RFC 1321).
4 | *
5 | * Homepage:
6 | * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
7 | *
8 | * Author: Alexander Peslyak, better known as Solar Designer
10 | */
11 |
12 | #include
13 | #include
14 | #include
15 |
16 | #include "md5.h"
17 |
18 | typedef unsigned int MD5_u32plus;
19 |
20 | typedef struct {
21 | MD5_u32plus lo, hi;
22 | MD5_u32plus a, b, c, d;
23 | unsigned char buffer[64];
24 | MD5_u32plus block[16];
25 | } MD5_CTX;
26 |
27 | /*
28 | * The basic MD5 functions.
29 | *
30 | * F and G are optimized compared to their RFC 1321 definitions for
31 | * architectures that lack an AND-NOT instruction, just like in Colin Plumb's
32 | * implementation.
33 | */
34 | #define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
35 | #define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y))))
36 | #define H(x, y, z) ((x) ^ (y) ^ (z))
37 | #define I(x, y, z) ((y) ^ ((x) | ~(z)))
38 |
39 | /*
40 | * The MD5 transformation for all four rounds.
41 | */
42 | #define STEP(f, a, b, c, d, x, t, s) \
43 | (a) += f((b), (c), (d)) + (x) + (t); \
44 | (a) = (((a) << (s)) | (((a)&0xffffffff) >> (32 - (s)))); \
45 | (a) += (b);
46 |
47 | /*
48 | * SET reads 4 input bytes in little-endian byte order and stores them
49 | * in a properly aligned word in host byte order.
50 | *
51 | * The check for little-endian architectures that tolerate unaligned
52 | * memory accesses is just an optimization. Nothing will break if it
53 | * doesn't work.
54 | */
55 | #if defined(__i386__) || defined(__x86_64__) || defined(__vax__)
56 | #define SET(n) (*(MD5_u32plus *)&ptr[(n)*4])
57 | #define GET(n) SET(n)
58 | #else
59 | #define SET(n) \
60 | (ctx->block[(n)] = (MD5_u32plus)ptr[(n)*4] | \
61 | ((MD5_u32plus)ptr[(n)*4 + 1] << 8) | \
62 | ((MD5_u32plus)ptr[(n)*4 + 2] << 16) | \
63 | ((MD5_u32plus)ptr[(n)*4 + 3] << 24))
64 | #define GET(n) (ctx->block[(n)])
65 | #endif
66 |
67 | /*
68 | * This processes one or more 64-byte data blocks, but does NOT update
69 | * the bit counters. There are no alignment requirements.
70 | */
71 | static void *body(MD5_CTX *ctx, void *data, unsigned long size) {
72 | unsigned char *ptr;
73 | MD5_u32plus a, b, c, d;
74 | MD5_u32plus saved_a, saved_b, saved_c, saved_d;
75 |
76 | ptr = data;
77 |
78 | a = ctx->a;
79 | b = ctx->b;
80 | c = ctx->c;
81 | d = ctx->d;
82 |
83 | do {
84 | saved_a = a;
85 | saved_b = b;
86 | saved_c = c;
87 | saved_d = d;
88 |
89 | /* Round 1 */
90 | STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7)
91 | STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12)
92 | STEP(F, c, d, a, b, SET(2), 0x242070db, 17)
93 | STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22)
94 | STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7)
95 | STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12)
96 | STEP(F, c, d, a, b, SET(6), 0xa8304613, 17)
97 | STEP(F, b, c, d, a, SET(7), 0xfd469501, 22)
98 | STEP(F, a, b, c, d, SET(8), 0x698098d8, 7)
99 | STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12)
100 | STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17)
101 | STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22)
102 | STEP(F, a, b, c, d, SET(12), 0x6b901122, 7)
103 | STEP(F, d, a, b, c, SET(13), 0xfd987193, 12)
104 | STEP(F, c, d, a, b, SET(14), 0xa679438e, 17)
105 | STEP(F, b, c, d, a, SET(15), 0x49b40821, 22)
106 |
107 | /* Round 2 */
108 | STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5)
109 | STEP(G, d, a, b, c, GET(6), 0xc040b340, 9)
110 | STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14)
111 | STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20)
112 | STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5)
113 | STEP(G, d, a, b, c, GET(10), 0x02441453, 9)
114 | STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14)
115 | STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20)
116 | STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5)
117 | STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9)
118 | STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14)
119 | STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20)
120 | STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5)
121 | STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9)
122 | STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14)
123 | STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20)
124 |
125 | /* Round 3 */
126 | STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4)
127 | STEP(H, d, a, b, c, GET(8), 0x8771f681, 11)
128 | STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16)
129 | STEP(H, b, c, d, a, GET(14), 0xfde5380c, 23)
130 | STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4)
131 | STEP(H, d, a, b, c, GET(4), 0x4bdecfa9, 11)
132 | STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16)
133 | STEP(H, b, c, d, a, GET(10), 0xbebfbc70, 23)
134 | STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4)
135 | STEP(H, d, a, b, c, GET(0), 0xeaa127fa, 11)
136 | STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16)
137 | STEP(H, b, c, d, a, GET(6), 0x04881d05, 23)
138 | STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4)
139 | STEP(H, d, a, b, c, GET(12), 0xe6db99e5, 11)
140 | STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16)
141 | STEP(H, b, c, d, a, GET(2), 0xc4ac5665, 23)
142 |
143 | /* Round 4 */
144 | STEP(I, a, b, c, d, GET(0), 0xf4292244, 6)
145 | STEP(I, d, a, b, c, GET(7), 0x432aff97, 10)
146 | STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15)
147 | STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21)
148 | STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6)
149 | STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10)
150 | STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15)
151 | STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21)
152 | STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6)
153 | STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10)
154 | STEP(I, c, d, a, b, GET(6), 0xa3014314, 15)
155 | STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21)
156 | STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6)
157 | STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10)
158 | STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15)
159 | STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21)
160 |
161 | a += saved_a;
162 | b += saved_b;
163 | c += saved_c;
164 | d += saved_d;
165 |
166 | ptr += 64;
167 | } while (size -= 64);
168 |
169 | ctx->a = a;
170 | ctx->b = b;
171 | ctx->c = c;
172 | ctx->d = d;
173 |
174 | return ptr;
175 | }
176 |
177 | void MD5_Init(MD5_CTX *ctx) {
178 | ctx->a = 0x67452301;
179 | ctx->b = 0xefcdab89;
180 | ctx->c = 0x98badcfe;
181 | ctx->d = 0x10325476;
182 |
183 | ctx->lo = 0;
184 | ctx->hi = 0;
185 | }
186 |
187 | void MD5_Update(MD5_CTX *ctx, void *data, unsigned long size) {
188 | MD5_u32plus saved_lo;
189 | unsigned long used, free;
190 |
191 | saved_lo = ctx->lo;
192 | if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo) {
193 | ctx->hi++;
194 | }
195 | ctx->hi += size >> 29;
196 |
197 | used = saved_lo & 0x3f;
198 |
199 | if (used) {
200 | free = 64 - used;
201 |
202 | if (size < free) {
203 | memcpy(&ctx->buffer[used], data, size);
204 | return;
205 | }
206 |
207 | memcpy(&ctx->buffer[used], data, free);
208 | data = (unsigned char *)data + free;
209 | size -= free;
210 | body(ctx, ctx->buffer, 64);
211 | }
212 |
213 | if (size >= 64) {
214 | data = body(ctx, data, size & ~(unsigned long)0x3f);
215 | size &= 0x3f;
216 | }
217 |
218 | memcpy(ctx->buffer, data, size);
219 | }
220 |
221 | void MD5_Final(unsigned char *result, MD5_CTX *ctx) {
222 | unsigned long used, free;
223 |
224 | used = ctx->lo & 0x3f;
225 |
226 | ctx->buffer[used++] = 0x80;
227 |
228 | free = 64 - used;
229 |
230 | if (free < 8) {
231 | memset(&ctx->buffer[used], 0, free);
232 | body(ctx, ctx->buffer, 64);
233 | used = 0;
234 | free = 64;
235 | }
236 |
237 | memset(&ctx->buffer[used], 0, free - 8);
238 |
239 | ctx->lo <<= 3;
240 | ctx->buffer[56] = ctx->lo;
241 | ctx->buffer[57] = ctx->lo >> 8;
242 | ctx->buffer[58] = ctx->lo >> 16;
243 | ctx->buffer[59] = ctx->lo >> 24;
244 | ctx->buffer[60] = ctx->hi;
245 | ctx->buffer[61] = ctx->hi >> 8;
246 | ctx->buffer[62] = ctx->hi >> 16;
247 | ctx->buffer[63] = ctx->hi >> 24;
248 |
249 | body(ctx, ctx->buffer, 64);
250 |
251 | result[0] = ctx->a;
252 | result[1] = ctx->a >> 8;
253 | result[2] = ctx->a >> 16;
254 | result[3] = ctx->a >> 24;
255 | result[4] = ctx->b;
256 | result[5] = ctx->b >> 8;
257 | result[6] = ctx->b >> 16;
258 | result[7] = ctx->b >> 24;
259 | result[8] = ctx->c;
260 | result[9] = ctx->c >> 8;
261 | result[10] = ctx->c >> 16;
262 | result[11] = ctx->c >> 24;
263 | result[12] = ctx->d;
264 | result[13] = ctx->d >> 8;
265 | result[14] = ctx->d >> 16;
266 | result[15] = ctx->d >> 24;
267 |
268 | memset(ctx, 0, sizeof(*ctx));
269 | }
270 |
271 | /*
272 | * Just a simple method for getting the signature
273 | * result must be == 16
274 | */
275 | void md5_signature(unsigned char *key, unsigned long length,
276 | unsigned char *result) {
277 | MD5_CTX my_md5;
278 |
279 | MD5_Init(&my_md5);
280 | (void)MD5_Update(&my_md5, key, length);
281 | MD5_Final(result, &my_md5);
282 | }
283 |
284 | uint32_t hash_md5(const char *key, size_t key_length) {
285 | unsigned char results[16];
286 |
287 | md5_signature((unsigned char *)key, (unsigned long)key_length, results);
288 |
289 | return ((uint32_t)(results[3] & 0xFF) << 24) |
290 | ((uint32_t)(results[2] & 0xFF) << 16) |
291 | ((uint32_t)(results[1] & 0xFF) << 8) | (results[0] & 0xFF);
292 | }
293 |
--------------------------------------------------------------------------------
/src/md5.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015, Chao Wang
3 | *
4 | * md5 hash function.
5 | * deps: None.
6 | */
7 |
8 | /*
9 | * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
10 | * MD5 Message-Digest Algorithm (RFC 1321).
11 | *
12 | * Homepage:
13 | * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
14 | *
15 | * Author: Alexander Peslyak, better known as Solar Designer
17 | */
18 |
19 | #ifndef __MD5_H__
20 | #define __MD5_H__
21 |
22 | #include
23 | #include
24 |
25 | #if defined(__cplusplus)
26 | extern "C" {
27 | #endif
28 |
29 | void md5_signature(unsigned char *key, unsigned long length,
30 | unsigned char *result);
31 | uint32_t hash_md5(const char *key, size_t key_length);
32 |
33 | #if defined(__cplusplus)
34 | }
35 | #endif
36 |
37 | #endif
38 |
--------------------------------------------------------------------------------
/src/queue.c:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015, Chao Wang
3 | */
4 |
5 | #include
6 | #include
7 |
8 | #include "queue.h"
9 |
10 | /* Create new queue node. */
11 | struct queue_node *queue_node_new(void *data) {
12 | struct queue_node *node = malloc(sizeof(struct queue_node));
13 |
14 | if (node != NULL) {
15 | node->data = data;
16 | node->next = NULL;
17 | }
18 | return node;
19 | }
20 |
21 | /* Free a queue node. */
22 | void queue_node_free(struct queue_node *node) {
23 | if (node != NULL) free(node);
24 | }
25 |
26 | /* Create a empty queue */
27 | struct queue *queue_new(void) {
28 | struct queue *queue = malloc(sizeof(struct queue));
29 | if (queue != NULL) {
30 | queue->head = NULL;
31 | queue->tail = NULL;
32 | queue->len = 0;
33 | }
34 | return queue;
35 | }
36 |
37 | /* Free queue. */
38 | void queue_free(struct queue *queue) {
39 | if (queue != NULL) {
40 | queue_clear(queue);
41 | free(queue);
42 | }
43 | }
44 |
45 | /* Clear a queue. */
46 | void queue_clear(struct queue *queue) {
47 | assert(queue != NULL);
48 |
49 | while (queue_len(queue) != 0) queue_pop(queue);
50 | }
51 |
52 | /* Get queue length. */
53 | size_t queue_len(struct queue *queue) {
54 | assert(queue != NULL);
55 | return queue->len;
56 | }
57 |
58 | /* Push an item into the queue. */
59 | int queue_push(struct queue *queue, void *data) {
60 | assert(queue != NULL);
61 |
62 | struct queue_node *node = queue_node_new(data);
63 | if (node == NULL) return QUEUE_ENOMEM;
64 |
65 | if (queue->len == 0) {
66 | assert(queue->head == NULL && queue->tail == NULL);
67 | queue->head = node;
68 | queue->tail = node;
69 | } else {
70 | assert(queue->head != NULL && queue->tail != NULL);
71 | queue->tail->next = node;
72 | queue->tail = node;
73 | }
74 |
75 | queue->len += 1;
76 | return QUEUE_OK;
77 | }
78 |
79 | /* Pop an item from the queue, NULL on empty */
80 | void *queue_pop(struct queue *queue) {
81 | assert(queue != NULL);
82 |
83 | if (queue->len == 0) {
84 | assert(queue->head == NULL && queue->tail == NULL);
85 | return NULL;
86 | }
87 | assert(queue->head != NULL && queue->tail != NULL);
88 | struct queue_node *head = queue->head;
89 |
90 | queue->head = head->next;
91 | queue->len -= 1;
92 |
93 | if (queue->head == NULL) {
94 | assert(queue->len == 0);
95 | queue->tail = NULL;
96 | }
97 |
98 | void *data = head->data;
99 | queue_node_free(head);
100 | return data;
101 | }
102 |
103 | /* Get an item from the top if the queue, NULL on empty. */
104 | void *queue_top(struct queue *queue) {
105 | assert(queue != NULL);
106 |
107 | if (queue->len == 0) {
108 | assert(queue->head == NULL && queue->tail == NULL);
109 | return NULL;
110 | }
111 | assert(queue->head != NULL && queue->tail != NULL);
112 | return queue->head->data;
113 | }
114 |
--------------------------------------------------------------------------------
/src/queue.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015, Chao Wang
3 | *
4 | * List based queue implementation.
5 | * deps: None.
6 | */
7 |
8 | #ifndef __QUEUE_H__
9 | #define __QUEUE_H__
10 |
11 | #include
12 |
13 | #if defined(__cplusplus)
14 | extern "C" {
15 | #endif
16 |
17 | #define queue() queue_new()
18 |
19 | enum {
20 | QUEUE_OK = 0, /* operation is ok */
21 | QUEUE_ENOMEM = 1, /* no memory error */
22 | };
23 |
24 | struct queue_node {
25 | void *data; /* node data */
26 | struct queue_node *next; /* next node */
27 | };
28 |
29 | struct queue {
30 | struct queue_node *head; /* head node */
31 | struct queue_node *tail; /* last node */
32 | size_t len; /* queue length */
33 | };
34 |
35 | struct queue_node *queue_node_new(void *data);
36 | void queue_node_free(struct queue_node *node);
37 | struct queue *queue_new(void);
38 | void queue_free(struct queue *queue);
39 | void queue_clear(struct queue *queue);
40 | size_t queue_len(struct queue *queue); /* O(1) */
41 | int queue_push(struct queue *queue, void *data); /* O(1) */
42 | void *queue_pop(struct queue *queue); /* O(1) */
43 | void *queue_top(struct queue *queue); /* O(1) */
44 |
45 | #if defined(__cplusplus)
46 | }
47 | #endif
48 |
49 | #endif
50 |
--------------------------------------------------------------------------------
/src/signals.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015, Chao Wang
3 | *
4 | * Signals hanlder util.
5 | * deps: None.
6 | */
7 |
8 | #ifndef __SIGNALS_H__
9 | #define __SIGNALS_H__
10 |
11 | #include
12 | #include
13 |
14 | #if defined(__cplusplus)
15 | extern "C" {
16 | #endif
17 |
18 | void signals_register(int signal, void (*handler)(int)) {
19 | struct sigaction signal_action;
20 | sigemptyset(&signal_action.sa_mask);
21 | signal_action.sa_flags = 0;
22 | signal_action.sa_handler = handler;
23 | sigaction(signal, &signal_action, NULL);
24 | }
25 |
26 | #if defined(__cplusplus)
27 | }
28 | #endif
29 |
30 | #endif
31 |
--------------------------------------------------------------------------------
/src/skiplist.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015, Chao Wang
3 | *
4 | * Skiplist implementation.
5 | * deps: None.
6 | */
7 |
8 | #ifndef __SKIPLIST_H__
9 | #define __SKIPLIST_H__
10 |
11 | #include
12 |
13 | #if defined(__cplusplus)
14 | extern "C" {
15 | #endif
16 |
17 | #define SKIPLIST_LEVEL_MAX 32 /* max skiplist level (0~11) */
18 | #define SKIPLIST_FACTOR_P 0.5
19 |
20 | #define skiplist(cmp) skiplist_new(cmp)
21 | #define skiplist_height(sl) skiplist_level(sl)
22 | #define skiplist_iter(sl) skiplist_iter_new(sl)
23 | #define skiplist_each(sl, node) \
24 | for ((node) = (sl)->head->forwards[0]; (node) != NULL; \
25 | (node) = (node)->forwards[0])
26 |
27 | /* socre comparator type, return < 0 if arg#0 < arg#1 */
28 | typedef int (*skiplist_cmp_t)(unsigned long score1, unsigned long score2);
29 |
30 | enum {
31 | SKIPLIST_OK = 0, /* operation is ok */
32 | SKIPLIST_ENOMEM = 1, /* no memory error */
33 | };
34 |
35 | struct skiplist_node {
36 | unsigned long score; /* node score */
37 | void *data; /* node data */
38 | struct skiplist_node **forwards; /* node forward links */
39 | struct skiplist_node *backward; /* node backward link */
40 | };
41 |
42 | struct skiplist {
43 | size_t len; /* skiplist length */
44 | int level; /* skiplist level */
45 | struct skiplist_node *head; /* skiplist head */
46 | struct skiplist_node *tail; /* skiplist tail */
47 | skiplist_cmp_t cmp; /* score comparator */
48 | };
49 |
50 | struct skiplist_iter {
51 | struct skiplist *skiplist; /* skiplist to iterate */
52 | struct skiplist_node *node; /* current skiplist node */
53 | };
54 |
55 | struct skiplist_node *skiplist_node_new(int level, unsigned long score,
56 | void *data);
57 | void skiplist_node_free(struct skiplist_node *node);
58 | struct skiplist *skiplist_new(skiplist_cmp_t cmp);
59 | void skiplist_free(struct skiplist *skiplist);
60 | void skiplist_clear(struct skiplist *skiplist);
61 | size_t skiplist_len(struct skiplist *skiplist); /* O(1) */
62 | int skiplist_level(struct skiplist *skiplist); /* O(1) */
63 | int skiplist_push(struct skiplist *skiplist, unsigned long score,
64 | void *data); /* O(logN) */
65 | void *skiplist_get(struct skiplist *skiplist,
66 | unsigned long score); /* O(logN) */
67 | void *skiplist_pop(struct skiplist *skiplist,
68 | unsigned long score); /* O(logN) */
69 | void *skiplist_popfirst(struct skiplist *skiplist); /* O(1) */
70 | void *skiplist_poplast(struct skiplist *skiplist); /* O(logN) */
71 | struct skiplist_node *skiplist_first(struct skiplist *skiplist); /* O(1) */
72 | struct skiplist_node *skiplist_last(struct skiplist *skiplist); /* O(1) */
73 | struct skiplist_iter *skiplist_iter_new(struct skiplist *skiplist);
74 | void skiplist_iter_free(struct skiplist_iter *iter);
75 | struct skiplist_node *skiplist_iter_next(struct skiplist_iter *iter); /* O(1) */
76 | struct skiplist_node *skiplist_iter_prev(struct skiplist_iter *iter); /* O(1) */
77 | void skiplist_iter_rewind(struct skiplist_iter *iter); /* O(1) */
78 | void skiplist_print(struct skiplist *skiplist);
79 |
80 | #if defined(__cplusplus)
81 | }
82 | #endif
83 |
84 | #endif
85 |
--------------------------------------------------------------------------------
/src/stack.c:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015, Chao Wang
3 | */
4 |
5 | #include
6 | #include
7 |
8 | #include "stack.h"
9 |
10 | /* Create new stack with an initialized capacity. */
11 | struct stack *stack_new(size_t cap) {
12 | struct stack *stack = malloc(sizeof(struct stack));
13 |
14 | if (stack != NULL) {
15 | stack->data = NULL;
16 | stack->len = 0;
17 | stack->cap = 0;
18 |
19 | if (cap > 0 && stack_grow(stack, cap) != STACK_OK) return NULL;
20 | }
21 |
22 | return stack;
23 | }
24 |
25 | /* Free stack and its data. */
26 | void stack_free(struct stack *stack) {
27 | if (stack != NULL) {
28 | if (stack->data != NULL) free(stack->data);
29 | free(stack);
30 | }
31 | }
32 |
33 | /* Clear stack data to NULL and clean its len and cap to zero. */
34 | void stack_clear(struct stack *stack) {
35 | assert(stack != NULL);
36 |
37 | if (stack->data != NULL) {
38 | free(stack->data);
39 | stack->data = NULL;
40 | }
41 |
42 | stack->cap = 0;
43 | stack->len = 0;
44 | }
45 |
46 | /* Get stack length */
47 | size_t stack_len(struct stack *stack) {
48 | assert(stack != NULL);
49 | return stack->len;
50 | }
51 |
52 | /* Get stack capacity */
53 | size_t stack_cap(struct stack *stack) {
54 | assert(stack != NULL);
55 | return stack->cap;
56 | }
57 |
58 | /* Grow a stack's memory capacity to given cap. */
59 | int stack_grow(struct stack *stack, size_t cap) {
60 | assert(stack != NULL);
61 |
62 | if (cap > STACK_CAP_MAX) return STACK_ENOMEM;
63 |
64 | if (cap <= stack->cap) return STACK_OK;
65 |
66 | size_t unit = stack->cap;
67 |
68 | if (unit > STACK_UNIT_MAX) unit = STACK_UNIT_MAX;
69 |
70 | if (unit < STACK_UNIT_MIN) unit = STACK_UNIT_MIN;
71 |
72 | size_t new_cap = stack->cap + unit;
73 | while (new_cap < cap) new_cap += unit;
74 |
75 | void **data = realloc(stack->data, new_cap * sizeof(void *));
76 | if (data == NULL) return STACK_ENOMEM;
77 |
78 | stack->data = data;
79 | stack->cap = new_cap;
80 |
81 | if (stack->len > new_cap) stack->len = new_cap;
82 | return STACK_OK;
83 | }
84 |
85 | /* Push an item on the top of the stack. */
86 | int stack_push(struct stack *stack, void *data) {
87 | assert(stack != NULL);
88 |
89 | if (stack->len <= stack->cap &&
90 | stack_grow(stack, stack->len + 1) != STACK_OK)
91 | return STACK_ENOMEM;
92 |
93 | stack->data[stack->len++] = data;
94 | return STACK_OK;
95 | }
96 |
97 | /* Pop an item from the top of the stack, NULL on empty. */
98 | void *stack_pop(struct stack *stack) {
99 | assert(stack != NULL);
100 |
101 | if (stack->len == 0 || stack->data == NULL) return NULL;
102 |
103 | return stack->data[--stack->len];
104 | }
105 |
106 | /* Get an item from the top of the stack, NULL on empty. */
107 | void *stack_top(struct stack *stack) {
108 | assert(stack != NULL);
109 |
110 | if (stack->len == 0 || stack->data == NULL) return NULL;
111 |
112 | return stack->data[stack->len - 1];
113 | }
114 |
--------------------------------------------------------------------------------
/src/stack.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015, Chao Wang
3 | *
4 | * Array based stack implementation.
5 | * deps: None.
6 | */
7 |
8 | #ifndef __STACK_H__
9 | #define __STACK_H__
10 |
11 | #include
12 |
13 | #if defined(__cplusplus)
14 | extern "C" {
15 | #endif
16 |
17 | /* note that real allocated size is cap * sizeof(void *). */
18 | #define STACK_CAP_MAX 16 * 1024 * 1024 /* max stack capacity: 16mb */
19 | #define STACK_UNIT_MIN 1 /* min stack realloc unit: 1 */
20 | #define STACK_UNIT_MAX 1024 /* max stack realloc unit: 1k */
21 |
22 | #define stack(cap) stack_new(cap)
23 |
24 | enum {
25 | STACK_OK = 0, /* operation is ok */
26 | STACK_ENOMEM = 1, /* no memory error */
27 | };
28 |
29 | struct stack {
30 | size_t len; /* stack length */
31 | size_t cap; /* stack capacity */
32 | void **data; /* stack data */
33 | };
34 |
35 | struct stack *stack_new(size_t cap);
36 | void stack_free(struct stack *stack);
37 | void stack_clear(struct stack *stack);
38 | size_t stack_len(struct stack *stack); /* O(1) */
39 | size_t stack_cap(struct stack *stack); /* O(1) */
40 | void *stack_pop(struct stack *stack); /* O(1) */
41 | void *stack_top(struct stack *stack); /* O(1) */
42 | int stack_push(struct stack *stack, void *data); /* O(1) */
43 | int stack_grow(struct stack *stack, size_t cap);
44 |
45 | #if defined(__cplusplus)
46 | }
47 | #endif
48 |
49 | #endif
50 |
--------------------------------------------------------------------------------
/src/strings.c:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015, Chao Wang
3 | */
4 |
5 | #include
6 | #include
7 | #include
8 |
9 | #include "strings.h"
10 |
11 | /* Search null-terminated string `sub` in string `s`, simple version via
12 | * Boyer Moore string search algorithm. Return the first position of the
13 | * `sub` in the `s`, return the `s`'s length on failure. */
14 | size_t strings_search(char *s, char *sub, size_t start) {
15 | assert(s != NULL && sub != NULL);
16 |
17 | size_t s_len = strlen(s);
18 | size_t len = strlen(sub);
19 | size_t last = len - 1;
20 | size_t idx;
21 |
22 | size_t table[256] = {0};
23 |
24 | /* build bad char table */
25 | for (idx = 0; idx < 256; idx++) table[idx] = len;
26 |
27 | for (idx = 0; idx < len; idx++) table[(int)sub[idx]] = last - idx;
28 |
29 | /* do search */
30 | size_t i, j, k, t, skip;
31 |
32 | for (i = start; i < s_len; i += skip) {
33 | skip = 0;
34 | for (j = 0; j < len; j++) {
35 | k = last - j;
36 | if (sub[k] != s[i + k]) {
37 | t = table[(int)s[i + k]];
38 | skip = t > j ? t - j : 1;
39 | break;
40 | }
41 | }
42 | if (skip == 0)
43 | // hit
44 | return i;
45 | }
46 | // failed
47 | return s_len;
48 | }
49 |
50 | /* Create random string with length `len`, you may want
51 | * to set rand seed before all your `rand` calls. */
52 | char *strings_rand(char *s, size_t len) {
53 | static const char chs[] =
54 | "0123456789"
55 | "abcdefghijklmnopqrstuvwxyz"
56 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
57 | static const int mask = 10 + 26 * 2 - 1;
58 |
59 | int i;
60 |
61 | for (i = 0; i < len; i++) s[i] = chs[rand() & mask];
62 |
63 | s[len] = 0;
64 | return s;
65 | }
66 |
67 | /* Replace all `sub` in string `src` with `rep` and concat the
68 | * result into `dst`. All the arguments are NULL-terminated c
69 | * string, return */
70 | char *strings_replace(char *dst, char *src, char *sub, char *rep) {
71 | size_t src_len = strlen(src);
72 | size_t sub_len = strlen(sub);
73 | size_t rep_len = strlen(rep);
74 | size_t dst_len = 0;
75 | size_t idx, start = 0;
76 |
77 | while ((idx = strings_search(src, sub, start)) < src_len) {
78 | strncat(dst + dst_len, src + start, idx - start);
79 | dst_len += idx - start;
80 | strcat(dst + dst_len, rep);
81 | dst_len += rep_len;
82 | start = idx + sub_len;
83 | }
84 | strcat(dst + dst_len, src + start);
85 | dst_len += src_len - start;
86 | dst[dst_len] = '\0';
87 | return dst;
88 | }
89 |
--------------------------------------------------------------------------------
/src/strings.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015, Chao Wang
3 | *
4 | * Util functions for C native strings.
5 | * deps: None.
6 | */
7 |
8 | #ifndef __STRINGS_H__
9 | #define __STRINGS_H__
10 |
11 | #include
12 |
13 | #if defined(__cplusplus)
14 | extern "C" {
15 | #endif
16 |
17 | size_t strings_search(char *s, char *sub,
18 | size_t start); /* best O(N/M), worst O(M*N) */
19 | char *strings_rand(char *s, size_t len); /* O(N) */
20 | char *strings_replace(char *dst, char *src, char *sub,
21 | char *rep); /* best O(N), worst O(N*N) */
22 |
23 | #if defined(__cplusplus)
24 | }
25 | #endif
26 |
27 | #endif
28 |
--------------------------------------------------------------------------------
/src/utils.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015, Chao Wang
3 | * deps: None.
4 | */
5 |
6 | #ifndef __UTILS_H__
7 | #define __UTILS_H__
8 |
9 | #include
10 | #include
11 |
12 | #if defined(__cplusplus)
13 | extern "C" {
14 | #endif
15 |
16 | /**
17 | * MIN and MAX
18 | */
19 | #define MIN(a, b) ((a) < (b) ? (a) : (b))
20 | #define MAX(a, b) ((a) > (b) ? (a) : (b))
21 |
22 | /**
23 | * OS Platforms
24 | */
25 | #ifdef __linux__
26 | #define OSPLAT_LINUX 1
27 | #endif
28 |
29 | #if defined(__APPLE__)
30 | #define OSPLAT_OSX 1
31 | #endif
32 |
33 | #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
34 | #define OSPLAT_BSD 1
35 | #endif
36 |
37 | #ifdef __sun
38 | #define OSPLAT_SUN 1
39 | #endif
40 |
41 | #if defined(__cplusplus)
42 | }
43 | #endif
44 |
45 | #endif
46 |
--------------------------------------------------------------------------------
/test/.ycm_extra_conf.py:
--------------------------------------------------------------------------------
1 | # This file is NOT licensed under the GPLv3, which is the license for the rest
2 | # of YouCompleteMe.
3 | #
4 | # Here's the license text for this file:
5 | #
6 | # This is free and unencumbered software released into the public domain.
7 | #
8 | # Anyone is free to copy, modify, publish, use, compile, sell, or
9 | # distribute this software, either in source code form or as a compiled
10 | # binary, for any purpose, commercial or non-commercial, and by any
11 | # means.
12 | #
13 | # In jurisdictions that recognize copyright laws, the author or authors
14 | # of this software dedicate any and all copyright interest in the
15 | # software to the public domain. We make this dedication for the benefit
16 | # of the public at large and to the detriment of our heirs and
17 | # successors. We intend this dedication to be an overt act of
18 | # relinquishment in perpetuity of all present and future rights to this
19 | # software under copyright law.
20 | #
21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
24 | # IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
25 | # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
26 | # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27 | # OTHER DEALINGS IN THE SOFTWARE.
28 | #
29 | # For more information, please refer to
30 |
31 | import os
32 | import ycm_core
33 |
34 | flags = [
35 | # INSERT FLAGS HERE
36 | '-Wall',
37 | '-I../src',
38 | '-std=c99',
39 | '-D_GNU_SOURCE',
40 | '-pthread',
41 | ]
42 |
43 |
44 | # Set this to the absolute path to the folder (NOT the file!) containing the
45 | # compile_commands.json file to use that instead of 'flags'. See here for
46 | # more details: http://clang.llvm.org/docs/JSONCompilationDatabase.html
47 | #
48 | # You can get CMake to generate this file for you by adding:
49 | # set( CMAKE_EXPORT_COMPILE_COMMANDS 1 )
50 | # to your CMakeLists.txt file.
51 | #
52 | # Most projects will NOT need to set this to anything; you can just change the
53 | # 'flags' list of compilation flags. Notice that YCM itself uses that approach.
54 | compilation_database_folder = ''
55 |
56 | if os.path.exists(compilation_database_folder):
57 | database = ycm_core.CompilationDatabase(compilation_database_folder)
58 | else:
59 | database = None
60 |
61 | SOURCE_EXTENSIONS = ['.cpp', '.cxx', '.cc', '.c', '.m', '.mm']
62 |
63 |
64 | def DirectoryOfThisScript():
65 | return os.path.dirname(os.path.abspath(__file__))
66 |
67 |
68 | def MakeRelativePathsInFlagsAbsolute(flags, working_directory):
69 | if not working_directory:
70 | return list(flags)
71 | new_flags = []
72 | make_next_absolute = False
73 | path_flags = ['-isystem', '-I', '-iquote', '--sysroot=']
74 | for flag in flags:
75 | new_flag = flag
76 |
77 | if make_next_absolute:
78 | make_next_absolute = False
79 | if not flag.startswith('/'):
80 | new_flag = os.path.join(working_directory, flag)
81 |
82 | for path_flag in path_flags:
83 | if flag == path_flag:
84 | make_next_absolute = True
85 | break
86 |
87 | if flag.startswith(path_flag):
88 | path = flag[len(path_flag):]
89 | new_flag = path_flag + os.path.join(working_directory, path)
90 | break
91 |
92 | if new_flag:
93 | new_flags.append(new_flag)
94 | return new_flags
95 |
96 |
97 | def IsHeaderFile(filename):
98 | extension = os.path.splitext(filename)[1]
99 | return extension in ['.h', '.hxx', '.hpp', '.hh']
100 |
101 |
102 | def GetCompilationInfoForFile(filename):
103 | if IsHeaderFile(filename):
104 | basename = os.path.splitext(filename)[0]
105 | for extension in SOURCE_EXTENSIONS:
106 | replacement_file = basename + extension
107 | if os.path.exists(replacement_file):
108 | compilation_info = database.GetCompilationInfoForFile(
109 | replacement_file)
110 | if compilation_info.compiler_flags_:
111 | return compilation_info
112 | return None
113 | return database.GetCompilationInfoForFile(filename)
114 |
115 |
116 | def FlagsForFile(filename, **kwargs):
117 | if database:
118 | # Bear in mind that compilation_info.compiler_flags_ does NOT return a
119 | # python list, but a "list-like" StringVec object
120 | compilation_info = GetCompilationInfoForFile(filename)
121 | if not compilation_info:
122 | return None
123 |
124 | final_flags = MakeRelativePathsInFlagsAbsolute(
125 | compilation_info.compiler_flags_,
126 | compilation_info.compiler_working_dir_)
127 |
128 | else:
129 | relative_to = DirectoryOfThisScript()
130 | final_flags = MakeRelativePathsInFlagsAbsolute(flags, relative_to)
131 |
132 | return {
133 | 'flags': final_flags,
134 | 'do_cache': True
135 | }
136 |
--------------------------------------------------------------------------------
/test/Makefile:
--------------------------------------------------------------------------------
1 | # vim:set noet:
2 |
3 | default: runtests
4 |
5 | NAME=test
6 | CC=cc -std=c99
7 | OPTIMIZATION?=
8 | CFLAGS=-Wall $(OPTIMIZATION) -D_GNU_SOURCE -g -I../src
9 | LDFLAGS=-Wall -pthread
10 | BIN=$(NAME)
11 | SRC:=$(wildcard ../src/*.c) $(wildcard *.c)
12 | EV_EPOLL:=$(wildcard ../src/event_epoll.c)
13 | EV_KQUEUE:=$(wildcard ../src/event_kqueue.c)
14 | EV_TIMER:=$(wildcard ../src/event_timer.c)
15 | SRC:=$(filter-out $(EV_EPOLL), $(SRC))
16 | SRC:=$(filter-out $(EV_KQUEUE), $(SRC))
17 | SRC:=$(filter-out $(EV_TIMER), $(SRC))
18 | OBJ:=$(SRC:c=o)
19 | LOG:=$(NAME)-mtrace.log
20 | UNAME=$(shell uname)
21 |
22 | $(BIN): $(OBJ)
23 |
24 | runtests: $(BIN)
25 | ifeq ($(UNAME), Linux)
26 | @env MALLOC_TRACE=$(LOG) ./$(BIN)
27 | @mtrace $(BIN) $(LOG)
28 | else
29 | ./$(BIN)
30 | endif
31 |
32 | clean:
33 | rm -f $(BIN) $(LOG) $(OBJ) test.log*
34 |
--------------------------------------------------------------------------------
/test/buf_test.c:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015, Chao Wang
3 | */
4 |
5 | #include
6 | #include
7 |
8 | #include "buf.h"
9 |
10 | void case_buf_clear() {
11 | struct buf *buf1 = buf("test");
12 | struct buf *buf2 = buf(NULL);
13 | assert(!buf_isempty(buf1));
14 | assert(buf_isempty(buf2));
15 | buf_clear(buf1);
16 | buf_clear(buf2);
17 | assert(buf_isempty(buf1));
18 | assert(buf_isempty(buf2));
19 | buf_free(buf1);
20 | buf_free(buf2);
21 | }
22 |
23 | void case_buf_put() {
24 | struct buf *buf = buf(NULL);
25 | assert(buf_put(buf, "abc", 3) == BUF_OK);
26 | assert(strcmp(str(buf), "abc") == 0);
27 | assert(buf_put(buf, "efg", 3) == BUF_OK);
28 | assert(strcmp(str(buf), "abcefg") == 0);
29 | buf_free(buf);
30 | }
31 |
32 | void case_buf_puts() {
33 | struct buf *buf = buf(NULL);
34 | assert(buf_puts(buf, "abc") == BUF_OK);
35 | assert(strcmp(str(buf), "abc") == 0);
36 | assert(buf_puts(buf, "efg") == BUF_OK);
37 | assert(strcmp(str(buf), "abcefg") == 0);
38 | buf_free(buf);
39 | }
40 |
41 | void case_buf_putc() {
42 | struct buf *buf = buf(NULL);
43 | assert(buf_putc(buf, 'a') == BUF_OK);
44 | assert(buf_putc(buf, 'b') == BUF_OK);
45 | assert(buf_putc(buf, 'c') == BUF_OK);
46 | assert(buf_putc(buf, 'd') == BUF_OK);
47 | assert(strcmp(str(buf), "abcd") == 0);
48 | buf_free(buf);
49 | }
50 |
51 | void case_buf_str() {
52 | struct buf *buf = buf(NULL);
53 | assert(strcmp(str(buf), "") == 0);
54 | buf_puts(buf, "abcdef");
55 | assert(strcmp(str(buf), "abcdef") == 0);
56 | buf_free(buf);
57 | }
58 |
59 | void case_buf_sprintf() {
60 | struct buf *buf = buf(NULL);
61 | assert(buf_sprintf(buf, "%s %s!", "hello", "world") == BUF_OK);
62 | assert(strcmp(buf_str(buf), "hello world!") == 0);
63 | buf_free(buf);
64 | }
65 |
66 | void case_buf_isempty() {
67 | struct buf *buf1 = buf("test");
68 | struct buf *buf2 = buf(NULL);
69 | assert(!buf_isempty(buf1));
70 | assert(buf_isempty(buf2));
71 | buf_free(buf1);
72 | buf_free(buf2);
73 | }
74 |
75 | void case_buf_lrm() {
76 | struct buf *buf = buf("testabcdef");
77 | buf_lrm(buf, 4);
78 | assert(strcmp(buf_str(buf), "abcdef") == 0);
79 | buf_lrm(buf, 100);
80 | assert(strcmp(buf_str(buf), "") == 0);
81 | buf_free(buf);
82 | }
83 |
84 | void case_buf_len() {
85 | struct buf *buf = buf("abcdef");
86 | assert(buf_len(buf) == 6);
87 | buf_free(buf);
88 | }
89 |
90 | void case_buf_cap() {
91 | struct buf *buf = buf("abcdef");
92 | assert(buf_cap(buf) == 6);
93 | buf_puts(buf, "abc");
94 | assert(buf_cap(buf) == 12);
95 | buf_free(buf);
96 | }
97 |
--------------------------------------------------------------------------------
/test/cfg_test.c:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015, Chao Wang
3 | */
4 |
5 | #include
6 | #include
7 | #include
8 |
9 | #include "cfg.h"
10 |
11 | void case_cfg_get() {
12 | char s[1024] =
13 | "# this is an proxy example cfg.\n"
14 | "port 8125 # port to bind\n"
15 | "# backend server nodes\n"
16 | "node 127.0.0.1:8001\n";
17 | struct cfg cfg;
18 | cfg.data = s;
19 | cfg.len = strlen(s);
20 | cfg.lineno = 1;
21 |
22 | assert(cfg_get(&cfg) == CFG_OK);
23 | assert(strncmp("port", cfg.key, cfg.key_len) == 0);
24 | assert(strncmp("8125", cfg.val, cfg.val_len) == 0);
25 |
26 | assert(cfg_get(&cfg) == CFG_OK);
27 | assert(strncmp("node", cfg.key, cfg.key_len) == 0);
28 | assert(strncmp("127.0.0.1:8001", cfg.val, cfg.val_len) == 0);
29 | }
30 |
--------------------------------------------------------------------------------
/test/datetime_test.c:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015, Chao Wang
3 | */
4 |
5 | #include
6 |
7 | #include "datetime.h"
8 |
9 | void case_datetime_stamp_now() {
10 | /* assert current timstamp must be greater than 1447502650543
11 | * (the stamp when I'm writing this test case) */
12 | assert(datetime_stamp_now() > 1447502650543);
13 | /* assert that the code will run so fast the two getting results
14 | * diff should smaller than 1ms */
15 | assert((long)datetime_stamp_now() == (long)datetime_stamp_now());
16 | }
17 |
--------------------------------------------------------------------------------
/test/dict_test.c:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015, Chao Wang
3 | */
4 |
5 | #include
6 | #include
7 |
8 | #include "dict.h"
9 |
10 | void case_dict_set() {
11 | struct dict *dict = dict();
12 | char *key = "key", *val = "val";
13 | assert(dict_set(dict, key, val) == DICT_OK);
14 | assert(dict_len(dict) == 1);
15 | char *val_ = "val_";
16 | assert(dict_get(dict, key) == val);
17 | assert(dict_set(dict, key, val_) == DICT_OK);
18 | assert(dict_get(dict, key) == val_);
19 | dict_free(dict);
20 | }
21 |
22 | void case_dict_get() {
23 | struct dict *dict = dict();
24 | char *key = "key", *val = "val";
25 | assert(dict_set(dict, key, val) == DICT_OK);
26 | assert(dict_len(dict) == 1);
27 | assert(dict_get(dict, key) == val);
28 | assert(dict_get(dict, "not exist") == NULL);
29 | dict_free(dict);
30 | }
31 |
32 | void case_dict_pop() {
33 | struct dict *dict = dict();
34 | char *key = "key", *val = "val";
35 | assert(dict_set(dict, key, val) == DICT_OK);
36 | assert(dict_len(dict) == 1);
37 | assert(dict_pop(dict, key) == val);
38 | assert(dict_len(dict) == 0);
39 | assert(dict_pop(dict, key) == NULL);
40 | assert(dict_len(dict) == 0);
41 | dict_free(dict);
42 | }
43 |
44 | void case_dict_has() {
45 | struct dict *dict = dict();
46 | char *key = "key", *val = "val";
47 | assert(dict_set(dict, key, val) == DICT_OK);
48 | assert(!dict_has(dict, "not exist"));
49 | assert(dict_has(dict, key));
50 | dict_free(dict);
51 | }
52 |
53 | void case_dict_clear() {
54 | struct dict *dict = dict();
55 | assert(dict_set(dict, "key1", "val1") == DICT_OK);
56 | assert(dict_set(dict, "key2", "val2") == DICT_OK);
57 | assert(dict_set(dict, "key3", "val3") == DICT_OK);
58 | assert(dict_set(dict, "key4", "val4") == DICT_OK);
59 | assert(dict_len(dict) == 4);
60 | dict_clear(dict);
61 | assert(dict_len(dict) == 0);
62 | dict_free(dict);
63 | }
64 |
65 | void case_dict_resize() {
66 | struct dict *dict = dict();
67 | assert(dict_set(dict, "key1", "val1") == DICT_OK);
68 | assert(dict_set(dict, "key2", "val2") == DICT_OK);
69 | assert(dict_set(dict, "key3", "val3") == DICT_OK);
70 | assert(dict_set(dict, "key4", "val4") == DICT_OK);
71 | assert(dict_len(dict) == 4);
72 | assert(dict->idx == 0 && dict_cap(dict) == 7);
73 | assert(dict_set(dict, "key5", "val5") == DICT_OK);
74 | assert(dict_set(dict, "key6", "val6") == DICT_OK);
75 | assert(dict_len(dict) == 6);
76 | assert(dict->idx == 1 && dict_cap(dict) == 17);
77 | dict_free(dict);
78 | }
79 |
80 | void case_dict_iter() {
81 | struct dict *dict = dict();
82 | char *key1 = "key1";
83 | char *key2 = "key2";
84 | char *key3 = "key3";
85 | char *key4 = "key4";
86 | char *key5 = "key5";
87 | char *key6 = "key6";
88 | assert(dict_set(dict, key1, "val1") == DICT_OK);
89 | assert(dict_set(dict, key2, "val2") == DICT_OK);
90 | assert(dict_set(dict, key3, "val3") == DICT_OK);
91 | assert(dict_set(dict, key4, "val4") == DICT_OK);
92 | assert(dict_set(dict, key5, "val5") == DICT_OK);
93 | assert(dict_set(dict, key6, "val6") == DICT_OK);
94 |
95 | struct dict_iter *iter = dict_iter(dict);
96 |
97 | assert(dict_iter_next(iter) != NULL);
98 | assert(dict_iter_next(iter) != NULL);
99 | assert(dict_iter_next(iter) != NULL);
100 | assert(dict_iter_next(iter) != NULL);
101 | assert(dict_iter_next(iter) != NULL);
102 | assert(dict_iter_next(iter) != NULL);
103 | assert(dict_iter_next(iter) == NULL);
104 | dict_iter_free(iter);
105 |
106 | struct dict_iter iter2 = {dict};
107 | struct dict_node *node = NULL;
108 | dict_each(&iter2, node) {
109 | assert(node != NULL);
110 | assert(strlen((char *)node->val) == 4);
111 | };
112 | dict_free(dict);
113 | }
114 |
--------------------------------------------------------------------------------
/test/event_test.c:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015, Chao Wang
3 | */
4 |
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 |
13 | #include "event.h"
14 |
15 | int fds[2];
16 |
17 | void *write_data(void *data) {
18 | usleep(1000);
19 | char buf[256] = "abcdef";
20 | assert(write(fds[1], buf, 6) == 6);
21 | return NULL;
22 | }
23 |
24 | void read_data(struct event_loop *loop, int fd, int mask, void *data) {
25 | char buf[256];
26 |
27 | if (fd == fds[0]) {
28 | assert(read(fd, buf, 6) == 6);
29 | assert(strcmp(buf, "abcdef") == 0);
30 | event_loop_stop(loop);
31 | }
32 | }
33 |
34 | void case_event_simple() {
35 | assert(pipe(fds) == 0);
36 |
37 | struct event_loop *loop = event_loop_new(100);
38 | event_add_in(loop, fds[0], &read_data, NULL);
39 |
40 | pthread_t t;
41 | pthread_create(&t, NULL, &write_data, NULL);
42 |
43 | event_loop_start(loop);
44 | event_loop_free(loop);
45 |
46 | pthread_join(t, NULL);
47 | }
48 |
--------------------------------------------------------------------------------
/test/heap_test.c:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015, Chao Wang
3 | */
4 |
5 | #include
6 |
7 | #include "heap.h"
8 |
9 | int heap_cmp(void *a, void *b) { return *(int *)a - *(int *)b; }
10 | void case_heap_clear() {
11 | struct heap *heap = heap(heap_cmp);
12 | int a = 1;
13 | assert(heap_push(heap, (void *)&a) == HEAP_OK);
14 | assert(heap_len(heap) == 1);
15 | assert(heap_cap(heap) == 1);
16 | heap_clear(heap);
17 | assert(heap_len(heap) == 0);
18 | heap_free(heap);
19 | }
20 |
21 | void case_heap_len() {
22 | struct heap *heap = heap(heap_cmp);
23 | assert(heap_len(heap) == 0);
24 | int a = 1, b = 2, c = 3;
25 | assert(heap_push(heap, (void *)&a) == HEAP_OK);
26 | assert(heap_push(heap, (void *)&b) == HEAP_OK);
27 | assert(heap_push(heap, (void *)&c) == HEAP_OK);
28 | assert(heap_len(heap) == 3);
29 | heap_free(heap);
30 | }
31 |
32 | void case_heap_cap() {
33 | struct heap *heap = heap(heap_cmp);
34 | assert(heap_cap(heap) == 0);
35 | int a = 1, b = 2, c = 3;
36 | assert(heap_push(heap, (void *)&a) == HEAP_OK);
37 | assert(heap_cap(heap) == 1);
38 | assert(heap_push(heap, (void *)&b) == HEAP_OK);
39 | assert(heap_cap(heap) == 2);
40 | assert(heap_push(heap, (void *)&c) == HEAP_OK);
41 | assert(heap_cap(heap) == 4);
42 | heap_free(heap);
43 | }
44 |
45 | void case_heap_push() {
46 | struct heap *heap = heap(heap_cmp);
47 | int a = 3, b = 1, c = 2;
48 | assert(heap_push(heap, (void *)&a) == HEAP_OK);
49 | assert(heap_push(heap, (void *)&b) == HEAP_OK);
50 | assert(heap_push(heap, (void *)&c) == HEAP_OK);
51 | assert(heap_len(heap) == 3);
52 | assert(*(int *)heap_pop(heap) == 1);
53 | assert(*(int *)heap_pop(heap) == 2);
54 | assert(*(int *)heap_pop(heap) == 3);
55 | heap_free(heap);
56 | }
57 |
58 | void case_heap_pop() {
59 | struct heap *heap = heap(heap_cmp);
60 | int a = 3, b = 1, c = 2, d = 4;
61 | assert(heap_push(heap, (void *)&a) == HEAP_OK);
62 | assert(heap_push(heap, (void *)&b) == HEAP_OK);
63 | assert(heap_push(heap, (void *)&c) == HEAP_OK);
64 | assert(heap_push(heap, (void *)&d) == HEAP_OK);
65 | assert(heap_len(heap) == 4);
66 | assert(*(int *)heap_pop(heap) == 1);
67 | assert(*(int *)heap_pop(heap) == 2);
68 | assert(*(int *)heap_pop(heap) == 3);
69 | assert(*(int *)heap_pop(heap) == 4);
70 | assert(heap_len(heap) == 0);
71 | heap_free(heap);
72 | }
73 |
74 | void case_heap_top() {
75 | struct heap *heap = heap(heap_cmp);
76 | int a = 3, b = 2, c = 4, d = 1;
77 | assert(heap_push(heap, (void *)&a) == HEAP_OK);
78 | assert(*(int *)(heap_top(heap)) == 3);
79 | assert(heap_push(heap, (void *)&b) == HEAP_OK);
80 | assert(*(int *)(heap_top(heap)) == 2);
81 | assert(heap_push(heap, (void *)&c) == HEAP_OK);
82 | assert(*(int *)(heap_top(heap)) == 2);
83 | assert(heap_push(heap, (void *)&d) == HEAP_OK);
84 | assert(*(int *)(heap_top(heap)) == 1);
85 | heap_free(heap);
86 | }
87 |
88 | void case_heap_pushpop() {
89 | struct heap *heap = heap(heap_cmp);
90 | int a = 3, b = 2, c = 4;
91 | assert(*(int *)heap_pushpop(heap, (void *)&a) == 3);
92 | assert(heap_push(heap, (void *)&b) == HEAP_OK);
93 | assert(heap_push(heap, (void *)&c) == HEAP_OK);
94 | assert(*(int *)heap_pushpop(heap, (void *)&a) == 2);
95 | heap_free(heap);
96 | }
97 |
98 | void case_heap_del() {
99 | struct heap *heap = heap(heap_cmp);
100 | int a = 3, b = 2, c = 5, d = 7, e = 4, f = 6, g = 1, h = 4;
101 | assert(heap_push(heap, (void *)&a) == HEAP_OK);
102 | assert(heap_push(heap, (void *)&b) == HEAP_OK);
103 | assert(heap_push(heap, (void *)&c) == HEAP_OK);
104 | assert(heap_push(heap, (void *)&d) == HEAP_OK);
105 | assert(heap_push(heap, (void *)&e) == HEAP_OK);
106 | assert(heap_push(heap, (void *)&f) == HEAP_OK);
107 | assert(heap_push(heap, (void *)&g) == HEAP_OK);
108 | assert(4 == *(int *)heap_del(heap, 4)); /* this assert means nothing */
109 | assert(heap_len(heap) == 6);
110 | assert(1 == *(int *)heap_pop(heap));
111 | assert(2 == *(int *)heap_pop(heap));
112 | assert(3 == *(int *)heap_pop(heap));
113 | assert(heap_push(heap, (void *)&h) == HEAP_OK);
114 | assert(4 == *(int *)heap_pop(heap));
115 | assert(5 == *(int *)heap_pop(heap));
116 | assert(6 == *(int *)heap_pop(heap));
117 | assert(7 == *(int *)heap_pop(heap));
118 | heap_free(heap);
119 | }
120 |
121 | void case_heap_repalce() {
122 | struct heap *heap = heap(heap_cmp);
123 | int a = 3, b = 2, c = 5, d = 7, e = 4, f = 6, g = 1, h = 4;
124 | assert(heap_push(heap, (void *)&a) == HEAP_OK);
125 | assert(heap_push(heap, (void *)&b) == HEAP_OK);
126 | assert(heap_push(heap, (void *)&c) == HEAP_OK);
127 | assert(heap_push(heap, (void *)&d) == HEAP_OK);
128 | assert(heap_push(heap, (void *)&e) == HEAP_OK);
129 | assert(heap_push(heap, (void *)&f) == HEAP_OK);
130 | assert(heap_push(heap, (void *)&g) == HEAP_OK);
131 | assert(1 == *(int *)heap_replace(heap, (void *)&h));
132 | assert(2 == *(int *)heap_pop(heap));
133 | assert(3 == *(int *)heap_pop(heap));
134 | assert(4 == *(int *)heap_pop(heap));
135 | heap_free(heap);
136 | }
137 |
--------------------------------------------------------------------------------
/test/ketama_test.c:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015, Chao Wang
3 | */
4 |
5 | #include
6 | #include
7 | #include
8 | #include
9 |
10 | #include "ketama.h"
11 | #include "strings.h"
12 |
13 | void case_ketama_balance() {
14 | struct ketama_node nodes[13] = {
15 | {"127.0.0.1:8000", 1},
16 | {"127.0.0.1:8001", 1},
17 | {"127.0.0.1:8002", 1},
18 | {"127.0.0.1:8003", 1},
19 | {"127.0.0.1:8004", 1},
20 | {"127.0.0.1:8005", 1},
21 | {"127.0.0.1:8006", 1},
22 | {"127.0.0.1:8007", 1},
23 | {"127.0.0.1:8008", 1},
24 | {"127.0.0.1:8009", 1},
25 | {"127.0.0.1:8010", 1},
26 | {"127.0.0.1:8011", 1},
27 | {"127.0.0.1:8012", 1},
28 | };
29 | struct ketama_ring *ring = ketama_ring_new(nodes, 13);
30 | assert(ring->nodes != NULL);
31 | assert(ring->len == 13 * 160);
32 |
33 | int i;
34 | for (i = 0; i < 2600; i++) {
35 | char key[11];
36 | strings_rand(key, 10);
37 | struct ketama_node *node = ketama_node_get(ring, key);
38 | nodes[node->idx].idata += 1;
39 | }
40 |
41 | for (i = 0; i < 13; i++)
42 | assert(nodes[i].idata > 150 && nodes[i].idata < 300);
43 |
44 | ketama_ring_free(ring);
45 | }
46 |
47 | void case_ketama_consistence() {
48 | /* consistence testing */
49 | struct ketama_node nodes[5] = {
50 | {"192.168.0.1:9527", 1},
51 | {"192.168.0.2:9527", 1},
52 | {"192.168.0.3:9527", 2},
53 | {"192.168.0.4:9527", 2},
54 | {"192.168.0.5:9527", 4},
55 | };
56 | struct ketama_ring *ring = ketama_ring_new(nodes, 5);
57 | assert(ring->len == (1 + 1 + 2 + 2 + 4) * 160);
58 | assert(ring->nodes != NULL);
59 |
60 | char key[11];
61 | srand(time(NULL));
62 | strings_rand(key, 10);
63 | struct ketama_node *node = ketama_node_get(ring, key);
64 | int i;
65 | for (i = 0; i < 1000; i++) {
66 | assert(strcmp(node->key, ketama_node_get(ring, key)->key) == 0);
67 | }
68 |
69 | ketama_ring_free(ring);
70 | }
71 |
--------------------------------------------------------------------------------
/test/list_test.c:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015, Chao Wang
3 | */
4 |
5 | #include
6 |
7 | #include "list.h"
8 |
9 | void case_list_clear() {
10 | struct list *list = list();
11 | char *s1 = "s1", *s2 = "s2", *s3 = "s3";
12 | assert(list_lpush(list, s1) == LIST_OK);
13 | assert(list_lpush(list, s2) == LIST_OK);
14 | assert(list_lpush(list, s3) == LIST_OK);
15 | assert(list_len(list) == 3);
16 | list_clear(list);
17 | assert(list_len(list) == 0);
18 | assert(list->head == NULL);
19 | assert(list->tail == NULL);
20 | list_free(list);
21 | }
22 |
23 | void case_list_lpush() {
24 | struct list *list = list();
25 | char *s1 = "s1", *s2 = "s2", *s3 = "s3";
26 | assert(list_lpush(list, s1) == LIST_OK);
27 | assert(list->head->data == s1);
28 | assert(list->tail->data == s1);
29 | assert(list_len(list) == 1);
30 | assert(list_lpush(list, s2) == LIST_OK);
31 | assert(list->head->data == s2);
32 | assert(list->tail->data == s1);
33 | assert(list_len(list) == 2);
34 | assert(list_lpush(list, s3) == LIST_OK);
35 | assert(list->head->data == s3);
36 | assert(list->tail->data == s1);
37 | assert(list_len(list) == 3);
38 | list_free(list);
39 | }
40 |
41 | void case_list_rpush() {
42 | struct list *list = list();
43 | char *s1 = "s1", *s2 = "s2", *s3 = "s3";
44 | assert(list_rpush(list, s1) == LIST_OK);
45 | assert(list->head->data == s1);
46 | assert(list->tail->data == s1);
47 | assert(list_len(list) == 1);
48 | assert(list_rpush(list, s2) == LIST_OK);
49 | assert(list->head->data == s1);
50 | assert(list->tail->data == s2);
51 | assert(list_len(list) == 2);
52 | assert(list_rpush(list, s3) == LIST_OK);
53 | assert(list->head->data == s1);
54 | assert(list->tail->data == s3);
55 | assert(list_len(list) == 3);
56 | list_free(list);
57 | }
58 |
59 | void case_list_lpop() {
60 | struct list *list = list();
61 | char *s1 = "s1", *s2 = "s2", *s3 = "s3";
62 | assert(list_rpush(list, s1) == LIST_OK);
63 | assert(list_rpush(list, s2) == LIST_OK);
64 | assert(list_rpush(list, s3) == LIST_OK);
65 | assert(list_len(list) == 3);
66 | assert(list->head->data == s1);
67 | assert(list_lpop(list) == s1);
68 | assert(list_len(list) == 2);
69 | assert(list->head->data == s2);
70 | assert(list_lpop(list) == s2);
71 | assert(list_len(list) == 1);
72 | assert(list->head->data == s3);
73 | assert(list_lpop(list) == s3);
74 | assert(list_len(list) == 0);
75 | assert(list->head == NULL);
76 | list_free(list);
77 | }
78 |
79 | void case_list_rpop() {
80 | struct list *list = list();
81 | char *s1 = "s1", *s2 = "s2", *s3 = "s3";
82 | assert(list_lpush(list, s1) == LIST_OK);
83 | assert(list_lpush(list, s2) == LIST_OK);
84 | assert(list_lpush(list, s3) == LIST_OK);
85 | assert(list_len(list) == 3);
86 | assert(list->tail->data == s1);
87 | assert(list_rpop(list) == s1);
88 | assert(list_len(list) == 2);
89 | assert(list->tail->data == s2);
90 | assert(list_rpop(list) == s2);
91 | assert(list_len(list) == 1);
92 | assert(list->tail->data == s3);
93 | assert(list_rpop(list) == s3);
94 | assert(list_len(list) == 0);
95 | assert(list->tail == NULL);
96 | list_free(list);
97 | }
98 |
99 | void case_list_iter() {
100 | struct list *list = list();
101 | char *s1 = "s1", *s2 = "s2", *s3 = "s3";
102 | list_push(list, s1);
103 | list_push(list, s2);
104 | list_push(list, s3);
105 | struct list_iter *iter = list_iter(list);
106 | assert(iter->list == list);
107 | assert(iter->node == list->head);
108 | assert(list_iter_next(iter) == s1);
109 | assert(list_iter_next(iter) == s2);
110 | assert(list_iter_next(iter) == s3);
111 | list_iter_seek_tail(iter);
112 | assert(list_iter_prev(iter) == s3);
113 | assert(list_iter_prev(iter) == s2);
114 | assert(list_iter_prev(iter) == s1);
115 | list_iter_free(iter);
116 | int i = 0;
117 | struct list_node *node;
118 | list_each(list, node) {
119 | char *s = node->data;
120 | assert(s[1] - 49 == i);
121 | i += 1;
122 | }
123 | assert(list_len(list) == i);
124 | list_free(list);
125 | }
126 |
--------------------------------------------------------------------------------
/test/log_test.c:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015, Chao Wang
3 | */
4 |
5 | #include
6 |
7 | #include "log.h"
8 |
9 | void case_log_open_close() {
10 | assert(log_open("test", NULL, 0) == LOG_OK);
11 | assert(log_open("test", "test.log", 0) == LOG_OK);
12 | assert(log_open("test", "test.log", 0) == LOG_OK);
13 | assert(log_open("test", "test.log", 1024) == LOG_OK);
14 | log_close();
15 | }
16 |
17 | void case_log_log() {
18 | assert(log_open("test", "test.log", 0) == LOG_OK);
19 | log_debug("test message debug");
20 | log_info("test message info");
21 | log_warn("test message warn");
22 | log_error("test message error");
23 | log_critical("test message critical");
24 | log_close();
25 | }
26 |
27 | void case_log_rotate() {
28 | assert(log_open("test", "test.log", 1024) == LOG_OK);
29 | int i;
30 |
31 | for (i = 0; i < 10; i++) log_info("test message");
32 | }
33 |
--------------------------------------------------------------------------------
/test/map_test.c:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015, Chao Wang
3 | */
4 |
5 | #include
6 | #include
7 |
8 | #include "map.h"
9 | #include "strings.h"
10 |
11 | void case_map_set() {
12 | struct map *m = map();
13 | char *key = "key", *val = "val";
14 | assert(map_set(m, key, val) == MAP_OK);
15 | assert(map_len(m) == 1);
16 | assert(map_get(m, key) == val);
17 | /* set multiple times */
18 | int i;
19 | for (i = 0; i < 10000; i++) {
20 | char key[11];
21 | char val[21];
22 | strings_rand(key, 10);
23 | strings_rand(val, 20);
24 | assert(map_set(m, key, val) == MAP_OK);
25 | assert(map_get(m, key) == val);
26 | }
27 | map_free(m);
28 | }
29 |
30 | void case_map_get() {
31 | struct map *m = map();
32 | char *key = "key", *val = "val";
33 | assert(map_set(m, key, val) == MAP_OK);
34 | assert(map_len(m) == 1);
35 | assert(map_get(m, key) == val);
36 | assert(map_get(m, "not exist") == NULL);
37 | map_free(m);
38 | }
39 |
40 | void case_map_pop() {
41 | struct map *m = map();
42 | char *key = "key", *val = "val";
43 | assert(map_set(m, key, val) == MAP_OK);
44 | assert(map_len(m) == 1);
45 | assert(map_pop(m, key) == val);
46 | assert(map_len(m) == 0);
47 | assert(map_pop(m, "not-exist") == NULL);
48 | map_free(m);
49 | }
50 |
51 | void case_map_has() {
52 | struct map *m = map();
53 | char *key = "key", *val = "val";
54 | assert(map_set(m, key, val) == MAP_OK);
55 | assert(!map_has(m, "not exist"));
56 | assert(map_has(m, key));
57 | map_free(m);
58 | }
59 |
60 | void case_map_clear() {
61 | struct map *m = map();
62 | assert(map_set(m, "key1", "val1") == MAP_OK);
63 | assert(map_set(m, "key2", "val2") == MAP_OK);
64 | assert(map_set(m, "key3", "val3") == MAP_OK);
65 | assert(map_set(m, "key4", "val4") == MAP_OK);
66 | assert(map_set(m, "key5", "val5") == MAP_OK);
67 | assert(map_len(m) == 5);
68 | map_clear(m);
69 | assert(map_len(m) == 0);
70 | map_free(m);
71 | }
72 |
73 | void case_map_iter() {
74 | struct map *m = map();
75 | char *key1 = "key1";
76 | char *key2 = "key2";
77 | char *key3 = "key3";
78 | char *key4 = "key4";
79 | char *key5 = "key5";
80 | char *key6 = "key6";
81 | assert(map_set(m, key1, "val1") == MAP_OK);
82 | assert(map_set(m, key2, "val2") == MAP_OK);
83 | assert(map_set(m, key3, "val3") == MAP_OK);
84 | assert(map_set(m, key4, "val4") == MAP_OK);
85 | assert(map_set(m, key5, "val5") == MAP_OK);
86 | assert(map_set(m, key6, "val6") == MAP_OK);
87 | struct map_iter *iter = map_iter(m);
88 | assert(map_iter_next(iter) != NULL);
89 | assert(map_iter_next(iter) != NULL);
90 | assert(map_iter_next(iter) != NULL);
91 | assert(map_iter_next(iter) != NULL);
92 | assert(map_iter_next(iter) != NULL);
93 | assert(map_iter_next(iter) != NULL);
94 | assert(map_iter_next(iter) == NULL);
95 | map_iter_free(iter);
96 | map_free(m);
97 | }
98 |
--------------------------------------------------------------------------------
/test/queue_test.c:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015, Chao Wang
3 | */
4 |
5 | #include
6 |
7 | #include "queue.h"
8 |
9 | void case_queue_clear() {
10 | struct queue *queue = queue();
11 | queue_push(queue, "a");
12 | queue_push(queue, "a");
13 | queue_clear(queue);
14 | assert(queue->head == NULL);
15 | assert(queue->tail == NULL);
16 | assert(queue_len(queue) == 0);
17 | queue_free(queue);
18 | }
19 |
20 | void case_queue_push_pop_top() {
21 | struct queue *queue = queue();
22 | char *s1 = "a", *s2 = "b", *s3 = "c";
23 | assert(queue_push(queue, s1) == QUEUE_OK);
24 | assert(queue_push(queue, s2) == QUEUE_OK);
25 | assert(queue_push(queue, s3) == QUEUE_OK);
26 | assert(queue_len(queue) == 3);
27 | assert(queue_top(queue) == s1);
28 | assert(queue_pop(queue) == s1);
29 | assert(queue_top(queue) == s2);
30 | assert(queue_pop(queue) == s2);
31 | assert(queue_top(queue) == s3);
32 | assert(queue_pop(queue) == s3);
33 | assert(queue_len(queue) == 0);
34 | queue_free(queue);
35 | }
36 |
--------------------------------------------------------------------------------
/test/skiplist_test.c:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015, Chao Wang
3 | */
4 |
5 | #include
6 |
7 | #include "skiplist.h"
8 |
9 | void case_skiplist_base() {
10 | struct skiplist *skiplist = skiplist(NULL);
11 | assert(skiplist != NULL);
12 | assert(skiplist->len == 0);
13 | assert(skiplist->head != NULL);
14 | assert(skiplist->tail == skiplist->head);
15 | assert(skiplist->level == 1);
16 | assert(skiplist_push(skiplist, 2, NULL) == SKIPLIST_OK);
17 | assert(skiplist_push(skiplist, 1, NULL) == SKIPLIST_OK);
18 | assert(skiplist_push(skiplist, 3, NULL) == SKIPLIST_OK);
19 | assert(skiplist_len(skiplist) == 3);
20 | assert(skiplist_level(skiplist) <= SKIPLIST_LEVEL_MAX);
21 | assert(skiplist->tail->score == 3);
22 | skiplist_clear(skiplist);
23 | assert(skiplist_level(skiplist) == 1);
24 | assert(skiplist_len(skiplist) == 0);
25 | assert(skiplist->head != NULL);
26 | assert(skiplist->tail == skiplist->head);
27 | skiplist_free(skiplist);
28 | }
29 |
30 | void case_skiplist_push() {
31 | struct skiplist *skiplist = skiplist(NULL);
32 | struct skiplist_iter *iter = skiplist_iter(skiplist);
33 | assert(skiplist != NULL && iter != NULL);
34 | assert(skiplist_push(skiplist, 3, NULL) == SKIPLIST_OK);
35 | assert(skiplist_push(skiplist, 9, NULL) == SKIPLIST_OK);
36 | assert(skiplist_push(skiplist, 7, NULL) == SKIPLIST_OK);
37 | assert(skiplist_push(skiplist, 2, NULL) == SKIPLIST_OK);
38 | assert(skiplist_push(skiplist, 6, NULL) == SKIPLIST_OK);
39 | assert(skiplist_push(skiplist, 5, NULL) == SKIPLIST_OK);
40 | assert(skiplist_push(skiplist, 8, NULL) == SKIPLIST_OK);
41 | assert(skiplist_push(skiplist, 1, NULL) == SKIPLIST_OK);
42 | assert(skiplist_push(skiplist, 4, NULL) == SKIPLIST_OK);
43 | assert(skiplist_len(skiplist) == 9);
44 | assert(skiplist_level(skiplist) > 0);
45 | assert(skiplist_iter_next(iter)->score == 1);
46 | assert(skiplist_iter_next(iter)->score == 2);
47 | assert(skiplist_iter_next(iter)->score == 3);
48 | assert(skiplist_iter_next(iter)->score == 4);
49 | assert(skiplist_iter_next(iter)->score == 5);
50 | assert(skiplist_iter_next(iter)->score == 6);
51 | assert(skiplist_iter_next(iter)->score == 7);
52 | assert(skiplist_iter_next(iter)->score == 8);
53 | assert(skiplist_iter_next(iter)->score == 9);
54 | assert(skiplist_first(skiplist)->score == 1);
55 | assert(skiplist_last(skiplist)->score == 9);
56 | skiplist_iter_rewind(iter);
57 | struct skiplist_node *first = skiplist_iter_next(iter);
58 | struct skiplist_node *second = skiplist_iter_next(iter);
59 | struct skiplist_node *last = skiplist_last(skiplist);
60 | assert(skiplist->head->forwards[0] == first);
61 | assert(first != skiplist->head);
62 | assert(first->forwards[0] == second);
63 | assert(second->backward == first);
64 | assert(first->backward == skiplist->head);
65 | assert(last->backward != NULL);
66 | assert(last->forwards[0] == NULL);
67 | skiplist_iter_free(iter);
68 | skiplist_free(skiplist);
69 | }
70 |
71 | void case_skiplist_pop() {
72 | struct skiplist *skiplist = skiplist(NULL);
73 | struct skiplist_iter *iter = skiplist_iter(skiplist);
74 | assert(skiplist != NULL && iter != NULL);
75 | int v1 = 1, v2 = 2, v3 = 3, v4 = 4, v5 = 5, v6 = 6, v7 = 7, v8 = 8, v9 = 9;
76 | assert(skiplist_push(skiplist, 3, (void *)(&v3)) == SKIPLIST_OK);
77 | assert(skiplist_push(skiplist, 9, (void *)(&v9)) == SKIPLIST_OK);
78 | assert(skiplist_push(skiplist, 7, (void *)(&v7)) == SKIPLIST_OK);
79 | assert(skiplist_push(skiplist, 2, (void *)(&v2)) == SKIPLIST_OK);
80 | assert(skiplist_push(skiplist, 6, (void *)(&v6)) == SKIPLIST_OK);
81 | assert(skiplist_push(skiplist, 5, (void *)(&v5)) == SKIPLIST_OK);
82 | assert(skiplist_push(skiplist, 8, (void *)(&v8)) == SKIPLIST_OK);
83 | assert(skiplist_push(skiplist, 1, (void *)(&v1)) == SKIPLIST_OK);
84 | assert(skiplist_push(skiplist, 4, (void *)(&v4)) == SKIPLIST_OK);
85 | assert(skiplist_len(skiplist) == 9);
86 | assert(skiplist_level(skiplist) > 0);
87 | assert(skiplist_last(skiplist)->score == 9);
88 | assert(skiplist_pop(skiplist, 3) == &v3);
89 | assert(skiplist_pop(skiplist, 4) == &v4);
90 | assert(skiplist_pop(skiplist, 9) == &v9);
91 | assert(skiplist_pop(skiplist, 1) == &v1);
92 | assert(skiplist_len(skiplist) == 5);
93 | assert(skiplist_first(skiplist)->score == 2);
94 | assert(skiplist->head->forwards[skiplist->level - 1] != NULL);
95 | skiplist_iter_free(iter);
96 | skiplist_free(skiplist);
97 | }
98 |
99 | void case_skiplist_popfirst() {
100 | struct skiplist *skiplist = skiplist(NULL);
101 | struct skiplist_iter *iter = skiplist_iter(skiplist);
102 | assert(skiplist != NULL && iter != NULL);
103 | int v1 = 1, v2 = 2, v3 = 3, v4 = 4, v5 = 5, v6 = 6, v7 = 7, v8 = 8, v9 = 9;
104 | assert(skiplist_push(skiplist, 3, (void *)(&v3)) == SKIPLIST_OK);
105 | assert(skiplist_push(skiplist, 9, (void *)(&v9)) == SKIPLIST_OK);
106 | assert(skiplist_push(skiplist, 7, (void *)(&v7)) == SKIPLIST_OK);
107 | assert(skiplist_push(skiplist, 2, (void *)(&v2)) == SKIPLIST_OK);
108 | assert(skiplist_push(skiplist, 6, (void *)(&v6)) == SKIPLIST_OK);
109 | assert(skiplist_push(skiplist, 5, (void *)(&v5)) == SKIPLIST_OK);
110 | assert(skiplist_push(skiplist, 8, (void *)(&v8)) == SKIPLIST_OK);
111 | assert(skiplist_push(skiplist, 1, (void *)(&v1)) == SKIPLIST_OK);
112 | assert(skiplist_push(skiplist, 4, (void *)(&v4)) == SKIPLIST_OK);
113 | assert(skiplist_len(skiplist) == 9);
114 | assert(skiplist_level(skiplist) > 0);
115 | assert(skiplist_popfirst(skiplist) == &v1);
116 | assert(skiplist_popfirst(skiplist) == &v2);
117 | assert(skiplist_popfirst(skiplist) == &v3);
118 | assert(skiplist_popfirst(skiplist) == &v4);
119 | assert(skiplist_len(skiplist) == 5);
120 | assert(skiplist_level(skiplist) > 0);
121 | assert(skiplist->head->forwards[skiplist->level - 1] != NULL);
122 | struct skiplist_node *first = skiplist_iter_next(iter);
123 | struct skiplist_node *second = skiplist_iter_next(iter);
124 | assert(first->score == 5);
125 | assert(second->score == 6);
126 | assert(first->backward == skiplist->head);
127 | assert(first->forwards[0] == second);
128 | assert(second->backward == first);
129 | assert(skiplist->tail != first && skiplist->tail != second);
130 | assert(skiplist_popfirst(skiplist) == &v5);
131 | assert(skiplist_popfirst(skiplist) == &v6);
132 | assert(skiplist_popfirst(skiplist) == &v7);
133 | assert(skiplist_popfirst(skiplist) == &v8);
134 | assert(skiplist_last(skiplist)->score == 9);
135 | assert(skiplist_popfirst(skiplist) == &v9);
136 | assert(skiplist_last(skiplist) == NULL);
137 | assert(skiplist_level(skiplist) == 1);
138 | assert(skiplist_len(skiplist) == 0);
139 | skiplist_iter_free(iter);
140 | skiplist_free(skiplist);
141 | }
142 |
143 | void case_skiplist_poplast() {
144 | struct skiplist *skiplist = skiplist(NULL);
145 | struct skiplist_iter *iter = skiplist_iter(skiplist);
146 | assert(skiplist != NULL && iter != NULL);
147 | int v1 = 1, v2 = 2, v3 = 3, v4 = 4, v5 = 5, v6 = 6, v7 = 7, v8 = 8, v9 = 9;
148 | assert(skiplist_push(skiplist, 3, (void *)(&v3)) == SKIPLIST_OK);
149 | assert(skiplist_push(skiplist, 9, (void *)(&v9)) == SKIPLIST_OK);
150 | assert(skiplist_push(skiplist, 7, (void *)(&v7)) == SKIPLIST_OK);
151 | assert(skiplist_push(skiplist, 2, (void *)(&v2)) == SKIPLIST_OK);
152 | assert(skiplist_push(skiplist, 6, (void *)(&v6)) == SKIPLIST_OK);
153 | assert(skiplist_push(skiplist, 5, (void *)(&v5)) == SKIPLIST_OK);
154 | assert(skiplist_push(skiplist, 8, (void *)(&v8)) == SKIPLIST_OK);
155 | assert(skiplist_push(skiplist, 1, (void *)(&v1)) == SKIPLIST_OK);
156 | assert(skiplist_push(skiplist, 4, (void *)(&v4)) == SKIPLIST_OK);
157 | assert(skiplist_len(skiplist) == 9);
158 | assert(skiplist_level(skiplist) > 0);
159 | assert(skiplist_poplast(skiplist) == &v9);
160 | assert(skiplist_poplast(skiplist) == &v8);
161 | assert(skiplist_poplast(skiplist) == &v7);
162 | assert(skiplist_poplast(skiplist) == &v6);
163 | assert(skiplist_poplast(skiplist) == &v5);
164 | assert(skiplist_last(skiplist)->score == 4);
165 | assert(skiplist_first(skiplist)->score == 1);
166 | assert(skiplist->tail->score == 4);
167 | assert(skiplist->tail->backward->score == 3);
168 | assert(skiplist->tail->backward->backward->score == 2);
169 | assert(skiplist->head->forwards[skiplist->level - 1] != NULL);
170 | skiplist_iter_free(iter);
171 | skiplist_free(skiplist);
172 | }
173 |
174 | void case_skiplist_get() {
175 | struct skiplist *skiplist = skiplist(NULL);
176 | int v1 = 1, v2 = 2, v3 = 3, v4 = 4, v5 = 5, v6 = 6, v7 = 7, v8 = 8, v9 = 9;
177 | assert(skiplist_push(skiplist, 3, (void *)(&v3)) == SKIPLIST_OK);
178 | assert(skiplist_push(skiplist, 9, (void *)(&v9)) == SKIPLIST_OK);
179 | assert(skiplist_push(skiplist, 7, (void *)(&v7)) == SKIPLIST_OK);
180 | assert(skiplist_push(skiplist, 2, (void *)(&v2)) == SKIPLIST_OK);
181 | assert(skiplist_push(skiplist, 6, (void *)(&v6)) == SKIPLIST_OK);
182 | assert(skiplist_push(skiplist, 5, (void *)(&v5)) == SKIPLIST_OK);
183 | assert(skiplist_push(skiplist, 8, (void *)(&v8)) == SKIPLIST_OK);
184 | assert(skiplist_push(skiplist, 1, (void *)(&v1)) == SKIPLIST_OK);
185 | assert(skiplist_push(skiplist, 4, (void *)(&v4)) == SKIPLIST_OK);
186 | assert(skiplist_len(skiplist) == 9);
187 | assert(skiplist_get(skiplist, 8) == &v8);
188 | assert(skiplist_get(skiplist, 9) == &v9);
189 | assert(skiplist_get(skiplist, 1) == &v1);
190 | assert(skiplist_get(skiplist, 2) == &v2);
191 | assert(skiplist_get(skiplist, 10) == NULL);
192 | assert(skiplist_get(skiplist, 9999) == NULL);
193 | skiplist_free(skiplist);
194 | }
195 |
--------------------------------------------------------------------------------
/test/stack_test.c:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015, Chao Wang
3 | */
4 |
5 | #include
6 |
7 | #include "stack.h"
8 |
9 | void case_stack_clear() {
10 | struct stack *stack = stack(5);
11 | stack_push(stack, "hello");
12 | stack_clear(stack);
13 | assert(stack->data == NULL);
14 | assert(stack_len(stack) == 0);
15 | assert(stack_cap(stack) == 0);
16 | stack_free(stack);
17 | }
18 |
19 | void case_stack_push() {
20 | struct stack *stack = stack(1);
21 | char *s1 = "a", *s2 = "b";
22 | assert(stack_push(stack, s1) == STACK_OK);
23 | assert(stack_push(stack, s2) == STACK_OK);
24 | assert(stack_len(stack) == 2);
25 | assert(stack_cap(stack) == 2);
26 | assert(stack_pop(stack) == s2);
27 | assert(stack_len(stack) == 1);
28 | assert(stack_cap(stack) == 2);
29 | assert(stack_pop(stack) == s1);
30 | stack_free(stack);
31 | }
32 |
33 | void case_stack_pop() {
34 | struct stack *stack = stack(3);
35 | char *s1 = "a", *s2 = "b";
36 | assert(stack_push(stack, s1) == STACK_OK);
37 | assert(stack_push(stack, s2) == STACK_OK);
38 | assert(stack_len(stack) == 2);
39 | assert(stack_cap(stack) == 3);
40 | assert(stack_pop(stack) == s2);
41 | assert(stack_pop(stack) == s1);
42 | assert(stack_len(stack) == 0);
43 | assert(stack_cap(stack) == 3);
44 | stack_free(stack);
45 | }
46 |
47 | void case_stack_top() {
48 | struct stack *stack = stack(3);
49 | char *s1 = "a", *s2 = "b", *s3 = "c";
50 | assert(stack_push(stack, s1) == STACK_OK);
51 | assert(stack_top(stack) == s1);
52 | assert(stack_push(stack, s2) == STACK_OK);
53 | assert(stack_top(stack) == s2);
54 | assert(stack_push(stack, s3) == STACK_OK);
55 | assert(stack_top(stack) == s3);
56 | assert(stack_len(stack) == 3);
57 | assert(stack_cap(stack) == 3);
58 | stack_free(stack);
59 | }
60 |
--------------------------------------------------------------------------------
/test/strings_test.c:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015, Chao Wang
3 | */
4 |
5 | #include
6 | #include
7 |
8 | #include "strings.h"
9 |
10 | void case_strings_search() {
11 | char s1[] = "this is a simple example";
12 | assert(strings_search(s1, "this", 0) == 0);
13 | assert(strings_search(s1, "is", 0) == 2);
14 | assert(strings_search(s1, "is", 3) == 5);
15 | assert(strings_search(s1, "mp", 0) == 12);
16 | assert(strings_search(s1, "mp", 13) == 20);
17 | assert(strings_search(s1, "not exist", 0) == strlen(s1));
18 |
19 | char s2[] = "这是中文是的";
20 | assert(strings_search(s2, "这是", 0) == 0);
21 | assert(strings_search(s2, "中文", 0) == 6);
22 | assert(strings_search(s2, "是", 0) == 3);
23 | assert(strings_search(s2, "是", 6) == 12);
24 | }
25 |
26 | void case_strings_rand() {
27 | /* we are going to assert n times random strings (with length 16)
28 | * are not the same with each other */
29 | int n = 100;
30 | char strings[n][17]; /* because 2d array are continuously on
31 | memory, so we use 16+1 */
32 | int i, j;
33 |
34 | for (i = 0; i < n; i++) {
35 | strings_rand(strings[i], 16);
36 | for (j = 0; j < i; j++) assert(strcmp(strings[i], strings[j]) != 0);
37 | }
38 | }
39 |
40 | void case_strings_replace() {
41 | char *src = "abcdbcefghbcio";
42 | char *sub = "bc";
43 | char *rep = "xyz";
44 | char dst[30] = {0};
45 | assert(strings_replace(dst, src, sub, rep) == dst);
46 | assert(strcmp(dst, "axyzdxyzefghxyzio") == 0);
47 | }
48 |
--------------------------------------------------------------------------------
/test/test.c:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015, Chao Wang
3 | */
4 |
5 | #ifdef __linux
6 | #include
7 | #endif
8 |
9 | #include "test.h"
10 |
11 | /**
12 | * buf_test
13 | */
14 | void case_buf_clear();
15 | void case_buf_put();
16 | void case_buf_puts();
17 | void case_buf_putc();
18 | void case_buf_str();
19 | void case_buf_isempty();
20 | void case_buf_sprintf();
21 | void case_buf_lrm();
22 | void case_buf_len();
23 | void case_buf_cap();
24 | static struct test_case buf_test_cases[] = {
25 | {"buf_clear", &case_buf_clear},
26 | {"buf_put", &case_buf_put},
27 | {"buf_puts", &case_buf_puts},
28 | {"buf_putc", &case_buf_putc},
29 | {"buf_str", &case_buf_str},
30 | {"buf_isempty", &case_buf_isempty},
31 | {"buf_sprintf", &case_buf_sprintf},
32 | {"buf_lrm", &case_buf_lrm},
33 | {"buf_len", &case_buf_len},
34 | {"buf_cap", &case_buf_cap},
35 | {NULL, NULL},
36 | };
37 |
38 | /**
39 | * cfg_test
40 | */
41 | void case_cfg_get();
42 | static struct test_case cfg_test_cases[] = {
43 | {"cfg_get", &case_cfg_get}, {NULL, NULL},
44 | };
45 |
46 | /**
47 | * datetime_test
48 | */
49 | void case_datetime_stamp_now();
50 | static struct test_case datetime_test_cases[] = {
51 | {"datetime_stamp_now", &case_datetime_stamp_now}, {NULL, NULL},
52 | };
53 |
54 | /**
55 | * dict_test
56 | */
57 | void case_dict_set();
58 | void case_dict_get();
59 | void case_dict_pop();
60 | void case_dict_has();
61 | void case_dict_clear();
62 | void case_dict_resize();
63 | void case_dict_iter();
64 | static struct test_case dict_test_cases[] = {
65 | {"dict_set", &case_dict_set},
66 | {"dict_get", &case_dict_get},
67 | {"dict_pop", &case_dict_pop},
68 | {"dict_has", &case_dict_has},
69 | {"dict_clear", &case_dict_clear},
70 | {"dict_resize", &case_dict_resize},
71 | {"dict_iter", &case_dict_iter},
72 | {NULL, NULL},
73 | };
74 |
75 | /**
76 | * event_test
77 | */
78 | void case_event_simple();
79 | static struct test_case event_test_cases[] = {
80 | {"event_simple", &case_event_simple}, {NULL, NULL},
81 | };
82 |
83 | /**
84 | * heap_test
85 | */
86 | void case_heap_clear();
87 | void case_heap_len();
88 | void case_heap_cap();
89 | void case_heap_push();
90 | void case_heap_pop();
91 | void case_heap_top();
92 | void case_heap_pushpop();
93 | void case_heap_del();
94 | void case_heap_repalce();
95 | static struct test_case heap_test_cases[] = {
96 | {"heap_clear", &case_heap_clear},
97 | {"heap_len", &case_heap_len},
98 | {"heap_cap", &case_heap_cap},
99 | {"heap_push", &case_heap_push},
100 | {"heap_pop", &case_heap_pop},
101 | {"heap_top", &case_heap_top},
102 | {"heap_pushpop", &case_heap_pushpop},
103 | {"heap_del", &case_heap_del},
104 | {"heap_replace", &case_heap_repalce},
105 | {NULL, NULL},
106 | };
107 |
108 | /**
109 | * ketama_test
110 | */
111 | void case_ketama_balance();
112 | void case_ketama_consistence();
113 | static struct test_case ketama_test_cases[] = {
114 | {"ketama_balance", &case_ketama_balance},
115 | {"ketama_consistence", &case_ketama_consistence},
116 | {NULL, NULL},
117 | };
118 |
119 | /**
120 | * list_test
121 | */
122 | void case_list_clear();
123 | void case_list_lpush();
124 | void case_list_rpush();
125 | void case_list_lpop();
126 | void case_list_rpop();
127 | void case_list_iter();
128 | static struct test_case list_test_cases[] = {
129 | {"list_clear", &case_list_clear},
130 | {"list_lpush", &case_list_lpush},
131 | {"list_rpush", &case_list_rpush},
132 | {"list_lpop", &case_list_lpop},
133 | {"list_rpop", &case_list_rpop},
134 | {"list_iter", &case_list_iter},
135 | {NULL, NULL},
136 | };
137 |
138 | /**
139 | * log_test
140 | */
141 | void case_log_open_close();
142 | void case_log_log();
143 | void case_log_rotate();
144 | static struct test_case log_test_cases[] = {
145 | {"log_open_close", &case_log_open_close},
146 | {"log_log", &case_log_log},
147 | {"log_rotate", &case_log_rotate},
148 | {NULL, NULL},
149 | };
150 |
151 | /**
152 | * map_test
153 | */
154 | void case_map_set();
155 | void case_map_get();
156 | void case_map_pop();
157 | void case_map_has();
158 | void case_map_clear();
159 | void case_map_iter();
160 | static struct test_case map_test_cases[] = {
161 | {"map_set", &case_map_set},
162 | {"map_get", &case_map_get},
163 | {"map_pop", &case_map_pop},
164 | {"map_has", &case_map_has},
165 | {"map_clear", &case_map_clear},
166 | {"map_iter", &case_map_iter},
167 | {NULL, NULL},
168 | };
169 |
170 | /**
171 | * queue_test
172 | */
173 | void case_queue_clear();
174 | void case_queue_push_pop_top();
175 | static struct test_case queue_test_cases[] = {
176 | {"queue_clear", &case_queue_clear},
177 | {"queue_push_pop_top", &case_queue_push_pop_top},
178 | {NULL, NULL},
179 | };
180 |
181 | /**
182 | * skiplist_test
183 | */
184 | void case_skiplist_base();
185 | void case_skiplist_push();
186 | void case_skiplist_pop();
187 | void case_skiplist_popfirst();
188 | void case_skiplist_poplast();
189 | void case_skiplist_get();
190 | static struct test_case skiplist_test_cases[] = {
191 | {"skiplist_base", &case_skiplist_base},
192 | {"skiplist_push", &case_skiplist_push},
193 | {"skiplist_pop", &case_skiplist_pop},
194 | {"skiplist_popfirst", &case_skiplist_popfirst},
195 | {"skiplist_poplast", &case_skiplist_poplast},
196 | {"skiplist_get", &case_skiplist_get},
197 | {NULL, NULL},
198 | };
199 |
200 | /**
201 | * stack_test
202 | */
203 | void case_stack_clear();
204 | void case_stack_push();
205 | void case_stack_pop();
206 | void case_stack_top();
207 | static struct test_case stack_test_cases[] = {
208 | {"stack_clear", &case_stack_clear},
209 | {"stack_push", &case_stack_push},
210 | {"stack_pop", &case_stack_pop},
211 | {"stack_top", &case_stack_top},
212 | {NULL, NULL},
213 | };
214 |
215 | /**
216 | * strings_test
217 | */
218 | void case_strings_search();
219 | void case_strings_rand();
220 | void case_strings_replace();
221 | static struct test_case strings_test_cases[] = {
222 | {"strings_search", &case_strings_search},
223 | {"strings_rand", &case_strings_rand},
224 | {"strings_replace", &case_strings_replace},
225 | {NULL, NULL},
226 | };
227 |
228 | /**
229 | * utils_test
230 | */
231 | void case_utils_min();
232 | void case_utils_max();
233 | static struct test_case utils_test_cases[] = {
234 | {"utils_min", &case_utils_min},
235 | {"utils_max", &case_utils_max},
236 | {NULL, NULL},
237 | };
238 |
239 | static void run_cases(const char *name, struct test_case cases[]) {
240 | int idx = 0;
241 |
242 | while (1) {
243 | struct test_case c = cases[idx];
244 | if (c.name == NULL || c.fn == NULL) break;
245 | double start_at = datetime_stamp_now();
246 | (c.fn)();
247 | double end_at = datetime_stamp_now();
248 | idx += 1;
249 | fprintf(stderr, "ok\t%-27s %-27s %17.3fµs\n", name, c.name,
250 | 1000.0 * (end_at - start_at));
251 | }
252 | }
253 |
254 | int main(int argc, const char *argv[]) {
255 | #ifdef __linux
256 | mtrace();
257 | #endif
258 | run_cases("buf_test", buf_test_cases);
259 | run_cases("cfg_test", cfg_test_cases);
260 | run_cases("datetime_test", datetime_test_cases);
261 | run_cases("dict_test", dict_test_cases);
262 | run_cases("event_test", event_test_cases);
263 | run_cases("heap_test", heap_test_cases);
264 | run_cases("ketama_test", ketama_test_cases);
265 | run_cases("list_test", list_test_cases);
266 | run_cases("log_test", log_test_cases);
267 | run_cases("map_test", map_test_cases);
268 | run_cases("queue_test", queue_test_cases);
269 | run_cases("skiplist_test", skiplist_test_cases);
270 | run_cases("stack_test", stack_test_cases);
271 | run_cases("strings_test", strings_test_cases);
272 | run_cases("utils_test", utils_test_cases);
273 | return 0;
274 | }
275 |
--------------------------------------------------------------------------------
/test/test.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015, Chao Wang
3 | */
4 |
5 | #include
6 | #include
7 |
8 | #include "datetime.h"
9 |
10 | struct test_case {
11 | const char *name; /* test case name */
12 | void (*fn)(); /* test case function */
13 | };
14 |
15 | static void run_cases(const char *name, struct test_case cases[]);
16 |
--------------------------------------------------------------------------------
/test/utils_test.c:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015, Chao Wang
3 | */
4 |
5 | #include
6 | #include
7 |
8 | #include "utils.h"
9 |
10 | void case_utils_min() {
11 | assert(MIN(1, 3) == 1);
12 | assert(MIN(1, -3) == -3);
13 | }
14 |
15 | void case_utils_max() {
16 | assert(MAX(1, 3) == 3);
17 | assert(MAX(1, -3) == 1);
18 | }
19 |
--------------------------------------------------------------------------------