google-protobuf 3.11.3 → 3.19.3
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 +348 -0
- data/ext/google/protobuf_c/convert.h +72 -0
- data/ext/google/protobuf_c/defs.c +468 -1462
- data/ext/google/protobuf_c/defs.h +107 -0
- data/ext/google/protobuf_c/extconf.rb +4 -5
- data/ext/google/protobuf_c/map.c +314 -482
- data/ext/google/protobuf_c/map.h +67 -0
- data/ext/google/protobuf_c/message.c +916 -437
- data/ext/google/protobuf_c/message.h +101 -0
- data/ext/google/protobuf_c/protobuf.c +398 -64
- data/ext/google/protobuf_c/protobuf.h +43 -592
- data/ext/google/protobuf_c/repeated_field.c +294 -321
- data/ext/google/protobuf_c/repeated_field.h +63 -0
- data/ext/google/protobuf_c/ruby-upb.c +9171 -0
- data/ext/google/protobuf_c/ruby-upb.h +4704 -0
- data/lib/google/protobuf/api_pb.rb +1 -0
- data/lib/google/protobuf/descriptor_dsl.rb +458 -0
- data/lib/google/protobuf/descriptor_pb.rb +268 -0
- data/lib/google/protobuf/type_pb.rb +1 -0
- data/lib/google/protobuf/well_known_types.rb +5 -0
- data/lib/google/protobuf.rb +1 -69
- data/tests/basic.rb +248 -53
- data/tests/generated_code_test.rb +0 -0
- data/tests/stress.rb +1 -1
- metadata +20 -28
- data/ext/google/protobuf_c/encode_decode.c +0 -1758
- data/ext/google/protobuf_c/storage.c +0 -1149
- data/ext/google/protobuf_c/upb.c +0 -13289
- data/ext/google/protobuf_c/upb.h +0 -7085
data/ext/google/protobuf_c/map.c
CHANGED
@@ -28,170 +28,233 @@
|
|
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
|
-
// 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, const char* buf, size_t length) {
|
104
|
-
switch (self->key_type) {
|
105
|
-
case UPB_TYPE_BYTES:
|
106
|
-
case UPB_TYPE_STRING: {
|
107
|
-
VALUE ret = rb_str_new(buf, length);
|
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, buf);
|
120
|
-
|
121
|
-
default:
|
122
|
-
assert(false);
|
123
|
-
return Qnil;
|
124
|
-
}
|
125
|
-
}
|
126
|
-
|
127
|
-
static void* value_memory(upb_value* v) {
|
128
|
-
return (void*)(&v->val);
|
129
|
-
}
|
130
|
-
|
131
46
|
// -----------------------------------------------------------------------------
|
132
47
|
// Map container type.
|
133
48
|
// -----------------------------------------------------------------------------
|
134
49
|
|
50
|
+
typedef struct {
|
51
|
+
const upb_map *map; // Can convert to mutable when non-frozen.
|
52
|
+
upb_fieldtype_t key_type;
|
53
|
+
TypeInfo value_type_info;
|
54
|
+
VALUE value_type_class;
|
55
|
+
VALUE arena;
|
56
|
+
} Map;
|
57
|
+
|
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
|
+
|
135
64
|
const rb_data_type_t Map_type = {
|
136
65
|
"Google::Protobuf::Map",
|
137
|
-
{ Map_mark,
|
66
|
+
{ Map_mark, RUBY_DEFAULT_FREE, NULL },
|
67
|
+
.flags = RUBY_TYPED_FREE_IMMEDIATELY,
|
138
68
|
};
|
139
69
|
|
140
70
|
VALUE cMap;
|
141
71
|
|
142
|
-
Map* ruby_to_Map(VALUE _self) {
|
72
|
+
static Map* ruby_to_Map(VALUE _self) {
|
143
73
|
Map* self;
|
144
74
|
TypedData_Get_Struct(_self, Map, &Map_type, self);
|
145
75
|
return self;
|
146
76
|
}
|
147
77
|
|
148
|
-
|
149
|
-
Map* self =
|
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
|
+
}
|
150
86
|
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
87
|
+
VALUE Map_GetRubyWrapper(upb_map* map, upb_fieldtype_t key_type,
|
88
|
+
TypeInfo value_type, 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 == UPB_TYPE_MESSAGE) {
|
103
|
+
const upb_msgdef *val_m = self->value_type_info.def.msgdef;
|
104
|
+
self->value_type_class = Descriptor_DefToClass(val_m);
|
164
105
|
}
|
165
106
|
}
|
107
|
+
|
108
|
+
return val;
|
166
109
|
}
|
167
110
|
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
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;
|
172
119
|
}
|
173
120
|
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
return
|
121
|
+
static TypeInfo Map_keyinfo(Map* self) {
|
122
|
+
TypeInfo ret;
|
123
|
+
ret.type = self->key_type;
|
124
|
+
ret.def.msgdef = NULL;
|
125
|
+
return ret;
|
179
126
|
}
|
180
127
|
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
return val;
|
128
|
+
static upb_map *Map_GetMutable(VALUE _self) {
|
129
|
+
rb_check_frozen(_self);
|
130
|
+
return (upb_map*)ruby_to_Map(_self)->map;
|
185
131
|
}
|
186
132
|
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
133
|
+
VALUE Map_CreateHash(const upb_map* map, upb_fieldtype_t key_type,
|
134
|
+
TypeInfo val_info) {
|
135
|
+
VALUE hash = rb_hash_new();
|
136
|
+
size_t iter = UPB_MAP_BEGIN;
|
137
|
+
TypeInfo key_info = TypeInfo_from_type(key_type);
|
138
|
+
|
139
|
+
if (!map) return hash;
|
140
|
+
|
141
|
+
while (upb_mapiter_next(map, &iter)) {
|
142
|
+
upb_msgval key = upb_mapiter_key(map, iter);
|
143
|
+
upb_msgval val = upb_mapiter_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 = UPB_MAP_BEGIN;
|
159
|
+
while (upb_mapiter_next(self->map, &iter)) {
|
160
|
+
upb_msgval key = upb_mapiter_key(self->map, iter);
|
161
|
+
upb_msgval val = upb_mapiter_value(self->map, iter);
|
162
|
+
upb_msgval val_copy = Msgval_DeepCopy(val, self->value_type_info, arena);
|
163
|
+
upb_map_set(new_map, key, val_copy, arena);
|
164
|
+
}
|
165
|
+
|
166
|
+
return Map_GetRubyWrapper(new_map, self->key_type, self->value_type_info,
|
167
|
+
new_arena_rb);
|
168
|
+
}
|
169
|
+
|
170
|
+
const upb_map* Map_GetUpbMap(VALUE val, const upb_fielddef* field,
|
171
|
+
upb_arena* arena) {
|
172
|
+
const upb_fielddef* key_field = map_field_key(field);
|
173
|
+
const upb_fielddef* value_field = map_field_value(field);
|
174
|
+
TypeInfo value_type_info = TypeInfo_get(value_field);
|
175
|
+
Map* self;
|
176
|
+
|
177
|
+
if (!RB_TYPE_P(val, T_DATA) || !RTYPEDDATA_P(val) ||
|
178
|
+
RTYPEDDATA_TYPE(val) != &Map_type) {
|
179
|
+
rb_raise(cTypeError, "Expected Map instance");
|
180
|
+
}
|
181
|
+
|
182
|
+
self = ruby_to_Map(val);
|
183
|
+
if (self->key_type != upb_fielddef_type(key_field)) {
|
184
|
+
rb_raise(cTypeError, "Map key type does not match field's key type");
|
185
|
+
}
|
186
|
+
if (self->value_type_info.type != value_type_info.type) {
|
187
|
+
rb_raise(cTypeError, "Map value type does not match field's value type");
|
188
|
+
}
|
189
|
+
if (self->value_type_info.def.msgdef != value_type_info.def.msgdef) {
|
190
|
+
rb_raise(cTypeError, "Map value type has wrong message/enum class");
|
191
|
+
}
|
192
|
+
|
193
|
+
Arena_fuse(self->arena, arena);
|
194
|
+
return self->map;
|
195
|
+
}
|
196
|
+
|
197
|
+
void Map_Inspect(StringBuilder* b, const upb_map* map, upb_fieldtype_t key_type,
|
198
|
+
TypeInfo val_type) {
|
199
|
+
bool first = true;
|
200
|
+
TypeInfo key_type_info = {key_type};
|
201
|
+
StringBuilder_Printf(b, "{");
|
202
|
+
if (map) {
|
203
|
+
size_t iter = UPB_MAP_BEGIN;
|
204
|
+
while (upb_mapiter_next(map, &iter)) {
|
205
|
+
upb_msgval key = upb_mapiter_key(map, iter);
|
206
|
+
upb_msgval val = upb_mapiter_value(map, iter);
|
207
|
+
if (first) {
|
208
|
+
first = false;
|
209
|
+
} else {
|
210
|
+
StringBuilder_Printf(b, ", ");
|
211
|
+
}
|
212
|
+
StringBuilder_PrintMsgval(b, key, key_type_info);
|
213
|
+
StringBuilder_Printf(b, "=>");
|
214
|
+
StringBuilder_PrintMsgval(b, val, val_type);
|
215
|
+
}
|
216
|
+
}
|
217
|
+
StringBuilder_Printf(b, "}");
|
218
|
+
}
|
219
|
+
|
220
|
+
static int merge_into_self_callback(VALUE key, VALUE val, VALUE _self) {
|
221
|
+
Map* self = ruby_to_Map(_self);
|
222
|
+
upb_arena *arena = Arena_get(self->arena);
|
223
|
+
upb_msgval key_val = Convert_RubyToUpb(key, "", Map_keyinfo(self), arena);
|
224
|
+
upb_msgval val_val = Convert_RubyToUpb(val, "", self->value_type_info, arena);
|
225
|
+
upb_map_set(Map_GetMutable(_self), key_val, val_val, arena);
|
226
|
+
return ST_CONTINUE;
|
227
|
+
}
|
228
|
+
|
229
|
+
// Used only internally -- shared by #merge and #initialize.
|
230
|
+
static VALUE Map_merge_into_self(VALUE _self, VALUE hashmap) {
|
231
|
+
if (TYPE(hashmap) == T_HASH) {
|
232
|
+
rb_hash_foreach(hashmap, merge_into_self_callback, _self);
|
233
|
+
} else if (RB_TYPE_P(hashmap, T_DATA) && RTYPEDDATA_P(hashmap) &&
|
234
|
+
RTYPEDDATA_TYPE(hashmap) == &Map_type) {
|
235
|
+
Map* self = ruby_to_Map(_self);
|
236
|
+
Map* other = ruby_to_Map(hashmap);
|
237
|
+
upb_arena *arena = Arena_get(self->arena);
|
238
|
+
upb_msg *self_msg = Map_GetMutable(_self);
|
239
|
+
size_t iter = UPB_MAP_BEGIN;
|
240
|
+
|
241
|
+
Arena_fuse(other->arena, arena);
|
242
|
+
|
243
|
+
if (self->key_type != other->key_type ||
|
244
|
+
self->value_type_info.type != other->value_type_info.type ||
|
245
|
+
self->value_type_class != other->value_type_class) {
|
246
|
+
rb_raise(rb_eArgError, "Attempt to merge Map with mismatching types");
|
247
|
+
}
|
248
|
+
|
249
|
+
while (upb_mapiter_next(other->map, &iter)) {
|
250
|
+
upb_msgval key = upb_mapiter_key(other->map, iter);
|
251
|
+
upb_msgval val = upb_mapiter_value(other->map, iter);
|
252
|
+
upb_map_set(self_msg, key, val, arena);
|
253
|
+
}
|
254
|
+
} else {
|
255
|
+
rb_raise(rb_eArgError, "Unknown type merging into Map");
|
194
256
|
}
|
257
|
+
return _self;
|
195
258
|
}
|
196
259
|
|
197
260
|
/*
|
@@ -224,9 +287,9 @@ static bool needs_typeclass(upb_fieldtype_t type) {
|
|
224
287
|
* references to underlying objects will be shared if the value type is a
|
225
288
|
* message type.
|
226
289
|
*/
|
227
|
-
VALUE Map_init(int argc, VALUE* argv, VALUE _self) {
|
290
|
+
static VALUE Map_init(int argc, VALUE* argv, VALUE _self) {
|
228
291
|
Map* self = ruby_to_Map(_self);
|
229
|
-
|
292
|
+
VALUE init_arg;
|
230
293
|
|
231
294
|
// We take either two args (:key_type, :value_type), three args (:key_type,
|
232
295
|
// :value_type, "ValueMessageType"), or four args (the above plus an initial
|
@@ -236,8 +299,9 @@ VALUE Map_init(int argc, VALUE* argv, VALUE _self) {
|
|
236
299
|
}
|
237
300
|
|
238
301
|
self->key_type = ruby_to_fieldtype(argv[0]);
|
239
|
-
self->
|
240
|
-
|
302
|
+
self->value_type_info =
|
303
|
+
TypeInfo_FromClass(argc, argv, 1, &self->value_type_class, &init_arg);
|
304
|
+
self->arena = Arena_new();
|
241
305
|
|
242
306
|
// Check that the key type is an allowed type.
|
243
307
|
switch (self->key_type) {
|
@@ -254,21 +318,12 @@ VALUE Map_init(int argc, VALUE* argv, VALUE _self) {
|
|
254
318
|
rb_raise(rb_eArgError, "Invalid key type for map.");
|
255
319
|
}
|
256
320
|
|
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
|
-
}
|
321
|
+
self->map = upb_map_new(Arena_get(self->arena), self->key_type,
|
322
|
+
self->value_type_info.type);
|
323
|
+
ObjectCache_Add(self->map, _self);
|
269
324
|
|
270
|
-
if (
|
271
|
-
Map_merge_into_self(_self,
|
325
|
+
if (init_arg != Qnil) {
|
326
|
+
Map_merge_into_self(_self, init_arg);
|
272
327
|
}
|
273
328
|
|
274
329
|
return Qnil;
|
@@ -282,24 +337,16 @@ VALUE Map_init(int argc, VALUE* argv, VALUE _self) {
|
|
282
337
|
* Note that Map also includes Enumerable; map thus acts like a normal Ruby
|
283
338
|
* sequence.
|
284
339
|
*/
|
285
|
-
VALUE Map_each(VALUE _self) {
|
340
|
+
static VALUE Map_each(VALUE _self) {
|
286
341
|
Map* self = ruby_to_Map(_self);
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
VALUE
|
294
|
-
|
295
|
-
|
296
|
-
upb_value v = upb_strtable_iter_value(&it);
|
297
|
-
void* mem = value_memory(&v);
|
298
|
-
VALUE value = native_slot_get(self->value_type,
|
299
|
-
self->value_type_class,
|
300
|
-
mem);
|
301
|
-
|
302
|
-
rb_yield_values(2, key, value);
|
342
|
+
size_t iter = UPB_MAP_BEGIN;
|
343
|
+
|
344
|
+
while (upb_mapiter_next(self->map, &iter)) {
|
345
|
+
upb_msgval key = upb_mapiter_key(self->map, iter);
|
346
|
+
upb_msgval val = upb_mapiter_value(self->map, iter);
|
347
|
+
VALUE key_val = Convert_UpbToRuby(key, Map_keyinfo(self), self->arena);
|
348
|
+
VALUE val_val = Convert_UpbToRuby(val, self->value_type_info, self->arena);
|
349
|
+
rb_yield_values(2, key_val, val_val);
|
303
350
|
}
|
304
351
|
|
305
352
|
return Qnil;
|
@@ -311,19 +358,15 @@ VALUE Map_each(VALUE _self) {
|
|
311
358
|
*
|
312
359
|
* Returns the list of keys contained in the map, in unspecified order.
|
313
360
|
*/
|
314
|
-
VALUE Map_keys(VALUE _self) {
|
361
|
+
static VALUE Map_keys(VALUE _self) {
|
315
362
|
Map* self = ruby_to_Map(_self);
|
316
|
-
|
363
|
+
size_t iter = UPB_MAP_BEGIN;
|
317
364
|
VALUE ret = rb_ary_new();
|
318
|
-
upb_strtable_iter it;
|
319
|
-
for (upb_strtable_begin(&it, &self->table);
|
320
|
-
!upb_strtable_done(&it);
|
321
|
-
upb_strtable_next(&it)) {
|
322
|
-
|
323
|
-
VALUE key = table_key_to_ruby(
|
324
|
-
self, upb_strtable_iter_key(&it), upb_strtable_iter_keylength(&it));
|
325
365
|
|
326
|
-
|
366
|
+
while (upb_mapiter_next(self->map, &iter)) {
|
367
|
+
upb_msgval key = upb_mapiter_key(self->map, iter);
|
368
|
+
VALUE key_val = Convert_UpbToRuby(key, Map_keyinfo(self), self->arena);
|
369
|
+
rb_ary_push(ret, key_val);
|
327
370
|
}
|
328
371
|
|
329
372
|
return ret;
|
@@ -335,22 +378,15 @@ VALUE Map_keys(VALUE _self) {
|
|
335
378
|
*
|
336
379
|
* Returns the list of values contained in the map, in unspecified order.
|
337
380
|
*/
|
338
|
-
VALUE Map_values(VALUE _self) {
|
381
|
+
static VALUE Map_values(VALUE _self) {
|
339
382
|
Map* self = ruby_to_Map(_self);
|
340
|
-
|
383
|
+
size_t iter = UPB_MAP_BEGIN;
|
341
384
|
VALUE ret = rb_ary_new();
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
upb_value v = upb_strtable_iter_value(&it);
|
348
|
-
void* mem = value_memory(&v);
|
349
|
-
VALUE value = native_slot_get(self->value_type,
|
350
|
-
self->value_type_class,
|
351
|
-
mem);
|
352
|
-
|
353
|
-
rb_ary_push(ret, value);
|
385
|
+
|
386
|
+
while (upb_mapiter_next(self->map, &iter)) {
|
387
|
+
upb_msgval val = upb_mapiter_value(self->map, iter);
|
388
|
+
VALUE val_val = Convert_UpbToRuby(val, self->value_type_info, self->arena);
|
389
|
+
rb_ary_push(ret, val_val);
|
354
390
|
}
|
355
391
|
|
356
392
|
return ret;
|
@@ -363,18 +399,13 @@ VALUE Map_values(VALUE _self) {
|
|
363
399
|
* Accesses the element at the given key. Throws an exception if the key type is
|
364
400
|
* incorrect. Returns nil when the key is not present in the map.
|
365
401
|
*/
|
366
|
-
VALUE Map_index(VALUE _self, VALUE key) {
|
402
|
+
static VALUE Map_index(VALUE _self, VALUE key) {
|
367
403
|
Map* self = ruby_to_Map(_self);
|
404
|
+
upb_msgval key_upb = Convert_RubyToUpb(key, "", Map_keyinfo(self), NULL);
|
405
|
+
upb_msgval val;
|
368
406
|
|
369
|
-
|
370
|
-
|
371
|
-
size_t length = 0;
|
372
|
-
upb_value v;
|
373
|
-
key = table_key(self, key, keybuf, &keyval, &length);
|
374
|
-
|
375
|
-
if (upb_strtable_lookup2(&self->table, keyval, length, &v)) {
|
376
|
-
void* mem = value_memory(&v);
|
377
|
-
return native_slot_get(self->value_type, self->value_type_class, mem);
|
407
|
+
if (upb_map_get(self->map, key_upb, &val)) {
|
408
|
+
return Convert_UpbToRuby(val, self->value_type_info, self->arena);
|
378
409
|
} else {
|
379
410
|
return Qnil;
|
380
411
|
}
|
@@ -388,33 +419,15 @@ VALUE Map_index(VALUE _self, VALUE key) {
|
|
388
419
|
* Throws an exception if the key type is incorrect. Returns the new value that
|
389
420
|
* was just inserted.
|
390
421
|
*/
|
391
|
-
VALUE Map_index_set(VALUE _self, VALUE key, VALUE
|
422
|
+
static VALUE Map_index_set(VALUE _self, VALUE key, VALUE val) {
|
392
423
|
Map* self = ruby_to_Map(_self);
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
upb_value v;
|
397
|
-
void* mem;
|
398
|
-
key = table_key(self, key, keybuf, &keyval, &length);
|
399
|
-
|
400
|
-
rb_check_frozen(_self);
|
401
|
-
|
402
|
-
if (TYPE(value) == T_HASH) {
|
403
|
-
VALUE args[1] = { value };
|
404
|
-
value = rb_class_new_instance(1, args, self->value_type_class);
|
405
|
-
}
|
424
|
+
upb_arena *arena = Arena_get(self->arena);
|
425
|
+
upb_msgval key_upb = Convert_RubyToUpb(key, "", Map_keyinfo(self), NULL);
|
426
|
+
upb_msgval val_upb = Convert_RubyToUpb(val, "", self->value_type_info, arena);
|
406
427
|
|
407
|
-
|
408
|
-
native_slot_set("", self->value_type, self->value_type_class, mem, value);
|
428
|
+
upb_map_set(Map_GetMutable(_self), key_upb, val_upb, arena);
|
409
429
|
|
410
|
-
|
411
|
-
upb_strtable_remove2(&self->table, keyval, length, NULL);
|
412
|
-
if (!upb_strtable_insert2(&self->table, keyval, length, v)) {
|
413
|
-
rb_raise(rb_eRuntimeError, "Could not insert into table");
|
414
|
-
}
|
415
|
-
|
416
|
-
// Ruby hashmap's :[]= method also returns the inserted value.
|
417
|
-
return value;
|
430
|
+
return val;
|
418
431
|
}
|
419
432
|
|
420
433
|
/*
|
@@ -424,15 +437,11 @@ VALUE Map_index_set(VALUE _self, VALUE key, VALUE value) {
|
|
424
437
|
* Returns true if the given key is present in the map. Throws an exception if
|
425
438
|
* the key has the wrong type.
|
426
439
|
*/
|
427
|
-
VALUE Map_has_key(VALUE _self, VALUE key) {
|
440
|
+
static VALUE Map_has_key(VALUE _self, VALUE key) {
|
428
441
|
Map* self = ruby_to_Map(_self);
|
442
|
+
upb_msgval key_upb = Convert_RubyToUpb(key, "", Map_keyinfo(self), NULL);
|
429
443
|
|
430
|
-
|
431
|
-
const char* keyval = NULL;
|
432
|
-
size_t length = 0;
|
433
|
-
key = table_key(self, key, keybuf, &keyval, &length);
|
434
|
-
|
435
|
-
if (upb_strtable_lookup2(&self->table, keyval, length, NULL)) {
|
444
|
+
if (upb_map_get(self->map, key_upb, NULL)) {
|
436
445
|
return Qtrue;
|
437
446
|
} else {
|
438
447
|
return Qfalse;
|
@@ -446,22 +455,25 @@ VALUE Map_has_key(VALUE _self, VALUE key) {
|
|
446
455
|
* Deletes the value at the given key, if any, returning either the old value or
|
447
456
|
* nil if none was present. Throws an exception if the key is of the wrong type.
|
448
457
|
*/
|
449
|
-
VALUE Map_delete(VALUE _self, VALUE key) {
|
458
|
+
static VALUE Map_delete(VALUE _self, VALUE key) {
|
450
459
|
Map* self = ruby_to_Map(_self);
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
upb_value v;
|
455
|
-
key = table_key(self, key, keybuf, &keyval, &length);
|
460
|
+
upb_msgval key_upb = Convert_RubyToUpb(key, "", Map_keyinfo(self), NULL);
|
461
|
+
upb_msgval val_upb;
|
462
|
+
VALUE ret;
|
456
463
|
|
457
464
|
rb_check_frozen(_self);
|
458
465
|
|
459
|
-
|
460
|
-
|
461
|
-
|
466
|
+
// TODO(haberman): make upb_map_delete() also capable of returning the deleted
|
467
|
+
// value.
|
468
|
+
if (upb_map_get(self->map, key_upb, &val_upb)) {
|
469
|
+
ret = Convert_UpbToRuby(val_upb, self->value_type_info, self->arena);
|
462
470
|
} else {
|
463
|
-
|
471
|
+
ret = Qnil;
|
464
472
|
}
|
473
|
+
|
474
|
+
upb_map_delete(Map_GetMutable(_self), key_upb);
|
475
|
+
|
476
|
+
return ret;
|
465
477
|
}
|
466
478
|
|
467
479
|
/*
|
@@ -470,17 +482,8 @@ VALUE Map_delete(VALUE _self, VALUE key) {
|
|
470
482
|
*
|
471
483
|
* Removes all entries from the map.
|
472
484
|
*/
|
473
|
-
VALUE Map_clear(VALUE _self) {
|
474
|
-
|
475
|
-
|
476
|
-
rb_check_frozen(_self);
|
477
|
-
|
478
|
-
// Uninit and reinit the table -- this is faster than iterating and doing a
|
479
|
-
// delete-lookup on each key.
|
480
|
-
upb_strtable_uninit(&self->table);
|
481
|
-
if (!upb_strtable_init(&self->table, UPB_CTYPE_INT64)) {
|
482
|
-
rb_raise(rb_eRuntimeError, "Unable to re-initialize table");
|
483
|
-
}
|
485
|
+
static VALUE Map_clear(VALUE _self) {
|
486
|
+
upb_map_clear(Map_GetMutable(_self));
|
484
487
|
return Qnil;
|
485
488
|
}
|
486
489
|
|
@@ -490,24 +493,9 @@ VALUE Map_clear(VALUE _self) {
|
|
490
493
|
*
|
491
494
|
* Returns the number of entries (key-value pairs) in the map.
|
492
495
|
*/
|
493
|
-
VALUE Map_length(VALUE _self) {
|
496
|
+
static VALUE Map_length(VALUE _self) {
|
494
497
|
Map* self = ruby_to_Map(_self);
|
495
|
-
return ULL2NUM(
|
496
|
-
}
|
497
|
-
|
498
|
-
VALUE Map_new_this_type(VALUE _self) {
|
499
|
-
Map* self = ruby_to_Map(_self);
|
500
|
-
VALUE new_map = Qnil;
|
501
|
-
VALUE key_type = fieldtype_to_ruby(self->key_type);
|
502
|
-
VALUE value_type = fieldtype_to_ruby(self->value_type);
|
503
|
-
if (self->value_type_class != Qnil) {
|
504
|
-
new_map = rb_funcall(CLASS_OF(_self), rb_intern("new"), 3,
|
505
|
-
key_type, value_type, self->value_type_class);
|
506
|
-
} else {
|
507
|
-
new_map = rb_funcall(CLASS_OF(_self), rb_intern("new"), 2,
|
508
|
-
key_type, value_type);
|
509
|
-
}
|
510
|
-
return new_map;
|
498
|
+
return ULL2NUM(upb_map_size(self->map));
|
511
499
|
}
|
512
500
|
|
513
501
|
/*
|
@@ -517,60 +505,23 @@ VALUE Map_new_this_type(VALUE _self) {
|
|
517
505
|
* Duplicates this map with a shallow copy. References to all non-primitive
|
518
506
|
* element objects (e.g., submessages) are shared.
|
519
507
|
*/
|
520
|
-
VALUE Map_dup(VALUE _self) {
|
521
|
-
Map* self = ruby_to_Map(_self);
|
522
|
-
VALUE new_map = Map_new_this_type(_self);
|
523
|
-
Map* new_self = ruby_to_Map(new_map);
|
524
|
-
|
525
|
-
upb_strtable_iter it;
|
526
|
-
for (upb_strtable_begin(&it, &self->table);
|
527
|
-
!upb_strtable_done(&it);
|
528
|
-
upb_strtable_next(&it)) {
|
529
|
-
|
530
|
-
upb_value v = upb_strtable_iter_value(&it);
|
531
|
-
void* mem = value_memory(&v);
|
532
|
-
upb_value dup;
|
533
|
-
void* dup_mem = value_memory(&dup);
|
534
|
-
native_slot_dup(self->value_type, dup_mem, mem);
|
535
|
-
|
536
|
-
if (!upb_strtable_insert2(&new_self->table,
|
537
|
-
upb_strtable_iter_key(&it),
|
538
|
-
upb_strtable_iter_keylength(&it),
|
539
|
-
dup)) {
|
540
|
-
rb_raise(rb_eRuntimeError, "Error inserting value into new table");
|
541
|
-
}
|
542
|
-
}
|
543
|
-
|
544
|
-
return new_map;
|
545
|
-
}
|
546
|
-
|
547
|
-
// Used by Google::Protobuf.deep_copy but not exposed directly.
|
548
|
-
VALUE Map_deep_copy(VALUE _self) {
|
508
|
+
static VALUE Map_dup(VALUE _self) {
|
549
509
|
Map* self = ruby_to_Map(_self);
|
550
|
-
VALUE
|
551
|
-
Map* new_self = ruby_to_Map(
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
native_slot_deep_copy(self->value_type, self->value_type_class, dup_mem,
|
563
|
-
mem);
|
564
|
-
|
565
|
-
if (!upb_strtable_insert2(&new_self->table,
|
566
|
-
upb_strtable_iter_key(&it),
|
567
|
-
upb_strtable_iter_keylength(&it),
|
568
|
-
dup)) {
|
569
|
-
rb_raise(rb_eRuntimeError, "Error inserting value into new table");
|
570
|
-
}
|
510
|
+
VALUE new_map_rb = Map_new_this_type(self);
|
511
|
+
Map* new_self = ruby_to_Map(new_map_rb);
|
512
|
+
size_t iter = UPB_MAP_BEGIN;
|
513
|
+
upb_arena *arena = Arena_get(new_self->arena);
|
514
|
+
upb_map *new_map = Map_GetMutable(new_map_rb);
|
515
|
+
|
516
|
+
Arena_fuse(self->arena, arena);
|
517
|
+
|
518
|
+
while (upb_mapiter_next(self->map, &iter)) {
|
519
|
+
upb_msgval key = upb_mapiter_key(self->map, iter);
|
520
|
+
upb_msgval val = upb_mapiter_value(self->map, iter);
|
521
|
+
upb_map_set(new_map, key, val, arena);
|
571
522
|
}
|
572
523
|
|
573
|
-
return
|
524
|
+
return new_map_rb;
|
574
525
|
}
|
575
526
|
|
576
527
|
/*
|
@@ -589,12 +540,11 @@ VALUE Map_deep_copy(VALUE _self) {
|
|
589
540
|
VALUE Map_eq(VALUE _self, VALUE _other) {
|
590
541
|
Map* self = ruby_to_Map(_self);
|
591
542
|
Map* other;
|
592
|
-
upb_strtable_iter it;
|
593
543
|
|
594
544
|
// Allow comparisons to Ruby hashmaps by converting to a temporary Map
|
595
545
|
// instance. Slow, but workable.
|
596
546
|
if (TYPE(_other) == T_HASH) {
|
597
|
-
VALUE other_map = Map_new_this_type(
|
547
|
+
VALUE other_map = Map_new_this_type(self);
|
598
548
|
Map_merge_into_self(other_map, _other);
|
599
549
|
_other = other_map;
|
600
550
|
}
|
@@ -605,36 +555,27 @@ VALUE Map_eq(VALUE _self, VALUE _other) {
|
|
605
555
|
return Qtrue;
|
606
556
|
}
|
607
557
|
if (self->key_type != other->key_type ||
|
608
|
-
self->
|
558
|
+
self->value_type_info.type != other->value_type_info.type ||
|
609
559
|
self->value_type_class != other->value_type_class) {
|
610
560
|
return Qfalse;
|
611
561
|
}
|
612
|
-
if (
|
562
|
+
if (upb_map_size(self->map) != upb_map_size(other->map)) {
|
613
563
|
return Qfalse;
|
614
564
|
}
|
615
565
|
|
616
566
|
// For each member of self, check that an equal member exists at the same key
|
617
567
|
// in other.
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
upb_value other_v;
|
625
|
-
void* other_mem = value_memory(&other_v);
|
626
|
-
|
627
|
-
if (!upb_strtable_lookup2(&other->table,
|
628
|
-
upb_strtable_iter_key(&it),
|
629
|
-
upb_strtable_iter_keylength(&it),
|
630
|
-
&other_v)) {
|
568
|
+
size_t iter = UPB_MAP_BEGIN;
|
569
|
+
while (upb_mapiter_next(self->map, &iter)) {
|
570
|
+
upb_msgval key = upb_mapiter_key(self->map, iter);
|
571
|
+
upb_msgval val = upb_mapiter_value(self->map, iter);
|
572
|
+
upb_msgval other_val;
|
573
|
+
if (!upb_map_get(other->map, key, &other_val)) {
|
631
574
|
// Not present in other map.
|
632
575
|
return Qfalse;
|
633
576
|
}
|
634
|
-
|
635
|
-
|
636
|
-
other_mem)) {
|
637
|
-
// Present, but value not equal.
|
577
|
+
if (!Msgval_IsEqual(val, other_val, self->value_type_info)) {
|
578
|
+
// Present but different value.
|
638
579
|
return Qfalse;
|
639
580
|
}
|
640
581
|
}
|
@@ -642,6 +583,22 @@ VALUE Map_eq(VALUE _self, VALUE _other) {
|
|
642
583
|
return Qtrue;
|
643
584
|
}
|
644
585
|
|
586
|
+
/*
|
587
|
+
* call-seq:
|
588
|
+
* Message.freeze => self
|
589
|
+
*
|
590
|
+
* Freezes the message object. We have to intercept this so we can pin the
|
591
|
+
* Ruby object into memory so we don't forget it's frozen.
|
592
|
+
*/
|
593
|
+
static VALUE Map_freeze(VALUE _self) {
|
594
|
+
Map* self = ruby_to_Map(_self);
|
595
|
+
if (!RB_OBJ_FROZEN(_self)) {
|
596
|
+
Arena_Pin(self->arena, _self);
|
597
|
+
RB_OBJ_FREEZE(_self);
|
598
|
+
}
|
599
|
+
return _self;
|
600
|
+
}
|
601
|
+
|
645
602
|
/*
|
646
603
|
* call-seq:
|
647
604
|
* Map.hash => hash_value
|
@@ -650,28 +607,18 @@ VALUE Map_eq(VALUE _self, VALUE _other) {
|
|
650
607
|
*/
|
651
608
|
VALUE Map_hash(VALUE _self) {
|
652
609
|
Map* self = ruby_to_Map(_self);
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
self, upb_strtable_iter_key(&it), upb_strtable_iter_keylength(&it));
|
663
|
-
|
664
|
-
upb_value v = upb_strtable_iter_value(&it);
|
665
|
-
void* mem = value_memory(&v);
|
666
|
-
VALUE value = native_slot_get(self->value_type,
|
667
|
-
self->value_type_class,
|
668
|
-
mem);
|
669
|
-
|
670
|
-
h = rb_hash_uint(h, NUM2LONG(rb_funcall(key, hash_sym, 0)));
|
671
|
-
h = rb_hash_uint(h, NUM2LONG(rb_funcall(value, hash_sym, 0)));
|
610
|
+
uint64_t hash = 0;
|
611
|
+
|
612
|
+
size_t iter = UPB_MAP_BEGIN;
|
613
|
+
TypeInfo key_info = {self->key_type};
|
614
|
+
while (upb_mapiter_next(self->map, &iter)) {
|
615
|
+
upb_msgval key = upb_mapiter_key(self->map, iter);
|
616
|
+
upb_msgval val = upb_mapiter_value(self->map, iter);
|
617
|
+
hash = Msgval_GetHash(key, key_info, hash);
|
618
|
+
hash = Msgval_GetHash(val, self->value_type_info, hash);
|
672
619
|
}
|
673
620
|
|
674
|
-
return
|
621
|
+
return LL2NUM(hash);
|
675
622
|
}
|
676
623
|
|
677
624
|
/*
|
@@ -682,25 +629,7 @@ VALUE Map_hash(VALUE _self) {
|
|
682
629
|
*/
|
683
630
|
VALUE Map_to_h(VALUE _self) {
|
684
631
|
Map* self = ruby_to_Map(_self);
|
685
|
-
|
686
|
-
upb_strtable_iter it;
|
687
|
-
for (upb_strtable_begin(&it, &self->table);
|
688
|
-
!upb_strtable_done(&it);
|
689
|
-
upb_strtable_next(&it)) {
|
690
|
-
VALUE key = table_key_to_ruby(
|
691
|
-
self, upb_strtable_iter_key(&it), upb_strtable_iter_keylength(&it));
|
692
|
-
upb_value v = upb_strtable_iter_value(&it);
|
693
|
-
void* mem = value_memory(&v);
|
694
|
-
VALUE value = native_slot_get(self->value_type,
|
695
|
-
self->value_type_class,
|
696
|
-
mem);
|
697
|
-
|
698
|
-
if (self->value_type == UPB_TYPE_MESSAGE) {
|
699
|
-
value = Message_to_h(value);
|
700
|
-
}
|
701
|
-
rb_hash_aset(hash, key, value);
|
702
|
-
}
|
703
|
-
return hash;
|
632
|
+
return Map_CreateHash(self->map, self->key_type, self->value_type_info);
|
704
633
|
}
|
705
634
|
|
706
635
|
/*
|
@@ -714,36 +643,11 @@ VALUE Map_to_h(VALUE _self) {
|
|
714
643
|
VALUE Map_inspect(VALUE _self) {
|
715
644
|
Map* self = ruby_to_Map(_self);
|
716
645
|
|
717
|
-
|
718
|
-
|
719
|
-
|
720
|
-
|
721
|
-
|
722
|
-
upb_strtable_iter it;
|
723
|
-
for (upb_strtable_begin(&it, &self->table);
|
724
|
-
!upb_strtable_done(&it);
|
725
|
-
upb_strtable_next(&it)) {
|
726
|
-
VALUE key = table_key_to_ruby(
|
727
|
-
self, upb_strtable_iter_key(&it), upb_strtable_iter_keylength(&it));
|
728
|
-
|
729
|
-
upb_value v = upb_strtable_iter_value(&it);
|
730
|
-
void* mem = value_memory(&v);
|
731
|
-
VALUE value = native_slot_get(self->value_type,
|
732
|
-
self->value_type_class,
|
733
|
-
mem);
|
734
|
-
|
735
|
-
if (!first) {
|
736
|
-
str = rb_str_cat2(str, ", ");
|
737
|
-
} else {
|
738
|
-
first = false;
|
739
|
-
}
|
740
|
-
str = rb_str_append(str, rb_funcall(key, inspect_sym, 0));
|
741
|
-
str = rb_str_cat2(str, "=>");
|
742
|
-
str = rb_str_append(str, rb_funcall(value, inspect_sym, 0));
|
743
|
-
}
|
744
|
-
|
745
|
-
str = rb_str_cat2(str, "}");
|
746
|
-
return str;
|
646
|
+
StringBuilder* builder = StringBuilder_New();
|
647
|
+
Map_Inspect(builder, self->map, self->key_type, self->value_type_info);
|
648
|
+
VALUE ret = StringBuilder_ToRubyString(builder);
|
649
|
+
StringBuilder_Free(builder);
|
650
|
+
return ret;
|
747
651
|
}
|
748
652
|
|
749
653
|
/*
|
@@ -755,87 +659,11 @@ VALUE Map_inspect(VALUE _self) {
|
|
755
659
|
* in the new copy of this map. Returns the new copy of this map with merged
|
756
660
|
* contents.
|
757
661
|
*/
|
758
|
-
VALUE Map_merge(VALUE _self, VALUE hashmap) {
|
662
|
+
static VALUE Map_merge(VALUE _self, VALUE hashmap) {
|
759
663
|
VALUE dupped = Map_dup(_self);
|
760
664
|
return Map_merge_into_self(dupped, hashmap);
|
761
665
|
}
|
762
666
|
|
763
|
-
static int merge_into_self_callback(VALUE key, VALUE value, VALUE self) {
|
764
|
-
Map_index_set(self, key, value);
|
765
|
-
return ST_CONTINUE;
|
766
|
-
}
|
767
|
-
|
768
|
-
// Used only internally -- shared by #merge and #initialize.
|
769
|
-
VALUE Map_merge_into_self(VALUE _self, VALUE hashmap) {
|
770
|
-
if (TYPE(hashmap) == T_HASH) {
|
771
|
-
rb_hash_foreach(hashmap, merge_into_self_callback, _self);
|
772
|
-
} else if (RB_TYPE_P(hashmap, T_DATA) && RTYPEDDATA_P(hashmap) &&
|
773
|
-
RTYPEDDATA_TYPE(hashmap) == &Map_type) {
|
774
|
-
|
775
|
-
Map* self = ruby_to_Map(_self);
|
776
|
-
Map* other = ruby_to_Map(hashmap);
|
777
|
-
upb_strtable_iter it;
|
778
|
-
|
779
|
-
if (self->key_type != other->key_type ||
|
780
|
-
self->value_type != other->value_type ||
|
781
|
-
self->value_type_class != other->value_type_class) {
|
782
|
-
rb_raise(rb_eArgError, "Attempt to merge Map with mismatching types");
|
783
|
-
}
|
784
|
-
|
785
|
-
for (upb_strtable_begin(&it, &other->table);
|
786
|
-
!upb_strtable_done(&it);
|
787
|
-
upb_strtable_next(&it)) {
|
788
|
-
|
789
|
-
// Replace any existing value by issuing a 'remove' operation first.
|
790
|
-
upb_value v;
|
791
|
-
upb_value oldv;
|
792
|
-
upb_strtable_remove2(&self->table,
|
793
|
-
upb_strtable_iter_key(&it),
|
794
|
-
upb_strtable_iter_keylength(&it),
|
795
|
-
&oldv);
|
796
|
-
|
797
|
-
v = upb_strtable_iter_value(&it);
|
798
|
-
upb_strtable_insert2(&self->table,
|
799
|
-
upb_strtable_iter_key(&it),
|
800
|
-
upb_strtable_iter_keylength(&it),
|
801
|
-
v);
|
802
|
-
}
|
803
|
-
} else {
|
804
|
-
rb_raise(rb_eArgError, "Unknown type merging into Map");
|
805
|
-
}
|
806
|
-
return _self;
|
807
|
-
}
|
808
|
-
|
809
|
-
// Internal method: map iterator initialization (used for serialization).
|
810
|
-
void Map_begin(VALUE _self, Map_iter* iter) {
|
811
|
-
Map* self = ruby_to_Map(_self);
|
812
|
-
iter->self = self;
|
813
|
-
upb_strtable_begin(&iter->it, &self->table);
|
814
|
-
}
|
815
|
-
|
816
|
-
void Map_next(Map_iter* iter) {
|
817
|
-
upb_strtable_next(&iter->it);
|
818
|
-
}
|
819
|
-
|
820
|
-
bool Map_done(Map_iter* iter) {
|
821
|
-
return upb_strtable_done(&iter->it);
|
822
|
-
}
|
823
|
-
|
824
|
-
VALUE Map_iter_key(Map_iter* iter) {
|
825
|
-
return table_key_to_ruby(
|
826
|
-
iter->self,
|
827
|
-
upb_strtable_iter_key(&iter->it),
|
828
|
-
upb_strtable_iter_keylength(&iter->it));
|
829
|
-
}
|
830
|
-
|
831
|
-
VALUE Map_iter_value(Map_iter* iter) {
|
832
|
-
upb_value v = upb_strtable_iter_value(&iter->it);
|
833
|
-
void* mem = value_memory(&v);
|
834
|
-
return native_slot_get(iter->self->value_type,
|
835
|
-
iter->self->value_type_class,
|
836
|
-
mem);
|
837
|
-
}
|
838
|
-
|
839
667
|
void Map_register(VALUE module) {
|
840
668
|
VALUE klass = rb_define_class_under(module, "Map", rb_cObject);
|
841
669
|
rb_define_alloc_func(klass, Map_alloc);
|
@@ -852,8 +680,12 @@ void Map_register(VALUE module) {
|
|
852
680
|
rb_define_method(klass, "delete", Map_delete, 1);
|
853
681
|
rb_define_method(klass, "clear", Map_clear, 0);
|
854
682
|
rb_define_method(klass, "length", Map_length, 0);
|
683
|
+
rb_define_method(klass, "size", Map_length, 0);
|
855
684
|
rb_define_method(klass, "dup", Map_dup, 0);
|
685
|
+
// Also define #clone so that we don't inherit Object#clone.
|
686
|
+
rb_define_method(klass, "clone", Map_dup, 0);
|
856
687
|
rb_define_method(klass, "==", Map_eq, 1);
|
688
|
+
rb_define_method(klass, "freeze", Map_freeze, 0);
|
857
689
|
rb_define_method(klass, "hash", Map_hash, 0);
|
858
690
|
rb_define_method(klass, "to_h", Map_to_h, 0);
|
859
691
|
rb_define_method(klass, "inspect", Map_inspect, 0);
|