Class: Google::Protobuf::Map

Inherits:
Object
  • Object
show all
Extended by:
Internal::Convert
Includes:
Enumerable, Internal::Convert
Defined in:
lib/google/protobuf/ffi/map.rb

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Internal::Convert

convert_ruby_to_upb, convert_upb_to_ruby, map_create_hash, message_value_deep_copy, repeated_field_create_array, scalar_create_hash, to_h_internal

Class Method Details

.new(key_type, value_type, value_typeclass = nil, init_hashmap = {}) ⇒ Object

call-seq:

Map.new(key_type, value_type, value_typeclass = nil, init_hashmap = {})
=> new map

Allocates a new Map container. This constructor may be called with 2, 3, or 4 arguments. The first two arguments are always present and are symbols (taking on the same values as field-type symbols in message descriptors) that indicate the type of the map key and value fields.

The supported key types are: :int32, :int64, :uint32, :uint64, :bool, :string, :bytes.

The supported value types are: :int32, :int64, :uint32, :uint64, :bool, :string, :bytes, :enum, :message.

The third argument, value_typeclass, must be present if value_type is :enum or :message. As in RepeatedField#new, this argument must be a message class (for :message) or enum module (for :enum).

The last argument, if present, provides initial content for map. Note that this may be an ordinary Ruby hashmap or another Map instance with identical key and value types. Also note that this argument may be present whether or not value_typeclass is present (and it is unambiguously separate from value_typeclass because value_typeclass’s presence is strictly determined by value_type). The contents of this initial hashmap or Map instance are shallow-copied into the new Map: the original map is unmodified, but references to underlying objects will be shared if the value type is a message type.



56
57
58
59
60
61
62
63
64
65
66
# File 'lib/google/protobuf/ffi/map.rb', line 56

def self.new(key_type, value_type, value_typeclass = nil, init_hashmap = {})
  instance = allocate
  # TODO This argument mangling doesn't agree with the type signature,
  # but does align with the text of the comments and is required to make unit tests pass.
  if init_hashmap.empty? and ![:enum, :message].include?(value_type)
    init_hashmap = value_typeclass
    value_typeclass = nil
  end
  instance.send(:initialize, key_type, value_type, value_type_class: value_typeclass, initial_values: init_hashmap)
  instance
end

Instance Method Details

#==(other) ⇒ Object

call-seq:

Map.==(other) => boolean

Compares this map to another. Maps are equal if they have identical key sets, and for each key, the values in both maps compare equal. Elements are compared as per normal Ruby semantics, by calling their :== methods (or performing a more efficient comparison for primitive types).

Maps with dissimilar key types or value types/typeclasses are never equal, even if value comparison (for example, between integers and floats) would have otherwise indicated that every element has equal value.



194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
# File 'lib/google/protobuf/ffi/map.rb', line 194

def ==(other)
  if other.is_a? Hash
    other = self.class.send(:private_constructor, key_type, value_type, descriptor, initial_values: other)
  elsif !other.is_a? Google::Protobuf::Map
    return false
  end

  return true if object_id == other.object_id
  return false if key_type != other.send(:key_type) or value_type != other.send(:value_type) or descriptor != other.send(:descriptor) or length != other.length
  other_map_ptr = other.send(:map_ptr)
  each_msg_val do |key_message_value, value_message_value|
    other_value = Google::Protobuf::FFI::MessageValue.new
    return false unless Google::Protobuf::FFI.map_get(other_map_ptr, key_message_value, other_value)
    return false unless Google::Protobuf::FFI.message_value_equal(value_message_value, other_value, value_type, descriptor)
  end
  true
end

#[](key) ⇒ Object

call-seq:

  Map.[](key) => value

Accesses the element at the given key. Throws an exception if the key type is
incorrect. Returns nil when the key is not present in the map.


102
103
104
105
106
107
108
# File 'lib/google/protobuf/ffi/map.rb', line 102

def [](key)
  value = Google::Protobuf::FFI::MessageValue.new
  key_message_value = convert_ruby_to_upb(key, arena, key_type, nil)
  if Google::Protobuf::FFI.map_get(@map_ptr, key_message_value, value)
     convert_upb_to_ruby(value, value_type, descriptor, arena)
  end
end

#[]=(key, value) ⇒ Object

call-seq:

Map.[]=(key, value) => value

Inserts or overwrites the value at the given key with the given new value. Throws an exception if the key type is incorrect. Returns the new value that was just inserted.



117
118
119
120
121
122
123
# File 'lib/google/protobuf/ffi/map.rb', line 117

def []=(key, value)
  raise FrozenError.new "can't modify frozen #{self.class}" if frozen?
  key_message_value = convert_ruby_to_upb(key, arena, key_type, nil)
  value_message_value = convert_ruby_to_upb(value, arena, value_type, descriptor)
  Google::Protobuf::FFI.map_set(@map_ptr, key_message_value, value_message_value, arena)
  value
end

#clearObject



147
148
149
150
151
# File 'lib/google/protobuf/ffi/map.rb', line 147

def clear
  raise FrozenError.new "can't modify frozen #{self.class}" if frozen?
  Google::Protobuf::FFI.map_clear(@map_ptr)
  nil
end

#delete(key) ⇒ Object

call-seq:

Map.delete(key) => old_value

Deletes the value at the given key, if any, returning either the old value or nil if none was present. Throws an exception if the key is of the wrong type.



136
137
138
139
140
141
142
143
144
145
# File 'lib/google/protobuf/ffi/map.rb', line 136

