google-protobuf 3.14.0 → 3.21.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.
- checksums.yaml +4 -4
- data/ext/google/protobuf_c/convert.c +361 -0
- data/ext/google/protobuf_c/convert.h +75 -0
- data/ext/google/protobuf_c/defs.c +576 -1662
- data/ext/google/protobuf_c/defs.h +107 -0
- data/ext/google/protobuf_c/extconf.rb +13 -6
- data/ext/google/protobuf_c/map.c +329 -463
- data/ext/google/protobuf_c/map.h +66 -0
- data/ext/google/protobuf_c/message.c +1010 -467
- data/ext/google/protobuf_c/message.h +104 -0
- data/ext/google/protobuf_c/protobuf.c +411 -67
- data/ext/google/protobuf_c/protobuf.h +49 -596
- data/ext/google/protobuf_c/repeated_field.c +299 -328
- data/ext/google/protobuf_c/repeated_field.h +63 -0
- data/ext/google/protobuf_c/ruby-upb.c +11115 -0
- data/ext/google/protobuf_c/ruby-upb.h +5612 -0
- data/ext/google/protobuf_c/third_party/utf8_range/LICENSE +21 -0
- data/ext/google/protobuf_c/third_party/utf8_range/naive.c +92 -0
- data/ext/google/protobuf_c/third_party/utf8_range/range2-neon.c +157 -0
- data/ext/google/protobuf_c/third_party/utf8_range/range2-sse.c +170 -0
- data/ext/google/protobuf_c/third_party/utf8_range/utf8_range.h +9 -0
- data/ext/google/protobuf_c/wrap_memcpy.c +4 -3
- data/lib/google/protobuf/api_pb.rb +1 -0
- data/lib/google/protobuf/descriptor_dsl.rb +465 -0
- data/lib/google/protobuf/descriptor_pb.rb +269 -0
- data/lib/google/protobuf/message_exts.rb +2 -2
- data/lib/google/protobuf/repeated_field.rb +15 -2
- data/lib/google/protobuf/type_pb.rb +1 -0
- data/lib/google/protobuf/well_known_types.rb +12 -2
- data/lib/google/protobuf.rb +5 -73
- data/tests/basic.rb +209 -13
- data/tests/stress.rb +1 -1
- metadata +23 -32
- data/ext/google/protobuf_c/encode_decode.c +0 -1795
- data/ext/google/protobuf_c/storage.c +0 -1198
- data/ext/google/protobuf_c/upb.c +0 -13817
- data/ext/google/protobuf_c/upb.h +0 -6777
data/ext/google/protobuf_c/map.c
CHANGED
@@ -28,170 +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
|
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
|
-
//
|
49
|
-
//
|
50
|
-
//
|
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;
|
46
|
+
// -----------------------------------------------------------------------------
|
47
|
+
// Map container type.
|
48
|
+
// -----------------------------------------------------------------------------
|
82
49
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
*out_length = native_slot_size(self->key_type);
|
91
|
-
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;
|
92
57
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
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;
|
99
71
|
|
100
|
-
|
72
|
+
static Map* ruby_to_Map(VALUE _self) {
|
73
|
+
Map* self;
|
74
|
+
TypedData_Get_Struct(_self, Map, &Map_type, self);
|
75
|
+
return self;
|
101
76
|
}
|
102
77
|
|
103
|
-
static VALUE
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
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);
|
112
105
|
}
|
106
|
+
}
|
113
107
|
|
114
|
-
|
115
|
-
|
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);
|
108
|
+
return val;
|
109
|
+
}
|
120
110
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
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;
|
125
119
|
}
|
126
120
|
|
127
|
-
static
|
128
|
-
|
121
|
+
static TypeInfo Map_keyinfo(Map* self) {
|
122
|
+
TypeInfo ret;
|
123
|
+
ret.type = self->key_type;
|
124
|
+
ret.def.msgdef = NULL;
|
125
|
+
return ret;
|
129
126
|
}
|
130
127
|
|
131
|
-
|
132
|
-
|
133
|
-
|
128
|
+
static upb_Map* Map_GetMutable(VALUE _self) {
|
129
|
+
rb_check_frozen(_self);
|
130
|
+
return (upb_Map*)ruby_to_Map(_self)->map;
|
131
|
+
}
|
134
132
|
|
135
|
-
const
|
136
|
-
|
137
|
-
|
138
|
-
|
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);
|
139
138
|
|
140
|
-
|
139
|
+
if (!map) return hash;
|
141
140
|
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
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
|
+
}
|
147
148
|
|
148
|
-
|
149
|
-
|
149
|
+
return hash;
|
150
|
+
}
|
150
151
|
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
self->
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
}
|
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
165
|
}
|
166
|
+
|
167
|
+
return Map_GetRubyWrapper(new_map, self->key_type, self->value_type_info,
|
168
|
+
new_arena_rb);
|
166
169
|
}
|
167
170
|
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
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;
|
177
|
+
|
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
|
+
}
|
182
|
+
|
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");
|
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;
|
172
196
|
}
|
173
197
|
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
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, "}");
|
179
219
|
}
|
180
220
|
|
181
|
-
|
182
|
-
Map* self = ruby_to_Map(
|
183
|
-
|
184
|
-
|
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;
|
185
230
|
}
|
186
231
|
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
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");
|
194
259
|
}
|
260
|
+
return _self;
|
195
261
|
}
|
196
262
|
|
197
263
|
/*
|
@@ -224,9 +290,9 @@ static bool needs_typeclass(upb_fieldtype_t type) {
|
|
224
290
|
* references to underlying objects will be shared if the value type is a
|
225
291
|
* message type.
|
226
292
|
*/
|
227
|
-
VALUE Map_init(int argc, VALUE* argv, VALUE _self) {
|
293
|
+
static VALUE Map_init(int argc, VALUE* argv, VALUE _self) {
|
228
294
|
Map* self = ruby_to_Map(_self);
|
229
|
-
|
295
|
+
VALUE init_arg;
|
230
296
|
|
231
297
|
// We take either two args (:key_type, :value_type), three args (:key_type,
|
232
298
|
// :value_type, "ValueMessageType"), or four args (the above plus an initial
|
@@ -236,39 +302,31 @@ VALUE Map_init(int argc, VALUE* argv, VALUE _self) {
|
|
236
302
|
}
|
237
303
|
|
238
304
|
self->key_type = ruby_to_fieldtype(argv[0]);
|
239
|
-
self->
|
240
|
-
|
305
|
+
self->value_type_info =
|
306
|
+
TypeInfo_FromClass(argc, argv, 1, &self->value_type_class, &init_arg);
|
307
|
+
self->arena = Arena_new();
|
241
308
|
|
242
309
|
// Check that the key type is an allowed type.
|
243
310
|
switch (self->key_type) {
|
244
|
-
case
|
245
|
-
case
|
246
|
-
case
|
247
|
-
case
|
248
|
-
case
|
249
|
-
case
|
250
|
-
case
|
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:
|
251
318
|
// These are OK.
|
252
319
|
break;
|
253
320
|
default:
|
254
321
|
rb_raise(rb_eArgError, "Invalid key type for map.");
|
255
322
|
}
|
256
323
|
|
257
|
-
|
258
|
-
|
259
|
-
|
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
|
-
}
|
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);
|
269
327
|
|
270
|
-
if (
|
271
|
-
Map_merge_into_self(_self,
|
328
|
+
if (init_arg != Qnil) {
|
329
|
+
Map_merge_into_self(_self, init_arg);
|
272
330
|
}
|
273
331
|
|
274
332
|
return Qnil;
|
@@ -282,22 +340,16 @@ VALUE Map_init(int argc, VALUE* argv, VALUE _self) {
|
|
282
340
|
* Note that Map also includes Enumerable; map thus acts like a normal Ruby
|
283
341
|
* sequence.
|
284
342
|
*/
|
285
|
-
VALUE Map_each(VALUE _self) {
|
343
|
+
static VALUE Map_each(VALUE _self) {
|
286
344
|
Map* self = ruby_to_Map(_self);
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
VALUE
|
293
|
-
|
294
|
-
|
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);
|
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);
|
301
353
|
}
|
302
354
|
|
303
355
|
return Qnil;
|
@@ -309,17 +361,15 @@ VALUE Map_each(VALUE _self) {
|
|
309
361
|
*
|
310
362
|
* Returns the list of keys contained in the map, in unspecified order.
|
311
363
|
*/
|
312
|
-
VALUE Map_keys(VALUE _self) {
|
364
|
+
static VALUE Map_keys(VALUE _self) {
|
313
365
|
Map* self = ruby_to_Map(_self);
|
314
|
-
|
366
|
+
size_t iter = kUpb_Map_Begin;
|
315
367
|
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));
|
321
368
|
|
322
|
-
|
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);
|
323
373
|
}
|
324
374
|
|
325
375
|
return ret;
|
@@ -331,22 +381,15 @@ VALUE Map_keys(VALUE _self) {
|
|
331
381
|
*
|
332
382
|
* Returns the list of values contained in the map, in unspecified order.
|
333
383
|
*/
|
334
|
-
VALUE Map_values(VALUE _self) {
|
384
|
+
static VALUE Map_values(VALUE _self) {
|
335
385
|
Map* self = ruby_to_Map(_self);
|
336
|
-
|
386
|
+
size_t iter = kUpb_Map_Begin;
|
337
387
|
VALUE ret = rb_ary_new();
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
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);
|
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);
|
350
393
|
}
|
351
394
|
|
352
395
|
return ret;
|
@@ -359,18 +402,14 @@ VALUE Map_values(VALUE _self) {
|
|
359
402
|
* Accesses the element at the given key. Throws an exception if the key type is
|
360
403
|
* incorrect. Returns nil when the key is not present in the map.
|
361
404
|
*/
|
362
|
-
VALUE Map_index(VALUE _self, VALUE key) {
|
405
|
+
static VALUE Map_index(VALUE _self, VALUE key) {
|
363
406
|
Map* self = ruby_to_Map(_self);
|
407
|
+
upb_MessageValue key_upb =
|
408
|
+
Convert_RubyToUpb(key, "", Map_keyinfo(self), NULL);
|
409
|
+
upb_MessageValue val;
|
364
410
|
|
365
|
-
|
366
|
-
|
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);
|
411
|
+
if (upb_Map_Get(self->map, key_upb, &val)) {
|
412
|
+
return Convert_UpbToRuby(val, self->value_type_info, self->arena);
|
374
413
|
} else {
|
375
414
|
return Qnil;
|
376
415
|
}
|
@@ -384,33 +423,17 @@ VALUE Map_index(VALUE _self, VALUE key) {
|
|
384
423
|
* Throws an exception if the key type is incorrect. Returns the new value that
|
385
424
|
* was just inserted.
|
386
425
|
*/
|
387
|
-
VALUE Map_index_set(VALUE _self, VALUE key, VALUE
|
426
|
+
static VALUE Map_index_set(VALUE _self, VALUE key, VALUE val) {
|
388
427
|
Map* self = ruby_to_Map(_self);
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
key = table_key(self, key, keybuf, &keyval, &length);
|
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);
|
395
433
|
|
396
|
-
|
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
|
-
}
|
402
|
-
|
403
|
-
mem = value_memory(&v);
|
404
|
-
native_slot_set("", self->value_type, self->value_type_class, mem, value);
|
405
|
-
|
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
|
-
}
|
434
|
+
upb_Map_Set(Map_GetMutable(_self), key_upb, val_upb, arena);
|
411
435
|
|
412
|
-
|
413
|
-
return value;
|
436
|
+
return val;
|
414
437
|
}
|
415
438
|
|
416
439
|
/*
|
@@ -420,15 +443,12 @@ VALUE Map_index_set(VALUE _self, VALUE key, VALUE value) {
|
|
420
443
|
* Returns true if the given key is present in the map. Throws an exception if
|
421
444
|
* the key has the wrong type.
|
422
445
|
*/
|
423
|
-
VALUE Map_has_key(VALUE _self, VALUE key) {
|
446
|
+
static VALUE Map_has_key(VALUE _self, VALUE key) {
|
424
447
|
Map* self = ruby_to_Map(_self);
|
448
|
+
upb_MessageValue key_upb =
|
449
|
+
Convert_RubyToUpb(key, "", Map_keyinfo(self), NULL);
|
425
450
|
|
426
|
-
|
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)) {
|
451
|
+
if (upb_Map_Get(self->map, key_upb, NULL)) {
|
432
452
|
return Qtrue;
|
433
453
|
} else {
|
434
454
|
return Qfalse;
|
@@ -442,22 +462,26 @@ VALUE Map_has_key(VALUE _self, VALUE key) {
|
|
442
462
|
* Deletes the value at the given key, if any, returning either the old value or
|
443
463
|
* nil if none was present. Throws an exception if the key is of the wrong type.
|
444
464
|
*/
|
445
|
-
VALUE Map_delete(VALUE _self, VALUE key) {
|
465
|
+
static VALUE Map_delete(VALUE _self, VALUE key) {
|
446
466
|
Map* self = ruby_to_Map(_self);
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
key = table_key(self, key, keybuf, &keyval, &length);
|
467
|
+
upb_MessageValue key_upb =
|
468
|
+
Convert_RubyToUpb(key, "", Map_keyinfo(self), NULL);
|
469
|
+
upb_MessageValue val_upb;
|
470
|
+
VALUE ret;
|
452
471
|
|
453
472
|
rb_check_frozen(_self);
|
454
473
|
|
455
|
-
|
456
|
-
|
457
|
-
|
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);
|
458
478
|
} else {
|
459
|
-
|
479
|
+
ret = Qnil;
|
460
480
|
}
|
481
|
+
|
482
|
+
upb_Map_Delete(Map_GetMutable(_self), key_upb);
|
483
|
+
|
484
|
+
return ret;
|
461
485
|
}
|
462
486
|
|
463
487
|
/*
|
@@ -466,17 +490,8 @@ VALUE Map_delete(VALUE _self, VALUE key) {
|
|
466
490
|
*
|
467
491
|
* Removes all entries from the map.
|
468
492
|
*/
|
469
|
-
VALUE Map_clear(VALUE _self) {
|
470
|
-
|
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
|
-
}
|
493
|
+
static VALUE Map_clear(VALUE _self) {
|
494
|
+
upb_Map_Clear(Map_GetMutable(_self));
|
480
495
|
return Qnil;
|
481
496
|
}
|
482
497
|
|
@@ -486,24 +501,9 @@ VALUE Map_clear(VALUE _self) {
|
|
486
501
|
*
|
487
502
|
* Returns the number of entries (key-value pairs) in the map.
|
488
503
|
*/
|
489
|
-
VALUE Map_length(VALUE _self) {
|
490
|
-
Map* self = ruby_to_Map(_self);
|
491
|
-
return ULL2NUM(upb_strtable_count(&self->table));
|
492
|
-
}
|
493
|
-
|
494
|
-
VALUE Map_new_this_type(VALUE _self) {
|
504
|
+
static VALUE Map_length(VALUE _self) {
|
495
505
|
Map* self = ruby_to_Map(_self);
|
496
|
-
|
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;
|
506
|
+
return ULL2NUM(upb_Map_Size(self->map));
|
507
507
|
}
|
508
508
|
|
509
509
|
/*
|
@@ -513,54 +513,23 @@ VALUE Map_new_this_type(VALUE _self) {
|
|
513
513
|
* Duplicates this map with a shallow copy. References to all non-primitive
|
514
514
|
* element objects (e.g., submessages) are shared.
|
515
515
|
*/
|
516
|
-
VALUE Map_dup(VALUE _self) {
|
517
|
-
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
|
-
}
|
536
|
-
|
537
|
-
return new_map;
|
538
|
-
}
|
539
|
-
|
540
|
-
// Used by Google::Protobuf.deep_copy but not exposed directly.
|
541
|
-
VALUE Map_deep_copy(VALUE _self) {
|
516
|
+
static VALUE Map_dup(VALUE _self) {
|
542
517
|
Map* self = ruby_to_Map(_self);
|
543
|
-
VALUE
|
544
|
-
Map* new_self = ruby_to_Map(
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
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
|
-
}
|
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);
|
561
530
|
}
|
562
531
|
|
563
|
-
return
|
532
|
+
return new_map_rb;
|
564
533
|
}
|
565
534
|
|
566
535
|
/*
|
@@ -579,12 +548,11 @@ VALUE Map_deep_copy(VALUE _self) {
|
|
579
548
|
VALUE Map_eq(VALUE _self, VALUE _other) {
|
580
549
|
Map* self = ruby_to_Map(_self);
|
581
550
|
Map* other;
|
582
|
-
upb_strtable_iter it;
|
583
551
|
|
584
552
|
// Allow comparisons to Ruby hashmaps by converting to a temporary Map
|
585
553
|
// instance. Slow, but workable.
|
586
554
|
if (TYPE(_other) == T_HASH) {
|
587
|
-
VALUE other_map = Map_new_this_type(
|
555
|
+
VALUE other_map = Map_new_this_type(self);
|
588
556
|
Map_merge_into_self(other_map, _other);
|
589
557
|
_other = other_map;
|
590
558
|
}
|
@@ -595,33 +563,27 @@ VALUE Map_eq(VALUE _self, VALUE _other) {
|
|
595
563
|
return Qtrue;
|
596
564
|
}
|
597
565
|
if (self->key_type != other->key_type ||
|
598
|
-
self->
|
566
|
+
self->value_type_info.type != other->value_type_info.type ||
|
599
567
|
self->value_type_class != other->value_type_class) {
|
600
568
|
return Qfalse;
|
601
569
|
}
|
602
|
-
if (
|
570
|
+
if (upb_Map_Size(self->map) != upb_Map_Size(other->map)) {
|
603
571
|
return Qfalse;
|
604
572
|
}
|
605
573
|
|
606
574
|
// For each member of self, check that an equal member exists at the same key
|
607
575
|
// in other.
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
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)) {
|
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)) {
|
618
582
|
// Not present in other map.
|
619
583
|
return Qfalse;
|
620
584
|
}
|
621
|
-
|
622
|
-
|
623
|
-
other_mem)) {
|
624
|
-
// Present, but value not equal.
|
585
|
+
if (!Msgval_IsEqual(val, other_val, self->value_type_info)) {
|
586
|
+
// Present but different value.
|
625
587
|
return Qfalse;
|
626
588
|
}
|
627
589
|
}
|
@@ -629,6 +591,22 @@ VALUE Map_eq(VALUE _self, VALUE _other) {
|
|
629
591
|
return Qtrue;
|
630
592
|
}
|
631
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
|
+
|
632
610
|
/*
|
633
611
|
* call-seq:
|
634
612
|
* Map.hash => hash_value
|
@@ -637,26 +615,18 @@ VALUE Map_eq(VALUE _self, VALUE _other) {
|
|
637
615
|
*/
|
638
616
|
VALUE Map_hash(VALUE _self) {
|
639
617
|
Map* self = ruby_to_Map(_self);
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
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);
|
654
|
-
|
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)));
|
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);
|
657
627
|
}
|
658
628
|
|
659
|
-
return
|
629
|
+
return LL2NUM(hash);
|
660
630
|
}
|
661
631
|
|
662
632
|
/*
|
@@ -667,24 +637,7 @@ VALUE Map_hash(VALUE _self) {
|
|
667
637
|
*/
|
668
638
|
VALUE Map_to_h(VALUE _self) {
|
669
639
|
Map* self = ruby_to_Map(_self);
|
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(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;
|
640
|
+
return Map_CreateHash(self->map, self->key_type, self->value_type_info);
|
688
641
|
}
|
689
642
|
|
690
643
|
/*
|
@@ -698,34 +651,11 @@ VALUE Map_to_h(VALUE _self) {
|
|
698
651
|
VALUE Map_inspect(VALUE _self) {
|
699
652
|
Map* self = ruby_to_Map(_self);
|
700
653
|
|
701
|
-
|
702
|
-
|
703
|
-
|
704
|
-
|
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;
|
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;
|
729
659
|
}
|
730
660
|
|
731
661
|
/*
|
@@ -737,79 +667,11 @@ VALUE Map_inspect(VALUE _self) {
|
|
737
667
|
* in the new copy of this map. Returns the new copy of this map with merged
|
738
668
|
* contents.
|
739
669
|
*/
|
740
|
-
VALUE Map_merge(VALUE _self, VALUE hashmap) {
|
670
|
+
static VALUE Map_merge(VALUE _self, VALUE hashmap) {
|
741
671
|
VALUE dupped = Map_dup(_self);
|
742
672
|
return Map_merge_into_self(dupped, hashmap);
|
743
673
|
}
|
744
674
|
|
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
675
|
void Map_register(VALUE module) {
|
814
676
|
VALUE klass = rb_define_class_under(module, "Map", rb_cObject);
|
815
677
|
rb_define_alloc_func(klass, Map_alloc);
|
@@ -826,8 +688,12 @@ void Map_register(VALUE module) {
|
|
826
688
|
rb_define_method(klass, "delete", Map_delete, 1);
|
827
689
|
rb_define_method(klass, "clear", Map_clear, 0);
|
828
690
|
rb_define_method(klass, "length", Map_length, 0);
|
691
|
+
rb_define_method(klass, "size", Map_length, 0);
|
829
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);
|
830
695
|
rb_define_method(klass, "==", Map_eq, 1);
|
696
|
+
rb_define_method(klass, "freeze", Map_freeze, 0);
|
831
697
|
rb_define_method(klass, "hash", Map_hash, 0);
|
832
698
|
rb_define_method(klass, "to_h", Map_to_h, 0);
|
833
699
|
rb_define_method(klass, "inspect", Map_inspect, 0);
|