• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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