1   package org.djutils.immutablecollections;
2   
3   import java.util.Comparator;
4   import java.util.Map;
5   import java.util.Map.Entry;
6   import java.util.NavigableMap;
7   import java.util.NavigableSet;
8   import java.util.TreeMap;
9   import java.util.TreeSet;
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  public class ImmutableTreeMap<K, V> extends ImmutableAbstractMap<K, V> implements ImmutableNavigableMap<K, V>
25  {
26      
27      private ImmutableSortedSet<K> cachedKeySet = null;
28  
29      
30      private ImmutableSortedSet<ImmutableEntry<K, V>> cachedEntrySet = null;
31  
32      
33  
34  
35      public ImmutableTreeMap(final Map<K, V> sortedMap)
36      {
37          super(new TreeMap<K, V>(sortedMap), Immutable.COPY);
38      }
39  
40      
41  
42  
43  
44      public ImmutableTreeMap(final NavigableMap<K, V> map, final Immutable copyOrWrap)
45      {
46          super(copyOrWrap == Immutable.COPY ? new TreeMap<K, V>(map) : map, copyOrWrap);
47      }
48  
49      
50  
51  
52      public ImmutableTreeMap(final ImmutableAbstractMap<K, V> immutableMap)
53      {
54          super(new TreeMap<K, V>(immutableMap.getUnderlyingMap()), Immutable.COPY);
55      }
56  
57      
58  
59  
60  
61      public ImmutableTreeMap(final ImmutableTreeMap<K, V> immutableTreeMap, final Immutable copyOrWrap)
62      {
63          super(copyOrWrap == Immutable.COPY ? new TreeMap<K, V>(immutableTreeMap.getUnderlyingMap())
64                  : immutableTreeMap.getUnderlyingMap(), copyOrWrap);
65      }
66  
67      @Override
68      protected final NavigableMap<K, V> getUnderlyingMap()
69      {
70          return (NavigableMap<K, V>) super.getUnderlyingMap();
71      }
72  
73      @Override
74      public final NavigableMap<K, V> toMap()
75      {
76          return new TreeMap<K, V>(super.getUnderlyingMap());
77      }
78  
79      @Override
80      public final ImmutableSortedSet<K> keySet()
81      {
82          if (this.cachedKeySet == null)
83          {
84              NavigableSet<K> immutableKeySet = new TreeSet<>(getUnderlyingMap().comparator());
85              immutableKeySet.addAll(getUnderlyingMap().keySet());
86              this.cachedKeySet = new ImmutableTreeSet<>(immutableKeySet, Immutable.WRAP);
87          }
88          return this.cachedKeySet;
89      }
90  
91      @Override
92      public ImmutableSortedSet<ImmutableEntry<K, V>> entrySet()
93      {
94          if (this.cachedEntrySet == null)
95          {
96              NavigableSet<ImmutableEntry<K, V>> immutableEntrySet = new TreeSet<>(new Comparator<ImmutableEntry<K, V>>()
97              {
98                  @SuppressWarnings("unchecked")
99                  @Override
100                 public int compare(final ImmutableEntry<K, V> o1, final ImmutableEntry<K, V> o2)
101                 {
102                     return ((Comparable<K>) o1.getKey()).compareTo(o2.getKey());
103                 }
104 
105             });
106             for (Entry<K, V> entry : getUnderlyingMap().entrySet())
107             {
108                 immutableEntrySet.add(new ImmutableEntry<>(entry));
109             }
110             this.cachedEntrySet = new ImmutableTreeSet<>(immutableEntrySet, Immutable.WRAP);
111         }
112         return this.cachedEntrySet;
113     }
114 
115     @Override
116     public ImmutableSortedSet<V> values()
117     {
118         if (this.cachedValues == null)
119         {
120             NavigableSet<V> immutableValues = new TreeSet<>(getUnderlyingMap().values());
121             this.cachedValues = new ImmutableTreeSet<>(immutableValues, Immutable.WRAP);
122         }
123         return (ImmutableNavigableSet<V>) this.cachedValues;
124     }
125 
126     @Override
127     public final Comparator<? super K> comparator()
128     {
129         return getUnderlyingMap().comparator();
130     }
131 
132     @Override
133     public final ImmutableSortedMap<K, V> subMap(final K fromKey, final K toKey)
134     {
135         return new ImmutableTreeMap<K, V>(getUnderlyingMap().subMap(fromKey, toKey));
136     }
137 
138     @Override
139     public final ImmutableSortedMap<K, V> headMap(final K toKey)
140     {
141         return new ImmutableTreeMap<K, V>(getUnderlyingMap().headMap(toKey));
142     }
143 
144     @Override
145     public final ImmutableSortedMap<K, V> tailMap(final K fromKey)
146     {
147         return new ImmutableTreeMap<K, V>(getUnderlyingMap().tailMap(fromKey));
148     }
149 
150     @Override
151     public final K firstKey()
152     {
153         return getUnderlyingMap().firstKey();
154     }
155 
156     @Override
157     public final K lastKey()
158     {
159         return getUnderlyingMap().lastKey();
160     }
161 
162     @Override
163     public final K lowerKey(final K key)
164     {
165         return getUnderlyingMap().lowerKey(key);
166     }
167 
168     @Override
169     public final K floorKey(final K key)
170     {
171         return getUnderlyingMap().floorKey(key);
172     }
173 
174     @Override
175     public final K ceilingKey(final K key)
176     {
177         return getUnderlyingMap().ceilingKey(key);
178     }
179 
180     @Override
181     public final K higherKey(final K key)
182     {
183         return getUnderlyingMap().higherKey(key);
184     }
185 
186     @Override
187     public final ImmutableNavigableMap<K, V> descendingMap()
188     {
189         return new ImmutableTreeMap<K, V>(getUnderlyingMap().descendingMap());
190     }
191 
192     @Override
193     public final ImmutableNavigableMap<K, V> subMap(final K fromKey, final boolean fromInclusive, final K toKey,
194             final boolean toInclusive)
195     {
196         return new ImmutableTreeMap<K, V>(getUnderlyingMap().subMap(fromKey, fromInclusive, toKey, toInclusive));
197     }
198 
199     @Override
200     public final ImmutableNavigableMap<K, V> headMap(final K toKey, final boolean inclusive)
201     {
202         return new ImmutableTreeMap<K, V>(getUnderlyingMap().headMap(toKey, inclusive));
203     }
204 
205     @Override
206     public final ImmutableNavigableMap<K, V> tailMap(final K fromKey, final boolean inclusive)
207     {
208         return new ImmutableTreeMap<K, V>(getUnderlyingMap().tailMap(fromKey, inclusive));
209     }
210 
211     @Override
212     public final String toString()
213     {
214         NavigableMap<K, V> map = getUnderlyingMap();
215         if (null == map)
216         {
217             return "ImmutableTreeMap []";
218         }
219         return "ImmutableTreeMap [" + map.toString() + "]";
220     }
221 
222 }