usamin 7.7.9 → 7.7.10

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,29 @@
1
+ #ifndef USAMIN_RB_USAMIN_ARRAY_HPP
2
+ #define USAMIN_RB_USAMIN_ARRAY_HPP
3
+
4
+ #include <ruby.h>
5
+ #include "rubynized_rapidjson.hpp"
6
+
7
+ void flatten_array(RubynizedValue &value, VALUE array, int level, VALUE root_document);
8
+
9
+ VALUE w_array_operator_indexer(const int argc, const VALUE *argv, const VALUE self);
10
+ VALUE w_array_at(const VALUE self, const VALUE nth);
11
+ VALUE w_array_compact(const VALUE self);
12
+ VALUE w_array_dig(const int argc, const VALUE *argv, const VALUE self);
13
+ VALUE w_array_each(const VALUE self);
14
+ VALUE w_array_each_index(const VALUE self);
15
+ VALUE w_array_isempty(const VALUE self);
16
+ VALUE w_array_fetch(const int argc, const VALUE *argv, const VALUE self);
17
+ VALUE w_array_find_index(const int argc, const VALUE *argv, const VALUE self);
18
+ VALUE w_array_flatten(const int argc, const VALUE *argv, const VALUE self);
19
+ VALUE w_array_first(const int argc, const VALUE *argv, const VALUE self);
20
+ VALUE w_array_include(const VALUE self, const VALUE val);
21
+ VALUE w_array_inspect(const VALUE self);
22
+ VALUE w_array_last(const int argc, const VALUE *argv, const VALUE self);
23
+ VALUE w_array_length(const VALUE self);
24
+ VALUE w_array_reverse(const VALUE self);
25
+ VALUE w_array_rindex(const int argc, const VALUE *argv, const VALUE self);
26
+ VALUE w_array_rotate(const int argc, const VALUE *argv, const VALUE self);
27
+ VALUE w_array_eval(const VALUE self);
28
+
29
+ #endif
@@ -0,0 +1,517 @@
1
+ #include <rapidjson/document.h>
2
+ #include <ruby.h>
3
+ #include <ruby/version.h>
4
+ #include "rb_usamin_array.hpp"
5
+ #include "usamin_value.hpp"
6
+ #include "parser_helper.hpp"
7
+
8
+ /*
9
+ * @return [Object | nil]
10
+ *
11
+ * @note This method has linear time complexity.
12
+ */
13
+ VALUE w_hash_operator_indexer(const VALUE self, const VALUE key) {
14
+ UsaminValue *value = get_value(self);
15
+ check_object(value);
16
+ for (auto &m : value->value->GetObject())
17
+ if (str_compare_xx(key, m.name))
18
+ return eval(m.value, value->root_document);
19
+ return Qnil;
20
+ }
21
+
22
+ /*
23
+ * @return [::Array | nil]
24
+ *
25
+ * @note This method has linear time complexity.
26
+ */
27
+ VALUE w_hash_assoc(const VALUE self, const VALUE key) {
28
+ UsaminValue *value = get_value(self);
29
+ check_object(value);
30
+ for (auto &m : value->value->GetObject())
31
+ if (str_compare_xx(key, m.name))
32
+ return rb_assoc_new(eval_str(m.name), eval(m.value, value->root_document));
33
+ return Qnil;
34
+ }
35
+
36
+ /*
37
+ * @return [::Hash]
38
+ */
39
+ VALUE w_hash_compact(const VALUE self) {
40
+ UsaminValue *value = get_value(self);
41
+ check_object(value);
42
+ VALUE hash = rb_hash_new();
43
+ for (auto &m : value->value->GetObject())
44
+ if (!m.value.IsNull())
45
+ rb_hash_aset(hash, eval(m.name, value->root_document), eval(m.value, value->root_document));
46
+ return hash;
47
+ }
48
+
49
+ /*
50
+ * @return [::Hash]
51
+ */
52
+ VALUE w_hash_deconstruct_keys(const VALUE self, const VALUE keys) {
53
+ UsaminValue *value = get_value(self);
54
+ check_object(value);
55
+ if (NIL_P(keys))
56
+ return eval_object(*(value->value), value->root_document, 1);
57
+ VALUE hash_keys = rb_hash_new();
58
+ VALUE *key_iter = RARRAY_PTR(keys);
59
+ const VALUE *key_iter_end = key_iter + RARRAY_LEN(keys);
60
+ for (VALUE *k = key_iter; k < key_iter_end; k++)
61
+ rb_hash_aset(hash_keys, *k, Qtrue);
62
+ VALUE hash = rb_hash_new();
63
+ for (auto &m : value->value->GetObject()) {
64
+ VALUE name = rb_to_symbol(new_utf8_str(m.name.GetString(), m.name.GetStringLength()));
65
+ if (!NIL_P(rb_hash_lookup(hash_keys, name)))
66
+ rb_hash_aset(hash, name, eval(m.value, value->root_document));
67
+ }
68
+ return hash;
69
+ }
70
+
71
+ /*
72
+ * @return [Object | nil]
73
+ */
74
+ VALUE w_hash_dig(const int argc, const VALUE *argv, const VALUE self) {
75
+ rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS);
76
+ VALUE value = w_hash_operator_indexer(self, argv[0]);
77
+ if (argc == 1)
78
+ return value;
79
+ else if (value == Qnil)
80
+ return Qnil;
81
+ extern ID id_dig;
82
+ return rb_funcall3(value, id_dig, argc - 1, argv + 1);
83
+ }
84
+
85
+ static VALUE hash_enum_size(const VALUE self, const VALUE, const VALUE) {
86
+ return UINT2NUM(get_value(self)->value->MemberCount());
87
+ }
88
+
89
+ /*
90
+ * @yield [key, value]
91
+ * @yieldparam key [String]
92
+ * @yieldparam value [Object]
93
+ * @return [Enumerator | self]
94
+ */
95
+ VALUE w_hash_each(const VALUE self) {
96
+ UsaminValue *value = get_value(self);
97
+ check_object(value);
98
+ RETURN_SIZED_ENUMERATOR(self, 0, nullptr, hash_enum_size);
99
+ if (rb_proc_arity(rb_block_proc()) > 1) {
100
+ for (auto &m : value->value->GetObject()) {
101
+ VALUE args[] = {eval_str(m.name), eval(m.value, value->root_document)};
102
+ rb_yield_values2(2, args);
103
+ }
104
+ } else {
105
+ for (auto &m : value->value->GetObject())
106
+ rb_yield(rb_assoc_new(eval_str(m.name), eval(m.value, value->root_document)));
107
+ }
108
+ return self;
109
+ }
110
+
111
+ /*
112
+ * @yield [key]
113
+ * @yieldparam key [String]
114
+ * @return [Enumerator | self]
115
+ */
116
+ VALUE w_hash_each_key(const VALUE self) {
117
+ UsaminValue *value = get_value(self);
118
+ check_object(value);
119
+ RETURN_SIZED_ENUMERATOR(self, 0, nullptr, hash_enum_size);
120
+ for (auto &m : value->value->GetObject())
121
+ rb_yield(eval_str(m.name));
122
+ return self;
123
+ }
124
+
125
+ /*
126
+ * @yield [value]
127
+ * @return [Enumerator | self]
128
+ */
129
+ VALUE w_hash_each_value(const VALUE self) {
130
+ UsaminValue *value = get_value(self);
131
+ check_object(value);
132
+ RETURN_SIZED_ENUMERATOR(self, 0, nullptr, hash_enum_size);
133
+ for (auto &m : value->value->GetObject())
134
+ rb_yield(eval(m.value, value->root_document));
135
+ return self;
136
+ }
137
+
138
+ VALUE w_hash_isempty(const VALUE self) {
139
+ UsaminValue *value = get_value(self);
140
+ check_object(value);
141
+ return value->value->MemberCount() == 0 ? Qtrue : Qfalse;
142
+ }
143
+
144
+ /*
145
+ * @overload fetch(key, default = nil)
146
+ * @param [String] key
147
+ * @param [Object] default
148
+ * @return [Object]
149
+ *
150
+ * @overload fetch(key)
151
+ * @param [String] key
152
+ * @yield [key]
153
+ * @return [Object]
154
+ */
155
+ VALUE w_hash_fetch(const int argc, const VALUE *argv, const VALUE self) {
156
+ rb_check_arity(argc, 1, 2);
157
+ if (argc == 2 && rb_block_given_p())
158
+ rb_warn("block supersedes default value argument");
159
+ UsaminValue *value = get_value(self);
160
+ check_object(value);
161
+ for (auto &m : value->value->GetObject())
162
+ if (str_compare_xx(argv[0], m.name))
163
+ return eval(m.value, value->root_document);
164
+ return rb_block_given_p() ? rb_yield(argv[0]) : argc == 2 ? argv[1] : Qnil;
165
+ }
166
+
167
+ /*
168
+ * @param [String] key
169
+ * @return [::Array<Object>]
170
+ */
171
+ VALUE w_hash_fetch_values(const int argc, VALUE *argv, const VALUE self) {
172
+ UsaminValue *value = get_value(self);
173
+ check_object(value);
174
+ VALUE ret = rb_ary_new2(argc);
175
+ for (int i = 0; i < argc; i++) {
176
+ bool found = false;
177
+ for (auto &m : value->value->GetObject()) {
178
+ if (str_compare_xx(argv[i], m.name)) {
179
+ rb_ary_push(ret, eval(m.value, value->root_document));
180
+ found = true;
181
+ break;
182
+ }
183
+ }
184
+ if (!found) {
185
+ if (rb_block_given_p()) {
186
+ rb_ary_push(ret, rb_yield(argv[i]));
187
+ } else {
188
+ rb_ary_free(ret);
189
+ rb_raise(rb_eKeyError, "key not found: \"%s\"", StringValueCStr(argv[i]));
190
+ return Qnil;
191
+ }
192
+ }
193
+ }
194
+ return ret;
195
+ }
196
+
197
+ /*
198
+ * @overload flatten(level = 1)
199
+ * @return [::Array<Object>]
200
+ */
201
+ VALUE w_hash_flatten(const int argc, const VALUE *argv, const VALUE self) {
202
+ rb_check_arity(argc, 0, 1);
203
+ UsaminValue *value = get_value(self);
204
+ check_object(value);
205
+
206
+ int level = 1;
207
+ if (argc == 1 && !NIL_P(argv[0])) {
208
+ level = NUM2INT(argv[0]);
209
+ if (level < 0)
210
+ level = -1;
211
+ }
212
+
213
+ if (level == 0) {
214
+ VALUE ret = rb_ary_new2(value->value->MemberCount());
215
+ for (auto &m : value->value->GetObject())
216
+ rb_ary_push(ret, rb_ary_new3(2, eval_str(m.name), eval(m.value, value->root_document)));
217
+ return ret;
218
+ }
219
+
220
+ VALUE ret = rb_ary_new2(value->value->MemberCount() * 2);
221
+ if (level == 1) {
222
+ for (auto &m : value->value->GetObject()) {
223
+ rb_ary_push(ret, eval_str(m.name));
224
+ rb_ary_push(ret, eval(m.value, value->root_document));
225
+ }
226
+ } else {
227
+ for (auto &m : value->value->GetObject()) {
228
+ rb_ary_push(ret, eval_str(m.name));
229
+ if (m.value.IsArray())
230
+ flatten_array(m.value, ret, level > 0 ? level - 2 : level, value->root_document);
231
+ else
232
+ rb_ary_push(ret, eval(m.value, value->root_document));
233
+ }
234
+ }
235
+ return ret;
236
+ }
237
+
238
+ /*
239
+ * @note This method has linear time complexity.
240
+ */
241
+ VALUE w_hash_haskey(const VALUE self, const VALUE key) {
242
+ UsaminValue *value = get_value(self);
243
+ check_object(value);
244
+ for (auto &m : value->value->GetObject())
245
+ if (str_compare_xx(key, m.name))
246
+ return Qtrue;
247
+ return Qfalse;
248
+ }
249
+
250
+ VALUE w_hash_hasvalue(const VALUE self, const VALUE val) {
251
+ UsaminValue *value = get_value(self);
252
+ check_object(value);
253
+ for (auto &m : value->value->GetObject())
254
+ if (rb_equal(val, eval_r(m.value, 0)))
255
+ return Qtrue;
256
+ return Qfalse;
257
+ }
258
+
259
+ /*
260
+ * @return [String | nil]
261
+ */
262
+ VALUE w_hash_key(const VALUE self, const VALUE val) {
263
+ UsaminValue *value = get_value(self);
264
+ check_object(value);
265
+ for (auto &m : value->value->GetObject())
266
+ if (rb_equal(val, eval_r(m.value, 0)))
267
+ return eval_str(m.name);
268
+ return Qnil;
269
+ }
270
+
271
+ /*
272
+ * @return [String]
273
+ */
274
+ VALUE w_hash_inspect(const VALUE self) {
275
+ UsaminValue *value = get_value(self);
276
+ check_object(value);
277
+ VALUE ret = rb_str_new2("{");
278
+ bool first = true;
279
+ for (auto &m : value->value->GetObject()) {
280
+ if (!first)
281
+ ret = rb_str_cat2(ret, ", ");
282
+ ret = rb_str_append(ret, rb_inspect(eval_str(m.name)));
283
+ ret = rb_str_cat2(ret, "=>");
284
+ switch (m.value.GetType()) {
285
+ case rapidjson::kObjectType:
286
+ ret = rb_str_cat2(ret, "{...}");
287
+ break;
288
+ case rapidjson::kArrayType:
289
+ ret = rb_str_cat2(ret, "[...]");
290
+ break;
291
+ default:
292
+ ret = rb_str_append(ret, rb_inspect(eval(m.value, value->root_document)));
293
+ break;
294
+ }
295
+ first = false;
296
+ }
297
+ ret = rb_str_cat2(ret, "}");
298
+ return ret;
299
+ }
300
+
301
+ /*
302
+ * @return [::Hash]
303
+ */
304
+ VALUE w_hash_invert(const VALUE self) {
305
+ UsaminValue *value = get_value(self);
306
+ check_object(value);
307
+ VALUE ret = rb_hash_new();
308
+ for (auto &m : value->value->GetObject())
309
+ rb_hash_aset(ret, eval(m.value, value->root_document), eval_str(m.name));
310
+ return ret;
311
+ }
312
+
313
+ /*
314
+ * @return [::Array<String>]
315
+ */
316
+ VALUE w_hash_keys(const VALUE self) {
317
+ UsaminValue *value = get_value(self);
318
+ check_object(value);
319
+ VALUE ret = rb_ary_new2(value->value->MemberCount());
320
+ for (auto &m : value->value->GetObject())
321
+ rb_ary_push(ret, eval_str(m.name));
322
+ return ret;
323
+ }
324
+
325
+ /*
326
+ * @return [Integer]
327
+ */
328
+ VALUE w_hash_length(const VALUE self) {
329
+ UsaminValue *value = get_value(self);
330
+ check_object(value);
331
+ return UINT2NUM(value->value->MemberCount());
332
+ }
333
+
334
+ /*
335
+ * @return [::Array | nil]
336
+ */
337
+ VALUE w_hash_rassoc(const VALUE self, const VALUE val) {
338
+ UsaminValue *value = get_value(self);
339
+ check_object(value);
340
+ for (auto &m : value->value->GetObject())
341
+ if (rb_funcall(val, rb_intern("=="), 1, eval_r(m.value, 0)))
342
+ return rb_assoc_new(eval_str(m.name), eval(m.value, value->root_document));
343
+ return Qnil;
344
+ }
345
+
346
+ /*
347
+ * @yield [key, value]
348
+ * @yieldparam key [String]
349
+ * @yieldparam value [Object]
350
+ * @return [Enumerator | ::Hash]
351
+ */
352
+ VALUE w_hash_select(const VALUE self) {
353
+ UsaminValue *value = get_value(self);
354
+ check_object(value);
355
+ RETURN_SIZED_ENUMERATOR(self, 0, nullptr, hash_enum_size);
356
+ VALUE hash = rb_hash_new();
357
+ if (rb_proc_arity(rb_block_proc()) > 1) {
358
+ for (auto &m : value->value->GetObject()) {
359
+ VALUE args[] = {eval_str(m.name), eval(m.value, value->root_document)};
360
+ if (RTEST(rb_yield_values2(2, args)))
361
+ rb_hash_aset(hash, args[0], args[1]);
362
+ }
363
+ } else {
364
+ for (auto &m : value->value->GetObject()) {
365
+ VALUE key = eval_str(m.name);
366
+ VALUE val = eval(m.value, value->root_document);
367
+ if (RTEST(rb_yield(rb_assoc_new(key, val))))
368
+ rb_hash_aset(hash, key, val);
369
+ }
370
+ }
371
+ return hash;
372
+ }
373
+
374
+ /*
375
+ * @yield [key, value]
376
+ * @yieldparam key [String]
377
+ * @yieldparam value [Object]
378
+ * @return [Enumerator | ::Hash]
379
+ */
380
+ VALUE w_hash_reject(const VALUE self) {
381
+ UsaminValue *value = get_value(self);
382
+ check_object(value);
383
+ RETURN_SIZED_ENUMERATOR(self, 0, nullptr, hash_enum_size);
384
+ VALUE hash = rb_hash_new();
385
+ if (rb_proc_arity(rb_block_proc()) > 1) {
386
+ for (auto &m : value->value->GetObject()) {
387
+ VALUE args[] = {eval_str(m.name), eval(m.value, value->root_document)};
388
+ if (!RTEST(rb_yield_values2(2, args)))
389
+ rb_hash_aset(hash, args[0], args[1]);
390
+ }
391
+ } else {
392
+ for (auto &m : value->value->GetObject()) {
393
+ VALUE key = eval_str(m.name);
394
+ VALUE val = eval(m.value, value->root_document);
395
+ if (!RTEST(rb_yield(rb_assoc_new(key, val))))
396
+ rb_hash_aset(hash, key, val);
397
+ }
398
+ }
399
+ return hash;
400
+ }
401
+
402
+ /*
403
+ * @yield [key, value]
404
+ * @yieldparam key [String]
405
+ * @yieldparam value [Object]
406
+ * @return [Enumerator | ::Hash]
407
+ */
408
+ VALUE w_hash_slice(const int argc, const VALUE *argv, const VALUE self) {
409
+ UsaminValue *value = get_value(self);
410
+ check_object(value);
411
+ VALUE hash = rb_hash_new();
412
+ for (int i = 0; i < argc; i++)
413
+ for (auto &m : value->value->GetObject())
414
+ if (str_compare_xx(argv[i], m.name))
415
+ rb_hash_aset(hash, eval_str(m.name), eval(m.value, value->root_document));
416
+ return hash;
417
+ }
418
+
419
+ /*
420
+ * Convert to Ruby Hash. Same as {Value#eval}.
421
+ *
422
+ * @return [::Hash]
423
+ */
424
+ VALUE w_hash_eval(const VALUE self) {
425
+ UsaminValue *value = get_value(self);
426
+ check_object(value);
427
+ return eval_object(*(value->value), value->root_document, 0);
428
+ }
429
+
430
+ /*
431
+ * @return [::Hash]
432
+ */
433
+ VALUE w_hash_merge(const int argc, const VALUE *argv, const VALUE self) {
434
+ static ID s = rb_intern("merge");
435
+ VALUE args, block;
436
+ rb_scan_args(argc, argv, "*&", &args, &block);
437
+ return rb_funcall_with_block(w_hash_eval(self), s, RARRAY_LENINT(args), RARRAY_CONST_PTR(args), block);
438
+ }
439
+
440
+ /*
441
+ * @return [::Array<Object>]
442
+ */
443
+ VALUE w_hash_values(const VALUE self) {
444
+ UsaminValue *value = get_value(self);
445
+ check_object(value);
446
+ VALUE ret = rb_ary_new2(value->value->MemberCount());
447
+ for (auto &m : value->value->GetObject())
448
+ rb_ary_push(ret, eval(m.value, value->root_document));
449
+ return ret;
450
+ }
451
+
452
+ static VALUE hash_proc_call(RB_BLOCK_CALL_FUNC_ARGLIST(key, self)) {
453
+ rb_check_arity(argc, 1, 1);
454
+ return w_hash_operator_indexer(self, key);
455
+ }
456
+
457
+ /*
458
+ * @return [Proc]
459
+ */
460
+ VALUE w_hash_to_proc(const VALUE self) {
461
+ #if RUBY_API_VERSION_CODE < 20700
462
+ return rb_proc_new(RUBY_METHOD_FUNC(hash_proc_call), self);
463
+ #else
464
+ return rb_proc_new(hash_proc_call, self);
465
+ #endif
466
+ }
467
+
468
+ /*
469
+ * @yield [key]
470
+ * @yieldparam key [String]
471
+ * @return [Enumerator | ::Hash]
472
+ */
473
+ VALUE w_hash_transform_keys(const VALUE self) {
474
+ UsaminValue *value = get_value(self);
475
+ check_object(value);
476
+ RETURN_SIZED_ENUMERATOR(self, 0, nullptr, hash_enum_size);
477
+ VALUE hash = rb_hash_new();
478
+ for (auto &m : value->value->GetObject())
479
+ rb_hash_aset(hash, rb_yield(eval_str(m.name)), eval(m.value, value->root_document));
480
+ return hash;
481
+ }
482
+
483
+ /*
484
+ * @yield [value]
485
+ * @yieldparam value [Object]
486
+ * @return [Enumerator | ::Hash]
487
+ */
488
+ VALUE w_hash_transform_values(const VALUE self) {
489
+ UsaminValue *value = get_value(self);
490
+ check_object(value);
491
+ RETURN_SIZED_ENUMERATOR(self, 0, nullptr, hash_enum_size);
492
+ VALUE hash = rb_hash_new();
493
+ for (auto &m : value->value->GetObject())
494
+ rb_hash_aset(hash, eval_str(m.name), rb_yield(eval(m.value, value->root_document)));
495
+ return hash;
496
+ }
497
+
498
+ /*
499
+ * @param [String] keys
500
+ * @return [::Array<Object>]
501
+ */
502
+ VALUE w_hash_values_at(const int argc, const VALUE *argv, const VALUE self) {
503
+ UsaminValue *value = get_value(self);
504
+ check_object(value);
505
+ VALUE ret = rb_ary_new2(argc);
506
+ for (int i = 0; i < argc; i++) {
507
+ VALUE data = Qnil;
508
+ for (auto &m : value->value->GetObject()) {
509
+ if (str_compare_xx(argv[i], m.name)) {
510
+ data = eval(m.value, value->root_document);
511
+ break;
512
+ }
513
+ }
514
+ rb_ary_push(ret, data);
515
+ }
516
+ return ret;
517
+ }