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 37const rb_data_type_t RepeatedField_type = { 38 "Google::Protobuf::RepeatedField", 39 { RepeatedField_mark, RepeatedField_free, NULL }, 40}; 41 42VALUE cRepeatedField; 43 44RepeatedField* ruby_to_RepeatedField(VALUE _self) { 45 RepeatedField* self; 46 TypedData_Get_Struct(_self, RepeatedField, &RepeatedField_type, self); 47 return self; 48} 49 50void* RepeatedField_memoryat(RepeatedField* self, int index, int element_size) { 51 return ((uint8_t *)self->elements) + index * element_size; 52} 53 54static 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 62VALUE 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 */ 87VALUE 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 */ 110VALUE 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 */ 160VALUE 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 189static int kInitialSize = 8; 190 191void 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 */ 216VALUE 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 230VALUE 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. 239void 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 251void* 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 258int 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 */ 266VALUE 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 */ 291VALUE 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 */ 309VALUE 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 */ 321VALUE RepeatedField_length(VALUE _self) { 322 RepeatedField* self = ruby_to_RepeatedField(_self); 323 return INT2NUM(self->size); 324} 325 326VALUE 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 */ 347VALUE 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. 368VALUE 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 */ 395VALUE 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 */ 424VALUE 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 */ 469VALUE 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 */ 497VALUE 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 */ 534VALUE 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 545void 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 570void 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 612void 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 625void 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 */ 642VALUE 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 652VALUE RepeatedField_init(int argc, VALUE* argv, VALUE self) { 653 RepeatedField_init_args(argc, argv, self); 654 return Qnil; 655} 656 657void 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