hiredis 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,164 @@
1
+ require "hiredis/version"
2
+
3
+ module Hiredis
4
+ module Ruby
5
+ class Reader
6
+
7
+ def initialize
8
+ @buffer = Buffer.new
9
+ @task = Task.new(@buffer)
10
+ end
11
+
12
+ def feed(data)
13
+ @buffer << data
14
+ end
15
+
16
+ def gets
17
+ reply = @task.process
18
+ @buffer.discard!
19
+ reply
20
+ end
21
+
22
+ protected
23
+
24
+ class Task
25
+
26
+ # Use lookup table to map reply types to methods
27
+ method_index = {}
28
+ method_index[?-] = :process_error_reply
29
+ method_index[?+] = :process_status_reply
30
+ method_index[?:] = :process_integer_reply
31
+ method_index[?$] = :process_bulk_reply
32
+ method_index[?*] = :process_multi_bulk_reply
33
+ METHOD_INDEX = method_index.freeze
34
+
35
+ attr_accessor :parent, :child
36
+ attr_accessor :multi_bulk
37
+
38
+ def initialize(buffer, parent = nil, depth = 0)
39
+ @buffer, @parent = buffer, parent
40
+
41
+ # Require 3 nested tasks
42
+ @child = Task.new(@buffer, self, depth + 1) if depth < 2
43
+ end
44
+
45
+ def root
46
+ parent ? parent.root : self
47
+ end
48
+
49
+ def reset!
50
+ @line = @type = @multi_bulk = nil
51
+ end
52
+
53
+ def process_error_reply
54
+ RuntimeError.new(@line)
55
+ end
56
+
57
+ def process_status_reply
58
+ @line
59
+ end
60
+
61
+ def process_integer_reply
62
+ @line.to_i
63
+ end
64
+
65
+ def process_bulk_reply
66
+ bulk_length = @line.to_i
67
+ return nil if bulk_length < 0
68
+
69
+ # Caught by caller function when false
70
+ @buffer.read(bulk_length, 2)
71
+ end
72
+
73
+ def process_multi_bulk_reply
74
+ multi_bulk_length = @line.to_i
75
+
76
+ if multi_bulk_length > 0
77
+ @multi_bulk ||= []
78
+
79
+ # We know the multi bulk is not complete when this path is taken.
80
+ while (element = child.process) != false
81
+ @multi_bulk << element
82
+ return @multi_bulk if @multi_bulk.length == multi_bulk_length
83
+ end
84
+
85
+ false
86
+ elsif multi_bulk_length == 0
87
+ []
88
+ else
89
+ nil
90
+ end
91
+ end
92
+
93
+ def process_protocol_error
94
+ raise "Protocol error"
95
+ end
96
+
97
+ def process
98
+ @line ||= @buffer.read_line
99
+ return false if @line == false
100
+
101
+ @type ||= @line.slice!(0)
102
+ reply = send(METHOD_INDEX[@type] || :process_protocol_error)
103
+
104
+ reset! if reply != false
105
+ reply
106
+ end
107
+ end
108
+
109
+ class Buffer
110
+
111
+ CRLF = "\r\n".freeze
112
+
113
+ def initialize
114
+ @buffer = ""
115
+ @length = @pos = 0
116
+ end
117
+
118
+ def <<(data)
119
+ @length += data.length
120
+ @buffer << data
121
+ end
122
+
123
+ def length
124
+ @length
125
+ end
126
+
127
+ def empty?
128
+ @length == 0
129
+ end
130
+
131
+ def discard!
132
+ if @length == 0
133
+ @buffer = ""
134
+ @length = @pos = 0
135
+ else
136
+ if @pos >= 1024
137
+ @buffer.slice!(0, @pos)
138
+ @length -= @pos
139
+ @pos = 0
140
+ end
141
+ end
142
+ end
143
+
144
+ def read(bytes, skip = 0)
145
+ start = @pos
146
+ stop = start + bytes + skip
147
+ return false if @length < stop
148
+
149
+ @pos = stop
150
+ @buffer[start, bytes]
151
+ end
152
+
153
+ def read_line
154
+ start = @pos
155
+ stop = @buffer.index(CRLF, @pos)
156
+ return false unless stop
157
+
158
+ @pos = stop + 2 # include CRLF
159
+ @buffer[start, stop - start]
160
+ end
161
+ end
162
+ end
163
+ end
164
+ end
@@ -1,3 +1,3 @@
1
1
  module Hiredis
