hiredis 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
-