redis-client 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +7 -0
  2. data/.rubocop.yml +190 -0
  3. data/CHANGELOG.md +3 -0
  4. data/Gemfile +23 -0
  5. data/Gemfile.lock +67 -0
  6. data/LICENSE.md +21 -0
  7. data/README.md +347 -0
  8. data/Rakefile +86 -0
  9. data/ext/redis_client/hiredis/extconf.rb +54 -0
  10. data/ext/redis_client/hiredis/hiredis_connection.c +696 -0
  11. data/ext/redis_client/hiredis/vendor/.gitignore +9 -0
  12. data/ext/redis_client/hiredis/vendor/.travis.yml +131 -0
  13. data/ext/redis_client/hiredis/vendor/CHANGELOG.md +364 -0
  14. data/ext/redis_client/hiredis/vendor/CMakeLists.txt +165 -0
  15. data/ext/redis_client/hiredis/vendor/COPYING +29 -0
  16. data/ext/redis_client/hiredis/vendor/Makefile +308 -0
  17. data/ext/redis_client/hiredis/vendor/README.md +664 -0
  18. data/ext/redis_client/hiredis/vendor/adapters/ae.h +130 -0
  19. data/ext/redis_client/hiredis/vendor/adapters/glib.h +156 -0
  20. data/ext/redis_client/hiredis/vendor/adapters/ivykis.h +84 -0
  21. data/ext/redis_client/hiredis/vendor/adapters/libev.h +179 -0
  22. data/ext/redis_client/hiredis/vendor/adapters/libevent.h +175 -0
  23. data/ext/redis_client/hiredis/vendor/adapters/libuv.h +117 -0
  24. data/ext/redis_client/hiredis/vendor/adapters/macosx.h +115 -0
  25. data/ext/redis_client/hiredis/vendor/adapters/qt.h +135 -0
  26. data/ext/redis_client/hiredis/vendor/alloc.c +86 -0
  27. data/ext/redis_client/hiredis/vendor/alloc.h +91 -0
  28. data/ext/redis_client/hiredis/vendor/appveyor.yml +24 -0
  29. data/ext/redis_client/hiredis/vendor/async.c +887 -0
  30. data/ext/redis_client/hiredis/vendor/async.h +147 -0
  31. data/ext/redis_client/hiredis/vendor/async_private.h +75 -0
  32. data/ext/redis_client/hiredis/vendor/dict.c +352 -0
  33. data/ext/redis_client/hiredis/vendor/dict.h +126 -0
  34. data/ext/redis_client/hiredis/vendor/fmacros.h +12 -0
  35. data/ext/redis_client/hiredis/vendor/hiredis-config.cmake.in +13 -0
  36. data/ext/redis_client/hiredis/vendor/hiredis.c +1174 -0
  37. data/ext/redis_client/hiredis/vendor/hiredis.h +336 -0
  38. data/ext/redis_client/hiredis/vendor/hiredis.pc.in +12 -0
  39. data/ext/redis_client/hiredis/vendor/hiredis_ssl-config.cmake.in +13 -0
  40. data/ext/redis_client/hiredis/vendor/hiredis_ssl.h +157 -0
  41. data/ext/redis_client/hiredis/vendor/hiredis_ssl.pc.in +12 -0
  42. data/ext/redis_client/hiredis/vendor/net.c +612 -0
  43. data/ext/redis_client/hiredis/vendor/net.h +56 -0
  44. data/ext/redis_client/hiredis/vendor/read.c +739 -0
  45. data/ext/redis_client/hiredis/vendor/read.h +129 -0
  46. data/ext/redis_client/hiredis/vendor/sds.c +1289 -0
  47. data/ext/redis_client/hiredis/vendor/sds.h +278 -0
  48. data/ext/redis_client/hiredis/vendor/sdsalloc.h +44 -0
  49. data/ext/redis_client/hiredis/vendor/sockcompat.c +248 -0
  50. data/ext/redis_client/hiredis/vendor/sockcompat.h +92 -0
  51. data/ext/redis_client/hiredis/vendor/ssl.c +544 -0
  52. data/ext/redis_client/hiredis/vendor/test.c +1401 -0
  53. data/ext/redis_client/hiredis/vendor/test.sh +78 -0
  54. data/ext/redis_client/hiredis/vendor/win32.h +56 -0
  55. data/lib/redis-client.rb +3 -0
  56. data/lib/redis_client/buffered_io.rb +149 -0
  57. data/lib/redis_client/config.rb +174 -0
  58. data/lib/redis_client/connection.rb +86 -0
  59. data/lib/redis_client/hiredis_connection.rb +78 -0
  60. data/lib/redis_client/pooled.rb +86 -0
  61. data/lib/redis_client/resp3.rb +225 -0
  62. data/lib/redis_client/sentinel_config.rb +134 -0
  63. data/lib/redis_client/version.rb +5 -0
  64. data/lib/redis_client.rb +438 -0
  65. data/redis-client.gemspec +34 -0
  66. metadata +125 -0
