google-protobuf 3.11.3 → 3.19.3

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.

@@ -28,170 +28,233 @@
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
- if (TYPE(key) == T_SYMBOL) {
75
- key = rb_id2str(SYM2ID(key));
76
- }
77
- Check_Type(key, T_STRING);
78
- key = native_slot_encode_and_freeze_string(self->key_type, key);
79
- *out_key = RSTRING_PTR(key);
80
- *out_length = RSTRING_LEN(key);
81
- break;
82
-
83
- case UPB_TYPE_BOOL:
84
- case UPB_TYPE_INT32:
85
- case UPB_TYPE_INT64:
86
- case UPB_TYPE_UINT32:
87
- case UPB_TYPE_UINT64:
88
- native_slot_set("", self->key_type, Qnil, buf, key);
89
- *out_key = buf;
90
- *out_length = native_slot_size(self->key_type);
91
- break;
92
-
93
- default:
94
- // Map constructor should not allow a Map with another key type to be
95
- // constructed.
96
- assert(false);
97
- break;
98
- }
99
-
100
- return key;
101
- }
102
-
103
- static VALUE table_key_to_ruby(Map* self, const char* buf, size_t length) {
104
- switch (self->key_type) {
105
- case UPB_TYPE_BYTES:
106
- case UPB_TYPE_STRING: {
107
- VALUE ret = rb_str_new(buf, length);
108
- rb_enc_associate(ret,
109
- (self->key_type == UPB_TYPE_BYTES) ?
110
- kRubyString8bitEncoding : kRubyStringUtf8Encoding);
111
- return ret;
112
- }
113
-
114
- case UPB_TYPE_BOOL:
115
- case UPB_TYPE_INT32:
116
- case UPB_TYPE_INT64:
117
- case UPB_TYPE_UINT32:
118
- case UPB_TYPE_UINT64:
119
- return native_slot_get(self->key_type, Qnil, buf);
120
-
121
- default:
122
- assert(false);
123
- return Qnil;
124
- }
125
- }
126
-
127
- static void* value_memory(upb_value* v) {
128
- return (void*)(&v->val);
129
- }
130
-
131
46
  // -----------------------------------------------------------------------------
132
47
  // Map container type.
133
48
  // -----------------------------------------------------------------------------
134
49
 
50
+ typedef struct {
51
+ const upb_map *map; // Can convert to mutable when non-frozen.
52
+ upb_fieldtype_t key_type;
53
+ TypeInfo value_type_info;
54
+ VALUE value_type_class;
55
+ VALUE arena;
56
+ } Map;
57
+
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
+
135
64
  const rb_data_type_t Map_type = {
136
65
  "Google::Protobuf::Map",
137
- { Map_mark, Map_free, NULL },
66
+ { Map_mark, RUBY_DEFAULT_FREE, NULL },
67
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY,
138
68
  };
139
69
 
140
70
  VALUE cMap;
141
71
 
