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
143static 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
152static 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
160static 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
170static inline bool HlEntry_eq(HlEntry ae1, HlEntry ae2)
171{
172 return memcmp(&ae1, &ae2, sizeof(ae1)) == 0;
173}
174
175
176
177MAP_IMPL(int, int, DEFAULT_INITIALIZER)
178MAP_IMPL(cstr_t, ptr_t, DEFAULT_INITIALIZER)
179MAP_IMPL(ptr_t, ptr_t, DEFAULT_INITIALIZER)
180MAP_IMPL(uint64_t, ptr_t, DEFAULT_INITIALIZER)
181MAP_IMPL(handle_T, ptr_t, DEFAULT_INITIALIZER)
182#define MSGPACK_HANDLER_INITIALIZER { .fn = NULL, .fast = false }
183MAP_IMPL(String, MsgpackRpcRequestHandler, MSGPACK_HANDLER_INITIALIZER)
184#define KVEC_INITIALIZER { .size = 0, .capacity = 0, .items = NULL }
185MAP_IMPL(HlEntry, int, DEFAULT_INITIALIZER)
186MAP_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///
192void 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