diff options
Diffstat (limited to 'third_party/protobuf/3.2.0/ruby/ext/google/protobuf_c/map.c')
-rw-r--r-- | third_party/protobuf/3.2.0/ruby/ext/google/protobuf_c/map.c | 810 |
1 files changed, 0 insertions, 810 deletions
diff --git a/third_party/protobuf/3.2.0/ruby/ext/google/protobuf_c/map.c b/third_party/protobuf/3.2.0/ruby/ext/google/protobuf_c/map.c deleted file mode 100644 index 12f1f9ddd5..0000000000 --- a/third_party/protobuf/3.2.0/ruby/ext/google/protobuf_c/map.c +++ /dev/null @@ -1,810 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2014 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "protobuf.h" - -// ----------------------------------------------------------------------------- -// Basic map operations on top of upb's strtable. -// -// Note that we roll our own `Map` container here because, as for -// `RepeatedField`, we want a strongly-typed container. This is so that any user -// errors due to incorrect map key or value types are raised as close as -// possible to the error site, rather than at some deferred point (e.g., -// serialization). -// -// We build our `Map` on top of upb_strtable so that we're able to take -// advantage of the native_slot storage abstraction, as RepeatedField does. -// (This is not quite a perfect mapping -- see the key conversions below -- but -// gives us full support and error-checking for all value types for free.) -// ----------------------------------------------------------------------------- - -// Map values are stored using the native_slot abstraction (as with repeated -// field values), but keys are a bit special. Since we use a strtable, we need -// to store keys as sequences of bytes such that equality of those bytes maps -// one-to-one to equality of keys. We store strings directly (i.e., they map to -// their own bytes) and integers as native integers (using the native_slot -// abstraction). - -// Note that there is another tradeoff here in keeping string keys as native -// strings rather than Ruby strings: traversing the Map requires conversion to -// Ruby string values on every traversal, potentially creating more garbage. We -// should consider ways to cache a Ruby version of the key if this becomes an -// issue later. - -// Forms a key to use with the underlying strtable from a Ruby key value. |buf| -// must point to TABLE_KEY_BUF_LENGTH bytes of temporary space, used to -// construct a key byte sequence if needed. |out_key| and |out_length| provide -// the resulting key data/length. -#define TABLE_KEY_BUF_LENGTH 8 // sizeof(uint64_t) -static VALUE table_key(Map* self, VALUE key, - char* buf, - const char** out_key, - size_t* out_length) { - switch (self->key_type) { - case UPB_TYPE_BYTES: - case UPB_TYPE_STRING: - // Strings: use string content directly. - Check_Type(key, T_STRING); - key = native_slot_encode_and_freeze_string(self->key_type, key); - *out_key = RSTRING_PTR(key); - *out_length = RSTRING_LEN(key); - break; - - case UPB_TYPE_BOOL: - case UPB_TYPE_INT32: - case UPB_TYPE_INT64: - case UPB_TYPE_UINT32: - case UPB_TYPE_UINT64: - native_slot_set(self->key_type, Qnil, buf, key); - *out_key = buf; - *out_length = native_slot_size(self->key_type); - break; - - default: - // Map constructor should not allow a Map with another key type to be - // constructed. - assert(false); - break; - } - - return key; -} - -static VALUE table_key_to_ruby(Map* self, const char* buf, size_t length) { - switch (self->key_type) { - case UPB_TYPE_BYTES: - case UPB_TYPE_STRING: { - VALUE ret = rb_str_new(buf, length); - rb_enc_associate(ret, - (self->key_type == UPB_TYPE_BYTES) ? - kRubyString8bitEncoding : kRubyStringUtf8Encoding); - return ret; - } - - case UPB_TYPE_BOOL: - case UPB_TYPE_INT32: - case UPB_TYPE_INT64: - case UPB_TYPE_UINT32: - case UPB_TYPE_UINT64: - return native_slot_get(self->key_type, Qnil, buf); - - default: - assert(false); - return Qnil; - } -} - -static void* value_memory(upb_value* v) { - return (void*)(&v->val); -} - -// ----------------------------------------------------------------------------- -// Map container type. -// ----------------------------------------------------------------------------- - -const rb_data_type_t Map_type = { - "Google::Protobuf::Map", - { Map_mark, Map_free, NULL }, -}; - -VALUE cMap; - -Map* ruby_to_Map(VALUE _self) { - Map* self; - TypedData_Get_Struct(_self, Map, &Map_type, self); - return self; -} - -void Map_mark(void* _self) { - Map* self = _self; - - rb_gc_mark(self->value_type_class); - - if (self->value_type == UPB_TYPE_STRING || - self->value_type == UPB_TYPE_BYTES || - self->value_type == UPB_TYPE_MESSAGE) { - upb_strtable_iter it; - for (upb_strtable_begin(&it, &self->table); - !upb_strtable_done(&it); - upb_strtable_next(&it)) { - upb_value v = upb_strtable_iter_value(&it); - void* mem = value_memory(&v); - native_slot_mark(self->value_type, mem); - } - } -} - -void Map_free(void* _self) { - Map* self = _self; - upb_strtable_uninit(&self->table); - xfree(self); -} - -VALUE Map_alloc(VALUE klass) { - Map* self = ALLOC(Map); - memset(self, 0, sizeof(Map)); - self->value_type_class = Qnil; - return TypedData_Wrap_Struct(klass, &Map_type, self); -} - -static bool needs_typeclass(upb_fieldtype_t type) { - switch (type) { - case UPB_TYPE_MESSAGE: - case UPB_TYPE_ENUM: - return true; - default: - return false; - } -} - -/* - * 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. - */ -VALUE Map_init(int argc, VALUE* argv, VALUE _self) { - Map* self = ruby_to_Map(_self); - int init_value_arg; - - // We take either two args (:key_type, :value_type), three args (:key_type, - // :value_type, "ValueMessageType"), or four args (the above plus an initial - // hashmap). - if (argc < 2 || argc > 4) { - rb_raise(rb_eArgError, "Map constructor expects 2, 3 or 4 arguments."); - } - - self->key_type = ruby_to_fieldtype(argv[0]); - self->value_type = ruby_to_fieldtype(argv[1]); - - // Check that the key type is an allowed type. - switch (self->key_type) { - case UPB_TYPE_INT32: - case UPB_TYPE_INT64: - case UPB_TYPE_UINT32: - case UPB_TYPE_UINT64: - case UPB_TYPE_BOOL: - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: - // These are OK. - break; - default: - rb_raise(rb_eArgError, "Invalid key type for map."); - } - - init_value_arg = 2; - if (needs_typeclass(self->value_type) && argc > 2) { - self->value_type_class = argv[2]; - validate_type_class(self->value_type, self->value_type_class); - init_value_arg = 3; - } - - // Table value type is always UINT64: this ensures enough space to store the - // native_slot value. - if (!upb_strtable_init(&self->table, UPB_CTYPE_UINT64)) { - rb_raise(rb_eRuntimeError, "Could not allocate table."); - } - - if (argc > init_value_arg) { - Map_merge_into_self(_self, argv[init_value_arg]); - } - - return Qnil; -} - -/* - * 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. - */ -VALUE Map_each(VALUE _self) { - Map* self = ruby_to_Map(_self); - - upb_strtable_iter it; - for (upb_strtable_begin(&it, &self->table); - !upb_strtable_done(&it); - upb_strtable_next(&it)) { - - VALUE key = table_key_to_ruby( - self, upb_strtable_iter_key(&it), upb_strtable_iter_keylength(&it)); - - upb_value v = upb_strtable_iter_value(&it); - void* mem = value_memory(&v); - VALUE value = native_slot_get(self->value_type, - self->value_type_class, - mem); - - rb_yield_values(2, key, value); - } - - return Qnil; -} - -/* - * call-seq: - * Map.keys => [list_of_keys] - * - * Returns the list of keys contained in the map, in unspecified order. - */ -VALUE Map_keys(VALUE _self) { - Map* self = ruby_to_Map(_self); - - VALUE ret = rb_ary_new(); - upb_strtable_iter it; - for (upb_strtable_begin(&it, &self->table); - !upb_strtable_done(&it); - upb_strtable_next(&it)) { - - VALUE key = table_key_to_ruby( - self, upb_strtable_iter_key(&it), upb_strtable_iter_keylength(&it)); - - rb_ary_push(ret, key); - } - - return ret; -} - -/* - * call-seq: - * Map.values => [list_of_values] - * - * Returns the list of values contained in the map, in unspecified order. - */ -VALUE Map_values(VALUE _self) { - Map* self = ruby_to_Map(_self); - - VALUE ret = rb_ary_new(); - upb_strtable_iter it; - for (upb_strtable_begin(&it, &self->table); - !upb_strtable_done(&it); - upb_strtable_next(&it)) { - - upb_value v = upb_strtable_iter_value(&it); - void* mem = value_memory(&v); - VALUE value = native_slot_get(self->value_type, - self->value_type_class, - mem); - - rb_ary_push(ret, value); - } - - return ret; -} - -/* - * 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. - */ -VALUE Map_index(VALUE _self, VALUE key) { - Map* self = ruby_to_Map(_self); - - char keybuf[TABLE_KEY_BUF_LENGTH]; - const char* keyval = NULL; - size_t length = 0; - upb_value v; - key = table_key(self, key, keybuf, &keyval, &length); - - if (upb_strtable_lookup2(&self->table, keyval, length, &v)) { - void* mem = value_memory(&v); - return native_slot_get(self->value_type, self->value_type_class, mem); - } else { - return Qnil; - } -} - -/* - * 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. - */ -VALUE Map_index_set(VALUE _self, VALUE key, VALUE value) { - Map* self = ruby_to_Map(_self); - - char keybuf[TABLE_KEY_BUF_LENGTH]; - const char* keyval = NULL; - size_t length = 0; - upb_value v; - void* mem; - key = table_key(self, key, keybuf, &keyval, &length); - - mem = value_memory(&v); - native_slot_set(self->value_type, self->value_type_class, mem, value); - - // Replace any existing value by issuing a 'remove' operation first. - upb_strtable_remove2(&self->table, keyval, length, NULL); - if (!upb_strtable_insert2(&self->table, keyval, length, v)) { - rb_raise(rb_eRuntimeError, "Could not insert into table"); - } - - // Ruby hashmap's :[]= method also returns the inserted value. - return value; -} - -/* - * call-seq: - * Map.has_key?(key) => bool - * - * Returns true if the given key is present in the map. Throws an exception if - * the key has the wrong type. - */ -VALUE Map_has_key(VALUE _self, VALUE key) { - Map* self = ruby_to_Map(_self); - - char keybuf[TABLE_KEY_BUF_LENGTH]; - const char* keyval = NULL; - size_t length = 0; - key = table_key(self, key, keybuf, &keyval, &length); - - if (upb_strtable_lookup2(&self->table, keyval, length, NULL)) { - return Qtrue; - } else { - return Qfalse; - } -} - -/* - * 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. - */ -VALUE Map_delete(VALUE _self, VALUE key) { - Map* self = ruby_to_Map(_self); - - char keybuf[TABLE_KEY_BUF_LENGTH]; - const char* keyval = NULL; - size_t length = 0; - upb_value v; - key = table_key(self, key, keybuf, &keyval, &length); - - if (upb_strtable_remove2(&self->table, keyval, length, &v)) { - void* mem = value_memory(&v); - return native_slot_get(self->value_type, self->value_type_class, mem); - } else { - return Qnil; - } -} - -/* - * call-seq: - * Map.clear - * - * Removes all entries from the map. - */ -VALUE Map_clear(VALUE _self) { - Map* self = ruby_to_Map(_self); - - // Uninit and reinit the table -- this is faster than iterating and doing a - // delete-lookup on each key. - upb_strtable_uninit(&self->table); - if (!upb_strtable_init(&self->table, UPB_CTYPE_INT64)) { - rb_raise(rb_eRuntimeError, "Unable to re-initialize table"); - } - return Qnil; -} - -/* - * call-seq: - * Map.length - * - * Returns the number of entries (key-value pairs) in the map. - */ -VALUE Map_length(VALUE _self) { - Map* self = ruby_to_Map(_self); - return ULL2NUM(upb_strtable_count(&self->table)); -} - -static VALUE Map_new_this_type(VALUE _self) { - Map* self = ruby_to_Map(_self); - VALUE new_map = Qnil; - VALUE key_type = fieldtype_to_ruby(self->key_type); - VALUE value_type = fieldtype_to_ruby(self->value_type); - if (self->value_type_class != Qnil) { - new_map = rb_funcall(CLASS_OF(_self), rb_intern("new"), 3, - key_type, value_type, self->value_type_class); - } else { - new_map = rb_funcall(CLASS_OF(_self), rb_intern("new"), 2, - key_type, value_type); - } - return new_map; -} - -/* - * 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. - */ -VALUE Map_dup(VALUE _self) { - Map* self = ruby_to_Map(_self); - VALUE new_map = Map_new_this_type(_self); - Map* new_self = ruby_to_Map(new_map); - - upb_strtable_iter it; - for (upb_strtable_begin(&it, &self->table); - !upb_strtable_done(&it); - upb_strtable_next(&it)) { - - upb_value v = upb_strtable_iter_value(&it); - void* mem = value_memory(&v); - upb_value dup; - void* dup_mem = value_memory(&dup); - native_slot_dup(self->value_type, dup_mem, mem); - - if (!upb_strtable_insert2(&new_self->table, - upb_strtable_iter_key(&it), - upb_strtable_iter_keylength(&it), - dup)) { - rb_raise(rb_eRuntimeError, "Error inserting value into new table"); - } - } - - return new_map; -} - -// Used by Google::Protobuf.deep_copy but not exposed directly. -VALUE Map_deep_copy(VALUE _self) { - Map* self = ruby_to_Map(_self); - VALUE new_map = Map_new_this_type(_self); - Map* new_self = ruby_to_Map(new_map); - - upb_strtable_iter it; - for (upb_strtable_begin(&it, &self->table); - !upb_strtable_done(&it); - upb_strtable_next(&it)) { - - upb_value v = upb_strtable_iter_value(&it); - void* mem = value_memory(&v); - upb_value dup; - void* dup_mem = value_memory(&dup); - native_slot_deep_copy(self->value_type, dup_mem, mem); - - if (!upb_strtable_insert2(&new_self->table, - upb_strtable_iter_key(&it), - upb_strtable_iter_keylength(&it), - dup)) { - rb_raise(rb_eRuntimeError, "Error inserting value into new table"); - } - } - - return new_map; -} - -/* - * 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. - */ -VALUE Map_eq(VALUE _self, VALUE _other) { - Map* self = ruby_to_Map(_self); - Map* other; - upb_strtable_iter it; - - // Allow comparisons to Ruby hashmaps by converting to a temporary Map - // instance. Slow, but workable. - if (TYPE(_other) == T_HASH) { - VALUE other_map = Map_new_this_type(_self); - Map_merge_into_self(other_map, _other); - _other = other_map; - } - - other = ruby_to_Map(_other); - - if (self == other) { - return Qtrue; - } - if (self->key_type != other->key_type || - self->value_type != other->value_type || - self->value_type_class != other->value_type_class) { - return Qfalse; - } - if (upb_strtable_count(&self->table) != upb_strtable_count(&other->table)) { - return Qfalse; - } - - // For each member of self, check that an equal member exists at the same key - // in other. - for (upb_strtable_begin(&it, &self->table); - !upb_strtable_done(&it); - upb_strtable_next(&it)) { - - upb_value v = upb_strtable_iter_value(&it); - void* mem = value_memory(&v); - upb_value other_v; - void* other_mem = value_memory(&other_v); - - if (!upb_strtable_lookup2(&other->table, - upb_strtable_iter_key(&it), - upb_strtable_iter_keylength(&it), - &other_v)) { - // Not present in other map. - return Qfalse; - } - - if (!native_slot_eq(self->value_type, mem, other_mem)) { - // Present, but value not equal. - return Qfalse; - } - } - - return Qtrue; -} - -/* - * call-seq: - * Map.hash => hash_value - * - * Returns a hash value based on this map's contents. - */ -VALUE Map_hash(VALUE _self) { - Map* self = ruby_to_Map(_self); - - st_index_t h = rb_hash_start(0); - VALUE hash_sym = rb_intern("hash"); - - upb_strtable_iter it; - for (upb_strtable_begin(&it, &self->table); - !upb_strtable_done(&it); - upb_strtable_next(&it)) { - VALUE key = table_key_to_ruby( - self, upb_strtable_iter_key(&it), upb_strtable_iter_keylength(&it)); - - upb_value v = upb_strtable_iter_value(&it); - void* mem = value_memory(&v); - VALUE value = native_slot_get(self->value_type, - self->value_type_class, - mem); - - h = rb_hash_uint(h, NUM2LONG(rb_funcall(key, hash_sym, 0))); - h = rb_hash_uint(h, NUM2LONG(rb_funcall(value, hash_sym, 0))); - } - - return INT2FIX(h); -} - -/* - * call-seq: - * Map.inspect => string - * - * Returns a string representing this map's elements. It will be formatted as - * "{key => value, key => value, ...}", with each key and value string - * representation computed by its own #inspect method. - */ -VALUE Map_inspect(VALUE _self) { - Map* self = ruby_to_Map(_self); - - VALUE str = rb_str_new2("{"); - - bool first = true; - VALUE inspect_sym = rb_intern("inspect"); - - upb_strtable_iter it; - for (upb_strtable_begin(&it, &self->table); - !upb_strtable_done(&it); - upb_strtable_next(&it)) { - VALUE key = table_key_to_ruby( - self, upb_strtable_iter_key(&it), upb_strtable_iter_keylength(&it)); - - upb_value v = upb_strtable_iter_value(&it); - void* mem = value_memory(&v); - VALUE value = native_slot_get(self->value_type, - self->value_type_class, - mem); - - if (!first) { - str = rb_str_cat2(str, ", "); - } else { - first = false; - } - str = rb_str_append(str, rb_funcall(key, inspect_sym, 0)); - str = rb_str_cat2(str, "=>"); - str = rb_str_append(str, rb_funcall(value, inspect_sym, 0)); - } - - str = rb_str_cat2(str, "}"); - return str; -} - -/* - * 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. - */ -VALUE Map_merge(VALUE _self, VALUE hashmap) { - VALUE dupped = Map_dup(_self); - return Map_merge_into_self(dupped, hashmap); -} - -static int merge_into_self_callback(VALUE key, VALUE value, VALUE self) { - Map_index_set(self, key, value); - return ST_CONTINUE; -} - -// Used only internally -- shared by #merge and #initialize. -VALUE Map_merge_into_self(VALUE _self, VALUE hashmap) { - if (TYPE(hashmap) == T_HASH) { - rb_hash_foreach(hashmap, merge_into_self_callback, _self); - } else if (RB_TYPE_P(hashmap, T_DATA) && RTYPEDDATA_P(hashmap) && - RTYPEDDATA_TYPE(hashmap) == &Map_type) { - - Map* self = ruby_to_Map(_self); - Map* other = ruby_to_Map(hashmap); - upb_strtable_iter it; - - if (self->key_type != other->key_type || - self->value_type != other->value_type || - self->value_type_class != other->value_type_class) { - rb_raise(rb_eArgError, "Attempt to merge Map with mismatching types"); - } - - for (upb_strtable_begin(&it, &other->table); - !upb_strtable_done(&it); - upb_strtable_next(&it)) { - - // Replace any existing value by issuing a 'remove' operation first. - upb_value v; - upb_value oldv; - upb_strtable_remove2(&self->table, - upb_strtable_iter_key(&it), - upb_strtable_iter_keylength(&it), - &oldv); - - v = upb_strtable_iter_value(&it); - upb_strtable_insert2(&self->table, - upb_strtable_iter_key(&it), - upb_strtable_iter_keylength(&it), - v); - } - } else { - rb_raise(rb_eArgError, "Unknown type merging into Map"); - } - return _self; -} - -// Internal method: map iterator initialization (used for serialization). -void Map_begin(VALUE _self, Map_iter* iter) { - Map* self = ruby_to_Map(_self); - iter->self = self; - upb_strtable_begin(&iter->it, &self->table); -} - -void Map_next(Map_iter* iter) { - upb_strtable_next(&iter->it); -} - -bool Map_done(Map_iter* iter) { - return upb_strtable_done(&iter->it); -} - -VALUE Map_iter_key(Map_iter* iter) { - return table_key_to_ruby( - iter->self, - upb_strtable_iter_key(&iter->it), - upb_strtable_iter_keylength(&iter->it)); -} - -VALUE Map_iter_value(Map_iter* iter) { - upb_value v = upb_strtable_iter_value(&iter->it); - void* mem = value_memory(&v); - return native_slot_get(iter->self->value_type, - iter->self->value_type_class, - mem); -} - -void Map_register(VALUE module) { - VALUE klass = rb_define_class_under(module, "Map", rb_cObject); - rb_define_alloc_func(klass, Map_alloc); - cMap = klass; - rb_gc_register_address(&cMap); - - rb_define_method(klass, "initialize", Map_init, -1); - rb_define_method(klass, "each", Map_each, 0); - rb_define_method(klass, "keys", Map_keys, 0); - rb_define_method(klass, "values", Map_values, 0); - rb_define_method(klass, "[]", Map_index, 1); - rb_define_method(klass, "[]=", Map_index_set, 2); - rb_define_method(klass, "has_key?", Map_has_key, 1); - rb_define_method(klass, "delete", Map_delete, 1); - rb_define_method(klass, "clear", Map_clear, 0); - rb_define_method(klass, "length", Map_length, 0); - rb_define_method(klass, "dup", Map_dup, 0); - rb_define_method(klass, "==", Map_eq, 1); - rb_define_method(klass, "hash", Map_hash, 0); - rb_define_method(klass, "inspect", Map_inspect, 0); - rb_define_method(klass, "merge", Map_merge, 1); - rb_include_module(klass, rb_mEnumerable); -} |