google-protobuf 3.5.0 → 3.23.4

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of google-protobuf might be problematic. Click here for more details.

Files changed (47) hide show
  1. checksums.yaml +5 -5
  2. data/ext/google/protobuf_c/convert.c +361 -0
  3. data/ext/google/protobuf_c/convert.h +75 -0
  4. data/ext/google/protobuf_c/defs.c +770 -1254
  5. data/ext/google/protobuf_c/defs.h +107 -0
  6. data/ext/google/protobuf_c/extconf.rb +15 -5
  7. data/ext/google/protobuf_c/map.c +312 -474
  8. data/ext/google/protobuf_c/map.h +66 -0
  9. data/ext/google/protobuf_c/message.c +1139 -372
  10. data/ext/google/protobuf_c/message.h +104 -0
  11. data/ext/google/protobuf_c/protobuf.c +418 -51
  12. data/ext/google/protobuf_c/protobuf.h +53 -485
  13. data/ext/google/protobuf_c/repeated_field.c +319 -316
  14. data/ext/google/protobuf_c/repeated_field.h +63 -0
  15. data/ext/google/protobuf_c/ruby-upb.c +13974 -0
  16. data/ext/google/protobuf_c/ruby-upb.h +11780 -0
  17. data/ext/google/protobuf_c/third_party/utf8_range/LICENSE +22 -0
  18. data/ext/google/protobuf_c/third_party/utf8_range/naive.c +92 -0
  19. data/ext/google/protobuf_c/third_party/utf8_range/range2-neon.c +157 -0
  20. data/ext/google/protobuf_c/third_party/utf8_range/range2-sse.c +170 -0
  21. data/ext/google/protobuf_c/third_party/utf8_range/utf8_range.h +21 -0
  22. data/ext/google/protobuf_c/wrap_memcpy.c +4 -3
  23. data/lib/google/protobuf/any_pb.rb +26 -5
  24. data/lib/google/protobuf/api_pb.rb +31 -25
  25. data/lib/google/protobuf/descriptor_dsl.rb +465 -0
  26. data/lib/google/protobuf/descriptor_pb.rb +75 -0
  27. data/lib/google/protobuf/duration_pb.rb +26 -5
  28. data/lib/google/protobuf/empty_pb.rb +26 -3
  29. data/lib/google/protobuf/field_mask_pb.rb +26 -4
  30. data/lib/google/protobuf/message_exts.rb +9 -4
  31. data/lib/google/protobuf/plugin_pb.rb +47 -0
  32. data/lib/google/protobuf/repeated_field.rb +17 -4
  33. data/lib/google/protobuf/source_context_pb.rb +26 -4
  34. data/lib/google/protobuf/struct_pb.rb +28 -22
  35. data/lib/google/protobuf/timestamp_pb.rb +26 -5
  36. data/lib/google/protobuf/type_pb.rb +37 -76
  37. data/lib/google/protobuf/well_known_types.rb +32 -4
  38. data/lib/google/protobuf/wrappers_pb.rb +35 -37
  39. data/lib/google/protobuf.rb +11 -8
  40. metadata +29 -37
  41. data/ext/google/protobuf_c/encode_decode.c +0 -1307
  42. data/ext/google/protobuf_c/storage.c +0 -904
  43. data/ext/google/protobuf_c/upb.c +0 -14913
  44. data/ext/google/protobuf_c/upb.h +0 -8969
  45. data/tests/basic.rb +0 -1403
  46. data/tests/generated_code_test.rb +0 -19
  47. data/tests/stress.rb +0 -38
@@ -28,167 +28,232 @@
28
28
  // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
29
  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
30
 
31
+ #include "convert.h"
32
+ #include "defs.h"
33
+ #include "message.h"
31
34
  #include "protobuf.h"
32
35
 
33
36
  // -----------------------------------------------------------------------------
34
- // Basic map operations on top of upb's strtable.
37
+ // Basic map operations on top of upb_Map.
35
38
  //
36
39
  // Note that we roll our own `Map` container here because, as for
37
40
  // `RepeatedField`, we want a strongly-typed container. This is so that any user
38
41
  // errors due to incorrect map key or value types are raised as close as
39
42
  // possible to the error site, rather than at some deferred point (e.g.,
40
43
  // serialization).
41
- //
42
- // We build our `Map` on top of upb_strtable so that we're able to take
43
- // advantage of the native_slot storage abstraction, as RepeatedField does.
44
- // (This is not quite a perfect mapping -- see the key conversions below -- but
45
- // gives us full support and error-checking for all value types for free.)
46
44
  // -----------------------------------------------------------------------------
47
45
 
