Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
BEGIN LICENSE BLOCK ***** Version: CPL 1.0/GPL 2.0/LGPL 2.1 The contents of this file are subject to the Common Public License Version 1.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.eclipse.org/legal/cpl-v10.html Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. Copyright (C) 2001 Chad Fowler <chadfowler@chadfowler.com> Copyright (C) 2001 Alan Moore <alan_moore@gmx.net> Copyright (C) 2001-2002 Benoit Cerrina <b.cerrina@wanadoo.fr> Copyright (C) 2001-2004 Jan Arne Petersen <jpetersen@uni-bonn.de> Copyright (C) 2002-2004 Anders Bengtsson <ndrsbngtssn@yahoo.se> Copyright (C) 2004-2006 Thomas E Enebo <enebo@acm.org> Copyright (C) 2004 Stefan Matthias Aust <sma@3plus4.de> Copyright (C) 2005 Charles O Nutter <headius@headius.com> Copyright (C) 2006 Ola Bini <Ola.Bini@ki.se> Copyright (C) 2006 Tim Azzopardi <tim@tigerfive.com> Copyright (C) 2006 Miguel Covarrubias <mlcovarrubias@gmail.com> Copyright (C) 2007 MenTaLguY <mental@rydia.net> Alternatively, the contents of this file may be used under the terms of either of the GNU General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the LGPL are applicable instead of those above. If you wish to allow use of your version of this file only under the terms of either the GPL or the LGPL, and not to allow others to use your version of this file under the terms of the CPL, indicate your decision by deleting the provisions above and replace them with the notice and other provisions required by the GPL or the LGPL. If you do not delete the provisions above, a recipient may use your version of this file under the terms of any one of the CPL, the GPL or the LGPL. END LICENSE BLOCK ***
  
  package org.jruby;
  
  import static org.jruby.RubyEnumerator.enumeratorize;
  
  import java.util.Map;
  import java.util.Set;
  import static org.jruby.runtime.Visibility.*;
  
  import static org.jruby.CompatVersion.*;
  import static org.jruby.javasupport.util.RuntimeHelpers.invokedynamic;
  import static org.jruby.runtime.invokedynamic.MethodNames.HASH;
  
  // Design overview:
  //
  // RubyHash is implemented as hash table with a singly-linked list of
  // RubyHash.RubyHashEntry objects for each bucket.  RubyHashEntry objects
  // are also kept in a doubly-linked list which reflects their insertion
  // order and is used for iteration.  For simplicity, this latter list is
  // circular; a dummy RubyHashEntry, RubyHash.head, is used to mark the
  // ends of the list.
  //
  // When an entry is removed from the table, it is also removed from the
  // doubly-linked list.  However, while the reference to the previous
  // RubyHashEntry is cleared (to mark the entry as dead), the reference
  // to the next RubyHashEntry is preserved so that iterators are not
  // invalidated: any iterator with a reference to a dead entry can climb
  // back up into the list of live entries by chasing next references until
  // it finds a live entry (or head).
  //
  // Ordinarily, this scheme would require O(N) time to clear a hash (since
  // each RubyHashEntry would need to be visited and unlinked from the
  // iteration list), but RubyHash also maintains a generation count.  Every
  // time the hash is cleared, the doubly-linked list is simply discarded and
  // the generation count incremented.  Iterators check to see whether the
  // generation count has changed; if it has, they reset themselves back to
  // the new start of the list.
  //
 // This design means that iterators are never invalidated by changes to the
 // hashtable, and they do not need to modify the structure during their
 // lifecycle.
 //
 
