3030
3131package org .scijava .table ;
3232
33+ import java .lang .reflect .Array ;
34+ import java .util .AbstractList ;
3335import java .util .ArrayList ;
3436import java .util .Collection ;
3537import java .util .Iterator ;
3638import java .util .List ;
3739import java .util .ListIterator ;
3840import java .util .Objects ;
41+ import java .util .stream .Collectors ;
3942
4043/**
4144 * A table of values.
@@ -411,18 +414,27 @@ default boolean isEmpty() {
411414 * tested.
412415 */
413416 @ Override
414- boolean contains (Object column );
417+ default boolean contains (final Object column ) {
418+ return indexOf (column ) >= 0 ;
419+ }
415420
416421 /** Returns an iterator over the columns in the table in proper sequence. */
417422 @ Override
418- Iterator <C > iterator ();
423+ default Iterator <C > iterator () {
424+ return listIterator ();
425+ }
419426
420427 /**
421428 * Returns an array containing all of the columns in the table in proper
422429 * sequence (from first to last column).
423430 */
424431 @ Override
425- Object [] toArray ();
432+ default Object [] toArray () {
433+ final Object [] columns = new Object [getColumnCount ()];
434+ for (int c = 0 ; c < columns .length ; c ++)
435+ columns [c ] = get (c );
436+ return columns ;
437+ }
426438
427439 /**
428440 * Returns an array containing all of the column in the table in proper
@@ -433,7 +445,15 @@ default boolean isEmpty() {
433445 * list of columns.
434446 */
435447 @ Override
436- <A > A [] toArray (A [] a );
448+ @ SuppressWarnings ("unchecked" )
449+ default <A > A [] toArray (final A [] a ) {
450+ final A [] columns = a .length >= getColumnCount () ? a : //
451+ (A []) Array .newInstance (a .getClass ().getComponentType (),
452+ getColumnCount ());
453+ for (int c = 0 ; c < getColumnCount (); c ++)
454+ columns [c ] = (A ) get (c );
455+ return columns ;
456+ }
437457
438458 /**
439459 * Appends the specified column to the end of the table.
@@ -443,7 +463,10 @@ default boolean isEmpty() {
443463 * </p>
444464 */
445465 @ Override
446- boolean add (C column );
466+ default boolean add (final C column ) {
467+ add (getColumnCount (), column );
468+ return true ;
469+ }
447470
448471 /**
449472 * Removes the first occurrence of the specified column from the table, if it
@@ -452,14 +475,24 @@ default boolean isEmpty() {
452475 * @return <tt>true</tt> if the table contained the specified column
453476 */
454477 @ Override
455- boolean remove (Object column );
478+ default boolean remove (final Object column ) {
479+ final int colIndex = indexOf (column );
480+ if (colIndex < 0 ) return false ;
481+ remove (colIndex );
482+ return true ;
483+ }
456484
457485 /**
458486 * Returns <tt>true</tt> if the table contains all of the columns of the
459487 * specified collection.
460488 */
461489 @ Override
462- boolean containsAll (Collection <?> c );
490+ default boolean containsAll (final Collection <?> c ) {
491+ for (final Object column : c ) {
492+ if (!contains (column )) return false ;
493+ }
494+ return true ;
495+ }
463496
464497 /**
465498 * Appends all of the columns in the specified collection to the end of the
@@ -473,7 +506,12 @@ default boolean isEmpty() {
473506 * @return <tt>true</tt> if the table changed as a result of the call
474507 */
475508 @ Override
476- boolean addAll (Collection <? extends C > c );
509+ default boolean addAll (final Collection <? extends C > c ) {
510+ boolean changed = false ;
511+ for (final C column : c )
512+ changed |= add (column );
513+ return changed ;
514+ }
477515
478516 /**
479517 * Inserts all of the columns in the specified collection into this list at
@@ -486,7 +524,12 @@ default boolean isEmpty() {
486524 * @return <tt>true</tt> if the table changed as a result of the call
487525 */
488526 @ Override
489- boolean addAll (int col , Collection <? extends C > c );
527+ default boolean addAll (final int col , final Collection <? extends C > c ) {
528+ int index = col ;
529+ for (final C column : c )
530+ add (index ++, column );
531+ return c .size () > 0 ;
532+ }
490533
491534 /**
492535 * Removes from the table all of its columns that are contained in the
@@ -495,7 +538,12 @@ default boolean isEmpty() {
495538 * @return <tt>true</tt> if the table changed as a result of the call
496539 */
497540 @ Override
498- boolean removeAll (Collection <?> c );
541+ default boolean removeAll (final Collection <?> c ) {
542+ boolean changed = false ;
543+ for (final Object column : c )
544+ changed |= remove (column );
545+ return changed ;
546+ }
499547
500548 /**
501549 * Retains only the columns in the table that are contained in the specified
@@ -505,7 +553,12 @@ default boolean isEmpty() {
505553 * @return <tt>true</tt> if the table changed as a result of the call
506554 */
507555 @ Override
508- boolean retainAll (Collection <?> c );
556+ default boolean retainAll (final Collection <?> c ) {
557+ final List <?> absent = stream () //
558+ .filter (column -> !c .contains (column )) //
559+ .collect (Collectors .toList ());
560+ return removeAll (absent );
561+ }
509562
510563 /**
511564 * Removes all data (including row and column headers) from the table. The
@@ -559,27 +612,93 @@ default boolean isEmpty() {
559612 * table, or -1 if the table does not contain the column.
560613 */
561614 @ Override
562- int indexOf (Object column );
615+ default int indexOf (final Object column ) {
616+ for (int c = 0 ; c < size (); c ++)
617+ if (Objects .equals (get (c ), column )) return c ;
618+ return -1 ;
619+ }
563620
564621 /**
565622 * Returns the index of the last occurrence of the specified column in the
566623 * table, or -1 if the table does not contain the column.
567624 */
568625 @ Override
569- int lastIndexOf (Object column );
626+ default int lastIndexOf (final Object column ) {
627+ for (int c = size () - 1 ; c >= 0 ; c --)
628+ if (Objects .equals (get (c ), column )) return c ;
629+ return -1 ;
630+ }
570631
571632 /**
572633 * Returns a list iterator over the columns in the table (in proper sequence).
573634 */
574635 @ Override
575- ListIterator <C > listIterator ();
636+ default ListIterator <C > listIterator () {
637+ return listIterator (0 );
638+ }
576639
577640 /**
578641 * Returns a list iterator of the columns in the table (in proper sequence),
579642 * starting at the specified position in the table.
580643 */
581644 @ Override
582- ListIterator <C > listIterator (int col );
645+ default ListIterator <C > listIterator (final int col ) {
646+
647+ return new ListIterator <C >() {
648+
649+ int last = -1 ;
650+ int c = col ;
651+
652+ @ Override
653+ public boolean hasNext () {
654+ return c < getColumnCount ();
655+ }
656+
657+ @ Override
658+ public C next () {
659+ return get (last = c ++);
660+ }
661+
662+ @ Override
663+ public boolean hasPrevious () {
664+ return c > 0 ;
665+ }
666+
667+ @ Override
668+ public C previous () {
669+ return get (last = --c );
670+ }
671+
672+ @ Override
673+ public int nextIndex () {
674+ return c ;
675+ }
676+
677+ @ Override
678+ public int previousIndex () {
679+ return c - 1 ;
680+ }
681+
682+ @ Override
683+ public void remove () {
684+ if (last < 0 ) throw new IllegalStateException ();
685+ Table .this .remove (last );
686+ last = -1 ;
687+ }
688+
689+ @ Override
690+ public void set (final C e ) {
691+ if (last < 0 ) throw new IllegalStateException ();
692+ Table .this .set (last , e );
693+ }
694+
695+ @ Override
696+ public void add (final C e ) {
697+ Table .this .add (c ++, e );
698+ last = -1 ;
699+ }
700+ };
701+ }
583702
584703 /**
585704 * Returns a view of the portion of the table between the specified
@@ -588,6 +707,18 @@ default boolean isEmpty() {
588707 * returned list are reflected in the table, and vice-versa.
589708 */
590709 @ Override
591- List <C > subList (int fromCol , int toCol );
710+ default List <C > subList (final int fromCol , final int toCol ) {
711+ return new AbstractList <C >() {
712+
713+ @ Override
714+ public C get (final int index ) {
715+ return Table .this .get (index + fromCol );
716+ }
592717
718+ @ Override
719+ public int size () {
720+ return toCol - fromCol ;
721+ }
722+ };
723+ }
593724}
0 commit comments