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