google-protobuf 3.5.0 → 3.23.4
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 +5 -5
- 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 +770 -1254
- data/ext/google/protobuf_c/defs.h +107 -0
- data/ext/google/protobuf_c/extconf.rb +15 -5
- data/ext/google/protobuf_c/map.c +312 -474
- data/ext/google/protobuf_c/map.h +66 -0
- data/ext/google/protobuf_c/message.c +1139 -372
- data/ext/google/protobuf_c/message.h +104 -0
- data/ext/google/protobuf_c/protobuf.c +418 -51
- data/ext/google/protobuf_c/protobuf.h +53 -485
- data/ext/google/protobuf_c/repeated_field.c +319 -316
- data/ext/google/protobuf_c/repeated_field.h +63 -0
- data/ext/google/protobuf_c/ruby-upb.c +13974 -0
- data/ext/google/protobuf_c/ruby-upb.h +11780 -0
- data/ext/google/protobuf_c/third_party/utf8_range/LICENSE +22 -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 +21 -0
- data/ext/google/protobuf_c/wrap_memcpy.c +4 -3
- data/lib/google/protobuf/any_pb.rb +26 -5
- data/lib/google/protobuf/api_pb.rb +31 -25
- data/lib/google/protobuf/descriptor_dsl.rb +465 -0
- data/lib/google/protobuf/descriptor_pb.rb +75 -0
- data/lib/google/protobuf/duration_pb.rb +26 -5
- data/lib/google/protobuf/empty_pb.rb +26 -3
- data/lib/google/protobuf/field_mask_pb.rb +26 -4
- data/lib/google/protobuf/message_exts.rb +9 -4
- data/lib/google/protobuf/plugin_pb.rb +47 -0
- data/lib/google/protobuf/repeated_field.rb +17 -4
- data/lib/google/protobuf/source_context_pb.rb +26 -4
- data/lib/google/protobuf/struct_pb.rb +28 -22
- data/lib/google/protobuf/timestamp_pb.rb +26 -5
- data/lib/google/protobuf/type_pb.rb +37 -76
- data/lib/google/protobuf/well_known_types.rb +32 -4
- data/lib/google/protobuf/wrappers_pb.rb +35 -37
- data/lib/google/protobuf.rb +11 -8
- metadata +29 -37
- data/ext/google/protobuf_c/encode_decode.c +0 -1307
- data/ext/google/protobuf_c/storage.c +0 -904
- data/ext/google/protobuf_c/upb.c +0 -14913
- data/ext/google/protobuf_c/upb.h +0 -8969
- data/tests/basic.rb +0 -1403
- data/tests/generated_code_test.rb +0 -19
- data/tests/stress.rb +0 -38
data/ext/google/protobuf_c/map.c
CHANGED
@@ -28,167 +28,232 @@
|
|
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
|
-
Check_Type(key, T_STRING);
|
75
|
-
key = native_slot_encode_and_freeze_string(self->key_type, key);
|
76
|
-
*out_key = RSTRING_PTR(key);
|
77
|
-
*out_length = RSTRING_LEN(key);
|
78
|
-
break;
|
46
|
+
// -----------------------------------------------------------------------------
|
47
|
+
// Map container type.
|
48
|
+
// -----------------------------------------------------------------------------
|
79
49
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
*out_length = native_slot_size(self->key_type);
|
88
|
-
break;
|
50
|
+
typedef struct {
|
51
|
+
const upb_Map* map; // Can convert to mutable when non-frozen.
|
52
|
+
upb_CType key_type;
|
53
|
+
TypeInfo value_type_info;
|
54
|
+
VALUE value_type_class;
|
55
|
+
VALUE arena;
|
56
|
+
} Map;
|
89
57
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
58
|
+
static void Map_mark(void* _self) {
|
59
|
+
Map* self = _self;
|
60
|
+
rb_gc_mark(self->value_type_class);
|
61
|
+
rb_gc_mark(self->arena);
|
62
|
+
}
|
63
|
+
|
64
|
+
const rb_data_type_t Map_type = {
|
65
|
+
"Google::Protobuf::Map",
|
66
|
+
{Map_mark, RUBY_DEFAULT_FREE, NULL},
|
67
|
+
.flags = RUBY_TYPED_FREE_IMMEDIATELY,
|
68
|
+
};
|
69
|
+
|
70
|
+
VALUE cMap;
|
96
71
|
|
97
|
-
|
72
|
+
static Map* ruby_to_Map(VALUE _self) {
|
73
|
+
Map* self;
|
74
|
+
TypedData_Get_Struct(_self, Map, &Map_type, self);
|
75
|
+
return self;
|
98
76
|
}
|
99
77
|
|
100
|
-
static VALUE
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
78
|
+
static VALUE Map_alloc(VALUE klass) {
|
79
|
+
Map* self = ALLOC(Map);
|
80
|
+
self->map = NULL;
|
81
|
+
self->value_type_class = Qnil;
|
82
|
+
self->value_type_info.def.msgdef = NULL;
|
83
|
+
self->arena = Qnil;
|
84
|
+
return TypedData_Wrap_Struct(klass, &Map_type, self);
|
85
|
+
}
|
86
|
+
|
87
|
+
VALUE Map_GetRubyWrapper(upb_Map* map, upb_CType key_type, TypeInfo value_type,
|
88
|
+
VALUE arena) {
|
89
|
+
PBRUBY_ASSERT(map);
|
90
|
+
|
91
|
+
VALUE val = ObjectCache_Get(map);
|
92
|
+
|
93
|
+
if (val == Qnil) {
|
94
|
+
val = Map_alloc(cMap);
|
95
|
+
Map* self;
|
96
|
+
ObjectCache_Add(map, val);
|
97
|
+
TypedData_Get_Struct(val, Map, &Map_type, self);
|
98
|
+
self->map = map;
|
99
|
+
self->arena = arena;
|
100
|
+
self->key_type = key_type;
|
101
|
+
self->value_type_info = value_type;
|
102
|
+
if (self->value_type_info.type == kUpb_CType_Message) {
|
103
|
+
const upb_MessageDef* val_m = self->value_type_info.def.msgdef;
|
104
|
+
self->value_type_class = Descriptor_DefToClass(val_m);
|
109
105
|
}
|
106
|
+
}
|
110
107
|
|
111
|
-
|
112
|
-
|
113
|
-
case UPB_TYPE_INT64:
|
114
|
-
case UPB_TYPE_UINT32:
|
115
|
-
case UPB_TYPE_UINT64:
|
116
|
-
return native_slot_get(self->key_type, Qnil, buf);
|
108
|
+
return val;
|
109
|
+
}
|
117
110
|
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
111
|
+
static VALUE Map_new_this_type(Map* from) {
|
112
|
+
VALUE arena_rb = Arena_new();
|
113
|
+
upb_Map* map = upb_Map_New(Arena_get(arena_rb), from->key_type,
|
114
|
+
from->value_type_info.type);
|
115
|
+
VALUE ret =
|
116
|
+
Map_GetRubyWrapper(map, from->key_type, from->value_type_info, arena_rb);
|
117
|
+
PBRUBY_ASSERT(ruby_to_Map(ret)->value_type_class == from->value_type_class);
|
118
|
+
return ret;
|
122
119
|
}
|
123
120
|
|
124
|
-
static
|
125
|
-
|
121
|
+
static TypeInfo Map_keyinfo(Map* self) {
|
122
|
+
TypeInfo ret;
|
123
|
+
ret.type = self->key_type;
|
124
|
+
ret.def.msgdef = NULL;
|
125
|
+
return ret;
|
126
126
|
}
|
127
127
|
|
128
|
-
|
129
|
-
|
130
|
-
|
128
|
+
static upb_Map* Map_GetMutable(VALUE _self) {
|
129
|
+
rb_check_frozen(_self);
|
130
|
+
return (upb_Map*)ruby_to_Map(_self)->map;
|
131
|
+
}
|
131
132
|
|
132
|
-
const
|
133
|
-
|
134
|
-
|
135
|
-
|
133
|
+
VALUE Map_CreateHash(const upb_Map* map, upb_CType key_type,
|
134
|
+
TypeInfo val_info) {
|
135
|
+
VALUE hash = rb_hash_new();
|
136
|
+
TypeInfo key_info = TypeInfo_from_type(key_type);
|
136
137
|
|
137
|
-
|
138
|
+
if (!map) return hash;
|
138
139
|
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
140
|
+
size_t iter = kUpb_Map_Begin;
|
141
|
+
upb_MessageValue key, val;
|
142
|
+
while (upb_Map_Next(map, &key, &val, &iter)) {
|
143
|
+
VALUE key_val = Convert_UpbToRuby(key, key_info, Qnil);
|
144
|
+
VALUE val_val = Scalar_CreateHash(val, val_info);
|
145
|
+
rb_hash_aset(hash, key_val, val_val);
|
146
|
+
}
|
144
147
|
|
145
|
-
|
146
|
-
|
148
|
+
return hash;
|
149
|
+
}
|
147
150
|
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
self->
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
native_slot_mark(self->value_type, mem);
|
161
|
-
}
|
151
|
+
VALUE Map_deep_copy(VALUE obj) {
|
152
|
+
Map* self = ruby_to_Map(obj);
|
153
|
+
VALUE new_arena_rb = Arena_new();
|
154
|
+
upb_Arena* arena = Arena_get(new_arena_rb);
|
155
|
+
upb_Map* new_map =
|
156
|
+
upb_Map_New(arena, self->key_type, self->value_type_info.type);
|
157
|
+
size_t iter = kUpb_Map_Begin;
|
158
|
+
upb_MessageValue key, val;
|
159
|
+
while (upb_Map_Next(self->map, &key, &val, &iter)) {
|
160
|
+
upb_MessageValue val_copy =
|
161
|
+
Msgval_DeepCopy(val, self->value_type_info, arena);
|
162
|
+
upb_Map_Set(new_map, key, val_copy, arena);
|
162
163
|
}
|
164
|
+
|
165
|
+
return Map_GetRubyWrapper(new_map, self->key_type, self->value_type_info,
|
166
|
+
new_arena_rb);
|
163
167
|
}
|
164
168
|
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
+
const upb_Map* Map_GetUpbMap(VALUE val, const upb_FieldDef* field,
|
170
|
+
upb_Arena* arena) {
|
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_CType(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
|
+
Arena_fuse(self->arena, arena);
|
193
|
+
return self->map;
|
169
194
|
}
|
170
195
|
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
196
|
+
void Map_Inspect(StringBuilder* b, const upb_Map* map, upb_CType key_type,
|
197
|
+
TypeInfo val_type) {
|
198
|
+
bool first = true;
|
199
|
+
TypeInfo key_type_info = {key_type};
|
200
|
+
StringBuilder_Printf(b, "{");
|
201
|
+
if (map) {
|
202
|
+
size_t iter = kUpb_Map_Begin;
|
203
|
+
upb_MessageValue key, val;
|
204
|
+
while (upb_Map_Next(map, &key, &val, &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, "}");
|
176
216
|
}
|
177
217
|
|
178
|
-
|
179
|
-
Map* self = ruby_to_Map(
|
180
|
-
|
181
|
-
|
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_MessageValue key_val =
|
222
|
+
Convert_RubyToUpb(key, "", Map_keyinfo(self), arena);
|
223
|
+
upb_MessageValue val_val =
|
224
|
+
Convert_RubyToUpb(val, "", self->value_type_info, arena);
|
225
|
+
upb_Map_Set(Map_GetMutable(_self), key_val, val_val, arena);
|
226
|
+
return ST_CONTINUE;
|
182
227
|
}
|
183
228
|
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
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_Message* self_msg = Map_GetMutable(_self);
|
239
|
+
|
240
|
+
Arena_fuse(other->arena, arena);
|
241
|
+
|
242
|
+
if (self->key_type != other->key_type ||
|
243
|
+
self->value_type_info.type != other->value_type_info.type ||
|
244
|
+
self->value_type_class != other->value_type_class) {
|
245
|
+
rb_raise(rb_eArgError, "Attempt to merge Map with mismatching types");
|
246
|
+
}
|
247
|
+
|
248
|
+
size_t iter = kUpb_Map_Begin;
|
249
|
+
upb_MessageValue key, val;
|
250
|
+
while (upb_Map_Next(other->map, &key, &val, &iter)) {
|
251
|
+
upb_Map_Set(self_msg, key, val, arena);
|
252
|
+
}
|
253
|
+
} else {
|
254
|
+
rb_raise(rb_eArgError, "Unknown type merging into Map");
|
191
255
|
}
|
256
|
+
return _self;
|
192
257
|
}
|
193
258
|
|
194
259
|
/*
|
@@ -221,9 +286,9 @@ static bool needs_typeclass(upb_fieldtype_t type) {
|
|
221
286
|
* references to underlying objects will be shared if the value type is a
|
222
287
|
* message type.
|
223
288
|
*/
|
224
|
-
VALUE Map_init(int argc, VALUE* argv, VALUE _self) {
|
289
|
+
static VALUE Map_init(int argc, VALUE* argv, VALUE _self) {
|
225
290
|
Map* self = ruby_to_Map(_self);
|
226
|
-
|
291
|
+
VALUE init_arg;
|
227
292
|
|
228
293
|
// We take either two args (:key_type, :value_type), three args (:key_type,
|
229
294
|
// :value_type, "ValueMessageType"), or four args (the above plus an initial
|
@@ -233,39 +298,31 @@ VALUE Map_init(int argc, VALUE* argv, VALUE _self) {
|
|
233
298
|
}
|
234
299
|
|
235
300
|
self->key_type = ruby_to_fieldtype(argv[0]);
|
236
|
-
self->
|
237
|
-
|
301
|
+
self->value_type_info =
|
302
|
+
TypeInfo_FromClass(argc, argv, 1, &self->value_type_class, &init_arg);
|
303
|
+
self->arena = Arena_new();
|
238
304
|
|
239
305
|
// Check that the key type is an allowed type.
|
240
306
|
switch (self->key_type) {
|
241
|
-
case
|
242
|
-
case
|
243
|
-
case
|
244
|
-
case
|
245
|
-
case
|
246
|
-
case
|
247
|
-
case
|
307
|
+
case kUpb_CType_Int32:
|
308
|
+
case kUpb_CType_Int64:
|
309
|
+
case kUpb_CType_UInt32:
|
310
|
+
case kUpb_CType_UInt64:
|
311
|
+
case kUpb_CType_Bool:
|
312
|
+
case kUpb_CType_String:
|
313
|
+
case kUpb_CType_Bytes:
|
248
314
|
// These are OK.
|
249
315
|
break;
|
250
316
|
default:
|
251
317
|
rb_raise(rb_eArgError, "Invalid key type for map.");
|
252
318
|
}
|
253
319
|
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
validate_type_class(self->value_type, self->value_type_class);
|
258
|
-
init_value_arg = 3;
|
259
|
-
}
|
260
|
-
|
261
|
-
// Table value type is always UINT64: this ensures enough space to store the
|
262
|
-
// native_slot value.
|
263
|
-
if (!upb_strtable_init(&self->table, UPB_CTYPE_UINT64)) {
|
264
|
-
rb_raise(rb_eRuntimeError, "Could not allocate table.");
|
265
|
-
}
|
320
|
+
self->map = upb_Map_New(Arena_get(self->arena), self->key_type,
|
321
|
+
self->value_type_info.type);
|
322
|
+
ObjectCache_Add(self->map, _self);
|
266
323
|
|
267
|
-
if (
|
268
|
-
Map_merge_into_self(_self,
|
324
|
+
if (init_arg != Qnil) {
|
325
|
+
Map_merge_into_self(_self, init_arg);
|
269
326
|
}
|
270
327
|
|
271
328
|
return Qnil;
|
@@ -279,24 +336,15 @@ VALUE Map_init(int argc, VALUE* argv, VALUE _self) {
|
|
279
336
|
* Note that Map also includes Enumerable; map thus acts like a normal Ruby
|
280
337
|
* sequence.
|
281
338
|
*/
|
282
|
-
VALUE Map_each(VALUE _self) {
|
339
|
+
static VALUE Map_each(VALUE _self) {
|
283
340
|
Map* self = ruby_to_Map(_self);
|
341
|
+
size_t iter = kUpb_Map_Begin;
|
342
|
+
upb_MessageValue key, val;
|
284
343
|
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
VALUE key = table_key_to_ruby(
|
291
|
-
self, upb_strtable_iter_key(&it), upb_strtable_iter_keylength(&it));
|
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);
|
344
|
+
while (upb_Map_Next(self->map, &key, &val, &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 = kUpb_Map_Begin;
|
314
362
|
VALUE ret = rb_ary_new();
|
315
|
-
|
316
|
-
for (upb_strtable_begin(&it, &self->table);
|
317
|
-
!upb_strtable_done(&it);
|
318
|
-
upb_strtable_next(&it)) {
|
319
|
-
|
320
|
-
VALUE key = table_key_to_ruby(
|
321
|
-
self, upb_strtable_iter_key(&it), upb_strtable_iter_keylength(&it));
|
363
|
+
upb_MessageValue key, val;
|
322
364
|
|
323
|
-
|
365
|
+
while (upb_Map_Next(self->map, &key, &val, &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 = kUpb_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
|
+
upb_MessageValue key, val;
|
384
|
+
|
385
|
+
while (upb_Map_Next(self->map, &key, &val, &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,14 @@ 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_MessageValue key_upb =
|
403
|
+
Convert_RubyToUpb(key, "", Map_keyinfo(self), NULL);
|
404
|
+
upb_MessageValue val;
|
365
405
|
|
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);
|
406
|
+
if (upb_Map_Get(self->map, key_upb, &val)) {
|
407
|
+
return Convert_UpbToRuby(val, self->value_type_info, self->arena);
|
375
408
|
} else {
|
376
409
|
return Qnil;
|
377
410
|
}
|
@@ -385,27 +418,17 @@ VALUE Map_index(VALUE _self, VALUE key) {
|
|
385
418
|
* Throws an exception if the key type is incorrect. Returns the new value that
|
386
419
|
* was just inserted.
|
387
420
|
*/
|
388
|
-
VALUE Map_index_set(VALUE _self, VALUE key, VALUE
|
421
|
+
static VALUE Map_index_set(VALUE _self, VALUE key, VALUE val) {
|
389
422
|
Map* self = ruby_to_Map(_self);
|
423
|
+
upb_Arena* arena = Arena_get(self->arena);
|
424
|
+
upb_MessageValue key_upb =
|
425
|
+
Convert_RubyToUpb(key, "", Map_keyinfo(self), NULL);
|
426
|
+
upb_MessageValue val_upb =
|
427
|
+
Convert_RubyToUpb(val, "", self->value_type_info, arena);
|
390
428
|
|
391
|
-
|
392
|
-
const char* keyval = NULL;
|
393
|
-
size_t length = 0;
|
394
|
-
upb_value v;
|
395
|
-
void* mem;
|
396
|
-
key = table_key(self, key, keybuf, &keyval, &length);
|
397
|
-
|
398
|
-
mem = value_memory(&v);
|
399
|
-
native_slot_set(self->value_type, self->value_type_class, mem, value);
|
429
|
+
upb_Map_Set(Map_GetMutable(_self), key_upb, val_upb, arena);
|
400
430
|
|
401
|
-
|
402
|
-
upb_strtable_remove2(&self->table, keyval, length, NULL);
|
403
|
-
if (!upb_strtable_insert2(&self->table, keyval, length, v)) {
|
404
|
-
rb_raise(rb_eRuntimeError, "Could not insert into table");
|
405
|
-
}
|
406
|
-
|
407
|
-
// Ruby hashmap's :[]= method also returns the inserted value.
|
408
|
-
return value;
|
431
|
+
return val;
|
409
432
|
}
|
410
433
|
|
411
434
|
/*
|
@@ -415,15 +438,12 @@ VALUE Map_index_set(VALUE _self, VALUE key, VALUE value) {
|
|
415
438
|
* Returns true if the given key is present in the map. Throws an exception if
|
416
439
|
* the key has the wrong type.
|
417
440
|
*/
|
418
|
-
VALUE Map_has_key(VALUE _self, VALUE key) {
|
441
|
+
static VALUE Map_has_key(VALUE _self, VALUE key) {
|
419
442
|
Map* self = ruby_to_Map(_self);
|
443
|
+
upb_MessageValue key_upb =
|
444
|
+
Convert_RubyToUpb(key, "", Map_keyinfo(self), NULL);
|
420
445
|
|
421
|
-
|
422
|
-
const char* keyval = NULL;
|
423
|
-
size_t length = 0;
|
424
|
-
key = table_key(self, key, keybuf, &keyval, &length);
|
425
|
-
|
426
|
-
if (upb_strtable_lookup2(&self->table, keyval, length, NULL)) {
|
446
|
+
if (upb_Map_Get(self->map, key_upb, NULL)) {
|
427
447
|
return Qtrue;
|
428
448
|
} else {
|
429
449
|
return Qfalse;
|
@@ -437,18 +457,16 @@ VALUE Map_has_key(VALUE _self, VALUE key) {
|
|
437
457
|
* Deletes the value at the given key, if any, returning either the old value or
|
438
458
|
* nil if none was present. Throws an exception if the key is of the wrong type.
|
439
459
|
*/
|
440
|
-
VALUE Map_delete(VALUE _self, VALUE key) {
|
460
|
+
static VALUE Map_delete(VALUE _self, VALUE key) {
|
441
461
|
Map* self = ruby_to_Map(_self);
|
462
|
+
rb_check_frozen(_self);
|
442
463
|
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
upb_value v;
|
447
|
-
key = table_key(self, key, keybuf, &keyval, &length);
|
464
|
+
upb_MessageValue key_upb =
|
465
|
+
Convert_RubyToUpb(key, "", Map_keyinfo(self), NULL);
|
466
|
+
upb_MessageValue val_upb;
|
448
467
|
|
449
|
-
if (
|
450
|
-
|
451
|
-
return native_slot_get(self->value_type, self->value_type_class, mem);
|
468
|
+
if (upb_Map_Delete(self->map, key_upb, &val_upb)) {
|
469
|
+
return Convert_UpbToRuby(val_upb, self->value_type_info, self->arena);
|
452
470
|
} else {
|
453
471
|
return Qnil;
|
454
472
|
}
|
@@ -460,15 +478,8 @@ VALUE Map_delete(VALUE _self, VALUE key) {
|
|
460
478
|
*
|
461
479
|
* Removes all entries from the map.
|
462
480
|
*/
|
463
|
-
VALUE Map_clear(VALUE _self) {
|
464
|
-
|
465
|
-
|
466
|
-
// Uninit and reinit the table -- this is faster than iterating and doing a
|
467
|
-
// delete-lookup on each key.
|
468
|
-
upb_strtable_uninit(&self->table);
|
469
|
-
if (!upb_strtable_init(&self->table, UPB_CTYPE_INT64)) {
|
470
|
-
rb_raise(rb_eRuntimeError, "Unable to re-initialize table");
|
471
|
-
}
|
481
|
+
static VALUE Map_clear(VALUE _self) {
|
482
|
+
upb_Map_Clear(Map_GetMutable(_self));
|
472
483
|
return Qnil;
|
473
484
|
}
|
474
485
|
|
@@ -478,24 +489,9 @@ VALUE Map_clear(VALUE _self) {
|
|
478
489
|
*
|
479
490
|
* Returns the number of entries (key-value pairs) in the map.
|
480
491
|
*/
|
481
|
-
VALUE Map_length(VALUE _self) {
|
492
|
+
static VALUE Map_length(VALUE _self) {
|
482
493
|
Map* self = ruby_to_Map(_self);
|
483
|
-
return ULL2NUM(
|
484
|
-
}
|
485
|
-
|
486
|
-
static VALUE Map_new_this_type(VALUE _self) {
|
487
|
-
Map* self = ruby_to_Map(_self);
|
488
|
-
VALUE new_map = Qnil;
|
489
|
-
VALUE key_type = fieldtype_to_ruby(self->key_type);
|
490
|
-
VALUE value_type = fieldtype_to_ruby(self->value_type);
|
491
|
-
if (self->value_type_class != Qnil) {
|
492
|
-
new_map = rb_funcall(CLASS_OF(_self), rb_intern("new"), 3,
|
493
|
-
key_type, value_type, self->value_type_class);
|
494
|
-
} else {
|
495
|
-
new_map = rb_funcall(CLASS_OF(_self), rb_intern("new"), 2,
|
496
|
-
key_type, value_type);
|
497
|
-
}
|
498
|
-
return new_map;
|
494
|
+
return ULL2NUM(upb_Map_Size(self->map));
|
499
495
|
}
|
500
496
|
|
501
497
|
/*
|
@@ -505,59 +501,22 @@ static VALUE Map_new_this_type(VALUE _self) {
|
|
505
501
|
* Duplicates this map with a shallow copy. References to all non-primitive
|
506
502
|
* element objects (e.g., submessages) are shared.
|
507
503
|
*/
|
508
|
-
VALUE Map_dup(VALUE _self) {
|
504
|
+
static VALUE Map_dup(VALUE _self) {
|
509
505
|
Map* self = ruby_to_Map(_self);
|
510
|
-
VALUE
|
511
|
-
Map* new_self = ruby_to_Map(
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
!upb_strtable_done(&it);
|
516
|
-
upb_strtable_next(&it)) {
|
517
|
-
|
518
|
-
upb_value v = upb_strtable_iter_value(&it);
|
519
|
-
void* mem = value_memory(&v);
|
520
|
-
upb_value dup;
|
521
|
-
void* dup_mem = value_memory(&dup);
|
522
|
-
native_slot_dup(self->value_type, dup_mem, mem);
|
523
|
-
|
524
|
-
if (!upb_strtable_insert2(&new_self->table,
|
525
|
-
upb_strtable_iter_key(&it),
|
526
|
-
upb_strtable_iter_keylength(&it),
|
527
|
-
dup)) {
|
528
|
-
rb_raise(rb_eRuntimeError, "Error inserting value into new table");
|
529
|
-
}
|
530
|
-
}
|
506
|
+
VALUE new_map_rb = Map_new_this_type(self);
|
507
|
+
Map* new_self = ruby_to_Map(new_map_rb);
|
508
|
+
size_t iter = kUpb_Map_Begin;
|
509
|
+
upb_Arena* arena = Arena_get(new_self->arena);
|
510
|
+
upb_Map* new_map = Map_GetMutable(new_map_rb);
|
531
511
|
|
532
|
-
|
533
|
-
}
|
512
|
+
Arena_fuse(self->arena, arena);
|
534
513
|
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
VALUE new_map = Map_new_this_type(_self);
|
539
|
-
Map* new_self = ruby_to_Map(new_map);
|
540
|
-
|
541
|
-
upb_strtable_iter it;
|
542
|
-
for (upb_strtable_begin(&it, &self->table);
|
543
|
-
!upb_strtable_done(&it);
|
544
|
-
upb_strtable_next(&it)) {
|
545
|
-
|
546
|
-
upb_value v = upb_strtable_iter_value(&it);
|
547
|
-
void* mem = value_memory(&v);
|
548
|
-
upb_value dup;
|
549
|
-
void* dup_mem = value_memory(&dup);
|
550
|
-
native_slot_deep_copy(self->value_type, dup_mem, mem);
|
551
|
-
|
552
|
-
if (!upb_strtable_insert2(&new_self->table,
|
553
|
-
upb_strtable_iter_key(&it),
|
554
|
-
upb_strtable_iter_keylength(&it),
|
555
|
-
dup)) {
|
556
|
-
rb_raise(rb_eRuntimeError, "Error inserting value into new table");
|
557
|
-
}
|
514
|
+
upb_MessageValue key, val;
|
515
|
+
while (upb_Map_Next(self->map, &key, &val, &iter)) {
|
516
|
+
upb_Map_Set(new_map, key, val, arena);
|
558
517
|
}
|
559
518
|
|
560
|
-
return
|
519
|
+
return new_map_rb;
|
561
520
|
}
|
562
521
|
|
563
522
|
/*
|
@@ -576,12 +535,11 @@ VALUE Map_deep_copy(VALUE _self) {
|
|
576
535
|
VALUE Map_eq(VALUE _self, VALUE _other) {
|
577
536
|
Map* self = ruby_to_Map(_self);
|
578
537
|
Map* other;
|
579
|
-
upb_strtable_iter it;
|
580
538
|
|
581
539
|
// Allow comparisons to Ruby hashmaps by converting to a temporary Map
|
582
540
|
// instance. Slow, but workable.
|
583
541
|
if (TYPE(_other) == T_HASH) {
|
584
|
-
VALUE other_map = Map_new_this_type(
|
542
|
+
VALUE other_map = Map_new_this_type(self);
|
585
543
|
Map_merge_into_self(other_map, _other);
|
586
544
|
_other = other_map;
|
587
545
|
}
|
@@ -592,35 +550,26 @@ VALUE Map_eq(VALUE _self, VALUE _other) {
|
|
592
550
|
return Qtrue;
|
593
551
|
}
|
594
552
|
if (self->key_type != other->key_type ||
|
595
|
-
self->
|
553
|
+
self->value_type_info.type != other->value_type_info.type ||
|
596
554
|
self->value_type_class != other->value_type_class) {
|
597
555
|
return Qfalse;
|
598
556
|
}
|
599
|
-
if (
|
557
|
+
if (upb_Map_Size(self->map) != upb_Map_Size(other->map)) {
|
600
558
|
return Qfalse;
|
601
559
|
}
|
602
560
|
|
603
561
|
// For each member of self, check that an equal member exists at the same key
|
604
562
|
// in other.
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
void* mem = value_memory(&v);
|
611
|
-
upb_value other_v;
|
612
|
-
void* other_mem = value_memory(&other_v);
|
613
|
-
|
614
|
-
if (!upb_strtable_lookup2(&other->table,
|
615
|
-
upb_strtable_iter_key(&it),
|
616
|
-
upb_strtable_iter_keylength(&it),
|
617
|
-
&other_v)) {
|
563
|
+
size_t iter = kUpb_Map_Begin;
|
564
|
+
upb_MessageValue key, val;
|
565
|
+
while (upb_Map_Next(self->map, &key, &val, &iter)) {
|
566
|
+
upb_MessageValue other_val;
|
567
|
+
if (!upb_Map_Get(other->map, key, &other_val)) {
|
618
568
|
// Not present in other map.
|
619
569
|
return Qfalse;
|
620
570
|
}
|
621
|
-
|
622
|
-
|
623
|
-
// Present, but value not equal.
|
571
|
+
if (!Msgval_IsEqual(val, other_val, self->value_type_info)) {
|
572
|
+
// Present but different value.
|
624
573
|
return Qfalse;
|
625
574
|
}
|
626
575
|
}
|
@@ -628,6 +577,22 @@ VALUE Map_eq(VALUE _self, VALUE _other) {
|
|
628
577
|
return Qtrue;
|
629
578
|
}
|
630
579
|
|
580
|
+
/*
|
581
|
+
* call-seq:
|
582
|
+
* Message.freeze => self
|
583
|
+
*
|
584
|
+
* Freezes the message object. We have to intercept this so we can pin the
|
585
|
+
* Ruby object into memory so we don't forget it's frozen.
|
586
|
+
*/
|
587
|
+
static VALUE Map_freeze(VALUE _self) {
|
588
|
+
Map* self = ruby_to_Map(_self);
|
589
|
+
if (!RB_OBJ_FROZEN(_self)) {
|
590
|
+
Arena_Pin(self->arena, _self);
|
591
|
+
RB_OBJ_FREEZE(_self);
|
592
|
+
}
|
593
|
+
return _self;
|
594
|
+
}
|
595
|
+
|
631
596
|
/*
|
632
597
|
* call-seq:
|
633
598
|
* Map.hash => hash_value
|
@@ -636,28 +601,17 @@ VALUE Map_eq(VALUE _self, VALUE _other) {
|
|
636
601
|
*/
|
637
602
|
VALUE Map_hash(VALUE _self) {
|
638
603
|
Map* self = ruby_to_Map(_self);
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
VALUE key = table_key_to_ruby(
|
648
|
-
self, upb_strtable_iter_key(&it), upb_strtable_iter_keylength(&it));
|
649
|
-
|
650
|
-
upb_value v = upb_strtable_iter_value(&it);
|
651
|
-
void* mem = value_memory(&v);
|
652
|
-
VALUE value = native_slot_get(self->value_type,
|
653
|
-
self->value_type_class,
|
654
|
-
mem);
|
655
|
-
|
656
|
-
h = rb_hash_uint(h, NUM2LONG(rb_funcall(key, hash_sym, 0)));
|
657
|
-
h = rb_hash_uint(h, NUM2LONG(rb_funcall(value, hash_sym, 0)));
|
604
|
+
uint64_t hash = 0;
|
605
|
+
|
606
|
+
size_t iter = kUpb_Map_Begin;
|
607
|
+
TypeInfo key_info = {self->key_type};
|
608
|
+
upb_MessageValue key, val;
|
609
|
+
while (upb_Map_Next(self->map, &key, &val, &iter)) {
|
610
|
+
hash = Msgval_GetHash(key, key_info, hash);
|
611
|
+
hash = Msgval_GetHash(val, self->value_type_info, hash);
|
658
612
|
}
|
659
613
|
|
660
|
-
return
|
614
|
+
return LL2NUM(hash);
|
661
615
|
}
|
662
616
|
|
663
617
|
/*
|
@@ -668,25 +622,7 @@ VALUE Map_hash(VALUE _self) {
|
|
668
622
|
*/
|
669
623
|
VALUE Map_to_h(VALUE _self) {
|
670
624
|
Map* self = ruby_to_Map(_self);
|
671
|
-
|
672
|
-
upb_strtable_iter it;
|
673
|
-
for (upb_strtable_begin(&it, &self->table);
|
674
|
-
!upb_strtable_done(&it);
|
675
|
-
upb_strtable_next(&it)) {
|
676
|
-
VALUE key = table_key_to_ruby(
|
677
|
-
self, upb_strtable_iter_key(&it), upb_strtable_iter_keylength(&it));
|
678
|
-
upb_value v = upb_strtable_iter_value(&it);
|
679
|
-
void* mem = value_memory(&v);
|
680
|
-
VALUE value = native_slot_get(self->value_type,
|
681
|
-
self->value_type_class,
|
682
|
-
mem);
|
683
|
-
|
684
|
-
if (self->value_type == UPB_TYPE_MESSAGE) {
|
685
|
-
value = Message_to_h(value);
|
686
|
-
}
|
687
|
-
rb_hash_aset(hash, key, value);
|
688
|
-
}
|
689
|
-
return hash;
|
625
|
+
return Map_CreateHash(self->map, self->key_type, self->value_type_info);
|
690
626
|
}
|
691
627
|
|
692
628
|
/*
|
@@ -700,36 +636,11 @@ VALUE Map_to_h(VALUE _self) {
|
|
700
636
|
VALUE Map_inspect(VALUE _self) {
|
701
637
|
Map* self = ruby_to_Map(_self);
|
702
638
|
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
upb_strtable_iter it;
|
709
|
-
for (upb_strtable_begin(&it, &self->table);
|
710
|
-
!upb_strtable_done(&it);
|
711
|
-
upb_strtable_next(&it)) {
|
712
|
-
VALUE key = table_key_to_ruby(
|
713
|
-
self, upb_strtable_iter_key(&it), upb_strtable_iter_keylength(&it));
|
714
|
-
|
715
|
-
upb_value v = upb_strtable_iter_value(&it);
|
716
|
-
void* mem = value_memory(&v);
|
717
|
-
VALUE value = native_slot_get(self->value_type,
|
718
|
-
self->value_type_class,
|
719
|
-
mem);
|
720
|
-
|
721
|
-
if (!first) {
|
722
|
-
str = rb_str_cat2(str, ", ");
|
723
|
-
} else {
|
724
|
-
first = false;
|
725
|
-
}
|
726
|
-
str = rb_str_append(str, rb_funcall(key, inspect_sym, 0));
|
727
|
-
str = rb_str_cat2(str, "=>");
|
728
|
-
str = rb_str_append(str, rb_funcall(value, inspect_sym, 0));
|
729
|
-
}
|
730
|
-
|
731
|
-
str = rb_str_cat2(str, "}");
|
732
|
-
return str;
|
639
|
+
StringBuilder* builder = StringBuilder_New();
|
640
|
+
Map_Inspect(builder, self->map, self->key_type, self->value_type_info);
|
641
|
+
VALUE ret = StringBuilder_ToRubyString(builder);
|
642
|
+
StringBuilder_Free(builder);
|
643
|
+
return ret;
|
733
644
|
}
|
734
645
|
|
735
646
|
/*
|
@@ -741,92 +652,16 @@ VALUE Map_inspect(VALUE _self) {
|
|
741
652
|
* in the new copy of this map. Returns the new copy of this map with merged
|
742
653
|
* contents.
|
743
654
|
*/
|
744
|
-
VALUE Map_merge(VALUE _self, VALUE hashmap) {
|
655
|
+
static VALUE Map_merge(VALUE _self, VALUE hashmap) {
|
745
656
|
VALUE dupped = Map_dup(_self);
|
746
657
|
return Map_merge_into_self(dupped, hashmap);
|
747
658
|
}
|
748
659
|
|
749
|
-
static int merge_into_self_callback(VALUE key, VALUE value, VALUE self) {
|
750
|
-
Map_index_set(self, key, value);
|
751
|
-
return ST_CONTINUE;
|
752
|
-
}
|
753
|
-
|
754
|
-
// Used only internally -- shared by #merge and #initialize.
|
755
|
-
VALUE Map_merge_into_self(VALUE _self, VALUE hashmap) {
|
756
|
-
if (TYPE(hashmap) == T_HASH) {
|
757
|
-
rb_hash_foreach(hashmap, merge_into_self_callback, _self);
|
758
|
-
} else if (RB_TYPE_P(hashmap, T_DATA) && RTYPEDDATA_P(hashmap) &&
|
759
|
-
RTYPEDDATA_TYPE(hashmap) == &Map_type) {
|
760
|
-
|
761
|
-
Map* self = ruby_to_Map(_self);
|
762
|
-
Map* other = ruby_to_Map(hashmap);
|
763
|
-
upb_strtable_iter it;
|
764
|
-
|
765
|
-
if (self->key_type != other->key_type ||
|
766
|
-
self->value_type != other->value_type ||
|
767
|
-
self->value_type_class != other->value_type_class) {
|
768
|
-
rb_raise(rb_eArgError, "Attempt to merge Map with mismatching types");
|
769
|
-
}
|
770
|
-
|
771
|
-
for (upb_strtable_begin(&it, &other->table);
|
772
|
-
!upb_strtable_done(&it);
|
773
|
-
upb_strtable_next(&it)) {
|
774
|
-
|
775
|
-
// Replace any existing value by issuing a 'remove' operation first.
|
776
|
-
upb_value v;
|
777
|
-
upb_value oldv;
|
778
|
-
upb_strtable_remove2(&self->table,
|
779
|
-
upb_strtable_iter_key(&it),
|
780
|
-
upb_strtable_iter_keylength(&it),
|
781
|
-
&oldv);
|
782
|
-
|
783
|
-
v = upb_strtable_iter_value(&it);
|
784
|
-
upb_strtable_insert2(&self->table,
|
785
|
-
upb_strtable_iter_key(&it),
|
786
|
-
upb_strtable_iter_keylength(&it),
|
787
|
-
v);
|
788
|
-
}
|
789
|
-
} else {
|
790
|
-
rb_raise(rb_eArgError, "Unknown type merging into Map");
|
791
|
-
}
|
792
|
-
return _self;
|
793
|
-
}
|
794
|
-
|
795
|
-
// Internal method: map iterator initialization (used for serialization).
|
796
|
-
void Map_begin(VALUE _self, Map_iter* iter) {
|
797
|
-
Map* self = ruby_to_Map(_self);
|
798
|
-
iter->self = self;
|
799
|
-
upb_strtable_begin(&iter->it, &self->table);
|
800
|
-
}
|
801
|
-
|
802
|
-
void Map_next(Map_iter* iter) {
|
803
|
-
upb_strtable_next(&iter->it);
|
804
|
-
}
|
805
|
-
|
806
|
-
bool Map_done(Map_iter* iter) {
|
807
|
-
return upb_strtable_done(&iter->it);
|
808
|
-
}
|
809
|
-
|
810
|
-
VALUE Map_iter_key(Map_iter* iter) {
|
811
|
-
return table_key_to_ruby(
|
812
|
-
iter->self,
|
813
|
-
upb_strtable_iter_key(&iter->it),
|
814
|
-
upb_strtable_iter_keylength(&iter->it));
|
815
|
-
}
|
816
|
-
|
817
|
-
VALUE Map_iter_value(Map_iter* iter) {
|
818
|
-
upb_value v = upb_strtable_iter_value(&iter->it);
|
819
|
-
void* mem = value_memory(&v);
|
820
|
-
return native_slot_get(iter->self->value_type,
|
821
|
-
iter->self->value_type_class,
|
822
|
-
mem);
|
823
|
-
}
|
824
|
-
|
825
660
|
void Map_register(VALUE module) {
|
826
661
|
VALUE klass = rb_define_class_under(module, "Map", rb_cObject);
|
827
662
|
rb_define_alloc_func(klass, Map_alloc);
|
828
|
-
cMap = klass;
|
829
663
|
rb_gc_register_address(&cMap);
|
664
|
+
cMap = klass;
|
830
665
|
|
831
666
|
rb_define_method(klass, "initialize", Map_init, -1);
|
832
667
|
rb_define_method(klass, "each", Map_each, 0);
|
@@ -838,10 +673,13 @@ void Map_register(VALUE module) {
|
|
838
673
|
rb_define_method(klass, "delete", Map_delete, 1);
|
839
674
|
rb_define_method(klass, "clear", Map_clear, 0);
|
840
675
|
rb_define_method(klass, "length", Map_length, 0);
|
676
|
+
rb_define_method(klass, "size", Map_length, 0);
|
841
677
|
rb_define_method(klass, "dup", Map_dup, 0);
|
678
|
+
// Also define #clone so that we don't inherit Object#clone.
|
679
|
+
rb_define_method(klass, "clone", Map_dup, 0);
|
842
680
|
rb_define_method(klass, "==", Map_eq, 1);
|
681
|
+
rb_define_method(klass, "freeze", Map_freeze, 0);
|
843
682
|
rb_define_method(klass, "hash", Map_hash, 0);
|
844
|
-
rb_define_method(klass, "to_hash", Map_to_h, 0);
|
845
683
|
rb_define_method(klass, "to_h", Map_to_h, 0);
|
846
684
|
rb_define_method(klass, "inspect", Map_inspect, 0);
|
847
685
|
rb_define_method(klass, "merge", Map_merge, 1);
|