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.util.IList;
26 import org.millscript.commons.util.IMap;
27 import org.millscript.commons.util.ListIterator;
28 import org.millscript.commons.util.MapIterator;
29 import org.millscript.commons.util.Maplet;
30 import org.millscript.commons.util.iterator.AbstractListIterator;
31 import org.millscript.commons.util.iterator.AbstractMapIterator;
32 import org.millscript.commons.util.iterator.ArrayListIterator;
33 import org.millscript.commons.util.list.AbstractIList;
34 import org.millscript.commons.util.list.IArrayList;
35
36 /**
37 * This class provides an immutable <code>Map</code> implementation which is
38 * backed by an array of <code>Maplet</code>s.
39 */
40 public class IMapletArrayMap< K, V > extends AbstractIMap< K, V > implements Cloneable, Serializable {
41
42 /**
43 * This is the ID from the release 0.1.0 for future compatibility.
44 */
45 private static final long serialVersionUID = -6198347924099627391L;
46
47 /**
48 * This class implements an immutable list which is backed by an array of
49 * maplets, but NOTE the values in the list are actually the individual
50 * maplet keys.
51 */
52 public static class MapletArrayKeysList< K > extends MapletArrayXList< K > {
53
54 /**
55 * Constructs a new maplet array keys map iterator to iterate over the
56 * maplet keys in array of maplets.
57 *
58 * @param maplets the array of maplets to iterate over
59 * @param first the index(one based, inclusive) of the first name
60 * @param last the index(one based, inclusive) of the last name
61 */
62 public MapletArrayKeysList( final Maplet< ?, ? >[] maplets, final int first, final int last ) {
63 super( maplets, first, last );
64 }
65
66 /**
67 * @see org.millscript.commons.util.map.IMapletArrayMap.MapletArrayXList#getAppropriateMapletPart(org.millscript.commons.util.Maplet)
68 */
69 @Override
70 @SuppressWarnings( "unchecked" )
71 K getAppropriateMapletPart( final Maplet< ?, ? > maplet ) {
72 return (K) maplet.getKey();
73 }
74
75 /**
76 * @see org.millscript.commons.util.map.IMapletArrayMap.MapletArrayXList#sharedIterator()
77 */
78 @Override
79 ListIterator< K > sharedIterator() {
80 return new MapletArrayKeysMapIterator< K >( this.store, this.firstIndex, this.lastIndex );
81 }
82
83 /**
84 * @see org.millscript.commons.util.map.IMapletArrayMap.MapletArrayXList#sharedSlice(int, int)
85 */
86 @Override
87 IList< K > sharedSlice( final int first, final int last ) {
88
89
90
91 return new MapletArrayKeysList< K >(
92 this.store,
93 this.firstIndex + first - 1,
94 this.firstIndex + last - 1
95 );
96 }
97
98 }
99
100 /**
101 * This class implements a map iterator which iterates over the maplet keys
102 * in an array of maplets. i.e. the "key" in the iterator is the position
103 * in the iteration and the "value" in the iterator is the result of the
104 * <code>getKey</code> method for each maplet.
105 */
106 public static class MapletArrayKeysMapIterator< K > extends MapletArrayXMapIterator< K > {
107
108 /**
109 * Constructs a new maplet array keys map iterator to iterate over the
110 * maplet keys in array of maplets.
111 *
112 * @param maplets the array of maplets to iterate over
113 * @param first the index(one based, inclusive) of the first name
114 * @param last the index(one based, inclusive) of the last name
115 */
116 public MapletArrayKeysMapIterator( final Maplet< ?, ? >[] maplets, final int first, final int last ) {
117 super( maplets, first, last );
118 }
119
120 /**
121 * @see org.millscript.commons.util.map.IMapletArrayMap.MapletArrayXMapIterator#getAppropriateMapletPart(org.millscript.commons.util.Maplet)
122 */
123 @Override
124 @SuppressWarnings( "unchecked" )
125 K getAppropriateMapletPart( final Maplet< ?, ? > maplet ) {
126 return (K) maplet.getValue();
127 }
128
129 }
130
131 /**
132 * This class implements a map iterator which iterates over an array
133 * of maplets.
134 */
135 public static class MapletArrayMapIterator< K, V > extends AbstractMapIterator< K, V > {
136
137 /**
138 * The current position of the iterator within the array.
139 */
140 int pos = -1;
141
142 /**
143 * The backing store containing a fixed array of alternate name-value
144 * objects.
145 */
146 final Maplet< K, V >[] store;
147
148 /**
149 * Constructs a new maplet array iterator to iterate over the array of
150 * maplets.
151 *
152 * @param maplets the array of maplets to iterate over
153 * @param share if <code>true</code> the specified object array will be
154 * shared otherwise the array will be copied.
155 */
156 @SuppressWarnings( "unchecked" )
157 public MapletArrayMapIterator( final Maplet< K, V >[] maplets, final boolean share ) {
158 if ( maplets == null || share ) {
159 this.store = maplets;
160 } else {
161 this.store = new Maplet[ maplets.length ];
162 System.arraycopy( maplets, 0, this.store, 0, maplets.length );
163 }
164 }
165
166 /**
167 * @see org.millscript.commons.util.iterator.AbstractMapIterator#advance()
168 */
169 @Override
170 protected void advance() {
171 if ( this.store != null ) {
172 this.pos++;
173 }
174 }
175
176 /**
177 * @see org.millscript.commons.util.iterator.AbstractMapIterator#getKey()
178 */
179 @Override
180 protected K getKey() {
181 return store[ pos ].getKey();
182 }
183
184 /**
185 * @see org.millscript.commons.util.iterator.AbstractMapIterator#getValue()
186 */
187 @Override
188 protected V getValue() {
189 return store[ pos ].getValue();
190 }
191
192 /**
193 * @see org.millscript.commons.util.MapIterator#hasNext()
194 */
195 public boolean hasNext() {
196 return this.store != null && this.pos + 1 < store.length;
197 }
198
199 /**
200 * @see org.millscript.commons.util.iterator.AbstractMapIterator#outOfBounds()
201 */
202 @Override
203 protected boolean outOfBounds() {
204 return this.store == null || this.pos < 0 || this.pos >= this.store.length;
205 }
206
207 }
208
209 /**
210 * This class implements an immutable list which is backed by an array of
211 * maplets, but NOTE the values in the list are actually the individual
212 * maplet values.
213 * <p>
214 * This list implementation is used to allow sharing of the underlying
215 * store when requesting a list of the keys in a maplet array map instance.
216 * </p>
217 */
218 public static class MapletArrayValuesList< V > extends MapletArrayXList< V > {
219
220 /**
221 * Constructs a new maplet array keys map iterator to iterate over the
222 * maplet keys in array of maplets.
223 *
224 * @param maplets the array of maplets to iterate over
225 * @param first the index(one based, inclusive) of the first name
226 * @param last the index(one based, inclusive) of the last name
227 */
228 public MapletArrayValuesList( final Maplet< ?, ? >[] maplets, final int first, final int last ) {
229 super( maplets, first, last );
230 }
231
232 /**
233 * @see org.millscript.commons.util.map.IMapletArrayMap.MapletArrayXList#getAppropriateMapletPart(org.millscript.commons.util.Maplet)
234 */
235 @Override
236 @SuppressWarnings( "unchecked" )
237 V getAppropriateMapletPart( final Maplet< ?, ? > maplet ) {
238 return (V) maplet.getValue();
239 }
240
241 /**
242 * @see org.millscript.commons.util.map.IMapletArrayMap.MapletArrayXList#sharedIterator()
243 */
244 @Override
245 ListIterator< V > sharedIterator() {
246 return new MapletArrayValuesMapIterator< V >( this.store, this.firstIndex, this.lastIndex );
247 }
248
249 /**
250 * @see org.millscript.commons.util.map.IMapletArrayMap.MapletArrayXList#sharedSlice(int, int)
251 */
252 @Override
253 IList< V > sharedSlice( final int first, final int last ) {
254
255
256
257 return new MapletArrayValuesList< V >(
258 this.store,
259 this.firstIndex + first - 1,
260 this.firstIndex + last - 1
261 );
262 }
263
264 }
265
266 /**
267 * This class implements a map iterator which iterates over the maplet
268 * values in an array of maplets. i.e. the "key" in the iterator is the
269 * position in the iteration and the "value" in the iterator is the result
270 * of the <code>getValue</code> method for each maplet.
271 */
272 public static class MapletArrayValuesMapIterator< V > extends MapletArrayXMapIterator< V > {
273
274 /**
275 * Constructs a new maplet array keys map iterator to iterate over the
276 * maplet keys in array of maplets.
277 *
278 * @param maplets the array of maplets to iterate over
279 * @param first the index(one based, inclusive) of the first name
280 * @param last the index(one based, inclusive) of the last name
281 */
282 public MapletArrayValuesMapIterator( final Maplet< ?, ? >[] maplets, final int first, final int last ) {
283 super( maplets, first, last );
284 }
285
286 /**
287 * @see org.millscript.commons.util.map.IMapletArrayMap.MapletArrayXMapIterator#getAppropriateMapletPart(org.millscript.commons.util.Maplet)
288 */
289 @Override
290 @SuppressWarnings( "unchecked" )
291 V getAppropriateMapletPart( final Maplet< ?, ? > maplet ) {
292 return (V) maplet.getValue();
293 }
294
295 }
296
297 /**
298 * This class implements a map iterator which iterates over the maplet keys
299 * or values in an array of maplets. i.e. the "key" in the iterator is the
300 * position in the iteration and the "value" in the iterator is the result
301 * of the <code>getKey</code> or the <code>getValue</code> method for each
302 * maplet.
303 */
304 private static abstract class MapletArrayXMapIterator< V > extends AbstractListIterator< V > {
305
306 /**
307 * The index of the first element in the iteration.
308 */
309 private final int firstIndex;
310
311 /**
312 * The number of elements in the iteration.
313 */
314 private final int size;
315
316 /**
317 * The backing store containing a fixed array of alternate name-value
318 * objects.
319 */
320 private final Maplet< ?, ? >[] store;
321
322 /**
323 * Constructs a new maplet array keys map iterator to iterate over the
324 * maplet keys in array of maplets.
325 *
326 * @param maplets the array of maplets to iterate over
327 * @param first the index(one based, inclusive) of the first name
328 * @param last the index(one based, inclusive) of the last name
329 */
330 private MapletArrayXMapIterator( final Maplet< ?, ? >[] maplets, final int first, final int last ) {
331 this.firstIndex = first - 1;
332 this.size = last - first + 1;
333 this.store = maplets;
334 }
335
336 /**
337 * Returns the appropriate part of the specified maplet for this list.
338 *
339 * @param maplet the maplet to get the appropriate part from
340 * @return the appropriate part of the specified maplet
341 */
342 abstract V getAppropriateMapletPart( Maplet< ?, ? > maplet );
343
344 /**
345 * @see org.millscript.commons.util.iterator.AbstractMapIterator#getValue()
346 */
347 @Override
348 protected V getValue() {
349 return this.getAppropriateMapletPart(
350 this.store[ this.firstIndex + super.position - 1 ]
351 );
352 }
353
354 /**
355 * @see org.millscript.commons.util.MapIterator#hasNext()
356 */
357 public boolean hasNext() {
358 return super.position < this.size;
359 }
360
361 /**
362 * @see org.millscript.commons.util.iterator.AbstractMapIterator#outOfBounds()
363 */
364 @Override
365 protected boolean outOfBounds() {
366 return super.position == 0 || super.position > this.store.length;
367 }
368
369 }
370
371 /**
372 * This class implements an immutable list which is backed by an array of
373 * maplets, but NOTE the values in the list are actually the individual
374 * maplet keys or values.
375 */
376 private static abstract class MapletArrayXList< V > extends AbstractIList< V > {
377
378 /**
379 * The index of the first element in the iteration.
380 */
381 final int firstIndex;
382
383 /**
384 * The index of the last element in the iteration.
385 */
386 final int lastIndex;
387
388 /**
389 * The backing store containing a fixed array of alternate name-value
390 * objects.
391 */
392 final Maplet< ?, ? >[] store;
393
394 /**
395 * Constructs a new maplet array keys map iterator to iterate over the
396 * maplet keys in array of maplets.
397 *
398 * @param maplets the array of maplets to iterate over
399 * @param first the index(one based, inclusive) of the first name
400 * @param last the index(one based, inclusive) of the last name
401 */
402 private MapletArrayXList( final Maplet< ?, ? >[] maplets, final int first, final int last ) {
403 this.firstIndex = first;
404 this.lastIndex = last;
405 this.store = maplets;
406 }
407
408 /**
409 * @see org.millscript.commons.util.list.AbstractIList#doGet(int)
410 */
411 @Override
412 protected V doGet( final int pos ) {
413
414
415 return this.getAppropriateMapletPart(
416 this.store[ this.firstIndex - 2 + pos ]
417 );
418 }
419
420 /**
421 * @see org.millscript.commons.util.list.AbstractIList#doSlice(int, int, boolean)
422 */
423 @Override
424 @SuppressWarnings( "unchecked" )
425 protected IList< V > doSlice( final int first, final int last, final boolean share ) {
426 if ( share ) {
427 return this.sharedSlice( first, last );
428 } else {
429
430 final V[] objects = (V[]) new Object[ last - first + 1 ];
431 for ( int i = this.firstIndex + first - 2, j = 0; i < this.firstIndex + last - 2; i++, j++ ) {
432 objects[ j ] = this.getAppropriateMapletPart( this.store[ i ] );
433 }
434 return new IArrayList< V >( objects, true );
435 }
436 }
437
438 /**
439 * Returns the appropriate part of the specified maplet for this list.
440 *
441 * @param maplet the maplet to get the appropriate part from
442 * @return the appropriate part of the specified maplet
443 */
444 abstract V getAppropriateMapletPart( Maplet< ?, ? > maplet );
445
446 /**
447 * @see org.millscript.commons.util.IList#indexOf(java.lang.Object)
448 */
449 public int indexOf( final V value ) {
450 if ( value == null ) {
451 for ( int i = this.firstIndex - 1; i < this.lastIndex; i++ ) {
452 if ( this.getAppropriateMapletPart( this.store[ i ] ) == null ) {
453 return i - this.firstIndex + 2;
454 }
455 }
456 } else {
457 for ( int i = this.firstIndex - 1; i < this.lastIndex; i++ ) {
458 if ( value.equals( this.getAppropriateMapletPart( this.store[ i ] ) ) ) {
459 return i - this.firstIndex + 2;
460 }
461 }
462 }
463 return 0;
464 }
465
466 /**
467 * @see org.millscript.commons.util.IMap#iterator(boolean)
468 */
469 @SuppressWarnings( "unchecked" )
470 public ListIterator< V > iterator( boolean share ) {
471 if ( share ) {
472 return this.sharedIterator();
473 } else {
474 final V[] objects = (V[]) new Object[ this.size() ];
475 for ( int i = this.firstIndex - 1, j = 0; i < this.lastIndex; i++, j++ ) {
476 objects[ j ] = this.getAppropriateMapletPart( this.store[ i ] );
477 }
478 return new ArrayListIterator< V >( objects, true );
479 }
480 }
481
482 /**
483 * Returns a map iterator which shares backing store with this list.
484 *
485 * @return a map iterator which shares this lists backing store
486 */
487 abstract ListIterator< V > sharedIterator();
488
489 /**
490 * Returns a slice of this list which shares backing store with this
491 * list.
492 *
493 * @param first the index(one based) of the first element in the slice
494 * @param last the index(one based) of the last element in the slice
495 * @return a slice of this list which shares this lists backing store
496 */
497 abstract IList< V > sharedSlice( int first, int last );
498
499 /**
500 * @see org.millscript.commons.util.IMap#size()
501 */
502 public int size() {
503 return this.lastIndex - this.firstIndex + 1;
504 }
505
506 }
507
508 /**
509 * The backing store containing a sequence of maplets.
510 */
511 private final Maplet< K, V >[] store;
512
513 /**
514 * Constructs a new empty immutable maplet array map.
515 */
516 public IMapletArrayMap() {
517 this.store = null;
518 }
519
520 /**
521 * Constructs a new immutable maplet array map with a copy of the specified
522 * backing array of maplets.
523 *
524 * @param maplets the backing array of maplet objects to copy
525 * @param share if <code>true</code> the specified maplet array will be
526 * shared otherwise the array will be copied.
527 */
528 @SuppressWarnings( "unchecked" )
529 public IMapletArrayMap( final Maplet< K, V >[] maplets, final boolean share ) {
530 if ( share ) {
531 this.store = maplets;
532 } else {
533 this.store = new Maplet[ maplets.length ];
534 System.arraycopy( maplets, 0, this.store, 0, maplets.length );
535 }
536 }
537
538 /**
539 * @see java.lang.Object#clone()
540 */
541 @Override
542 public Object clone() throws CloneNotSupportedException {
543
544 return super.clone();
545 }
546
547 /**
548 * @see org.millscript.commons.util.IMap#contains(org.millscript.commons.util.Maplet)
549 */
550 @Override
551 public boolean contains( final Maplet< ? extends K, ? extends V > entry ) {
552 for ( int i = 0; this.store != null && i < this.store.length; i++ ) {
553 if ( entry == null ? this.store[ i ] == null : entry.equals( this.store[ i ] ) ) {
554 return true;
555 }
556 }
557 return false;
558 }
559
560 /**
561 * @see org.millscript.commons.util.IMap#contains(java.lang.Object, java.lang.Object)
562 */
563 public boolean contains( final K key, final V value ) {
564 for ( int i = 0; this.store != null && i < this.store.length; i++ ) {
565 final Maplet< K, V > maplet = this.store[ i ];
566 if ( key == null ? maplet.getKey() == null : key.equals( maplet.getKey() ) ) {
567
568
569 return value == null ? maplet.getValue() == null
570 : value.equals( maplet.getValue() );
571 }
572 }
573 return false;
574 }
575
576 /**
577 * @see org.millscript.commons.util.IMap#containsAll(org.millscript.commons.util.IMap)
578 */
579 @Override
580 public boolean containsAll( final IMap< ? extends K, ? extends V > map ) {
581 MapIterator< ? extends K, ? extends V > it = map.iterator( true );
582 while ( it.hasNext() ) {
583 if ( ! this.contains( it.nextMaplet() ) ) {
584 return false;
585 }
586 }
587 return true;
588 }
589
590 /**
591 * @see org.millscript.commons.util.IMap#containsKey(java.lang.Object)
592 */
593 public boolean containsKey( final K key ) {
594 for ( int i = 0; this.store != null && i < this.store.length; i++ ) {
595 if ( key == null ? this.store[ i ].getKey() == null : key.equals( this.store[ i ].getKey() ) ) {
596 return true;
597 }
598 }
599 return false;
600 }
601
602 /**
603 * @see org.millscript.commons.util.IMap#containsValue(java.lang.Object)
604 */
605 public boolean containsValue( final V value ) {
606 for ( int i = 0; this.store != null && i < this.store.length; i++ ) {
607 final Maplet< K, V > maplet = this.store[ i ];
608 if ( value == null ? maplet.getValue() == null : value.equals( maplet.getValue() ) ) {
609 return true;
610 }
611 }
612 return false;
613 }
614
615 /**
616 * @see org.millscript.commons.util.IMap#get(java.lang.Object)
617 */
618 public V get( final K key ) {
619 for ( int i = 0; this.store != null && i < this.store.length; i++ ) {
620 final Maplet< K, V > maplet = this.store[ i ];
621 if ( key == null ? maplet.getKey() == null : key.equals( maplet.getKey() ) ) {
622 return maplet.getValue();
623 }
624 }
625 return this.getDefault().get( this, key );
626 }
627
628 /**
629 * @see org.millscript.commons.util.IMap#iterator(boolean)
630 */
631 public MapIterator< K, V > iterator( boolean share ) {
632 return new MapletArrayMapIterator< K, V >( this.store, share );
633 }
634
635 /**
636 * @see org.millscript.commons.util.map.AbstractIMap#sharedKeyList()
637 */
638 @Override
639 protected IList< K > sharedKeyList() {
640 return new MapletArrayKeysList< K >( this.store, 1, this.size() );
641 }
642
643 /**
644 * @see org.millscript.commons.util.map.AbstractIMap#sharedMapletList()
645 */
646 @Override
647 protected IList< Maplet< K, V > > sharedMapletList() {
648 return new IArrayList< Maplet< K, V > >( this.store, true );
649 }
650
651 /**
652 * @see org.millscript.commons.util.map.AbstractIMap#sharedValueList()
653 */
654 @Override
655 protected IList< V > sharedValueList() {
656 return new MapletArrayValuesList< V >( this.store, 1, this.size() );
657 }
658
659 /**
660 * @see org.millscript.commons.util.IMap#size()
661 */
662 public int size() {
663 return this.store == null ? 0 : this.store.length;
664 }
665
666 }