google-protobuf 3.14.0 → 4.26.1

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