1 #import "HashMap.h"
2 /**
3  * <p>Hash table and linked list implementation of the <tt>Map</tt> interface,
4  * with predictable iteration order.  This implementation differs from
5  * <tt>HashMap</tt> in that it maintains a doubly-linked list running through
6  * all of its entries.  This linked list defines the iteration ordering,
7  * which is normally the order in which keys were inserted into the map
8  * (<i>insertion-order</i>).  Note that insertion order is not affected
9  * if a key is <i>re-inserted</i> into the map.  (A key <tt>k</tt> is
10  * reinserted into a map <tt>m</tt> if <tt>m.put(k, v)</tt> is invoked when
11  * <tt>m.containsKey(k)</tt> would return <tt>true</tt> immediately prior to
12  * the invocation.)
13  *
14  * <p>This implementation spares its clients from the unspecified, generally
15  * chaotic ordering provided by {@link HashMap} (and {@link Hashtable}),
16  * without incurring the increased cost associated with {@link TreeMap}.  It
17  * can be used to produce a copy of a map that has the same order as the
18  * original, regardless of the original map's implementation:
19  * <pre>
20  * void foo(Map m) {
21  * Map copy = new LinkedHashMap(m);
22  * ...
23  * }
24  * </pre>
25  * This technique is particularly useful if a module takes a map on input,
26  * copies it, and later returns results whose order is determined by that of
27  * the copy.  (Clients generally appreciate having things returned in the same
28  * order they were presented.)
29  *
30  * <p>A special {@link #LinkedHashMap(NSInteger,float,boolean) constructor} is
31  * provided to create a linked hash map whose order of iteration is the order
32  * in which its entries were last accessed, from least-recently accessed to
33  * most-recently (<i>access-order</i>).  This kind of map is well-suited to
34  * building LRU caches.  Invoking the <tt>put</tt> or <tt>get</tt> method
35  * results in an access to the corresponding entry (assuming it exists after
36  * the invocation completes).  The <tt>putAll</tt> method generates one entry
37  * access for each mapping in the specified map, in the order that key-value
38  * mappings are provided by the specified map's entry set iterator.  <i>No
39  * other methods generate entry accesses.</i> In particular, operations on
40  * collection-views do <i>not</i> affect the order of iteration of the backing
41  * map.
42  *
43  * <p>The {@link #removeEldestEntry(Map.Entry)} method may be overridden to
44  * impose a policy for removing stale mappings automatically when new mappings
45  * are added to the map.
46  *
47  * <p>This class provides all of the optional <tt>Map</tt> operations, and
48  * permits null elements.  Like <tt>HashMap</tt>, it provides constant-time
49  * performance for the basic operations (<tt>add</tt>, <tt>contains</tt> and
50  * <tt>remove</tt>), assuming the hash function disperses elements
51  * properly among the buckets.  Performance is likely to be just slightly
52  * below that of <tt>HashMap</tt>, due to the added expense of maintaining the
53  * linked list, with one exception: Iteration over the collection-views
54  * of a <tt>LinkedHashMap</tt> requires time proportional to the <i>size</i>
55  * of the map, regardless of its capacity.  Iteration over a <tt>HashMap</tt>
56  * is likely to be more expensive, requiring time proportional to its
57  * <i>capacity</i>.
58  *
59  * <p>A linked hash map has two parameters that affect its performance:
60  * <i>initial capacity</i> and <i>load factor</i>.  They are defined precisely
61  * as for <tt>HashMap</tt>.  Note, however, that the penalty for choosing an
62  * excessively high value for initial capacity is less severe for this class
63  * than for <tt>HashMap</tt>, as iteration times for this class are unaffected
64  * by capacity.
65  *
66  * <p><strong>Note that this implementation is not synchronized.</strong>
67  * If multiple threads access a linked hash map concurrently, and at least
68  * one of the threads modifies the map structurally, it <em>must</em> be
69  * synchronized externally.  This is typically accomplished by
70  * synchronizing on some object that naturally encapsulates the map.
71  *
72  * If no such object exists, the map should be "wrapped" using the
73  * {@link Collections#synchronizedMap Collections.synchronizedMap}
74  * method.  This is best done at creation time, to prevent accidental
75  * unsynchronized access to the map:<pre>
76  * Map m = Collections.synchronizedMap(new LinkedHashMap(...));</pre>
77  *
78  * A structural modification is any operation that adds or deletes one or more
79  * mappings or, in the case of access-ordered linked hash maps, affects
80  * iteration order.  In insertion-ordered linked hash maps, merely changing
81  * the value associated with a key that is already contained in the map is not
82  * a structural modification.  <strong>In access-ordered linked hash maps,
83  * merely querying the map with <tt>get</tt> is a structural
84  * modification.</strong>)
85  *
86  * <p>The iterators returned by the <tt>iterator</tt> method of the collections
87  * returned by all of this class's collection view methods are
88  * <em>fail-fast</em>: if the map is structurally modified at any time after
89  * the iterator is created, in any way except through the iterator's own
90  * <tt>remove</tt> method, the iterator will throw a {@link
91  * ConcurrentModificationException}.  Thus, in the face of concurrent
92  * modification, the iterator fails quickly and cleanly, rather than risking
93  * arbitrary, non-deterministic behavior at an undetermined time in the future.
94  *
95  * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
96  * as it is, generally speaking, impossible to make any hard guarantees in the
97  * presence of unsynchronized concurrent modification.  Fail-fast iterators
98  * throw <tt>ConcurrentModificationException</tt> on a best-effort basis.
99  * Therefore, it would be wrong to write a program that depended on this
100  * exception for its correctness:   <i>the fail-fast behavior of iterators
101  * should be used only to detect bugs.</i>
102  *
103  * <p>This class is a member of the
104  * <a href="{@docRoot}/../technotes/guides/collections/index.html">
105  * Java Collections Framework</a>.
106  *
107  * @param <K> the type of keys maintained by this map
108  * @param <V> the type of mapped values
109  *
110  * @author  Josh Bloch
111  * @see     Object#hashCode()
112  * @see     Collection
113  * @see     Map
114  * @see     HashMap
115  * @see     TreeMap
116  * @see     Hashtable
117  * @since   1.4
118  */
119 @class LinkedHashMap;
120 
121 /**
122  * LinkedHashMap entry.
123  */
124 
125 @interface LHMEntry : HMEntry
126 {
127     LHMEntry *before;
128     LHMEntry *after;
129     BOOL accessOrder;
130 }
131 
132 @property (retain) LHMEntry *before;
133 @property (retain) LHMEntry *after;
134 @property (assign) BOOL accessOrder;
135 
136 - (id) newEntry:(NSInteger)aHash key:(NSString *)aKey value:(id)aValue next:(LHMEntry *)aNext;
137 
138 - (id) init:(NSInteger)hash key:(NSString *)key value:(id)value next:(LHMEntry *)next;
139 - (void) recordAccess:(LinkedHashMap *)m;
140 - (void) recordRemoval:(LinkedHashMap *)m;
141 
142 @end
143 
144 /**
145  * LinkedHashMapIterator.
146  */
147 
148 @interface LinkedHashIterator : HashIterator
149 {
150     LHMEntry *nextEntry;
151     LHMEntry *lastReturned;
152     LinkedHashMap *lhm;
153 }
154 
155 @property (retain) LHMEntry *nextEntry;
156 @property (retain) LHMEntry *lastReturned;
157 @property (retain) LinkedHashMap *lhm;
158 
159 + (LinkedHashIterator *) newIterator:(LinkedHashMap *)aLHM;
160 
161 - (id) init:(LinkedHashMap *)aLHM;
162 - (BOOL) hasNext;
163 - (void) remove;
164 - (LHMEntry *) nextEntry;
165 @end
166 
167 @interface LHMEntryIterator : LinkedHashIterator
168 {
169 }
170 
171 + (LHMEntryIterator *)newIterator:(LinkedHashMap *)aHM;
172 
173 - (id) init:(LinkedHashMap *)aHM;
174 - (LHMEntry *) next;
175 @end
176 
177 @interface LHMKeyIterator : LinkedHashIterator
178 {
179 }
180 
181 + (LHMKeyIterator *)newIterator:(LinkedHashMap *)aHM;
182 
183 - (id) init:(LinkedHashMap *)aHM;
184 - (NSString *) next;
185 @end
186 
187 @interface LHMValueIterator : LinkedHashIterator
188 {
189 }
190 
191 + (LHMValueIterator *)newIterator:(LinkedHashMap *)aHM;
192 
193 - (id) init:(LinkedHashMap *)aHM;
194 - (id) next;
195 @end
196 
197 
198 @interface LinkedHashMap : HashMap
199 {
200 
201     /**
202      * The head of the doubly linked list.
203      */
204     LHMEntry *header;
205     /**
206      * The iteration ordering method for this linked hash map: <tt>true</tt>
207      * for access-order, <tt>false</tt> for insertion-order.
208      *
209      * @serial
210      */
211     BOOL accessOrder;
212 
213 }
214 
215 @property (retain) LHMEntry *header;
216 @property (assign) BOOL accessOrder;
217 
218 + (id) newLinkedHashMap:(NSInteger)anInitialCapacity;
219 + (id) newLinkedHashMap:(NSInteger)anInitialCapacity
220              loadFactor:(float)loadFactor;
221 + (id) newLinkedHashMap:(NSInteger)anInitialCapacity
222              loadFactor:(float)loadFactor
223             accessOrder:(BOOL)anAccessOrder;
224 
225 - (id) init:(NSInteger)initialCapacity loadFactor:(float)loadFactor accessOrder:(BOOL)accessOrder;
226 - (id) init:(NSInteger)initialCapacity loadFactor:(float)loadFactor;
227 - (id) init:(NSInteger)initialCapacity;
228 - (id) init;
229 - (id) initWithM:(AMutableDictionary *)m;
230 - (void) transfer:(NSArray *)newTable;
231 - (BOOL) containsValue:(NSObject *)value;
232 - (id) get:(NSString *)key;
233 - (void) clear;
234 - (LHMEntryIterator *) newEntryIterator;
235 - (LHMKeyIterator *) newKeyIterator;
236 - (LHMValueIterator *) newValueIterator;
237 - (void) addEntry:(NSInteger)hash key:(NSString *)key value:(id)value bucketIndex:(NSInteger)bucketIndex;
238 - (void) createEntry:(NSInteger)hash key:(NSString *)key value:(id)value bucketIndex:(NSInteger)bucketIndex;
239 - (BOOL) removeEldestEntry:(LHMEntry *)eldest;
240 @end
241