/** 
 * This hashtable class is generated by TGen 2.0r.
 *
 * PLEASE DO NOT MODIFY THIS SOURCE.
 *
 * @author Ben L. Titzer
 * @author Christian Grothoff
 * @author TGen2
 **/

// HashtableName : HTSelector_Method2byteArray
// KeyType       : Selector.Method
// ValueType     : byte[]
// Compare       : .equals
// HashFunction  : .hashCode()
// NotFound      : null
// Default size  : 64
// Synchronized  : no
// Serializable  : no
// Iterator      : 
// Profiling     : no 

package s3.services.bootimage;

import ovm.core.repository.Selector;
 


/**
 * This Hashtable is generated by TGen. Its key type is Selector.Method and its
 * value type is byte[].
 * @author Ben L. Titzer
 * @author Christian Grothoff
 * @author TGen2
 **/
public class HTSelector_Method2byteArray extends ovm.core.OVMBase {



    public static final int MININT = Integer.MIN_VALUE;
    public static final byte[] NOTFOUND = null; 
    public static final HTSelector_Method2byteArray EMPTY 
        = new HTSelector_Method2byteArray(0) {
        /**
         * Put a key and value into the hashtable. Checks to see if
         * the key is already in the hashtable, and if so, updates
         * the value associated with the key.
         **/
         public void put(Selector.Method key, byte[] value) {
              throw new Error("can not put into empty Selector.Method");
         }
    }; /* end of EMPTY singleton */


    private static final int DEFAULT_SIZE = 64;

    final  int mask_;                     // mask for main arrays
    final  int maskCollisions_;           // mask for collision table
     int numElems_;                 // tracks the size of the hashtable
     Selector.Method[] keys_;     // array of keys
     byte[][] values_; // array of values




    /**
     * If there is a collision, we keep the 'collided' elements in here (linked list).
     **/
     Binding[] collisions_;

    public HTSelector_Method2byteArray cloneHT() {
         HTSelector_Method2byteArray clone = new HTSelector_Method2byteArray(this);
         keys_ = (Selector.Method[]) keys_.clone();
         values_ = (byte[][]) values_.clone();
         Binding[] col = new Binding[collisions_.length];
         for (int i=0;i<collisions_.length;i++)
           if (collisions_[i] != null)
             col[i] = collisions_[i].cloneBinding();
         collisions_ = col;
         return clone;
    }

    /**
     * Internal binding class. Stores a key, value, and a link
     * to the next binding in the chain.
     **/
    static private final class Binding extends ovm.core.OVMBase {
	Binding link;
	Selector.Method key;
	byte[] value;
	Binding(Binding link, Selector.Method key, byte[] value) {
	    this.link = link;
	    this.key = key;
	    this.value = value;
	} 
        public String toString() {
            return "B(" + this.key + ","+this.value + ") ->" + link;
        }
        Binding cloneBinding() {
            if (link == null)
                return new Binding(null, key, value);
            else
                return new Binding(link.cloneBinding(), key, value);
        }
    }

    protected HTSelector_Method2byteArray complementaryView_;

    public  HTSelector_Method2byteArray getReadOnlyView() {
	if (complementaryView_ == null) {
		complementaryView_ = new ReadOnly(this);
	}		
	return complementaryView_;
    } 
	  
    private static class ReadOnly extends HTSelector_Method2byteArray {
	ReadOnly(HTSelector_Method2byteArray other) {	
		super(other);
	 	complementaryView_ = other;
	}

	public HTSelector_Method2byteArray getReadOnlyView() {
		return this;
	}
 	public void put(Selector.Method key, byte[] value) {
		throw new ovm.util.ReadonlyViewException();
	}
 	public int size() {
        	return complementaryView_.size();
    	}
    	public void remove(Selector.Method key) {
		throw new ovm.util.ReadonlyViewException();
	}
    }

    /**
     * Public default constructor.
     **/
    public HTSelector_Method2byteArray() {
	this(DEFAULT_SIZE);
    }

    protected HTSelector_Method2byteArray(HTSelector_Method2byteArray other) {
 	complementaryView_ = other.complementaryView_;
 	this.mask_ = other.mask_;
 	this.maskCollisions_ = other.maskCollisions_;
 	this.collisions_ = other.collisions_;
 	this.keys_ = other.keys_;
 	this.values_ = other.values_;
    }

    /**
     * Constructor to build a new hashtable. The size hint passed is used
     * to choose the least power of 2 greater than the hint for the hashtable.
     **/
    public HTSelector_Method2byteArray(int hint) {	    
        int size = 8;
	int sizeCollisions;
        while ( size < hint ) size *= 2;
        mask_ = size-1;
	sizeCollisions = size>>3;
	maskCollisions_ = sizeCollisions-1; /* make collision table 1/8th of the size of the main table */
	this.collisions_ = new Binding[sizeCollisions];
	this.keys_ = new Selector.Method[size];
	this.values_ = new byte[size][];

    }

    /**
     * Get a value from hashtable given a key. Returns the value NOTFOUND
     * if the key specified is not found in the hashtable.
     **/
    public final byte[] get(Selector.Method key) {
	int hash = mask_&key.hashCode();
	Selector.Method keys_hash = keys_[hash];
	if (keys_hash == null) {
           
	   return NOTFOUND;
        }
	if (key.equals(keys_hash)) {
           
	   return values_[hash];
        }
	return findInCollisions(maskCollisions_&hash, key);
    }

