1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.millscript.commons.util.map;
22
23 import java.io.Serializable;
24
25 import org.millscript.commons.alert.alerts.Fault;
26 import org.millscript.commons.util.IList;
27 import org.millscript.commons.util.IMap;
28 import org.millscript.commons.util.ListIterator;
29 import org.millscript.commons.util.MapIterator;
30 import org.millscript.commons.util.Maplet;
31 import org.millscript.commons.util.alerts.KeyAlreadyExistsAlert;
32 import org.millscript.commons.util.alerts.ListIndexOutOfBoundsAlert;
33 import org.millscript.commons.util.iterator.AbstractListIterator;
34 import org.millscript.commons.util.iterator.AbstractMapIterator;
35 import org.millscript.commons.util.iterator.ArrayListIterator;
36 import org.millscript.commons.util.list.AbstractIList;
37 import org.millscript.commons.util.list.IArrayList;
38 import org.millscript.commons.util.maplet.IMaplet;
39
40 /**
41 * This class provides an immutable <code>Map</code> implementation that uses
42 * an array of hash code buckets to store the data.
43 */
44 public class ILinkedHashMap< K, V > extends AbstractIMap< K, V > implements Cloneable, Serializable {
45
46 /**
47 * This is the ID from the release 0.1.0 for future compatibility.
48 */
49 private static final long serialVersionUID = 2779589907033092111L;
50
51 /**
52 * This class implements a map iterator which iterates over an array
53 * of hash map buckets.
54 */
55 public static class LinkedHashMapIterator< K, V > extends AbstractMapIterator< K, V > {
56
57 /**
58 * The maplet for the current point in the iteration.
59 */
60 private LinkedHashMaplet< K, V > currentMaplet;
61
62 /**
63 * The next maplet in the iteration. If this is <code>null</code> there
64 * are no more elements in the iteration.
65 */
66 private LinkedHashMaplet< K, V > nextMaplet;
67
68 /**
69 * Constructs a new hash map iterator to iterate over the specified
70 * array of hash map buckets.
71 *
72 * @param first the first element to be returned in the iteration
73 * @param share if <code>true</code> the specified object array will be
74 * shared otherwise the array will be copied.
75 */
76 public LinkedHashMapIterator( final LinkedHashMaplet< K, V > first, final boolean share ) {
77 if ( share ) {
78 this.nextMaplet = first;
79 } else if ( first != null ) {
80 this.nextMaplet = first.deepCopy();
81 }
82 }
83
84 /**
85 * @see org.millscript.commons.util.iterator.AbstractMapIterator#advance()
86 */
87 @Override
88 protected void advance() {
89 this.currentMaplet = this.nextMaplet;
90 if ( this.nextMaplet != null ) {
91 this.nextMaplet = this.nextMaplet.nextByInsertion;
92 }
93 }
94
95 /**
96 * @see org.millscript.commons.util.iterator.AbstractMapIterator#getKey()
97 */
98 @Override
99 protected K getKey() {
100 return currentMaplet.getKey();
101 }
102
103 /**
104 * @see org.millscript.commons.util.iterator.AbstractMapIterator#getValue()
105 */
106 @Override
107 protected V getValue() {
108 return currentMaplet.getValue();
109 }
110
111 /**
112 * @see org.millscript.commons.util.MapIterator#hasNext()
113 */
114 public boolean hasNext() {
115 return this.nextMaplet != null;
116 }
117
118 /**
119 * @see org.millscript.commons.util.iterator.AbstractMapIterator#outOfBounds()
120 */
121 @Override
122 protected boolean outOfBounds() {
123 return currentMaplet == null;
124 }
125
126 }
127
128 /**
129 * This class implements a map iterator which iterates over an array
130 * of hash map buckets, returning each maplet key.
131 */
132 public static class LinkedHashMapKeysIterator< K > extends LinkedHashMapXIterator< K > {
133
134 /**
135 * Constructs a new hash map iterator to iterate over the specified
136 * array of hash map buckets returning the maplet keys.
137 *
138 * @param start the first LinkedHashMaplet in the iteration
139 * @param num the number of elements in the iteration
140 */
141 public LinkedHashMapKeysIterator( final LinkedHashMaplet< ?, ? > start, final int num ) {
142 super( start, num );
143 }
144
145 /**
146 * @see org.millscript.commons.util.map.ILinkedHashMap.LinkedHashMapXIterator#getAppropriateMapletPart(org.millscript.commons.util.Maplet)
147 */
148 @Override
149 @SuppressWarnings( "unchecked" )
150 K getAppropriateMapletPart( final Maplet< ?, ? > maplet ) {
151 return (K) maplet.getKey();
152 }
153
154 }
155
156 /**
157 * This class implements an immutable list which is backed by an array of
158 * hash map buckets, but NOTE the values in the list are actually the
159 * individual hash maplet keys.
160 */
161 public static class LinkedHashMapKeysList< K > extends LinkedHashMapXList< K > {
162
163 /**
164 * Constructs a new hash maplet array list of the individual maplet
165 * keys.
166 *
167 * @param start the LinkedHashMap element with index 1
168 * @param num the number of elements in the list
169 */
170 public LinkedHashMapKeysList( final LinkedHashMaplet< ?, ? > start, final int num ) {
171 super( start, num );
172 }
173
174 /**
175 * Constructs a new hash maplet array list of the individual maplet
176 * keys.
177 *
178 * @param start the LinkedHashMap element with index 1
179 * @param first the index(one based, inclusive) of the first name
180 * @param last the index(one based, inclusive) of the last name
181 */
182 public LinkedHashMapKeysList( final LinkedHashMaplet< ?, ? > start, final int first, final int last ) {
183 super( start, first, last );
184 }
185
186 /**
187 * @see org.millscript.commons.util.map.ILinkedHashMap.LinkedHashMapXList#getAppropriateMapletPart(org.millscript.commons.util.Maplet)
188 */
189 @Override
190 @SuppressWarnings( "unchecked" )
191 K getAppropriateMapletPart( final Maplet< ?, ? > maplet ) {
192 return (K) maplet.getKey();
193 }
194
195 /**
196 * @see org.millscript.commons.util.map.IHashMap.LinkedHashMapKeysIterator.LinkedHashMapXList#sharedIterator()
197 */
198 @Override
199 ListIterator< K > sharedIterator() {
200 return new LinkedHashMapKeysIterator< K >( this.firstHashMaplet, this.size );
201 }
202
203 /**
204 * @see org.millscript.commons.util.map.ILinkedHashMap.LinkedHashMapXList#sharedSlice(int, int)
205 */
206 @Override
207 IList< K > sharedSlice( final int first, final int last ) {
208 return new LinkedHashMapKeysList< K >( this.firstHashMaplet, first, last );
209 }
210
211 }
212
213 /**
214 * This class provides an immutable implementation of a <code>Maplet</code>
215 * which also acts as a bucket in our hashmap.
216 */
217 private static class LinkedHashMaplet< K, V > extends IMaplet< K, V > {
218
219 /**
220 * This is the ID from the release 0.1.0 for future compatibility.
221 */
222 private static final long serialVersionUID = 7458320862201860770L;
223
224 /**
225 * The next hash maplet in this chain.
226 */
227 LinkedHashMaplet< K, V > next;
228
229 /**
230 * The next hash maplet in the insertion order.
231 */
232 LinkedHashMaplet< K, V > nextByInsertion;
233
234 /**
235 * Constructs a new hash maplet with the given key and value.
236 *
237 * @param previous the previous LinkedHashMaplet that was inserted
238 * into this map
239 * @param k the maplets key
240 * @param v the maplets value
241 */
242 private LinkedHashMaplet( final LinkedHashMaplet< K, V > previous, final K k, final V v ) {
243 super( k, v );
244 if ( previous != null ) {
245 previous.nextByInsertion = this;
246 }
247 }
248
249 /**
250 * Constructs a new hash maplet taking its key and value from the
251 * specified maplet.
252 *
253 * @param previous the previous LinkedHashMaplet that was inserted
254 * into this map
255 * @param m the maplet to copy the key and value from
256 */
257 private LinkedHashMaplet( final LinkedHashMaplet< K, V > previous, final Maplet< K, V > m ) {
258 super( m );
259 if ( previous != null ) {
260 previous.nextByInsertion = this;
261 }
262 }
263
264 LinkedHashMaplet< K, V > deepCopy() {
265 return new LinkedHashMaplet< K, V >(
266 this.nextByInsertion == null ? null : this.nextByInsertion.deepCopy(),
267 this
268 );
269 }
270
271 }
272
273 /**
274 * This class implements a map iterator which iterates over an array
275 * of hash map buckets, returning each maplet as the value.
276 */
277 public static class LinkedHashMapMapletIterator< K, V > extends LinkedHashMapXIterator< Maplet< K, V > > {
278
279 /**
280 * Constructs a new hash map iterator to iterate over the specified
281 * array of hash map buckets returning the maplet as the value.
282 *
283 * @param start the first LinkedHashMaplet in the iteration
284 * @param num the number of elements in the iteration
285 */
286 public LinkedHashMapMapletIterator( final LinkedHashMaplet< ?, ? > start, final int num ) {
287 super( start, num );
288 }
289
290 /**
291 * @see org.millscript.commons.util.map.ILinkedHashMap.LinkedHashMapXIterator#getAppropriateMapletPart(org.millscript.commons.util.Maplet)
292 */
293 @Override
294 @SuppressWarnings( "unchecked" )
295 Maplet< K, V > getAppropriateMapletPart( final Maplet< ?, ? > maplet ) {
296 return (Maplet< K, V >) maplet;
297 }
298
299 }
300
301 /**
302 * This class implements an immutable list which is backed by an array of
303 * hash map buckets, but NOTE the values in the list are actually the
304 * individual hash maplets themselves.
305 */
306 public static class LinkedHashMapMapletList< K, V > extends LinkedHashMapXList< Maplet< K, V > > {
307
308 /**
309 * Constructs a new hash maplet array list of the individual maplets.
310 *
311 * @param start the LinkedHashMap element with index 1
312 * @param num the number of elements in the list
313 */
314 public LinkedHashMapMapletList( final LinkedHashMaplet< ?, ? > start, final int num ) {
315 super( start, num );
316 }
317
318 /**
319 * Constructs a new hash maplet array list of the individual maplets.
320 *
321 * @param start the LinkedHashMap element with index 1
322 * @param first the index(one based, inclusive) of the first name
323 * @param last the index(one based, inclusive) of the last name
324 */
325 public LinkedHashMapMapletList( final LinkedHashMaplet< ?, ? > start, final int first, final int last ) {
326 super( start, first, last );
327 }
328
329 /**
330 * @see org.millscript.commons.util.map.ILinkedHashMap.LinkedHashMapXList#getAppropriateMapletPart(org.millscript.commons.util.Maplet)
331 */
332 @Override
333 @SuppressWarnings( "unchecked" )
334 Maplet< K, V > getAppropriateMapletPart( final Maplet< ?, ? > maplet ) {
335 return (Maplet< K, V >) maplet;
336 }
337
338 /**
339 * @see org.millscript.commons.util.map.IHashMap.LinkedHashMapKeysIterator.LinkedHashMapXList#sharedIterator()
340 */
341 @Override
342 ListIterator< Maplet< K, V > > sharedIterator() {
343 return new LinkedHashMapMapletIterator< K, V >( this.firstHashMaplet, this.size );
344 }
345
346 /**
347 * @see org.millscript.commons.util.map.ILinkedHashMap.LinkedHashMapXList#sharedSlice(int, int)
348 */
349 @Override
350 IList< Maplet< K, V > > sharedSlice( final int first, final int last ) {
351 return new LinkedHashMapMapletList< K, V >( this.firstHashMaplet, first, last );
352 }
353
354 }
355
356 /**
357 * This class implements a map iterator which iterates over an array
358 * of hash map buckets, returning each maplet value.
359 */
360 public static class LinkedHashMapValuesIterator< V > extends LinkedHashMapXIterator< V > {
361
362 /**
363 * Constructs a new hash map iterator to iterate over the specified
364 * array of hash map buckets returning the maplet values.
365 *
366 * @param start the first LinkedHashMaplet in the iteration
367 * @param num the number of elements in the iteration
368 */
369 public LinkedHashMapValuesIterator( final LinkedHashMaplet< ?, ? > start, final int num ) {
370 super( start, num );
371 }
372
373 /**
374 * @see org.millscript.commons.util.map.ILinkedHashMap.LinkedHashMapXIterator#getAppropriateMapletPart(org.millscript.commons.util.Maplet)
375 */
376 @Override
377 @SuppressWarnings( "unchecked" )
378 V getAppropriateMapletPart( final Maplet< ?, ? > maplet ) {
379 return (V) maplet.getValue();
380 }
381
382 }
383
384 /**
385 * This class implements an immutable list which is backed by an array of
386 * hash map buckets, but NOTE the values in the list are actually the
387 * individual hash maplet values.
388 */
389 public static class LinkedHashMapValuesList< V > extends LinkedHashMapXList< V > {
390
391 /**
392 * Constructs a new hash maplet array list of the individual maplet
393 * values.
394 *
395 * @param start the LinkedHashMap element with index 1
396 * @param num the number of elements in the list
397 */
398 public LinkedHashMapValuesList( final LinkedHashMaplet< ?, ? > start, final int num ) {
399 super( start, num );
400 }
401
402 /**
403 * Constructs a new hash maplet array list of the individual maplet
404 * values.
405 *
406 * @param start the LinkedHashMap element with index 1
407 * @param first the index(one based, inclusive) of the first name
408 * @param last the index(one based, inclusive) of the last name
409 */
410 public LinkedHashMapValuesList( final LinkedHashMaplet< ?, ? > start, final int first, final int last ) {
411 super( start, first, last );
412 }
413
414 /**
415 * @see org.millscript.commons.util.map.ILinkedHashMap.LinkedHashMapXList#getAppropriateMapletPart(org.millscript.commons.util.Maplet)
416 */
417 @Override
418 @SuppressWarnings( "unchecked" )
419 V getAppropriateMapletPart( final Maplet< ?, ? > maplet ) {
420 return (V) maplet.getValue();
421 }
422
423 /**
424 * @see org.millscript.commons.util.map.IHashMap.LinkedHashMapKeysIterator.LinkedHashMapXList#sharedIterator()
425 */
426 @Override
427 ListIterator< V > sharedIterator() {
428 return new LinkedHashMapValuesIterator< V >( this.firstHashMaplet, this.size );
429 }
430
431 /**
432 * @see org.millscript.commons.util.map.ILinkedHashMap.LinkedHashMapXList#sharedSlice(int, int)
433 */
434 @Override
435 IList< V > sharedSlice( final int first, final int last ) {
436 return new LinkedHashMapValuesList< V >( this.firstHashMaplet, first, last );
437 }
438
439 }
440
441 /**
442 * This class implements a map iterator which iterates over an array
443 * of hash map buckets, returning either the keys or values.
444 */
445 private static abstract class LinkedHashMapXIterator< V > extends AbstractListIterator< V > {
446
447 /**
448 * The maplet for the current point in the iteration.
449 */
450 private LinkedHashMaplet< ?, ? > currentMaplet;
451
452 /**
453 * The next maplet in the iteration. If this is <code>null</code> there
454 * are no more elements in the iteration.
455 */
456 private LinkedHashMaplet< ?, ? > nextMaplet;
457
458 /**
459 * The number of elements this iterator will return.
460 */
461 private final int size;
462
463 /**
464 * Constructs a new hash map iterator to iterate over the specified
465 * array of hash map buckets returning either the maplet keys or
466 * values.
467 *
468 * @param start the first LinkedHashMaplet in the iteration
469 * @param num the number of elements in the iteration
470 */
471 public LinkedHashMapXIterator( final LinkedHashMaplet< ?, ? > start, final int num ) {
472 this.nextMaplet = start;
473 this.size = num;
474 }
475
476 /**
477 * @see org.millscript.commons.util.iterator.AbstractMapIterator#advance()
478 */
479 @Override
480 protected void advance() {
481
482 super.advance();
483 this.currentMaplet = this.nextMaplet;
484 if ( super.position >= this.size ) {
485 this.nextMaplet = null;
486 } else if ( this.nextMaplet != null ) {
487 this.nextMaplet = this.nextMaplet.nextByInsertion;
488 }
489 }
490
491 /**
492 * Returns the appropriate part of the specified maplet for this list.
493 *
494 * @param maplet the maplet to get the appropriate part from
495 * @return the appropriate part of the specified maplet
496 */
497 abstract V getAppropriateMapletPart( Maplet< ?, ? > maplet );
498
499 /**
500 * @see org.millscript.commons.util.iterator.AbstractMapIterator#getValue()
501 */
502 @Override
503 protected V getValue() {
504 return this.getAppropriateMapletPart( this.currentMaplet );
505 }
506
507 /**
508 * @see org.millscript.commons.util.MapIterator#hasNext()
509 */
510 public boolean hasNext() {
511 return this.nextMaplet != null;
512 }
513
514 /**
515 * @see org.millscript.commons.util.iterator.AbstractMapIterator#outOfBounds()
516 */
517 @Override
518 protected boolean outOfBounds() {
519 return this.currentMaplet == null;
520 }
521
522 }
523
524 /**
525 * The class provides the skeletal implementation of a list backed by an
526 * array of hash map buckets, where the list values are either the maplet
527 * keys or values.
528 */
529 private static abstract class LinkedHashMapXList< V > extends AbstractIList< V > {
530
531 /**
532 * The first link in the shared part of the maplet chain.
533 */
534 final LinkedHashMaplet< ?, ? > firstHashMaplet;
535
536 /**
537 * The number of values in the list.
538 */
539 final int size;
540
541 /**
542 * Constructs a new hash maplet array list of either the individual
543 * maplet keys or values.
544 *
545 * @param start the LinkedHashMap element with index 1
546 * @param num the number of elements in the list
547 */
548 private LinkedHashMapXList( final LinkedHashMaplet< ?, ? > start, final int num ) {
549 this.firstHashMaplet = start;
550 this.size = num;
551 }
552
553 /**
554 * Constructs a new hash maplet array list of either the individual
555 * maplet keys or values.
556 *
557 * @param start the LinkedHashMap element with index 1
558 * @param first the index(one based, inclusive) of the first name
559 * @param last the index(one based, inclusive) of the last name
560 */
561 private LinkedHashMapXList( final LinkedHashMaplet< ?, ? > start, final int first, final int last ) {
562 LinkedHashMaplet< ?, ? > firstMaplet = null;
563 int totalMaplets = 1;
564
565 for ( LinkedHashMaplet< ?, ? > maplet = start; maplet != null; totalMaplets++, maplet = maplet.nextByInsertion ) {
566 if ( totalMaplets == first ) {
567 firstMaplet = maplet;
568 }
569 }
570 if ( first > last ) {
571 this.firstHashMaplet = null;
572 this.size = 0;
573 } else if ( first < 1 || first > totalMaplets ) {
574 throw new ListIndexOutOfBoundsAlert(
575 "First index in slice must be between 1 and the number of entries in the map"
576 ).culprit(
577 "index",
578 first
579 ).decorate( start ).mishap();
580 } else if ( last > totalMaplets ) {
581 throw new ListIndexOutOfBoundsAlert(
582 "Last index in slice must not be greater than the number of entries in the list"
583 ).culprit(
584 "index",
585 last
586 ).decorate( start ).mishap();
587 } else {
588 this.firstHashMaplet = firstMaplet;
589 this.size = last - first + 1;
590 }
591 }
592
593 /**
594 * @see org.millscript.commons.util.list.AbstractIList#doGet(int)
595 */
596 @Override
597 protected V doGet( final int pos ) {
598 int currentPos = 1;
599 for ( LinkedHashMaplet< ?, ? > maplet = this.firstHashMaplet; maplet != null; maplet = maplet.nextByInsertion ) {
600 if ( pos == currentPos++ ) {
601 return this.getAppropriateMapletPart( maplet );
602 }
603 }
604 throw new Fault(
605 "Specified position is neither out of bounds or within the list!"
606 ).culprit( "index", pos ).decorate( this ).mishap();
607 }
608
609 /**
610 * @see org.millscript.commons.util.list.AbstractIList#doSlice(int, int, boolean)
611 */
612 @Override
613 @SuppressWarnings( "unchecked" )
614 protected IList< V > doSlice( final int first, final int last, final boolean share ) {
615 if ( share ) {
616 return this.sharedSlice( first, last );
617 } else {
618
619 final V[] objects = (V[]) new Object[ this.size() ];
620 LinkedHashMaplet< ?, ? > hmp = this.firstHashMaplet;
621 int outerListCount = 1;
622
623 for ( ; outerListCount <= first; outerListCount++ ) {
624 hmp = hmp.next;
625 }
626
627 int newArrayPos = 0;
628 for ( ; hmp != null && outerListCount <= last; hmp = hmp.next, outerListCount++ ) {
629 objects[ newArrayPos++ ] = this.getAppropriateMapletPart( hmp );
630 }
631 return new IArrayList< V >( objects, true );
632 }
633 }
634
635 /**
636 * Returns the appropriate part of the specified maplet for this list.
637 *
638 * @param maplet the maplet to get the appropriate part from
639 * @return the appropriate part of the specified maplet
640 */
641 abstract V getAppropriateMapletPart( Maplet< ?, ? > maplet );
642
643 /**
644 * @see org.millscript.commons.util.IList#indexOf(java.lang.Object)
645 */
646 public int indexOf( final V value ) {
647 int pos = 1;
648 LinkedHashMaplet< ?, ? > hmp = this.firstHashMaplet;
649 if ( value == null ) {
650 for ( ; hmp != null && pos <= this.size; hmp = hmp.nextByInsertion, pos++ ) {
651 if ( this.getAppropriateMapletPart( hmp ) == null ) {
652 return pos;
653 }
654 }
655 } else {
656 for ( ; hmp != null && pos <= this.size; hmp = hmp.nextByInsertion, pos++ ) {
657 if ( value.equals( this.getAppropriateMapletPart( hmp ) ) ) {
658 return pos;
659 }
660 }
661 }
662 return 0;
663 }
664
665 /**
666 * @see org.millscript.commons.util.IMap#iterator(boolean)
667 */
668 @SuppressWarnings( "unchecked" )
669 public ListIterator< V > iterator( final boolean share ) {
670 if ( share ) {
671 return this.sharedIterator();
672 } else {
673
674
675 final V[] objects = (V[]) new Object[ this.size() ];
676 int pos = 0;
677 LinkedHashMaplet< ?, ? > current = this.firstHashMaplet;
678 while ( current != null ) {
679 objects[ pos++ ] = this.getAppropriateMapletPart( current );
680 current = current.nextByInsertion;
681 }
682 return new ArrayListIterator< V >( objects, true );
683 }
684 }
685
686 /**
687 * Returns a list iterator which shares backing store with this list.
688 *
689 * @return a list iterator which shares this lists backing store
690 */
691 abstract ListIterator< V > sharedIterator();
692
693 /**
694 * Returns a slice of this list which shares backing store with this
695 * list.
696 *
697 * @param first the index(one based) of the first element in the slice
698 * @param last the index(one based) of the last element in the slice
699 * @return a slice of this list which shares this lists backing store
700 */
701 abstract IList< V > sharedSlice( int first, int last );
702
703 /**
704 * @see org.millscript.commons.util.IMap#size()
705 */
706 public int size() {
707 return this.size;
708 }
709
710 }
711
712 /**
713 * The first LinkedHashMaplet in the insertion order chain.
714 */
715 private final LinkedHashMaplet< K, V > firstElement;
716
717 /**
718 * The number of maplets in this mapping.
719 */
720 private final int size;
721
722 /**
723 * The backing store for this hash map is a fixed array of LinkedHashMaplet
724 * buckets.
725 */
726 private final LinkedHashMaplet< K, V >[] store;
727
728 /**
729 * Constructs a new, emtpy immutable hash map.
730 */
731 public ILinkedHashMap() {
732 this.firstElement = null;
733 this.size = 0;
734 this.store = null;
735 }
736
737 /**
738 * Constructs a new immutable hash map which contains all the mappings from
739 * the specified map.
740 *
741 * @param map the <code>Map</code> to copy mappings from
742 */
743 @SuppressWarnings( "unchecked" )
744 public ILinkedHashMap( final IMap< K, V > map ) {
745 if ( map.size() == 0 ) {
746 this.firstElement = null;
747 this.size = 0;
748 this.store = null;
749 } else {
750 final MapIterator< K, V > it = map.iterator( true );
751 int num = 1;
752 this.store = new LinkedHashMaplet[ map.size() ];
753 this.firstElement = new LinkedHashMaplet< K, V >( null, it.currentKey(), it.currentValue() );
754 LinkedHashMaplet< K, V > lastInserted = this.firstElement;
755 this.store[ it.nextKey() == null ? 0 : ( it.currentKey().hashCode() & 0x7FFFFFFF ) % this.store.length ] = lastInserted;
756 while ( it.hasNext() ) {
757 final int pos = it.nextKey() == null ? 0 : ( it.currentKey().hashCode() & 0x7FFFFFFF ) % this.store.length;
758 if ( this.store[ pos ] == null ) {
759 lastInserted = new LinkedHashMaplet< K, V >( lastInserted, it.currentKey(), it.currentValue() );
760 this.store[ pos ] = lastInserted;
761 } else {
762 for ( LinkedHashMaplet< K, V > hmp = this.store[ pos ]; hmp != null; hmp = hmp.next ) {
763 if ( hmp.getKey() == null ? it.currentKey() == null : hmp.getKey().equals( it.currentKey() ) ) {
764 throw new KeyAlreadyExistsAlert(
765 "Specified key is already present in this map"
766 ).culprit(
767 "existing maplet",
768 hmp
769 ).culprit(
770 "duplicate maplet",
771 it.currentMaplet()
772 ).mishap();
773 } else if ( hmp.next == null ) {
774 lastInserted = new LinkedHashMaplet< K, V >( lastInserted, it.currentKey(), it.currentValue() );
775 hmp.next = lastInserted;
776 break;
777 }
778 }
779 }
780 num++;
781 }
782 this.size = num;
783 }
784 }
785
786 /**
787 * @see java.lang.Object#clone()
788 */
789 @Override
790 public Object clone() throws CloneNotSupportedException {
791
792 return super.clone();
793 }
794
795 /**
796 * @see org.millscript.commons.util.IMap#contains(java.lang.Object, java.lang.Object)
797 */
798 public boolean contains( final K key, final V value ) {
799 final int pos = key == null ? 0 : ( key.hashCode() & 0x7FFFFFFF ) % this.store.length;
800 for ( LinkedHashMaplet< K, V > hmp = this.store[ pos ]; hmp != null; hmp = hmp.next ) {
801 if ( key == null ? hmp.getKey() == null : key.equals( hmp.getKey() ) ) {
802
803
804 return hmp.getValue() == null ? value == null
805 : hmp.getValue().equals( value );
806 }
807 }
808 return false;
809 }
810
811 /**
812 * @see org.millscript.commons.util.IMap#containsKey(java.lang.Object)
813 */
814 public boolean containsKey( final K key ) {
815 final int pos = key == null ? 0 : ( key.hashCode() & 0x7FFFFFFF ) % this.store.length;
816 for ( LinkedHashMaplet< K, V > hmp = this.store[ pos ]; hmp != null; hmp = hmp.next ) {
817 if ( key == null ? hmp.getKey() == null : key.equals( hmp.getKey() ) ) {
818 return true;
819 }
820 }
821 return false;
822 }
823
824 /**
825 * @see org.millscript.commons.util.IMap#containsValue(java.lang.Object)
826 */
827 public boolean containsValue( final V value ) {
828
829 LinkedHashMaplet< K, V > current = this.firstElement;
830 while ( current != null ) {
831 if ( value == null ? current.getValue() == null : value.equals( current.getValue() ) ) {
832 return true;
833 } else {
834 current = current.nextByInsertion;
835 }
836 }
837 return false;
838 }
839
840 /**
841 * @see org.millscript.commons.util.IMap#get(java.lang.Object)
842 */
843 public V get( final K key ) {
844 final int pos = key == null ? 0 : ( key.hashCode() & 0x7FFFFFFF ) % this.store.length;
845 for ( LinkedHashMaplet< K, V > hmp = this.store[ pos ]; hmp != null; hmp = hmp.next ) {
846 if ( key == null ? hmp.getKey() == null : key.equals( hmp.getKey() ) ) {
847 return hmp.getValue();
848 }
849 }
850 return this.getDefault().get( this, key );
851 }
852
853 /**
854 * @see org.millscript.commons.util.IMap#isEmtpy()
855 */
856 @Override
857 public boolean isEmtpy() {
858 return this.firstElement != null;
859 }
860
861 /**
862 * @see org.millscript.commons.util.IMap#iterator(boolean)
863 */
864 @SuppressWarnings( "unchecked" )
865 public MapIterator< K, V > iterator( final boolean share ) {
866 if ( share ) {
867 return new LinkedHashMapIterator< K, V >( this.firstElement, share );
868 } else {
869
870
871
872 final Maplet< K, V >[] maplets = new Maplet[ this.size() ];
873 LinkedHashMaplet< K, V > current = this.firstElement;
874 for ( int i = 0; current != null; current = current.nextByInsertion ) {
875 maplets[ i++ ] = new IMaplet< K, V >( current );
876 }
877 return new IMapletArrayMap.MapletArrayMapIterator< K, V >( maplets, true );
878 }
879 }
880
881 /**
882 * @see org.millscript.commons.util.map.AbstractIMap#sharedKeyList()
883 */
884 @Override
885 protected IList< K > sharedKeyList() {
886 return new LinkedHashMapKeysList< K >( this.firstElement, this.size() );
887 }
888
889 /**
890 * @see org.millscript.commons.util.map.AbstractIMap#sharedMapletList()
891 */
892 @Override
893 protected IList< Maplet< K, V > > sharedMapletList() {
894 return new LinkedHashMapMapletList< K, V >( this.firstElement, this.size() );
895 }
896
897 /**
898 * @see org.millscript.commons.util.map.AbstractIMap#sharedValueList()
899 */
900 @Override
901 protected IList< V > sharedValueList() {
902 return new LinkedHashMapValuesList< V >( this.firstElement, this.size() );
903 }
904
905 /**
906 * @see org.millscript.commons.util.IMap#size()
907 */
908 public int size() {
909 return this.size;
910 }
911
912 }