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