    /**
     * Put a key and value into the hashtable. Checks to see if
     * the key is already in the hashtable, and if so, updates
     * the value associated with the key. If the {@link #keys_ keys_},
     * {@link #collisions_ collisions_} or {@link #values_ values_} 
     * arrays (or any other internal state) ever change, notify the readonly 
     * view.  
     **/
    public void put(Selector.Method key, byte[] value) {
	int hash = mask_&key.hashCode();
   	Selector.Method keys_hash = keys_[hash];
	if (keys_hash == null) { // simple insert
           numElems_++;
           keys_[hash] = key;
           values_[hash] = value;
           
	   return;
        }     
        if (key.equals(keys_hash)) { // replace
	   values_[hash] = value;
	   
           return;
        } 
        // collision
	int hashCollision = hash&maskCollisions_;
	insertInCollisions(hashCollision, key, value);
	
    }

    /**
     * Return the size (number of elements currently present) of the hashtable.
     **/
    public int size() {
        return numElems_;
    }

    /**
     * Private function to search the collision table for a key value.
     * Searches the collisions_ table starting at the given offset until
     * either the correct Binding is found or the end of the list is reached.
     **/
    private final byte[] findInCollisions(int offset, Selector.Method key) {
	Binding p;
	

	for (p = collisions_[offset]; p != null; p = p.link) {
	    if (key.equals(p.key)) { 
	       return p.value;
            }
	    
        } 
	return NOTFOUND;
    }

    /**
     * Private function to insert a key and value into the collision table.
     * Searches the collisions_ table starting at the given offset and
     * continues until either the correct Binding is found, or the end of
     * the list is reached. If no Binding is found with the correct key, it
     * will create a new Binding to hold the key and value.
     **/
    private final  void insertInCollisions(int offset, 
					 Selector.Method key,
					 byte[] value) {
	Binding h = collisions_[offset], p;
	

	for (p = h; p != null; p = p.link) {
	    if (key.equals(p.key)) { 
                p.value = value;
                
	        return;
            }
	    
        }

        numElems_++;		
        collisions_[offset] = new Binding(h, key, value); 
    }



    public void  remove(Selector.Method key) {
	int hash = mask_ & key.hashCode();
	Selector.Method result = keys_[hash];
	if (result == null) return;
	if (key.equals(result)) { /* found match */
	    numElems_--;
	    int offset = maskCollisions_ & hash;	    
	    Binding p = collisions_[offset];
            for (; p!= null; p = p.link) 
		if ((mask_ & p.key.hashCode()) == hash) break;
	    if (p == null) {
		keys_[hash] = null;
		values_[hash] = NOTFOUND;
	    }
	    else {
		Binding prev = collisions_[offset];
		if (prev == p) collisions_[offset] = p.link;
		else {
		    while (prev.link != p) prev = prev.link;
		    prev.link = p.link;
		}
		keys_[hash] = p.key;
		values_[hash] = p.value;
	    }
	} else {
	    int offset = maskCollisions_ & hash;	    
	    Binding p = collisions_[offset];
            for (; p!= null; p = p.link) 
		if (key.equals(p.key)) break;
	    if (p != null) {
                numElems_--;
		Binding prev = collisions_[offset];
		if (prev == p) {
		    collisions_[offset] = p.link;
		} else {
		    while (prev.link != p) prev = prev.link;
		    prev.link = p.link;
		}
	    }
	}
    }


    public String toString() {
         StringBuffer result = new StringBuffer();
         result.append(super.toString());
         result.append("=(" + size() + "){");
         for (int i=0;i<keys_.length;i++) {
             result.append("(");
             result.append(" "+keys_[i]);
             result.append(",");
             result.append(" "+values_[i]);
             result.append("),\n");              
         }
         result.append("Collisions: ");
         for (int i=0;i<collisions_.length;i++) {
             result.append(collisions_[i]);
             result.append(",\n");
         }
         return result.toString();
    }
    
    public Iterator getIterator() { return new Iterator(); }

    public final class Iterator  {
	private int position_;
	private boolean iteratingOverKeys_;
	private Binding currentBinding_;
	private boolean reachEnd;
	
	Iterator() {
	    currentBinding_ = collisions_[0];
	    position_ = -1;
	    iteratingOverKeys_ = true;
	    reachEnd = false;
	    findNext();
	}
	public boolean hasNext() {
	    return !reachEnd;
        }
	public Selector.Method next() {
	    Selector.Method res;
	    if (iteratingOverKeys_) {
		res = keys_[position_];
	    } else {
		res = currentBinding_.key;
	    }
	    findNext();
	    return res;
	}

	public byte[] nextValue() {
	    byte[] res;
	    if (iteratingOverKeys_) {
		res = values_[position_];
	    } else {
		res = currentBinding_.value;
	    }
	    findNext();
	    return res;
	}

	public void remove() { throw new Error("Remove Not Implemented"); }

	private void findNext() {
	    if (iteratingOverKeys_) {
		position_++;
		while (position_ < keys_.length && 
		       keys_[position_] == null)
		    position_++;
		if (position_ == keys_.length) {
		    iteratingOverKeys_ = false;
		    position_ = 0;
		    while (position_ < collisions_.length &&
			   collisions_[position_] == null)
			position_++;
		    if (position_ == collisions_.length)
			reachEnd = true;
		    else
			currentBinding_ = collisions_[position_];
		}
	    } else {
		currentBinding_ = currentBinding_.link;
		if (currentBinding_ == null) {
		    position_++;
		    while (position_ < collisions_.length && 
			   collisions_[position_] == null)
			position_++;
		    if (position_ == collisions_.length)
			reachEnd = true;
		    else
			currentBinding_ = collisions_[position_];
		} 
	    }
        }
    } // End Iterator

} // End HTSelector_Method2byteArray




