gt:             if(this == obj)
context: /* ---------------------------------------------------------------------
   * Numenta Platform for Intelligent Computing (NuPIC)
   * Copyright (C) 2014, Numenta, Inc.  Unless you have an agreement
   * with Numenta, Inc., for a separate license for this software code, the
   * following terms and conditions apply:
   *
   * This program is free software: you can redistribute it and/or modify
   * it under the terms of the GNU General Public License version 3 as
   * published by the Free Software Foundation.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
   * See the GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program.  If not, see http://www.gnu.org/licenses.
   *
   * http://numenta.org/licenses/
   * ---------------------------------------------------------------------
   */
  
  package org.numenta.nupic.util;
  
  import java.lang.reflect.Array;
  import java.util.Arrays;
  
  /**
   * Immutable tuple which adds associative lookup functionality.
   * 
   * @author David Ray
   */
  public class NamedTuple extends Tuple {
      Bucket[] entries;
      String[] keys;
      
      int hash;
      
      private static final String[] EMPTY_KEYS = {};
      
      /**
       * Constructs and new {@code NamedTuple}
       * 
       * @param keys      
       * @param objects
       */
      public NamedTuple(String[] keys, Object... objects) {
          super(interleave(keys, objects));
          
          if(keys.length != objects.length) {
              throw new IllegalArgumentException("Keys and values must be same length.");
          }
          
          this.keys = keys;
          
          entries = new Bucket[keys.length * 2];
          for(int i = 0;i < entries.length;i++) {
              entries[i] = new Bucket(i);
          }
          
          for(int i = 0;i < keys.length;i++) {
              addEntry(keys[i], objects[i]);
          }
      }
      
      /**
       * Returns a array copy of this {@code NamedTuple}'s keys.
       * @return
       */
      public String[] keys() {
          if(keys == null || keys.length < 1) return EMPTY_KEYS;
          
          return Arrays.copyOf(keys, keys.length);
      }
      
      /**
       * Returns the Object corresponding with the specified
       * key.
       * 
       * @param key   the identifier with the same corresponding index as 
       *              its value during this {@code NamedTuple}'s construction.
       * @return
       */
      public Object get(String key) {
          if(key == null) return null;
          
          int hash = hashIndex(key);
          Entry e = entries[hash].find(key, hash);
          return e == null ? null : e.value;
      }
      
      /**
       * Returns a flag indicating whether the specified key
       * exists within this {@code NamedTuple}
       * 
       * @param key
       * @return
       */
      public boolean hasKey(String key) {
          int hash = hashIndex(key);
          Entry e = entries[hash].find(key, hash);
          return e != null;
      }
      
      /**
       * {@inheritDoc}
       */
      public String toString() {
          StringBuilder sb = new StringBuilder();
          for(int i = 0;i < entries.length;i++) {
              sb.append(entries[i].toString());
          }
          return sb.toString();
      }
      
      /**
       * Creates an {@link Entry} with the hashed key value, checking 
       * for duplicates (which aren't allowed during construction).
       * 
       * @param key       the unique String identifier
       * @param value     the Object corresponding to the specified key
       */
      private void addEntry(String key, Object value) {
          int hash = hashIndex(key);
          Entry e;
          if((e = entries[hash].find(key, hash)) != null && e.key.equals(key)) {
              throw new IllegalStateException(
                  "Duplicates Not Allowed - Key: " + key + ", reinserted.");
          }
          
          Entry entry = new Entry(key, value, hash);
          entries[hash].add(entry);
      }
      
      /**
       * Creates and returns a hash code conforming to a number
       * between 0 - n-1, where n = #Buckets
       * 
       * @param key   String to be hashed.
       * @return
       */
      private int hashIndex(String key) {
          return Math.abs(key.hashCode()) % entries.length;
      }
      
      /**
       * {@inheritDoc}
       */
      @Override
      public int hashCode() {
          if(hash == 0) {
              final int prime = 31;
              int result = super.hashCode();
              result = prime * result + Arrays.hashCode(entries);
              hash = result;
          }
          return hash;
      }
  
      /**
       * {@inheritDoc}
       */
      @Override
      public boolean equals(Object obj) {
          if(this == obj)
              return true;
          if(getClass() != obj.getClass())
              return false;
          if(!super.equals(obj))
              return false;
          NamedTuple other = (NamedTuple)obj;
          if(!Arrays.equals(entries, other.entries))
              return false;
          return true;
      }
  
      /**
       * Encapsulates the hashed key/value pair in a linked node.
       */
      private final class Entry {
          String key;
          Object value;
          int hash;
          Entry prev;
          
          /**
           * Constructs a new {@code Entry}
           * 
           * @param key
           * @param value
           * @param hash
           */
          public Entry(String key, Object value, int hash) {
              this.key = key;
              this.value = value;
              this.hash = hashIndex(key);
          }
          
          /**
           * {@inheritDoc}
           */
          @Override
          public String toString() {
              return new StringBuilder("key=").append(key)
                  .append(", value=").append(value)
                      .append(", hash=").append(hash).toString();
          }
  
          /**
           * {@inheritDoc}
           */
          @Override
          public int hashCode() {
              final int prime = 31;
              int result = 1;
              result = prime * result + hash;
              result = prime * result + ((key == null) ? 0 : key.hashCode());
              return result;
          }
  
          /**
           * {@inheritDoc}
           */
          @Override
          public boolean equals(Object obj) {
  