142
- Map* ruby_to_Map(VALUE _self) {
72
+ static Map* ruby_to_Map(VALUE _self) {
143
73
  Map* self;
144
74
  TypedData_Get_Struct(_self, Map, &Map_type, self);
145
75
  return self;
146
76
  }
147
77
 
148
- void Map_mark(void* _self) {
149
- Map* self = _self;
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
+ }
150
86
 
151
- rb_gc_mark(self->value_type_class);
152
- rb_gc_mark(self->parse_frame);
153
-
154
- if (self->value_type == UPB_TYPE_STRING ||
155
- self->value_type == UPB_TYPE_BYTES ||
156
- self->value_type == UPB_TYPE_MESSAGE) {
157
- upb_strtable_iter it;
158
- for (upb_strtable_begin(&it, &self->table);
159
- !upb_strtable_done(&it);
160
- upb_strtable_next(&it)) {
161
- upb_value v = upb_strtable_iter_value(&it);
162
- void* mem = value_memory(&v);
163
- native_slot_mark(self->value_type, mem);
87
+ VALUE Map_GetRubyWrapper(upb_map* map, upb_fieldtype_t key_type,
88
+ TypeInfo value_type, 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 == UPB_TYPE_MESSAGE) {
103
+ const upb_msgdef *val_m = self->value_type_info.def.msgdef;
104
+ self->value_type_class = Descriptor_DefToClass(val_m);
164
105
  }
165
106
  }
107
+
108
+ return val;
166
109
  }
167
110
 
168
- void Map_free(void* _self) {
169
- Map* self = _self;
170
- upb_strtable_uninit(&self->table);
171
- xfree(self);
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;
172
119
  }
173
120
 
174
- VALUE Map_alloc(VALUE klass) {
175
- Map* self = ALLOC(Map);
176
- memset(self, 0, sizeof(Map));
177
- self->value_type_class = Qnil;
178
- return TypedData_Wrap_Struct(klass, &Map_type, self);
121
+ static TypeInfo Map_keyinfo(Map* self) {
122
+ TypeInfo ret;
123
+ ret.type = self->key_type;
124
+ ret.def.msgdef = NULL;
125
+ return ret;
179
126
  }
180
127
 
181
- VALUE Map_set_frame(VALUE map, VALUE val) {
182
- Map* self = ruby_to_Map(map);
183
- self->parse_frame = val;
184
- return val;
128
+ static upb_map *Map_GetMutable(VALUE _self) {
129
+ rb_check_frozen(_self);
130
+ return (upb_map*)ruby_to_Map(_self)->map;
185
131
  }
186
132
 
187
- static bool needs_typeclass(upb_fieldtype_t type) {
188
- switch (type) {
189
- case UPB_TYPE_MESSAGE:
190
- case UPB_TYPE_ENUM:
191
- return true;
192
- default:
193
- return false;
133
+ VALUE Map_CreateHash(const upb_map* map, upb_fieldtype_t key_type,
134
+ TypeInfo val_info) {
135
+ VALUE hash = rb_hash_new();
136
+ size_t iter = UPB_MAP_BEGIN;
137
+ TypeInfo key_info = TypeInfo_from_type(key_type);
138
+
139
+ if (!map) return hash;
140
+
141
+ while (upb_mapiter_next(map, &iter)) {
142
+ upb_msgval key = upb_mapiter_key(map, iter);
143
+ upb_msgval val = upb_mapiter_value(map, iter);
144
+ VALUE key_val = Convert_UpbToRuby(key, key_info, Qnil);
145
+ VALUE val_val = Scalar_CreateHash(val, val_info);
146
+ rb_hash_aset(hash, key_val, val_val);
147
+ }
148
+
149
+ return hash;
150
+ }
151
+
152
+ VALUE Map_deep_copy(VALUE obj) {
153
+ Map* self = ruby_to_Map(obj);
154
+ VALUE new_arena_rb = Arena_new();
155
+ upb_arena *arena = Arena_get(new_arena_rb);
156
+ upb_map* new_map =
157
+ upb_map_new(arena, self->key_type, self->value_type_info.type);
158
+ size_t iter = UPB_MAP_BEGIN;
159
+ while (upb_mapiter_next(self->map, &iter)) {
160
+ upb_msgval key = upb_mapiter_key(self->map, iter);
161
+ upb_msgval val = upb_mapiter_value(self->map, iter);
162
+ upb_msgval val_copy = Msgval_DeepCopy(val, self->value_type_info, arena);
163
+ upb_map_set(new_map, key, val_copy, arena);
164
+ }
165
+
166
+ return Map_GetRubyWrapper(new_map, self->key_type, self->value_type_info,
167
+ new_arena_rb);
168
+ }
169
+
170
+ const upb_map* Map_GetUpbMap(VALUE val, const upb_fielddef* field,
171
+ upb_arena* arena) {
172
+ const upb_fielddef* key_field = map_field_key(field);
173
+ const upb_fielddef* value_field = map_field_value(field);
174
+ TypeInfo value_type_info = TypeInfo_get(value_field);
175
+ Map* self;
176
+
177
+ if (!RB_TYPE_P(val, T_DATA) || !RTYPEDDATA_P(val) ||
178
+ RTYPEDDATA_TYPE(val) != &Map_type) {
179
+ rb_raise(cTypeError, "Expected Map instance");
180
+ }
181
+
182
+ self = ruby_to_Map(val);
183
+ if (self->key_type != upb_fielddef_type(key_field)) {
184
+ rb_raise(cTypeError, "Map key type does not match field's key type");
185
+ }
186
+ if (self->value_type_info.type != value_type_info.type) {
187
+ rb_raise(cTypeError, "Map value type does not match field's value type");
188
+ }
189
+ if (self->value_type_info.def.msgdef != value_type_info.def.msgdef) {
190
+ rb_raise(cTypeError, "Map value type has wrong message/enum class");
191
+ }
192
+
193
+ Arena_fuse(self->arena, arena);
194
+ return self->map;
195
+ }
196
+
197
+ void Map_Inspect(StringBuilder* b, const upb_map* map, upb_fieldtype_t key_type,
198
+ TypeInfo val_type) {
199
+ bool first = true;
200
+ TypeInfo key_type_info = {key_type};
201
+ StringBuilder_Printf(b, "{");
202
+ if (map) {
203
+ size_t iter = UPB_MAP_BEGIN;
204
+ while (upb_mapiter_next(map, &iter)) {
205
+ upb_msgval key = upb_mapiter_key(map, iter);
206
+ upb_msgval val = upb_mapiter_value(map, iter);
207
+ if (first) {
208
+ first = false;
209
+ } else {
210
+ StringBuilder_Printf(b, ", ");
211
+ }
212
+ StringBuilder_PrintMsgval(b, key, key_type_info);
213
+ StringBuilder_Printf(b, "=>");
214
+ StringBuilder_PrintMsgval(b, val, val_type);
215
+ }
216
+ }
217
+ StringBuilder_Printf(b, "}");
218
+ }
219
+
220
+ static int merge_into_self_callback(VALUE key, VALUE val, VALUE _self) {
221
+ Map* self = ruby_to_Map(_self);
222
+ upb_arena *arena = Arena_get(self->arena);
223
+ upb_msgval key_val = Convert_RubyToUpb(key, "", Map_keyinfo(self), arena);
224
+ upb_msgval val_val = Convert_RubyToUpb(val, "", self->value_type_info, arena);
225
+ upb_map_set(Map_GetMutable(_self), key_val, val_val, arena);
226
+ return ST_CONTINUE;
227
+ }
228
+
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_msg *self_msg = Map_GetMutable(_self);
239
+ size_t iter = UPB_MAP_BEGIN;
240
+
241
+ Arena_fuse(other->arena, arena);
242
+
243
+ if (self->key_type != other->key_type ||
244
+ self->value_type_info.type != other->value_type_info.type ||
245
+ self->value_type_class != other->value_type_class) {
246
+ rb_raise(rb_eArgError, "Attempt to merge Map with mismatching types");
247
+ }
248
+
249
+ while (upb_mapiter_next(other->map, &iter)) {
250
+ upb_msgval key = upb_mapiter_key(other->map, iter);
251
+ upb_msgval val = upb_mapiter_value(other->map, iter);
252
+ upb_map_set(self_msg, key, val, arena);
253
+ }
254
+ } else {
255
+ rb_raise(rb_eArgError, "Unknown type merging into Map");
194
256
  }
257
+ return _self;
195
258
  }
196
259
 
197
260
  /*
@@ -224,9 +287,9 @@ static bool needs_typeclass(upb_fieldtype_t type) {
224
287
  * references to underlying objects will be shared if the value type is a
225
288
  * message type.
226
289
  */
227
- VALUE Map_init(int argc, VALUE* argv, VALUE _self) {
290
+ static VALUE Map_init(int argc, VALUE* argv, VALUE _self) {
228
291
  Map* self = ruby_to_Map(_self);
229
- int init_value_arg;
292
+ VALUE init_arg;
230
293
 
231
294
  // We take either two args (:key_type, :value_type), three args (:key_type,
232
295
  // :value_type, "ValueMessageType"), or four args (the above plus an initial
@@ -236,8 +299,9 @@ VALUE Map_init(int argc, VALUE* argv, VALUE _self) {
236
299
  }
237
300
 
238
301
  self->key_type = ruby_to_fieldtype(argv[0]);
239
- self->value_type = ruby_to_fieldtype(argv[1]);
240
- self->parse_frame = Qnil;
302
+ self->value_type_info =
303
+ TypeInfo_FromClass(argc, argv, 1, &self->value_type_class, &init_arg);
304
+ self->arena = Arena_new();
241
305
 
242
306
  // Check that the key type is an allowed type.
243
307
  switch (self->key_type) {
@@ -254,21 +318,12 @@ VALUE Map_init(int argc, VALUE* argv, VALUE _self) {
254
318
  rb_raise(rb_eArgError, "Invalid key type for map.");
255
319
  }
256
320
 
257
- init_value_arg = 2;
258
- if (needs_typeclass(self->value_type) && argc > 2) {
259
- self->value_type_class = argv[2];
260
- validate_type_class(self->value_type, self->value_type_class);
261
- init_value_arg = 3;
262
- }
263
-
264
- // Table value type is always UINT64: this ensures enough space to store the
265
- // native_slot value.
266
- if (!upb_strtable_init(&self->table, UPB_CTYPE_UINT64)) {
267
- rb_raise(rb_eRuntimeError, "Could not allocate table.");
268
- }
321
+ self->map = upb_map_new(Arena_get(self->arena), self->key_type,
322
+ self->value_type_info.type);
323
+ ObjectCache_Add(self->map, _self);
269
324
 
270
- if (argc > init_value_arg) {
271
- Map_merge_into_self(_self, argv[init_value_arg]);
325
+ if (init_arg != Qnil) {
326
+ Map_merge_into_self(_self, init_arg);
272
327
  }
273
328
 
274
329
  return Qnil;
@@ -282,24 +337,16 @@ VALUE Map_init(int argc, VALUE* argv, VALUE _self) {
282
337
  * Note that Map also includes Enumerable; map thus acts like a normal Ruby
283
338
  * sequence.
284
339
  */
285
- VALUE Map_each(VALUE _self) {
340
+ static VALUE Map_each(VALUE _self) {
286
341
  Map* self = ruby_to_Map(_self);
287
-
288
- upb_strtable_iter it;
289
- for (upb_strtable_begin(&it, &self->table);
290
- !upb_strtable_done(&it);
291
- upb_strtable_next(&it)) {
292
-
293
- VALUE key = table_key_to_ruby(
294
- self, upb_strtable_iter_key(&it), upb_strtable_iter_keylength(&it));
295
-
296
- upb_value v = upb_strtable_iter_value(&it);
297
- void* mem = value_memory(&v);
298
- VALUE value = native_slot_get(self->value_type,
299
- self->value_type_class,
300
- mem);
301
-
302
- rb_yield_values(2, key, value);
342
+ size_t iter = UPB_MAP_BEGIN;
343
+
344
+ while (upb_mapiter_next(self->map, &iter)) {
345
+ upb_msgval key = upb_mapiter_key(self->map, iter);
346
+ upb_msgval val = upb_mapiter_value(self->map, iter);
347
+ VALUE key_val = Convert_UpbToRuby(key, Map_keyinfo(self), self->arena);
348
+ VALUE val_val = Convert_UpbToRuby(val, self->value_type_info, self->arena);
349
+ rb_yield_values(2, key_val, val_val);
303
350
  }
304
351
 
305
352
  return Qnil;
@@ -311,19 +358,15 @@ VALUE Map_each(VALUE _self) {
311
358
  *
312
359
  * Returns the list of keys contained in the map, in unspecified order.
313
360
  */
314
- VALUE Map_keys(VALUE _self) {
361
+ static VALUE Map_keys(VALUE _self) {
315
362
  Map* self = ruby_to_Map(_self);
316
-
363
+ size_t iter = UPB_MAP_BEGIN;
317
364
  VALUE ret = rb_ary_new();
318
- upb_strtable_iter it;
319
- for (upb_strtable_begin(&it, &self->table);
320
- !upb_strtable_done(&it);
321
- upb_strtable_next(&it)) {
322
-
323
- VALUE key = table_key_to_ruby(
324
- self, upb_strtable_iter_key(&it), upb_strtable_iter_keylength(&it));
325
365
 
326
- rb_ary_push(ret, key);
366
+ while (upb_mapiter_next(self->map, &iter)) {
367
+ upb_msgval key = upb_mapiter_key(self->map, iter);
368
+ VALUE key_val = Convert_UpbToRuby(key, Map_keyinfo(self), self->arena);
369
+ rb_ary_push(ret, key_val);
327
370
  }
328
371
 
329
372
  return ret;
@@ -335,22 +378,15 @@ VALUE Map_keys(VALUE _self) {
335
378
  *
336
379
  * Returns the list of values contained in the map, in unspecified order.
337
380
  */
338
- VALUE Map_values(VALUE _self) {
381
+ static VALUE Map_values(VALUE _self) {
339
382
  Map* self = ruby_to_Map(_self);
340
-
383
+ size_t iter = UPB_MAP_BEGIN;
341
384
  VALUE ret = rb_ary_new();
342
- upb_strtable_iter it;
343
- for (upb_strtable_begin(&it, &self->table);
344
- !upb_strtable_done(&it);
345
- upb_strtable_next(&it)) {
346
-
347
- upb_value v = upb_strtable_iter_value(&it);
348
- void* mem = value_memory(&v);
349
- VALUE value = native_slot_get(self->value_type,
350
- self->value_type_class,
351
- mem);
352
-
353
- rb_ary_push(ret, value);
385
+
386
+ while (upb_mapiter_next(self->map, &iter)) {
387
+ upb_msgval val = upb_mapiter_value(self->map, iter);
388
+ VALUE val_val = Convert_UpbToRuby(val, self->value_type_info, self->arena);
389
+ rb_ary_push(ret, val_val);
354
390
  }
355
391
 
356
392
  return ret;
@@ -363,18 +399,13 @@ VALUE Map_values(VALUE _self) {
363
399
  * Accesses the element at the given key. Throws an exception if the key type is
364
400
  * incorrect. Returns nil when the key is not present in the map.
365
401
  */
366
- VALUE Map_index(VALUE _self, VALUE key) {
402
+ static VALUE Map_index(VALUE _self, VALUE key) {
367
403
  Map* self = ruby_to_Map(_self);
404
+ upb_msgval key_upb = Convert_RubyToUpb(key, "", Map_keyinfo(self), NULL);
405
+ upb_msgval val;
368
406
 
369
- char keybuf[TABLE_KEY_BUF_LENGTH];
370
- const char* keyval = NULL;
371
- size_t length = 0;
372
- upb_value v;
373
- key = table_key(self, key, keybuf, &keyval, &length);
374
-
375
- if (upb_strtable_lookup2(&self->table, keyval, length, &v)) {
376
- void* mem = value_memory(&v);
377
- return native_slot_get(self->value_type, self->value_type_class, mem);
407
+ if (upb_map_get(self->map, key_upb, &val)) {
408
+ return Convert_UpbToRuby(val, self->value_type_info, self->arena);
378
409
  } else {
379
410
  return Qnil;
380
411
  }
@@ -388,33 +419,15 @@ VALUE Map_index(VALUE _self, VALUE key) {
388
419
  * Throws an exception if the key type is incorrect. Returns the new value that
389
420
  * was just inserted.
390
421
  */
391
- VALUE Map_index_set(VALUE _self, VALUE key, VALUE value) {
422
+ static VALUE Map_index_set(VALUE _self, VALUE key, VALUE val) {
392
423
  Map* self = ruby_to_Map(_self);
393
- char keybuf[TABLE_KEY_BUF_LENGTH];
394
- const char* keyval = NULL;
395
- size_t length = 0;
396
- upb_value v;
397
- void* mem;
398
- key = table_key(self, key, keybuf, &keyval, &length);
399
-
400
- rb_check_frozen(_self);
401
-
402
- if (TYPE(value) == T_HASH) {
403
- VALUE args[1] = { value };
404
- value = rb_class_new_instance(1, args, self->value_type_class);
405
- }
424
+ upb_arena *arena = Arena_get(self->arena);
425
+ upb_msgval key_upb = Convert_RubyToUpb(key, "", Map_keyinfo(self), NULL);
426
+ upb_msgval val_upb = Convert_RubyToUpb(val, "", self->value_type_info, arena);
406
427
 
407
- mem = value_memory(&v);
408
- native_slot_set("", self->value_type, self->value_type_class, mem, value);
428
+ upb_map_set(Map_GetMutable(_self), key_upb, val_upb, arena);
409
429
 
410
- // Replace any existing value by issuing a 'remove' operation first.
411
- upb_strtable_remove2(&self->table, keyval, length, NULL);
412
- if (!upb_strtable_insert2(&self->table, keyval, length, v)) {
413
- rb_raise(rb_eRuntimeError, "Could not insert into table");
414
- }
415
-
416
- // Ruby hashmap's :[]= method also returns the inserted value.
417
- return value;
430
+ return val;
418
431
  }
419
432
 
420
433
  /*
@@ -424,15 +437,11 @@ VALUE Map_index_set(VALUE _self, VALUE key, VALUE value) {
424
437
  * Returns true if the given key is present in the map. Throws an exception if
425
438
  * the key has the wrong type.
426
439
  */
427
- VALUE Map_has_key(VALUE _self, VALUE key) {
440
+ static VALUE Map_has_key(VALUE _self, VALUE key) {
428
441
  Map* self = ruby_to_Map(_self);
442
+ upb_msgval key_upb = Convert_RubyToUpb(key, "", Map_keyinfo(self), NULL);
429
443
 
430
- char keybuf[TABLE_KEY_BUF_LENGTH];
431
- const char* keyval = NULL;
432
- size_t length = 0;
433
- key = table_key(self, key, keybuf, &keyval, &length);
434
-
435
- if (upb_strtable_lookup2(&self->table, keyval, length, NULL)) {
444
+ if (upb_map_get(self->map, key_upb, NULL)) {
436
445
  return Qtrue;
437
446
  } else {
438
447
  return Qfalse;
@@ -446,22 +455,25 @@ VALUE Map_has_key(VALUE _self, VALUE key) {
446
455
  * Deletes the value at the given key, if any, returning either the old value or
447
456
  * nil if none was present. Throws an exception if the key is of the wrong type.
448
457
  */
449
- VALUE Map_delete(VALUE _self, VALUE key) {
458
+ static VALUE Map_delete(VALUE _self, VALUE key) {
450
459
  Map* self = ruby_to_Map(_self);
451
- char keybuf[TABLE_KEY_BUF_LENGTH];
452
- const char* keyval = NULL;
453
- size_t length = 0;
454
- upb_value v;
455
- key = table_key(self, key, keybuf, &keyval, &length);
460
+ upb_msgval key_upb = Convert_RubyToUpb(key, "", Map_keyinfo(self), NULL);
461
+ upb_msgval val_upb;
462
+ VALUE ret;
456
463
 
457
464
  rb_check_frozen(_self);
458
465
 
459
- if (upb_strtable_remove2(&self->table, keyval, length, &v)) {
460
- void* mem = value_memory(&v);
461
- return native_slot_get(self->value_type, self->value_type_class, mem);
466
+ // TODO(haberman): make upb_map_delete() also capable of returning the deleted
467
+ // value.
468
+ if (upb_map_get(self->map, key_upb, &val_upb)) {
469
+ ret = Convert_UpbToRuby(val_upb, self->value_type_info, self->arena);
462
470
  } else {
463
- return Qnil;
471
+ ret = Qnil;
464
472
  }
473
+
474
+ upb_map_delete(Map_GetMutable(_self), key_upb);
475
+
476
+ return ret;
465
477
  }
466
478
 
467
479
  /*
@@ -470,17 +482,8 @@ VALUE Map_delete(VALUE _self, VALUE key) {
470
482
  *
471
483
  * Removes all entries from the map.
472
484
  */
473
- VALUE Map_clear(VALUE _self) {
474
- Map* self = ruby_to_Map(_self);
475
-
476
- rb_check_frozen(_self);
477
-
478
- // Uninit and reinit the table -- this is faster than iterating and doing a
479
- // delete-lookup on each key.
480
- upb_strtable_uninit(&self->table);
481
- if (!upb_strtable_init(&self->table, UPB_CTYPE_INT64)) {
482
- rb_raise(rb_eRuntimeError, "Unable to re-initialize table");
483
- }
485
+ static VALUE Map_clear(VALUE _self) {
486
+ upb_map_clear(Map_GetMutable(_self));
484
487
  return Qnil;
485
488
  }
486
489
 
@@ -490,24 +493,9 @@ VALUE Map_clear(VALUE _self) {
490
493
  *
491
494
  * Returns the number of entries (key-value pairs) in the map.
492
495
  */
493
- VALUE Map_length(VALUE _self) {
496
+ static VALUE Map_length(VALUE _self) {
494
497
  Map* self = ruby_to_Map(_self);
495
- return ULL2NUM(upb_strtable_count(&self->table));
496
- }
497
-
498
- VALUE Map_new_this_type(VALUE _self) {
499
- Map* self = ruby_to_Map(_self);
500
- VALUE new_map = Qnil;
501
- VALUE key_type = fieldtype_to_ruby(self->key_type);
502
- VALUE value_type = fieldtype_to_ruby(self->value_type);
503
- if (self->value_type_class != Qnil) {
504
- new_map = rb_funcall(CLASS_OF(_self), rb_intern("new"), 3,
505
- key_type, value_type, self->value_type_class);
506
- } else {
507
- new_map = rb_funcall(CLASS_OF(_self), rb_intern("new"), 2,
508
- key_type, value_type);
509
- }
510
- return new_map;
498
+ return ULL2NUM(upb_map_size(self->map));
511
499
  }
512
500
 
513
501
  /*
@@ -517,60 +505,23 @@ VALUE Map_new_this_type(VALUE _self) {
517
505
  * Duplicates this map with a shallow copy. References to all non-primitive
518
506
  * element objects (e.g., submessages) are shared.
519
507
  */
520
- VALUE Map_dup(VALUE _self) {
521
- Map* self = ruby_to_Map(_self);
522
- VALUE new_map = Map_new_this_type(_self);
523
- Map* new_self = ruby_to_Map(new_map);
524
-
525
- upb_strtable_iter it;
526
- for (upb_strtable_begin(&it, &self->table);
527
- !upb_strtable_done(&it);
528
- upb_strtable_next(&it)) {
529
-
530
- upb_value v = upb_strtable_iter_value(&it);
531
- void* mem = value_memory(&v);
532
- upb_value dup;
533
- void* dup_mem = value_memory(&dup);
534
- native_slot_dup(self->value_type, dup_mem, mem);
535
-
536
- if (!upb_strtable_insert2(&new_self->table,
537
- upb_strtable_iter_key(&it),
538
- upb_strtable_iter_keylength(&it),
539
- dup)) {
540
- rb_raise(rb_eRuntimeError, "Error inserting value into new table");
541
- }
542
- }
543
-
544
- return new_map;
545
- }
546
-
547
- // Used by Google::Protobuf.deep_copy but not exposed directly.
548
- VALUE Map_deep_copy(VALUE _self) {
508
+ static VALUE Map_dup(VALUE _self) {
549
509
  Map* self = ruby_to_Map(_self);
550
- VALUE new_map = Map_new_this_type(_self);
551
- Map* new_self = ruby_to_Map(new_map);
552
-
553
- upb_strtable_iter it;
554
- for (upb_strtable_begin(&it, &self->table);
555
- !upb_strtable_done(&it);
556
- upb_strtable_next(&it)) {
557
-
558
- upb_value v = upb_strtable_iter_value(&it);
559
- void* mem = value_memory(&v);
560
- upb_value dup;
561
- void* dup_mem = value_memory(&dup);
562
- native_slot_deep_copy(self->value_type, self->value_type_class, dup_mem,
563
- mem);
564
-
565
- if (!upb_strtable_insert2(&new_self->table,
566
- upb_strtable_iter_key(&it),
567
- upb_strtable_iter_keylength(&it),
568
- dup)) {
569
- rb_raise(rb_eRuntimeError, "Error inserting value into new table");
570
- }
510
+ VALUE new_map_rb = Map_new_this_type(self);
511
+ Map* new_self = ruby_to_Map(new_map_rb);
512
+ size_t iter = UPB_MAP_BEGIN;
513
+ upb_arena *arena = Arena_get(new_self->arena);
514
+ upb_map *new_map = Map_GetMutable(new_map_rb);
515
+
516
+ Arena_fuse(self->arena, arena);
517
+
518
+ while (upb_mapiter_next(self->map, &iter)) {
519
+ upb_msgval key = upb_mapiter_key(self->map, iter);
520
+ upb_msgval val = upb_mapiter_value(self->map, iter);
521
+ upb_map_set(new_map, key, val, arena);
571
522
  }
572
523
 
573
- return new_map;
524
+ return new_map_rb;
574
525
  }
575
526
 
576
527
  /*
@@ -589,12 +540,11 @@ VALUE Map_deep_copy(VALUE _self) {
589
540
  VALUE Map_eq(VALUE _self, VALUE _other) {
590
541
  Map* self = ruby_to_Map(_self);
591
542
  Map* other;
592
- upb_strtable_iter it;
593
543
 
594
544
  // Allow comparisons to Ruby hashmaps by converting to a temporary Map
595
545
  // instance. Slow, but workable.
596
546
  if (TYPE(_other) == T_HASH) {
597
- VALUE other_map = Map_new_this_type(_self);
547
+ VALUE other_map = Map_new_this_type(self);
598
548
  Map_merge_into_self(other_map, _other);
599
549
  _other = other_map;
600
550
  }
@@ -605,36 +555,27 @@ VALUE Map_eq(VALUE _self, VALUE _other) {
605
555
  return Qtrue;
606
556
  }
607
557
  if (self->key_type != other->key_type ||
608
- self->value_type != other->value_type ||
558
+ self->value_type_info.type != other->value_type_info.type ||
609
559
  self->value_type_class != other->value_type_class) {
610
560
  return Qfalse;
611
561
  }
612
- if (upb_strtable_count(&self->table) != upb_strtable_count(&other->table)) {
562
+ if (upb_map_size(self->map) != upb_map_size(other->map)) {
613
563
  return Qfalse;
614
564
  }
615
565
 
616
566
  // For each member of self, check that an equal member exists at the same key
617
567
  // in other.
618
- for (upb_strtable_begin(&it, &self->table);
619
- !upb_strtable_done(&it);
620
- upb_strtable_next(&it)) {
621
-
622
- upb_value v = upb_strtable_iter_value(&it);
623
- void* mem = value_memory(&v);
624
- upb_value other_v;
625
- void* other_mem = value_memory(&other_v);
626
-
627
- if (!upb_strtable_lookup2(&other->table,
628
- upb_strtable_iter_key(&it),
629
- upb_strtable_iter_keylength(&it),
630
- &other_v)) {
568
+ size_t iter = UPB_MAP_BEGIN;
569
+ while (upb_mapiter_next(self->map, &iter)) {
570
+ upb_msgval key = upb_mapiter_key(self->map, iter);
571
+ upb_msgval val = upb_mapiter_value(self->map, iter);
572
+ upb_msgval other_val;
573
+ if (!upb_map_get(other->map, key, &other_val)) {
631
574
  // Not present in other map.
632
575
  return Qfalse;
633
576
  }
634
-
635
- if (!native_slot_eq(self->value_type, self->value_type_class, mem,
636
- other_mem)) {
637
- // Present, but value not equal.
577
+ if (!Msgval_IsEqual(val, other_val, self->value_type_info)) {
578
+ // Present but different value.
638
579
  return Qfalse;
639
580
  }
640
581
  }
@@ -642,6 +583,22 @@ VALUE Map_eq(VALUE _self, VALUE _other) {
642
583
  return Qtrue;
643
584
  }
644
585
 
586
+ /*
587
+ * call-seq:
588
+ * Message.freeze => self
589
+ *
590
+ * Freezes the message object. We have to intercept this so we can pin the
591
+ * Ruby object into memory so we don't forget it's frozen.
592
+ */
593
+ static VALUE Map_freeze(VALUE _self) {
594
+ Map* self = ruby_to_Map(_self);
595
+ if (!RB_OBJ_FROZEN(_self)) {
596
+ Arena_Pin(self->arena, _self);
597
+ RB_OBJ_FREEZE(_self);
598
+ }
599
+ return _self;
600
+ }
601
+
645
602
  /*
646
603
  * call-seq:
647
604
  * Map.hash => hash_value
@@ -650,28 +607,18 @@ VALUE Map_eq(VALUE _self, VALUE _other) {
650
607
  */
651
608
  VALUE Map_hash(VALUE _self) {
652
609
  Map* self = ruby_to_Map(_self);
653
-
654
- st_index_t h = rb_hash_start(0);
655
- VALUE hash_sym = rb_intern("hash");
656
-
657
- upb_strtable_iter it;
658
- for (upb_strtable_begin(&it, &self->table);
659
- !upb_strtable_done(&it);
660
- upb_strtable_next(&it)) {
661
- VALUE key = table_key_to_ruby(
662
- self, upb_strtable_iter_key(&it), upb_strtable_iter_keylength(&it));
663
-
664
- upb_value v = upb_strtable_iter_value(&it);
665
- void* mem = value_memory(&v);
666
- VALUE value = native_slot_get(self->value_type,
667
- self->value_type_class,
668
- mem);
669
-
670
- h = rb_hash_uint(h, NUM2LONG(rb_funcall(key, hash_sym, 0)));
671
- h = rb_hash_uint(h, NUM2LONG(rb_funcall(value, hash_sym, 0)));
610
+ uint64_t hash = 0;
611
+
612
+ size_t iter = UPB_MAP_BEGIN;
613
+ TypeInfo key_info = {self->key_type};
614
+ while (upb_mapiter_next(self->map, &iter)) {
615
+ upb_msgval key = upb_mapiter_key(self->map, iter);
616
+ upb_msgval val = upb_mapiter_value(self->map, iter);
617
+ hash = Msgval_GetHash(key, key_info, hash);
618
+ hash = Msgval_GetHash(val, self->value_type_info, hash);
672
619
  }
673
620
 
674
- return INT2FIX(h);
621
+ return LL2NUM(hash);
675
622
  }
676
623
 
677
624
  /*
@@ -682,25 +629,7 @@ VALUE Map_hash(VALUE _self) {
682
629
  */
683
630
  VALUE Map_to_h(VALUE _self) {
684
631
  Map* self = ruby_to_Map(_self);
685
- VALUE hash = rb_hash_new();
686
- upb_strtable_iter it;
687
- for (upb_strtable_begin(&it, &self->table);
688
- !upb_strtable_done(&it);
689
- upb_strtable_next(&it)) {
690
- VALUE key = table_key_to_ruby(
691
- self, upb_strtable_iter_key(&it), upb_strtable_iter_keylength(&it));
692
- upb_value v = upb_strtable_iter_value(&it);
693
- void* mem = value_memory(&v);
694
- VALUE value = native_slot_get(self->value_type,
695
- self->value_type_class,
696
- mem);
697
-
698
- if (self->value_type == UPB_TYPE_MESSAGE) {
699
- value = Message_to_h(value);
700
- }
701
- rb_hash_aset(hash, key, value);
702
- }
703
- return hash;
632
+ return Map_CreateHash(self->map, self->key_type, self->value_type_info);
704
633
  }
705
634
 
706
635
  /*
@@ -714,36 +643,11 @@ VALUE Map_to_h(VALUE _self) {
714
643
  VALUE Map_inspect(VALUE _self) {
715
644
  Map* self = ruby_to_Map(_self);
716
645
 
717
- VALUE str = rb_str_new2("{");
718
-
719
- bool first = true;
720
- VALUE inspect_sym = rb_intern("inspect");
721
-
722
- upb_strtable_iter it;
723
- for (upb_strtable_begin(&it, &self->table);
724
- !upb_strtable_done(&it);
725
- upb_strtable_next(&it)) {
726
- VALUE key = table_key_to_ruby(
727
- self, upb_strtable_iter_key(&it), upb_strtable_iter_keylength(&it));
728
-
729
- upb_value v = upb_strtable_iter_value(&it);
730
- void* mem = value_memory(&v);
731
- VALUE value = native_slot_get(self->value_type,
732
- self->value_type_class,
733
- mem);
734
-
735
- if (!first) {
736
- str = rb_str_cat2(str, ", ");
737
- } else {
738
- first = false;
739
- }
740
- str = rb_str_append(str, rb_funcall(key, inspect_sym, 0));
741
- str = rb_str_cat2(str, "=>");
742
- str = rb_str_append(str, rb_funcall(value, inspect_sym, 0));
743
- }
744
-
745
- str = rb_str_cat2(str, "}");
746
- return str;
646
+ StringBuilder* builder = StringBuilder_New();
647
+ Map_Inspect(builder, self->map, self->key_type, self->value_type_info);
648
+ VALUE ret = StringBuilder_ToRubyString(builder);
649
+ StringBuilder_Free(builder);
650
+ return ret;
747
651
  }
748
652
 
749
653
  /*
@@ -755,87 +659,11 @@ VALUE Map_inspect(VALUE _self) {
755
659
  * in the new copy of this map. Returns the new copy of this map with merged
756
660
  * contents.
757
661
  */
758
- VALUE Map_merge(VALUE _self, VALUE hashmap) {
662
+ static VALUE Map_merge(VALUE _self, VALUE hashmap) {
759
663
  VALUE dupped = Map_dup(_self);
760
664
  return Map_merge_into_self(dupped, hashmap);
761
665
  }
762
666
 
763
- static int merge_into_self_callback(VALUE key, VALUE value, VALUE self) {
764
- Map_index_set(self, key, value);
765
- return ST_CONTINUE;
766
- }
767
-
768
- // Used only internally -- shared by #merge and #initialize.
769
- VALUE Map_merge_into_self(VALUE _self, VALUE hashmap) {
770
- if (TYPE(hashmap) == T_HASH) {
771
- rb_hash_foreach(hashmap, merge_into_self_callback, _self);
772
- } else if (RB_TYPE_P(hashmap, T_DATA) && RTYPEDDATA_P(hashmap) &&
773
- RTYPEDDATA_TYPE(hashmap) == &Map_type) {
774
-
775
- Map* self = ruby_to_Map(_self);
776
- Map* other = ruby_to_Map(hashmap);
777
- upb_strtable_iter it;
778
-
779
- if (self->key_type != other->key_type ||
780
- self->value_type != other->value_type ||
781
- self->value_type_class != other->value_type_class) {
782
- rb_raise(rb_eArgError, "Attempt to merge Map with mismatching types");
783
- }
784
-
785
- for (upb_strtable_begin(&it, &other->table);
786
- !upb_strtable_done(&it);
787
- upb_strtable_next(&it)) {
788
-
789
- // Replace any existing value by issuing a 'remove' operation first.
790
- upb_value v;
791
- upb_value oldv;
792
- upb_strtable_remove2(&self->table,
793
- upb_strtable_iter_key(&it),
794
- upb_strtable_iter_keylength(&it),
795
- &oldv);
796
-
797
- v = upb_strtable_iter_value(&it);
798
- upb_strtable_insert2(&self->table,
799
- upb_strtable_iter_key(&it),
800
- upb_strtable_iter_keylength(&it),
801
- v);
802
- }
803
- } else {
804
- rb_raise(rb_eArgError, "Unknown type merging into Map");
805
- }
806
- return _self;
807
- }
808
-
809
- // Internal method: map iterator initialization (used for serialization).
810
- void Map_begin(VALUE _self, Map_iter* iter) {
811
- Map* self = ruby_to_Map(_self);
812
- iter->self = self;
813
- upb_strtable_begin(&iter->it, &self->table);
814
- }
815
-
816
- void Map_next(Map_iter* iter) {
817
- upb_strtable_next(&iter->it);
818
- }
819
-
820
- bool Map_done(Map_iter* iter) {
821
- return upb_strtable_done(&iter->it);
822
- }
823
-
824
- VALUE Map_iter_key(Map_iter* iter) {
825
- return table_key_to_ruby(
826
- iter->self,
827
- upb_strtable_iter_key(&iter->it),
828
- upb_strtable_iter_keylength(&iter->it));
829
- }
830
-
831
- VALUE Map_iter_value(Map_iter* iter) {
832
- upb_value v = upb_strtable_iter_value(&iter->it);
833
- void* mem = value_memory(&v);
834
- return native_slot_get(iter->self->value_type,
835
- iter->self->value_type_class,
836
- mem);
837
- }
838
-
839
667
  void Map_register(VALUE module) {
840
668
  VALUE klass = rb_define_class_under(module, "Map", rb_cObject);
841
669
  rb_define_alloc_func(klass, Map_alloc);
@@ -852,8 +680,12 @@ void Map_register(VALUE module) {
852
680
  rb_define_method(klass, "delete", Map_delete, 1);
853
681
  rb_define_method(klass, "clear", Map_clear, 0);
854
682
  rb_define_method(klass, "length", Map_length, 0);
683
+ rb_define_method(klass, "size", Map_length, 0);
855
684
  rb_define_method(klass, "dup", Map_dup, 0);
685
+ // Also define #clone so that we don't inherit Object#clone.
686
+ rb_define_method(klass, "clone", Map_dup, 0);
856
687
  rb_define_method(klass, "==", Map_eq, 1);
688
+ rb_define_method(klass, "freeze", Map_freeze, 0);
857
689
  rb_define_method(klass, "hash", Map_hash, 0);
858
690
  rb_define_method(klass, "to_h", Map_to_h, 0);
859
691
  rb_define_method(klass, "inspect", Map_inspect, 0);