• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2014 Google Inc.  All rights reserved.
3 // https://developers.google.com/protocol-buffers/
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 //     * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 //     * Redistributions in binary form must reproduce the above
12 // copyright notice, this list of conditions and the following disclaimer
13 // in the documentation and/or other materials provided with the
14 // distribution.
15 //     * Neither the name of Google Inc. nor the names of its
16 // contributors may be used to endorse or promote products derived from
17 // this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 
31 #include "protobuf.h"
32 
33 // -----------------------------------------------------------------------------
34 // Repeated field container type.
35 // -----------------------------------------------------------------------------
36 
37 const rb_data_type_t RepeatedField_type = {
38   "Google::Protobuf::RepeatedField",
39   { RepeatedField_mark, RepeatedField_free, NULL },
40 };
41 
42 VALUE cRepeatedField;
43 
ruby_to_RepeatedField(VALUE _self)44 RepeatedField* ruby_to_RepeatedField(VALUE _self) {
45   RepeatedField* self;
46   TypedData_Get_Struct(_self, RepeatedField, &RepeatedField_type, self);
47   return self;
48 }
49 
RepeatedField_memoryat(RepeatedField * self,int index,int element_size)50 void* RepeatedField_memoryat(RepeatedField* self, int index, int element_size) {
51   return ((uint8_t *)self->elements) + index * element_size;
52 }
53 
index_position(VALUE _index,RepeatedField * repeated_field)54 static int index_position(VALUE _index, RepeatedField* repeated_field) {
55   int index = NUM2INT(_index);
56   if (index < 0 && repeated_field->size > 0) {
57     index = repeated_field->size + index;
58   }
59   return index;
60 }
61 
RepeatedField_subarray(VALUE _self,long beg,long len)62 VALUE RepeatedField_subarray(VALUE _self, long beg, long len) {
63   RepeatedField* self = ruby_to_RepeatedField(_self);
64   int element_size = native_slot_size(self->field_type);
65   upb_fieldtype_t field_type = self->field_type;
66   VALUE field_type_class = self->field_type_class;
67   size_t off = beg * element_size;
68   VALUE ary = rb_ary_new2(len);
69   int i;
70 
71   for (i = beg; i < beg + len; i++, off += element_size) {
72     void* mem = ((uint8_t *)self->elements) + off;
73     VALUE elem = native_slot_get(field_type, field_type_class, mem);
74     rb_ary_push(ary, elem);
75   }
76   return ary;
77 }
78 
79 /*
80  * call-seq:
81  *     RepeatedField.each(&block)
82  *
83  * Invokes the block once for each element of the repeated field. RepeatedField
84  * also includes Enumerable; combined with this method, the repeated field thus
85  * acts like an ordinary Ruby sequence.
86  */
RepeatedField_each(VALUE _self)87 VALUE RepeatedField_each(VALUE _self) {
88   RepeatedField* self = ruby_to_RepeatedField(_self);
89   upb_fieldtype_t field_type = self->field_type;
90   VALUE field_type_class = self->field_type_class;
91   int element_size = native_slot_size(field_type);
92   size_t off = 0;
93   int i;
94 
95   for (i = 0; i < self->size; i++, off += element_size) {
96     void* memory = (void *) (((uint8_t *)self->elements) + off);
97     VALUE val = native_slot_get(field_type, field_type_class, memory);
98     rb_yield(val);
99   }
100   return _self;
101 }
102 
103 
104 /*
105  * call-seq:
106  *     RepeatedField.[](index) => value
107  *
108  * Accesses the element at the given index. Returns nil on out-of-bounds
109  */
RepeatedField_index(int argc,VALUE * argv,VALUE _self)110 VALUE RepeatedField_index(int argc, VALUE* argv, VALUE _self) {
111   RepeatedField* self = ruby_to_RepeatedField(_self);
112   int element_size = native_slot_size(self->field_type);
113   upb_fieldtype_t field_type = self->field_type;
114   VALUE field_type_class = self->field_type_class;
115 
116   VALUE arg = argv[0];
117   long beg, len;
118 
119   if (argc == 1){
120     if (FIXNUM_P(arg)) {
121       /* standard case */
122       void* memory;
123       int index = index_position(argv[0], self);
124       if (index < 0 || index >= self->size) {
125         return Qnil;
126       }
127       memory = RepeatedField_memoryat(self, index, element_size);
128       return native_slot_get(field_type, field_type_class, memory);
129     }else{
130       /* check if idx is Range */
131       switch (rb_range_beg_len(arg, &beg, &len, self->size, 0)) {
132         case Qfalse:
133           break;
134         case Qnil:
135           return Qnil;
136         default:
137           return RepeatedField_subarray(_self, beg, len);
138       }
139     }
140   }
141   /* assume 2 arguments */
142   beg = NUM2LONG(argv[0]);
143   len = NUM2LONG(argv[1]);
144   if (beg < 0) {
145     beg += self->size;
146   }
147   if (beg >= self->size) {
148     return Qnil;
149   }
150   return RepeatedField_subarray(_self, beg, len);
151 }
152 
153 /*
154  * call-seq:
155  *     RepeatedField.[]=(index, value)
156  *
157  * Sets the element at the given index. On out-of-bounds assignments, extends
158  * the array and fills the hole (if any) with default values.
159  */
RepeatedField_index_set(VALUE _self,VALUE _index,VALUE val)160 VALUE RepeatedField_index_set(VALUE _self, VALUE _index, VALUE val) {
161   RepeatedField* self = ruby_to_RepeatedField(_self);
162   upb_fieldtype_t field_type = self->field_type;
163   VALUE field_type_class = self->field_type_class;
164   int element_size = native_slot_size(field_type);
165   void* memory;
166 
167   int index = index_position(_index, self);
168   if (index < 0 || index >= (INT_MAX - 1)) {
169     return Qnil;
170   }
171   if (index >= self->size) {
172     upb_fieldtype_t field_type = self->field_type;
173     int element_size = native_slot_size(field_type);
174     int i;
175 
176     RepeatedField_reserve(self, index + 1);
177     for (i = self->size; i <= index; i++) {
178       void* elem = RepeatedField_memoryat(self, i, element_size);
179       native_slot_init(field_type, elem);
180     }
181     self->size = index + 1;
182   }
183 
184   memory = RepeatedField_memoryat(self, index, element_size);
185   native_slot_set("", field_type, field_type_class, memory, val);
186   return Qnil;
187 }
188 
189 static int kInitialSize = 8;
190 
RepeatedField_reserve(RepeatedField * self,int new_size)191 void RepeatedField_reserve(RepeatedField* self, int new_size) {
192   void* old_elems = self->elements;
193   int elem_size = native_slot_size(self->field_type);
194   if (new_size <= self->capacity) {
195     return;
196   }
197   if (self->capacity == 0) {
198     self->capacity = kInitialSize;
199   }
200   while (self->capacity < new_size) {
201     self->capacity *= 2;
202   }
203   self->elements = ALLOC_N(uint8_t, elem_size * self->capacity);
204   if (old_elems != NULL) {
205     memcpy(self->elements, old_elems, self->size * elem_size);
206     xfree(old_elems);
207   }
208 }
209 
210 /*
211  * call-seq:
212  *     RepeatedField.push(value)
213  *
214  * Adds a new element to the repeated field.
215  */
RepeatedField_push(VALUE _self,VALUE val)216 VALUE RepeatedField_push(VALUE _self, VALUE val) {
217   RepeatedField* self = ruby_to_RepeatedField(_self);
218   upb_fieldtype_t field_type = self->field_type;
219   int element_size = native_slot_size(field_type);
220   void* memory;
221 
222   RepeatedField_reserve(self, self->size + 1);
223   memory = (void *) (((uint8_t *)self->elements) + self->size * element_size);
224   native_slot_set("", field_type, self->field_type_class, memory, val);
225   // native_slot_set may raise an error; bump size only after set.
226   self->size++;
227   return _self;
228 }
229 
RepeatedField_push_vararg(VALUE _self,VALUE args)230 VALUE RepeatedField_push_vararg(VALUE _self, VALUE args) {
231   int i;
232   for (i = 0; i < RARRAY_LEN(args); i++) {
233     RepeatedField_push(_self, rb_ary_entry(args, i));
234   }
235   return _self;
236 }
237 
238 // Used by parsing handlers.
RepeatedField_push_native(VALUE _self,void * data)239 void RepeatedField_push_native(VALUE _self, void* data) {
240   RepeatedField* self = ruby_to_RepeatedField(_self);
241   upb_fieldtype_t field_type = self->field_type;
242   int element_size = native_slot_size(field_type);
243   void* memory;
244 
245   RepeatedField_reserve(self, self->size + 1);
246   memory = (void *) (((uint8_t *)self->elements) + self->size * element_size);
247   memcpy(memory, data, element_size);
248   self->size++;
249 }
250 
RepeatedField_index_native(VALUE _self,int index)251 void* RepeatedField_index_native(VALUE _self, int index) {
252   RepeatedField* self = ruby_to_RepeatedField(_self);
253   upb_fieldtype_t field_type = self->field_type;
254   int element_size = native_slot_size(field_type);
255   return RepeatedField_memoryat(self, index, element_size);
256 }
257 
RepeatedField_size(VALUE _self)258 int RepeatedField_size(VALUE _self) {
259   RepeatedField* self = ruby_to_RepeatedField(_self);
260   return self->size;
261 }
262 
263 /*
264  * Private ruby method, used by RepeatedField.pop
265  */
RepeatedField_pop_one(VALUE _self)266 VALUE RepeatedField_pop_one(VALUE _self) {
267   RepeatedField* self = ruby_to_RepeatedField(_self);
268   upb_fieldtype_t field_type = self->field_type;
269   VALUE field_type_class = self->field_type_class;
270   int element_size = native_slot_size(field_type);
271   int index;
272   void* memory;
273   VALUE ret;
274 
275   if (self->size == 0) {
276     return Qnil;
277   }
278   index = self->size - 1;
279   memory = RepeatedField_memoryat(self, index, element_size);
280   ret = native_slot_get(field_type, field_type_class, memory);
281   self->size--;
282   return ret;
283 }
284 
285 /*
286  * call-seq:
287  *     RepeatedField.replace(list)
288  *
289  * Replaces the contents of the repeated field with the given list of elements.
290  */
RepeatedField_replace(VALUE _self,VALUE list)291 VALUE RepeatedField_replace(VALUE _self, VALUE list) {
292   RepeatedField* self = ruby_to_RepeatedField(_self);
293   int i;
294 
295   Check_Type(list, T_ARRAY);
296   self->size = 0;
297   for (i = 0; i < RARRAY_LEN(list); i++) {
298     RepeatedField_push(_self, rb_ary_entry(list, i));
299   }
300   return list;
301 }
302 
303 /*
304  * call-seq:
305  *     RepeatedField.clear
306  *
307  * Clears (removes all elements from) this repeated field.
308  */
RepeatedField_clear(VALUE _self)309 VALUE RepeatedField_clear(VALUE _self) {
310   RepeatedField* self = ruby_to_RepeatedField(_self);
311   self->size = 0;
312   return _self;
313 }
314 
315 /*
316  * call-seq:
317  *     RepeatedField.length
318  *
319  * Returns the length of this repeated field.
320  */
RepeatedField_length(VALUE _self)321 VALUE RepeatedField_length(VALUE _self) {
322   RepeatedField* self = ruby_to_RepeatedField(_self);
323   return INT2NUM(self->size);
324 }
325 
RepeatedField_new_this_type(VALUE _self)326 VALUE RepeatedField_new_this_type(VALUE _self) {
327   RepeatedField* self = ruby_to_RepeatedField(_self);
328   VALUE new_rptfield = Qnil;
329   VALUE element_type = fieldtype_to_ruby(self->field_type);
330   if (self->field_type_class != Qnil) {
331     new_rptfield = rb_funcall(CLASS_OF(_self), rb_intern("new"), 2,
332                               element_type, self->field_type_class);
333   } else {
334     new_rptfield = rb_funcall(CLASS_OF(_self), rb_intern("new"), 1,
335                               element_type);
336   }
337   return new_rptfield;
338 }
339 
340 /*
341  * call-seq:
342  *     RepeatedField.dup => repeated_field
343  *
344  * Duplicates this repeated field with a shallow copy. References to all
345  * non-primitive element objects (e.g., submessages) are shared.
346  */
RepeatedField_dup(VALUE _self)347 VALUE RepeatedField_dup(VALUE _self) {
348   RepeatedField* self = ruby_to_RepeatedField(_self);
349   VALUE new_rptfield = RepeatedField_new_this_type(_self);
350   RepeatedField* new_rptfield_self = ruby_to_RepeatedField(new_rptfield);
351   upb_fieldtype_t field_type = self->field_type;
352   size_t elem_size = native_slot_size(field_type);
353   size_t off = 0;
354   int i;
355 
356   RepeatedField_reserve(new_rptfield_self, self->size);
357   for (i = 0; i < self->size; i++, off += elem_size) {
358     void* to_mem = (uint8_t *)new_rptfield_self->elements + off;
359     void* from_mem = (uint8_t *)self->elements + off;
360     native_slot_dup(field_type, to_mem, from_mem);
361     new_rptfield_self->size++;
362   }
363 
364   return new_rptfield;
365 }
366 
367 // Internal only: used by Google::Protobuf.deep_copy.
RepeatedField_deep_copy(VALUE _self)368 VALUE RepeatedField_deep_copy(VALUE _self) {
369   RepeatedField* self = ruby_to_RepeatedField(_self);
370   VALUE new_rptfield = RepeatedField_new_this_type(_self);
371   RepeatedField* new_rptfield_self = ruby_to_RepeatedField(new_rptfield);
372   upb_fieldtype_t field_type = self->field_type;
373   size_t elem_size = native_slot_size(field_type);
374   size_t off = 0;
375   int i;
376 
377   RepeatedField_reserve(new_rptfield_self, self->size);
378   for (i = 0; i < self->size; i++, off += elem_size) {
379     void* to_mem = (uint8_t *)new_rptfield_self->elements + off;
380     void* from_mem = (uint8_t *)self->elements + off;
381     native_slot_deep_copy(field_type, self->field_type_class, to_mem, from_mem);
382     new_rptfield_self->size++;
383   }
384 
385   return new_rptfield;
386 }
387 
388 /*
389  * call-seq:
390  *     RepeatedField.to_ary => array
391  *
392  * Used when converted implicitly into array, e.g. compared to an Array.
393  * Also called as a fallback of Object#to_a
394  */
RepeatedField_to_ary(VALUE _self)395 VALUE RepeatedField_to_ary(VALUE _self) {
396   RepeatedField* self = ruby_to_RepeatedField(_self);
397   upb_fieldtype_t field_type = self->field_type;
398   size_t elem_size = native_slot_size(field_type);
399   size_t off = 0;
400   VALUE ary = rb_ary_new2(self->size);
401   int i;
402 
403   for (i = 0; i < self->size; i++, off += elem_size) {
404     void* mem = ((uint8_t *)self->elements) + off;
405     VALUE elem = native_slot_get(field_type, self->field_type_class, mem);
406     rb_ary_push(ary, elem);
407   }
408   return ary;
409 }
410 
411 /*
412  * call-seq:
413  *     RepeatedField.==(other) => boolean
414  *
415  * Compares this repeated field to another. Repeated fields are equal if their
416  * element types are equal, their lengths are equal, and each element is equal.
417  * Elements are compared as per normal Ruby semantics, by calling their :==
418  * methods (or performing a more efficient comparison for primitive types).
419  *
420  * Repeated fields with dissimilar element types are never equal, even if value
421  * comparison (for example, between integers and floats) would have otherwise
422  * indicated that every element has equal value.
423  */
RepeatedField_eq(VALUE _self,VALUE _other)424 VALUE RepeatedField_eq(VALUE _self, VALUE _other) {
425   RepeatedField* self;
426   RepeatedField* other;
427 
428   if (_self == _other) {
429     return Qtrue;
430   }
431 
432   if (TYPE(_other) == T_ARRAY) {
433     VALUE self_ary = RepeatedField_to_ary(_self);
434     return rb_equal(self_ary, _other);
435   }
436 
437   self = ruby_to_RepeatedField(_self);
438   other = ruby_to_RepeatedField(_other);
439   if (self->field_type != other->field_type ||
440       self->field_type_class != other->field_type_class ||
441       self->size != other->size) {
442     return Qfalse;
443   }
444 
445   {
446     upb_fieldtype_t field_type = self->field_type;
447     size_t elem_size = native_slot_size(field_type);
448     size_t off = 0;
449     int i;
450 
451     for (i = 0; i < self->size; i++, off += elem_size) {
452       void* self_mem = ((uint8_t *)self->elements) + off;
453       void* other_mem = ((uint8_t *)other->elements) + off;
454       if (!native_slot_eq(field_type, self->field_type_class, self_mem,
455                           other_mem)) {
456         return Qfalse;
457       }
458     }
459     return Qtrue;
460   }
461 }
462 
463 /*
464  * call-seq:
465  *     RepeatedField.hash => hash_value
466  *
467  * Returns a hash value computed from this repeated field's elements.
468  */
RepeatedField_hash(VALUE _self)469 VALUE RepeatedField_hash(VALUE _self) {
470   RepeatedField* self = ruby_to_RepeatedField(_self);
471   st_index_t h = rb_hash_start(0);
472   VALUE hash_sym = rb_intern("hash");
473   upb_fieldtype_t field_type = self->field_type;
474   VALUE field_type_class = self->field_type_class;
475   size_t elem_size = native_slot_size(field_type);
476   size_t off = 0;
477   int i;
478 
479   for (i = 0; i < self->size; i++, off += elem_size) {
480     void* mem = ((uint8_t *)self->elements) + off;
481     VALUE elem = native_slot_get(field_type, field_type_class, mem);
482     h = rb_hash_uint(h, NUM2LONG(rb_funcall(elem, hash_sym, 0)));
483   }
484   h = rb_hash_end(h);
485 
486   return INT2FIX(h);
487 }
488 
489 /*
490  * call-seq:
491  *     RepeatedField.+(other) => repeated field
492  *
493  * Returns a new repeated field that contains the concatenated list of this
494  * repeated field's elements and other's elements. The other (second) list may
495  * be either another repeated field or a Ruby array.
496  */
RepeatedField_plus(VALUE _self,VALUE list)497 VALUE RepeatedField_plus(VALUE _self, VALUE list) {
498   VALUE dupped = RepeatedField_dup(_self);
499 
500   if (TYPE(list) == T_ARRAY) {
501     int i;
502     for (i = 0; i < RARRAY_LEN(list); i++) {
503       VALUE elem = rb_ary_entry(list, i);
504       RepeatedField_push(dupped, elem);
505     }
506   } else if (RB_TYPE_P(list, T_DATA) && RTYPEDDATA_P(list) &&
507              RTYPEDDATA_TYPE(list) == &RepeatedField_type) {
508     RepeatedField* self = ruby_to_RepeatedField(_self);
509     RepeatedField* list_rptfield = ruby_to_RepeatedField(list);
510     int i;
511 
512     if (self->field_type != list_rptfield->field_type ||
513         self->field_type_class != list_rptfield->field_type_class) {
514       rb_raise(rb_eArgError,
515                "Attempt to append RepeatedField with different element type.");
516     }
517     for (i = 0; i < list_rptfield->size; i++) {
518       void* mem = RepeatedField_index_native(list, i);
519       RepeatedField_push_native(dupped, mem);
520     }
521   } else {
522     rb_raise(rb_eArgError, "Unknown type appending to RepeatedField");
523   }
524 
525   return dupped;
526 }
527 
528 /*
529  * call-seq:
530  *     RepeatedField.concat(other) => self
531  *
532  * concats the passed in array to self.  Returns a Ruby array.
533  */
RepeatedField_concat(VALUE _self,VALUE list)534 VALUE RepeatedField_concat(VALUE _self, VALUE list) {
535   int i;
536 
537   Check_Type(list, T_ARRAY);
538   for (i = 0; i < RARRAY_LEN(list); i++) {
539     RepeatedField_push(_self, rb_ary_entry(list, i));
540   }
541   return _self;
542 }
543 
544 
validate_type_class(upb_fieldtype_t type,VALUE klass)545 void validate_type_class(upb_fieldtype_t type, VALUE klass) {
546   if (rb_ivar_get(klass, descriptor_instancevar_interned) == Qnil) {
547     rb_raise(rb_eArgError,
548              "Type class has no descriptor. Please pass a "
549              "class or enum as returned by the DescriptorPool.");
550   }
551   if (type == UPB_TYPE_MESSAGE) {
552     VALUE desc = rb_ivar_get(klass, descriptor_instancevar_interned);
553     if (!RB_TYPE_P(desc, T_DATA) || !RTYPEDDATA_P(desc) ||
554         RTYPEDDATA_TYPE(desc) != &_Descriptor_type) {
555       rb_raise(rb_eArgError, "Descriptor has an incorrect type.");
556     }
557     if (rb_get_alloc_func(klass) != &Message_alloc) {
558       rb_raise(rb_eArgError,
559                "Message class was not returned by the DescriptorPool.");
560     }
561   } else if (type == UPB_TYPE_ENUM) {
562     VALUE enumdesc = rb_ivar_get(klass, descriptor_instancevar_interned);
563     if (!RB_TYPE_P(enumdesc, T_DATA) || !RTYPEDDATA_P(enumdesc) ||
564         RTYPEDDATA_TYPE(enumdesc) != &_EnumDescriptor_type) {
565       rb_raise(rb_eArgError, "Descriptor has an incorrect type.");
566     }
567   }
568 }
569 
RepeatedField_init_args(int argc,VALUE * argv,VALUE _self)570 void RepeatedField_init_args(int argc, VALUE* argv,
571                              VALUE _self) {
572   RepeatedField* self = ruby_to_RepeatedField(_self);
573   VALUE ary = Qnil;
574   if (argc < 1) {
575     rb_raise(rb_eArgError, "Expected at least 1 argument.");
576   }
577   self->field_type = ruby_to_fieldtype(argv[0]);
578 
579   if (self->field_type == UPB_TYPE_MESSAGE ||
580       self->field_type == UPB_TYPE_ENUM) {
581     if (argc < 2) {
582       rb_raise(rb_eArgError, "Expected at least 2 arguments for message/enum.");
583     }
584     self->field_type_class = argv[1];
585     if (argc > 2) {
586       ary = argv[2];
587     }
588     validate_type_class(self->field_type, self->field_type_class);
589   } else {
590     if (argc > 2) {
591       rb_raise(rb_eArgError, "Too many arguments: expected 1 or 2.");
592     }
593     if (argc > 1) {
594       ary = argv[1];
595     }
596   }
597 
598   if (ary != Qnil) {
599     int i;
600 
601     if (!RB_TYPE_P(ary, T_ARRAY)) {
602       rb_raise(rb_eArgError, "Expected array as initialize argument");
603     }
604     for (i = 0; i < RARRAY_LEN(ary); i++) {
605       RepeatedField_push(_self, rb_ary_entry(ary, i));
606     }
607   }
608 }
609 
610 // Mark, free, alloc, init and class setup functions.
611 
RepeatedField_mark(void * _self)612 void RepeatedField_mark(void* _self) {
613   RepeatedField* self = (RepeatedField*)_self;
614   upb_fieldtype_t field_type = self->field_type;
615   int element_size = native_slot_size(field_type);
616   int i;
617 
618   rb_gc_mark(self->field_type_class);
619   for (i = 0; i < self->size; i++) {
620     void* memory = (((uint8_t *)self->elements) + i * element_size);
621     native_slot_mark(self->field_type, memory);
622   }
623 }
624 
RepeatedField_free(void * _self)625 void RepeatedField_free(void* _self) {
626   RepeatedField* self = (RepeatedField*)_self;
627   xfree(self->elements);
628   xfree(self);
629 }
630 
631 /*
632  * call-seq:
633  *     RepeatedField.new(type, type_class = nil, initial_elems = [])
634  *
635  * Creates a new repeated field. The provided type must be a Ruby symbol, and
636  * can take on the same values as those accepted by FieldDescriptor#type=. If
637  * the type is :message or :enum, type_class must be non-nil, and must be the
638  * Ruby class or module returned by Descriptor#msgclass or
639  * EnumDescriptor#enummodule, respectively. An initial list of elements may also
640  * be provided.
641  */
RepeatedField_alloc(VALUE klass)642 VALUE RepeatedField_alloc(VALUE klass) {
643   RepeatedField* self = ALLOC(RepeatedField);
644   self->elements = NULL;
645   self->size = 0;
646   self->capacity = 0;
647   self->field_type = -1;
648   self->field_type_class = Qnil;
649   return TypedData_Wrap_Struct(klass, &RepeatedField_type, self);
650 }
651 
RepeatedField_init(int argc,VALUE * argv,VALUE self)652 VALUE RepeatedField_init(int argc, VALUE* argv, VALUE self) {
653   RepeatedField_init_args(argc, argv, self);
654   return Qnil;
655 }
656 
RepeatedField_register(VALUE module)657 void RepeatedField_register(VALUE module) {
658   VALUE klass = rb_define_class_under(
659       module, "RepeatedField", rb_cObject);
660   rb_define_alloc_func(klass, RepeatedField_alloc);
661   rb_gc_register_address(&cRepeatedField);
662   cRepeatedField = klass;
663 
664   rb_define_method(klass, "initialize",
665                    RepeatedField_init, -1);
666   rb_define_method(klass, "each", RepeatedField_each, 0);
667   rb_define_method(klass, "[]", RepeatedField_index, -1);
668   rb_define_method(klass, "at", RepeatedField_index, -1);
669   rb_define_method(klass, "[]=", RepeatedField_index_set, 2);
670   rb_define_method(klass, "push", RepeatedField_push_vararg, -2);
671   rb_define_method(klass, "<<", RepeatedField_push, 1);
672   rb_define_private_method(klass, "pop_one", RepeatedField_pop_one, 0);
673   rb_define_method(klass, "replace", RepeatedField_replace, 1);
674   rb_define_method(klass, "clear", RepeatedField_clear, 0);
675   rb_define_method(klass, "length", RepeatedField_length, 0);
676   rb_define_method(klass, "size", RepeatedField_length, 0);
677   rb_define_method(klass, "dup", RepeatedField_dup, 0);
678   // Also define #clone so that we don't inherit Object#clone.
679   rb_define_method(klass, "clone", RepeatedField_dup, 0);
680   rb_define_method(klass, "==", RepeatedField_eq, 1);
681   rb_define_method(klass, "to_ary", RepeatedField_to_ary, 0);
682   rb_define_method(klass, "hash", RepeatedField_hash, 0);
683   rb_define_method(klass, "+", RepeatedField_plus, 1);
684   rb_define_method(klass, "concat", RepeatedField_concat, 1);
685   rb_include_module(klass, rb_mEnumerable);
686 }
687