hyperdex 1.4.5.1.gc197953

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,975 @@
1
+ /* Copyright (c) 2013, Cornell University
2
+ * All rights reserved.
3
+ *
4
+ * Redistribution and use in source and binary forms, with or without
5
+ * modification, are permitted provided that the following conditions are met:
6
+ *
7
+ * * Redistributions of source code must retain the above copyright notice,
8
+ * this list of conditions and the following disclaimer.
9
+ * * Redistributions in binary form must reproduce the above copyright
10
+ * notice, this list of conditions and the following disclaimer in the
11
+ * documentation and/or other materials provided with the distribution.
12
+ * * Neither the name of HyperDex nor the names of its contributors may be
13
+ * used to endorse or promote products derived from this software without
14
+ * specific prior written permission.
15
+ *
16
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26
+ * POSSIBILITY OF SUCH DAMAGE.
27
+ */
28
+
29
+ /* C */
30
+ #include <assert.h>
31
+
32
+ /* Ruby */
33
+ #include <ruby/ruby.h>
34
+ #include <ruby/intern.h>
35
+ #include <ruby/st.h>
36
+
37
+ /* HyperDex */
38
+ #include "hyperdex/client.h"
39
+ #include "hyperdex/datastructures.h"
40
+
41
+ extern VALUE mod_hyperdex;
42
+ static VALUE mod_hyperdex_client;
43
+ static VALUE class_exception;
44
+ static VALUE Set;
45
+ static VALUE class_client;
46
+ static VALUE class_predicate;
47
+ static VALUE class_equals;
48
+ static VALUE class_lessequal;
49
+ static VALUE class_greaterequal;
50
+ static VALUE class_lessthan;
51
+ static VALUE class_greaterthan;
52
+ static VALUE class_range;
53
+ static VALUE class_regex;
54
+ static VALUE class_lengthequals;
55
+ static VALUE class_lengthlessequal;
56
+ static VALUE class_lengthgreaterequal;
57
+ static VALUE class_contains;
58
+
59
+ #define IV2PTR(obj, iv) (void *)NUM2LONG(rb_funcall(rb_iv_get((obj), (iv)), rb_intern("address"), 0))
60
+
61
+ /******************************* Error Handling *******************************/
62
+
63
+ void
64
+ hyperdex_ruby_out_of_memory()
65
+ {
66
+ rb_raise(rb_eNoMemError, "failed to allocate memory");
67
+ }
68
+
69
+ void
70
+ hyperdex_ruby_client_throw_exception(enum hyperdex_client_returncode status,
71
+ const char* error_message)
72
+ {
73
+ VALUE args[2] = { INT2NUM(status), rb_str_new2(error_message) };
74
+ rb_exc_raise(rb_class_new_instance(2, args, class_exception));
75
+ }
76
+
77
+ /******************************* Predicate class ******************************/
78
+
79
+ struct hyperdex_ruby_client_predicate_inner
80
+ {
81
+ VALUE v;
82
+ enum hyperpredicate predicate;
83
+ };
84
+
85
+ struct hyperdex_ruby_client_predicate
86
+ {
87
+ size_t num_checks;
88
+ struct hyperdex_ruby_client_predicate_inner checks[1];
89
+ };
90
+
91
+ /********************************** Ruby -> C *********************************/
92
+
93
+ static const char*
94
+ hyperdex_ruby_client_convert_cstring(VALUE x, const char* error_message)
95
+ {
96
+ if (TYPE(x) == T_SYMBOL)
97
+ {
98
+ return rb_id2name(SYM2ID(x));
99
+ }
100
+ else if (TYPE(x) == T_STRING)
101
+ {
102
+ return StringValueCStr(x);
103
+ }
104
+ else
105
+ {
106
+ rb_exc_raise(rb_exc_new2(rb_eTypeError, error_message));
107
+ abort(); /* unreachable? */
108
+ }
109
+ }
110
+
111
+ typedef int (*elem_string_fptr)(void*, const char*, size_t, enum hyperdex_ds_returncode*);
112
+ typedef int (*elem_int_fptr)(void*, int64_t, enum hyperdex_ds_returncode*);
113
+ typedef int (*elem_float_fptr)(void*, double, enum hyperdex_ds_returncode*);
114
+
115
+ #define HDRB_HANDLE_ELEM_ERROR(X, TYPE) \
116
+ switch (X) \
117
+ { \
118
+ case HYPERDEX_DS_NOMEM: \
119
+ hyperdex_ruby_out_of_memory(); \
120
+ case HYPERDEX_DS_MIXED_TYPES: \
121
+ rb_raise(rb_eTypeError, "Cannot add " TYPE " to a heterogenous container"); \
122
+ case HYPERDEX_DS_SUCCESS: \
123
+ case HYPERDEX_DS_STRING_TOO_LONG: \
124
+ case HYPERDEX_DS_WRONG_STATE: \
125
+ default: \
126
+ rb_raise(rb_eTypeError, "Cannot convert " TYPE " to a HyperDex type"); \
127
+ }
128
+
129
+ static void
130
+ hyperdex_ruby_client_convert_elem(VALUE e,
131
+ void* x,
132
+ elem_string_fptr f_string,
133
+ elem_int_fptr f_int,
134
+ elem_float_fptr f_float)
135
+ {
136
+ enum hyperdex_ds_returncode error;
137
+ const char* tmp_str;
138
+ size_t tmp_str_sz;
139
+ int64_t tmp_i;
140
+ double tmp_d;
141
+
142
+ switch (TYPE(e))
143
+ {
144
+ case T_SYMBOL:
145
+ tmp_str = rb_id2name(SYM2ID(e));
146
+ tmp_str_sz = strlen(tmp_str);
147
+ if (f_string(x, tmp_str, tmp_str_sz, &error) < 0)
148
+ {
149
+ HDRB_HANDLE_ELEM_ERROR(error, "string");
150
+ }
151
+ break;
152
+ case T_STRING:
153
+ tmp_str = StringValuePtr(e);
154
+ tmp_str_sz = RSTRING_LEN(e);
155
+ if (f_string(x, tmp_str, tmp_str_sz, &error) < 0)
156
+ {
157
+ HDRB_HANDLE_ELEM_ERROR(error, "string");
158
+ }
159
+ break;
160
+ case T_FIXNUM:
161
+ case T_BIGNUM:
162
+ tmp_i = NUM2LL(e);
163
+ if (f_int(x, tmp_i, &error) < 0)
164
+ {
165
+ HDRB_HANDLE_ELEM_ERROR(error, "integer");
166
+ }
167
+ break;
168
+ case T_FLOAT:
169
+ tmp_d = NUM2DBL(e);
170
+ if (f_float(x, tmp_d, &error) < 0)
171
+ {
172
+ HDRB_HANDLE_ELEM_ERROR(error, "float");
173
+ }
174
+ break;
175
+ default:
176
+ rb_raise(rb_eTypeError, "Cannot convert object to a HyperDex container element");
177
+ break;
178
+ }
179
+ }
180
+
181
+ static void
182
+ hyperdex_ruby_client_convert_list(struct hyperdex_ds_arena* arena,
183
+ VALUE x,
184
+ const char** value,
185
+ size_t* value_sz,
186
+ enum hyperdatatype* datatype)
187
+ {
188
+ struct hyperdex_ds_list* list;
189
+ enum hyperdex_ds_returncode error;
190
+ VALUE entry;
191
+ ssize_t i = 0;
192
+
193
+ list = hyperdex_ds_allocate_list(arena);
194
+
195
+ if (!list)
196
+ {
197
+ hyperdex_ruby_out_of_memory();
198
+ }
199
+
200
+ for (i = 0; i < RARRAY_LEN(x); ++i)
201
+ {
202
+ entry = rb_ary_entry(x, i);
203
+ hyperdex_ruby_client_convert_elem(entry, list,
204
+ (elem_string_fptr) hyperdex_ds_list_append_string,
205
+ (elem_int_fptr) hyperdex_ds_list_append_int,
206
+ (elem_float_fptr) hyperdex_ds_list_append_float);
207
+ }
208
+
209
+ if (hyperdex_ds_list_finalize(list, &error, value, value_sz, datatype) < 0)
210
+ {
211
+ hyperdex_ruby_out_of_memory();
212
+ }
213
+ }
214
+
215
+ static void
216
+ hyperdex_ruby_client_convert_set(struct hyperdex_ds_arena* arena,
217
+ VALUE _x,
218
+ const char** value,
219
+ size_t* value_sz,
220
+ enum hyperdatatype* datatype)
221
+ {
222
+ struct hyperdex_ds_set* set;
223
+ enum hyperdex_ds_returncode error;
224
+ VALUE entry;
225
+ ssize_t i = 0;
226
+ VALUE x = rb_funcall(_x, rb_intern("to_a"), 0);
227
+
228
+ set = hyperdex_ds_allocate_set(arena);
229
+
230
+ if (!set)
231
+ {
232
+ hyperdex_ruby_out_of_memory();
233
+ }
234
+
235
+ for (i = 0; i < RARRAY_LEN(x); ++i)
236
+ {
237
+ entry = rb_ary_entry(x, i);
238
+ hyperdex_ruby_client_convert_elem(entry, set,
239
+ (elem_string_fptr) hyperdex_ds_set_insert_string,
240
+ (elem_int_fptr) hyperdex_ds_set_insert_int,
241
+ (elem_float_fptr) hyperdex_ds_set_insert_float);
242
+ }
243
+
244
+ if (hyperdex_ds_set_finalize(set, &error, value, value_sz, datatype) < 0)
245
+ {
246
+ hyperdex_ruby_out_of_memory();
247
+ }
248
+ }
249
+
250
+ static void
251
+ hyperdex_ruby_client_convert_map(struct hyperdex_ds_arena* arena,
252
+ VALUE _x,
253
+ const char** value,
254
+ size_t* value_sz,
255
+ enum hyperdatatype* datatype)
256
+ {
257
+ struct hyperdex_ds_map* map;
258
+ enum hyperdex_ds_returncode error;
259
+ VALUE entry;
260
+ VALUE key;
261
+ VALUE val;
262
+ ssize_t i = 0;
263
+ VALUE x = rb_funcall(_x, rb_intern("to_a"), 0);
264
+
265
+ map = hyperdex_ds_allocate_map(arena);
266
+
267
+ if (!map)
268
+ {
269
+ hyperdex_ruby_out_of_memory();
270
+ }
271
+
272
+ for (i = 0; i < RARRAY_LEN(x); ++i)
273
+ {
274
+ entry = rb_ary_entry(x, i);
275
+ key = rb_ary_entry(entry, 0);
276
+ val = rb_ary_entry(entry, 1);
277
+ hyperdex_ruby_client_convert_elem(key, map,
278
+ (elem_string_fptr) hyperdex_ds_map_insert_key_string,
279
+ (elem_int_fptr) hyperdex_ds_map_insert_key_int,
280
+ (elem_float_fptr) hyperdex_ds_map_insert_key_float);
281
+ hyperdex_ruby_client_convert_elem(val, map,
282
+ (elem_string_fptr) hyperdex_ds_map_insert_val_string,
283
+ (elem_int_fptr) hyperdex_ds_map_insert_val_int,
284
+ (elem_float_fptr) hyperdex_ds_map_insert_val_float);
285
+ }
286
+
287
+ if (hyperdex_ds_map_finalize(map, &error, value, value_sz, datatype) < 0)
288
+ {
289
+ hyperdex_ruby_out_of_memory();
290
+ }
291
+ }
292
+
293
+ static void
294
+ hyperdex_ruby_client_convert_type(struct hyperdex_ds_arena* arena,
295
+ VALUE x,
296
+ const char** value,
297
+ size_t* value_sz,
298
+ enum hyperdatatype* datatype)
299
+ {
300
+ enum hyperdex_ds_returncode error;
301
+ const char* tmp_str;
302
+ size_t tmp_str_sz;
303
+ int64_t tmp_i;
304
+ double tmp_d;
305
+
306
+ switch (TYPE(x))
307
+ {
308
+ case T_SYMBOL:
309
+ tmp_str = rb_id2name(SYM2ID(x));
310
+ tmp_str_sz = strlen(tmp_str);
311
+
312
+ if (hyperdex_ds_copy_string(arena, tmp_str, tmp_str_sz,
313
+ &error, value, value_sz) < 0)
314
+ {
315
+ hyperdex_ruby_out_of_memory();
316
+ }
317
+
318
+ *datatype = HYPERDATATYPE_STRING;
319
+ break;
320
+ case T_STRING:
321
+ tmp_str = StringValuePtr(x);
322
+ tmp_str_sz = RSTRING_LEN(x);
323
+
324
+ if (hyperdex_ds_copy_string(arena, tmp_str, tmp_str_sz,
325
+ &error, value, value_sz) < 0)
326
+ {
327
+ hyperdex_ruby_out_of_memory();
328
+ }
329
+
330
+ *datatype = HYPERDATATYPE_STRING;
331
+ break;
332
+ case T_FIXNUM:
333
+ case T_BIGNUM:
334
+ tmp_i = NUM2LL(x);
335
+
336
+ if (hyperdex_ds_copy_int(arena, tmp_i,
337
+ &error, value, value_sz) < 0)
338
+ {
339
+ hyperdex_ruby_out_of_memory();
340
+ }
341
+
342
+ *datatype = HYPERDATATYPE_INT64;
343
+ break;
344
+ case T_FLOAT:
345
+ tmp_d = NUM2DBL(x);
346
+
347
+ if (hyperdex_ds_copy_float(arena, tmp_d,
348
+ &error, value, value_sz) < 0)
349
+ {
350
+ hyperdex_ruby_out_of_memory();
351
+ }
352
+
353
+ *datatype = HYPERDATATYPE_FLOAT;
354
+ break;
355
+ case T_ARRAY:
356
+ hyperdex_ruby_client_convert_list(arena, x, value, value_sz, datatype);
357
+ break;
358
+ case T_HASH:
359
+ hyperdex_ruby_client_convert_map(arena, x, value, value_sz, datatype);
360
+ break;
361
+ case T_OBJECT:
362
+ if (!rb_obj_is_kind_of(x, Set) == Qtrue)
363
+ {
364
+ rb_raise(rb_eTypeError, "Cannot convert object to a HyperDex type");
365
+ break;
366
+ }
367
+
368
+ hyperdex_ruby_client_convert_set(arena, x, value, value_sz, datatype);
369
+ break;
370
+ default:
371
+ rb_raise(rb_eTypeError, "Cannot convert object to a HyperDex type");
372
+ break;
373
+ }
374
+ }
375
+
376
+ static void
377
+ hyperdex_ruby_client_convert_attributes(struct hyperdex_ds_arena* arena,
378
+ VALUE x,
379
+ const struct hyperdex_client_attribute** _attrs,
380
+ size_t* _attrs_sz)
381
+ {
382
+ VALUE hash_pairs = Qnil;
383
+ VALUE hash_pair = Qnil;
384
+ VALUE key = Qnil;
385
+ VALUE val = Qnil;
386
+ struct hyperdex_client_attribute* attrs;
387
+ size_t attrs_sz;
388
+ ssize_t i;
389
+
390
+ if (TYPE(x) != T_HASH)
391
+ {
392
+ rb_exc_raise(rb_exc_new2(rb_eTypeError, "Attributes must be specified as a hash"));
393
+ abort(); /* unreachable? */
394
+ }
395
+
396
+ hash_pairs = rb_funcall(x, rb_intern("to_a"), 0);
397
+ attrs_sz = RARRAY_LEN(hash_pairs);
398
+ attrs = hyperdex_ds_allocate_attribute(arena, attrs_sz);
399
+
400
+ if (!attrs)
401
+ {
402
+ hyperdex_ruby_out_of_memory();
403
+ }
404
+
405
+ *_attrs = attrs;
406
+ *_attrs_sz = attrs_sz;
407
+
408
+ for (i = 0; i < RARRAY_LEN(hash_pairs); ++i)
409
+ {
410
+ hash_pair = rb_ary_entry(hash_pairs, i);
411
+ key = rb_ary_entry(hash_pair, 0);
412
+ val = rb_ary_entry(hash_pair, 1);
413
+
414
+ attrs[i].attr = hyperdex_ruby_client_convert_cstring(key, "Attribute name must be a string or symbol");
415
+ hyperdex_ruby_client_convert_type(arena, val, &attrs[i].value, &attrs[i].value_sz, &attrs[i].datatype);
416
+ }
417
+ }
418
+
419
+ static void
420
+ hyperdex_ruby_client_convert_key(struct hyperdex_ds_arena* arena,
421
+ VALUE x,
422
+ const char** key,
423
+ size_t* key_sz)
424
+ {
425
+ enum hyperdatatype datatype;
426
+ hyperdex_ruby_client_convert_type(arena, x, key, key_sz, &datatype);
427
+ }
428
+
429
+ static void
430
+ hyperdex_ruby_client_convert_limit(struct hyperdex_ds_arena* arena,
431
+ VALUE x,
432
+ uint64_t* limit)
433
+ {
434
+ *limit = rb_num2ulong(x);
435
+ (void) arena;
436
+ }
437
+
438
+ static void
439
+ hyperdex_ruby_client_convert_mapattributes(struct hyperdex_ds_arena* arena,
440
+ VALUE x,
441
+ const struct hyperdex_client_map_attribute** _mapattrs,
442
+ size_t* _mapattrs_sz)
443
+ {
444
+ VALUE outer_pairs = Qnil;
445
+ VALUE outer_pair = Qnil;
446
+ VALUE inner_pairs = Qnil;
447
+ VALUE inner_pair = Qnil;
448
+ VALUE attr = Qnil;
449
+ VALUE key = Qnil;
450
+ VALUE val = Qnil;
451
+ struct hyperdex_client_map_attribute* mapattrs = NULL;
452
+ size_t mapattrs_sz = 0;
453
+ size_t mapattrs_idx = 0;
454
+ ssize_t i = 0;
455
+ size_t j = 0;
456
+
457
+ if (TYPE(x) != T_HASH)
458
+ {
459
+ rb_exc_raise(rb_exc_new2(rb_eTypeError, "Map attributes must be specified as a hash"));
460
+ abort(); /* unreachable? */
461
+ }
462
+
463
+ outer_pairs = rb_funcall(x, rb_intern("to_a"), 0);
464
+
465
+ for (i = 0; i < RARRAY_LEN(outer_pairs); ++i)
466
+ {
467
+ outer_pair = rb_ary_entry(outer_pairs, i);
468
+ inner_pairs = rb_ary_entry(outer_pair, 1);
469
+
470
+ if (TYPE(inner_pairs) != T_HASH)
471
+ {
472
+ rb_exc_raise(rb_exc_new2(rb_eTypeError, "Map attributes must be specified as a hash"));
473
+ abort(); /* unreachable? */
474
+ }
475
+
476
+ mapattrs_sz += RHASH_SIZE(inner_pairs);
477
+ }
478
+
479
+ mapattrs = hyperdex_ds_allocate_map_attribute(arena, mapattrs_sz);
480
+
481
+ if (!mapattrs)
482
+ {
483
+ hyperdex_ruby_out_of_memory();
484
+ }
485
+
486
+ *_mapattrs = mapattrs;
487
+ *_mapattrs_sz = mapattrs_sz;
488
+
489
+ for (i = 0; i < RARRAY_LEN(outer_pairs); ++i)
490
+ {
491
+ outer_pair = rb_ary_entry(outer_pairs, i);
492
+ attr = rb_ary_entry(outer_pair, 0);
493
+ inner_pairs = rb_ary_entry(outer_pair, 1);
494
+ inner_pairs = rb_funcall(inner_pairs, rb_intern("to_a"), 0);
495
+
496
+ for (j = 0; RARRAY_LEN(inner_pairs); ++j)
497
+ {
498
+ inner_pair = rb_ary_entry(inner_pairs, j);
499
+ key = rb_ary_entry(inner_pair, 0);
500
+ val = rb_ary_entry(inner_pair, 1);
501
+ mapattrs[mapattrs_idx].attr = hyperdex_ruby_client_convert_cstring(attr, "Attribute name must be a string or symbol");
502
+ hyperdex_ruby_client_convert_type(arena, key,
503
+ &mapattrs[mapattrs_idx].map_key,
504
+ &mapattrs[mapattrs_idx].map_key_sz,
505
+ &mapattrs[mapattrs_idx].map_key_datatype);
506
+ hyperdex_ruby_client_convert_type(arena, val,
507
+ &mapattrs[mapattrs_idx].value,
508
+ &mapattrs[mapattrs_idx].value_sz,
509
+ &mapattrs[mapattrs_idx].value_datatype);
510
+ ++mapattrs_idx;
511
+ }
512
+ }
513
+ }
514
+
515
+ static void
516
+ hyperdex_ruby_client_convert_maxmin(struct hyperdex_ds_arena* arena,
517
+ VALUE x,
518
+ int* maxmin)
519
+ {
520
+ *maxmin = x == Qtrue ? 1: 0;
521
+ (void) arena;
522
+ }
523
+
524
+ static size_t
525
+ hyperdex_ruby_client_estimate_predicate_size(VALUE x)
526
+ {
527
+ VALUE pred = Qnil;
528
+ struct hyperdex_ruby_client_predicate* p = NULL;
529
+ ssize_t i = 0;
530
+ size_t sum = 0;
531
+
532
+ if (TYPE(x) == T_DATA &&
533
+ rb_obj_is_kind_of(x, class_predicate) == Qtrue)
534
+ {
535
+ Data_Get_Struct(x, struct hyperdex_ruby_client_predicate, p);
536
+ return p->num_checks;
537
+ }
538
+ else if (TYPE(x) == T_ARRAY &&
539
+ RARRAY_LEN(x) > 0 &&
540
+ rb_obj_is_kind_of(rb_ary_entry(x, 0), class_predicate) == Qtrue)
541
+ {
542
+ for (i = 0; i < RARRAY_LEN(x); ++i)
543
+ {
544
+ pred = rb_ary_entry(x, i);
545
+
546
+ if (TYPE(pred) != T_DATA ||
547
+ rb_obj_is_kind_of(pred, class_predicate) != Qtrue)
548
+ {
549
+ rb_raise(rb_eTypeError, "Cannot convert predicate to a HyperDex type");
550
+ return 0;
551
+ }
552
+
553
+ Data_Get_Struct(pred, struct hyperdex_ruby_client_predicate, p);
554
+ sum += p->num_checks;
555
+ }
556
+
557
+ return sum;
558
+ }
559
+ else
560
+ {
561
+ return 1;
562
+ }
563
+ }
564
+
565
+ static size_t
566
+ hyperdex_ruby_client_convert_predicate(struct hyperdex_ds_arena* arena,
567
+ const char* attr,
568
+ VALUE x,
569
+ struct hyperdex_client_attribute_check* checks,
570
+ size_t checks_idx)
571
+ {
572
+ VALUE pred = Qnil;
573
+ struct hyperdex_ruby_client_predicate* p = NULL;
574
+ size_t i = 0;
575
+
576
+ if (TYPE(x) == T_DATA &&
577
+ rb_obj_is_kind_of(x, class_predicate) == Qtrue)
578
+ {
579
+ Data_Get_Struct(x, struct hyperdex_ruby_client_predicate, p);
580
+
581
+ for (i = 0; i < p->num_checks; ++i)
582
+ {
583
+ checks[checks_idx + i].attr = attr;
584
+ checks[checks_idx + i].predicate = p->checks[i].predicate;
585
+ hyperdex_ruby_client_convert_type(arena, p->checks[i].v,
586
+ &checks[checks_idx + i].value,
587
+ &checks[checks_idx + i].value_sz,
588
+ &checks[checks_idx + i].datatype);
589
+ }
590
+
591
+ return checks_idx + p->num_checks;
592
+ }
593
+ else if (TYPE(x) == T_ARRAY &&
594
+ RARRAY_LEN(x) > 0 &&
595
+ rb_obj_is_kind_of(rb_ary_entry(x, 0), class_predicate) == Qtrue)
596
+ {
597
+ for (i = 0; i < (size_t)RARRAY_LEN(x); ++i)
598
+ {
599
+ pred = rb_ary_entry(x, i);
600
+ assert(TYPE(pred) == T_DATA);
601
+ assert(rb_obj_is_kind_of(pred, class_predicate) == Qtrue);
602
+ checks_idx = hyperdex_ruby_client_convert_predicate(arena, attr, pred, checks, checks_idx);
603
+ }
604
+
605
+ return checks_idx;
606
+ }
607
+ else
608
+ {
609
+ checks[checks_idx].attr = attr;
610
+ checks[checks_idx].predicate = HYPERPREDICATE_EQUALS,
611
+ hyperdex_ruby_client_convert_type(arena, x,
612
+ &checks[checks_idx].value,
613
+ &checks[checks_idx].value_sz,
614
+ &checks[checks_idx].datatype);
615
+ return checks_idx + 1;
616
+ }
617
+ }
618
+
619
+ static void
620
+ hyperdex_ruby_client_convert_predicates(struct hyperdex_ds_arena* arena,
621
+ VALUE x,
622
+ const struct hyperdex_client_attribute_check** _checks,
623
+ size_t* _checks_sz)
624
+ {
625
+ VALUE hash_pairs = Qnil;
626
+ VALUE hash_pair = Qnil;
627
+ VALUE key = Qnil;
628
+ VALUE val = Qnil;
629
+ struct hyperdex_client_attribute_check* checks = NULL;
630
+ size_t checks_sz = 0;
631
+ size_t checks_idx = 0;
632
+ ssize_t i = 0;
633
+ const char* attr;
634
+
635
+ if (TYPE(x) != T_HASH)
636
+ {
637
+ rb_exc_raise(rb_exc_new2(rb_eTypeError, "Predicates must be specified as a hash"));
638
+ abort(); /* unreachable? */
639
+ }
640
+
641
+ hash_pairs = rb_funcall(x, rb_intern("to_a"), 0);
642
+
643
+ /* figure out how many checks to allocate */
644
+ for (i = 0; i < RARRAY_LEN(hash_pairs); ++i)
645
+ {
646
+ hash_pair = rb_ary_entry(hash_pairs, i);
647
+ val = rb_ary_entry(hash_pair, 1);
648
+ checks_sz += hyperdex_ruby_client_estimate_predicate_size(val);
649
+ }
650
+
651
+ checks = hyperdex_ds_allocate_attribute_check(arena, checks_sz);
652
+
653
+ if (!checks)
654
+ {
655
+ hyperdex_ruby_out_of_memory();
656
+ }
657
+
658
+ *_checks = checks;
659
+ *_checks_sz = checks_sz;
660
+ checks_idx = 0;
661
+
662
+ /* turn the predicate into checks */
663
+ for (i = 0; i < RARRAY_LEN(hash_pairs); ++i)
664
+ {
665
+ hash_pair = rb_ary_entry(hash_pairs, i);
666
+ key = rb_ary_entry(hash_pair, 0);
667
+ val = rb_ary_entry(hash_pair, 1);
668
+
669
+ attr = hyperdex_ruby_client_convert_cstring(key, "Attribute name must be a string or symbol");
670
+ checks_idx = hyperdex_ruby_client_convert_predicate(arena, attr, val, checks, checks_idx);
671
+ }
672
+ }
673
+
674
+ static void
675
+ hyperdex_ruby_client_convert_attributenames(struct hyperdex_ds_arena* arena,
676
+ VALUE x,
677
+ const char*** names, size_t* names_sz)
678
+ {
679
+ size_t i = 0;
680
+ *names_sz = RARRAY_LEN(x);
681
+ *names = hyperdex_ds_malloc(arena, sizeof(char*) * (*names_sz));
682
+
683
+ if (!(*names))
684
+ {
685
+ hyperdex_ruby_out_of_memory();
686
+ }
687
+
688
+ for (i = 0; i < *names_sz; ++i)
689
+ {
690
+ (*names)[i] = hyperdex_ruby_client_convert_cstring(rb_ary_entry(x, i),
691
+ "Attribute name must be a string or symbol");
692
+ }
693
+ }
694
+
695
+ static void
696
+ hyperdex_ruby_client_convert_sortby(struct hyperdex_ds_arena* arena,
697
+ VALUE x,
698
+ const char** sortby)
699
+ {
700
+ *sortby = hyperdex_ruby_client_convert_cstring(x, "sortby must be a string or symbol");
701
+ (void) arena;
702
+ }
703
+
704
+ static void
705
+ hyperdex_ruby_client_convert_spacename(struct hyperdex_ds_arena* arena,
706
+ VALUE x,
707
+ const char** spacename)
708
+ {
709
+ *spacename = hyperdex_ruby_client_convert_cstring(x, "spacename must be a string or symbol");
710
+ (void) arena;
711
+ }
712
+
713
+ /******************************** Client Class ********************************/
714
+
715
+ #include "definitions.c"
716
+
717
+ /********************************* Predicates *********************************/
718
+
719
+ static void
720
+ hyperdex_ruby_client_predicate_mark(struct hyperdex_ruby_client_predicate* pred)
721
+ {
722
+ size_t i = 0;
723
+
724
+ if (!pred)
725
+ {
726
+ return;
727
+ }
728
+
729
+ for (i = 0; i < pred->num_checks; ++i)
730
+ {
731
+ rb_gc_mark(pred->checks[i].v);
732
+ }
733
+ }
734
+
735
+ static VALUE
736
+ hyperdex_ruby_client_predicate_alloc1(VALUE class)
737
+ {
738
+ struct hyperdex_ruby_client_predicate* pred = NULL;
739
+ size_t sz = offsetof(struct hyperdex_ruby_client_predicate, checks)
740
+ + sizeof(struct hyperdex_ruby_client_predicate_inner);
741
+ pred = malloc(sz);
742
+
743
+ if (!pred)
744
+ {
745
+ hyperdex_ruby_out_of_memory();
746
+ return Qnil;
747
+ }
748
+
749
+ memset(pred, 0, sz);
750
+ pred->num_checks = 1;
751
+ return Data_Wrap_Struct(class, hyperdex_ruby_client_predicate_mark, free, pred);
752
+ }
753
+
754
+ static VALUE
755
+ hyperdex_ruby_client_predicate_alloc2(VALUE class)
756
+ {
757
+ struct hyperdex_ruby_client_predicate* pred = NULL;
758
+ size_t sz = offsetof(struct hyperdex_ruby_client_predicate, checks)
759
+ + 2 * sizeof(struct hyperdex_ruby_client_predicate_inner);
760
+ pred = malloc(sz);
761
+
762
+ if (!pred)
763
+ {
764
+ hyperdex_ruby_out_of_memory();
765
+ return Qnil;
766
+ }
767
+
768
+ memset(pred, 0, sz);
769
+ pred->num_checks = 2;
770
+ return Data_Wrap_Struct(class, hyperdex_ruby_client_predicate_mark, free, pred);
771
+ }
772
+
773
+ static VALUE
774
+ hyperdex_ruby_client_predicate_init(VALUE self)
775
+ {
776
+ struct hyperdex_ruby_client_predicate* pred = NULL;
777
+ Data_Get_Struct(self, struct hyperdex_ruby_client_predicate, pred);
778
+ pred->checks[0].v = Qnil;
779
+ pred->checks[0].predicate = HYPERPREDICATE_FAIL;
780
+ return self;
781
+ }
782
+
783
+ static VALUE
784
+ hyperdex_ruby_client_predicate_equals_init(VALUE self, VALUE v)
785
+ {
786
+ struct hyperdex_ruby_client_predicate* pred = NULL;
787
+ Data_Get_Struct(self, struct hyperdex_ruby_client_predicate, pred);
788
+ pred->checks[0].v = v;
789
+ pred->checks[0].predicate = HYPERPREDICATE_EQUALS;
790
+ return self;
791
+ }
792
+
793
+ static VALUE
794
+ hyperdex_ruby_client_predicate_lessequal_init(VALUE self, VALUE v)
795
+ {
796
+ struct hyperdex_ruby_client_predicate* pred = NULL;
797
+ Data_Get_Struct(self, struct hyperdex_ruby_client_predicate, pred);
798
+ pred->checks[0].v = v;
799
+ pred->checks[0].predicate = HYPERPREDICATE_LESS_EQUAL;
800
+ return self;
801
+ }
802
+
803
+ static VALUE
804
+ hyperdex_ruby_client_predicate_greaterequal_init(VALUE self, VALUE v)
805
+ {
806
+ struct hyperdex_ruby_client_predicate* pred = NULL;
807
+ Data_Get_Struct(self, struct hyperdex_ruby_client_predicate, pred);
808
+ pred->checks[0].v = v;
809
+ pred->checks[0].predicate = HYPERPREDICATE_GREATER_EQUAL;
810
+ return self;
811
+ }
812
+
813
+ static VALUE
814
+ hyperdex_ruby_client_predicate_lessthan_init(VALUE self, VALUE v)
815
+ {
816
+ struct hyperdex_ruby_client_predicate* pred = NULL;
817
+ Data_Get_Struct(self, struct hyperdex_ruby_client_predicate, pred);
818
+ pred->checks[0].v = v;
819
+ pred->checks[0].predicate = HYPERPREDICATE_LESS_THAN;
820
+ return self;
821
+ }
822
+
823
+ static VALUE
824
+ hyperdex_ruby_client_predicate_greaterthan_init(VALUE self, VALUE v)
825
+ {
826
+ struct hyperdex_ruby_client_predicate* pred = NULL;
827
+ Data_Get_Struct(self, struct hyperdex_ruby_client_predicate, pred);
828
+ pred->checks[0].v = v;
829
+ pred->checks[0].predicate = HYPERPREDICATE_GREATER_THAN;
830
+ return self;
831
+ }
832
+
833
+ static VALUE
834
+ hyperdex_ruby_client_predicate_range_init(VALUE self, VALUE lower, VALUE upper)
835
+ {
836
+ struct hyperdex_ruby_client_predicate* pred = NULL;
837
+ Data_Get_Struct(self, struct hyperdex_ruby_client_predicate, pred);
838
+ pred->checks[0].v = lower;
839
+ pred->checks[0].predicate = HYPERPREDICATE_GREATER_EQUAL;
840
+ pred->checks[1].v = upper;
841
+ pred->checks[1].predicate = HYPERPREDICATE_LESS_EQUAL;
842
+ return self;
843
+ }
844
+
845
+ static VALUE
846
+ hyperdex_ruby_client_predicate_regex_init(VALUE self, VALUE v)
847
+ {
848
+ struct hyperdex_ruby_client_predicate* pred = NULL;
849
+ Data_Get_Struct(self, struct hyperdex_ruby_client_predicate, pred);
850
+ pred->checks[0].v = v;
851
+ pred->checks[0].predicate = HYPERPREDICATE_REGEX;
852
+ return self;
853
+ }
854
+
855
+ static VALUE
856
+ hyperdex_ruby_client_predicate_lengthequals_init(VALUE self, VALUE v)
857
+ {
858
+ struct hyperdex_ruby_client_predicate* pred = NULL;
859
+ Data_Get_Struct(self, struct hyperdex_ruby_client_predicate, pred);
860
+ pred->checks[0].v = v;
861
+ pred->checks[0].predicate = HYPERPREDICATE_LENGTH_EQUALS;
862
+ return self;
863
+ }
864
+
865
+ static VALUE
866
+ hyperdex_ruby_client_predicate_lengthlessequal_init(VALUE self, VALUE v)
867
+ {
868
+ struct hyperdex_ruby_client_predicate* pred = NULL;
869
+ Data_Get_Struct(self, struct hyperdex_ruby_client_predicate, pred);
870
+ pred->checks[0].v = v;
871
+ pred->checks[0].predicate = HYPERPREDICATE_LENGTH_LESS_EQUAL;
872
+ return self;
873
+ }
874
+
875
+ static VALUE
876
+ hyperdex_ruby_client_predicate_lengthgreaterequal_init(VALUE self, VALUE v)
877
+ {
878
+ struct hyperdex_ruby_client_predicate* pred = NULL;
879
+ Data_Get_Struct(self, struct hyperdex_ruby_client_predicate, pred);
880
+ pred->checks[0].v = v;
881
+ pred->checks[0].predicate = HYPERPREDICATE_LENGTH_GREATER_EQUAL;
882
+ return self;
883
+ }
884
+
885
+ static VALUE
886
+ hyperdex_ruby_client_predicate_contains_init(VALUE self, VALUE v)
887
+ {
888
+ struct hyperdex_ruby_client_predicate* pred = NULL;
889
+ Data_Get_Struct(self, struct hyperdex_ruby_client_predicate, pred);
890
+ pred->checks[0].v = v;
891
+ pred->checks[0].predicate = HYPERPREDICATE_CONTAINS;
892
+ return self;
893
+ }
894
+
895
+ /******************************* Inititalization ******************************/
896
+
897
+ void
898
+ Init_hyperdex_client()
899
+ {
900
+ /* require the set type */
901
+ rb_require("set");
902
+ Set = rb_path2class("Set");
903
+
904
+ /* setup the module */
905
+ mod_hyperdex_client = rb_define_module_under(mod_hyperdex, "Client");
906
+
907
+ /* create the Exception class */
908
+ class_exception = rb_define_class_under(mod_hyperdex_client, "HyperDexClientException", rb_eStandardError);
909
+
910
+ /* create the Client class */
911
+ class_client = rb_define_class_under(mod_hyperdex_client, "Client", rb_cObject);
912
+
913
+ /* include the generated rb_define_* calls */
914
+ #include "prototypes.c"
915
+
916
+ /* create the Predicate class */
917
+ class_predicate = rb_define_class_under(mod_hyperdex_client, "Predicate", rb_cObject);
918
+ rb_define_alloc_func(class_predicate, hyperdex_ruby_client_predicate_alloc1);
919
+ rb_define_method(class_predicate, "initialize", hyperdex_ruby_client_predicate_init, 1);
920
+
921
+ /* create the Equals class */
922
+ class_equals = rb_define_class_under(mod_hyperdex_client, "Equals", class_predicate);
923
+ rb_define_alloc_func(class_equals , hyperdex_ruby_client_predicate_alloc1);
924
+ rb_define_method(class_equals , "initialize", hyperdex_ruby_client_predicate_equals_init, 1);
925
+
926
+ /* create the LessEqual class */
927
+ class_lessequal = rb_define_class_under(mod_hyperdex_client, "LessEqual", class_predicate);
928
+ rb_define_alloc_func(class_lessequal , hyperdex_ruby_client_predicate_alloc1);
929
+ rb_define_method(class_lessequal , "initialize", hyperdex_ruby_client_predicate_lessequal_init, 1);
930
+
931
+ /* create the GreaterEqual class */
932
+ class_greaterequal = rb_define_class_under(mod_hyperdex_client, "GreaterEqual", class_predicate);
933
+ rb_define_alloc_func(class_greaterequal , hyperdex_ruby_client_predicate_alloc1);
934
+ rb_define_method(class_greaterequal , "initialize", hyperdex_ruby_client_predicate_greaterequal_init, 1);
935
+
936
+ /* create the LessThan class */
937
+ class_lessthan = rb_define_class_under(mod_hyperdex_client, "LessThan", class_predicate);
938
+ rb_define_alloc_func(class_lessthan , hyperdex_ruby_client_predicate_alloc1);
939
+ rb_define_method(class_lessthan , "initialize", hyperdex_ruby_client_predicate_lessthan_init, 1);
940
+
941
+ /* create the GreaterThan class */
942
+ class_greaterthan = rb_define_class_under(mod_hyperdex_client, "GreaterThan", class_predicate);
943
+ rb_define_alloc_func(class_greaterthan , hyperdex_ruby_client_predicate_alloc1);
944
+ rb_define_method(class_greaterthan , "initialize", hyperdex_ruby_client_predicate_greaterthan_init, 1);
945
+
946
+ /* create the Range class */
947
+ class_range = rb_define_class_under(mod_hyperdex_client, "Range", class_predicate);
948
+ rb_define_alloc_func(class_range , hyperdex_ruby_client_predicate_alloc2);
949
+ rb_define_method(class_range , "initialize", hyperdex_ruby_client_predicate_range_init, 2);
950
+
951
+ /* create the Regex class */
952
+ class_regex = rb_define_class_under(mod_hyperdex_client, "Regex", class_predicate);
953
+ rb_define_alloc_func(class_regex , hyperdex_ruby_client_predicate_alloc1);
954
+ rb_define_method(class_regex , "initialize", hyperdex_ruby_client_predicate_regex_init, 1);
955
+
956
+ /* create the LengthEquals class */
957
+ class_lengthequals = rb_define_class_under(mod_hyperdex_client, "LengthEquals", class_predicate);
958
+ rb_define_alloc_func(class_lengthequals , hyperdex_ruby_client_predicate_alloc1);
959
+ rb_define_method(class_lengthequals , "initialize", hyperdex_ruby_client_predicate_lengthequals_init, 1);
960
+
961
+ /* create the LengthLessEqual class */
962
+ class_lengthlessequal = rb_define_class_under(mod_hyperdex_client, "LengthLessEqual", class_predicate);
963
+ rb_define_alloc_func(class_lengthlessequal , hyperdex_ruby_client_predicate_alloc1);
964
+ rb_define_method(class_lengthlessequal , "initialize", hyperdex_ruby_client_predicate_lengthlessequal_init, 1);
965
+
966
+ /* create the LengthGreaterEqual class */
967
+ class_lengthgreaterequal = rb_define_class_under(mod_hyperdex_client, "LengthGreaterEqual", class_predicate);
968
+ rb_define_alloc_func(class_lengthgreaterequal , hyperdex_ruby_client_predicate_alloc1);
969
+ rb_define_method(class_lengthgreaterequal , "initialize", hyperdex_ruby_client_predicate_lengthgreaterequal_init, 1);
970
+
971
+ /* create the Contains class */
972
+ class_contains = rb_define_class_under(mod_hyperdex_client, "Contains", class_predicate);
973
+ rb_define_alloc_func(class_contains , hyperdex_ruby_client_predicate_alloc1);
974
+ rb_define_method(class_contains , "initialize", hyperdex_ruby_client_predicate_contains_init, 1);
975
+ }