@@ -0,0 +1,147 @@
1
+ /*
2
+ * Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
3
+ * Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis at gmail dot com>
4
+ *
5
+ * All rights reserved.
6
+ *
7
+ * Redistribution and use in source and binary forms, with or without
8
+ * modification, are permitted provided that the following conditions are met:
9
+ *
10
+ * * Redistributions of source code must retain the above copyright notice,
11
+ * this list of conditions and the following disclaimer.
12
+ * * Redistributions in binary form must reproduce the above copyright
13
+ * notice, this list of conditions and the following disclaimer in the
14
+ * documentation and/or other materials provided with the distribution.
15
+ * * Neither the name of Redis nor the names of its contributors may be used
16
+ * to endorse or promote products derived from this software without
17
+ * specific prior written permission.
18
+ *
19
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
+ * POSSIBILITY OF SUCH DAMAGE.
30
+ */
31
+
32
+ #ifndef __HIREDIS_ASYNC_H
33
+ #define __HIREDIS_ASYNC_H
34
+ #include "hiredis.h"
35
+
36
+ #ifdef __cplusplus
37
+ extern "C" {
38
+ #endif
39
+
40
+ struct redisAsyncContext; /* need forward declaration of redisAsyncContext */
41
+ struct dict; /* dictionary header is included in async.c */
42
+
43
+ /* Reply callback prototype and container */
44
+ typedef void (redisCallbackFn)(struct redisAsyncContext*, void*, void*);
45
+ typedef struct redisCallback {
46
+ struct redisCallback *next; /* simple singly linked list */
47
+ redisCallbackFn *fn;
48
+ int pending_subs;
49
+ void *privdata;
50
+ } redisCallback;
51
+
52
+ /* List of callbacks for either regular replies or pub/sub */
53
+ typedef struct redisCallbackList {
54
+ redisCallback *head, *tail;
55
+ } redisCallbackList;
56
+
57
+ /* Connection callback prototypes */
58
+ typedef void (redisDisconnectCallback)(const struct redisAsyncContext*, int status);
59
+ typedef void (redisConnectCallback)(const struct redisAsyncContext*, int status);
60
+ typedef void(redisTimerCallback)(void *timer, void *privdata);
61
+
62
+ /* Context for an async connection to Redis */
63
+ typedef struct redisAsyncContext {
64
+ /* Hold the regular context, so it can be realloc'ed. */
65
+ redisContext c;
66
+
67
+ /* Setup error flags so they can be used directly. */
68
+ int err;
69
+ char *errstr;
70
+
71
+ /* Not used by hiredis */
72
+ void *data;
73
+ void (*dataCleanup)(void *privdata);
74
+
75
+ /* Event library data and hooks */
76
+ struct {
77
+ void *data;
78
+
79
+ /* Hooks that are called when the library expects to start
80
+ * reading/writing. These functions should be idempotent. */
81
+ void (*addRead)(void *privdata);
82
+ void (*delRead)(void *privdata);
83
+ void (*addWrite)(void *privdata);
84
+ void (*delWrite)(void *privdata);
85
+ void (*cleanup)(void *privdata);
86
+ void (*scheduleTimer)(void *privdata, struct timeval tv);
87
+ } ev;
88
+
89
+ /* Called when either the connection is terminated due to an error or per
90
+ * user request. The status is set accordingly (REDIS_OK, REDIS_ERR). */
91
+ redisDisconnectCallback *onDisconnect;
92
+
93
+ /* Called when the first write event was received. */
94
+ redisConnectCallback *onConnect;
95
+
96
+ /* Regular command callbacks */
97
+ redisCallbackList replies;
98
+
99
+ /* Address used for connect() */
100
+ struct sockaddr *saddr;
101
+ size_t addrlen;
102
+
103
+ /* Subscription callbacks */
104
+ struct {
105
+ redisCallbackList invalid;
106
+ struct dict *channels;
107
+ struct dict *patterns;
108
+ } sub;
109
+
110
+ /* Any configured RESP3 PUSH handler */
111
+ redisAsyncPushFn *push_cb;
112
+ } redisAsyncContext;
113
+
114
+ /* Functions that proxy to hiredis */
115
+ redisAsyncContext *redisAsyncConnectWithOptions(const redisOptions *options);
116
+ redisAsyncContext *redisAsyncConnect(const char *ip, int port);
117
+ redisAsyncContext *redisAsyncConnectBind(const char *ip, int port, const char *source_addr);
118
+ redisAsyncContext *redisAsyncConnectBindWithReuse(const char *ip, int port,
119
+ const char *source_addr);
120
+ redisAsyncContext *redisAsyncConnectUnix(const char *path);
121
+ int redisAsyncSetConnectCallback(redisAsyncContext *ac, redisConnectCallback *fn);
122
+ int redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconnectCallback *fn);
123
+
124
+ redisAsyncPushFn *redisAsyncSetPushCallback(redisAsyncContext *ac, redisAsyncPushFn *fn);
125
+ int redisAsyncSetTimeout(redisAsyncContext *ac, struct timeval tv);
126
+ void redisAsyncDisconnect(redisAsyncContext *ac);
127
+ void redisAsyncFree(redisAsyncContext *ac);
128
+
129
+ /* Handle read/write events */
130
+ void redisAsyncHandleRead(redisAsyncContext *ac);
131
+ void redisAsyncHandleWrite(redisAsyncContext *ac);
132
+ void redisAsyncHandleTimeout(redisAsyncContext *ac);
133
+ void redisAsyncRead(redisAsyncContext *ac);
134
+ void redisAsyncWrite(redisAsyncContext *ac);
135
+
136
+ /* Command functions for an async context. Write the command to the
137
+ * output buffer and register the provided callback. */
138
+ int redisvAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *format, va_list ap);
139
+ int redisAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *format, ...);
140
+ int redisAsyncCommandArgv(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, int argc, const char **argv, const size_t *argvlen);
141
+ int redisAsyncFormattedCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *cmd, size_t len);
142
+
143
+ #ifdef __cplusplus
144
+ }
145
+ #endif
146
+
147
+ #endif
@@ -0,0 +1,75 @@
1
+ /*
2
+ * Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
3
+ * Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis at gmail dot com>
4
+ *
5
+ * All rights reserved.
6
+ *
7
+ * Redistribution and use in source and binary forms, with or without
8
+ * modification, are permitted provided that the following conditions are met:
9
+ *
10
+ * * Redistributions of source code must retain the above copyright notice,
11
+ * this list of conditions and the following disclaimer.
12
+ * * Redistributions in binary form must reproduce the above copyright
13
+ * notice, this list of conditions and the following disclaimer in the
14
+ * documentation and/or other materials provided with the distribution.
15
+ * * Neither the name of Redis nor the names of its contributors may be used
16
+ * to endorse or promote products derived from this software without
17
+ * specific prior written permission.
18
+ *
19
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
+ * POSSIBILITY OF SUCH DAMAGE.
30
+ */
31
+
32
+ #ifndef __HIREDIS_ASYNC_PRIVATE_H
33
+ #define __HIREDIS_ASYNC_PRIVATE_H
34
+
35
+ #define _EL_ADD_READ(ctx) \
36
+ do { \
37
+ refreshTimeout(ctx); \
38
+ if ((ctx)->ev.addRead) (ctx)->ev.addRead((ctx)->ev.data); \
39
+ } while (0)
40
+ #define _EL_DEL_READ(ctx) do { \
41
+ if ((ctx)->ev.delRead) (ctx)->ev.delRead((ctx)->ev.data); \
42
+ } while(0)
43
+ #define _EL_ADD_WRITE(ctx) \
44
+ do { \
45
+ refreshTimeout(ctx); \
46
+ if ((ctx)->ev.addWrite) (ctx)->ev.addWrite((ctx)->ev.data); \
47
+ } while (0)
48
+ #define _EL_DEL_WRITE(ctx) do { \
49
+ if ((ctx)->ev.delWrite) (ctx)->ev.delWrite((ctx)->ev.data); \
50
+ } while(0)
51
+ #define _EL_CLEANUP(ctx) do { \
52
+ if ((ctx)->ev.cleanup) (ctx)->ev.cleanup((ctx)->ev.data); \
53
+ ctx->ev.cleanup = NULL; \
54
+ } while(0);
55
+
56
+ static inline void refreshTimeout(redisAsyncContext *ctx) {
57
+ #define REDIS_TIMER_ISSET(tvp) \
58
+ (tvp && ((tvp)->tv_sec || (tvp)->tv_usec))
59
+
60
+ #define REDIS_EL_TIMER(ac, tvp) \
61
+ if ((ac)->ev.scheduleTimer && REDIS_TIMER_ISSET(tvp)) { \
62
+ (ac)->ev.scheduleTimer((ac)->ev.data, *(tvp)); \
63
+ }
64
+
65
+ if (ctx->c.flags & REDIS_CONNECTED) {
66
+ REDIS_EL_TIMER(ctx, ctx->c.command_timeout);
67
+ } else {
68
+ REDIS_EL_TIMER(ctx, ctx->c.connect_timeout);
69
+ }
70
+ }
71
+
72
+ void __redisAsyncDisconnect(redisAsyncContext *ac);
73
+ void redisProcessCallbacks(redisAsyncContext *ac);
74
+
75
+ #endif /* __HIREDIS_ASYNC_PRIVATE_H */
@@ -0,0 +1,352 @@
1
+ /* Hash table implementation.
2
+ *
3
+ * This file implements in memory hash tables with insert/del/replace/find/
4
+ * get-random-element operations. Hash tables will auto resize if needed
5
+ * tables of power of two in size are used, collisions are handled by
6
+ * chaining. See the source code for more information... :)
7
+ *
8
+ * Copyright (c) 2006-2010, Salvatore Sanfilippo <antirez at gmail dot com>
9
+ * All rights reserved.
10
+ *
11
+ * Redistribution and use in source and binary forms, with or without
12
+ * modification, are permitted provided that the following conditions are met:
13
+ *
14
+ * * Redistributions of source code must retain the above copyright notice,
15
+ * this list of conditions and the following disclaimer.
16
+ * * Redistributions in binary form must reproduce the above copyright
17
+ * notice, this list of conditions and the following disclaimer in the
18
+ * documentation and/or other materials provided with the distribution.
19
+ * * Neither the name of Redis nor the names of its contributors may be used
20
+ * to endorse or promote products derived from this software without
21
+ * specific prior written permission.
22
+ *
23
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
27
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33
+ * POSSIBILITY OF SUCH DAMAGE.
34
+ */
35
+
36
+ #include "fmacros.h"
37
+ #include "alloc.h"
38
+ #include <stdlib.h>
39
+ #include <assert.h>
40
+ #include <limits.h>
41
+ #include "dict.h"
42
+
43
+ /* -------------------------- private prototypes ---------------------------- */
44
+
45
+ static int _dictExpandIfNeeded(dict *ht);
46
+ static unsigned long _dictNextPower(unsigned long size);
47
+ static int _dictKeyIndex(dict *ht, const void *key);
48
+ static int _dictInit(dict *ht, dictType *type, void *privDataPtr);
49
+
50
+ /* -------------------------- hash functions -------------------------------- */
51
+
52
+ /* Generic hash function (a popular one from Bernstein).
53
+ * I tested a few and this was the best. */
54
+ static unsigned int dictGenHashFunction(const unsigned char *buf, int len) {
55
+ unsigned int hash = 5381;
56
+
57
+ while (len--)
58
+ hash = ((hash << 5) + hash) + (*buf++); /* hash * 33 + c */
59
+ return hash;
60
+ }
61
+
62
+ /* ----------------------------- API implementation ------------------------- */
63
+
64
+ /* Reset an hashtable already initialized with ht_init().
65
+ * NOTE: This function should only called by ht_destroy(). */
66
+ static void _dictReset(dict *ht) {
67
+ ht->table = NULL;
68
+ ht->size = 0;
69
+ ht->sizemask = 0;
70
+ ht->used = 0;
71
+ }
72
+
73
+ /* Create a new hash table */
74
+ static dict *dictCreate(dictType *type, void *privDataPtr) {
75
+ dict *ht = hi_malloc(sizeof(*ht));
76
+ if (ht == NULL)
77
+ return NULL;
78
+
79
+ _dictInit(ht,type,privDataPtr);
80
+ return ht;
81
+ }
82
+
83
+ /* Initialize the hash table */
84
+ static int _dictInit(dict *ht, dictType *type, void *privDataPtr) {
85
+ _dictReset(ht);
86
+ ht->type = type;
87
+ ht->privdata = privDataPtr;
88
+ return DICT_OK;
89
+ }
90
+
91
+ /* Expand or create the hashtable */
92
+ static int dictExpand(dict *ht, unsigned long size) {
93
+ dict n; /* the new hashtable */
94
+ unsigned long realsize = _dictNextPower(size), i;
95
+
96
+ /* the size is invalid if it is smaller than the number of
97
+ * elements already inside the hashtable */
98
+ if (ht->used > size)
99
+ return DICT_ERR;
100
+
101
+ _dictInit(&n, ht->type, ht->privdata);
102
+ n.size = realsize;
103
+ n.sizemask = realsize-1;
104
+ n.table = hi_calloc(realsize,sizeof(dictEntry*));
105
+ if (n.table == NULL)
106
+ return DICT_ERR;
107
+
108
+ /* Copy all the elements from the old to the new table:
109
+ * note that if the old hash table is empty ht->size is zero,
110
+ * so dictExpand just creates an hash table. */
111
+ n.used = ht->used;
112
+ for (i = 0; i < ht->size && ht->used > 0; i++) {
113
+ dictEntry *he, *nextHe;
114
+
115
+ if (ht->table[i] == NULL) continue;
116
+
117
+ /* For each hash entry on this slot... */
118
+ he = ht->table[i];
119
+ while(he) {
120
+ unsigned int h;
121
+
122
+ nextHe = he->next;
123
+ /* Get the new element index */
124
+ h = dictHashKey(ht, he->key) & n.sizemask;
125
+ he->next = n.table[h];
126
+ n.table[h] = he;
127
+ ht->used--;
128
+ /* Pass to the next element */
129
+ he = nextHe;
130
+ }
131
+ }
132
+ assert(ht->used == 0);
133
+ hi_free(ht->table);
134
+
135
+ /* Remap the new hashtable in the old */
136
+ *ht = n;
137
+ return DICT_OK;
138
+ }
139
+
140
+ /* Add an element to the target hash table */
141
+ static int dictAdd(dict *ht, void *key, void *val) {
142
+ int index;
143
+ dictEntry *entry;
144
+
145
+ /* Get the index of the new element, or -1 if
146
+ * the element already exists. */
147
+ if ((index = _dictKeyIndex(ht, key)) == -1)
148
+ return DICT_ERR;
149
+
150
+ /* Allocates the memory and stores key */
151
+ entry = hi_malloc(sizeof(*entry));
152
+ if (entry == NULL)
153
+ return DICT_ERR;
154
+
155
+ entry->next = ht->table[index];
156
+ ht->table[index] = entry;
157
+
158
+ /* Set the hash entry fields. */
159
+ dictSetHashKey(ht, entry, key);
160
+ dictSetHashVal(ht, entry, val);
161
+ ht->used++;
162
+ return DICT_OK;
163
+ }
164
+
165
+ /* Add an element, discarding the old if the key already exists.
166
+ * Return 1 if the key was added from scratch, 0 if there was already an
167
+ * element with such key and dictReplace() just performed a value update
168
+ * operation. */
169
+ static int dictReplace(dict *ht, void *key, void *val) {
170
+ dictEntry *entry, auxentry;
171
+
172
+ /* Try to add the element. If the key
173
+ * does not exists dictAdd will succeed. */
174
+ if (dictAdd(ht, key, val) == DICT_OK)
175
+ return 1;
176
+ /* It already exists, get the entry */
177
+ entry = dictFind(ht, key);
178
+ if (entry == NULL)
179
+ return 0;
180
+
181
+ /* Free the old value and set the new one */
182
+ /* Set the new value and free the old one. Note that it is important
183
+ * to do that in this order, as the value may just be exactly the same
184
+ * as the previous one. In this context, think to reference counting,
185
+ * you want to increment (set), and then decrement (free), and not the
186
+ * reverse. */
187
+ auxentry = *entry;
188
+ dictSetHashVal(ht, entry, val);
189
+ dictFreeEntryVal(ht, &auxentry);
190
+ return 0;
191
+ }
192
+
193
+ /* Search and remove an element */
194
+ static int dictDelete(dict *ht, const void *key) {
195
+ unsigned int h;
196
+ dictEntry *de, *prevde;
197
+
198
+ if (ht->size == 0)
199
+ return DICT_ERR;
200
+ h = dictHashKey(ht, key) & ht->sizemask;
201
+ de = ht->table[h];
202
+
203
+ prevde = NULL;
204
+ while(de) {
205
+ if (dictCompareHashKeys(ht,key,de->key)) {
206
+ /* Unlink the element from the list */
207
+ if (prevde)
208
+ prevde->next = de->next;
209
+ else
210
+ ht->table[h] = de->next;
211
+
212
+ dictFreeEntryKey(ht,de);
213
+ dictFreeEntryVal(ht,de);
214
+ hi_free(de);
215
+ ht->used--;
216
+ return DICT_OK;
217
+ }
218
+ prevde = de;
219
+ de = de->next;
220
+ }
221
+ return DICT_ERR; /* not found */
222
+ }
223
+
224
+ /* Destroy an entire hash table */
225
+ static int _dictClear(dict *ht) {
226
+ unsigned long i;
227
+
228
+ /* Free all the elements */
229
+ for (i = 0; i < ht->size && ht->used > 0; i++) {
230
+ dictEntry *he, *nextHe;
231
+
232
+ if ((he = ht->table[i]) == NULL) continue;
233
+ while(he) {
234
+ nextHe = he->next;
235
+ dictFreeEntryKey(ht, he);
236
+ dictFreeEntryVal(ht, he);
237
+ hi_free(he);
238
+ ht->used--;
239
+ he = nextHe;
240
+ }
241
+ }
242
+ /* Free the table and the allocated cache structure */
243
+ hi_free(ht->table);
244
+ /* Re-initialize the table */
245
+ _dictReset(ht);
246
+ return DICT_OK; /* never fails */
247
+ }
248
+
249
+ /* Clear & Release the hash table */
250
+ static void dictRelease(dict *ht) {
251
+ _dictClear(ht);
252
+ hi_free(ht);
253
+ }
254
+
255
+ static dictEntry *dictFind(dict *ht, const void *key) {
256
+ dictEntry *he;
257
+ unsigned int h;
258
+
259
+ if (ht->size == 0) return NULL;
260
+ h = dictHashKey(ht, key) & ht->sizemask;
261
+ he = ht->table[h];
262
+ while(he) {
263
+ if (dictCompareHashKeys(ht, key, he->key))
264
+ return he;
265
+ he = he->next;
266
+ }
267
+ return NULL;
268
+ }
269
+
270
+ static dictIterator *dictGetIterator(dict *ht) {
271
+ dictIterator *iter = hi_malloc(sizeof(*iter));
272
+ if (iter == NULL)
273
+ return NULL;
274
+
275
+ iter->ht = ht;
276
+ iter->index = -1;
277
+ iter->entry = NULL;
278
+ iter->nextEntry = NULL;
279
+ return iter;
280
+ }
281
+
282
+ static dictEntry *dictNext(dictIterator *iter) {
283
+ while (1) {
284
+ if (iter->entry == NULL) {
285
+ iter->index++;
286
+ if (iter->index >=
287
+ (signed)iter->ht->size) break;
288
+ iter->entry = iter->ht->table[iter->index];
289
+ } else {
290
+ iter->entry = iter->nextEntry;
291
+ }
292
+ if (iter->entry) {
293
+ /* We need to save the 'next' here, the iterator user
294
+ * may delete the entry we are returning. */
295
+ iter->nextEntry = iter->entry->next;
296
+ return iter->entry;
297
+ }
298
+ }
299
+ return NULL;
300
+ }
301
+
302
+ static void dictReleaseIterator(dictIterator *iter) {
303
+ hi_free(iter);
304
+ }
305
+
306
+ /* ------------------------- private functions ------------------------------ */
307
+
308
+ /* Expand the hash table if needed */
309
+ static int _dictExpandIfNeeded(dict *ht) {
310
+ /* If the hash table is empty expand it to the initial size,
311
+ * if the table is "full" double its size. */
312
+ if (ht->size == 0)
313
+ return dictExpand(ht, DICT_HT_INITIAL_SIZE);
314
+ if (ht->used == ht->size)
315
+ return dictExpand(ht, ht->size*2);
316
+ return DICT_OK;
317
+ }
318
+
319
+ /* Our hash table capability is a power of two */
320
+ static unsigned long _dictNextPower(unsigned long size) {
321
+ unsigned long i = DICT_HT_INITIAL_SIZE;
322
+
323
+ if (size >= LONG_MAX) return LONG_MAX;
324
+ while(1) {
325
+ if (i >= size)
326
+ return i;
327
+ i *= 2;
328
+ }
329
+ }
330
+
331
+ /* Returns the index of a free slot that can be populated with
332
+ * an hash entry for the given 'key'.
333
+ * If the key already exists, -1 is returned. */
334
+ static int _dictKeyIndex(dict *ht, const void *key) {
335
+ unsigned int h;
336
+ dictEntry *he;
337
+
338
+ /* Expand the hashtable if needed */
339
+ if (_dictExpandIfNeeded(ht) == DICT_ERR)
340
+ return -1;
341
+ /* Compute the key hash value */
342
+ h = dictHashKey(ht, key) & ht->sizemask;
343
+ /* Search if this slot does not already contain the given key */
344
+ he = ht->table[h];
345
+ while(he) {
346
+ if (dictCompareHashKeys(ht, key, he->key))
347
+ return -1;
348
+ he = he->next;
349
+ }
350
+ return h;
351
+ }
352
+
@@ -0,0 +1,126 @@
1
+ /* Hash table implementation.
2
+ *
3
+ * This file implements in memory hash tables with insert/del/replace/find/
4
+ * get-random-element operations. Hash tables will auto resize if needed
5
+ * tables of power of two in size are used, collisions are handled by
6
+ * chaining. See the source code for more information... :)
7
+ *
8
+ * Copyright (c) 2006-2010, Salvatore Sanfilippo <antirez at gmail dot com>
9
+ * All rights reserved.
10
+ *
11
+ * Redistribution and use in source and binary forms, with or without
12
+ * modification, are permitted provided that the following conditions are met:
13
+ *
14
+ * * Redistributions of source code must retain the above copyright notice,
15
+ * this list of conditions and the following disclaimer.
16
+ * * Redistributions in binary form must reproduce the above copyright
17
+ * notice, this list of conditions and the following disclaimer in the
18
+ * documentation and/or other materials provided with the distribution.
19
+ * * Neither the name of Redis nor the names of its contributors may be used
20
+ * to endorse or promote products derived from this software without
21
+ * specific prior written permission.
22
+ *
23
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
27
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33
+ * POSSIBILITY OF SUCH DAMAGE.
34
+ */
35
+
36
+ #ifndef __DICT_H
37
+ #define __DICT_H
38
+
39
+ #define DICT_OK 0
40
+ #define DICT_ERR 1
41
+
42
+ /* Unused arguments generate annoying warnings... */
43
+ #define DICT_NOTUSED(V) ((void) V)
44
+
45
+ typedef struct dictEntry {
46
+ void *key;
47
+ void *val;
48
+ struct dictEntry *next;
49
+ } dictEntry;
50
+
51
+ typedef struct dictType {
52
+ unsigned int (*hashFunction)(const void *key);
53
+ void *(*keyDup)(void *privdata, const void *key);
54
+ void *(*valDup)(void *privdata, const void *obj);
55
+ int (*keyCompare)(void *privdata, const void *key1, const void *key2);
56
+ void (*keyDestructor)(void *privdata, void *key);
57
+ void (*valDestructor)(void *privdata, void *obj);
58
+ } dictType;
59
+
60
+ typedef struct dict {
61
+ dictEntry **table;
62
+ dictType *type;
63
+ unsigned long size;
64
+ unsigned long sizemask;
65
+ unsigned long used;
66
+ void *privdata;
67
+ } dict;
68
+
69
+ typedef struct dictIterator {
70
+ dict *ht;
71
+ int index;
72
+ dictEntry *entry, *nextEntry;
73
+ } dictIterator;
74
+
75
+ /* This is the initial size of every hash table */
76
+ #define DICT_HT_INITIAL_SIZE 4
77
+
78
+ /* ------------------------------- Macros ------------------------------------*/
79
+ #define dictFreeEntryVal(ht, entry) \
80
+ if ((ht)->type->valDestructor) \
81
+ (ht)->type->valDestructor((ht)->privdata, (entry)->val)
82
+
83
+ #define dictSetHashVal(ht, entry, _val_) do { \
84
+ if ((ht)->type->valDup) \
85
+ entry->val = (ht)->type->valDup((ht)->privdata, _val_); \
86
+ else \
87
+ entry->val = (_val_); \
88
+ } while(0)
89
+
90
+ #define dictFreeEntryKey(ht, entry) \
91
+ if ((ht)->type->keyDestructor) \
92
+ (ht)->type->keyDestructor((ht)->privdata, (entry)->key)
93
+
94
+ #define dictSetHashKey(ht, entry, _key_) do { \
95
+ if ((ht)->type->keyDup) \
96
+ entry->key = (ht)->type->keyDup((ht)->privdata, _key_); \
97
+ else \
98
+ entry->key = (_key_); \
99
+ } while(0)
100
+
101
+ #define dictCompareHashKeys(ht, key1, key2) \
102
+ (((ht)->type->keyCompare) ? \
103
+ (ht)->type->keyCompare((ht)->privdata, key1, key2) : \
104
+ (key1) == (key2))
105
+
106
+ #define dictHashKey(ht, key) (ht)->type->hashFunction(key)
107
+
108
+ #define dictGetEntryKey(he) ((he)->key)
109
+ #define dictGetEntryVal(he) ((he)->val)
110
+ #define dictSlots(ht) ((ht)->size)
111
+ #define dictSize(ht) ((ht)->used)
112
+
113
+ /* API */
114
+ static unsigned int dictGenHashFunction(const unsigned char *buf, int len);
115
+ static dict *dictCreate(dictType *type, void *privDataPtr);
116
+ static int dictExpand(dict *ht, unsigned long size);
117
+ static int dictAdd(dict *ht, void *key, void *val);
118
+ static int dictReplace(dict *ht, void *key, void *val);
119
+ static int dictDelete(dict *ht, const void *key);
120
+ static void dictRelease(dict *ht);
121
+ static dictEntry * dictFind(dict *ht, const void *key);
122
+ static dictIterator *dictGetIterator(dict *ht);
123
+ static dictEntry *dictNext(dictIterator *iter);
124
+ static void dictReleaseIterator(dictIterator *iter);
125
+
126
+ #endif /* __DICT_H */