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