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,11 @@
1
+ #ifndef USAMIN_GENERATOR_HPP
2
+ #define USAMIN_GENERATOR_HPP
3
+
4
+ #include <rapidjson/writer.h>
5
+ #include <ruby.h>
6
+ #include "rubynized_rapidjson.hpp"
7
+
8
+ VALUE w_generate(const VALUE self, const VALUE value);
9
+ VALUE w_pretty_generate(const int argc, const VALUE *argv, const VALUE self);
10
+
11
+ #endif
@@ -0,0 +1,100 @@
1
+ #include "default_parse_flags.hpp"
2
+ #include "parser.hpp"
3
+ #include <rapidjson/reader.h>
4
+ #include <rapidjson/error/en.h>
5
+ #include <ruby.h>
6
+ #include "rb_common.hpp"
7
+ #include "rubynized_rapidjson.hpp"
8
+ #include "usamin_value.hpp"
9
+ #include "parser_helper.hpp"
10
+
11
+ static inline rapidjson::ParseResult parse(RubynizedDocument &doc, const VALUE str, bool fast = false,
12
+ bool recursive = false) {
13
+ volatile VALUE v = get_utf8_str(str);
14
+ #define PARSE_WITH_FLAGS(flags) return doc.Parse<flags>(RSTRING_PTR(v), RSTRING_LEN(v))
15
+ if (recursive)
16
+ if (fast)
17
+ PARSE_WITH_FLAGS(RAPIDJSON_PARSE_FAST_FLAGS & ~rapidjson::kParseIterativeFlag);
18
+ else
19
+ PARSE_WITH_FLAGS(RAPIDJSON_PARSE_DEFAULT_FLAGS & ~rapidjson::kParseIterativeFlag);
20
+ else if (fast)
21
+ PARSE_WITH_FLAGS(RAPIDJSON_PARSE_FAST_FLAGS);
22
+ else
23
+ PARSE_WITH_FLAGS(RAPIDJSON_PARSE_DEFAULT_FLAGS);
24
+ #undef PARSE_WITH_FLAGS
25
+ }
26
+
27
+ /*
28
+ * Parse the JSON string into UsaminValue.
29
+ * If the document root is not an object or an array, the same value as {#parse} will be returned.
30
+ *
31
+ * @overload load(source, opts = {})
32
+ * @param [String] source JSON string to parse
33
+ * @param [::Hash] opts options
34
+ * @option opts :fast fast mode (but not precise)
35
+ * @option opts :recursive non-iterative (recursive) mode (fast but not safe, can cause SystemStackError and illegal hardware instruction)
36
+ * @return [Object]
37
+ */
38
+ VALUE w_load(const int argc, const VALUE *argv, const VALUE) {
39
+ extern VALUE rb_eUsaminError, rb_eParserError, sym_fast, sym_recursive;
40
+
41
+ VALUE source, options;
42
+ rb_scan_args(argc, argv, "1:", &source, &options);
43
+ RubynizedDocument *doc = new RubynizedDocument;
44
+ auto result = parse(*doc, source, test_option(options, sym_fast), test_option(options, sym_recursive));
45
+ if (!result) {
46
+ delete doc;
47
+ rb_raise(rb_eParserError, "%s Offset: %lu", GetParseError_En(result.Code()), result.Offset());
48
+ }
49
+
50
+ VALUE ret;
51
+ switch (doc->GetType()) {
52
+ case rapidjson::kNullType:
53
+ delete doc;
54
+ return Qnil;
55
+ case rapidjson::kFalseType:
56
+ delete doc;
57
+ return Qfalse;
58
+ case rapidjson::kTrueType:
59
+ delete doc;
60
+ return Qtrue;
61
+ case rapidjson::kObjectType:
62
+ return make_hash(new UsaminValue(doc, true), true);
63
+ case rapidjson::kArrayType:
64
+ return make_array(new UsaminValue(doc, true), true);
65
+ case rapidjson::kStringType:
66
+ ret = eval_str(*doc);
67
+ delete doc;
68
+ return ret;
69
+ case rapidjson::kNumberType:
70
+ ret = eval_num(*doc);
71
+ delete doc;
72
+ return ret;
73
+ default:
74
+ rb_raise(rb_eUsaminError, "unknown value type: %d", doc->GetType());
75
+ return Qnil;
76
+ }
77
+ }
78
+
79
+ /*
80
+ * Parse the JSON string into Ruby data structures.
81
+ *
82
+ * @overload parse(source, opts = {})
83
+ * @param [String] source a JSON string to parse
84
+ * @param [::Hash] opts options
85
+ * @option opts :fast fast mode (but not precise)
86
+ * @option opts :recursive non-iterative (recursive) mode (fast but not safe, can cause SystemStackError and illegal hardware instruction)
87
+ * @option opts :symbolize_names symbolize keys of all Hash objects
88
+ * @return [Object]
89
+ */
90
+ VALUE w_parse(const int argc, const VALUE *argv, const VALUE) {
91
+ extern VALUE rb_eParserError, sym_fast, sym_recursive, sym_symbolize_names;
92
+
93
+ VALUE source, options;
94
+ rb_scan_args(argc, argv, "1:", &source, &options);
95
+ RubynizedDocument doc;
96
+ auto result = parse(doc, source, test_option(options, sym_fast), test_option(options, sym_recursive));
97
+ if (!result)
98
+ rb_raise(rb_eParserError, "%s Offset: %lu", GetParseError_En(result.Code()), result.Offset());
99
+ return eval_r(doc, test_option(options, sym_symbolize_names));
100
+ }
@@ -0,0 +1,9 @@
1
+ #ifndef USAMIN_PARSER_HPP
2
+ #define USAMIN_PARSER_HPP
3
+
4
+ #include <ruby.h>
5
+
6
+ VALUE w_load(const int argc, const VALUE *argv, const VALUE self);
7
+ VALUE w_parse(const int argc, const VALUE *argv, const VALUE self);
8
+
9
+ #endif
@@ -0,0 +1,131 @@
1
+ #include <ruby.h>
2
+ #include "rb_common.hpp"
3
+ #include "rb_usamin_value.hpp"
4
+ #include "rubynized_rapidjson.hpp"
5
+ #include "usamin_value.hpp"
6
+
7
+ static inline int test_option(VALUE options, VALUE sym) {
8
+ return !NIL_P(options) && RTEST(rb_hash_lookup(options, sym));
9
+ }
10
+
11
+ static inline VALUE make_hash(UsaminValue *value, bool is_root = false) {
12
+ extern VALUE rb_cUsaminHash;
13
+ VALUE ret = rb_obj_alloc(rb_cUsaminHash);
14
+ set_value(ret, value);
15
+ if (is_root)
16
+ value->root_document = ret;
17
+ return ret;
18
+ }
19
+
20
+ static inline VALUE make_array(UsaminValue *value, bool is_root = false) {
21
+ extern VALUE rb_cUsaminArray;
22
+ VALUE ret = rb_obj_alloc(rb_cUsaminArray);
23
+ set_value(ret, value);
24
+ if (is_root)
25
+ value->root_document = ret;
26
+ return ret;
27
+ }
28
+
29
+ static inline VALUE eval_num(RubynizedValue &);
30
+ static inline VALUE eval_str(RubynizedValue &);
31
+ static inline VALUE eval_object_r(RubynizedValue &, int);
32
+ static inline VALUE eval_array_r(RubynizedValue &, int);
33
+
34
+ static VALUE eval(RubynizedValue &value, VALUE root_document) {
35
+ extern VALUE rb_eUsaminError;
36
+ switch (value.GetType()) {
37
+ case rapidjson::kObjectType:
38
+ return make_hash(new UsaminValue(&value, false, root_document));
39
+ case rapidjson::kArrayType:
40
+ return make_array(new UsaminValue(&value, false, root_document));
41
+ case rapidjson::kNullType:
42
+ return Qnil;
43
+ case rapidjson::kFalseType:
44
+ return Qfalse;
45
+ case rapidjson::kTrueType:
46
+ return Qtrue;
47
+ case rapidjson::kNumberType:
48
+ return eval_num(value);
49
+ case rapidjson::kStringType:
50
+ return eval_str(value);
51
+ default:
52
+ rb_raise(rb_eUsaminError, "unknown value type: %d", value.GetType());
53
+ return Qnil;
54
+ }
55
+ }
56
+
57
+ static VALUE eval_r(RubynizedValue &value, int symbolize) {
58
+ extern VALUE rb_eUsaminError;
59
+ switch (value.GetType()) {
60
+ case rapidjson::kObjectType:
61
+ return eval_object_r(value, symbolize);
62
+ case rapidjson::kArrayType:
63
+ return eval_array_r(value, symbolize);
64
+ case rapidjson::kNullType:
65
+ return Qnil;
66
+ case rapidjson::kFalseType:
67
+ return Qfalse;
68
+ case rapidjson::kTrueType:
69
+ return Qtrue;
70
+ case rapidjson::kNumberType:
71
+ return eval_num(value);
72
+ case rapidjson::kStringType:
73
+ return eval_str(value);
74
+ default:
75
+ rb_raise(rb_eUsaminError, "unknown value type: %d", value.GetType());
76
+ return Qnil;
77
+ }
78
+ }
79
+
80
+ static inline VALUE eval_num(RubynizedValue &value) {
81
+ if (value.IsInt())
82
+ return INT2FIX(value.GetInt());
83
+ else if (value.IsUint())
84
+ return UINT2NUM(value.GetUint());
85
+ else if (value.IsInt64())
86
+ return LL2NUM(value.GetInt64());
87
+ else if (value.IsUint64())
88
+ return ULL2NUM(value.GetUint64());
89
+ else
90
+ return DBL2NUM(value.GetDouble());
91
+ }
92
+
93
+ static inline VALUE eval_str(RubynizedValue &value) {
94
+ return new_utf8_str(value.GetString(), value.GetStringLength());
95
+ }
96
+
97
+ static inline VALUE eval_object(RubynizedValue &value, const VALUE root_document, int symbolize) {
98
+ VALUE ret = rb_hash_new();
99
+ if (symbolize)
100
+ for (auto &m : value.GetObject())
101
+ rb_hash_aset(ret, rb_to_symbol(eval_str(m.name)), eval(m.value, root_document));
102
+ else
103
+ for (auto &m : value.GetObject())
104
+ rb_hash_aset(ret, eval_str(m.name), eval(m.value, root_document));
105
+ return ret;
106
+ }
107
+
108
+ static inline VALUE eval_object_r(RubynizedValue &value, int symbolize) {
109
+ VALUE ret = rb_hash_new();
110
+ if (symbolize)
111
+ for (auto &m : value.GetObject())
112
+ rb_hash_aset(ret, rb_to_symbol(eval_str(m.name)), eval_r(m.value, symbolize));
113
+ else
114
+ for (auto &m : value.GetObject())
115
+ rb_hash_aset(ret, eval_str(m.name), eval_r(m.value, symbolize));
116
+ return ret;
117
+ }
118
+
119
+ static inline VALUE eval_array(RubynizedValue &value, const VALUE root_document) {
120
+ VALUE ret = rb_ary_new2(value.Size());
121
+ for (auto &v : value.GetArray())
122
+ rb_ary_push(ret, eval(v, root_document));
123
+ return ret;
124
+ }
125
+
126
+ static inline VALUE eval_array_r(RubynizedValue &value, int symbolize) {
127
+ VALUE ret = rb_ary_new2(value.Size());
128
+ for (auto &v : value.GetArray())
129
+ rb_ary_push(ret, eval_r(v, symbolize));
130
+ return ret;
131
+ }
@@ -0,0 +1,60 @@
1
+ #include <ruby.h>
2
+ #include <ruby/encoding.h>
3
+ #include "rubynized_rapidjson.hpp"
4
+ #include "usamin_value.hpp"
5
+
6
+ VALUE get_utf8_str(VALUE str) {
7
+ extern int utf8index;
8
+ extern VALUE utf8value;
9
+ extern rb_encoding *utf8;
10
+
11
+ Check_Type(str, T_STRING);
12
+ int encoding = rb_enc_get_index(str);
13
+ if (encoding == utf8index || rb_enc_compatible(str, utf8value) == utf8)
14
+ return str;
15
+ else
16
+ return rb_str_conv_enc(str, rb_enc_from_index(encoding), utf8);
17
+ }
18
+
19
+ VALUE new_utf8_str(const char *cstr, const long len) {
20
+ extern int utf8index;
21
+ VALUE ret = rb_str_new(cstr, len);
22
+ rb_enc_set_index(ret, utf8index);
23
+ return ret;
24
+ }
25
+
26
+ static inline bool str_compare(const char *str1, const long len1, const char *str2, const long len2) {
27
+ if (len1 != len2 || len1 < 0)
28
+ return false;
29
+ return memcmp(str1, str2, len1) == 0;
30
+ }
31
+
32
+ bool str_compare_xx(VALUE str1, const RubynizedValue &str2) {
33
+ if (RB_TYPE_P(str1, T_STRING))
34
+ str1 = get_utf8_str(str1);
35
+ else if (SYMBOL_P(str1))
36
+ str1 = get_utf8_str(rb_sym_to_s(str1));
37
+ else
38
+ str1 = get_utf8_str(StringValue(str1));
39
+ return str_compare(RSTRING_PTR(str1), RSTRING_LEN(str1), str2.GetString(), str2.GetStringLength());
40
+ }
41
+
42
+ void check_value(UsaminValue *ptr) {
43
+ extern VALUE rb_eUsaminError;
44
+ if (!ptr || !ptr->value)
45
+ rb_raise(rb_eUsaminError, "null reference");
46
+ }
47
+
48
+ void check_object(UsaminValue *ptr) {
49
+ extern VALUE rb_eUsaminError;
50
+ check_value(ptr);
51
+ if (!ptr->value->IsObject())
52
+ rb_raise(rb_eUsaminError, "unexpected type of value (expected: object)");
53
+ }
54
+
55
+ void check_array(UsaminValue *ptr) {
56
+ extern VALUE rb_eUsaminError;
57
+ check_value(ptr);
58
+ if (!ptr->value->IsArray())
59
+ rb_raise(rb_eUsaminError, "unexpected type of value (expected: array)");
60
+ }
@@ -0,0 +1,15 @@
1
+ #ifndef USAMIN_RB_COMMON_HPP
2
+ #define USAMIN_RB_COMMON_HPP
3
+
4
+ #include <ruby.h>
5
+ #include "rubynized_rapidjson.hpp"
6
+ #include "usamin_value.hpp"
7
+
8
+ VALUE get_utf8_str(VALUE str);
9
+ VALUE new_utf8_str(const char *cstr, const long len);
10
+ bool str_compare_xx(VALUE str1, const RubynizedValue &str2);
11
+ void check_value(UsaminValue *ptr);
12
+ void check_object(UsaminValue *ptr);
13
+ void check_array(UsaminValue *ptr);
14
+
15
+ #endif
@@ -0,0 +1,453 @@
1
+ #include <rapidjson/document.h>
2
+ #include <ruby.h>
3
+ #include "usamin_value.hpp"
4
+ #include "parser_helper.hpp"
5
+
6
+ /*
7
+ * @overload [](nth)
8
+ * @param [Integer] nth
9
+ * @return [Object | nil]
10
+ *
11
+ * @overload [](start, length)
12
+ * @param [Integer] start
13
+ * @param [Integer] length
14
+ * @return [::Array<Object> | nil]
15
+ *
16
+ * @overload [](range)
17
+ * @param [Range] range
18
+ * @return [::Array<Object> | nil]
19
+ */
20
+ VALUE w_array_operator_indexer(const int argc, const VALUE *argv, const VALUE self) {
21
+ rb_check_arity(argc, 1, 2);
22
+ UsaminValue *value = get_value(self);
23
+ check_array(value);
24
+ rapidjson::SizeType sz = value->value->Size();
25
+ if (argc == 2) {
26
+ int beg = FIX2INT(argv[0]);
27
+ int len = FIX2INT(argv[1]);
28
+ if (len < 0)
29
+ return Qnil;
30
+ if (beg < 0)
31
+ beg += sz;
32
+ if (beg < 0 || static_cast<rapidjson::SizeType>(beg) > sz)
33
+ return Qnil;
34
+ rapidjson::SizeType end = beg + len;
35
+ if (end > sz)
36
+ end = sz;
37
+ VALUE ret = rb_ary_new2(end - beg);
38
+ for (rapidjson::SizeType i = beg; i < end; i++)
39
+ rb_ary_push(ret, eval((*value->value)[i], value->root_document));
40
+ return ret;
41
+ } else if (rb_obj_is_kind_of(argv[0], rb_cRange)) {
42
+ long beg, len;
43
+ if (rb_range_beg_len(argv[0], &beg, &len, sz, 0) == Qtrue) {
44
+ VALUE ret = rb_ary_new2(len);
45
+ unsigned int beg_i = rb_long2int(beg);
46
+ unsigned int len_i = rb_long2int(len);
47
+ for (rapidjson::SizeType i = beg_i; i < beg_i + len_i; i++)
48
+ rb_ary_push(ret, eval((*value->value)[i], value->root_document));
49
+ return ret;
50
+ }
51
+ } else {
52
+ int l = FIX2INT(argv[0]);
53
+ if (l < 0)
54
+ l += sz;
55
+ if (0 <= l && static_cast<rapidjson::SizeType>(l) < sz)
56
+ return eval((*value->value)[l], value->root_document);
57
+ }
58
+ return Qnil;
59
+ }
60
+
61
+ /*
62
+ * @param [Integer] nth
63
+ * @return [Object]
64
+ */
65
+ VALUE w_array_at(const VALUE self, const VALUE nth) {
66
+ UsaminValue *value = get_value(self);
67
+ check_array(value);
68
+ int l = FIX2INT(nth);
69
+ rapidjson::SizeType sz = value->value->Size();
70
+ if (l < 0)
71
+ l += sz;
72
+ if (0 <= l && static_cast<rapidjson::SizeType>(l) < sz)
73
+ return eval((*value->value)[l], value->root_document);
74
+ return Qnil;
75
+ }
76
+
77
+ /*
78
+ * @return [::Array]
79
+ */
80
+ VALUE w_array_compact(const VALUE self) {
81
+ UsaminValue *value = get_value(self);
82
+ check_array(value);
83
+ VALUE ret = rb_ary_new2(value->value->Size());
84
+ for (auto &v : value->value->GetArray())
85
+ if (!v.IsNull())
86
+ rb_ary_push(ret, eval(v, value->root_document));
87
+ return ret;
88
+ }
89
+
90
+ /*
91
+ * @return [Object | nil]
92
+ */
93
+ VALUE w_array_dig(const int argc, const VALUE *argv, const VALUE self) {
94
+ rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS);
95
+ VALUE value = w_array_at(self, argv[0]);
96
+ if (argc == 1)
97
+ return value;
98
+ else if (value == Qnil)
99
+ return Qnil;
100
+ extern ID id_dig;
101
+ return rb_funcall3(value, id_dig, argc - 1, argv + 1);
102
+ }
103
+
104
+ static VALUE array_enum_size(const VALUE self, const VALUE, const VALUE) {
105
+ return UINT2NUM(get_value(self)->value->Size());
106
+ }
107
+
108
+ /*
109
+ * @yield [value]
110
+ * @return [Enumerator | self]
111
+ */
112
+ VALUE w_array_each(const VALUE self) {
113
+ UsaminValue *value = get_value(self);
114
+ check_array(value);
115
+ RETURN_SIZED_ENUMERATOR(self, 0, nullptr, array_enum_size);
116
+ for (auto &v : value->value->GetArray())
117
+ rb_yield(eval(v, value->root_document));
118
+ return self;
119
+ }
120
+
121
+ /*
122
+ * @yield [index]
123
+ * @yieldparam index [Integer]
124
+ * @return [Enumerator | self]
125
+ */
126
+ VALUE w_array_each_index(const VALUE self) {
127
+ UsaminValue *value = get_value(self);
128
+ check_array(value);
129
+ RETURN_SIZED_ENUMERATOR(self, 0, nullptr, array_enum_size);
130
+ for (rapidjson::SizeType i = 0; i < value->value->Size(); i++)
131
+ rb_yield(UINT2NUM(i));
132
+ return self;
133
+ }
134
+
135
+ VALUE w_array_isempty(const VALUE self) {
136
+ UsaminValue *value = get_value(self);
137
+ check_array(value);
138
+ return value->value->Size() == 0 ? Qtrue : Qfalse;
139
+ }
140
+
141
+ /*
142
+ * @overload fetch(nth)
143
+ * @param [Integer] nth
144
+ * @return [Object]
145
+ * @raise [IndexError] if nth is out of array bounds
146
+ *
147
+ * @overload fetch(nth, ifnone)
148
+ * @param [Integer] nth
149
+ * @param [Object] ifnone
150
+ * @return [Object]
151
+ *
152
+ * @overload fetch(nth)
153
+ * @param [Integer] nth
154
+ * @yield [nth]
155
+ * @return [Object]
156
+ */
157
+ VALUE w_array_fetch(const int argc, const VALUE *argv, const VALUE self) {
158
+ rb_check_arity(argc, 1, 2);
159
+ UsaminValue *value = get_value(self);
160
+ check_array(value);
161
+ rapidjson::SizeType sz = value->value->Size();
162
+
163
+ if (argc == 2 && rb_block_given_p())
164
+ rb_warn("block supersedes default value argument");
165
+
166
+ int l = FIX2INT(argv[0]);
167
+ if (l < 0)
168
+ l += sz;
169
+ if (0 <= l && static_cast<rapidjson::SizeType>(l) < sz)
170
+ return eval((*value->value)[l], value->root_document);
171
+
172
+ if (rb_block_given_p())
173
+ return rb_yield(argv[0]);
174
+ else if (argc == 2)
175
+ return argv[1];
176
+ else
177
+ rb_raise(rb_eIndexError, "index %ld outside of array bounds: %ld...%u", FIX2LONG(argv[0]),
178
+ -static_cast<long>(sz), sz);
179
+ return Qnil;
180
+ }
181
+
182
+ /*
183
+ * @overload find_index(val)
184
+ * @param [Object] val
185
+ * @return [Integer | nil]
186
+ *
187
+ * @overload find_index
188
+ * @yield [item]
189
+ * @yieldparam item [Object]
190
+ * @return [Integer | nil]
191
+ */
192
+ VALUE w_array_find_index(const int argc, const VALUE *argv, const VALUE self) {
193
+ rb_check_arity(argc, 0, 1);
194
+ UsaminValue *value = get_value(self);
195
+ check_array(value);
196
+
197
+ if (argc == 1) {
198
+ if (rb_block_given_p())
199
+ rb_warn("given block not used");
200
+ for (rapidjson::SizeType i = 0; i < value->value->Size(); i++) {
201
+ if (rb_equal(argv[0], eval_r((*value->value)[i], 0)) == Qtrue)
202
+ return UINT2NUM(i);
203
+ }
204
+ return Qnil;
205
+ }
206
+
207
+ RETURN_SIZED_ENUMERATOR(self, 0, nullptr, array_enum_size);
208
+ for (rapidjson::SizeType i = 0; i < value->value->Size(); i++) {
209
+ if (RTEST(rb_yield(eval((*value->value)[i], value->root_document))))
210
+ return UINT2NUM(i);
211
+ }
212
+ return Qnil;
213
+ }
214
+
215
+ void flatten_array(RubynizedValue &value, VALUE array, int level, VALUE root_document) {
216
+ if (level == 0)
217
+ for (auto &v : value.GetArray())
218
+ rb_ary_push(array, eval(v, root_document));
219
+ else
220
+ for (auto &v : value.GetArray())
221
+ if (v.IsArray())
222
+ flatten_array(v, array, level - 1, root_document);
223
+ else
224
+ rb_ary_push(array, eval(v, root_document));
225
+ }
226
+
227
+ /*
228
+ * @overload flatten(lv = nil)
229
+ * @return [::Array<Object>]
230
+ */
231
+ VALUE w_array_flatten(const int argc, const VALUE *argv, const VALUE self) {
232
+ rb_check_arity(argc, 0, 1);
233
+ UsaminValue *value = get_value(self);
234
+ check_array(value);
235
+ int level = -1;
236
+ if (argc == 1 && !NIL_P(argv[0]))
237
+ level = NUM2INT(argv[0]);
238
+ VALUE ret = rb_ary_new2(value->value->Size());
239
+ flatten_array(*value->value, ret, level, value->root_document);
240
+ return ret;
241
+ }
242
+
243
+ /*
244
+ * @overload first
245
+ * @return [Object | nil]
246
+ *
247
+ * @overload first(n)
248
+ * @return [::Array<Object>]
249
+ */
250
+ VALUE w_array_first(const int argc, const VALUE *argv, const VALUE self) {
251
+ rb_check_arity(argc, 0, 1);
252
+ UsaminValue *value = get_value(self);
253
+ check_array(value);
254
+ rapidjson::SizeType sz = value->value->Size();
255
+
256
+ if (argc == 0) {
257
+ if (sz == 0)
258
+ return Qnil;
259
+ return eval(*value->value->Begin(), value->root_document);
260
+ } else {
261
+ long l = FIX2LONG(argv[0]);
262
+ if (l > sz)
263
+ l = sz;
264
+ VALUE ret = rb_ary_new2(l);
265
+ for (auto v = value->value->Begin(); v < value->value->Begin() + l; v++)
266
+ rb_ary_push(ret, eval(*v, value->root_document));
267
+ return ret;
268
+ }
269
+ }
270
+
271
+ /*
272
+ * @return [Boolean]
273
+ */
274
+ VALUE w_array_include(const VALUE self, const VALUE val) {
275
+ UsaminValue *value = get_value(self);
276
+ check_array(value);
277
+ for (auto &v : value->value->GetArray())
278
+ if (rb_equal(val, eval_r(v, 0)))
279
+ return Qtrue;
280
+ return Qfalse;
281
+ }
282
+
283
+ /*
284
+ * @return [String]
285
+ */
286
+ VALUE w_array_inspect(const VALUE self) {
287
+ UsaminValue *value = get_value(self);
288
+ check_array(value);
289
+ VALUE ret = rb_str_new2("[");
290
+ bool first = true;
291
+ for (auto &v : value->value->GetArray()) {
292
+ if (!first)
293
+ ret = rb_str_cat2(ret, ", ");
294
+ switch (v.GetType()) {
295
+ case rapidjson::kObjectType:
296
+ ret = rb_str_cat2(ret, "{...}");
297
+ break;
298
+ case rapidjson::kArrayType:
299
+ ret = rb_str_cat2(ret, "[...]");
300
+ break;
301
+ default:
302
+ ret = rb_str_append(ret, rb_inspect(eval(v, value->root_document)));
303
+ break;
304
+ }
305
+ first = false;
306
+ }
307
+ ret = rb_str_cat2(ret, "]");
308
+ return ret;
309
+ }
310
+
311
+ /*
312
+ * @overload last
313
+ * @return [Object | nil]
314
+ *
315
+ * @overload last(n)
316
+ * @return [::Array<Object>]
317
+ */
318
+ VALUE w_array_last(const int argc, const VALUE *argv, const VALUE self) {
319
+ rb_check_arity(argc, 0, 1);
320
+ UsaminValue *value = get_value(self);
321
+ check_array(value);
322
+ rapidjson::SizeType sz = value->value->Size();
323
+
324
+ if (argc == 0) {
325
+ return sz > 0 ? eval(*(value->value->End() - 1), value->root_document) : Qnil;
326
+ } else {
327
+ long l = FIX2LONG(argv[0]);
328
+ if (l > sz)
329
+ l = sz;
330
+ VALUE ret = rb_ary_new2(l);
331
+ for (auto v = value->value->End() - l; v < value->value->End(); v++)
332
+ rb_ary_push(ret, eval(*v, value->root_document));
333
+ return ret;
334
+ }
335
+ }
336
+
337
+ /*
338
+ * @return [Integer]
339
+ */
340
+ VALUE w_array_length(const VALUE self) {
341
+ UsaminValue *value = get_value(self);
342
+ check_array(value);
343
+ return UINT2NUM(value->value->Size());
344
+ }
345
+
346
+ /*
347
+ * @return [::Array<Object>]
348
+ */
349
+ VALUE w_array_reverse(const VALUE self) {
350
+ UsaminValue *value = get_value(self);
351
+ check_array(value);
352
+
353
+ VALUE ret = rb_ary_new2(value->value->Size());
354
+ for (rapidjson::SizeType i = 0, j = value->value->Size() - 1; i < value->value->Size(); i++, j--)
355
+ rb_ary_push(ret, eval((*value->value)[j], value->root_document));
356
+ return ret;
357
+ }
358
+
359
+ /*
360
+ * @overload rindex(val)
361
+ * @param [Object] val
362
+ * @return [Integer | nil]
363
+ *
364
+ * @overload rindex
365
+ * @yield [item]
366
+ * @yieldparam item [Object]
367
+ * @return [Integer | nil]
368
+ */
369
+ VALUE w_array_rindex(const int argc, const VALUE *argv, const VALUE self) {
370
+ rb_check_arity(argc, 0, 1);
371
+ UsaminValue *value = get_value(self);
372
+ check_array(value);
373
+
374
+ if (argc == 1) {
375
+ for (rapidjson::SizeType i = 0, j = value->value->Size() - 1; i < value->value->Size(); i++, j--) {
376
+ if (rb_equal(argv[0], eval_r((*value->value)[j], 0)) == Qtrue)
377
+ return UINT2NUM(j);
378
+ }
379
+ return Qnil;
380
+ }
381
+
382
+ RETURN_SIZED_ENUMERATOR(self, 0, nullptr, array_enum_size);
383
+ for (rapidjson::SizeType i = 0, j = value->value->Size() - 1; i < value->value->Size(); i++, j--) {
384
+ if (RTEST(rb_yield(eval((*value->value)[j], value->root_document))))
385
+ return UINT2NUM(j);
386
+ }
387
+ return Qnil;
388
+ }
389
+
390
+ /*
391
+ * @overload rotate(cnt = 1)
392
+ * @return [::Array<Object>]
393
+ */
394
+ VALUE w_array_rotate(const int argc, const VALUE *argv, const VALUE self) {
395
+ rb_check_arity(argc, 0, 1);
396
+ UsaminValue *value = get_value(self);
397
+ check_array(value);
398
+
399
+ switch (value->value->Size()) {
400
+ case 0:
401
+ return rb_ary_new();
402
+ case 1:
403
+ return rb_ary_new3(1, eval(value->value->operator[](0), value->root_document));
404
+ }
405
+
406
+ int cnt = argc == 1 ? NUM2INT(argv[0]) : 1;
407
+ if (cnt >= 0) {
408
+ cnt = cnt % value->value->Size();
409
+ } else {
410
+ cnt = -cnt % value->value->Size();
411
+ if (cnt)
412
+ cnt = value->value->Size() - cnt;
413
+ }
414
+ if (cnt == 0)
415
+ return eval_array(*(value->value), value->root_document);
416
+
417
+ rapidjson::SizeType ucnt = cnt;
418
+ VALUE ret = rb_ary_new2(value->value->Size());
419
+ for (rapidjson::SizeType i = ucnt; i < value->value->Size(); i++)
420
+ rb_ary_push(ret, eval((*value->value)[i], value->root_document));
421
+ for (rapidjson::SizeType i = 0; i < ucnt; i++)
422
+ rb_ary_push(ret, eval((*value->value)[i], value->root_document));
423
+ return ret;
424
+ }
425
+
426
+ /*
427
+ * @overload slice(nth)
428
+ * @param [Integer] nth
429
+ * @return [Object | nil]
430
+ *
431
+ * @overload slice(start, length)
432
+ * @param [Integer] start
433
+ * @param [Integer] length
434
+ * @return [::Array<Object> | nil]
435
+ *
436
+ * @overload slice(range)
437
+ * @param [Range] range
438
+ * @return [::Array<Object> | nil]
439
+ */
440
+ VALUE w_array_slice(const int argc, const VALUE *argv, const VALUE self) {
441
+ return w_array_operator_indexer(argc, argv, self);
442
+ }
443
+
444
+ /*
445
+ * Convert to Ruby data structures. Same as {Value#eval}.
446
+ *
447
+ * @return [::Array<Object>]
448
+ */
449
+ VALUE w_array_eval(const VALUE self) {
450
+ UsaminValue *value = get_value(self);
451
+ check_array(value);
452
+ return eval_array(*(value->value), value->root_document);
453
+ }