1 | // This is an open source non-commercial project. Dear PVS-Studio, please check |
2 | // it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com |
3 | |
4 | // |
5 | // map.c: khash.h wrapper |
6 | // |
7 | // NOTE: Callers must manage memory (allocate) for keys and values. |
8 | // khash.h does not make its own copy of the key or value. |
9 | // |
10 | |
11 | #include <stdlib.h> |
12 | #include <stdbool.h> |
13 | #include <string.h> |
14 | |
15 | #include "nvim/map.h" |
16 | #include "nvim/map_defs.h" |
17 | #include "nvim/vim.h" |
18 | #include "nvim/memory.h" |
19 | #include "nvim/api/private/dispatch.h" |
20 | |
21 | #include "nvim/lib/khash.h" |
22 | |
23 | #define cstr_t_hash kh_str_hash_func |
24 | #define cstr_t_eq kh_str_hash_equal |
25 | #define uint64_t_hash kh_int64_hash_func |
26 | #define uint64_t_eq kh_int64_hash_equal |
27 | #define uint32_t_hash kh_int_hash_func |
28 | #define uint32_t_eq kh_int_hash_equal |
29 | #define int_hash kh_int_hash_func |
30 | #define int_eq kh_int_hash_equal |
31 | #define linenr_T_hash kh_int_hash_func |
32 | #define linenr_T_eq kh_int_hash_equal |
33 | #define handle_T_hash kh_int_hash_func |
34 | #define handle_T_eq kh_int_hash_equal |
35 | |
36 | |
37 | #if defined(ARCH_64) |
38 | #define ptr_t_hash(key) uint64_t_hash((uint64_t)key) |
39 | #define ptr_t_eq(a, b) uint64_t_eq((uint64_t)a, (uint64_t)b) |
40 | #elif defined(ARCH_32) |
41 | #define ptr_t_hash(key) uint32_t_hash((uint32_t)key) |
42 | #define ptr_t_eq(a, b) uint32_t_eq((uint32_t)a, (uint32_t)b) |
43 | #endif |
44 | |
45 | #define INITIALIZER(T, U) T##_##U##_initializer |
46 | #define INITIALIZER_DECLARE(T, U, ...) const U INITIALIZER(T, U) = __VA_ARGS__ |
47 | #define DEFAULT_INITIALIZER {0} |
48 | |
49 | #define MAP_IMPL(T, U, ...) \ |
50 | INITIALIZER_DECLARE(T, U, __VA_ARGS__); \ |
51 | __KHASH_IMPL(T##_##U##_map,, T, U, 1, T##_hash, T##_eq) \ |
52 | \ |
53 | Map(T, U) *map_##T##_##U##_new() \ |
54 | { \ |
55 | Map(T, U) *rv = xmalloc(sizeof(Map(T, U))); \ |
56 | rv->table = kh_init(T##_##U##_map); \ |
57 | return rv; \ |
58 | } \ |
59 | \ |
60 | void map_##T##_##U##_free(Map(T, U) *map) \ |
61 | { \ |
62 | kh_destroy(T##_##U##_map, map->table); \ |
63 | xfree(map); \ |
64 | } \ |
65 | \ |
66 | U map_##T##_##U##_get(Map(T, U) *map, T key) \ |
67 | { \ |
68 | khiter_t k; \ |
69 | \ |
70 | if ((k = kh_get(T##_##U##_map, map->table, key)) == kh_end(map->table)) { \ |
71 | return INITIALIZER(T, U); \ |
72 | } \ |
73 | \ |
74 | return kh_val(map->table, k); \ |
75 | } \ |
76 | \ |
77 | bool map_##T##_##U##_has(Map(T, U) *map, T key) \ |
78 | { \ |
79 | return kh_get(T##_##U##_map, map->table, key) != kh_end(map->table); \ |
80 | } \ |
81 | \ |
82 | T map_##T##_##U##_key(Map(T, U) *map, T key) \ |
83 | { \ |
84 | khiter_t k; \ |
85 | \ |
86 | if ((k = kh_get(T##_##U##_map, map->table, key)) == kh_end(map->table)) { \ |
87 | abort(); /* Caller must check map_has(). */ \ |
88 | } \ |
89 | \ |
90 | return kh_key(map->table, k); \ |
91 | } \ |
92 | U map_##T##_##U##_put(Map(T, U) *map, T key, U value) \ |
93 | { \ |
94 | int ret; \ |
95 | U rv = INITIALIZER(T, U); \ |
96 | khiter_t k = kh_put(T##_##U##_map, map->table, key, &ret); \ |
97 | \ |
98 | if (!ret) { \ |
99 | rv = kh_val(map->table, k); \ |
100 | } \ |
101 | \ |
102 | kh_val(map->table, k) = value; \ |
103 | return rv; \ |
104 | } \ |
105 | \ |
106 | U *map_##T##_##U##_ref(Map(T, U) *map, T key, bool put) \ |
107 | { \ |
108 | int ret; \ |
109 | khiter_t k; \ |
110 | if (put) { \ |
111 | k = kh_put(T##_##U##_map, map->table, key, &ret); \ |
112 | if (ret) { \ |
113 | kh_val(map->table, k) = INITIALIZER(T, U); \ |
114 | } \ |
115 | } else { \ |
116 | k = kh_get(T##_##U##_map, map->table, key); \ |
117 | if (k == kh_end(map->table)) { \ |
118 | return NULL; \ |
119 | } \ |
120 | } \ |
121 | \ |
122 | return &kh_val(map->table, k); \ |
123 | } \ |
124 | \ |
125 | U map_##T##_##U##_del(Map(T, U) *map, T key) \ |
126 | { \ |
127 | U rv = INITIALIZER(T, U); \ |
128 | khiter_t k; \ |
129 | \ |
130 | if ((k = kh_get(T##_##U##_map, map->table, key)) != kh_end(map->table)) { \ |
131 | rv = kh_val(map->table, k); \ |
132 | kh_del(T##_##U##_map, map->table, k); \ |
133 | } \ |
134 | \ |
135 | return rv; \ |
136 | } \ |
137 | \ |
138 | void map_##T##_##U##_clear(Map(T, U) *map) \ |
139 | { \ |
140 | kh_clear(T##_##U##_map, map->table); \ |
141 | } |
142 | |
143 | static inline khint_t String_hash(String s) |
144 | { |
145 | khint_t h = 0; |
146 | for (size_t i = 0; i < s.size && s.data[i]; i++) { |
147 | h = (h << 5) - h + (uint8_t)s.data[i]; |
148 | } |
149 | return h; |
150 | } |
151 | |
152 | static inline bool String_eq(String a, String b) |
153 | { |
154 | if (a.size != b.size) { |
155 | return false; |
156 | } |
157 | return memcmp(a.data, b.data, a.size) == 0; |
158 | } |
159 | |
160 | static inline khint_t HlEntry_hash(HlEntry ae) |
161 | { |
162 | const uint8_t *data = (const uint8_t *)&ae; |
163 | khint_t h = 0; |
164 | for (size_t i = 0; i < sizeof(ae); i++) { |
165 | h = (h << 5) - h + data[i]; |
166 | } |
167 | return h; |
168 | } |
169 | |
170 | static inline bool HlEntry_eq(HlEntry ae1, HlEntry ae2) |
171 | { |
172 | return memcmp(&ae1, &ae2, sizeof(ae1)) == 0; |
173 | } |
174 | |
175 | |
176 | |
177 | MAP_IMPL(int, int, DEFAULT_INITIALIZER) |
178 | MAP_IMPL(cstr_t, ptr_t, DEFAULT_INITIALIZER) |
179 | MAP_IMPL(ptr_t, ptr_t, DEFAULT_INITIALIZER) |
180 | MAP_IMPL(uint64_t, ptr_t, DEFAULT_INITIALIZER) |
181 | MAP_IMPL(handle_T, ptr_t, DEFAULT_INITIALIZER) |
182 | #define MSGPACK_HANDLER_INITIALIZER { .fn = NULL, .fast = false } |
183 | MAP_IMPL(String, MsgpackRpcRequestHandler, MSGPACK_HANDLER_INITIALIZER) |
184 | #define KVEC_INITIALIZER { .size = 0, .capacity = 0, .items = NULL } |
185 | MAP_IMPL(HlEntry, int, DEFAULT_INITIALIZER) |
186 | MAP_IMPL(String, handle_T, 0) |
187 | |
188 | |
189 | /// Deletes a key:value pair from a string:pointer map, and frees the |
190 | /// storage of both key and value. |
191 | /// |
192 | void pmap_del2(PMap(cstr_t) *map, const char *key) |
193 | { |
194 | if (pmap_has(cstr_t)(map, key)) { |
195 | void *k = (void *)pmap_key(cstr_t)(map, key); |
196 | void *v = pmap_get(cstr_t)(map, key); |
197 | pmap_del(cstr_t)(map, key); |
198 | xfree(k); |
199 | xfree(v); |
200 | } |
201 | } |
202 | |