2
- VERSION = "0.2.0"
2
+ VERSION = "0.3.0"
3
3
  end
@@ -2,7 +2,7 @@
2
2
  # Copyright (C) 2010 Salvatore Sanfilippo <antirez at gmail dot com>
3
3
  # This file is released under the BSD license, see the COPYING file
4
4
 
5
- OBJ = net.o hiredis.o sds.o async.o dict.o
5
+ OBJ = net.o hiredis.o sds.o async.o
6
6
  BINS = hiredis-example hiredis-test
7
7
 
8
8
  uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not')
@@ -16,7 +16,7 @@ ifeq ($(uname_S),SunOS)
16
16
  STLIBNAME?=libhiredis.a
17
17
  STLIB_MAKE_CMD?=ar rcs ${STLIBNAME} ${OBJ}
18
18
  else ifeq ($(uname_S),Darwin)
19
- CFLAGS?=-std=c99 -pedantic $(OPTIMIZATION) -fPIC -Wall -W -Wwrite-strings $(ARCH) $(PROF)
19
+ CFLAGS?=-std=c99 -pedantic $(OPTIMIZATION) -fPIC -Wall -W -Wstrict-prototypes -Wwrite-strings $(ARCH) $(PROF)
20
20
  CCLINK?=-lm -pthread
21
21
  LDFLAGS?=-L. -Wl,-rpath,.
22
22
  OBJARCH?=-arch i386 -arch x86_64
@@ -25,7 +25,7 @@ else ifeq ($(uname_S),Darwin)
25
25
  STLIBNAME?=libhiredis.a
26
26
  STLIB_MAKE_CMD?=libtool -static -o ${STLIBNAME} - ${OBJ}
27
27
  else
28
- CFLAGS?=-std=c99 -pedantic $(OPTIMIZATION) -fPIC -Wall -W -Wwrite-strings $(ARCH) $(PROF)
28
+ CFLAGS?=-std=c99 -pedantic $(OPTIMIZATION) -fPIC -Wall -W -Wstrict-prototypes -Wwrite-strings $(ARCH) $(PROF)
29
29
  CCLINK?=-lm -pthread
30
30
  LDFLAGS?=-L. -Wl,-rpath,.
31
31
  DYLIBNAME?=libhiredis.so
@@ -45,11 +45,10 @@ all: ${DYLIBNAME} ${BINS}
45
45
 
46
46
  # Deps (use make dep to generate this)
47
47
  net.o: net.c fmacros.h net.h
48
- async.o: async.c async.h hiredis.h sds.h util.h
48
+ async.o: async.c async.h hiredis.h sds.h util.h dict.c dict.h
49
49
  example.o: example.c hiredis.h
50
50
  hiredis.o: hiredis.c hiredis.h net.h sds.h util.h
51
51
  sds.o: sds.c sds.h
52
- dict.o: dict.c dict.h
53
52
  test.o: test.c hiredis.h
54
53
 
55
54
  ${DYLIBNAME}: ${OBJ}
@@ -30,9 +30,11 @@
30
30
  */
31
31
 
32
32
  #include <string.h>
33
+ #include <strings.h>
33
34
  #include <assert.h>
34
35
  #include <ctype.h>
35
36
  #include "async.h"
37
+ #include "dict.c"
36
38
  #include "sds.h"
37
39
  #include "util.h"
38
40
 
@@ -32,13 +32,13 @@
32
32
  #ifndef __HIREDIS_ASYNC_H
33
33
  #define __HIREDIS_ASYNC_H
34
34
  #include "hiredis.h"
35
- #include "dict.h"
36
35
 
37
36
  #ifdef __cplusplus
