• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2014 Google Inc.  All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file or at
6 // https://developers.google.com/open-source/licenses/bsd
7 
8 #include "convert.h"
9 #include "defs.h"
10 #include "message.h"
11 #include "protobuf.h"
12 
13 // -----------------------------------------------------------------------------
14 // Basic map operations on top of upb_Map.
15 //
16 // Note that we roll our own `Map` container here because, as for
17 // `RepeatedField`, we want a strongly-typed container. This is so that any user
18 // errors due to incorrect map key or value types are raised as close as
19 // possible to the error site, rather than at some deferred point (e.g.,
20 // serialization).
21 // -----------------------------------------------------------------------------
22 
23 // -----------------------------------------------------------------------------
24 // Map container type.
25 // -----------------------------------------------------------------------------
26 
27 typedef struct {
28   const upb_Map* map;  // Can convert to mutable when non-frozen.
29   upb_CType key_type;
30   TypeInfo value_type_info;
31   VALUE value_type_class;
32   VALUE arena;
33 } Map;
34 
Map_mark(void * _self)35 static void Map_mark(void* _self) {
36   Map* self = _self;
37   rb_gc_mark(self->value_type_class);
38   rb_gc_mark(self->arena);
39 }
40 
Map_memsize(const void * _self)41 static size_t Map_memsize(const void* _self) { return sizeof(Map); }
42 
43 const rb_data_type_t Map_type = {
44     "Google::Protobuf::Map",
45     {Map_mark, RUBY_DEFAULT_FREE, Map_memsize},
46     .flags = RUBY_TYPED_FREE_IMMEDIATELY,
47 };
48 
49 VALUE cMap;
50 
ruby_to_Map(VALUE _self)51 static Map* ruby_to_Map(VALUE _self) {
52   Map* self;
53   TypedData_Get_Struct(_self, Map, &Map_type, self);
54   return self;
55 }
56 
Map_alloc(VALUE klass)57 static VALUE Map_alloc(VALUE klass) {
58   Map* self = ALLOC(Map);
59   self->map = NULL;
60   self->value_type_class = Qnil;
61   self->value_type_info.def.msgdef = NULL;
62   self->arena = Qnil;
63   return TypedData_Wrap_Struct(klass, &Map_type, self);
64 }
65 
Map_GetRubyWrapper(const upb_Map * map,upb_CType key_type,TypeInfo value_type,VALUE arena)66 VALUE Map_GetRubyWrapper(const upb_Map* map, upb_CType key_type,
67                          TypeInfo value_type, VALUE arena) {
68   PBRUBY_ASSERT(map);
69   PBRUBY_ASSERT(arena != Qnil);
70 
71   VALUE val = ObjectCache_Get(map);
72 
73   if (val == Qnil) {
74     val = Map_alloc(cMap);
75     Map* self;
76     TypedData_Get_Struct(val, Map, &Map_type, self);
77     self->map = map;
78     self->arena = arena;
79     self->key_type = key_type;
80     self->value_type_info = value_type;
81     if (self->value_type_info.type == kUpb_CType_Message) {
82       const upb_MessageDef* val_m = self->value_type_info.def.msgdef;
83       self->value_type_class = Descriptor_DefToClass(val_m);
84     }
85     return ObjectCache_TryAdd(map, val);
86   }
87   return val;
88 }
89 
Map_new_this_type(Map * from)90 static VALUE Map_new_this_type(Map* from) {
91   VALUE arena_rb = Arena_new();
92   upb_Map* map = upb_Map_New(Arena_get(arena_rb), from->key_type,
93                              from->value_type_info.type);
94   VALUE ret =
95       Map_GetRubyWrapper(map, from->key_type, from->value_type_info, arena_rb);
96   PBRUBY_ASSERT(ruby_to_Map(ret)->value_type_class == from->value_type_class);
97   return ret;
98 }
99 
Map_keyinfo(Map * self)100 static TypeInfo Map_keyinfo(Map* self) {
101   TypeInfo ret;
102   ret.type = self->key_type;
103   ret.def.msgdef = NULL;
104   return ret;
105 }
106 
Map_GetMutable(VALUE _self)107 static upb_Map* Map_GetMutable(VALUE _self) {
108   const upb_Map* map = ruby_to_Map(_self)->map;
109   Protobuf_CheckNotFrozen(_self, upb_Map_IsFrozen(map));
110   return (upb_Map*)map;
111 }
112 
Map_CreateHash(const upb_Map * map,upb_CType key_type,TypeInfo val_info)113 VALUE Map_CreateHash(const upb_Map* map, upb_CType key_type,
114                      TypeInfo val_info) {
115   VALUE hash = rb_hash_new();
116   TypeInfo key_info = TypeInfo_from_type(key_type);
117 
118   if (!map) return hash;
119 
120   size_t iter = kUpb_Map_Begin;
121   upb_MessageValue key, val;
122   while (upb_Map_Next(map, &key, &val, &iter)) {
123     VALUE key_val = Convert_UpbToRuby(key, key_info, Qnil);
124     VALUE val_val = Scalar_CreateHash(val, val_info);
125     rb_hash_aset(hash, key_val, val_val);
126   }
127 
128   return hash;
129 }
130 
Map_deep_copy(VALUE obj)131 VALUE Map_deep_copy(VALUE obj) {
132   Map* self = ruby_to_Map(obj);
133   VALUE new_arena_rb = Arena_new();
134   upb_Arena* arena = Arena_get(new_arena_rb);
135   upb_Map* new_map =
136       upb_Map_New(arena, self->key_type, self->value_type_info.type);
137   size_t iter = kUpb_Map_Begin;
138   upb_MessageValue key, val;
139   while (upb_Map_Next(self->map, &key, &val, &iter)) {
140     upb_MessageValue val_copy =
141         Msgval_DeepCopy(val, self->value_type_info, arena);
142     upb_Map_Set(new_map, key, val_copy, arena);
143   }
144 
145   return Map_GetRubyWrapper(new_map, self->key_type, self->value_type_info,
146                             new_arena_rb);
147 }
148 
Map_GetUpbMap(VALUE val,const upb_FieldDef * field,upb_Arena * arena)149 const upb_Map* Map_GetUpbMap(VALUE val, const upb_FieldDef* field,
150                              upb_Arena* arena) {
151   const upb_FieldDef* key_field = map_field_key(field);
152   const upb_FieldDef* value_field = map_field_value(field);
153   TypeInfo value_type_info = TypeInfo_get(value_field);
154   Map* self;
155 
156   if (!RB_TYPE_P(val, T_DATA) || !RTYPEDDATA_P(val) ||
157       RTYPEDDATA_TYPE(val) != &Map_type) {
158     rb_raise(cTypeError, "Expected Map instance");
159   }
160 
161   self = ruby_to_Map(val);
162   if (self->key_type != upb_FieldDef_CType(key_field)) {
163     rb_raise(cTypeError, "Map key type does not match field's key type");
164   }
165   if (self->value_type_info.type != value_type_info.type) {
166     rb_raise(cTypeError, "Map value type does not match field's value type");
167   }
168   if (self->value_type_info.def.msgdef != value_type_info.def.msgdef) {
169     rb_raise(cTypeError, "Map value type has wrong message/enum class");
170   }
171 
172   Arena_fuse(self->arena, arena);
173   return self->map;
174 }
175 
Map_Inspect(StringBuilder * b,const upb_Map * map,upb_CType key_type,TypeInfo val_type)176 void Map_Inspect(StringBuilder* b, const upb_Map* map, upb_CType key_type,
177                  TypeInfo val_type) {
178   bool first = true;
179   TypeInfo key_type_info = {key_type};
180   StringBuilder_Printf(b, "{");
181   if (map) {
182     size_t iter = kUpb_Map_Begin;
183     upb_MessageValue key, val;
184     while (upb_Map_Next(map, &key, &val, &iter)) {
185       if (first) {
186         first = false;
187       } else {
188         StringBuilder_Printf(b, ", ");
189       }
190       StringBuilder_PrintMsgval(b, key, key_type_info);
191       StringBuilder_Printf(b, "=>");
192       StringBuilder_PrintMsgval(b, val, val_type);
193     }
194   }
195   StringBuilder_Printf(b, "}");
196 }
197 
merge_into_self_callback(VALUE key,VALUE val,VALUE _self)198 static int merge_into_self_callback(VALUE key, VALUE val, VALUE _self) {
199   Map* self = ruby_to_Map(_self);
200   upb_Arena* arena = Arena_get(self->arena);
201   upb_MessageValue key_val =
202       Convert_RubyToUpb(key, "", Map_keyinfo(self), arena);
203   upb_MessageValue val_val =
204       Convert_RubyToUpb(val, "", self->value_type_info, arena);
205   upb_Map_Set(Map_GetMutable(_self), key_val, val_val, arena);
206   return ST_CONTINUE;
207 }
208 
209 // Used only internally -- shared by #merge and #initialize.
Map_merge_into_self(VALUE _self,VALUE hashmap)210 static VALUE Map_merge_into_self(VALUE _self, VALUE hashmap) {
211   if (TYPE(hashmap) == T_HASH) {
212     rb_hash_foreach(hashmap, merge_into_self_callback, _self);
213   } else if (RB_TYPE_P(hashmap, T_DATA) && RTYPEDDATA_P(hashmap) &&
214              RTYPEDDATA_TYPE(hashmap) == &Map_type) {
215     Map* self = ruby_to_Map(_self);
216     Map* other = ruby_to_Map(hashmap);
217     upb_Arena* arena = Arena_get(self->arena);
218     upb_Map* self_map = Map_GetMutable(_self);
219 
220     Arena_fuse(other->arena, arena);
221 
222     if (self->key_type != other->key_type ||
223         self->value_type_info.type != other->value_type_info.type ||
224         self->value_type_class != other->value_type_class) {
225       rb_raise(rb_eArgError, "Attempt to merge Map with mismatching types");
226     }
227 
228     size_t iter = kUpb_Map_Begin;
229     upb_MessageValue key, val;
230     while (upb_Map_Next(other->map, &key, &val, &iter)) {
231       upb_Map_Set(self_map, key, val, arena);
232     }
233   } else {
234     rb_raise(rb_eArgError, "Unknown type merging into Map");
235   }
236   return _self;
237 }
238 
239 /*
240  * call-seq:
241  *     Map.new(key_type, value_type, value_typeclass = nil, init_hashmap = {})
242  *     => new map
243  *
244  * Allocates a new Map container. This constructor may be called with 2, 3, or 4
245  * arguments. The first two arguments are always present and are symbols (taking
246  * on the same values as field-type symbols in message descriptors) that
247  * indicate the type of the map key and value fields.
248  *
249  * The supported key types are: :int32, :int64, :uint32, :uint64, :bool,
250  * :string, :bytes.
251  *
252  * The supported value types are: :int32, :int64, :uint32, :uint64, :bool,
253  * :string, :bytes, :enum, :message.
254  *
255  * The third argument, value_typeclass, must be present if value_type is :enum
256  * or :message. As in RepeatedField#new, this argument must be a message class
257  * (for :message) or enum module (for :enum).
258  *
259  * The last argument, if present, provides initial content for map. Note that
260  * this may be an ordinary Ruby hashmap or another Map instance with identical
261  * key and value types. Also note that this argument may be present whether or
262  * not value_typeclass is present (and it is unambiguously separate from
263  * value_typeclass because value_typeclass's presence is strictly determined by
264  * value_type). The contents of this initial hashmap or Map instance are
265  * shallow-copied into the new Map: the original map is unmodified, but
266  * references to underlying objects will be shared if the value type is a
267  * message type.
268  */
Map_init(int argc,VALUE * argv,VALUE _self)269 static VALUE Map_init(int argc, VALUE* argv, VALUE _self) {
270   Map* self = ruby_to_Map(_self);
271   VALUE init_arg;
272 
273   // We take either two args (:key_type, :value_type), three args (:key_type,
274   // :value_type, "ValueMessageType"), or four args (the above plus an initial
275   // hashmap).
276   if (argc < 2 || argc > 4) {
277     rb_raise(rb_eArgError, "Map constructor expects 2, 3 or 4 arguments.");
278   }
279 
280   self->key_type = ruby_to_fieldtype(argv[0]);
281   self->value_type_info =
282       TypeInfo_FromClass(argc, argv, 1, &self->value_type_class, &init_arg);
283   self->arena = Arena_new();
284 
285   // Check that the key type is an allowed type.
286   switch (self->key_type) {
287     case kUpb_CType_Int32:
288     case kUpb_CType_Int64:
289     case kUpb_CType_UInt32:
290     case kUpb_CType_UInt64:
291     case kUpb_CType_Bool:
292     case kUpb_CType_String:
293     case kUpb_CType_Bytes:
294       // These are OK.
295       break;
296     default:
297       rb_raise(rb_eArgError, "Invalid key type for map.");
298   }
299 
300   self->map = upb_Map_New(Arena_get(self->arena), self->key_type,
301                           self->value_type_info.type);
302   VALUE stored = ObjectCache_TryAdd(self->map, _self);
303   (void)stored;
304   PBRUBY_ASSERT(stored == _self);
305 
306   if (init_arg != Qnil) {
307     Map_merge_into_self(_self, init_arg);
308   }
309 
310   return Qnil;
311 }
312 
313 /*
314  * call-seq:
315  *     Map.each(&block)
316  *
317  * Invokes &block on each |key, value| pair in the map, in unspecified order.
318  * Note that Map also includes Enumerable; map thus acts like a normal Ruby
319  * sequence.
320  */
Map_each(VALUE _self)321 static VALUE Map_each(VALUE _self) {
322   Map* self = ruby_to_Map(_self);
323   size_t iter = kUpb_Map_Begin;
324   upb_MessageValue key, val;
325 
326   while (upb_Map_Next(self->map, &key, &val, &iter)) {
327     VALUE key_val = Convert_UpbToRuby(key, Map_keyinfo(self), self->arena);
328     VALUE val_val = Convert_UpbToRuby(val, self->value_type_info, self->arena);
329     rb_yield_values(2, key_val, val_val);
330   }
331 
332   return Qnil;
333 }
334 
335 /*
336  * call-seq:
337  *     Map.keys => [list_of_keys]
338  *
339  * Returns the list of keys contained in the map, in unspecified order.
340  */
Map_keys(VALUE _self)341 static VALUE Map_keys(VALUE _self) {
342   Map* self = ruby_to_Map(_self);
343   size_t iter = kUpb_Map_Begin;
344   VALUE ret = rb_ary_new();
345   upb_MessageValue key, val;
346 
347   while (upb_Map_Next(self->map, &key, &val, &iter)) {
348     VALUE key_val = Convert_UpbToRuby(key, Map_keyinfo(self), self->arena);
349     rb_ary_push(ret, key_val);
350   }
351 
352   return ret;
353 }
354 
355 /*
356  * call-seq:
357  *     Map.values => [list_of_values]
358  *
359  * Returns the list of values contained in the map, in unspecified order.
360  */
Map_values(VALUE _self)361 static VALUE Map_values(VALUE _self) {
362   Map* self = ruby_to_Map(_self);
363   size_t iter = kUpb_Map_Begin;
364   VALUE ret = rb_ary_new();
365   upb_MessageValue key, val;
366 
367   while (upb_Map_Next(self->map, &key, &val, &iter)) {
368     VALUE val_val = Convert_UpbToRuby(val, self->value_type_info, self->arena);
369     rb_ary_push(ret, val_val);
370   }
371 
372   return ret;
373 }
374 
375 /*
376  * call-seq:
377  *     Map.[](key) => value
378  *
379  * Accesses the element at the given key. Throws an exception if the key type is
380  * incorrect. Returns nil when the key is not present in the map.
381  */
Map_index(VALUE _self,VALUE key)382 static VALUE Map_index(VALUE _self, VALUE key) {
383   Map* self = ruby_to_Map(_self);
384   upb_MessageValue key_upb =
385       Convert_RubyToUpb(key, "", Map_keyinfo(self), NULL);
386   upb_MessageValue val;
387 
388   if (upb_Map_Get(self->map, key_upb, &val)) {
389     return Convert_UpbToRuby(val, self->value_type_info, self->arena);
390   } else {
391     return Qnil;
392   }
393 }
394 
395 /*
396  * call-seq:
397  *     Map.[]=(key, value) => value
398  *
399  * Inserts or overwrites the value at the given key with the given new value.
400  * Throws an exception if the key type is incorrect. Returns the new value that
401  * was just inserted.
402  */
Map_index_set(VALUE _self,VALUE key,VALUE val)403 static VALUE Map_index_set(VALUE _self, VALUE key, VALUE val) {
404   Map* self = ruby_to_Map(_self);
405   upb_Arena* arena = Arena_get(self->arena);
406   upb_MessageValue key_upb =
407       Convert_RubyToUpb(key, "", Map_keyinfo(self), NULL);
408   upb_MessageValue val_upb =
409       Convert_RubyToUpb(val, "", self->value_type_info, arena);
410 
411   upb_Map_Set(Map_GetMutable(_self), key_upb, val_upb, arena);
412 
413   return val;
414 }
415 
416 /*
417  * call-seq:
418  *     Map.has_key?(key) => bool
419  *
420  * Returns true if the given key is present in the map. Throws an exception if
421  * the key has the wrong type.
422  */
Map_has_key(VALUE _self,VALUE key)423 static VALUE Map_has_key(VALUE _self, VALUE key) {
424   Map* self = ruby_to_Map(_self);
425   upb_MessageValue key_upb =
426       Convert_RubyToUpb(key, "", Map_keyinfo(self), NULL);
427 
428   if (upb_Map_Get(self->map, key_upb, NULL)) {
429     return Qtrue;
430   } else {
431     return Qfalse;
432   }
433 }
434 
435 /*
436  * call-seq:
437  *     Map.delete(key) => old_value
438  *
439  * Deletes the value at the given key, if any, returning either the old value or
440  * nil if none was present. Throws an exception if the key is of the wrong type.
441  */
Map_delete(VALUE _self,VALUE key)442 static VALUE Map_delete(VALUE _self, VALUE key) {
443   upb_Map* map = Map_GetMutable(_self);
444   Map* self = ruby_to_Map(_self);
445 
446   upb_MessageValue key_upb =
447       Convert_RubyToUpb(key, "", Map_keyinfo(self), NULL);
448   upb_MessageValue val_upb;
449 
450   if (upb_Map_Delete(map, key_upb, &val_upb)) {
451     return Convert_UpbToRuby(val_upb, self->value_type_info, self->arena);
452   } else {
453     return Qnil;
454   }
455 }
456 
457 /*
458  * call-seq:
459  *     Map.clear
460  *
461  * Removes all entries from the map.
462  */
Map_clear(VALUE _self)463 static VALUE Map_clear(VALUE _self) {
464   upb_Map_Clear(Map_GetMutable(_self));
465   return Qnil;
466 }
467 
468 /*
469  * call-seq:
470  *     Map.length
471  *
472  * Returns the number of entries (key-value pairs) in the map.
473  */
Map_length(VALUE _self)474 static VALUE Map_length(VALUE _self) {
475   Map* self = ruby_to_Map(_self);
476   return ULL2NUM(upb_Map_Size(self->map));
477 }
478 
479 /*
480  * call-seq:
481  *     Map.dup => new_map
482  *
483  * Duplicates this map with a shallow copy. References to all non-primitive
484  * element objects (e.g., submessages) are shared.
485  */
Map_dup(VALUE _self)486 static VALUE Map_dup(VALUE _self) {
487   Map* self = ruby_to_Map(_self);
488   VALUE new_map_rb = Map_new_this_type(self);
489   Map* new_self = ruby_to_Map(new_map_rb);
490   size_t iter = kUpb_Map_Begin;
491   upb_Arena* arena = Arena_get(new_self->arena);
492   upb_Map* new_map = Map_GetMutable(new_map_rb);
493 
494   Arena_fuse(self->arena, arena);
495 
496   upb_MessageValue key, val;
497   while (upb_Map_Next(self->map, &key, &val, &iter)) {
498     upb_Map_Set(new_map, key, val, arena);
499   }
500 
501   return new_map_rb;
502 }
503 
504 /*
505  * call-seq:
506  *     Map.==(other) => boolean
507  *
508  * Compares this map to another. Maps are equal if they have identical key sets,
509  * and for each key, the values in both maps compare equal. Elements are
510  * compared as per normal Ruby semantics, by calling their :== methods (or
511  * performing a more efficient comparison for primitive types).
512  *
513  * Maps with dissimilar key types or value types/typeclasses are never equal,
514  * even if value comparison (for example, between integers and floats) would
515  * have otherwise indicated that every element has equal value.
516  */
Map_eq(VALUE _self,VALUE _other)517 VALUE Map_eq(VALUE _self, VALUE _other) {
518   Map* self = ruby_to_Map(_self);
519   Map* other;
520 
521   // Allow comparisons to Ruby hashmaps by converting to a temporary Map
522   // instance. Slow, but workable.
523   if (TYPE(_other) == T_HASH) {
524     VALUE other_map = Map_new_this_type(self);
525     Map_merge_into_self(other_map, _other);
526     _other = other_map;
527   }
528 
529   other = ruby_to_Map(_other);
530 
531   if (self == other) {
532     return Qtrue;
533   }
534   if (self->key_type != other->key_type ||
535       self->value_type_info.type != other->value_type_info.type ||
536       self->value_type_class != other->value_type_class) {
537     return Qfalse;
538   }
539   if (upb_Map_Size(self->map) != upb_Map_Size(other->map)) {
540     return Qfalse;
541   }
542 
543   // For each member of self, check that an equal member exists at the same key
544   // in other.
545   size_t iter = kUpb_Map_Begin;
546   upb_MessageValue key, val;
547   while (upb_Map_Next(self->map, &key, &val, &iter)) {
548     upb_MessageValue other_val;
549     if (!upb_Map_Get(other->map, key, &other_val)) {
550       // Not present in other map.
551       return Qfalse;
552     }
553     if (!Msgval_IsEqual(val, other_val, self->value_type_info)) {
554       // Present but different value.
555       return Qfalse;
556     }
557   }
558 
559   return Qtrue;
560 }
561 
562 /*
563  * call-seq:
564  *     Map.frozen? => bool
565  *
566  * Returns true if the map is frozen in either Ruby or the underlying
567  * representation. Freezes the Ruby map object if it is not already frozen in
568  * Ruby but it is frozen in the underlying representation.
569  */
Map_frozen(VALUE _self)570 VALUE Map_frozen(VALUE _self) {
571   Map* self = ruby_to_Map(_self);
572   if (!upb_Map_IsFrozen(self->map)) {
573     PBRUBY_ASSERT(!RB_OBJ_FROZEN(_self));
574     return Qfalse;
575   }
576 
577   // Lazily freeze the Ruby wrapper.
578   if (!RB_OBJ_FROZEN(_self)) RB_OBJ_FREEZE(_self);
579   return Qtrue;
580 }
581 
582 /*
583  * call-seq:
584  *     Map.freeze => self
585  *
586  * Freezes the map object. We have to intercept this so we can freeze the
587  * underlying representation, not just the Ruby wrapper.
588  */
Map_freeze(VALUE _self)589 VALUE Map_freeze(VALUE _self) {
590   Map* self = ruby_to_Map(_self);
591   if (RB_OBJ_FROZEN(_self)) {
592     PBRUBY_ASSERT(upb_Map_IsFrozen(self->map));
593     return _self;
594   }
595 
596   if (!upb_Map_IsFrozen(self->map)) {
597     if (self->value_type_info.type == kUpb_CType_Message) {
598       upb_Map_Freeze(
599           Map_GetMutable(_self),
600           upb_MessageDef_MiniTable(self->value_type_info.def.msgdef));
601     } else {
602       upb_Map_Freeze(Map_GetMutable(_self), NULL);
603     }
604   }
605 
606   RB_OBJ_FREEZE(_self);
607 
608   return _self;
609 }
610 
Map_EmptyFrozen(const upb_FieldDef * f)611 VALUE Map_EmptyFrozen(const upb_FieldDef* f) {
612   PBRUBY_ASSERT(upb_FieldDef_IsMap(f));
613   VALUE val = ObjectCache_Get(f);
614 
615   if (val == Qnil) {
616     const upb_FieldDef* key_f = map_field_key(f);
617     const upb_FieldDef* val_f = map_field_value(f);
618     upb_CType key_type = upb_FieldDef_CType(key_f);
619     TypeInfo value_type_info = TypeInfo_get(val_f);
620     val = Map_alloc(cMap);
621     Map* self;
622     TypedData_Get_Struct(val, Map, &Map_type, self);
623     self->arena = Arena_new();
624     self->map =
625         upb_Map_New(Arena_get(self->arena), key_type, value_type_info.type);
626     self->key_type = key_type;
627     self->value_type_info = value_type_info;
628     if (self->value_type_info.type == kUpb_CType_Message) {
629       const upb_MessageDef* val_m = value_type_info.def.msgdef;
630       self->value_type_class = Descriptor_DefToClass(val_m);
631     }
632     return ObjectCache_TryAdd(f, Map_freeze(val));
633   }
634   PBRUBY_ASSERT(RB_OBJ_FROZEN(val));
635   PBRUBY_ASSERT(upb_Map_IsFrozen(ruby_to_Map(val)->map));
636   return val;
637 }
638 
639 /*
640  * call-seq:
641  *     Map.hash => hash_value
642  *
643  * Returns a hash value based on this map's contents.
644  */
Map_hash(VALUE _self)645 VALUE Map_hash(VALUE _self) {
646   Map* self = ruby_to_Map(_self);
647   uint64_t hash = 0;
648 
649   size_t iter = kUpb_Map_Begin;
650   TypeInfo key_info = {self->key_type};
651   upb_MessageValue key, val;
652   while (upb_Map_Next(self->map, &key, &val, &iter)) {
653     hash = Msgval_GetHash(key, key_info, hash);
654     hash = Msgval_GetHash(val, self->value_type_info, hash);
655   }
656 
657   return LL2NUM(hash);
658 }
659 
660 /*
661  * call-seq:
662  *     Map.to_h => {}
663  *
664  * Returns a Ruby Hash object containing all the values within the map
665  */
Map_to_h(VALUE _self)666 VALUE Map_to_h(VALUE _self) {
667   Map* self = ruby_to_Map(_self);
668   return Map_CreateHash(self->map, self->key_type, self->value_type_info);
669 }
670 
671 /*
672  * call-seq:
673  *     Map.inspect => string
674  *
675  * Returns a string representing this map's elements. It will be formatted as
676  * "{key => value, key => value, ...}", with each key and value string
677  * representation computed by its own #inspect method.
678  */
Map_inspect(VALUE _self)679 VALUE Map_inspect(VALUE _self) {
680   Map* self = ruby_to_Map(_self);
681 
682   StringBuilder* builder = StringBuilder_New();
683   Map_Inspect(builder, self->map, self->key_type, self->value_type_info);
684   VALUE ret = StringBuilder_ToRubyString(builder);
685   StringBuilder_Free(builder);
686   return ret;
687 }
688 
689 /*
690  * call-seq:
691  *     Map.merge(other_map) => map
692  *
693  * Copies key/value pairs from other_map into a copy of this map. If a key is
694  * set in other_map and this map, the value from other_map overwrites the value
695  * in the new copy of this map. Returns the new copy of this map with merged
696  * contents.
697  */
Map_merge(VALUE _self,VALUE hashmap)698 static VALUE Map_merge(VALUE _self, VALUE hashmap) {
699   VALUE dupped = Map_dup(_self);
700   return Map_merge_into_self(dupped, hashmap);
701 }
702 
Map_register(VALUE module)703 void Map_register(VALUE module) {
704   VALUE klass = rb_define_class_under(module, "Map", rb_cObject);
705   rb_define_alloc_func(klass, Map_alloc);
706   rb_gc_register_address(&cMap);
707   cMap = klass;
708 
709   rb_define_method(klass, "initialize", Map_init, -1);
710   rb_define_method(klass, "each", Map_each, 0);
711   rb_define_method(klass, "keys", Map_keys, 0);
712   rb_define_method(klass, "values", Map_values, 0);
713   rb_define_method(klass, "[]", Map_index, 1);
714   rb_define_method(klass, "[]=", Map_index_set, 2);
715   rb_define_method(klass, "has_key?", Map_has_key, 1);
716   rb_define_method(klass, "delete", Map_delete, 1);
717   rb_define_method(klass, "clear", Map_clear, 0);
718   rb_define_method(klass, "length", Map_length, 0);
719   rb_define_method(klass, "size", Map_length, 0);
720   rb_define_method(klass, "dup", Map_dup, 0);
721   // Also define #clone so that we don't inherit Object#clone.
722   rb_define_method(klass, "clone", Map_dup, 0);
723   rb_define_method(klass, "==", Map_eq, 1);
724   rb_define_method(klass, "freeze", Map_freeze, 0);
725   rb_define_method(klass, "frozen?", Map_frozen, 0);
726   rb_define_method(klass, "hash", Map_hash, 0);
727   rb_define_method(klass, "to_h", Map_to_h, 0);
728   rb_define_method(klass, "inspect", Map_inspect, 0);
729   rb_define_method(klass, "merge", Map_merge, 1);
730   rb_include_module(klass, rb_mEnumerable);
731 }
732