001package com.hfg.util.collection;
002
003import java.util.ArrayList;
004import java.util.Collection;
005import java.util.HashMap;
006import java.util.Map;
007import java.util.Set;
008import java.util.function.BiConsumer;
009import java.util.function.BiFunction;
010import java.util.function.Function;
011
012//------------------------------------------------------------------------------
013/**
014 * HashMap that preserves the key order.
015 * @author J. Alex Taylor, hairyfatguy.com
016 */
017//------------------------------------------------------------------------------
018// com.hfg Library
019//
020// This library is free software; you can redistribute it and/or
021// modify it under the terms of the GNU Lesser General Public
022// License as published by the Free Software Foundation; either
023// version 2.1 of the License, or (at your option) any later version.
024//
025// This library is distributed in the hope that it will be useful,
026// but WITHOUT ANY WARRANTY; without even the implied warranty of
027// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
028// Lesser General Public License for more details.
029//
030// You should have received a copy of the GNU Lesser General Public
031// License along with this library; if not, write to the Free Software
032// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
033//
034// J. Alex Taylor, President, Founder, CEO, COO, CFO, OOPS hairyfatguy.com
035// jataylor@hairyfatguy.com
036//------------------------------------------------------------------------------
037
038public class OrderedMap<K, V> extends HashMap<K, V>
039{
040   private OrderedSet<K> mOrderedKeys;
041
042   //##########################################################################
043   // CONSTRUCTORS
044   //##########################################################################
045
046   //--------------------------------------------------------------------------
047   public OrderedMap()
048   {
049      super();
050      mOrderedKeys = new OrderedSet<>();
051   }
052
053   //--------------------------------------------------------------------------
054   public OrderedMap(int inInitialCapacity)
055   {
056      super(inInitialCapacity);
057      mOrderedKeys = new OrderedSet<>(inInitialCapacity);
058   }
059
060   //--------------------------------------------------------------------------
061   public OrderedMap(int inInitialCapacity, float loadFactor)
062   {
063      super(inInitialCapacity, loadFactor);
064      mOrderedKeys = new OrderedSet<>(inInitialCapacity);
065   }
066
067   //--------------------------------------------------------------------------
068   public OrderedMap(Map<? extends K,? extends V> m)
069   {
070      super(m);
071      mOrderedKeys = new OrderedSet<>(m.keySet());
072   }
073
074   //##########################################################################
075   // PUBLIC METHODS
076   //##########################################################################
077
078   //--------------------------------------------------------------------------
079   @Override
080   public void clear()
081   {
082      mOrderedKeys.clear();
083      super.clear();
084   }
085
086   //--------------------------------------------------------------------------
087   @Override
088   public V put(K inKey, V inValue)
089   {
090      mOrderedKeys.add(inKey);
091      return super.put(inKey, inValue);
092   }
093
094   //--------------------------------------------------------------------------
095   @Override
096   public void putAll(Map<? extends K,? extends V> m)
097   {
098      for (K key : m.keySet())
099      {
100         put(key, m.get(key));
101      }
102   }
103
104   //--------------------------------------------------------------------------
105   @Override
106   public V putIfAbsent(K inKey, V inValue)
107   {
108      mOrderedKeys.add(inKey);
109      return super.putIfAbsent(inKey, inValue);
110   }
111
112   //--------------------------------------------------------------------------
113   @Override
114   public V computeIfPresent(K inKey,
115                             BiFunction<? super K, ? super V, ? extends V> inRemappingFunction)
116   {
117      mOrderedKeys.add(inKey);
118      return super.computeIfPresent(inKey, inRemappingFunction);
119   }
120
121   //--------------------------------------------------------------------------
122   @Override
123   public V computeIfAbsent(K inKey,
124                            Function<? super K, ? extends V> inRemappingFunction)
125   {
126      mOrderedKeys.add(inKey);
127      return super.computeIfAbsent(inKey, inRemappingFunction);
128   }
129
130   //--------------------------------------------------------------------------
131   @Override
132   public V compute(K inKey,
133                    BiFunction<? super K, ? super V, ? extends V> inRemappingFunction)
134   {
135      mOrderedKeys.add(inKey);
136      return super.compute(inKey, inRemappingFunction);
137   }
138
139   //--------------------------------------------------------------------------
140   @Override
141   public V merge(K inKey, V inValue,
142                  BiFunction<? super V, ? super V, ? extends V> inRemappingFunction)
143   {
144      mOrderedKeys.add(inKey);
145      return super.merge(inKey, inValue, inRemappingFunction);
146   }
147
148   //--------------------------------------------------------------------------
149   @Override
150   public Collection<V> values()
151   {
152      Collection<V> values = null;
153      if (CollectionUtil.hasValues(this))
154      {
155         values = new ArrayList<V>(size());
156         for (K key : keySet())
157         {
158            values.add(get(key));
159         }
160      }
161
162      return values;
163   }
164
165   //--------------------------------------------------------------------------
166   @Override
167   public V remove(Object inKey)
168   {
169      mOrderedKeys.remove(inKey);
170      return super.remove(inKey);
171   }
172
173   //--------------------------------------------------------------------------
174   @Override
175   public OrderedSet<K> keySet()
176   {
177      return mOrderedKeys;
178   }
179
180   //--------------------------------------------------------------------------
181   @Override
182   public Set<Entry<K, V>> entrySet()
183   {
184      Set<Entry<K, V>> orderedEntries = new OrderedSet<>(size());
185
186      for (K key : keySet())
187      {
188         orderedEntries.add(new OrderedEntry(key, get(key)));
189      }
190
191      return orderedEntries;
192   }
193
194   //--------------------------------------------------------------------------
195   @Override
196   public void forEach(BiConsumer<? super K, ? super V> inAction)
197   {
198      for (K key : keySet())
199      {
200         inAction.accept(key, get(key));
201      }
202   }
203
204
205   private class OrderedEntry implements Map.Entry<K, V>
206   {
207      private K mKey;
208      private V mValue;
209
210      //-----------------------------------------------------------------------
211      public OrderedEntry(K inKey, V inValue)
212      {
213         mKey = inKey;
214         mValue = inValue;
215      }
216
217      //-----------------------------------------------------------------------
218      @Override
219      public K getKey()
220      {
221         return mKey;
222      }
223
224      //-----------------------------------------------------------------------
225      @Override
226      public V getValue()
227      {
228         return mValue;
229      }
230
231      //-----------------------------------------------------------------------
232      @Override
233      public V setValue(V inValue)
234      {
235         V oldValue = mValue;
236         mValue = inValue;
237
238         return oldValue;
239      }
240   }
241}