google-protobuf 3.0.0 → 3.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

Files changed (46) 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 +760 -1243
  5. data/ext/google/protobuf_c/defs.h +107 -0
  6. data/ext/google/protobuf_c/extconf.rb +22 -4
  7. data/ext/google/protobuf_c/map.c +342 -450
  8. data/ext/google/protobuf_c/map.h +66 -0
  9. data/ext/google/protobuf_c/message.c +1108 -284
  10. data/ext/google/protobuf_c/message.h +104 -0
  11. data/ext/google/protobuf_c/protobuf.c +416 -51
  12. data/ext/google/protobuf_c/protobuf.h +53 -472
  13. data/ext/google/protobuf_c/repeated_field.c +318 -317
  14. data/ext/google/protobuf_c/repeated_field.h +63 -0
  15. data/ext/google/protobuf_c/ruby-upb.c +11115 -0
  16. data/ext/google/protobuf_c/ruby-upb.h +5612 -0
  17. data/ext/google/protobuf_c/third_party/utf8_range/LICENSE +21 -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 +9 -0
  22. data/ext/google/protobuf_c/wrap_memcpy.c +52 -0
  23. data/lib/google/protobuf/any_pb.rb +6 -4
  24. data/lib/google/protobuf/api_pb.rb +27 -24
  25. data/lib/google/protobuf/descriptor_dsl.rb +465 -0
  26. data/lib/google/protobuf/descriptor_pb.rb +269 -0
  27. data/lib/google/protobuf/duration_pb.rb +6 -4
  28. data/lib/google/protobuf/empty_pb.rb +4 -2
  29. data/lib/google/protobuf/field_mask_pb.rb +5 -3
  30. data/lib/google/protobuf/message_exts.rb +4 -4
  31. data/lib/google/protobuf/repeated_field.rb +4 -4
  32. data/lib/google/protobuf/source_context_pb.rb +5 -3
  33. data/lib/google/protobuf/struct_pb.rb +23 -21
  34. data/lib/google/protobuf/timestamp_pb.rb +6 -4
  35. data/lib/google/protobuf/type_pb.rb +77 -74
  36. data/lib/google/protobuf/well_known_types.rb +240 -0
  37. data/lib/google/protobuf/wrappers_pb.rb +37 -35
  38. data/lib/google/protobuf.rb +12 -9
  39. data/tests/basic.rb +489 -1001
  40. data/tests/generated_code_test.rb +6 -2
  41. data/tests/stress.rb +1 -1
  42. metadata +39 -34
  43. data/ext/google/protobuf_c/encode_decode.c +0 -1264
  44. data/ext/google/protobuf_c/storage.c +0 -893
  45. data/ext/google/protobuf_c/upb.c +0 -12812
  46. data/ext/google/protobuf_c/upb.h +0 -8569
@@ -28,160 +28,236 @@
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
+ size_t iter = kUpb_Map_Begin;
137
+ TypeInfo key_info = TypeInfo_from_type(key_type);
136
138
 
137
- VALUE cMap;
139
+ if (!map) return hash;
138
140
 
