Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(78)

Side by Side Diff: third_party/protobuf/ruby/ext/google/protobuf_c/storage.c

Issue 1842653006: Update //third_party/protobuf to version 3. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: merge Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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 #include <math.h>
34
35 #include <ruby/encoding.h>
36
37 // -----------------------------------------------------------------------------
38 // Ruby <-> native slot management.
39 // -----------------------------------------------------------------------------
40
41 #define DEREF(memory, type) *(type*)(memory)
42
43 size_t native_slot_size(upb_fieldtype_t type) {
44 switch (type) {
45 case UPB_TYPE_FLOAT: return 4;
46 case UPB_TYPE_DOUBLE: return 8;
47 case UPB_TYPE_BOOL: return 1;
48 case UPB_TYPE_STRING: return sizeof(VALUE);
49 case UPB_TYPE_BYTES: return sizeof(VALUE);
50 case UPB_TYPE_MESSAGE: return sizeof(VALUE);
51 case UPB_TYPE_ENUM: return 4;
52 case UPB_TYPE_INT32: return 4;
53 case UPB_TYPE_INT64: return 8;
54 case UPB_TYPE_UINT32: return 4;
55 case UPB_TYPE_UINT64: return 8;
56 default: return 0;
57 }
58 }
59
60 static bool is_ruby_num(VALUE value) {
61 return (TYPE(value) == T_FLOAT ||
62 TYPE(value) == T_FIXNUM ||
63 TYPE(value) == T_BIGNUM);
64 }
65
66 void native_slot_check_int_range_precision(upb_fieldtype_t type, VALUE val) {
67 if (!is_ruby_num(val)) {
68 rb_raise(rb_eTypeError, "Expected number type for integral field.");
69 }
70
71 // NUM2{INT,UINT,LL,ULL} macros do the appropriate range checks on upper
72 // bound; we just need to do precision checks (i.e., disallow rounding) and
73 // check for < 0 on unsigned types.
74 if (TYPE(val) == T_FLOAT) {
75 double dbl_val = NUM2DBL(val);
76 if (floor(dbl_val) != dbl_val) {
77 rb_raise(rb_eRangeError,
78 "Non-integral floating point value assigned to integer field.");
79 }
80 }
81 if (type == UPB_TYPE_UINT32 || type == UPB_TYPE_UINT64) {
82 if (NUM2DBL(val) < 0) {
83 rb_raise(rb_eRangeError,
84 "Assigning negative value to unsigned integer field.");
85 }
86 }
87 }
88
89 void native_slot_validate_string_encoding(upb_fieldtype_t type, VALUE value) {
90 bool bad_encoding = false;
91 rb_encoding* string_encoding = rb_enc_from_index(ENCODING_GET(value));
92 if (type == UPB_TYPE_STRING) {
93 bad_encoding =
94 string_encoding != kRubyStringUtf8Encoding &&
95 string_encoding != kRubyStringASCIIEncoding;
96 } else {
97 bad_encoding =
98 string_encoding != kRubyString8bitEncoding;
99 }
100 // Check that encoding is UTF-8 or ASCII (for string fields) or ASCII-8BIT
101 // (for bytes fields).
102 if (bad_encoding) {
103 rb_raise(rb_eTypeError, "Encoding for '%s' fields must be %s (was %s)",
104 (type == UPB_TYPE_STRING) ? "string" : "bytes",
105 (type == UPB_TYPE_STRING) ? "UTF-8 or ASCII" : "ASCII-8BIT",
106 rb_enc_name(string_encoding));
107 }
108 }
109
110 void native_slot_set(upb_fieldtype_t type, VALUE type_class,
111 void* memory, VALUE value) {
112 native_slot_set_value_and_case(type, type_class, memory, value, NULL, 0);
113 }
114
115 void native_slot_set_value_and_case(upb_fieldtype_t type, VALUE type_class,
116 void* memory, VALUE value,
117 uint32_t* case_memory,
118 uint32_t case_number) {
119 // Note that in order to atomically change the value in memory and the case
120 // value (w.r.t. Ruby VM calls), we must set the value at |memory| only after
121 // all Ruby VM calls are complete. The case is then set at the bottom of this
122 // function.
123 switch (type) {
124 case UPB_TYPE_FLOAT:
125 if (!is_ruby_num(value)) {
126 rb_raise(rb_eTypeError, "Expected number type for float field.");
127 }
128 DEREF(memory, float) = NUM2DBL(value);
129 break;
130 case UPB_TYPE_DOUBLE:
131 if (!is_ruby_num(value)) {
132 rb_raise(rb_eTypeError, "Expected number type for double field.");
133 }
134 DEREF(memory, double) = NUM2DBL(value);
135 break;
136 case UPB_TYPE_BOOL: {
137 int8_t val = -1;
138 if (value == Qtrue) {
139 val = 1;
140 } else if (value == Qfalse) {
141 val = 0;
142 } else {
143 rb_raise(rb_eTypeError, "Invalid argument for boolean field.");
144 }
145 DEREF(memory, int8_t) = val;
146 break;
147 }
148 case UPB_TYPE_STRING:
149 case UPB_TYPE_BYTES: {
150 if (CLASS_OF(value) != rb_cString) {
151 rb_raise(rb_eTypeError, "Invalid argument for string field.");
152 }
153 native_slot_validate_string_encoding(type, value);
154 DEREF(memory, VALUE) = value;
155 break;
156 }
157 case UPB_TYPE_MESSAGE: {
158 if (CLASS_OF(value) == CLASS_OF(Qnil)) {
159 value = Qnil;
160 } else if (CLASS_OF(value) != type_class) {
161 rb_raise(rb_eTypeError,
162 "Invalid type %s to assign to submessage field.",
163 rb_class2name(CLASS_OF(value)));
164 }
165 DEREF(memory, VALUE) = value;
166 break;
167 }
168 case UPB_TYPE_ENUM: {
169 int32_t int_val = 0;
170 if (!is_ruby_num(value) && TYPE(value) != T_SYMBOL) {
171 rb_raise(rb_eTypeError,
172 "Expected number or symbol type for enum field.");
173 }
174 if (TYPE(value) == T_SYMBOL) {
175 // Ensure that the given symbol exists in the enum module.
176 VALUE lookup = rb_funcall(type_class, rb_intern("resolve"), 1, value);
177 if (lookup == Qnil) {
178 rb_raise(rb_eRangeError, "Unknown symbol value for enum field.");
179 } else {
180 int_val = NUM2INT(lookup);
181 }
182 } else {
183 native_slot_check_int_range_precision(UPB_TYPE_INT32, value);
184 int_val = NUM2INT(value);
185 }
186 DEREF(memory, int32_t) = int_val;
187 break;
188 }
189 case UPB_TYPE_INT32:
190 case UPB_TYPE_INT64:
191 case UPB_TYPE_UINT32:
192 case UPB_TYPE_UINT64:
193 native_slot_check_int_range_precision(type, value);
194 switch (type) {
195 case UPB_TYPE_INT32:
196 DEREF(memory, int32_t) = NUM2INT(value);
197 break;
198 case UPB_TYPE_INT64:
199 DEREF(memory, int64_t) = NUM2LL(value);
200 break;
201 case UPB_TYPE_UINT32:
202 DEREF(memory, uint32_t) = NUM2UINT(value);
203 break;
204 case UPB_TYPE_UINT64:
205 DEREF(memory, uint64_t) = NUM2ULL(value);
206 break;
207 default:
208 break;
209 }
210 break;
211 default:
212 break;
213 }
214
215 if (case_memory != NULL) {
216 *case_memory = case_number;
217 }
218 }
219
220 VALUE native_slot_get(upb_fieldtype_t type,
221 VALUE type_class,
222 const void* memory) {
223 switch (type) {
224 case UPB_TYPE_FLOAT:
225 return DBL2NUM(DEREF(memory, float));
226 case UPB_TYPE_DOUBLE:
227 return DBL2NUM(DEREF(memory, double));
228 case UPB_TYPE_BOOL:
229 return DEREF(memory, int8_t) ? Qtrue : Qfalse;
230 case UPB_TYPE_STRING:
231 case UPB_TYPE_BYTES:
232 case UPB_TYPE_MESSAGE:
233 return DEREF(memory, VALUE);
234 case UPB_TYPE_ENUM: {
235 int32_t val = DEREF(memory, int32_t);
236 VALUE symbol = enum_lookup(type_class, INT2NUM(val));
237 if (symbol == Qnil) {
238 return INT2NUM(val);
239 } else {
240 return symbol;
241 }
242 }
243 case UPB_TYPE_INT32:
244 return INT2NUM(DEREF(memory, int32_t));
245 case UPB_TYPE_INT64:
246 return LL2NUM(DEREF(memory, int64_t));
247 case UPB_TYPE_UINT32:
248 return UINT2NUM(DEREF(memory, uint32_t));
249 case UPB_TYPE_UINT64:
250 return ULL2NUM(DEREF(memory, uint64_t));
251 default:
252 return Qnil;
253 }
254 }
255
256 void native_slot_init(upb_fieldtype_t type, void* memory) {
257 switch (type) {
258 case UPB_TYPE_FLOAT:
259 DEREF(memory, float) = 0.0;
260 break;
261 case UPB_TYPE_DOUBLE:
262 DEREF(memory, double) = 0.0;
263 break;
264 case UPB_TYPE_BOOL:
265 DEREF(memory, int8_t) = 0;
266 break;
267 case UPB_TYPE_STRING:
268 case UPB_TYPE_BYTES:
269 DEREF(memory, VALUE) = rb_str_new2("");
270 rb_enc_associate(DEREF(memory, VALUE), (type == UPB_TYPE_BYTES) ?
271 kRubyString8bitEncoding : kRubyStringUtf8Encoding);
272 break;
273 case UPB_TYPE_MESSAGE:
274 DEREF(memory, VALUE) = Qnil;
275 break;
276 case UPB_TYPE_ENUM:
277 case UPB_TYPE_INT32:
278 DEREF(memory, int32_t) = 0;
279 break;
280 case UPB_TYPE_INT64:
281 DEREF(memory, int64_t) = 0;
282 break;
283 case UPB_TYPE_UINT32:
284 DEREF(memory, uint32_t) = 0;
285 break;
286 case UPB_TYPE_UINT64:
287 DEREF(memory, uint64_t) = 0;
288 break;
289 default:
290 break;
291 }
292 }
293
294 void native_slot_mark(upb_fieldtype_t type, void* memory) {
295 switch (type) {
296 case UPB_TYPE_STRING:
297 case UPB_TYPE_BYTES:
298 case UPB_TYPE_MESSAGE:
299 rb_gc_mark(DEREF(memory, VALUE));
300 break;
301 default:
302 break;
303 }
304 }
305
306 void native_slot_dup(upb_fieldtype_t type, void* to, void* from) {
307 memcpy(to, from, native_slot_size(type));
308 }
309
310 void native_slot_deep_copy(upb_fieldtype_t type, void* to, void* from) {
311 switch (type) {
312 case UPB_TYPE_STRING:
313 case UPB_TYPE_BYTES: {
314 VALUE from_val = DEREF(from, VALUE);
315 DEREF(to, VALUE) = (from_val != Qnil) ?
316 rb_funcall(from_val, rb_intern("dup"), 0) : Qnil;
317 break;
318 }
319 case UPB_TYPE_MESSAGE: {
320 VALUE from_val = DEREF(from, VALUE);
321 DEREF(to, VALUE) = (from_val != Qnil) ?
322 Message_deep_copy(from_val) : Qnil;
323 break;
324 }
325 default:
326 memcpy(to, from, native_slot_size(type));
327 }
328 }
329
330 bool native_slot_eq(upb_fieldtype_t type, void* mem1, void* mem2) {
331 switch (type) {
332 case UPB_TYPE_STRING:
333 case UPB_TYPE_BYTES:
334 case UPB_TYPE_MESSAGE: {
335 VALUE val1 = DEREF(mem1, VALUE);
336 VALUE val2 = DEREF(mem2, VALUE);
337 VALUE ret = rb_funcall(val1, rb_intern("=="), 1, val2);
338 return ret == Qtrue;
339 }
340 default:
341 return !memcmp(mem1, mem2, native_slot_size(type));
342 }
343 }
344
345 // -----------------------------------------------------------------------------
346 // Map field utilities.
347 // -----------------------------------------------------------------------------
348
349 const upb_msgdef* tryget_map_entry_msgdef(const upb_fielddef* field) {
350 const upb_msgdef* subdef;
351 if (upb_fielddef_label(field) != UPB_LABEL_REPEATED ||
352 upb_fielddef_type(field) != UPB_TYPE_MESSAGE) {
353 return NULL;
354 }
355 subdef = upb_fielddef_msgsubdef(field);
356 return upb_msgdef_mapentry(subdef) ? subdef : NULL;
357 }
358
359 const upb_msgdef *map_entry_msgdef(const upb_fielddef* field) {
360 const upb_msgdef* subdef = tryget_map_entry_msgdef(field);
361 assert(subdef);
362 return subdef;
363 }
364
365 bool is_map_field(const upb_fielddef *field) {
366 return tryget_map_entry_msgdef(field) != NULL;
367 }
368
369 const upb_fielddef* map_field_key(const upb_fielddef* field) {
370 const upb_msgdef* subdef = map_entry_msgdef(field);
371 return map_entry_key(subdef);
372 }
373
374 const upb_fielddef* map_field_value(const upb_fielddef* field) {
375 const upb_msgdef* subdef = map_entry_msgdef(field);
376 return map_entry_value(subdef);
377 }
378
379 const upb_fielddef* map_entry_key(const upb_msgdef* msgdef) {
380 const upb_fielddef* key_field = upb_msgdef_itof(msgdef, MAP_KEY_FIELD);
381 assert(key_field != NULL);
382 return key_field;
383 }
384
385 const upb_fielddef* map_entry_value(const upb_msgdef* msgdef) {
386 const upb_fielddef* value_field = upb_msgdef_itof(msgdef, MAP_VALUE_FIELD);
387 assert(value_field != NULL);
388 return value_field;
389 }
390
391 // -----------------------------------------------------------------------------
392 // Memory layout management.
393 // -----------------------------------------------------------------------------
394
395 static size_t align_up_to(size_t offset, size_t granularity) {
396 // Granularity must be a power of two.
397 return (offset + granularity - 1) & ~(granularity - 1);
398 }
399
400 MessageLayout* create_layout(const upb_msgdef* msgdef) {
401 MessageLayout* layout = ALLOC(MessageLayout);
402 int nfields = upb_msgdef_numfields(msgdef);
403 upb_msg_field_iter it;
404 upb_msg_oneof_iter oit;
405 size_t off = 0;
406
407 layout->fields = ALLOC_N(MessageField, nfields);
408
409 for (upb_msg_field_begin(&it, msgdef);
410 !upb_msg_field_done(&it);
411 upb_msg_field_next(&it)) {
412 const upb_fielddef* field = upb_msg_iter_field(&it);
413 size_t field_size;
414
415 if (upb_fielddef_containingoneof(field)) {
416 // Oneofs are handled separately below.
417 continue;
418 }
419
420 // Allocate |field_size| bytes for this field in the layout.
421 field_size = 0;
422 if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
423 field_size = sizeof(VALUE);
424 } else {
425 field_size = native_slot_size(upb_fielddef_type(field));
426 }
427 // Align current offset up to |size| granularity.
428 off = align_up_to(off, field_size);
429 layout->fields[upb_fielddef_index(field)].offset = off;
430 layout->fields[upb_fielddef_index(field)].case_offset =
431 MESSAGE_FIELD_NO_CASE;
432 off += field_size;
433 }
434
435 // Handle oneofs now -- we iterate over oneofs specifically and allocate only
436 // one slot per oneof.
437 //
438 // We assign all value slots first, then pack the 'case' fields at the end,
439 // since in the common case (modern 64-bit platform) these are 8 bytes and 4
440 // bytes respectively and we want to avoid alignment overhead.
441 //
442 // Note that we reserve 4 bytes (a uint32) per 'case' slot because the value
443 // space for oneof cases is conceptually as wide as field tag numbers. In
444 // practice, it's unlikely that a oneof would have more than e.g. 256 or 64K
445 // members (8 or 16 bits respectively), so conceivably we could assign
446 // consecutive case numbers and then pick a smaller oneof case slot size, but
447 // the complexity to implement this indirection is probably not worthwhile.
448 for (upb_msg_oneof_begin(&oit, msgdef);
449 !upb_msg_oneof_done(&oit);
450 upb_msg_oneof_next(&oit)) {
451 const upb_oneofdef* oneof = upb_msg_iter_oneof(&oit);
452 upb_oneof_iter fit;
453
454 // Always allocate NATIVE_SLOT_MAX_SIZE bytes, but share the slot between
455 // all fields.
456 size_t field_size = NATIVE_SLOT_MAX_SIZE;
457 // Align the offset.
458 off = align_up_to(off, field_size);
459 // Assign all fields in the oneof this same offset.
460 for (upb_oneof_begin(&fit, oneof);
461 !upb_oneof_done(&fit);
462 upb_oneof_next(&fit)) {
463 const upb_fielddef* field = upb_oneof_iter_field(&fit);
464 layout->fields[upb_fielddef_index(field)].offset = off;
465 }
466 off += field_size;
467 }
468
469 // Now the case fields.
470 for (upb_msg_oneof_begin(&oit, msgdef);
471 !upb_msg_oneof_done(&oit);
472 upb_msg_oneof_next(&oit)) {
473 const upb_oneofdef* oneof = upb_msg_iter_oneof(&oit);
474 upb_oneof_iter fit;
475
476 size_t field_size = sizeof(uint32_t);
477 // Align the offset.
478 off = (off + field_size - 1) & ~(field_size - 1);
479 // Assign all fields in the oneof this same offset.
480 for (upb_oneof_begin(&fit, oneof);
481 !upb_oneof_done(&fit);
482 upb_oneof_next(&fit)) {
483 const upb_fielddef* field = upb_oneof_iter_field(&fit);
484 layout->fields[upb_fielddef_index(field)].case_offset = off;
485 }
486 off += field_size;
487 }
488
489 layout->size = off;
490
491 layout->msgdef = msgdef;
492 upb_msgdef_ref(layout->msgdef, &layout->msgdef);
493
494 return layout;
495 }
496
497 void free_layout(MessageLayout* layout) {
498 xfree(layout->fields);
499 upb_msgdef_unref(layout->msgdef, &layout->msgdef);
500 xfree(layout);
501 }
502
503 VALUE field_type_class(const upb_fielddef* field) {
504 VALUE type_class = Qnil;
505 if (upb_fielddef_type(field) == UPB_TYPE_MESSAGE) {
506 VALUE submsgdesc =
507 get_def_obj(upb_fielddef_subdef(field));
508 type_class = Descriptor_msgclass(submsgdesc);
509 } else if (upb_fielddef_type(field) == UPB_TYPE_ENUM) {
510 VALUE subenumdesc =
511 get_def_obj(upb_fielddef_subdef(field));
512 type_class = EnumDescriptor_enummodule(subenumdesc);
513 }
514 return type_class;
515 }
516
517 static void* slot_memory(MessageLayout* layout,
518 const void* storage,
519 const upb_fielddef* field) {
520 return ((uint8_t *)storage) +
521 layout->fields[upb_fielddef_index(field)].offset;
522 }
523
524 static uint32_t* slot_oneof_case(MessageLayout* layout,
525 const void* storage,
526 const upb_fielddef* field) {
527 return (uint32_t *)(((uint8_t *)storage) +
528 layout->fields[upb_fielddef_index(field)].case_offset);
529 }
530
531
532 VALUE layout_get(MessageLayout* layout,
533 const void* storage,
534 const upb_fielddef* field) {
535 void* memory = slot_memory(layout, storage, field);
536 uint32_t* oneof_case = slot_oneof_case(layout, storage, field);
537
538 if (upb_fielddef_containingoneof(field)) {
539 if (*oneof_case != upb_fielddef_number(field)) {
540 return Qnil;
541 }
542 return native_slot_get(upb_fielddef_type(field),
543 field_type_class(field),
544 memory);
545 } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
546 return *((VALUE *)memory);
547 } else {
548 return native_slot_get(upb_fielddef_type(field),
549 field_type_class(field),
550 memory);
551 }
552 }
553
554 static void check_repeated_field_type(VALUE val, const upb_fielddef* field) {
555 RepeatedField* self;
556 assert(upb_fielddef_label(field) == UPB_LABEL_REPEATED);
557
558 if (!RB_TYPE_P(val, T_DATA) || !RTYPEDDATA_P(val) ||
559 RTYPEDDATA_TYPE(val) != &RepeatedField_type) {
560 rb_raise(rb_eTypeError, "Expected repeated field array");
561 }
562
563 self = ruby_to_RepeatedField(val);
564 if (self->field_type != upb_fielddef_type(field)) {
565 rb_raise(rb_eTypeError, "Repeated field array has wrong element type");
566 }
567
568 if (self->field_type == UPB_TYPE_MESSAGE ||
569 self->field_type == UPB_TYPE_ENUM) {
570 if (self->field_type_class !=
571 get_def_obj(upb_fielddef_subdef(field))) {
572 rb_raise(rb_eTypeError,
573 "Repeated field array has wrong message/enum class");
574 }
575 }
576 }
577
578 static void check_map_field_type(VALUE val, const upb_fielddef* field) {
579 const upb_fielddef* key_field = map_field_key(field);
580 const upb_fielddef* value_field = map_field_value(field);
581 Map* self;
582
583 if (!RB_TYPE_P(val, T_DATA) || !RTYPEDDATA_P(val) ||
584 RTYPEDDATA_TYPE(val) != &Map_type) {
585 rb_raise(rb_eTypeError, "Expected Map instance");
586 }
587
588 self = ruby_to_Map(val);
589 if (self->key_type != upb_fielddef_type(key_field)) {
590 rb_raise(rb_eTypeError, "Map key type does not match field's key type");
591 }
592 if (self->value_type != upb_fielddef_type(value_field)) {
593 rb_raise(rb_eTypeError, "Map value type does not match field's value type");
594 }
595 if (upb_fielddef_type(value_field) == UPB_TYPE_MESSAGE ||
596 upb_fielddef_type(value_field) == UPB_TYPE_ENUM) {
597 if (self->value_type_class !=
598 get_def_obj(upb_fielddef_subdef(value_field))) {
599 rb_raise(rb_eTypeError,
600 "Map value type has wrong message/enum class");
601 }
602 }
603 }
604
605
606 void layout_set(MessageLayout* layout,
607 void* storage,
608 const upb_fielddef* field,
609 VALUE val) {
610 void* memory = slot_memory(layout, storage, field);
611 uint32_t* oneof_case = slot_oneof_case(layout, storage, field);
612
613 if (upb_fielddef_containingoneof(field)) {
614 if (val == Qnil) {
615 // Assigning nil to a oneof field clears the oneof completely.
616 *oneof_case = ONEOF_CASE_NONE;
617 memset(memory, 0, NATIVE_SLOT_MAX_SIZE);
618 } else {
619 // The transition between field types for a single oneof (union) slot is
620 // somewhat complex because we need to ensure that a GC triggered at any
621 // point by a call into the Ruby VM sees a valid state for this field and
622 // does not either go off into the weeds (following what it thinks is a
623 // VALUE but is actually a different field type) or miss an object (seeing
624 // what it thinks is a primitive field but is actually a VALUE for the new
625 // field type).
626 //
627 // In order for the transition to be safe, the oneof case slot must be in
628 // sync with the value slot whenever the Ruby VM has been called. Thus, we
629 // use native_slot_set_value_and_case(), which ensures that both the value
630 // and case number are altered atomically (w.r.t. the Ruby VM).
631 native_slot_set_value_and_case(
632 upb_fielddef_type(field), field_type_class(field),
633 memory, val,
634 oneof_case, upb_fielddef_number(field));
635 }
636 } else if (is_map_field(field)) {
637 check_map_field_type(val, field);
638 DEREF(memory, VALUE) = val;
639 } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
640 check_repeated_field_type(val, field);
641 DEREF(memory, VALUE) = val;
642 } else {
643 native_slot_set(upb_fielddef_type(field), field_type_class(field),
644 memory, val);
645 }
646 }
647
648 void layout_init(MessageLayout* layout,
649 void* storage) {
650 upb_msg_field_iter it;
651 for (upb_msg_field_begin(&it, layout->msgdef);
652 !upb_msg_field_done(&it);
653 upb_msg_field_next(&it)) {
654 const upb_fielddef* field = upb_msg_iter_field(&it);
655 void* memory = slot_memory(layout, storage, field);
656 uint32_t* oneof_case = slot_oneof_case(layout, storage, field);
657
658 if (upb_fielddef_containingoneof(field)) {
659 memset(memory, 0, NATIVE_SLOT_MAX_SIZE);
660 *oneof_case = ONEOF_CASE_NONE;
661 } else if (is_map_field(field)) {
662 VALUE map = Qnil;
663
664 const upb_fielddef* key_field = map_field_key(field);
665 const upb_fielddef* value_field = map_field_value(field);
666 VALUE type_class = field_type_class(value_field);
667
668 if (type_class != Qnil) {
669 VALUE args[3] = {
670 fieldtype_to_ruby(upb_fielddef_type(key_field)),
671 fieldtype_to_ruby(upb_fielddef_type(value_field)),
672 type_class,
673 };
674 map = rb_class_new_instance(3, args, cMap);
675 } else {
676 VALUE args[2] = {
677 fieldtype_to_ruby(upb_fielddef_type(key_field)),
678 fieldtype_to_ruby(upb_fielddef_type(value_field)),
679 };
680 map = rb_class_new_instance(2, args, cMap);
681 }
682
683 DEREF(memory, VALUE) = map;
684 } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
685 VALUE ary = Qnil;
686
687 VALUE type_class = field_type_class(field);
688
689 if (type_class != Qnil) {
690 VALUE args[2] = {
691 fieldtype_to_ruby(upb_fielddef_type(field)),
692 type_class,
693 };
694 ary = rb_class_new_instance(2, args, cRepeatedField);
695 } else {
696 VALUE args[1] = { fieldtype_to_ruby(upb_fielddef_type(field)) };
697 ary = rb_class_new_instance(1, args, cRepeatedField);
698 }
699
700 DEREF(memory, VALUE) = ary;
701 } else {
702 native_slot_init(upb_fielddef_type(field), memory);
703 }
704 }
705 }
706
707 void layout_mark(MessageLayout* layout, void* storage) {
708 upb_msg_field_iter it;
709 for (upb_msg_field_begin(&it, layout->msgdef);
710 !upb_msg_field_done(&it);
711 upb_msg_field_next(&it)) {
712 const upb_fielddef* field = upb_msg_iter_field(&it);
713 void* memory = slot_memory(layout, storage, field);
714 uint32_t* oneof_case = slot_oneof_case(layout, storage, field);
715
716 if (upb_fielddef_containingoneof(field)) {
717 if (*oneof_case == upb_fielddef_number(field)) {
718 native_slot_mark(upb_fielddef_type(field), memory);
719 }
720 } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
721 rb_gc_mark(DEREF(memory, VALUE));
722 } else {
723 native_slot_mark(upb_fielddef_type(field), memory);
724 }
725 }
726 }
727
728 void layout_dup(MessageLayout* layout, void* to, void* from) {
729 upb_msg_field_iter it;
730 for (upb_msg_field_begin(&it, layout->msgdef);
731 !upb_msg_field_done(&it);
732 upb_msg_field_next(&it)) {
733 const upb_fielddef* field = upb_msg_iter_field(&it);
734
735 void* to_memory = slot_memory(layout, to, field);
736 uint32_t* to_oneof_case = slot_oneof_case(layout, to, field);
737 void* from_memory = slot_memory(layout, from, field);
738 uint32_t* from_oneof_case = slot_oneof_case(layout, from, field);
739
740 if (upb_fielddef_containingoneof(field)) {
741 if (*from_oneof_case == upb_fielddef_number(field)) {
742 *to_oneof_case = *from_oneof_case;
743 native_slot_dup(upb_fielddef_type(field), to_memory, from_memory);
744 }
745 } else if (is_map_field(field)) {
746 DEREF(to_memory, VALUE) = Map_dup(DEREF(from_memory, VALUE));
747 } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
748 DEREF(to_memory, VALUE) = RepeatedField_dup(DEREF(from_memory, VALUE));
749 } else {
750 native_slot_dup(upb_fielddef_type(field), to_memory, from_memory);
751 }
752 }
753 }
754
755 void layout_deep_copy(MessageLayout* layout, void* to, void* from) {
756 upb_msg_field_iter it;
757 for (upb_msg_field_begin(&it, layout->msgdef);
758 !upb_msg_field_done(&it);
759 upb_msg_field_next(&it)) {
760 const upb_fielddef* field = upb_msg_iter_field(&it);
761
762 void* to_memory = slot_memory(layout, to, field);
763 uint32_t* to_oneof_case = slot_oneof_case(layout, to, field);
764 void* from_memory = slot_memory(layout, from, field);
765 uint32_t* from_oneof_case = slot_oneof_case(layout, from, field);
766
767 if (upb_fielddef_containingoneof(field)) {
768 if (*from_oneof_case == upb_fielddef_number(field)) {
769 *to_oneof_case = *from_oneof_case;
770 native_slot_deep_copy(upb_fielddef_type(field), to_memory, from_memory);
771 }
772 } else if (is_map_field(field)) {
773 DEREF(to_memory, VALUE) =
774 Map_deep_copy(DEREF(from_memory, VALUE));
775 } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
776 DEREF(to_memory, VALUE) =
777 RepeatedField_deep_copy(DEREF(from_memory, VALUE));
778 } else {
779 native_slot_deep_copy(upb_fielddef_type(field), to_memory, from_memory);
780 }
781 }
782 }
783
784 VALUE layout_eq(MessageLayout* layout, void* msg1, void* msg2) {
785 upb_msg_field_iter it;
786 for (upb_msg_field_begin(&it, layout->msgdef);
787 !upb_msg_field_done(&it);
788 upb_msg_field_next(&it)) {
789 const upb_fielddef* field = upb_msg_iter_field(&it);
790
791 void* msg1_memory = slot_memory(layout, msg1, field);
792 uint32_t* msg1_oneof_case = slot_oneof_case(layout, msg1, field);
793 void* msg2_memory = slot_memory(layout, msg2, field);
794 uint32_t* msg2_oneof_case = slot_oneof_case(layout, msg2, field);
795
796 if (upb_fielddef_containingoneof(field)) {
797 if (*msg1_oneof_case != *msg2_oneof_case ||
798 (*msg1_oneof_case == upb_fielddef_number(field) &&
799 !native_slot_eq(upb_fielddef_type(field),
800 msg1_memory,
801 msg2_memory))) {
802 return Qfalse;
803 }
804 } else if (is_map_field(field)) {
805 if (!Map_eq(DEREF(msg1_memory, VALUE),
806 DEREF(msg2_memory, VALUE))) {
807 return Qfalse;
808 }
809 } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
810 if (!RepeatedField_eq(DEREF(msg1_memory, VALUE),
811 DEREF(msg2_memory, VALUE))) {
812 return Qfalse;
813 }
814 } else {
815 if (!native_slot_eq(upb_fielddef_type(field),
816 msg1_memory, msg2_memory)) {
817 return Qfalse;
818 }
819 }
820 }
821 return Qtrue;
822 }
823
824 VALUE layout_hash(MessageLayout* layout, void* storage) {
825 upb_msg_field_iter it;
826 st_index_t h = rb_hash_start(0);
827 VALUE hash_sym = rb_intern("hash");
828 for (upb_msg_field_begin(&it, layout->msgdef);
829 !upb_msg_field_done(&it);
830 upb_msg_field_next(&it)) {
831 const upb_fielddef* field = upb_msg_iter_field(&it);
832 VALUE field_val = layout_get(layout, storage, field);
833 h = rb_hash_uint(h, NUM2LONG(rb_funcall(field_val, hash_sym, 0)));
834 }
835 h = rb_hash_end(h);
836
837 return INT2FIX(h);
838 }
839
840 VALUE layout_inspect(MessageLayout* layout, void* storage) {
841 VALUE str = rb_str_new2("");
842
843 upb_msg_field_iter it;
844 bool first = true;
845 for (upb_msg_field_begin(&it, layout->msgdef);
846 !upb_msg_field_done(&it);
847 upb_msg_field_next(&it)) {
848 const upb_fielddef* field = upb_msg_iter_field(&it);
849 VALUE field_val = layout_get(layout, storage, field);
850
851 if (!first) {
852 str = rb_str_cat2(str, ", ");
853 } else {
854 first = false;
855 }
856 str = rb_str_cat2(str, upb_fielddef_name(field));
857 str = rb_str_cat2(str, ": ");
858
859 str = rb_str_append(str, rb_funcall(field_val, rb_intern("inspect"), 0));
860 }
861
862 return str;
863 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698