48
- // Map values are stored using the native_slot abstraction (as with repeated
49
- // field values), but keys are a bit special. Since we use a strtable, we need
50
- // to store keys as sequences of bytes such that equality of those bytes maps
51
- // one-to-one to equality of keys. We store strings directly (i.e., they map to
52
- // their own bytes) and integers as native integers (using the native_slot
53
- // abstraction).
54
-
55
- // Note that there is another tradeoff here in keeping string keys as native
56
- // strings rather than Ruby strings: traversing the Map requires conversion to
57
- // Ruby string values on every traversal, potentially creating more garbage. We
58
- // should consider ways to cache a Ruby version of the key if this becomes an
59
- // issue later.
60
-
61
- // Forms a key to use with the underlying strtable from a Ruby key value. |buf|
62
- // must point to TABLE_KEY_BUF_LENGTH bytes of temporary space, used to
63
- // construct a key byte sequence if needed. |out_key| and |out_length| provide
64
- // the resulting key data/length.
65
- #define TABLE_KEY_BUF_LENGTH 8 // sizeof(uint64_t)
66
- static VALUE table_key(Map* self, VALUE key,
67
- char* buf,
68
- const char** out_key,
69
- size_t* out_length) {
70
- switch (self->key_type) {
71
- case UPB_TYPE_BYTES:
72
- case UPB_TYPE_STRING:
73
- // Strings: use string content directly.
74
- Check_Type(key, T_STRING);
75
- key = native_slot_encode_and_freeze_string(self->key_type, key);
76
- *out_key = RSTRING_PTR(key);
77
- *out_length = RSTRING_LEN(key);
78
- break;
46
+ // -----------------------------------------------------------------------------
47
+ // Map container type.
48
+ // -----------------------------------------------------------------------------
79
49
 
80
- case UPB_TYPE_BOOL:
81
- case UPB_TYPE_INT32:
82
- case UPB_TYPE_INT64:
83
- case UPB_TYPE_UINT32:
84
- case UPB_TYPE_UINT64:
85
- native_slot_set(self->key_type, Qnil, buf, key);
86
- *out_key = buf;
87
- *out_length = native_slot_size(self->key_type);
88
- break;
50
+ typedef struct {
51
+ const upb_Map* map; // Can convert to mutable when non-frozen.
52
+ upb_CType key_type;
53
+ TypeInfo value_type_info;
54
+ VALUE value_type_class;
55
+ VALUE arena;
56
+ } Map;
89
57
 
90
- default:
91
- // Map constructor should not allow a Map with another key type to be
92
- // constructed.
93
- assert(false);
94
- break;
95
- }
58
+ static void Map_mark(void* _self) {
59
+ Map* self = _self;
60
+ rb_gc_mark(self->value_type_class);
61
+ rb_gc_mark(self->arena);
62
+ }
63
+
64
+ const rb_data_type_t Map_type = {
65
+ "Google::Protobuf::Map",
66
+ {Map_mark, RUBY_DEFAULT_FREE, NULL},
67
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY,
68
+ };
69
+
70
+ VALUE cMap;
96
71
 
97
- return key;
72
+ static Map* ruby_to_Map(VALUE _self) {
73
+ Map* self;
74
+ TypedData_Get_Struct(_self, Map, &Map_type, self);
75
+ return self;
98
76
  }
99
77
 
100
- static VALUE table_key_to_ruby(Map* self, const char* buf, size_t length) {
101
- switch (self->key_type) {
102
- case UPB_TYPE_BYTES:
103
- case UPB_TYPE_STRING: {
104
- VALUE ret = rb_str_new(buf, length);
105
- rb_enc_associate(ret,
106
- (self->key_type == UPB_TYPE_BYTES) ?
107
- kRubyString8bitEncoding : kRubyStringUtf8Encoding);
108
- return ret;
78
+ static VALUE Map_alloc(VALUE klass) {
79
+ Map* self = ALLOC(Map);
80
+ self->map = NULL;
81
+ self->value_type_class = Qnil;
82
+ self->value_type_info.def.msgdef = NULL;
83
+ self->arena = Qnil;
84
+ return TypedData_Wrap_Struct(klass, &Map_type, self);
85
+ }
86
+
87
+ VALUE Map_GetRubyWrapper(upb_Map* map, upb_CType key_type, TypeInfo value_type,
88
+ VALUE arena) {
89
+ PBRUBY_ASSERT(map);
90
+
91
+ VALUE val = ObjectCache_Get(map);
92
+
93
+ if (val == Qnil) {
94
+ val = Map_alloc(cMap);
95
+ Map* self;
96
+ ObjectCache_Add(map, val);
97
+ TypedData_Get_Struct(val, Map, &Map_type, self);
98
+ self->map = map;
99
+ self->arena = arena;
100
+ self->key_type = key_type;
101
+ self->value_type_info = value_type;
102
+ if (self->value_type_info.type == kUpb_CType_Message) {
103
+ const upb_MessageDef* val_m = self->value_type_info.def.msgdef;
104
+ self->value_type_class = Descriptor_DefToClass(val_m);
109
105
  }
106
+ }
110
107
 
111
- case UPB_TYPE_BOOL:
112
- case UPB_TYPE_INT32:
113
- case UPB_TYPE_INT64:
114
- case UPB_TYPE_UINT32:
115
- case UPB_TYPE_UINT64:
116
- return native_slot_get(self->key_type, Qnil, buf);
108
+ return val;
109
+ }
117
110
 
118
- default:
119
- assert(false);
120
- return Qnil;
121
- }
111
+ static VALUE Map_new_this_type(Map* from) {
112
+ VALUE arena_rb = Arena_new();
113
+ upb_Map* map = upb_Map_New(Arena_get(arena_rb), from->key_type,
114
+ from->value_type_info.type);
115
+ VALUE ret =
116
+ Map_GetRubyWrapper(map, from->key_type, from->value_type_info, arena_rb);
117
+ PBRUBY_ASSERT(ruby_to_Map(ret)->value_type_class == from->value_type_class);
118
+ return ret;
122
119
  }
123
120
 
124
- static void* value_memory(upb_value* v) {
125
- return (void*)(&v->val);
121
+ static TypeInfo Map_keyinfo(Map* self) {
122
+ TypeInfo ret;
123
+ ret.type = self->key_type;
124
+ ret.def.msgdef = NULL;
125
+ return ret;
126
126
  }
127
127
 
128
- // -----------------------------------------------------------------------------
129
- // Map container type.
130
- // -----------------------------------------------------------------------------
128
+ static upb_Map* Map_GetMutable(VALUE _self) {
129
+ rb_check_frozen(_self);
130
+ return (upb_Map*)ruby_to_Map(_self)->map;
131
+ }
131
132
 
132
- const rb_data_type_t Map_type = {
133
- "Google::Protobuf::Map",
134
- { Map_mark, Map_free, NULL },
135
- };
133
+ VALUE Map_CreateHash(const upb_Map* map, upb_CType key_type,
134
+ TypeInfo val_info) {
135
+ VALUE hash = rb_hash_new();
136
+ TypeInfo key_info = TypeInfo_from_type(key_type);
136
137
 
137
- VALUE cMap;
138
+ if (!map) return hash;
138
139
 
139
- Map* ruby_to_Map(VALUE _self) {
140
- Map* self;
141
- TypedData_Get_Struct(_self, Map, &Map_type, self);
142
- return self;
143
- }
140
+ size_t iter = kUpb_Map_Begin;
141
+ upb_MessageValue key, val;
142
+ while (upb_Map_Next(map, &key, &val, &iter)) {
143
+ VALUE key_val = Convert_UpbToRuby(key, key_info, Qnil);
144
+ VALUE val_val = Scalar_CreateHash(val, val_info);
145
+ rb_hash_aset(hash, key_val, val_val);
146
+ }
144
147
 
145
- void Map_mark(void* _self) {
146
- Map* self = _self;
148
+ return hash;
149
+ }
147
150
 
148
- rb_gc_mark(self->value_type_class);
149
- rb_gc_mark(self->parse_frame);
150
-
151
- if (self->value_type == UPB_TYPE_STRING ||
152
- self->value_type == UPB_TYPE_BYTES ||
153
- self->value_type == UPB_TYPE_MESSAGE) {
154
- upb_strtable_iter it;
155
- for (upb_strtable_begin(&it, &self->table);
156
- !upb_strtable_done(&it);
157
- upb_strtable_next(&it)) {
158
- upb_value v = upb_strtable_iter_value(&it);
159
- void* mem = value_memory(&v);
160
- native_slot_mark(self->value_type, mem);
161
- }
151
+ VALUE Map_deep_copy(VALUE obj) {
152
+ Map* self = ruby_to_Map(obj);
153
+ VALUE new_arena_rb = Arena_new();
154
+ upb_Arena* arena = Arena_get(new_arena_rb);
155
+ upb_Map* new_map =
156
+ upb_Map_New(arena, self->key_type, self->value_type_info.type);
157
+ size_t iter = kUpb_Map_Begin;
158
+ upb_MessageValue key, val;
159
+ while (upb_Map_Next(self->map, &key, &val, &iter)) {
160
+ upb_MessageValue val_copy =
161
+ Msgval_DeepCopy(val, self->value_type_info, arena);
162
+ upb_Map_Set(new_map, key, val_copy, arena);
162
163
  }
164
+
165
+ return Map_GetRubyWrapper(new_map, self->key_type, self->value_type_info,
166
+ new_arena_rb);
163
167
  }
164
168
 
165
- void Map_free(void* _self) {
166
- Map* self = _self;
167
- upb_strtable_uninit(&self->table);
168
- xfree(self);
169
+ const upb_Map* Map_GetUpbMap(VALUE val, const upb_FieldDef* field,
170
+ upb_Arena* arena) {
171
+ const upb_FieldDef* key_field = map_field_key(field);
172
+ const upb_FieldDef* value_field = map_field_value(field);
173
+ TypeInfo value_type_info = TypeInfo_get(value_field);
174
+ Map* self;
175
+
176
+ if (!RB_TYPE_P(val, T_DATA) || !RTYPEDDATA_P(val) ||
177
+ RTYPEDDATA_TYPE(val) != &Map_type) {
178
+ rb_raise(cTypeError, "Expected Map instance");
179
+ }
180
+
181
+ self = ruby_to_Map(val);
182
+ if (self->key_type != upb_FieldDef_CType(key_field)) {
183
+ rb_raise(cTypeError, "Map key type does not match field's key type");
184
+ }
185
+ if (self->value_type_info.type != value_type_info.type) {
186
+ rb_raise(cTypeError, "Map value type does not match field's value type");
187
+ }
188
+ if (self->value_type_info.def.msgdef != value_type_info.def.msgdef) {
189
+ rb_raise(cTypeError, "Map value type has wrong message/enum class");
190
+ }
191
+
192
+ Arena_fuse(self->arena, arena);
193
+ return self->map;
169
194
  }
170
195
 
171
- VALUE Map_alloc(VALUE klass) {
172
- Map* self = ALLOC(Map);
173
- memset(self, 0, sizeof(Map));
174
- self->value_type_class = Qnil;
175
- return TypedData_Wrap_Struct(klass, &Map_type, self);
196
+ void Map_Inspect(StringBuilder* b, const upb_Map* map, upb_CType key_type,
197
+ TypeInfo val_type) {
198
+ bool first = true;
199
+ TypeInfo key_type_info = {key_type};
200
+ StringBuilder_Printf(b, "{");
201
+ if (map) {
202
+ size_t iter = kUpb_Map_Begin;
203
+ upb_MessageValue key, val;
204
+ while (upb_Map_Next(map, &key, &val, &iter)) {
205
+ if (first) {
206
+ first = false;
207
+ } else {
208
+ StringBuilder_Printf(b, ", ");
209
+ }
210
+ StringBuilder_PrintMsgval(b, key, key_type_info);
211
+ StringBuilder_Printf(b, "=>");
212
+ StringBuilder_PrintMsgval(b, val, val_type);
213
+ }
214
+ }
215
+ StringBuilder_Printf(b, "}");
176
216
  }
177
217
 
178
- VALUE Map_set_frame(VALUE map, VALUE val) {
179
- Map* self = ruby_to_Map(map);
180
- self->parse_frame = val;
181
- return val;
218
+ static int merge_into_self_callback(VALUE key, VALUE val, VALUE _self) {
219
+ Map* self = ruby_to_Map(_self);
220
+ upb_Arena* arena = Arena_get(self->arena);
221
+ upb_MessageValue key_val =
222
+ Convert_RubyToUpb(key, "", Map_keyinfo(self), arena);
223
+ upb_MessageValue val_val =
224
+ Convert_RubyToUpb(val, "", self->value_type_info, arena);
225
+ upb_Map_Set(Map_GetMutable(_self), key_val, val_val, arena);
226
+ return ST_CONTINUE;
182
227
  }
183
228
 
184
- static bool needs_typeclass(upb_fieldtype_t type) {
185
- switch (type) {
186
- case UPB_TYPE_MESSAGE:
187
- case UPB_TYPE_ENUM:
188
- return true;
189
- default:
190
- return false;
229
+ // Used only internally -- shared by #merge and #initialize.
230
+ static VALUE Map_merge_into_self(VALUE _self, VALUE hashmap) {
231
+ if (TYPE(hashmap) == T_HASH) {
232
+ rb_hash_foreach(hashmap, merge_into_self_callback, _self);
233
+ } else if (RB_TYPE_P(hashmap, T_DATA) && RTYPEDDATA_P(hashmap) &&
234
+ RTYPEDDATA_TYPE(hashmap) == &Map_type) {
235
+ Map* self = ruby_to_Map(_self);
236
+ Map* other = ruby_to_Map(hashmap);
237
+ upb_Arena* arena = Arena_get(self->arena);
238
+ upb_Message* self_msg = Map_GetMutable(_self);
239
+
240
+ Arena_fuse(other->arena, arena);
241
+
242
+ if (self->key_type != other->key_type ||
243
+ self->value_type_info.type != other->value_type_info.type ||
244
+ self->value_type_class != other->value_type_class) {
245
+ rb_raise(rb_eArgError, "Attempt to merge Map with mismatching types");
246
+ }
247
+
248
+ size_t iter = kUpb_Map_Begin;
249
+ upb_MessageValue key, val;
250
+ while (upb_Map_Next(other->map, &key, &val, &iter)) {
251
+ upb_Map_Set(self_msg, key, val, arena);
252
+ }
253
+ } else {
254
+ rb_raise(rb_eArgError, "Unknown type merging into Map");
191
255
  }
256
+ return _self;
192
257
  }
193
258
 
194
259
  /*
@@ -221,9 +286,9 @@ static bool needs_typeclass(upb_fieldtype_t type) {
221
286
  * references to underlying objects will be shared if the value type is a
222
287
  * message type.
223
288
  */
224
- VALUE Map_init(int argc, VALUE* argv, VALUE _self) {
289
+ static VALUE Map_init(int argc, VALUE* argv, VALUE _self) {
225
290
  Map* self = ruby_to_Map(_self);
226
- int init_value_arg;
291
+ VALUE init_arg;
227
292
 
228
293
  // We take either two args (:key_type, :value_type), three args (:key_type,
229
294
  // :value_type, "ValueMessageType"), or four args (the above plus an initial
@@ -233,39 +298,31 @@ VALUE Map_init(int argc, VALUE* argv, VALUE _self) {
233
298
  }
234
299
 
235
300
  self->key_type = ruby_to_fieldtype(argv[0]);
236
- self->value_type = ruby_to_fieldtype(argv[1]);
237
- self->parse_frame = Qnil;
301
+ self->value_type_info =
302
+ TypeInfo_FromClass(argc, argv, 1, &self->value_type_class, &init_arg);
303
+ self->arena = Arena_new();
238
304
 
239
305
  // Check that the key type is an allowed type.
240
306
  switch (self->key_type) {
241
- case UPB_TYPE_INT32:
242
- case UPB_TYPE_INT64:
243
- case UPB_TYPE_UINT32:
244
- case UPB_TYPE_UINT64:
245
- case UPB_TYPE_BOOL:
246
- case UPB_TYPE_STRING:
247
- case UPB_TYPE_BYTES:
307
+ case kUpb_CType_Int32:
308
+ case kUpb_CType_Int64:
309
+ case kUpb_CType_UInt32:
310
+ case kUpb_CType_UInt64:
311
+ case kUpb_CType_Bool:
312
+ case kUpb_CType_String:
313
+ case kUpb_CType_Bytes:
248
314
  // These are OK.
249
315
  break;
250
316
  default:
251
317
  rb_raise(rb_eArgError, "Invalid key type for map.");
252
318
  }
253
319
 
254
- init_value_arg = 2;
255
- if (needs_typeclass(self->value_type) && argc > 2) {
256
- self->value_type_class = argv[2];
257
- validate_type_class(self->value_type, self->value_type_class);
258
- init_value_arg = 3;
259
- }
260
-
261
- // Table value type is always UINT64: this ensures enough space to store the
262
- // native_slot value.
263
- if (!upb_strtable_init(&self->table, UPB_CTYPE_UINT64)) {
264
- rb_raise(rb_eRuntimeError, "Could not allocate table.");
265
- }
320
+ self->map = upb_Map_New(Arena_get(self->arena), self->key_type,
321
+ self->value_type_info.type);
322
+ ObjectCache_Add(self->map, _self);
266
323
 
267
- if (argc > init_value_arg) {
268
- Map_merge_into_self(_self, argv[init_value_arg]);
324
+ if (init_arg != Qnil) {
325
+ Map_merge_into_self(_self, init_arg);
269
326
  }
270
327
 
271
328
  return Qnil;
@@ -279,24 +336,15 @@ VALUE Map_init(int argc, VALUE* argv, VALUE _self) {
279
336
  * Note that Map also includes Enumerable; map thus acts like a normal Ruby
280
337
  * sequence.
281
338
  */
282
- VALUE Map_each(VALUE _self) {
339
+ static VALUE Map_each(VALUE _self) {
283
340
  Map* self = ruby_to_Map(_self);
341
+ size_t iter = kUpb_Map_Begin;
342
+ upb_MessageValue key, val;
284
343
 
285
- upb_strtable_iter it;
286
- for (upb_strtable_begin(&it, &self->table);
287
- !upb_strtable_done(&it);
288
- upb_strtable_next(&it)) {
289
-
290
- VALUE key = table_key_to_ruby(
291
- self, upb_strtable_iter_key(&it), upb_strtable_iter_keylength(&it));
292
-
293
- upb_value v = upb_strtable_iter_value(&it);
294
- void* mem = value_memory(&v);
295
- VALUE value = native_slot_get(self->value_type,
296
- self->value_type_class,
297
- mem);
298
-
299
- rb_yield_values(2, key, value);
344
+ while (upb_Map_Next(self->map, &key, &val, &iter)) {
345
+ VALUE key_val = Convert_UpbToRuby(key, Map_keyinfo(self), self->arena);
346
+ VALUE val_val = Convert_UpbToRuby(val, self->value_type_info, self->arena);
347
+ rb_yield_values(2, key_val, val_val);
300
348
  }
301
349
 
302
350
  return Qnil;
@@ -308,19 +356,15 @@ VALUE Map_each(VALUE _self) {
308
356
  *
309
357
  * Returns the list of keys contained in the map, in unspecified order.
310
358
  */
311
- VALUE Map_keys(VALUE _self) {
359
+ static VALUE Map_keys(VALUE _self) {
312
360
  Map* self = ruby_to_Map(_self);
313
-
361
+ size_t iter = kUpb_Map_Begin;
314
362
  VALUE ret = rb_ary_new();
315
- upb_strtable_iter it;
316
- for (upb_strtable_begin(&it, &self->table);
317
- !upb_strtable_done(&it);
318
- upb_strtable_next(&it)) {
319
-
320
- VALUE key = table_key_to_ruby(
321
- self, upb_strtable_iter_key(&it), upb_strtable_iter_keylength(&it));
363
+ upb_MessageValue key, val;
322
364
 
323
- rb_ary_push(ret, key);
365
+ while (upb_Map_Next(self->map, &key, &val, &iter)) {
366
+ VALUE key_val = Convert_UpbToRuby(key, Map_keyinfo(self), self->arena);
367
+ rb_ary_push(ret, key_val);
324
368
  }
325
369
 
326
370
  return ret;
@@ -332,22 +376,15 @@ VALUE Map_keys(VALUE _self) {
332
376
  *
333
377
  * Returns the list of values contained in the map, in unspecified order.
334
378
  */
335
- VALUE Map_values(VALUE _self) {
379
+ static VALUE Map_values(VALUE _self) {
336
380
  Map* self = ruby_to_Map(_self);
337
-
381
+ size_t iter = kUpb_Map_Begin;
338
382
  VALUE ret = rb_ary_new();
339
- upb_strtable_iter it;
340
- for (upb_strtable_begin(&it, &self->table);
341
- !upb_strtable_done(&it);
342
- upb_strtable_next(&it)) {
343
-
344
- upb_value v = upb_strtable_iter_value(&it);
345
- void* mem = value_memory(&v);
346
- VALUE value = native_slot_get(self->value_type,
347
- self->value_type_class,
348
- mem);
349
-
350
- rb_ary_push(ret, value);
383
+ upb_MessageValue key, val;
384
+
385
+ while (upb_Map_Next(self->map, &key, &val, &iter)) {
386
+ VALUE val_val = Convert_UpbToRuby(val, self->value_type_info, self->arena);
387
+ rb_ary_push(ret, val_val);
351
388
  }
352
389
 
353
390
  return ret;
@@ -360,18 +397,14 @@ VALUE Map_values(VALUE _self) {
360
397
  * Accesses the element at the given key. Throws an exception if the key type is
361
398
  * incorrect. Returns nil when the key is not present in the map.
362
399
  */
363
- VALUE Map_index(VALUE _self, VALUE key) {
400
+ static VALUE Map_index(VALUE _self, VALUE key) {
364
401
  Map* self = ruby_to_Map(_self);
402
+ upb_MessageValue key_upb =
403
+ Convert_RubyToUpb(key, "", Map_keyinfo(self), NULL);
404
+ upb_MessageValue val;
365
405
 
366
- char keybuf[TABLE_KEY_BUF_LENGTH];
367
- const char* keyval = NULL;
368
- size_t length = 0;
369
- upb_value v;
370
- key = table_key(self, key, keybuf, &keyval, &length);
371
-
372
- if (upb_strtable_lookup2(&self->table, keyval, length, &v)) {
373
- void* mem = value_memory(&v);
374
- return native_slot_get(self->value_type, self->value_type_class, mem);
406
+ if (upb_Map_Get(self->map, key_upb, &val)) {
407
+ return Convert_UpbToRuby(val, self->value_type_info, self->arena);
375
408
  } else {
376
409
  return Qnil;
377
410
  }
@@ -385,27 +418,17 @@ VALUE Map_index(VALUE _self, VALUE key) {
385
418
  * Throws an exception if the key type is incorrect. Returns the new value that
386
419
  * was just inserted.
387
420
  */
388
- VALUE Map_index_set(VALUE _self, VALUE key, VALUE value) {
421
+ static VALUE Map_index_set(VALUE _self, VALUE key, VALUE val) {
389
422
  Map* self = ruby_to_Map(_self);
423
+ upb_Arena* arena = Arena_get(self->arena);
424
+ upb_MessageValue key_upb =
425
+ Convert_RubyToUpb(key, "", Map_keyinfo(self), NULL);
426
+ upb_MessageValue val_upb =
427
+ Convert_RubyToUpb(val, "", self->value_type_info, arena);
390
428
 
391
- char keybuf[TABLE_KEY_BUF_LENGTH];
392
- const char* keyval = NULL;
393
- size_t length = 0;
394
- upb_value v;
395
- void* mem;
396
- key = table_key(self, key, keybuf, &keyval, &length);
397
-
398
- mem = value_memory(&v);
399
- native_slot_set(self->value_type, self->value_type_class, mem, value);
429
+ upb_Map_Set(Map_GetMutable(_self), key_upb, val_upb, arena);
400
430
 
401
- // Replace any existing value by issuing a 'remove' operation first.
402
- upb_strtable_remove2(&self->table, keyval, length, NULL);
403
- if (!upb_strtable_insert2(&self->table, keyval, length, v)) {
404
- rb_raise(rb_eRuntimeError, "Could not insert into table");
405
- }
406
-
407
- // Ruby hashmap's :[]= method also returns the inserted value.
408
- return value;
431
+ return val;
409
432
  }
410
433
 
411
434
  /*
@@ -415,15 +438,12 @@ VALUE Map_index_set(VALUE _self, VALUE key, VALUE value) {
415
438
  * Returns true if the given key is present in the map. Throws an exception if
416
439
  * the key has the wrong type.
417
440
  */
418
- VALUE Map_has_key(VALUE _self, VALUE key) {
441
+ static VALUE Map_has_key(VALUE _self, VALUE key) {
419
442
  Map* self = ruby_to_Map(_self);
443
+ upb_MessageValue key_upb =
444
+ Convert_RubyToUpb(key, "", Map_keyinfo(self), NULL);
420
445
 
421
- char keybuf[TABLE_KEY_BUF_LENGTH];
422
- const char* keyval = NULL;
423
- size_t length = 0;
424
- key = table_key(self, key, keybuf, &keyval, &length);
425
-
426
- if (upb_strtable_lookup2(&self->table, keyval, length, NULL)) {
446
+ if (upb_Map_Get(self->map, key_upb, NULL)) {
427
447
  return Qtrue;
428
448
  } else {
429
449
  return Qfalse;
@@ -437,18 +457,16 @@ VALUE Map_has_key(VALUE _self, VALUE key) {
437
457
  * Deletes the value at the given key, if any, returning either the old value or
438
458
  * nil if none was present. Throws an exception if the key is of the wrong type.
439
459
  */
440
- VALUE Map_delete(VALUE _self, VALUE key) {
460
+ static VALUE Map_delete(VALUE _self, VALUE key) {
441
461
  Map* self = ruby_to_Map(_self);
462
+ rb_check_frozen(_self);
442
463
 
443
- char keybuf[TABLE_KEY_BUF_LENGTH];
444
- const char* keyval = NULL;
445
- size_t length = 0;
446
- upb_value v;
447
- key = table_key(self, key, keybuf, &keyval, &length);
464
+ upb_MessageValue key_upb =
465
+ Convert_RubyToUpb(key, "", Map_keyinfo(self), NULL);
466
+ upb_MessageValue val_upb;
448
467
 
449
- if (upb_strtable_remove2(&self->table, keyval, length, &v)) {
450
- void* mem = value_memory(&v);
451
- return native_slot_get(self->value_type, self->value_type_class, mem);
468
+ if (upb_Map_Delete(self->map, key_upb, &val_upb)) {
469
+ return Convert_UpbToRuby(val_upb, self->value_type_info, self->arena);
452
470
  } else {
453
471
  return Qnil;
454
472
  }
@@ -460,15 +478,8 @@ VALUE Map_delete(VALUE _self, VALUE key) {
460
478
  *
461
479
  * Removes all entries from the map.
462
480
  */
463
- VALUE Map_clear(VALUE _self) {
464
- Map* self = ruby_to_Map(_self);
465
-
466
- // Uninit and reinit the table -- this is faster than iterating and doing a
467
- // delete-lookup on each key.
468
- upb_strtable_uninit(&self->table);
469
- if (!upb_strtable_init(&self->table, UPB_CTYPE_INT64)) {
470
- rb_raise(rb_eRuntimeError, "Unable to re-initialize table");
471
- }
481
+ static VALUE Map_clear(VALUE _self) {
482
+ upb_Map_Clear(Map_GetMutable(_self));
472
483
  return Qnil;
473
484
  }
474
485
 
@@ -478,24 +489,9 @@ VALUE Map_clear(VALUE _self) {
478
489
  *
479
490
  * Returns the number of entries (key-value pairs) in the map.
480
491
  */
481
- VALUE Map_length(VALUE _self) {
492
+ static VALUE Map_length(VALUE _self) {
482
493
  Map* self = ruby_to_Map(_self);
483
- return ULL2NUM(upb_strtable_count(&self->table));
484
- }
485
-
486
- static VALUE Map_new_this_type(VALUE _self) {
487
- Map* self = ruby_to_Map(_self);
488
- VALUE new_map = Qnil;
489
- VALUE key_type = fieldtype_to_ruby(self->key_type);
490
- VALUE value_type = fieldtype_to_ruby(self->value_type);
491
- if (self->value_type_class != Qnil) {
492
- new_map = rb_funcall(CLASS_OF(_self), rb_intern("new"), 3,
493
- key_type, value_type, self->value_type_class);
494
- } else {
495
- new_map = rb_funcall(CLASS_OF(_self), rb_intern("new"), 2,
496
- key_type, value_type);
497
- }
498
- return new_map;
494
+ return ULL2NUM(upb_Map_Size(self->map));
499
495
  }
500
496
 
501
497
  /*
@@ -505,59 +501,22 @@ static VALUE Map_new_this_type(VALUE _self) {
505
501
  * Duplicates this map with a shallow copy. References to all non-primitive
506
502
  * element objects (e.g., submessages) are shared.
507
503
  */
508
- VALUE Map_dup(VALUE _self) {
504
+ static VALUE Map_dup(VALUE _self) {
509
505
  Map* self = ruby_to_Map(_self);
510
- VALUE new_map = Map_new_this_type(_self);
511
- Map* new_self = ruby_to_Map(new_map);
512
-
513
- upb_strtable_iter it;
514
- for (upb_strtable_begin(&it, &self->table);
515
- !upb_strtable_done(&it);
516
- upb_strtable_next(&it)) {
517
-
518
- upb_value v = upb_strtable_iter_value(&it);
519
- void* mem = value_memory(&v);
520
- upb_value dup;
521
- void* dup_mem = value_memory(&dup);
522
- native_slot_dup(self->value_type, dup_mem, mem);
523
-
524
- if (!upb_strtable_insert2(&new_self->table,
525
- upb_strtable_iter_key(&it),
526
- upb_strtable_iter_keylength(&it),
527
- dup)) {
528
- rb_raise(rb_eRuntimeError, "Error inserting value into new table");
529
- }
530
- }
506
+ VALUE new_map_rb = Map_new_this_type(self);
507
+ Map* new_self = ruby_to_Map(new_map_rb);
508
+ size_t iter = kUpb_Map_Begin;
509
+ upb_Arena* arena = Arena_get(new_self->arena);
510
+ upb_Map* new_map = Map_GetMutable(new_map_rb);
531
511
 
532
- return new_map;
533
- }
512
+ Arena_fuse(self->arena, arena);
534
513
 
535
- // Used by Google::Protobuf.deep_copy but not exposed directly.
536
- VALUE Map_deep_copy(VALUE _self) {
537
- Map* self = ruby_to_Map(_self);
538
- VALUE new_map = Map_new_this_type(_self);
539
- Map* new_self = ruby_to_Map(new_map);
540
-
541
- upb_strtable_iter it;
542
- for (upb_strtable_begin(&it, &self->table);
543
- !upb_strtable_done(&it);
544
- upb_strtable_next(&it)) {
545
-
546
- upb_value v = upb_strtable_iter_value(&it);
547
- void* mem = value_memory(&v);
548
- upb_value dup;
549
- void* dup_mem = value_memory(&dup);
550
- native_slot_deep_copy(self->value_type, dup_mem, mem);
551
-
552
- if (!upb_strtable_insert2(&new_self->table,
553
- upb_strtable_iter_key(&it),
554
- upb_strtable_iter_keylength(&it),
555
- dup)) {
556
- rb_raise(rb_eRuntimeError, "Error inserting value into new table");
557
- }
514
+ upb_MessageValue key, val;
515
+ while (upb_Map_Next(self->map, &key, &val, &iter)) {
516
+ upb_Map_Set(new_map, key, val, arena);
558
517
  }
559
518
 
560
- return new_map;
519
+ return new_map_rb;
561
520
  }
562
521
 
563
522
  /*
@@ -576,12 +535,11 @@ VALUE Map_deep_copy(VALUE _self) {
576
535
  VALUE Map_eq(VALUE _self, VALUE _other) {
577
536
  Map* self = ruby_to_Map(_self);
578
537
  Map* other;
579
- upb_strtable_iter it;
580
538
 
581
539
  // Allow comparisons to Ruby hashmaps by converting to a temporary Map
582
540
  // instance. Slow, but workable.
583
541
  if (TYPE(_other) == T_HASH) {
584
- VALUE other_map = Map_new_this_type(_self);
542
+ VALUE other_map = Map_new_this_type(self);
585
543
  Map_merge_into_self(other_map, _other);
586
544
  _other = other_map;
587
545
  }
@@ -592,35 +550,26 @@ VALUE Map_eq(VALUE _self, VALUE _other) {
592
550
  return Qtrue;
593
551
  }
594
552
  if (self->key_type != other->key_type ||
595
- self->value_type != other->value_type ||
553
+ self->value_type_info.type != other->value_type_info.type ||
596
554
  self->value_type_class != other->value_type_class) {
597
555
  return Qfalse;
598
556
  }
599
- if (upb_strtable_count(&self->table) != upb_strtable_count(&other->table)) {
557
+ if (upb_Map_Size(self->map) != upb_Map_Size(other->map)) {
600
558
  return Qfalse;
601
559
  }
602
560
 
603
561
  // For each member of self, check that an equal member exists at the same key
604
562
  // in other.
605
- for (upb_strtable_begin(&it, &self->table);
606
- !upb_strtable_done(&it);
607
- upb_strtable_next(&it)) {
608
-
609
- upb_value v = upb_strtable_iter_value(&it);
610
- void* mem = value_memory(&v);
611
- upb_value other_v;
612
- void* other_mem = value_memory(&other_v);
613
-
614
- if (!upb_strtable_lookup2(&other->table,
615
- upb_strtable_iter_key(&it),
616
- upb_strtable_iter_keylength(&it),
617
- &other_v)) {
563
+ size_t iter = kUpb_Map_Begin;
564
+ upb_MessageValue key, val;
565
+ while (upb_Map_Next(self->map, &key, &val, &iter)) {
566
+ upb_MessageValue other_val;
567
+ if (!upb_Map_Get(other->map, key, &other_val)) {
618
568
  // Not present in other map.
619
569
  return Qfalse;
620
570
  }
621
-
622
- if (!native_slot_eq(self->value_type, mem, other_mem)) {
623
- // Present, but value not equal.
571
+ if (!Msgval_IsEqual(val, other_val, self->value_type_info)) {
572
+ // Present but different value.
624
573
  return Qfalse;
625
574
  }
626
575
  }
@@ -628,6 +577,22 @@ VALUE Map_eq(VALUE _self, VALUE _other) {
628
577
  return Qtrue;
629
578
  }
630
579
 
580
+ /*
581
+ * call-seq:
582
+ * Message.freeze => self
583
+ *
584
+ * Freezes the message object. We have to intercept this so we can pin the
585
+ * Ruby object into memory so we don't forget it's frozen.
586
+ */
587
+ static VALUE Map_freeze(VALUE _self) {
588
+ Map* self = ruby_to_Map(_self);
589
+ if (!RB_OBJ_FROZEN(_self)) {
590
+ Arena_Pin(self->arena, _self);
591
+ RB_OBJ_FREEZE(_self);
592
+ }
593
+ return _self;
594
+ }
595
+
631
596
  /*
632
597
  * call-seq:
633
598
  * Map.hash => hash_value
@@ -636,28 +601,17 @@ VALUE Map_eq(VALUE _self, VALUE _other) {
636
601
  */
637
602
  VALUE Map_hash(VALUE _self) {
638
603
  Map* self = ruby_to_Map(_self);
639
-
640
- st_index_t h = rb_hash_start(0);
641
- VALUE hash_sym = rb_intern("hash");
642
-
643
- upb_strtable_iter it;
644
- for (upb_strtable_begin(&it, &self->table);
645
- !upb_strtable_done(&it);
646
- upb_strtable_next(&it)) {
647
- VALUE key = table_key_to_ruby(
648
- self, upb_strtable_iter_key(&it), upb_strtable_iter_keylength(&it));
649
-
650
- upb_value v = upb_strtable_iter_value(&it);
651
- void* mem = value_memory(&v);
652
- VALUE value = native_slot_get(self->value_type,
653
- self->value_type_class,
654
- mem);
655
-
656
- h = rb_hash_uint(h, NUM2LONG(rb_funcall(key, hash_sym, 0)));
657
- h = rb_hash_uint(h, NUM2LONG(rb_funcall(value, hash_sym, 0)));
604
+ uint64_t hash = 0;
605
+
606
+ size_t iter = kUpb_Map_Begin;
607
+ TypeInfo key_info = {self->key_type};
608
+ upb_MessageValue key, val;
609
+ while (upb_Map_Next(self->map, &key, &val, &iter)) {
610
+ hash = Msgval_GetHash(key, key_info, hash);
611
+ hash = Msgval_GetHash(val, self->value_type_info, hash);
658
612
  }
659
613
 
660
- return INT2FIX(h);
614
+ return LL2NUM(hash);
661
615
  }
662
616
 
663
617
  /*
@@ -668,25 +622,7 @@ VALUE Map_hash(VALUE _self) {
668
622
  */
669
623
  VALUE Map_to_h(VALUE _self) {
670
624
  Map* self = ruby_to_Map(_self);
671
- VALUE hash = rb_hash_new();
672
- upb_strtable_iter it;
673
- for (upb_strtable_begin(&it, &self->table);
674
- !upb_strtable_done(&it);
675
- upb_strtable_next(&it)) {
676
- VALUE key = table_key_to_ruby(
677
- self, upb_strtable_iter_key(&it), upb_strtable_iter_keylength(&it));
678
- upb_value v = upb_strtable_iter_value(&it);
679
- void* mem = value_memory(&v);
680
- VALUE value = native_slot_get(self->value_type,
681
- self->value_type_class,
682
- mem);
683
-
684
- if (self->value_type == UPB_TYPE_MESSAGE) {
685
- value = Message_to_h(value);
686
- }
687
- rb_hash_aset(hash, key, value);
688
- }
689
- return hash;
625
+ return Map_CreateHash(self->map, self->key_type, self->value_type_info);
690
626
  }
691
627
 
692
628
  /*
@@ -700,36 +636,11 @@ VALUE Map_to_h(VALUE _self) {
700
636
  VALUE Map_inspect(VALUE _self) {
701
637
  Map* self = ruby_to_Map(_self);
702
638
 
703
- VALUE str = rb_str_new2("{");
704
-
705
- bool first = true;
706
- VALUE inspect_sym = rb_intern("inspect");
707
-
708
- upb_strtable_iter it;
709
- for (upb_strtable_begin(&it, &self->table);
710
- !upb_strtable_done(&it);
711
- upb_strtable_next(&it)) {
712
- VALUE key = table_key_to_ruby(
713
- self, upb_strtable_iter_key(&it), upb_strtable_iter_keylength(&it));
714
-
715
- upb_value v = upb_strtable_iter_value(&it);
716
- void* mem = value_memory(&v);
717
- VALUE value = native_slot_get(self->value_type,
718
- self->value_type_class,
719
- mem);
720
-
721
- if (!first) {
722
- str = rb_str_cat2(str, ", ");
723
- } else {
724
- first = false;
725
- }
726
- str = rb_str_append(str, rb_funcall(key, inspect_sym, 0));
727
- str = rb_str_cat2(str, "=>");
728
- str = rb_str_append(str, rb_funcall(value, inspect_sym, 0));
729
- }
730
-
731
- str = rb_str_cat2(str, "}");
732
- return str;
639
+ StringBuilder* builder = StringBuilder_New();
640
+ Map_Inspect(builder, self->map, self->key_type, self->value_type_info);
641
+ VALUE ret = StringBuilder_ToRubyString(builder);
642
+ StringBuilder_Free(builder);
643
+ return ret;
733
644
  }
734
645
 
735
646
  /*
@@ -741,92 +652,16 @@ VALUE Map_inspect(VALUE _self) {
741
652
  * in the new copy of this map. Returns the new copy of this map with merged
742
653
  * contents.
743
654
  */
744
- VALUE Map_merge(VALUE _self, VALUE hashmap) {
655
+ static VALUE Map_merge(VALUE _self, VALUE hashmap) {
745
656
  VALUE dupped = Map_dup(_self);
746
657
  return Map_merge_into_self(dupped, hashmap);
747
658
  }
748
659
 
749
- static int merge_into_self_callback(VALUE key, VALUE value, VALUE self) {
750
- Map_index_set(self, key, value);
751
- return ST_CONTINUE;
752
- }
753
-
754
- // Used only internally -- shared by #merge and #initialize.
755
- VALUE Map_merge_into_self(VALUE _self, VALUE hashmap) {
756
- if (TYPE(hashmap) == T_HASH) {
757
- rb_hash_foreach(hashmap, merge_into_self_callback, _self);
758
- } else if (RB_TYPE_P(hashmap, T_DATA) && RTYPEDDATA_P(hashmap) &&
759
- RTYPEDDATA_TYPE(hashmap) == &Map_type) {
760
-
761
- Map* self = ruby_to_Map(_self);
762
- Map* other = ruby_to_Map(hashmap);
763
- upb_strtable_iter it;
764
-
765
- if (self->key_type != other->key_type ||
766
- self->value_type != other->value_type ||
767
- self->value_type_class != other->value_type_class) {
768
- rb_raise(rb_eArgError, "Attempt to merge Map with mismatching types");
769
- }
770
-
771
- for (upb_strtable_begin(&it, &other->table);
772
- !upb_strtable_done(&it);
773
- upb_strtable_next(&it)) {
774
-
775
- // Replace any existing value by issuing a 'remove' operation first.
776
- upb_value v;
777
- upb_value oldv;
778
- upb_strtable_remove2(&self->table,
779
- upb_strtable_iter_key(&it),
780
- upb_strtable_iter_keylength(&it),
781
- &oldv);
782
-
783
- v = upb_strtable_iter_value(&it);
784
- upb_strtable_insert2(&self->table,
785
- upb_strtable_iter_key(&it),
786
- upb_strtable_iter_keylength(&it),
787
- v);
788
- }
789
- } else {
790
- rb_raise(rb_eArgError, "Unknown type merging into Map");
791
- }
792
- return _self;
793
- }
794
-
795
- // Internal method: map iterator initialization (used for serialization).
796
- void Map_begin(VALUE _self, Map_iter* iter) {
797
- Map* self = ruby_to_Map(_self);
798
- iter->self = self;
799
- upb_strtable_begin(&iter->it, &self->table);
800
- }
801
-
802
- void Map_next(Map_iter* iter) {
803
- upb_strtable_next(&iter->it);
804
- }
805
-
806
- bool Map_done(Map_iter* iter) {
807
- return upb_strtable_done(&iter->it);
808
- }
809
-
810
- VALUE Map_iter_key(Map_iter* iter) {
811
- return table_key_to_ruby(
812
- iter->self,
813
- upb_strtable_iter_key(&iter->it),
814
- upb_strtable_iter_keylength(&iter->it));
815
- }
816
-
817
- VALUE Map_iter_value(Map_iter* iter) {
818
- upb_value v = upb_strtable_iter_value(&iter->it);
819
- void* mem = value_memory(&v);
820
- return native_slot_get(iter->self->value_type,
821
- iter->self->value_type_class,
822
- mem);
823
- }
824
-
825
660
  void Map_register(VALUE module) {
826
661
  VALUE klass = rb_define_class_under(module, "Map", rb_cObject);
827
662
  rb_define_alloc_func(klass, Map_alloc);
828
- cMap = klass;
829
663
  rb_gc_register_address(&cMap);
664
+ cMap = klass;
830
665
 
831
666
  rb_define_method(klass, "initialize", Map_init, -1);
832
667
  rb_define_method(klass, "each", Map_each, 0);
@@ -838,10 +673,13 @@ void Map_register(VALUE module) {
838
673
  rb_define_method(klass, "delete", Map_delete, 1);
839
674
  rb_define_method(klass, "clear", Map_clear, 0);
840
675
  rb_define_method(klass, "length", Map_length, 0);
676
+ rb_define_method(klass, "size", Map_length, 0);
841
677
  rb_define_method(klass, "dup", Map_dup, 0);
678
+ // Also define #clone so that we don't inherit Object#clone.
679
+ rb_define_method(klass, "clone", Map_dup, 0);
842
680
  rb_define_method(klass, "==", Map_eq, 1);
681
+ rb_define_method(klass, "freeze", Map_freeze, 0);
843
682
  rb_define_method(klass, "hash", Map_hash, 0);
844
- rb_define_method(klass, "to_hash", Map_to_h, 0);
845
683
  rb_define_method(klass, "to_h", Map_to_h, 0);
846
684
  rb_define_method(klass, "inspect", Map_inspect, 0);
847
685
  rb_define_method(klass, "merge", Map_merge, 1);