139
- Map* ruby_to_Map(VALUE _self) {
140
- Map* self;
141
- TypedData_Get_Struct(_self, Map, &Map_type, self);
142
- return self;
141
+ while (upb_MapIterator_Next(map, &iter)) {
142
+ upb_MessageValue key = upb_MapIterator_Key(map, iter);
143
+ upb_MessageValue val = upb_MapIterator_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 = kUpb_Map_Begin;
159
+ while (upb_MapIterator_Next(self->map, &iter)) {
160
+ upb_MessageValue key = upb_MapIterator_Key(self->map, iter);
161
+ upb_MessageValue val = upb_MapIterator_Value(self->map, iter);
162
+ upb_MessageValue val_copy =
163
+ Msgval_DeepCopy(val, self->value_type_info, arena);
164
+ upb_Map_Set(new_map, key, val_copy, arena);
165
+ }
166
+
167
+ return Map_GetRubyWrapper(new_map, self->key_type, self->value_type_info,
168
+ new_arena_rb);
143
169
  }
144
170
 
145
- void Map_mark(void* _self) {
146
- Map* self = _self;
171
+ const upb_Map* Map_GetUpbMap(VALUE val, const upb_FieldDef* field,
172
+ upb_Arena* arena) {
173
+ const upb_FieldDef* key_field = map_field_key(field);
174
+ const upb_FieldDef* value_field = map_field_value(field);
175
+ TypeInfo value_type_info = TypeInfo_get(value_field);
176
+ Map* self;
147
177
 
148
- rb_gc_mark(self->value_type_class);
178
+ if (!RB_TYPE_P(val, T_DATA) || !RTYPEDDATA_P(val) ||
179
+ RTYPEDDATA_TYPE(val) != &Map_type) {
180
+ rb_raise(cTypeError, "Expected Map instance");
181
+ }
149
182
 
150
- if (self->value_type == UPB_TYPE_STRING ||
151
- self->value_type == UPB_TYPE_BYTES ||
152
- self->value_type == UPB_TYPE_MESSAGE) {
153
- upb_strtable_iter it;
154
- for (upb_strtable_begin(&it, &self->table);
155
- !upb_strtable_done(&it);
156
- upb_strtable_next(&it)) {
157
- upb_value v = upb_strtable_iter_value(&it);
158
- void* mem = value_memory(&v);
159
- native_slot_mark(self->value_type, mem);
160
- }
183
+ self = ruby_to_Map(val);
184
+ if (self->key_type != upb_FieldDef_CType(key_field)) {
185
+ rb_raise(cTypeError, "Map key type does not match field's key type");
161
186
  }
187
+ if (self->value_type_info.type != value_type_info.type) {
188
+ rb_raise(cTypeError, "Map value type does not match field's value type");
189
+ }
190
+ if (self->value_type_info.def.msgdef != value_type_info.def.msgdef) {
191
+ rb_raise(cTypeError, "Map value type has wrong message/enum class");
192
+ }
193
+
194
+ Arena_fuse(self->arena, arena);
195
+ return self->map;
162
196
  }
163
197
 
164
- void Map_free(void* _self) {
165
- Map* self = _self;
166
- upb_strtable_uninit(&self->table);
167
- xfree(self);
198
+ void Map_Inspect(StringBuilder* b, const upb_Map* map, upb_CType key_type,
199
+ TypeInfo val_type) {
200
+ bool first = true;
201
+ TypeInfo key_type_info = {key_type};
202
+ StringBuilder_Printf(b, "{");
203
+ if (map) {
204
+ size_t iter = kUpb_Map_Begin;
205
+ while (upb_MapIterator_Next(map, &iter)) {
206
+ upb_MessageValue key = upb_MapIterator_Key(map, iter);
207
+ upb_MessageValue val = upb_MapIterator_Value(map, iter);
208
+ if (first) {
209
+ first = false;
210
+ } else {
211
+ StringBuilder_Printf(b, ", ");
212
+ }
213
+ StringBuilder_PrintMsgval(b, key, key_type_info);
214
+ StringBuilder_Printf(b, "=>");
215
+ StringBuilder_PrintMsgval(b, val, val_type);
216
+ }
217
+ }
218
+ StringBuilder_Printf(b, "}");
168
219
  }
169
220
 
170
- VALUE Map_alloc(VALUE klass) {
171
- Map* self = ALLOC(Map);
172
- memset(self, 0, sizeof(Map));
173
- self->value_type_class = Qnil;
174
- return TypedData_Wrap_Struct(klass, &Map_type, self);
221
+ static int merge_into_self_callback(VALUE key, VALUE val, VALUE _self) {
222
+ Map* self = ruby_to_Map(_self);
223
+ upb_Arena* arena = Arena_get(self->arena);
224
+ upb_MessageValue key_val =
225
+ Convert_RubyToUpb(key, "", Map_keyinfo(self), arena);
226
+ upb_MessageValue val_val =
227
+ Convert_RubyToUpb(val, "", self->value_type_info, arena);
228
+ upb_Map_Set(Map_GetMutable(_self), key_val, val_val, arena);
229
+ return ST_CONTINUE;
175
230
  }
176
231
 
177
- static bool needs_typeclass(upb_fieldtype_t type) {
178
- switch (type) {
179
- case UPB_TYPE_MESSAGE:
180
- case UPB_TYPE_ENUM:
181
- return true;
182
- default:
183
- return false;
232
+ // Used only internally -- shared by #merge and #initialize.
233
+ static VALUE Map_merge_into_self(VALUE _self, VALUE hashmap) {
234
+ if (TYPE(hashmap) == T_HASH) {
235
+ rb_hash_foreach(hashmap, merge_into_self_callback, _self);
236
+ } else if (RB_TYPE_P(hashmap, T_DATA) && RTYPEDDATA_P(hashmap) &&
237
+ RTYPEDDATA_TYPE(hashmap) == &Map_type) {
238
+ Map* self = ruby_to_Map(_self);
239
+ Map* other = ruby_to_Map(hashmap);
240
+ upb_Arena* arena = Arena_get(self->arena);
241
+ upb_Message* self_msg = Map_GetMutable(_self);
242
+ size_t iter = kUpb_Map_Begin;
243
+
244
+ Arena_fuse(other->arena, arena);
245
+
246
+ if (self->key_type != other->key_type ||
247
+ self->value_type_info.type != other->value_type_info.type ||
248
+ self->value_type_class != other->value_type_class) {
249
+ rb_raise(rb_eArgError, "Attempt to merge Map with mismatching types");
250
+ }
251
+
252
+ while (upb_MapIterator_Next(other->map, &iter)) {
253
+ upb_MessageValue key = upb_MapIterator_Key(other->map, iter);
254
+ upb_MessageValue val = upb_MapIterator_Value(other->map, iter);
255
+ upb_Map_Set(self_msg, key, val, arena);
256
+ }
257
+ } else {
258
+ rb_raise(rb_eArgError, "Unknown type merging into Map");
184
259
  }
260
+ return _self;
185
261
  }
186
262
 
187
263
  /*
@@ -214,9 +290,9 @@ static bool needs_typeclass(upb_fieldtype_t type) {
214
290
  * references to underlying objects will be shared if the value type is a
215
291
  * message type.
216
292
  */
217
- VALUE Map_init(int argc, VALUE* argv, VALUE _self) {
293
+ static VALUE Map_init(int argc, VALUE* argv, VALUE _self) {
218
294
  Map* self = ruby_to_Map(_self);
219
- int init_value_arg;
295
+ VALUE init_arg;
220
296
 
221
297
  // We take either two args (:key_type, :value_type), three args (:key_type,
222
298
  // :value_type, "ValueMessageType"), or four args (the above plus an initial
@@ -226,38 +302,31 @@ VALUE Map_init(int argc, VALUE* argv, VALUE _self) {
226
302
  }
227
303
 
228
304
  self->key_type = ruby_to_fieldtype(argv[0]);
229
- self->value_type = ruby_to_fieldtype(argv[1]);
305
+ self->value_type_info =
306
+ TypeInfo_FromClass(argc, argv, 1, &self->value_type_class, &init_arg);
307
+ self->arena = Arena_new();
230
308
 
231
309
  // Check that the key type is an allowed type.
232
310
  switch (self->key_type) {
233
- case UPB_TYPE_INT32:
234
- case UPB_TYPE_INT64:
235
- case UPB_TYPE_UINT32:
236
- case UPB_TYPE_UINT64:
237
- case UPB_TYPE_BOOL:
238
- case UPB_TYPE_STRING:
239
- case UPB_TYPE_BYTES:
311
+ case kUpb_CType_Int32:
312
+ case kUpb_CType_Int64:
313
+ case kUpb_CType_UInt32:
314
+ case kUpb_CType_UInt64:
315
+ case kUpb_CType_Bool:
316
+ case kUpb_CType_String:
317
+ case kUpb_CType_Bytes:
240
318
  // These are OK.
241
319
  break;
242
320
  default:
243
321
  rb_raise(rb_eArgError, "Invalid key type for map.");
244
322
  }
245
323
 
246
- init_value_arg = 2;
247
- if (needs_typeclass(self->value_type) && argc > 2) {
248
- self->value_type_class = argv[2];
249
- validate_type_class(self->value_type, self->value_type_class);
250
- init_value_arg = 3;
251
- }
252
-
253
- // Table value type is always UINT64: this ensures enough space to store the
254
- // native_slot value.
255
- if (!upb_strtable_init(&self->table, UPB_CTYPE_UINT64)) {
256
- rb_raise(rb_eRuntimeError, "Could not allocate table.");
257
- }
324
+ self->map = upb_Map_New(Arena_get(self->arena), self->key_type,
325
+ self->value_type_info.type);
326
+ ObjectCache_Add(self->map, _self);
258
327
 
259
- if (argc > init_value_arg) {
260
- Map_merge_into_self(_self, argv[init_value_arg]);
328
+ if (init_arg != Qnil) {
329
+ Map_merge_into_self(_self, init_arg);
261
330
  }
262
331
 
263
332
  return Qnil;
@@ -271,24 +340,16 @@ VALUE Map_init(int argc, VALUE* argv, VALUE _self) {
271
340
  * Note that Map also includes Enumerable; map thus acts like a normal Ruby
272
341
  * sequence.
273
342
  */
274
- VALUE Map_each(VALUE _self) {
343
+ static VALUE Map_each(VALUE _self) {
275
344
  Map* self = ruby_to_Map(_self);
276
-
277
- upb_strtable_iter it;
278
- for (upb_strtable_begin(&it, &self->table);
279
- !upb_strtable_done(&it);
280
- upb_strtable_next(&it)) {
281
-
282
- VALUE key = table_key_to_ruby(
283
- self, upb_strtable_iter_key(&it), upb_strtable_iter_keylength(&it));
284
-
285
- upb_value v = upb_strtable_iter_value(&it);
286
- void* mem = value_memory(&v);
287
- VALUE value = native_slot_get(self->value_type,
288
- self->value_type_class,
289
- mem);
290
-
291
- rb_yield_values(2, key, value);
345
+ size_t iter = kUpb_Map_Begin;
346
+
347
+ while (upb_MapIterator_Next(self->map, &iter)) {
348
+ upb_MessageValue key = upb_MapIterator_Key(self->map, iter);
349
+ upb_MessageValue val = upb_MapIterator_Value(self->map, iter);
350
+ VALUE key_val = Convert_UpbToRuby(key, Map_keyinfo(self), self->arena);
351
+ VALUE val_val = Convert_UpbToRuby(val, self->value_type_info, self->arena);
352
+ rb_yield_values(2, key_val, val_val);
292
353
  }
293
354
 
294
355
  return Qnil;
@@ -300,19 +361,15 @@ VALUE Map_each(VALUE _self) {
300
361
  *
301
362
  * Returns the list of keys contained in the map, in unspecified order.
302
363
  */
303
- VALUE Map_keys(VALUE _self) {
364
+ static VALUE Map_keys(VALUE _self) {
304
365
  Map* self = ruby_to_Map(_self);
305
-
366
+ size_t iter = kUpb_Map_Begin;
306
367
  VALUE ret = rb_ary_new();
307
- upb_strtable_iter it;
308
- for (upb_strtable_begin(&it, &self->table);
309
- !upb_strtable_done(&it);
310
- upb_strtable_next(&it)) {
311
368
 
312
- VALUE key = table_key_to_ruby(
313
- self, upb_strtable_iter_key(&it), upb_strtable_iter_keylength(&it));
314
-
315
- rb_ary_push(ret, key);
369
+ while (upb_MapIterator_Next(self->map, &iter)) {
370
+ upb_MessageValue key = upb_MapIterator_Key(self->map, iter);
371
+ VALUE key_val = Convert_UpbToRuby(key, Map_keyinfo(self), self->arena);
372
+ rb_ary_push(ret, key_val);
316
373
  }
317
374
 
318
375
  return ret;
@@ -324,22 +381,15 @@ VALUE Map_keys(VALUE _self) {
324
381
  *
325
382
  * Returns the list of values contained in the map, in unspecified order.
326
383
  */
327
- VALUE Map_values(VALUE _self) {
384
+ static VALUE Map_values(VALUE _self) {
328
385
  Map* self = ruby_to_Map(_self);
329
-
386
+ size_t iter = kUpb_Map_Begin;
330
387
  VALUE ret = rb_ary_new();
331
- upb_strtable_iter it;
332
- for (upb_strtable_begin(&it, &self->table);
333
- !upb_strtable_done(&it);
334
- upb_strtable_next(&it)) {
335
-
336
- upb_value v = upb_strtable_iter_value(&it);
337
- void* mem = value_memory(&v);
338
- VALUE value = native_slot_get(self->value_type,
339
- self->value_type_class,
340
- mem);
341
-
342
- rb_ary_push(ret, value);
388
+
389
+ while (upb_MapIterator_Next(self->map, &iter)) {
390
+ upb_MessageValue val = upb_MapIterator_Value(self->map, iter);
391
+ VALUE val_val = Convert_UpbToRuby(val, self->value_type_info, self->arena);
392
+ rb_ary_push(ret, val_val);
343
393
  }
344
394
 
345
395
  return ret;
@@ -352,18 +402,14 @@ VALUE Map_values(VALUE _self) {
352
402
  * Accesses the element at the given key. Throws an exception if the key type is
353
403
  * incorrect. Returns nil when the key is not present in the map.
354
404
  */
355
- VALUE Map_index(VALUE _self, VALUE key) {
405
+ static VALUE Map_index(VALUE _self, VALUE key) {
356
406
  Map* self = ruby_to_Map(_self);
407
+ upb_MessageValue key_upb =
408
+ Convert_RubyToUpb(key, "", Map_keyinfo(self), NULL);
409
+ upb_MessageValue val;
357
410
 
358
- char keybuf[TABLE_KEY_BUF_LENGTH];
359
- const char* keyval = NULL;
360
- size_t length = 0;
361
- upb_value v;
362
- key = table_key(self, key, keybuf, &keyval, &length);
363
-
364
- if (upb_strtable_lookup2(&self->table, keyval, length, &v)) {
365
- void* mem = value_memory(&v);
366
- return native_slot_get(self->value_type, self->value_type_class, mem);
411
+ if (upb_Map_Get(self->map, key_upb, &val)) {
412
+ return Convert_UpbToRuby(val, self->value_type_info, self->arena);
367
413
  } else {
368
414
  return Qnil;
369
415
  }
@@ -377,27 +423,17 @@ VALUE Map_index(VALUE _self, VALUE key) {
377
423
  * Throws an exception if the key type is incorrect. Returns the new value that
378
424
  * was just inserted.
379
425
  */
380
- VALUE Map_index_set(VALUE _self, VALUE key, VALUE value) {
426
+ static VALUE Map_index_set(VALUE _self, VALUE key, VALUE val) {
381
427
  Map* self = ruby_to_Map(_self);
428
+ upb_Arena* arena = Arena_get(self->arena);
429
+ upb_MessageValue key_upb =
430
+ Convert_RubyToUpb(key, "", Map_keyinfo(self), NULL);
431
+ upb_MessageValue val_upb =
432
+ Convert_RubyToUpb(val, "", self->value_type_info, arena);
382
433
 
383
- char keybuf[TABLE_KEY_BUF_LENGTH];
384
- const char* keyval = NULL;
385
- size_t length = 0;
386
- upb_value v;
387
- void* mem;
388
- key = table_key(self, key, keybuf, &keyval, &length);
389
-
390
- mem = value_memory(&v);
391
- native_slot_set(self->value_type, self->value_type_class, mem, value);
392
-
393
- // Replace any existing value by issuing a 'remove' operation first.
394
- upb_strtable_remove2(&self->table, keyval, length, NULL);
395
- if (!upb_strtable_insert2(&self->table, keyval, length, v)) {
396
- rb_raise(rb_eRuntimeError, "Could not insert into table");
397
- }
434
+ upb_Map_Set(Map_GetMutable(_self), key_upb, val_upb, arena);
398
435
 
399
- // Ruby hashmap's :[]= method also returns the inserted value.
400
- return value;
436
+ return val;
401
437
  }
402
438
 
403
439
  /*
@@ -407,15 +443,12 @@ VALUE Map_index_set(VALUE _self, VALUE key, VALUE value) {
407
443
  * Returns true if the given key is present in the map. Throws an exception if
408
444
  * the key has the wrong type.
409
445
  */
410
- VALUE Map_has_key(VALUE _self, VALUE key) {
446
+ static VALUE Map_has_key(VALUE _self, VALUE key) {
411
447
  Map* self = ruby_to_Map(_self);
448
+ upb_MessageValue key_upb =
449
+ Convert_RubyToUpb(key, "", Map_keyinfo(self), NULL);
412
450
 
413
- char keybuf[TABLE_KEY_BUF_LENGTH];
414
- const char* keyval = NULL;
415
- size_t length = 0;
416
- key = table_key(self, key, keybuf, &keyval, &length);
417
-
418
- if (upb_strtable_lookup2(&self->table, keyval, length, NULL)) {
451
+ if (upb_Map_Get(self->map, key_upb, NULL)) {
419
452
  return Qtrue;
420
453
  } else {
421
454
  return Qfalse;
@@ -429,21 +462,26 @@ VALUE Map_has_key(VALUE _self, VALUE key) {
429
462
  * Deletes the value at the given key, if any, returning either the old value or
430
463
  * nil if none was present. Throws an exception if the key is of the wrong type.
431
464
  */
432
- VALUE Map_delete(VALUE _self, VALUE key) {
465
+ static VALUE Map_delete(VALUE _self, VALUE key) {
433
466
  Map* self = ruby_to_Map(_self);
467
+ upb_MessageValue key_upb =
468
+ Convert_RubyToUpb(key, "", Map_keyinfo(self), NULL);
469
+ upb_MessageValue val_upb;
470
+ VALUE ret;
434
471
 
435
- char keybuf[TABLE_KEY_BUF_LENGTH];
436
- const char* keyval = NULL;
437
- size_t length = 0;
438
- upb_value v;
439
- key = table_key(self, key, keybuf, &keyval, &length);
472
+ rb_check_frozen(_self);
440
473
 
441
- if (upb_strtable_remove2(&self->table, keyval, length, &v)) {
442
- void* mem = value_memory(&v);
443
- return native_slot_get(self->value_type, self->value_type_class, mem);
474
+ // TODO(haberman): make upb_Map_Delete() also capable of returning the deleted
475
+ // value.
476
+ if (upb_Map_Get(self->map, key_upb, &val_upb)) {
477
+ ret = Convert_UpbToRuby(val_upb, self->value_type_info, self->arena);
444
478
  } else {
445
- return Qnil;
479
+ ret = Qnil;
446
480
  }
481
+
482
+ upb_Map_Delete(Map_GetMutable(_self), key_upb);
483
+
484
+ return ret;
447
485
  }
448
486
 
449
487
  /*
@@ -452,15 +490,8 @@ VALUE Map_delete(VALUE _self, VALUE key) {
452
490
  *
453
491
  * Removes all entries from the map.
454
492
  */
455
- VALUE Map_clear(VALUE _self) {
456
- Map* self = ruby_to_Map(_self);
457
-
458
- // Uninit and reinit the table -- this is faster than iterating and doing a
459
- // delete-lookup on each key.
460
- upb_strtable_uninit(&self->table);
461
- if (!upb_strtable_init(&self->table, UPB_CTYPE_INT64)) {
462
- rb_raise(rb_eRuntimeError, "Unable to re-initialize table");
463
- }
493
+ static VALUE Map_clear(VALUE _self) {
494
+ upb_Map_Clear(Map_GetMutable(_self));
464
495
  return Qnil;
465
496
  }
466
497
 
@@ -470,24 +501,9 @@ VALUE Map_clear(VALUE _self) {
470
501
  *
471
502
  * Returns the number of entries (key-value pairs) in the map.
472
503
  */
473
- VALUE Map_length(VALUE _self) {
504
+ static VALUE Map_length(VALUE _self) {
474
505
  Map* self = ruby_to_Map(_self);
475
- return ULL2NUM(upb_strtable_count(&self->table));
476
- }
477
-
478
- static VALUE Map_new_this_type(VALUE _self) {
479
- Map* self = ruby_to_Map(_self);
480
- VALUE new_map = Qnil;
481
- VALUE key_type = fieldtype_to_ruby(self->key_type);
482
- VALUE value_type = fieldtype_to_ruby(self->value_type);
483
- if (self->value_type_class != Qnil) {
484
- new_map = rb_funcall(CLASS_OF(_self), rb_intern("new"), 3,
485
- key_type, value_type, self->value_type_class);
486
- } else {
487
- new_map = rb_funcall(CLASS_OF(_self), rb_intern("new"), 2,
488
- key_type, value_type);
489
- }
490
- return new_map;
506
+ return ULL2NUM(upb_Map_Size(self->map));
491
507
  }
492
508
 
493
509
  /*
@@ -497,59 +513,23 @@ static VALUE Map_new_this_type(VALUE _self) {
497
513
  * Duplicates this map with a shallow copy. References to all non-primitive
498
514
  * element objects (e.g., submessages) are shared.
499
515
  */
500
- VALUE Map_dup(VALUE _self) {
501
- Map* self = ruby_to_Map(_self);
502
- VALUE new_map = Map_new_this_type(_self);
503
- Map* new_self = ruby_to_Map(new_map);
504
-
505
- upb_strtable_iter it;
506
- for (upb_strtable_begin(&it, &self->table);
507
- !upb_strtable_done(&it);
508
- upb_strtable_next(&it)) {
509
-
510
- upb_value v = upb_strtable_iter_value(&it);
511
- void* mem = value_memory(&v);
512
- upb_value dup;
513
- void* dup_mem = value_memory(&dup);
514
- native_slot_dup(self->value_type, dup_mem, mem);
515
-
516
- if (!upb_strtable_insert2(&new_self->table,
517
- upb_strtable_iter_key(&it),
518
- upb_strtable_iter_keylength(&it),
519
- dup)) {
520
- rb_raise(rb_eRuntimeError, "Error inserting value into new table");
521
- }
522
- }
523
-
524
- return new_map;
525
- }
526
-
527
- // Used by Google::Protobuf.deep_copy but not exposed directly.
528
- VALUE Map_deep_copy(VALUE _self) {
516
+ static VALUE Map_dup(VALUE _self) {
529
517
  Map* self = ruby_to_Map(_self);
530
- VALUE new_map = Map_new_this_type(_self);
531
- Map* new_self = ruby_to_Map(new_map);
532
-
533
- upb_strtable_iter it;
534
- for (upb_strtable_begin(&it, &self->table);
535
- !upb_strtable_done(&it);
536
- upb_strtable_next(&it)) {
537
-
538
- upb_value v = upb_strtable_iter_value(&it);
539
- void* mem = value_memory(&v);
540
- upb_value dup;
541
- void* dup_mem = value_memory(&dup);
542
- native_slot_deep_copy(self->value_type, dup_mem, mem);
543
-
544
- if (!upb_strtable_insert2(&new_self->table,
545
- upb_strtable_iter_key(&it),
546
- upb_strtable_iter_keylength(&it),
547
- dup)) {
548
- rb_raise(rb_eRuntimeError, "Error inserting value into new table");
549
- }
518
+ VALUE new_map_rb = Map_new_this_type(self);
519
+ Map* new_self = ruby_to_Map(new_map_rb);
520
+ size_t iter = kUpb_Map_Begin;
521
+ upb_Arena* arena = Arena_get(new_self->arena);
522
+ upb_Map* new_map = Map_GetMutable(new_map_rb);
523
+
524
+ Arena_fuse(self->arena, arena);
525
+
526
+ while (upb_MapIterator_Next(self->map, &iter)) {
527
+ upb_MessageValue key = upb_MapIterator_Key(self->map, iter);
528
+ upb_MessageValue val = upb_MapIterator_Value(self->map, iter);
529
+ upb_Map_Set(new_map, key, val, arena);
550
530
  }
551
531
 
552
- return new_map;
532
+ return new_map_rb;
553
533
  }
554
534
 
555
535
  /*
@@ -568,12 +548,11 @@ VALUE Map_deep_copy(VALUE _self) {
568
548
  VALUE Map_eq(VALUE _self, VALUE _other) {
569
549
  Map* self = ruby_to_Map(_self);
570
550
  Map* other;
571
- upb_strtable_iter it;
572
551
 
573
552
  // Allow comparisons to Ruby hashmaps by converting to a temporary Map
574
553
  // instance. Slow, but workable.
575
554
  if (TYPE(_other) == T_HASH) {
576
- VALUE other_map = Map_new_this_type(_self);
555
+ VALUE other_map = Map_new_this_type(self);
577
556
  Map_merge_into_self(other_map, _other);
578
557
  _other = other_map;
579
558
  }
@@ -584,35 +563,27 @@ VALUE Map_eq(VALUE _self, VALUE _other) {
584
563
  return Qtrue;
585
564
  }
586
565
  if (self->key_type != other->key_type ||
587
- self->value_type != other->value_type ||
566
+ self->value_type_info.type != other->value_type_info.type ||
588
567
  self->value_type_class != other->value_type_class) {
589
568
  return Qfalse;
590
569
  }
591
- if (upb_strtable_count(&self->table) != upb_strtable_count(&other->table)) {
570
+ if (upb_Map_Size(self->map) != upb_Map_Size(other->map)) {
592
571
  return Qfalse;
593
572
  }
594
573
 
595
574
  // For each member of self, check that an equal member exists at the same key
596
575
  // in other.
597
- for (upb_strtable_begin(&it, &self->table);
598
- !upb_strtable_done(&it);
599
- upb_strtable_next(&it)) {
600
-
601
- upb_value v = upb_strtable_iter_value(&it);
602
- void* mem = value_memory(&v);
603
- upb_value other_v;
604
- void* other_mem = value_memory(&other_v);
605
-
606
- if (!upb_strtable_lookup2(&other->table,
607
- upb_strtable_iter_key(&it),
608
- upb_strtable_iter_keylength(&it),
609
- &other_v)) {
576
+ size_t iter = kUpb_Map_Begin;
577
+ while (upb_MapIterator_Next(self->map, &iter)) {
578
+ upb_MessageValue key = upb_MapIterator_Key(self->map, iter);
579
+ upb_MessageValue val = upb_MapIterator_Value(self->map, iter);
580
+ upb_MessageValue other_val;
581
+ if (!upb_Map_Get(other->map, key, &other_val)) {
610
582
  // Not present in other map.
611
583
  return Qfalse;
612
584
  }
613
-
614
- if (!native_slot_eq(self->value_type, mem, other_mem)) {
615
- // Present, but value not equal.
585
+ if (!Msgval_IsEqual(val, other_val, self->value_type_info)) {
586
+ // Present but different value.
616
587
  return Qfalse;
617
588
  }
618
589
  }
@@ -620,6 +591,22 @@ VALUE Map_eq(VALUE _self, VALUE _other) {
620
591
  return Qtrue;
621
592
  }
622
593
 
594
+ /*
595
+ * call-seq:
596
+ * Message.freeze => self
597
+ *
598
+ * Freezes the message object. We have to intercept this so we can pin the
599
+ * Ruby object into memory so we don't forget it's frozen.
600
+ */
601
+ static VALUE Map_freeze(VALUE _self) {
602
+ Map* self = ruby_to_Map(_self);
603
+ if (!RB_OBJ_FROZEN(_self)) {
604
+ Arena_Pin(self->arena, _self);
605
+ RB_OBJ_FREEZE(_self);
606
+ }
607
+ return _self;
608
+ }
609
+
623
610
  /*
624
611
  * call-seq:
625
612
  * Map.hash => hash_value
@@ -628,28 +615,29 @@ VALUE Map_eq(VALUE _self, VALUE _other) {
628
615
  */
629
616
  VALUE Map_hash(VALUE _self) {
630
617
  Map* self = ruby_to_Map(_self);
631
-
632
- st_index_t h = rb_hash_start(0);
633
- VALUE hash_sym = rb_intern("hash");
634
-
635
- upb_strtable_iter it;
636
- for (upb_strtable_begin(&it, &self->table);
637
- !upb_strtable_done(&it);
638
- upb_strtable_next(&it)) {
639
- VALUE key = table_key_to_ruby(
640
- self, upb_strtable_iter_key(&it), upb_strtable_iter_keylength(&it));
641
-
642
- upb_value v = upb_strtable_iter_value(&it);
643
- void* mem = value_memory(&v);
644
- VALUE value = native_slot_get(self->value_type,
645
- self->value_type_class,
646
- mem);
647
-
648
- h = rb_hash_uint(h, NUM2LONG(rb_funcall(key, hash_sym, 0)));
649
- h = rb_hash_uint(h, NUM2LONG(rb_funcall(value, hash_sym, 0)));
618
+ uint64_t hash = 0;
619
+
620
+ size_t iter = kUpb_Map_Begin;
621
+ TypeInfo key_info = {self->key_type};
622
+ while (upb_MapIterator_Next(self->map, &iter)) {
623
+ upb_MessageValue key = upb_MapIterator_Key(self->map, iter);
624
+ upb_MessageValue val = upb_MapIterator_Value(self->map, iter);
625
+ hash = Msgval_GetHash(key, key_info, hash);
626
+ hash = Msgval_GetHash(val, self->value_type_info, hash);
650
627
  }
651
628
 
652
- return INT2FIX(h);
629
+ return LL2NUM(hash);
630
+ }
631
+
632
+ /*
633
+ * call-seq:
634
+ * Map.to_h => {}
635
+ *
636
+ * Returns a Ruby Hash object containing all the values within the map
637
+ */
638
+ VALUE Map_to_h(VALUE _self) {
639
+ Map* self = ruby_to_Map(_self);
640
+ return Map_CreateHash(self->map, self->key_type, self->value_type_info);
653
641
  }
654
642
 
655
643
  /*
@@ -663,36 +651,11 @@ VALUE Map_hash(VALUE _self) {
663
651
  VALUE Map_inspect(VALUE _self) {
664
652
  Map* self = ruby_to_Map(_self);
665
653
 
666
- VALUE str = rb_str_new2("{");
667
-
668
- bool first = true;
669
- VALUE inspect_sym = rb_intern("inspect");
670
-
671
- upb_strtable_iter it;
672
- for (upb_strtable_begin(&it, &self->table);
673
- !upb_strtable_done(&it);
674
- upb_strtable_next(&it)) {
675
- VALUE key = table_key_to_ruby(
676
- self, upb_strtable_iter_key(&it), upb_strtable_iter_keylength(&it));
677
-
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 (!first) {
685
- str = rb_str_cat2(str, ", ");
686
- } else {
687
- first = false;
688
- }
689
- str = rb_str_append(str, rb_funcall(key, inspect_sym, 0));
690
- str = rb_str_cat2(str, "=>");
691
- str = rb_str_append(str, rb_funcall(value, inspect_sym, 0));
692
- }
693
-
694
- str = rb_str_cat2(str, "}");
695
- return str;
654
+ StringBuilder* builder = StringBuilder_New();
655
+ Map_Inspect(builder, self->map, self->key_type, self->value_type_info);
656
+ VALUE ret = StringBuilder_ToRubyString(builder);
657
+ StringBuilder_Free(builder);
658
+ return ret;
696
659
  }
697
660
 
698
661
  /*
@@ -704,92 +667,16 @@ VALUE Map_inspect(VALUE _self) {
704
667
  * in the new copy of this map. Returns the new copy of this map with merged
705
668
  * contents.
706
669
  */
707
- VALUE Map_merge(VALUE _self, VALUE hashmap) {
670
+ static VALUE Map_merge(VALUE _self, VALUE hashmap) {
708
671
  VALUE dupped = Map_dup(_self);
709
672
  return Map_merge_into_self(dupped, hashmap);
710
673
  }
711
674
 
712
- static int merge_into_self_callback(VALUE key, VALUE value, VALUE self) {
713
- Map_index_set(self, key, value);
714
- return ST_CONTINUE;
715
- }
716
-
717
- // Used only internally -- shared by #merge and #initialize.
718
- VALUE Map_merge_into_self(VALUE _self, VALUE hashmap) {
719
- if (TYPE(hashmap) == T_HASH) {
720
- rb_hash_foreach(hashmap, merge_into_self_callback, _self);
721
- } else if (RB_TYPE_P(hashmap, T_DATA) && RTYPEDDATA_P(hashmap) &&
722
- RTYPEDDATA_TYPE(hashmap) == &Map_type) {
723
-
724
- Map* self = ruby_to_Map(_self);
725
- Map* other = ruby_to_Map(hashmap);
726
- upb_strtable_iter it;
727
-
728
- if (self->key_type != other->key_type ||
729
- self->value_type != other->value_type ||
730
- self->value_type_class != other->value_type_class) {
731
- rb_raise(rb_eArgError, "Attempt to merge Map with mismatching types");
732
- }
733
-
734
- for (upb_strtable_begin(&it, &other->table);
735
- !upb_strtable_done(&it);
736
- upb_strtable_next(&it)) {
737
-
738
- // Replace any existing value by issuing a 'remove' operation first.
739
- upb_value v;
740
- upb_value oldv;
741
- upb_strtable_remove2(&self->table,
742
- upb_strtable_iter_key(&it),
743
- upb_strtable_iter_keylength(&it),
744
- &oldv);
745
-
746
- v = upb_strtable_iter_value(&it);
747
- upb_strtable_insert2(&self->table,
748
- upb_strtable_iter_key(&it),
749
- upb_strtable_iter_keylength(&it),
750
- v);
751
- }
752
- } else {
753
- rb_raise(rb_eArgError, "Unknown type merging into Map");
754
- }
755
- return _self;
756
- }
757
-
758
- // Internal method: map iterator initialization (used for serialization).
759
- void Map_begin(VALUE _self, Map_iter* iter) {
760
- Map* self = ruby_to_Map(_self);
761
- iter->self = self;
762
- upb_strtable_begin(&iter->it, &self->table);
763
- }
764
-
765
- void Map_next(Map_iter* iter) {
766
- upb_strtable_next(&iter->it);
767
- }
768
-
769
- bool Map_done(Map_iter* iter) {
770
- return upb_strtable_done(&iter->it);
771
- }
772
-
773
- VALUE Map_iter_key(Map_iter* iter) {
774
- return table_key_to_ruby(
775
- iter->self,
776
- upb_strtable_iter_key(&iter->it),
777
- upb_strtable_iter_keylength(&iter->it));
778
- }
779
-
780
- VALUE Map_iter_value(Map_iter* iter) {
781
- upb_value v = upb_strtable_iter_value(&iter->it);
782
- void* mem = value_memory(&v);
783
- return native_slot_get(iter->self->value_type,
784
- iter->self->value_type_class,
785
- mem);
786
- }
787
-
788
675
  void Map_register(VALUE module) {
789
676
  VALUE klass = rb_define_class_under(module, "Map", rb_cObject);
790
677
  rb_define_alloc_func(klass, Map_alloc);
791
- cMap = klass;
792
678
  rb_gc_register_address(&cMap);
679
+ cMap = klass;
793
680
 
794
681
  rb_define_method(klass, "initialize", Map_init, -1);
795
682
  rb_define_method(klass, "each", Map_each, 0);
@@ -801,9 +688,14 @@ void Map_register(VALUE module) {
801
688
  rb_define_method(klass, "delete", Map_delete, 1);
802
689
  rb_define_method(klass, "clear", Map_clear, 0);
803
690
  rb_define_method(klass, "length", Map_length, 0);
691
+ rb_define_method(klass, "size", Map_length, 0);
804
692
  rb_define_method(klass, "dup", Map_dup, 0);
693
+ // Also define #clone so that we don't inherit Object#clone.
694
+ rb_define_method(klass, "clone", Map_dup, 0);
805
695
  rb_define_method(klass, "==", Map_eq, 1);
696
+ rb_define_method(klass, "freeze", Map_freeze, 0);
806
697
  rb_define_method(klass, "hash", Map_hash, 0);
698
+ rb_define_method(klass, "to_h", Map_to_h, 0);
807
699
  rb_define_method(klass, "inspect", Map_inspect, 0);
808
700
  rb_define_method(klass, "merge", Map_merge, 1);
809
701
  rb_include_module(klass, rb_mEnumerable);