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