001// ***************************************************************************************************************************
002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
003// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
005// * with the License.  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 distributed under the License is distributed on an  *
010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
011// * specific language governing permissions and limitations under the License.                                              *
012// ***************************************************************************************************************************
013package org.apache.juneau.internal;
014
015import static org.apache.juneau.common.internal.ArgUtils.*;
016import static org.apache.juneau.internal.ArrayUtils.*;
017import java.lang.reflect.*;
018import java.util.*;
019
020/**
021 * An instance of a <c>Map</c> where the keys and values are simple arrays.
022 *
023 * <p>
024 * Typically more efficient than <c>HashMaps</c> for small maps (e.g. &lt;10 entries).
025 *
026 * <p>
027 * Does not support adding or removing entries.
028 *
029 * <p>
030 * Setting values overwrites the value on the underlying value array.
031 *
032 * <h5 class='section'>See Also:</h5><ul>
033
034 * </ul>
035 *
036 * @param <K> The key type.
037 * @param <V> The value type.
038 */
039public final class SimpleMap<K,V> extends AbstractMap<K,V> {
040
041   final K[] keys;
042   final V[] values;
043   final SimpleMapEntry[] entries;
044
045   /**
046    * Constructor.
047    *
048    * @param keys The map keys.  Must not be <jk>null</jk>.
049    * @param values The map values.  Must not be <jk>null</jk>.
050    */
051   @SuppressWarnings("unchecked")
052   public SimpleMap(K[] keys, V[] values) {
053      assertArgNotNull("keys", keys);
054      assertArgNotNull("values", values);
055      assertArg(keys.length == values.length, "keys ''{0}'' and values ''{1}'' array lengths differ", keys.length, values.length);
056
057      this.keys = keys;
058      this.values = values;
059      entries = (SimpleMapEntry[]) Array.newInstance(SimpleMapEntry.class, keys.length);
060      for (int i = 0; i < keys.length; i++) {
061         assertArg(keys[i] != null, "Keys array cannot contain a null value.");
062         entries[i] = new SimpleMapEntry(i);
063   }
064   }
065
066   @Override /* Map */
067   public Set<Map.Entry<K,V>> entrySet() {
068      return asSet(entries);
069   }
070
071   @Override /* Map */
072   public V get(Object key) {
073      for (int i = 0; i < keys.length; i++)
074         if (keys[i].equals(key))
075            return values[i];
076      return null;
077   }
078
079   @Override /* Map */
080   public Set<K> keySet() {
081      return asSet(keys);
082   }
083
084   @Override /* Map */
085   public V put(K key, V value) {
086      for (int i = 0; i < keys.length; i++) {
087         if (keys[i].equals(key)) {
088            V v = values[i];
089            values[i] = value;
090            return v;
091         }
092      }
093      throw new IllegalArgumentException("No key '"+key+"' defined in map");
094   }
095
096   final class SimpleMapEntry implements Map.Entry<K,V> {
097
098      private int index;
099
100      SimpleMapEntry(int index) {
101         this.index = index;
102      }
103
104      @Override /* Map.Entry */
105      public K getKey() {
106         return keys[index];
107      }
108
109      @Override /* Map.Entry */
110      public V getValue() {
111         return values[index];
112      }
113
114      @Override /* Map.Entry */
115      public V setValue(V val) {
116         V v = values[index];
117         values[index] = val;
118         return v;
119      }
120   }
121}