1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2014 Google Inc. All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file or at
6 // https://developers.google.com/open-source/licenses/bsd
7
8 #include "repeated_field.h"
9
10 #include "convert.h"
11 #include "defs.h"
12 #include "message.h"
13 #include "protobuf.h"
14
15 // -----------------------------------------------------------------------------
16 // Repeated field container type.
17 // -----------------------------------------------------------------------------
18
19 typedef struct {
20 const upb_Array* array; // Can get as mutable when non-frozen.
21 TypeInfo type_info;
22 VALUE type_class; // To GC-root the msgdef/enumdef in type_info.
23 VALUE arena; // To GC-root the upb_Array.
24 } RepeatedField;
25
26 VALUE cRepeatedField;
27
RepeatedField_mark(void * _self)28 static void RepeatedField_mark(void* _self) {
29 RepeatedField* self = (RepeatedField*)_self;
30 rb_gc_mark(self->type_class);
31 rb_gc_mark(self->arena);
32 }
33
34 const rb_data_type_t RepeatedField_type = {
35 "Google::Protobuf::RepeatedField",
36 {RepeatedField_mark, RUBY_DEFAULT_FREE, NULL},
37 .flags = RUBY_TYPED_FREE_IMMEDIATELY,
38 };
39
ruby_to_RepeatedField(VALUE _self)40 static RepeatedField* ruby_to_RepeatedField(VALUE _self) {
41 RepeatedField* self;
42 TypedData_Get_Struct(_self, RepeatedField, &RepeatedField_type, self);
43 return self;
44 }
45
RepeatedField_GetMutable(VALUE _self)46 static upb_Array* RepeatedField_GetMutable(VALUE _self) {
47 const upb_Array* array = ruby_to_RepeatedField(_self)->array;
48 Protobuf_CheckNotFrozen(_self, upb_Array_IsFrozen(array));
49 return (upb_Array*)array;
50 }
51
RepeatedField_alloc(VALUE klass)52 VALUE RepeatedField_alloc(VALUE klass) {
53 RepeatedField* self = ALLOC(RepeatedField);
54 self->arena = Qnil;
55 self->type_class = Qnil;
56 self->array = NULL;
57 return TypedData_Wrap_Struct(klass, &RepeatedField_type, self);
58 }
59
RepeatedField_EmptyFrozen(const upb_FieldDef * f)60 VALUE RepeatedField_EmptyFrozen(const upb_FieldDef* f) {
61 PBRUBY_ASSERT(upb_FieldDef_IsRepeated(f));
62 VALUE val = ObjectCache_Get(f);
63
64 if (val == Qnil) {
65 val = RepeatedField_alloc(cRepeatedField);
66 RepeatedField* self;
67 TypedData_Get_Struct(val, RepeatedField, &RepeatedField_type, self);
68 self->arena = Arena_new();
69 TypeInfo type_info = TypeInfo_get(f);
70 self->array = upb_Array_New(Arena_get(self->arena), type_info.type);
71 self->type_info = type_info;
72 if (self->type_info.type == kUpb_CType_Message) {
73 self->type_class = Descriptor_DefToClass(type_info.def.msgdef);
74 }
75 val = ObjectCache_TryAdd(f, RepeatedField_freeze(val));
76 }
77 PBRUBY_ASSERT(RB_OBJ_FROZEN(val));
78 PBRUBY_ASSERT(upb_Array_IsFrozen(ruby_to_RepeatedField(val)->array));
79 return val;
80 }
81
RepeatedField_GetRubyWrapper(const upb_Array * array,TypeInfo type_info,VALUE arena)82 VALUE RepeatedField_GetRubyWrapper(const upb_Array* array, TypeInfo type_info,
83 VALUE arena) {
84 PBRUBY_ASSERT(array);
85 PBRUBY_ASSERT(arena != Qnil);
86 VALUE val = ObjectCache_Get(array);
87
88 if (val == Qnil) {
89 val = RepeatedField_alloc(cRepeatedField);
90 RepeatedField* self;
91 TypedData_Get_Struct(val, RepeatedField, &RepeatedField_type, self);
92 self->array = array;
93 self->arena = arena;
94 self->type_info = type_info;
95 if (self->type_info.type == kUpb_CType_Message) {
96 self->type_class = Descriptor_DefToClass(type_info.def.msgdef);
97 }
98 val = ObjectCache_TryAdd(array, val);
99 }
100
101 PBRUBY_ASSERT(ruby_to_RepeatedField(val)->type_info.type == type_info.type);
102 PBRUBY_ASSERT(ruby_to_RepeatedField(val)->type_info.def.msgdef ==
103 type_info.def.msgdef);
104 PBRUBY_ASSERT(ruby_to_RepeatedField(val)->array == array);
105 return val;
106 }
107
RepeatedField_new_this_type(RepeatedField * from)108 static VALUE RepeatedField_new_this_type(RepeatedField* from) {
109 VALUE arena_rb = Arena_new();
110 upb_Array* array = upb_Array_New(Arena_get(arena_rb), from->type_info.type);
111 VALUE ret = RepeatedField_GetRubyWrapper(array, from->type_info, arena_rb);
112 PBRUBY_ASSERT(ruby_to_RepeatedField(ret)->type_class == from->type_class);
113 return ret;
114 }
115
RepeatedField_Inspect(StringBuilder * b,const upb_Array * array,TypeInfo info)116 void RepeatedField_Inspect(StringBuilder* b, const upb_Array* array,
117 TypeInfo info) {
118 bool first = true;
119 StringBuilder_Printf(b, "[");
120 size_t n = array ? upb_Array_Size(array) : 0;
121 for (size_t i = 0; i < n; i++) {
122 if (first) {
123 first = false;
124 } else {
125 StringBuilder_Printf(b, ", ");
126 }
127 StringBuilder_PrintMsgval(b, upb_Array_Get(array, i), info);
128 }
129 StringBuilder_Printf(b, "]");
130 }
131
RepeatedField_deep_copy(VALUE _self)132 VALUE RepeatedField_deep_copy(VALUE _self) {
133 RepeatedField* self = ruby_to_RepeatedField(_self);
134 VALUE new_rptfield = RepeatedField_new_this_type(self);
135 RepeatedField* new_self = ruby_to_RepeatedField(new_rptfield);
136 VALUE arena_rb = new_self->arena;
137 upb_Array* new_array = RepeatedField_GetMutable(new_rptfield);
138 upb_Arena* arena = Arena_get(arena_rb);
139 size_t elements = upb_Array_Size(self->array);
140
141 upb_Array_Resize(new_array, elements, arena);
142
143 size_t size = upb_Array_Size(self->array);
144 for (size_t i = 0; i < size; i++) {
145 upb_MessageValue msgval = upb_Array_Get(self->array, i);
146 upb_MessageValue copy = Msgval_DeepCopy(msgval, self->type_info, arena);
147 upb_Array_Set(new_array, i, copy);
148 }
149
150 return new_rptfield;
151 }
152
RepeatedField_GetUpbArray(VALUE val,const upb_FieldDef * field,upb_Arena * arena)153 const upb_Array* RepeatedField_GetUpbArray(VALUE val, const upb_FieldDef* field,
154 upb_Arena* arena) {
155 RepeatedField* self;
156 TypeInfo type_info = TypeInfo_get(field);
157
158 if (!RB_TYPE_P(val, T_DATA) || !RTYPEDDATA_P(val) ||
159 RTYPEDDATA_TYPE(val) != &RepeatedField_type) {
160 rb_raise(cTypeError, "Expected repeated field array");
161 }
162
163 self = ruby_to_RepeatedField(val);
164 if (self->type_info.type != type_info.type) {
165 rb_raise(cTypeError, "Repeated field array has wrong element type");
166 }
167
168 if (self->type_info.def.msgdef != type_info.def.msgdef) {
169 rb_raise(cTypeError, "Repeated field array has wrong message/enum class");
170 }
171
172 Arena_fuse(self->arena, arena);
173 return self->array;
174 }
175
index_position(VALUE _index,RepeatedField * repeated_field)176 static int index_position(VALUE _index, RepeatedField* repeated_field) {
177 int index = NUM2INT(_index);
178 if (index < 0) index += upb_Array_Size(repeated_field->array);
179 return index;
180 }
181
RepeatedField_subarray(RepeatedField * self,long beg,long len)182 static VALUE RepeatedField_subarray(RepeatedField* self, long beg, long len) {
183 size_t size = upb_Array_Size(self->array);
184 VALUE ary = rb_ary_new2(size);
185 long i;
186
187 for (i = beg; i < beg + len; i++) {
188 upb_MessageValue msgval = upb_Array_Get(self->array, i);
189 VALUE elem = Convert_UpbToRuby(msgval, self->type_info, self->arena);
190 rb_ary_push(ary, elem);
191 }
192 return ary;
193 }
194
195 /*
196 * call-seq:
197 * RepeatedField.each(&block)
198 *
199 * Invokes the block once for each element of the repeated field. RepeatedField
200 * also includes Enumerable; combined with this method, the repeated field thus
201 * acts like an ordinary Ruby sequence.
202 */
RepeatedField_each(VALUE _self)203 static VALUE RepeatedField_each(VALUE _self) {
204 RepeatedField* self = ruby_to_RepeatedField(_self);
205 int size = upb_Array_Size(self->array);
206 int i;
207
208 for (i = 0; i < size; i++) {
209 upb_MessageValue msgval = upb_Array_Get(self->array, i);
210 VALUE val = Convert_UpbToRuby(msgval, self->type_info, self->arena);
211 rb_yield(val);
212 }
213 return _self;
214 }
215
216 /*
217 * call-seq:
218 * RepeatedField.[](index) => value
219 *
220 * Accesses the element at the given index. Returns nil on out-of-bounds
221 */
RepeatedField_index(int argc,VALUE * argv,VALUE _self)222 static VALUE RepeatedField_index(int argc, VALUE* argv, VALUE _self) {
223 RepeatedField* self = ruby_to_RepeatedField(_self);
224 long size = upb_Array_Size(self->array);
225
226 VALUE arg = argv[0];
227 long beg, len;
228
229 if (argc == 1) {
230 if (FIXNUM_P(arg)) {
231 /* standard case */
232 upb_MessageValue msgval;
233 int index = index_position(argv[0], self);
234 if (index < 0 || (size_t)index >= upb_Array_Size(self->array)) {
235 return Qnil;
236 }
237 msgval = upb_Array_Get(self->array, index);
238 return Convert_UpbToRuby(msgval, self->type_info, self->arena);
239 } else {
240 /* check if idx is Range */
241 switch (rb_range_beg_len(arg, &beg, &len, size, 0)) {
242 case Qfalse:
243 break;
244 case Qnil:
245 return Qnil;
246 default:
247 return RepeatedField_subarray(self, beg, len);
248 }
249 }
250 }
251
252 /* assume 2 arguments */
253 beg = NUM2LONG(argv[0]);
254 len = NUM2LONG(argv[1]);
255 if (beg < 0) {
256 beg += size;
257 }
258 if (beg >= size) {
259 return Qnil;
260 }
261 return RepeatedField_subarray(self, beg, len);
262 }
263
264 /*
265 * call-seq:
266 * RepeatedField.[]=(index, value)
267 *
268 * Sets the element at the given index. On out-of-bounds assignments, extends
269 * the array and fills the hole (if any) with default values.
270 */
RepeatedField_index_set(VALUE _self,VALUE _index,VALUE val)271 static VALUE RepeatedField_index_set(VALUE _self, VALUE _index, VALUE val) {
272 RepeatedField* self = ruby_to_RepeatedField(_self);
273 int size = upb_Array_Size(self->array);
274 upb_Array* array = RepeatedField_GetMutable(_self);
275 upb_Arena* arena = Arena_get(self->arena);
276 upb_MessageValue msgval = Convert_RubyToUpb(val, "", self->type_info, arena);
277
278 int index = index_position(_index, self);
279 if (index < 0 || index >= (INT_MAX - 1)) {
280 return Qnil;
281 }
282
283 if (index >= size) {
284 upb_Array_Resize(array, index + 1, arena);
285 upb_MessageValue fill;
286 memset(&fill, 0, sizeof(fill));
287 for (int i = size; i < index; i++) {
288 // Fill default values.
289 // TODO: should this happen at the upb level?
290 upb_Array_Set(array, i, fill);
291 }
292 }
293
294 upb_Array_Set(array, index, msgval);
295 return Qnil;
296 }
297
298 /*
299 * call-seq:
300 * RepeatedField.push(value, ...)
301 *
302 * Adds a new element to the repeated field.
303 */
RepeatedField_push_vararg(int argc,VALUE * argv,VALUE _self)304 static VALUE RepeatedField_push_vararg(int argc, VALUE* argv, VALUE _self) {
305 RepeatedField* self = ruby_to_RepeatedField(_self);
306 upb_Arena* arena = Arena_get(self->arena);
307 upb_Array* array = RepeatedField_GetMutable(_self);
308 int i;
309
310 for (i = 0; i < argc; i++) {
311 upb_MessageValue msgval =
312 Convert_RubyToUpb(argv[i], "", self->type_info, arena);
313 upb_Array_Append(array, msgval, arena);
314 }
315
316 return _self;
317 }
318
319 /*
320 * call-seq:
321 * RepeatedField.<<(value)
322 *
323 * Adds a new element to the repeated field.
324 */
RepeatedField_push(VALUE _self,VALUE val)325 static VALUE RepeatedField_push(VALUE _self, VALUE val) {
326 RepeatedField* self = ruby_to_RepeatedField(_self);
327 upb_Arena* arena = Arena_get(self->arena);
328 upb_Array* array = RepeatedField_GetMutable(_self);
329
330 upb_MessageValue msgval = Convert_RubyToUpb(val, "", self->type_info, arena);
331 upb_Array_Append(array, msgval, arena);
332
333 return _self;
334 }
335
336 /*
337 * Private ruby method, used by RepeatedField.pop
338 */
RepeatedField_pop_one(VALUE _self)339 static VALUE RepeatedField_pop_one(VALUE _self) {
340 RepeatedField* self = ruby_to_RepeatedField(_self);
341 size_t size = upb_Array_Size(self->array);
342 upb_Array* array = RepeatedField_GetMutable(_self);
343 upb_MessageValue last;
344 VALUE ret;
345
346 if (size == 0) {
347 return Qnil;
348 }
349
350 last = upb_Array_Get(self->array, size - 1);
351 ret = Convert_UpbToRuby(last, self->type_info, self->arena);
352
353 upb_Array_Resize(array, size - 1, Arena_get(self->arena));
354 return ret;
355 }
356
357 /*
358 * call-seq:
359 * RepeatedField.replace(list)
360 *
361 * Replaces the contents of the repeated field with the given list of elements.
362 */
RepeatedField_replace(VALUE _self,VALUE list)363 static VALUE RepeatedField_replace(VALUE _self, VALUE list) {
364 RepeatedField* self = ruby_to_RepeatedField(_self);
365 upb_Array* array = RepeatedField_GetMutable(_self);
366 int i;
367
368 Check_Type(list, T_ARRAY);
369 upb_Array_Resize(array, 0, Arena_get(self->arena));
370
371 for (i = 0; i < RARRAY_LEN(list); i++) {
372 RepeatedField_push(_self, rb_ary_entry(list, i));
373 }
374
375 return list;
376 }
377
378 /*
379 * call-seq:
380 * RepeatedField.clear
381 *
382 * Clears (removes all elements from) this repeated field.
383 */
RepeatedField_clear(VALUE _self)384 static VALUE RepeatedField_clear(VALUE _self) {
385 RepeatedField* self = ruby_to_RepeatedField(_self);
386 upb_Array* array = RepeatedField_GetMutable(_self);
387 upb_Array_Resize(array, 0, Arena_get(self->arena));
388 return _self;
389 }
390
391 /*
392 * call-seq:
393 * RepeatedField.length
394 *
395 * Returns the length of this repeated field.
396 */
RepeatedField_length(VALUE _self)397 static VALUE RepeatedField_length(VALUE _self) {
398 RepeatedField* self = ruby_to_RepeatedField(_self);
399 return INT2NUM(upb_Array_Size(self->array));
400 }
401
402 /*
403 * call-seq:
404 * RepeatedField.dup => repeated_field
405 *
406 * Duplicates this repeated field with a shallow copy. References to all
407 * non-primitive element objects (e.g., submessages) are shared.
408 */
RepeatedField_dup(VALUE _self)409 static VALUE RepeatedField_dup(VALUE _self) {
410 RepeatedField* self = ruby_to_RepeatedField(_self);
411 VALUE new_rptfield = RepeatedField_new_this_type(self);
412 RepeatedField* new_rptfield_self = ruby_to_RepeatedField(new_rptfield);
413 upb_Array* new_array = RepeatedField_GetMutable(new_rptfield);
414 upb_Arena* arena = Arena_get(new_rptfield_self->arena);
415 int size = upb_Array_Size(self->array);
416 int i;
417
418 Arena_fuse(self->arena, arena);
419
420 for (i = 0; i < size; i++) {
421 upb_MessageValue msgval = upb_Array_Get(self->array, i);
422 upb_Array_Append(new_array, msgval, arena);
423 }
424
425 return new_rptfield;
426 }
427
428 /*
429 * call-seq:
430 * RepeatedField.to_ary => array
431 *
432 * Used when converted implicitly into array, e.g. compared to an Array.
433 * Also called as a fallback of Object#to_a
434 */
RepeatedField_to_ary(VALUE _self)435 VALUE RepeatedField_to_ary(VALUE _self) {
436 RepeatedField* self = ruby_to_RepeatedField(_self);
437 int size = upb_Array_Size(self->array);
438 VALUE ary = rb_ary_new2(size);
439 int i;
440
441 for (i = 0; i < size; i++) {
442 upb_MessageValue msgval = upb_Array_Get(self->array, i);
443 VALUE val = Convert_UpbToRuby(msgval, self->type_info, self->arena);
444 rb_ary_push(ary, val);
445 }
446
447 return ary;
448 }
449
450 /*
451 * call-seq:
452 * RepeatedField.==(other) => boolean
453 *
454 * Compares this repeated field to another. Repeated fields are equal if their
455 * element types are equal, their lengths are equal, and each element is equal.
456 * Elements are compared as per normal Ruby semantics, by calling their :==
457 * methods (or performing a more efficient comparison for primitive types).
458 *
459 * Repeated fields with dissimilar element types are never equal, even if value
460 * comparison (for example, between integers and floats) would have otherwise
461 * indicated that every element has equal value.
462 */
RepeatedField_eq(VALUE _self,VALUE _other)463 VALUE RepeatedField_eq(VALUE _self, VALUE _other) {
464 RepeatedField* self;
465 RepeatedField* other;
466
467 if (_self == _other) {
468 return Qtrue;
469 }
470
471 if (TYPE(_other) == T_ARRAY) {
472 VALUE self_ary = RepeatedField_to_ary(_self);
473 return rb_equal(self_ary, _other);
474 }
475
476 self = ruby_to_RepeatedField(_self);
477 other = ruby_to_RepeatedField(_other);
478 size_t n = upb_Array_Size(self->array);
479
480 if (self->type_info.type != other->type_info.type ||
481 self->type_class != other->type_class ||
482 upb_Array_Size(other->array) != n) {
483 return Qfalse;
484 }
485
486 for (size_t i = 0; i < n; i++) {
487 upb_MessageValue val1 = upb_Array_Get(self->array, i);
488 upb_MessageValue val2 = upb_Array_Get(other->array, i);
489 if (!Msgval_IsEqual(val1, val2, self->type_info)) {
490 return Qfalse;
491 }
492 }
493
494 return Qtrue;
495 }
496
497 /*
498 * call-seq:
499 * RepeatedField.frozen? => bool
500 *
501 * Returns true if the repeated field is frozen in either Ruby or the underlying
502 * representation. Freezes the Ruby repeated field object if it is not already
503 * frozen in Ruby but it is frozen in the underlying representation.
504 */
RepeatedField_frozen(VALUE _self)505 VALUE RepeatedField_frozen(VALUE _self) {
506 RepeatedField* self = ruby_to_RepeatedField(_self);
507 if (!upb_Array_IsFrozen(self->array)) {
508 PBRUBY_ASSERT(!RB_OBJ_FROZEN(_self));
509 return Qfalse;
510 }
511
512 // Lazily freeze the Ruby wrapper.
513 if (!RB_OBJ_FROZEN(_self)) RB_OBJ_FREEZE(_self);
514 return Qtrue;
515 }
516
517 /*
518 * call-seq:
519 * RepeatedField.freeze => self
520 *
521 * Freezes the repeated field object. We have to intercept this so we can freeze
522 * the underlying representation, not just the Ruby wrapper.
523 */
RepeatedField_freeze(VALUE _self)524 VALUE RepeatedField_freeze(VALUE _self) {
525 RepeatedField* self = ruby_to_RepeatedField(_self);
526 if (RB_OBJ_FROZEN(_self)) {
527 PBRUBY_ASSERT(upb_Array_IsFrozen(self->array));
528 return _self;
529 }
530
531 if (!upb_Array_IsFrozen(self->array)) {
532 if (self->type_info.type == kUpb_CType_Message) {
533 upb_Array_Freeze(RepeatedField_GetMutable(_self),
534 upb_MessageDef_MiniTable(self->type_info.def.msgdef));
535 } else {
536 upb_Array_Freeze(RepeatedField_GetMutable(_self), NULL);
537 }
538 }
539 RB_OBJ_FREEZE(_self);
540 return _self;
541 }
542
543 /*
544 * call-seq:
545 * RepeatedField.hash => hash_value
546 *
547 * Returns a hash value computed from this repeated field's elements.
548 */
RepeatedField_hash(VALUE _self)549 VALUE RepeatedField_hash(VALUE _self) {
550 RepeatedField* self = ruby_to_RepeatedField(_self);
551 uint64_t hash = 0;
552 size_t n = upb_Array_Size(self->array);
553
554 for (size_t i = 0; i < n; i++) {
555 upb_MessageValue val = upb_Array_Get(self->array, i);
556 hash = Msgval_GetHash(val, self->type_info, hash);
557 }
558
559 return LL2NUM(hash);
560 }
561
562 /*
563 * call-seq:
564 * RepeatedField.+(other) => repeated field
565 *
566 * Returns a new repeated field that contains the concatenated list of this
567 * repeated field's elements and other's elements. The other (second) list may
568 * be either another repeated field or a Ruby array.
569 */
RepeatedField_plus(VALUE _self,VALUE list)570 VALUE RepeatedField_plus(VALUE _self, VALUE list) {
571 VALUE dupped_ = RepeatedField_dup(_self);
572
573 if (TYPE(list) == T_ARRAY) {
574 int i;
575 for (i = 0; i < RARRAY_LEN(list); i++) {
576 VALUE elem = rb_ary_entry(list, i);
577 RepeatedField_push(dupped_, elem);
578 }
579 } else if (RB_TYPE_P(list, T_DATA) && RTYPEDDATA_P(list) &&
580 RTYPEDDATA_TYPE(list) == &RepeatedField_type) {
581 RepeatedField* self = ruby_to_RepeatedField(_self);
582 RepeatedField* list_rptfield = ruby_to_RepeatedField(list);
583 RepeatedField* dupped = ruby_to_RepeatedField(dupped_);
584 upb_Array* dupped_array = RepeatedField_GetMutable(dupped_);
585 upb_Arena* arena = Arena_get(dupped->arena);
586 Arena_fuse(list_rptfield->arena, arena);
587 int size = upb_Array_Size(list_rptfield->array);
588 int i;
589
590 if (self->type_info.type != list_rptfield->type_info.type ||
591 self->type_class != list_rptfield->type_class) {
592 rb_raise(rb_eArgError,
593 "Attempt to append RepeatedField with different element type.");
594 }
595
596 for (i = 0; i < size; i++) {
597 upb_MessageValue msgval = upb_Array_Get(list_rptfield->array, i);
598 upb_Array_Append(dupped_array, msgval, arena);
599 }
600 } else {
601 rb_raise(rb_eArgError, "Unknown type appending to RepeatedField");
602 }
603
604 return dupped_;
605 }
606
607 /*
608 * call-seq:
609 * RepeatedField.concat(other) => self
610 *
611 * concats the passed in array to self. Returns a Ruby array.
612 */
RepeatedField_concat(VALUE _self,VALUE list)613 VALUE RepeatedField_concat(VALUE _self, VALUE list) {
614 int i;
615
616 Check_Type(list, T_ARRAY);
617 for (i = 0; i < RARRAY_LEN(list); i++) {
618 RepeatedField_push(_self, rb_ary_entry(list, i));
619 }
620 return _self;
621 }
622
623 /*
624 * call-seq:
625 * RepeatedField.new(type, type_class = nil, initial_elems = [])
626 *
627 * Creates a new repeated field. The provided type must be a Ruby symbol, and
628 * can take on the same values as those accepted by FieldDescriptor#type=. If
629 * the type is :message or :enum, type_class must be non-nil, and must be the
630 * Ruby class or module returned by Descriptor#msgclass or
631 * EnumDescriptor#enummodule, respectively. An initial list of elements may also
632 * be provided.
633 */
RepeatedField_init(int argc,VALUE * argv,VALUE _self)634 VALUE RepeatedField_init(int argc, VALUE* argv, VALUE _self) {
635 RepeatedField* self = ruby_to_RepeatedField(_self);
636 upb_Arena* arena;
637 VALUE ary = Qnil;
638
639 self->arena = Arena_new();
640 arena = Arena_get(self->arena);
641
642 if (argc < 1) {
643 rb_raise(rb_eArgError, "Expected at least 1 argument.");
644 }
645
646 self->type_info = TypeInfo_FromClass(argc, argv, 0, &self->type_class, &ary);
647 self->array = upb_Array_New(arena, self->type_info.type);
648 VALUE stored_val = ObjectCache_TryAdd(self->array, _self);
649 PBRUBY_ASSERT(stored_val == _self);
650
651 if (ary != Qnil) {
652 if (!RB_TYPE_P(ary, T_ARRAY)) {
653 rb_raise(rb_eArgError, "Expected array as initialize argument");
654 }
655 for (int i = 0; i < RARRAY_LEN(ary); i++) {
656 RepeatedField_push(_self, rb_ary_entry(ary, i));
657 }
658 }
659 return Qnil;
660 }
661
RepeatedField_register(VALUE module)662 void RepeatedField_register(VALUE module) {
663 VALUE klass = rb_define_class_under(module, "RepeatedField", rb_cObject);
664 rb_define_alloc_func(klass, RepeatedField_alloc);
665 rb_gc_register_address(&cRepeatedField);
666 cRepeatedField = klass;
667
668 rb_define_method(klass, "initialize", RepeatedField_init, -1);
669 rb_define_method(klass, "each", RepeatedField_each, 0);
670 rb_define_method(klass, "[]", RepeatedField_index, -1);
671 rb_define_method(klass, "at", RepeatedField_index, -1);
672 rb_define_method(klass, "[]=", RepeatedField_index_set, 2);
673 rb_define_method(klass, "push", RepeatedField_push_vararg, -1);
674 rb_define_method(klass, "<<", RepeatedField_push, 1);
675 rb_define_private_method(klass, "pop_one", RepeatedField_pop_one, 0);
676 rb_define_method(klass, "replace", RepeatedField_replace, 1);
677 rb_define_method(klass, "clear", RepeatedField_clear, 0);
678 rb_define_method(klass, "length", RepeatedField_length, 0);
679 rb_define_method(klass, "size", RepeatedField_length, 0);
680 rb_define_method(klass, "dup", RepeatedField_dup, 0);
681 // Also define #clone so that we don't inherit Object#clone.
682 rb_define_method(klass, "clone", RepeatedField_dup, 0);
683 rb_define_method(klass, "==", RepeatedField_eq, 1);
684 rb_define_method(klass, "to_ary", RepeatedField_to_ary, 0);
685 rb_define_method(klass, "freeze", RepeatedField_freeze, 0);
686 rb_define_method(klass, "frozen?", RepeatedField_frozen, 0);
687 rb_define_method(klass, "hash", RepeatedField_hash, 0);
688 rb_define_method(klass, "+", RepeatedField_plus, 1);
689 rb_define_method(klass, "concat", RepeatedField_concat, 1);
690 rb_include_module(klass, rb_mEnumerable);
691 }
692