def delete(key)
  raise FrozenError.new "can't modify frozen #{self.class}" if frozen?
  value = Google::Protobuf::FFI::MessageValue.new
  key_message_value = convert_ruby_to_upb(key, arena, key_type, nil)
  if Google::Protobuf::FFI.map_delete(@map_ptr, key_message_value, value)
    convert_upb_to_ruby(value, value_type, descriptor, arena)
  else
    nil
  end
end

#dupObject Also known as: clone

call-seq:

Map.dup => new_map

Duplicates this map with a shallow copy. References to all non-primitive element objects (e.g., submessages) are shared.



177
178
179
# File 'lib/google/protobuf/ffi/map.rb', line 177

def dup
  internal_dup
end

#each(&block) ⇒ Object

call-seq:

Map.each(&block)

Invokes &block on each |key, value| pair in the map, in unspecified order. Note that Map also includes Enumerable; map thus acts like a normal Ruby sequence.



271
272
273
274
275
276
277
278
# File 'lib/google/protobuf/ffi/map.rb', line 271

def each &block
  each_msg_val do |key_message_value, value_message_value|
    key_value = convert_upb_to_ruby(key_message_value, key_type)
    value_value = convert_upb_to_ruby(value_message_value, value_type, descriptor, arena)
    yield key_value, value_value
  end
  nil
end

#freezeObject



158
159
160
161
162
163
164
165
166
167
168
169
# File 'lib/google/protobuf/ffi/map.rb', line 158

def freeze
  return self if frozen?
  super
  @arena.pin self
  if value_type == :message
    internal_iterator do |iterator|
      value_message_value = Google::Protobuf::FFI.map_value(@map_ptr, iterator)
      convert_upb_to_ruby(value_message_value, value_type, descriptor, arena).freeze
    end
  end
  self
end

#has_key?(key) ⇒ Boolean

Returns:

  • (Boolean)


125
126
127
128
# File 'lib/google/protobuf/ffi/map.rb', line 125

def has_key?(key)
  key_message_value = convert_ruby_to_upb(key, arena, key_type, nil)
  Google::Protobuf::FFI.map_get(@map_ptr, key_message_value, nil)
end

#hashObject



212
213
214
215
216
217
218
219
# File 'lib/google/protobuf/ffi/map.rb', line 212

def hash
  return_value = 0
  each_msg_val do |key_message_value, value_message_value|
    return_value = Google::Protobuf::FFI.message_value_hash(key_message_value, key_type, nil, return_value)
    return_value = Google::Protobuf::FFI.message_value_hash(value_message_value, value_type, descriptor, return_value)
  end
  return_value
end

#inspectObject



237
238
239
240
241
242
243
244
245
246
247
248
249
250
# File 'lib/google/protobuf/ffi/map.rb', line 237

def inspect
  key_value_pairs = []
  each_msg_val do |key_message_value, value_message_value|
    key_string = convert_upb_to_ruby(key_message_value, key_type).inspect
    if value_type == :message
      sub_msg_descriptor = Google::Protobuf::FFI.get_subtype_as_message(descriptor)
      value_string = sub_msg_descriptor.msgclass.send(:inspect_internal, value_message_value[:msg_val])
    else
      value_string = convert_upb_to_ruby(value_message_value, value_type, descriptor).inspect
    end
    key_value_pairs << "#{key_string}=>#{value_string}"
  end
  "{#{key_value_pairs.join(", ")}}"
end

#keysObject

call-seq:

Map.keys => [list_of_keys]

Returns the list of keys contained in the map, in unspecified order.



73
74
75
76
77
78
79
80
# File 'lib/google/protobuf/ffi/map.rb', line 73

def keys
  return_value = []
  internal_iterator do |iterator|
    key_message_value = Google::Protobuf::FFI.map_key(@map_ptr, iterator)
    return_value << convert_upb_to_ruby(key_message_value, key_type)
  end
  return_value
end

#lengthObject Also known as: size



153
154
155
# File 'lib/google/protobuf/ffi/map.rb', line 153

def length
  Google::Protobuf::FFI.map_size(@map_ptr)
end

#merge(other) ⇒ Object

call-seq:

Map.merge(other_map) => map

Copies key/value pairs from other_map into a copy of this map. If a key is set in other_map and this map, the value from other_map overwrites the value in the new copy of this map. Returns the new copy of this map with merged contents.



260
261
262
# File 'lib/google/protobuf/ffi/map.rb', line 260

def merge(other)
  internal_merge(other)
end

#to_hObject

call-seq:

Map.to_h => {}

Returns a Ruby Hash object containing all the values within the map



226
227
228
229
230
231
232
233
234
235
# File 'lib/google/protobuf/ffi/map.rb', line 226

def to_h
  return {} if map_ptr.nil? or map_ptr.null?
  return_value = {}
  each_msg_val do |key_message_value, value_message_value|
    hash_key = convert_upb_to_ruby(key_message_value, key_type)
    hash_value = scalar_create_hash(value_message_value, value_type, msg_or_enum_descriptor: descriptor)
    return_value[hash_key] = hash_value
  end
  return_value
end

#valuesObject

call-seq:

Map.values => [list_of_values]

Returns the list of values contained in the map, in unspecified order.



87
88
89
90
91
92
93
94
# File 'lib/google/protobuf/ffi/map.rb', line 87

def values
  return_value = []
  internal_iterator do |iterator|
    value_message_value = Google::Protobuf::FFI.map_value(@map_ptr, iterator)
    return_value << convert_upb_to_ruby(value_message_value, value_type, descriptor, arena)
  end
  return_value
end