Implementation of the Hash class. Concurrency: no synchronization is required among readers, but all users must synchronize externally with writers.
 
 @JRubyClass(name = "Hash", include="Enumerable")
 public class RubyHash extends RubyObject implements Map {
     public static final int DEFAULT_INSPECT_STR_SIZE = 20;
 
     public static RubyClass createHashClass(Ruby runtime) {
         RubyClass hashc = runtime.defineClass("Hash"runtime.getObject(), );
         runtime.setHash(hashc);
 
         hashc.index = .;
         hashc.setReifiedClass(RubyHash.class);
         
         hashc.kindOf = new RubyModule.KindOf() {
             @Override
             public boolean isKindOf(IRubyObject objRubyModule type) {
                 return obj instanceof RubyHash;
             }
         };
 
         hashc.includeModule(runtime.getEnumerable());
 
         hashc.defineAnnotatedMethods(RubyHash.class);
 
         return hashc;
     }
 
     private final static ObjectAllocator HASH_ALLOCATOR = new ObjectAllocator() {
         public IRubyObject allocate(Ruby runtimeRubyClass klass) {
             return new RubyHash(runtimeklass);
         }
     };
 
     @Override
     public int getNativeTypeIndex() {
         return .;
     }

    
rb_hash_s_create
 
     @JRubyMethod(name = "[]", rest = true, meta = true)
     public static IRubyObject create(ThreadContext contextIRubyObject recvIRubyObject[] argsBlock block) {
         RubyClass klass = (RubyClassrecv;
         Ruby runtime = context.runtime;
         RubyHash hash;
 
         if (args.length == 1) {
             IRubyObject tmp = TypeConverter.convertToTypeWithCheck(
                     args[0], runtime.getHash(), "to_hash");
 
             if (!tmp.isNil()) {
                 RubyHash otherHash = (RubyHashtmp;
                 return new RubyHash(runtimeklassotherHash);
             }
 
             tmp = TypeConverter.convertToTypeWithCheck(args[0], runtime.getArray(), "to_ary");
             if (!tmp.isNil()) {
                 hash = (RubyHash)klass.allocate();
                 RubyArray arr = (RubyArray)tmp;
                 for(int i = 0, j = arr.getLength(); i<ji++) {
                     IRubyObject v = TypeConverter.convertToTypeWithCheck(arr.entry(i), runtime.getArray(), "to_ary");
                     IRubyObject key = runtime.getNil();
                     IRubyObject val = runtime.getNil();
                     if(v.isNil()) {
                         continue;
                     }
                     switch(((RubyArray)v).getLength()) {
                     case 2:
                         val = ((RubyArray)v).entry(1);
                     case 1:
                         key = ((RubyArray)v).entry(0);
                         hash.fastASet(keyval);
                     }
                 }
                 return hash;
             }
         }
 
         if ((args.length & 1) != 0) {
             throw runtime.newArgumentError("odd number of arguments for Hash");
         }
 
         hash = (RubyHash)klass.allocate();
         for (int i=0; i < args.lengthi+=2) hash.op_aset(contextargs[i], args[i+1]);
 
         return hash;
     }
 
     @JRubyMethod(name = "try_convert", meta = true, compat = )
     public static IRubyObject try_convert(ThreadContext contextIRubyObject recvIRubyObject args) {
         return TypeConverter.convertToTypeWithCheck(argscontext.runtime.getHash(), "to_hash");
     }

    
rb_hash_new
 
     public static final RubyHash newHash(Ruby runtime) {
         return new RubyHash(runtime);
     }

    
rb_hash_new
 
     public static final RubyHash newSmallHash(Ruby runtime) {
         return new RubyHash(runtime, 1);
     }

    
rb_hash_new
 
     public static final RubyHash newHash(Ruby runtimeMap valueMapIRubyObject defaultValue) {
         assert defaultValue != null;
 
         return new RubyHash(runtimevalueMapdefaultValue);
     }
 
     private RubyHashEntry[] table;
     protected int size = 0;
     private int threshold;
 
     private static final int PROCDEFAULT_HASH_F = 1 << 10;
 
     private IRubyObject ifNone;
 
     private RubyHash(Ruby runtimeRubyClass klassRubyHash other) {
         super(runtimeklass);
         this. = runtime.getNil();
          = ;
          = other.internalCopyTable();
          = other.size;
     }
 
     public RubyHash(Ruby runtimeRubyClass klass) {
         super(runtimeklass);
         this. = runtime.getNil();
         alloc();
     }
 
     public RubyHash(Ruby runtimeint buckets) {
         this(runtimeruntime.getNil(), buckets);
     }
 
     public RubyHash(Ruby runtime) {
         this(runtimeruntime.getNil());
     }
 
     public RubyHash(Ruby runtimeIRubyObject defaultValue) {
         super(runtimeruntime.getHash());
         this. = defaultValue;
         alloc();
     }
 
     public RubyHash(Ruby runtimeIRubyObject defaultValueint buckets) {
         super(runtimeruntime.getHash());
         this. = defaultValue;
         alloc(buckets);
     }
 
     /*
      *  Constructor for internal usage (mainly for Array#|, Array#&, Array#- and Array#uniq)
      *  it doesn't initialize ifNone field
      */
     RubyHash(Ruby runtimeboolean objectSpace) {
         super(runtimeruntime.getHash(), objectSpace);
         alloc();
     }
 
     // TODO should this be deprecated ? (to be efficient, internals should deal with RubyHash directly)
     public RubyHash(Ruby runtimeMap valueMapIRubyObject defaultValue) {
         super(runtimeruntime.getHash());
         this. = defaultValue;
         alloc();
 
         for (Iterator iter = valueMap.entrySet().iterator();iter.hasNext();) {
             Map.Entry e = (Map.Entry)iter.next();
             internalPut((IRubyObject)e.getKey(), (IRubyObject)e.getValue());
         }
     }
 
     private final void alloc() {
          = ;
         ++;
         . = . = ;
     }
 
     private final void alloc(int buckets) {
          = ;
         ++;
         . = . = ;
          = new RubyHashEntry[buckets];
     }
 
     /* ============================
      * Here are hash internals
      * (This could be extracted to a separate class but it's not too large though)
      * ============================
      */
 
     private static final int MRI_PRIMES[] = {
         8 + 3, 16 + 3, 32 + 5, 64 + 3, 128 + 3, 256 + 27, 512 + 9, 1024 + 9, 2048 + 5, 4096 + 3,
         8192 + 27, 16384 + 43, 32768 + 3, 65536 + 45, 131072 + 29, 262144 + 3, 524288 + 21, 1048576 + 7,
         2097152 + 17, 4194304 + 15, 8388608 + 9, 16777216 + 43, 33554432 + 35, 67108864 + 15,
         134217728 + 29, 268435456 + 3, 536870912 + 11, 1073741824 + 85, 0
     };
 
     private static final int JAVASOFT_INITIAL_CAPACITY = 8; // 16 ?
     private static final int MRI_INITIAL_CAPACITY = [0];
 
     private static final int INITIAL_THRESHOLD =  - ( >> 2);
     private static final int MAXIMUM_CAPACITY = 1 << 30;
 
     public static final RubyHashEntry NO_ENTRY = new RubyHashEntry();
     private int generation = 0; // generation count for O(1) clears
     private final RubyHashEntry head = new RubyHashEntry();
 
     { . = . = ; }
 
     public static final class RubyHashEntry implements Map.Entry {
         private IRubyObject key;
         private IRubyObject value;
         private RubyHashEntry next;
         private RubyHashEntry prevAdded;
         private RubyHashEntry nextAdded;
         private int hash;
 
         RubyHashEntry() {
              = ;
         }
 
         public RubyHashEntry(int hIRubyObject kIRubyObject vRubyHashEntry eRubyHashEntry head) {
              = k = v = e = h;
             if (head != null) {
                  = head.prevAdded;
                  = head;
                 . = this;
                 . = this;
             }
         }
 
         public void detach() {
             if ( != null) {
                 . = ;
                 . = ;
                  = null;
             }
         }
 
         public boolean isLive() {
             return  != null;
         }
 
         public Object getKey() {
             return ;
         }
         public Object getJavaifiedKey(){
             return .toJava(Object.class);
         }
 
         public Object getValue() {
             return ;
         }
         public Object getJavaifiedValue() {
             return .toJava(Object.class);
         }
 
         public Object setValue(Object value) {
             IRubyObject oldValue = this.;
             if (value instanceof IRubyObject) {
                 this. = (IRubyObject)value;
             } else {
                 throw new UnsupportedOperationException("directEntrySet() doesn't support setValue for non IRubyObject instance entries, convert them manually or use entrySet() instead");
             }
             return oldValue;
         }
 
         @Override
         public boolean equals(Object other){
             if(!(other instanceof RubyHashEntry)) return false;
             RubyHashEntry otherEntry = (RubyHashEntry)other;
             
             return ( == otherEntry.key || .eql(otherEntry.key)) &&
                     ( == otherEntry.value || .equals(otherEntry.value));
         }
 
         @Override
         public int hashCode(){
             return .hashCode() ^ .hashCode();
         }
     }
 
     private static int JavaSoftHashValue(int h) {
         h ^= (h >>> 20) ^ (h >>> 12);
         return h ^ (h >>> 7) ^ (h >>> 4);
     }
 
     private static int JavaSoftBucketIndex(final int hfinal int length) {
         return h & (length - 1);
     }
 
     private static int MRIHashValue(int h) {
         return h & ;
     }
 
     private static final int HASH_SIGN_BIT_MASK = ~(1 << 31);
     private static int MRIBucketIndex(final int hfinal int length) {
         return ((h & ) % length);
     }
 
     private final void resize(int newCapacity) {
         final RubyHashEntry[] oldTable = ;
         final RubyHashEntry[] newTable = new RubyHashEntry[newCapacity];
         for (int j = 0; j < oldTable.lengthj++) {
             RubyHashEntry entry = oldTable[j];
             oldTable[j] = null;
             while (entry != null) {
                 RubyHashEntry next = entry.next;
                 int i = bucketIndex(entry.hashnewCapacity);
                 entry.next = newTable[i];
                 newTable[i] = entry;
                 entry = next;
             }
         }
          = newTable;
     }
 
     private final void JavaSoftCheckResize() {
         if (overThreshold()) {
             RubyHashEntry[] tbl = ;
             if (tbl.length == ) {
                  = .;
                 return;
             }
             resizeAndAdjustThreshold();
         }
     }
     
     private boolean overThreshold() {
         return  > ;
     }
     
     private void resizeAndAdjustThreshold(RubyHashEntry[] oldTable) {
         int newCapacity = oldTable.length << 1;
         resize(newCapacity);
          = newCapacity - (newCapacity >> 2);
     }
 
     private static final int MIN_CAPA = 8;
     private static final int ST_DEFAULT_MAX_DENSITY = 5;
     private final void MRICheckResize() {
         if ( / . > ) {
             int forSize = . + 1; // size + 1;
             for (int i=0, newCapacity = i < .i++, newCapacity <<= 1) {
                 if (newCapacity > forSize) {
                     resize([i]);
                     return;
                 }
             }
             return// suboptimal for large hashes (> 1073741824 + 85 entries) not very likely to happen
         }
     }
     // ------------------------------
     private static final boolean MRI_HASH = true;
     private static final boolean MRI_HASH_RESIZE = true;
 
     protected static int hashValue(final int h) {
         return  ? MRIHashValue(h) : JavaSoftHashValue(h);
     }
 
     private static int bucketIndex(final int hfinal int length) {
         return  ? MRIBucketIndex(hlength) : JavaSoftBucketIndex(hlength);
     }
 
     private void checkResize() {
         if (MRICheckResize(); else JavaSoftCheckResize();
     }
 
     private void checkIterating() {
         if (.get() > 0) {
             throw getRuntime().newRuntimeError("can't add a new key into hash during iteration");
         }
     }
     // ------------------------------
     public static long collisions = 0;
 
     // put implementation
 
     private final void internalPut(final IRubyObject keyfinal IRubyObject value) {
         internalPut(keyvaluetrue);
     }
 
     private final void internalPutSmall(final IRubyObject keyfinal IRubyObject value) {
         internalPutSmall(keyvaluetrue);
     }
 
     protected void internalPut(final IRubyObject keyfinal IRubyObject valuefinal boolean checkForExisting) {
         checkResize();
 
         internalPutSmall(keyvaluecheckForExisting);
     }
 
     protected void internalPutSmall(final IRubyObject keyfinal IRubyObject valuefinal boolean checkForExisting) {
         final int hash = hashValue(key.hashCode());
         final int i = bucketIndex(hash.);
 
         // if (table[i] != null) collisions++;
 
         if (checkForExisting) {
             for (RubyHashEntry entry = [i]; entry != nullentry = entry.next) {
                 if (internalKeyExist(entryhashkey)) {
                     entry.value = value;
                     return;
                 }
             }
         }
 
         checkIterating();
 
         [i] = new RubyHashEntry(hashkeyvalue[i], );
         ++;
     }
 
     // get implementation
 
     protected IRubyObject internalGet(IRubyObject key) { // specialized for value
         return internalGetEntry(key).;
     }
 
     protected RubyHashEntry internalGetEntry(IRubyObject key) {
         final int hash = hashValue(key.hashCode());
         for (RubyHashEntry entry = [bucketIndex(hash.)]; entry != nullentry = entry.next) {
             if (internalKeyExist(entryhashkey)) {
                 return entry;
             }
         }
         return ;
     }
 
     private boolean internalKeyExist(RubyHashEntry entryint hashIRubyObject key) {
         return (entry.hash == hash
             && (entry.key == key || (!isComparedByIdentity() && key.eql(entry.key))));
     }
 
     // delete implementation
 
 
     protected RubyHashEntry internalDelete(final IRubyObject key) {
         return internalDelete(hashValue(key.hashCode()), key);
     }
 
     protected RubyHashEntry internalDeleteEntry(final RubyHashEntry entry) {
         // n.b. we need to recompute the hash in case the key object was modified
         return internalDelete(hashValue(entry.key.hashCode()), entry);
     }
 
     private final RubyHashEntry internalDelete(final int hashfinal EntryMatchType matchTypefinal Object obj) {
         final int i = bucketIndex(hash.);
 
         RubyHashEntry entry = [i];
         if (entry != null) {
             RubyHashEntry prior = null;
             for (; entry != nullprior = entryentry = entry.next) {
                 if (entry.hash == hash && matchType.matches(entryobj)) {
                     if (prior != null) {
                         prior.next = entry.next;
                     } else {
                         [i] = entry.next;
                     }
                     entry.detach();
                     --;
                     return entry;
                 }
             }
         }
 
         return ;
     }
 
     private static abstract class EntryMatchType {
         public abstract boolean matches(final RubyHashEntry entryfinal Object obj);
     }
 
     private static final EntryMatchType MATCH_KEY = new EntryMatchType() {
         public boolean matches(final RubyHashEntry entryfinal Object obj) {
             final IRubyObject key = entry.key;
             return obj == key || (((IRubyObject)obj).eql(key));
         }
     };
 
     private static final EntryMatchType MATCH_ENTRY = new EntryMatchType() {
         public boolean matches(final RubyHashEntry entryfinal Object obj) {
             return entry.equals(obj);
         }
     };
 
     private final RubyHashEntry[] internalCopyTable(RubyHashEntry destHead) {
          RubyHashEntry[]newTable = new RubyHashEntry[.];
 
          for (RubyHashEntry entry = .entry != entry = entry.nextAdded) {
              int i = bucketIndex(entry.hash.);
              newTable[i] = new RubyHashEntry(entry.hashentry.keyentry.valuenewTable[i], destHead);
          }
          return newTable;
     }
 
     public static abstract class Visitor {
         public abstract void visit(IRubyObject keyIRubyObject value);
     }
 
     public void visitAll(Visitor visitor) {
         int startGeneration = ;
         for (RubyHashEntry entry = .entry != entry = entry.nextAdded) {
             if (startGeneration != ) {
                 startGeneration = ;
                 entry = .;
                 if (entry == break;
             }
             if (entry.isLive()) visitor.visit(entry.keyentry.value);
         }
     }
 
     /* ============================
      * End of hash internals
      * ============================
      */
 
     /*  ================
      *  Instance Methods
      *  ================
      */

    
rb_hash_initialize
 
     @JRubyMethod(optional = 1, visibility = )
     public IRubyObject initialize(IRubyObject[] argsfinal Block block) {
         modify();
 
         if (block.isGiven()) {
             if (args.length > 0) throw getRuntime().newArgumentError("wrong number of arguments");
              = getRuntime().newProc(..block);
              |= ;
         } else {
             Arity.checkArgumentCount(getRuntime(), args, 0, 1);
             if (args.length == 1)  = args[0];
         }
         return this;
     }

    
rb_hash_default
 
     @Deprecated
     public IRubyObject default_value_get(ThreadContext contextIRubyObject[] args) {
         switch (args.length) {
             case 0: return default_value_get(context);
             case 1: return default_value_get(contextargs[0]);
             default:
                 throw context.runtime.newArgumentError(args.length, 1);
         }
     }
     @JRubyMethod(name = "default")
     public IRubyObject default_value_get(ThreadContext context) {
         if (( & ) != 0) {
             return getRuntime().getNil();
         }
         return ;
     }
     @JRubyMethod(name = "default")
     public IRubyObject default_value_get(ThreadContext contextIRubyObject arg) {
         if (( & ) != 0) {
             return RuntimeHelpers.invoke(context"call"thisarg);
         }
         return ;
     }

    
rb_hash_set_default
 
     @JRubyMethod(name = "default=", required = 1)
     public IRubyObject default_value_set(final IRubyObject defaultValue) {
         modify();
 
          = defaultValue;
          &= ~;
 
         return ;
     }

    
rb_hash_default_proc
 
     @JRubyMethod
     public IRubyObject default_proc() {
         return ( & ) != 0 ?  : getRuntime().getNil();
     }

    
default_proc_arity_check
 
     private void checkDefaultProcArity(IRubyObject proc) {
         int n = ((RubyProc)proc).getBlock().arity().getValue();
 
         if(((RubyProc)proc).getBlock(). == .. && n != 2 && (n >= 0 || n < -3)) {
             if(n < 0) n = -n-1;
             throw getRuntime().newTypeError("default_proc takes two arguments (2 for " + n + ")");
         }
     }

    
rb_hash_set_default_proc
 
     @JRubyMethod(name = "default_proc=", compat = )
     public IRubyObject set_default_proc(IRubyObject proc) {
         modify();
         IRubyObject b = TypeConverter.convertToType(procgetRuntime().getProc(), "to_proc");
         if(b.isNil() || !(b instanceof RubyProc)) {
             throw getRuntime().newTypeError("wrong default_proc type " + proc.getMetaClass() + " (expected Proc)");
         }
         proc = b;
         checkDefaultProcArity(proc);
          = proc;
          |= ;
         return proc;
     }

    
rb_hash_modify
 
     public void modify() {
     	testFrozen("Hash");
     }

    
inspect_hash
 
     private IRubyObject inspectHash(final ThreadContext context) {
         final RubyString str = RubyString.newStringLight(context.runtime);
         str.cat((byte)'{');
         final boolean[] firstEntry = new boolean[1];
 
         firstEntry[0] = true;
         final boolean is19 = context.runtime.is1_9();
         visitAll(new Visitor() {
             public void visit(IRubyObject keyIRubyObject value) {
                 if (!firstEntry[0]) str.cat((byte)',').cat((byte)' ');
 
                 RubyString inspectedKey = inspect(contextkey);
                 RubyString inspectedValue = inspect(contextvalue);
 
                 if (is19) {
                     str.cat19(inspectedKey);
                     str.cat((byte)'=').cat((byte)'>');
                     str.cat19(inspectedValue);
                 } else {
                     str.cat(inspectedKey);
                     str.cat((byte)'=').cat((byte)'>');
                     str.cat(inspectedValue);
                 }
                 
                 firstEntry[0] = false;
             }
         });
         str.cat((byte)'}');
         return str;
     }

    
rb_hash_inspect
 
     @JRubyMethod(name = "inspect")
     public IRubyObject inspect(ThreadContext context) {
         if ( == 0) return getRuntime().newString("{}");
         if (getRuntime().isInspecting(this)) return getRuntime().newString("{...}");
 
         try {
             getRuntime().registerInspecting(this);
             return inspectHash(context);
         } finally {
             getRuntime().unregisterInspecting(this);
         }
     }

    
rb_hash_size
 
     @JRubyMethod(name = {"size""length"})
     public RubyFixnum rb_size() {
         return getRuntime().newFixnum();
     }

    
rb_hash_empty_p
 
     @JRubyMethod(name = "empty?")
     public RubyBoolean empty_p() {
         return  == 0 ? getRuntime().getTrue() : getRuntime().getFalse();
     }

    
rb_hash_to_a
 
     @JRubyMethod(name = "to_a")
     @Override
     public RubyArray to_a() {
         final Ruby runtime = getRuntime();
         try {
             final RubyArray result = RubyArray.newArray(runtime);
 
             visitAll(new Visitor() {
                 public void visit(IRubyObject keyIRubyObject value) {
                     result.append(RubyArray.newArray(runtimekeyvalue));
                 }
             });
 
             result.setTaint(isTaint());
             return result;
         } catch (NegativeArraySizeException nase) {
             throw concurrentModification();
         }
     }

    
rb_hash_to_s & to_s_hash
 
     @JRubyMethod(name = "to_s")
     public IRubyObject to_s(ThreadContext context) {
         Ruby runtime = context.runtime;
         if (runtime.isInspecting(this)) return runtime.newString("{...}");
         try {
             runtime.registerInspecting(this);
             return to_a().to_s();
         } finally {
             runtime.unregisterInspecting(this);
         }
     }
 
     @JRubyMethod(name = "to_s", compat = )
     public IRubyObject to_s19(ThreadContext context) {
         return inspect(context);
     }

    
rb_hash_rehash
 
     @JRubyMethod(name = "rehash")
     public RubyHash rehash() {
         if (.get() > 0) {
             throw getRuntime().newRuntimeError("rehash during iteration");
         }
 
         modify();
         final RubyHashEntry[] oldTable = ;
         final RubyHashEntry[] newTable = new RubyHashEntry[oldTable.length];
         for (int j = 0; j < oldTable.lengthj++) {
             RubyHashEntry entry = oldTable[j];
             oldTable[j] = null;
             while (entry != null) {
                 RubyHashEntry next = entry.next;
                 entry.hash = hashValue(entry.key.hashCode()); // update the hash value
                 int i = bucketIndex(entry.hashnewTable.length);
                 entry.next = newTable[i];
                 newTable[i] = entry;
                 entry = next;
             }
         }
          = newTable;
         return this;
     }

    
rb_hash_to_hash
 
     @JRubyMethod(name = "to_hash")
     public RubyHash to_hash() {
         return this;
     }
 
     @Override
     public RubyHash convertToHash() {
         return this;
     }
 
     public final void fastASet(IRubyObject keyIRubyObject value) {
         internalPut(keyvalue);
     }
 
     public final RubyHash fastASetChained(IRubyObject keyIRubyObject value) {
         internalPut(keyvalue);
         return this;
     }
     
     public final void fastASetCheckString(Ruby runtimeIRubyObject keyIRubyObject value) {
       if (key instanceof RubyString) {
           op_asetForString(runtime, (RubyStringkeyvalue);
       } else {
           internalPut(keyvalue);
       }
     }
 
     public final void fastASetSmallCheckString(Ruby runtimeIRubyObject keyIRubyObject value) {
         if (key instanceof RubyString) {
             op_asetSmallForString(runtime, (RubyStringkeyvalue);
         } else {
             internalPutSmall(keyvalue);
         }
     }
 
     public final void fastASetCheckString19(Ruby runtimeIRubyObject keyIRubyObject value) {
       if (key.getMetaClass().getRealClass() == runtime.getString()) {
           op_asetForString(runtime, (RubyStringkeyvalue);
       } else {
           internalPut(keyvalue);
       }
     }
 
     public final void fastASetSmallCheckString19(Ruby runtimeIRubyObject keyIRubyObject value) {
         if (key.getMetaClass().getRealClass() == runtime.getString()) {
             op_asetSmallForString(runtime, (RubyStringkeyvalue);
         } else {
             internalPutSmall(keyvalue);
         }
     }
 
     @Deprecated
     public IRubyObject op_aset(IRubyObject keyIRubyObject value) {
         return op_aset(getRuntime().getCurrentContext(), keyvalue);
     }

    
rb_hash_aset
 
     @JRubyMethod(name = {"[]=""store"}, required = 2, compat = )
     public IRubyObject op_aset(ThreadContext contextIRubyObject keyIRubyObject value) {
         modify();
 
         fastASetCheckString(context.runtimekeyvalue);
         return value;
     }
 
     @JRubyMethod(name = {"[]=""store"}, required = 2, compat = )
     public IRubyObject op_aset19(ThreadContext contextIRubyObject keyIRubyObject value) {
         modify();
 
         fastASetCheckString19(context.runtimekeyvalue);
         return value;
     }
 
     protected void op_asetForString(Ruby runtimeRubyString keyIRubyObject value) {
         final RubyHashEntry entry = internalGetEntry(key);
         if (entry != ) {
             entry.value = value;
         } else {
             checkIterating();
             if (!key.isFrozen()) {
                 key = key.strDup(runtimekey.getMetaClass().getRealClass());
                 key.setFrozen(true);
             }
             internalPut(keyvaluefalse);
         }
     }
 
     protected void op_asetSmallForString(Ruby runtimeRubyString keyIRubyObject value) {
         final RubyHashEntry entry = internalGetEntry(key);
         if (entry != ) {
             entry.value = value;
         } else {
             checkIterating();
             if (!key.isFrozen()) {
                 key = key.strDup(runtimekey.getMetaClass().getRealClass());
                 key.setFrozen(true);
             }
             internalPutSmall(keyvaluefalse);
         }
     }

    
Note: this is included as a compatibility measure for AR-JDBC

Deprecated:
use RubyHash.op_aset instead
 
     public IRubyObject aset(IRubyObject keyIRubyObject value) {
         return op_aset(getRuntime().getCurrentContext(), keyvalue);
     }

    
Note: this is included as a compatibility measure for Mongrel+JRuby

Deprecated:
use RubyHash.op_aref instead
 
     public IRubyObject aref(IRubyObject key) {
         return op_aref(getRuntime().getCurrentContext(), key);
    }
    public final IRubyObject fastARef(IRubyObject key) { // retuns null when not found to avoid unnecessary getRuntime().getNil() call
        return internalGet(key);
    }
    public RubyBoolean compare(final ThreadContext contextfinal MethodNames methodIRubyObject other) {
        Ruby runtime = context.runtime;
        if (!(other instanceof RubyHash)) {
            if (!other.respondsTo("to_hash")) {
                return runtime.getFalse();
            } else {
                return RuntimeHelpers.rbEqual(contextotherthis);
            }
        }
        final RubyHash otherHash = (RubyHashother;
        if (this. != otherHash.size) {
            return runtime.getFalse();
        }
        try {
            visitAll(new Visitor() {
                public void visit(IRubyObject keyIRubyObject value) {
                    IRubyObject value2 = otherHash.fastARef(key);
                    if (value2 == null) {
                        // other hash does not contain key
                        throw ;
                    }
                    if (!(method == . ?
                            RuntimeHelpers.rbEqual(contextvaluevalue2) :
                            RuntimeHelpers.rbEql(contextvaluevalue2)).isTrue()) {
                        throw ;
                    }
                }
            });
        } catch (Mismatch e) {
            return runtime.getFalse();
        }
        
        return runtime.getTrue();
    }

    
rb_hash_equal
    @JRubyMethod(name = "==")
    public IRubyObject op_equal(final ThreadContext contextIRubyObject other) {
        return RecursiveComparator.compare(context.thisother);
    }

    
rb_hash_eql
    @JRubyMethod(name = "eql?")
    public IRubyObject op_eql19(final ThreadContext contextIRubyObject other) {
        return RecursiveComparator.compare(context.thisother);
    }

    
rb_hash_aref
    @JRubyMethod(name = "[]", required = 1)
    public IRubyObject op_aref(ThreadContext contextIRubyObject key) {
        IRubyObject value;
        return ((value = internalGet(key)) == null) ? callMethod(context"default"key) : value;
    }

    
rb_hash_hash
    @JRubyMethod(name = "hash", compat = )
    public RubyFixnum hash() {
        final Ruby runtime = getRuntime();
        final ThreadContext context = runtime.getCurrentContext();
        if ( == 0 || runtime.isInspecting(this)) return RubyFixnum.zero(runtime);
        final long hash[] = new long[]{};
        
        try {
            runtime.registerInspecting(this);
            visitAll(new Visitor() {
                public void visit(IRubyObject keyIRubyObject value) {
                    hash[0] ^= invokedynamic(contextkey).convertToInteger().getLongValue();
                    hash[0] ^= invokedynamic(contextvalue).convertToInteger().getLongValue();
                }
            });
        } finally {
            runtime.unregisterInspecting(this);
        }
        return RubyFixnum.newFixnum(runtimehash[0]);
    }

    
rb_hash_hash
    @JRubyMethod(name = "hash", compat = )
    public RubyFixnum hash19() {
        final Ruby runtime = getRuntime();
        final ThreadContext context = runtime.getCurrentContext();
                public IRubyObject call(IRubyObject objboolean recur) {