38
37
  extern "C" {
39
38
  #endif
40
39
 
41
40
  struct redisAsyncContext; /* need forward declaration of redisAsyncContext */
41
+ struct dict; /* dictionary header is included in async.c */
42
42
 
43
43
  /* Reply callback prototype and container */
44
44
  typedef void (redisCallbackFn)(struct redisAsyncContext*, void*, void*);
@@ -95,8 +95,8 @@ typedef struct redisAsyncContext {
95
95
  /* Subscription callbacks */
96
96
  struct {
97
97
  redisCallbackList invalid;
98
- dict *channels;
99
- dict *patterns;
98
+ struct dict *channels;
99
+ struct dict *patterns;
100
100
  } sub;
101
101
  } redisAsyncContext;
102
102
 
@@ -50,7 +50,7 @@ static int _dictInit(dict *ht, dictType *type, void *privDataPtr);
50
50
 
51
51
  /* Generic hash function (a popular one from Bernstein).
52
52
  * I tested a few and this was the best. */
53
- unsigned int dictGenHashFunction(const unsigned char *buf, int len) {
53
+ static unsigned int dictGenHashFunction(const unsigned char *buf, int len) {
54
54
  unsigned int hash = 5381;
55
55
 
56
56
  while (len--)
@@ -70,31 +70,22 @@ static void _dictReset(dict *ht) {
70
70
  }
71
71
 
72
72
  /* Create a new hash table */
73
- dict *dictCreate(dictType *type, void *privDataPtr) {
73
+ static dict *dictCreate(dictType *type, void *privDataPtr) {
74
74
  dict *ht = malloc(sizeof(*ht));
75
75
  _dictInit(ht,type,privDataPtr);
76
76
  return ht;
77
77
  }
78
78
 
79
79
  /* Initialize the hash table */
80
- int _dictInit(dict *ht, dictType *type, void *privDataPtr) {
80
+ static int _dictInit(dict *ht, dictType *type, void *privDataPtr) {
81
81
  _dictReset(ht);
82
82
  ht->type = type;
83
83
  ht->privdata = privDataPtr;
84
84
  return DICT_OK;
85
85
  }
86
86
 
87
- /* Resize the table to the minimal size that contains all the elements,
88
- * but with the invariant of a USER/BUCKETS ration near to <= 1 */
89
- int dictResize(dict *ht) {
90
- int minimal = ht->used;
91
- if (minimal < DICT_HT_INITIAL_SIZE)
92
- minimal = DICT_HT_INITIAL_SIZE;
93
- return dictExpand(ht, minimal);
94
- }
95
-
96
87
  /* Expand or create the hashtable */
97
- int dictExpand(dict *ht, unsigned long size) {
88
+ static int dictExpand(dict *ht, unsigned long size) {
98
89
  dict n; /* the new hashtable */
99
90
  unsigned long realsize = _dictNextPower(size), i;
100
91
 
@@ -141,7 +132,7 @@ int dictExpand(dict *ht, unsigned long size) {
141
132
  }
142
133
 
143
134
  /* Add an element to the target hash table */
144
- int dictAdd(dict *ht, void *key, void *val) {
135
+ static int dictAdd(dict *ht, void *key, void *val) {
145
136
  int index;
146
137
  dictEntry *entry;
147
138
 
@@ -166,7 +157,7 @@ int dictAdd(dict *ht, void *key, void *val) {
166
157
  * Return 1 if the key was added from scratch, 0 if there was already an
167
158
  * element with such key and dictReplace() just performed a value update
168
159
  * operation. */
169
- int dictReplace(dict *ht, void *key, void *val) {
160
+ static int dictReplace(dict *ht, void *key, void *val) {
170
161
  dictEntry *entry, auxentry;
171
162
 
172
163
  /* Try to add the element. If the key
@@ -188,47 +179,38 @@ int dictReplace(dict *ht, void *key, void *val) {
188
179
  }
189
180
 
190
181
  /* Search and remove an element */
191
- static int dictGenericDelete(dict *ht, const void *key, int nofree) {
182
+ static int dictDelete(dict *ht, const void *key) {
192
183
  unsigned int h;
193
- dictEntry *he, *prevHe;
184
+ dictEntry *de, *prevde;
194
185
 
195
186
  if (ht->size == 0)
196
187
  return DICT_ERR;
197
188
  h = dictHashKey(ht, key) & ht->sizemask;
198
- he = ht->table[h];
189
+ de = ht->table[h];
199
190
 
200
- prevHe = NULL;
201
- while(he) {
202
- if (dictCompareHashKeys(ht, key, he->key)) {
191
+ prevde = NULL;
192
+ while(de) {
193
+ if (dictCompareHashKeys(ht,key,de->key)) {
203
194
  /* Unlink the element from the list */
204
- if (prevHe)
205
- prevHe->next = he->next;
195
+ if (prevde)
196
+ prevde->next = de->next;
206
197
  else
207
- ht->table[h] = he->next;
208
- if (!nofree) {
209
- dictFreeEntryKey(ht, he);
210
- dictFreeEntryVal(ht, he);
211
- }
212
- free(he);
198
+ ht->table[h] = de->next;
199
+
200
+ dictFreeEntryKey(ht,de);
201
+ dictFreeEntryVal(ht,de);
202
+ free(de);
213
203
  ht->used--;
214
204
  return DICT_OK;
215
205
  }
216
- prevHe = he;
217
- he = he->next;
206
+ prevde = de;
207
+ de = de->next;
218
208
  }
219
209
  return DICT_ERR; /* not found */
220
210
  }
221
211
 
222
- int dictDelete(dict *ht, const void *key) {
223
- return dictGenericDelete(ht,key,0);
224
- }
225
-
226
- int dictDeleteNoFree(dict *ht, const void *key) {
227
- return dictGenericDelete(ht,key,1);
228
- }
229
-
230
212
  /* Destroy an entire hash table */
231
- int _dictClear(dict *ht) {
213
+ static int _dictClear(dict *ht) {
232
214
  unsigned long i;
233
215
 
234
216
  /* Free all the elements */
@@ -253,12 +235,12 @@ int _dictClear(dict *ht) {
253
235
  }
254
236
 
255
237
  /* Clear & Release the hash table */
256
- void dictRelease(dict *ht) {
238
+ static void dictRelease(dict *ht) {
257
239
  _dictClear(ht);
258
240
  free(ht);
259
241
  }
260
242
 
261
- dictEntry *dictFind(dict *ht, const void *key) {
243
+ static dictEntry *dictFind(dict *ht, const void *key) {
262
244
  dictEntry *he;
263
245
  unsigned int h;
264
246
 
@@ -273,7 +255,7 @@ dictEntry *dictFind(dict *ht, const void *key) {
273
255
  return NULL;
274
256
  }
275
257
 
276
- dictIterator *dictGetIterator(dict *ht) {
258
+ static dictIterator *dictGetIterator(dict *ht) {
277
259
  dictIterator *iter = malloc(sizeof(*iter));
278
260
 
279
261
  iter->ht = ht;
@@ -283,7 +265,7 @@ dictIterator *dictGetIterator(dict *ht) {
283
265
  return iter;
284
266
  }
285
267
 
286
- dictEntry *dictNext(dictIterator *iter) {
268
+ static dictEntry *dictNext(dictIterator *iter) {
287
269
  while (1) {
288
270
  if (iter->entry == NULL) {
289
271
  iter->index++;
@@ -303,38 +285,10 @@ dictEntry *dictNext(dictIterator *iter) {
303
285
  return NULL;
304
286
  }
305
287
 
306
- void dictReleaseIterator(dictIterator *iter) {
288
+ static void dictReleaseIterator(dictIterator *iter) {
307
289
  free(iter);
308
290
  }
309
291
 
310
- /* Return a random entry from the hash table. Useful to
311
- * implement randomized algorithms */
312
- dictEntry *dictGetRandomKey(dict *ht) {
313
- dictEntry *he;
314
- unsigned int h;
315
- int listlen, listele;
316
-
317
- if (ht->used == 0) return NULL;
318
- do {
319
- h = random() & ht->sizemask;
320
- he = ht->table[h];
321
- } while(he == NULL);
322
-
323
- /* Now we found a non empty bucket, but it is a linked
324
- * list and we need to get a random element from the list.
325
- * The only sane way to do so is to count the element and
326
- * select a random index. */
327
- listlen = 0;
328
- while(he) {
329
- he = he->next;
330
- listlen++;
331
- }
332
- listele = random() % listlen;
333
- he = ht->table[h];
334
- while(listele--) he = he->next;
335
- return he;
336
- }
337
-
338
292
  /* ------------------------- private functions ------------------------------ */
339
293
 
340
294
  /* Expand the hash table if needed */
@@ -382,7 +336,3 @@ static int _dictKeyIndex(dict *ht, const void *key) {
382
336
  return h;
383
337
  }
384
338
 
385
- void dictEmpty(dict *ht) {
386
- _dictClear(ht);
387
- }
388
-