google-protobuf 3.0.0 → 3.20.0

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

Potentially problematic release.


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

Files changed (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);