001    // Copyright 2005 The Apache Software Foundation
002    //
003    // Licensed under the Apache License, Version 2.0 (the "License");
004    // you may not use this file except in compliance with the License.
005    // You may obtain a copy of the License at
006    //
007    //     http://www.apache.org/licenses/LICENSE-2.0
008    //
009    // Unless required by applicable law or agreed to in writing, software
010    // distributed under the License is distributed on an "AS IS" BASIS,
011    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012    // See the License for the specific language governing permissions and
013    // limitations under the License.
014    
015    package org.apache.tapestry.util;
016    
017    /**
018     * A simple map-like collection, similar to (but more more limited than) JDK 1.4's IdentityHashMap.
019     * It is designed for <em>small</em> collections of objects.
020     * 
021     * @author Howard Lewis Ship
022     * @since 4.0
023     */
024    public class ObjectIdentityMap
025    {
026        private int _pairCount = 0;
027    
028        // Alternates between keys and values
029    
030        private Object[] _pairs;
031    
032        /**
033         * Adds or updates a key in the bag.
034         * 
035         * @param key
036         *            the key to store a value under; an existing value with the key is discarded
037         * @param value
038         *            the value to store
039         */
040        public void put(Object key, Object value)
041        {
042            for (int i = 0; i < _pairCount; i++)
043            {
044                int index = 2 * i;
045    
046                if (_pairs[index] == key)
047                {
048                    _pairs[index + 1] = value;
049                    return;
050                }
051            }
052    
053            expandPairsIfNeeded();
054    
055            int index = 2 * _pairCount;
056    
057            _pairs[index] = key;
058            _pairs[index + 1] = value;
059    
060            _pairCount++;
061        }
062    
063        /**
064         * Returns the object stored for the given key.
065         * 
066         * @return the value, or null if the key is not found
067         */
068    
069        public Object get(Object key)
070        {
071            for (int i = 0; i < _pairCount; i++)
072            {
073                int index = 2 * i;
074    
075                if (_pairs[index] == key)
076                {
077                    return _pairs[index + 1];
078                }
079            }
080    
081            return null;
082        }
083    
084        private void expandPairsIfNeeded()
085        {
086            int currentSize = _pairs == null ? 0 : _pairs.length;
087    
088            int newLength = 2 * (_pairCount + 1);
089    
090            if (newLength >= currentSize)
091            {
092                // Expand to dobule current size. Allocate room for 5 keys and 5 values
093                // initially.
094    
095                int newSize = Math.max(10, 2 * currentSize);
096    
097                Object[] newPairsArray = new Object[newSize];
098    
099                if (currentSize > 0)
100                    System.arraycopy(_pairs, 0, newPairsArray, 0, currentSize);
101    
102                _pairs = newPairsArray;
103            }
104        }
105    }