Coverage Report - jaggregate.Interval
 
Classes in this File Line Coverage Branch Coverage Complexity
Interval
99%
105/106
100%
28/28
0
 
 1  
 /*
 2  
  Copyright 2004-2008 Paul R. Holser, Jr.  All rights reserved.
 3  
  Licensed under the Academic Free License version 3.0
 4  
  */
 5  
 
 6  
 package jaggregate;
 7  
 
 8  
 import java.io.Serializable;
 9  
 import java.util.NoSuchElementException;
 10  
 
 11  
 import jaggregate.internal.Casting;
 12  
 import jaggregate.internal.ReadOnlySequences;
 13  
 import jaggregate.internal.number.OperableNumber;
 14  
 import static jaggregate.OrderedCollection.*;
 15  
 import static jaggregate.internal.ArgumentChecks.*;
 16  
 import static jaggregate.internal.Casting.*;
 17  
 import static jaggregate.internal.number.OperableNumberFactory.*;
 18  
 
 19  
 /**
 20  
  * Represents a collection whose <dfn>elements</dfn> form an arithmetic progression.
 21  
  * <p/>
 22  
  * Currently, all the derivatives of {@link Number} in JDK 5 that override
 23  
  * {@link Object#equals(Object) equals} for value equality are supported as type
 24  
  * arguments for this class.  This excludes the new {@link
 25  
  * java.util.concurrent.atomic.AtomicInteger AtomicInteger} and
 26  
  * {@link java.util.concurrent.atomic.AtomicLong AtomicLong}.
 27  
  * <p/>
 28  
  * This class does nothing to compensate for the inexact representation of primitive
 29  
  * floating-point values; keep this in mind when using intervals of {@code float} or
 30  
  * {@code double}.
 31  
  *
 32  
  * @param <E> a restriction on the kinds of numbers that can be in the interval
 33  
  * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
 34  
  * @version $Id: Interval.java,v 1.7 2008/10/03 19:01:23 pholser Exp $
 35  
  */
 36  8325
 public class Interval<E extends Number> extends AbstractCollection<E>
 37  
     implements ReadOnlySequence<E>, Serializable {
 38  
 
 39  
     private static final long serialVersionUID = -1L;
 40  
 
 41  
     private final OperableNumber<E> begin;
 42  
     private final OperableNumber<E> end;
 43  
     private final OperableNumber<E> step;
 44  
     private final int size;
 45  
 
 46  
     /**
 47  
      * Creates an interval representing an arithmetic progression from one number to
 48  
      * another, in increments of 1.
 49  
      * <p/>
 50  
      * The interval will be {@linkplain #isEmpty() empty} if {@code from > to}.
 51  
      *
 52  
      * @param from the {@linkplain #first() first} element in the interval
 53  
      * @param to the {@linkplain #last() last} element of the interval
 54  
      * @throws NullPointerException if either {@code from} or {@code to}
 55  
      * is {@code null}
 56  
      */
 57  
     public Interval( E from, E to ) {
 58  1466
         this( from, to, null );
 59  1466
     }
 60  
 
 61  
     /**
 62  
      * Creates an interval representing an arithmetic progression from one number to
 63  
      * another, with the given increment.
 64  
      * <p/>
 65  
      * {@code by} can be negative.
 66  
      * <p/>
 67  
      * Note that {@code to} is not necessarily an element in the interval.
 68  
      * The {@linkplain #last() last element} is given by:
 69  
      * <blockquote>
 70  
      *     {@code ( to - from ) / by * by + from}
 71  
      * </blockquote>
 72  
      * The interval will be {@linkplain #isEmpty() empty} if {@code from < to} and
 73  
      * {@code by < 0}, or if {@code from > to} and {@code by > 0}.
 74  
      *
 75  
      * @param from the {@linkplain #first() first} element in the interval
 76  
      * @param to the termination of the interval
 77  
      * @param by the increment to use to compute successive interval values.  If this is
 78  
      * {@code null}, it will be treated as 1.
 79  
      * @throws NullPointerException if either {@code from} or {@code to}
 80  
      * is {@code null}
 81  
      * @throws IllegalArgumentException if {@code by == 0}
 82  
      */
 83  5876
     public Interval( E from, E to, E by ) {
 84  5876
         ensureNotNull( from, "lower bound" );
 85  5876
         ensureNotNull( to, "upper bound" );
 86  
 
 87  5876
         OperableNumber<E> opFrom = cast( wrap( from ) );
 88  5876
         OperableNumber<E> opTo = cast( wrap( to ) );
 89  5876
         OperableNumber<E> opBy = by == null
 90  
             ? opTo.one()
 91  
             : Casting.<OperableNumber<E>>cast( wrap( by ) );
 92  
 
 93  5876
         if ( opBy.isZero() )
 94  8
             throw new IllegalArgumentException( "zero step" );
 95  
 
 96  5868
         begin = opFrom;
 97  5868
         if ( isEmptyIntervalSpecified( opFrom, opTo, opBy ) )
 98  769
             end = opTo;
 99  
         else
 100  5099
             end = opTo.minus( from ).dividedBy( opBy ).times( opBy ).plus( opFrom );
 101  
 
 102  5868
         step = opBy;
 103  5868
         size = computeSize();
 104  5868
     }
 105  
 
 106  
     /**
 107  
      * Creates an interval representing an arithmetic progression from one number to
 108  
      * another, in increments of 1.
 109  
      * <p/>
 110  
      * The interval will be {@linkplain #isEmpty() empty} if {@code from > to}.
 111  
      *
 112  
      * @param <T> the type of numbers in the interval
 113  
      * @param from the {@linkplain #first() first} element in the interval
 114  
      * @param to the {@linkplain #last() last} element of the interval
 115  
      * @return the new interval
 116  
      * @throws NullPointerException if either {@code from} or {@code to}
 117  
      * is {@code null}
 118  
      */
 119  
     public static <T extends Number> Interval<T> fromTo( T from, T to ) {
 120  1466
         return new Interval<T>( from, to );
 121  
     }
 122  
 
 123  
     /**
 124  
      * Creates an interval representing an arithmetic progression from one number to
 125  
      * another, with the given increment.
 126  
      * <p/>
 127  
      * {@code by} can be negative.
 128  
      * <p/>
 129  
      * Note that {@code to} is not necessarily an element in the interval.
 130  
      * The {@linkplain #last() last element} is given by:
 131  
      * {@code ( to - from ) / by * by + from}
 132  
      * <p/>
 133  
      * The interval will be {@linkplain #isEmpty() empty} if {@code from < to} and
 134  
      * {@code by < 0}, or if {@code from > to} and {@code by > 0}.
 135  
      *
 136  
      * @param <T> the type of numbers in the interval
 137  
      * @param from the {@linkplain #first() first} element in the interval
 138  
      * @param to the termination of the interval
 139  
      * @param by the increment to use to compute successive interval values.  If this is
 140  
      * {@code null}, it will be treated as 1.
 141  
      * @return the new interval
 142  
      * @throws NullPointerException if {@code from}, {@code to}, or {@code by} is
 143  
      * {@code null}
 144  
      * @throws IllegalArgumentException if {@code by == 0}
 145  
      */
 146  
     public static <T extends Number> Interval<T> fromToBy( T from, T to, T by ) {
 147  4410
         return new Interval<T>( from, to, by );
 148  
     }
 149  
 
 150  
     /**
 151  
      * {@inheritDoc}
 152  
      */
 153  
     @Override
 154  
     public <R> ReadOnlySequence<R> collect(
 155  
         UnaryFunctor<? super E, ? extends R> transformer ) {
 156  
 
 157  80
         return (ReadOnlySequence<R>) super.collect( transformer );
 158  
     }
 159  
 
 160  
     /**
 161  
      * {@inheritDoc}
 162  
      */
 163  
     @Override
 164  
     public ReadOnlySequence<E> reject( UnaryCondition<? super E> discriminator ) {
 165  88
         return (ReadOnlySequence<E>) super.reject( discriminator );
 166  
     }
 167  
 
 168  
     /**
 169  
      * {@inheritDoc}
 170  
      */
 171  
     @Override
 172  
     public ReadOnlySequence<E> select( UnaryCondition<? super E> discriminator ) {
 173  88
         return (ReadOnlySequence<E>) super.select( discriminator );
 174  
     }
 175  
 
 176  
     /**
 177  
      * {@inheritDoc}
 178  
      */
 179  
     public ReadOnlySequence<E> concat( ReadOnlySequence<? extends E> otherSequence ) {
 180  40
         return ReadOnlySequences.concat( this, otherSequence );
 181  
     }
 182  
 
 183  
     /**
 184  
      * {@inheritDoc}
 185  
      */
 186  
     public E after( E target ) {
 187  224
         if ( !includes( target ) )
 188  24
             throw new NoSuchElementException();
 189  
 
 190  200
         if ( step.isPositive() ) {
 191  104
             if ( begin.greaterThan( target ) || end.lessThanOrEqualTo( target ) )
 192  32
                 throw new NoSuchElementException();
 193  
         }
 194  
         else {
 195  96
             if ( begin.lessThan( target ) || end.greaterThanOrEqualTo( target ) )
 196  24
                 throw new NoSuchElementException();
 197  
         }
 198  
 
 199  144
         return step.plus( target ).unwrapped();
 200  
     }
 201  
 
 202  
     /**
 203  
      * {@inheritDoc}
 204  
      */
 205  
     public E at( int index ) {
 206  8301
         OperableNumber<E> result = step.times( index ).plus( begin );
 207  
 
 208  8301
         if ( step.isPositive() ) {
 209  5037
             if ( begin.greaterThan( result ) || end.lessThan( result ) )
 210  56
                 throw new IndexOutOfBoundsException();
 211  
         }
 212  
         else {
 213  3264
             if ( begin.lessThan( result ) || end.greaterThan( result ) )
 214  40
                 throw new IndexOutOfBoundsException();
 215  
         }
 216  
 
 217  8205
         return result.unwrapped();
 218  
     }
 219  
 
 220  
     /**
 221  
      * {@inheritDoc}
 222  
      */
 223  
     public E before( E target ) {
 224  224
         if ( !includes( target ) )
 225  24
             throw new NoSuchElementException();
 226  
 
 227  200
         if ( step.isPositive() ) {
 228  104
             if ( begin.greaterThanOrEqualTo( target ) || end.lessThan( target ) )
 229  32
                 throw new NoSuchElementException();
 230  
         }
 231  
         else {
 232  96
             if ( begin.lessThanOrEqualTo( target ) || end.greaterThan( target ) )
 233  24
                 throw new NoSuchElementException();
 234  
         }
 235  
 
 236  144
         return step.negated().plus( target ).unwrapped();
 237  
     }
 238  
 
 239  
     /**
 240  
      * {@inheritDoc}
 241  
      */
 242  
     public ReadOnlySequence<E> copyRange( int start, int stop ) {
 243  736
         return ReadOnlySequences.copyRange( this, start, stop );
 244  
     }
 245  
 
 246  
     /**
 247  
      * {@inheritDoc}
 248  
      */
 249  
     public ReadOnlySequence<E> copyWith( E newElement ) {
 250  56
         return ReadOnlySequences.copyWith( this, newElement );
 251  
     }
 252  
 
 253  
     /**
 254  
      * {@inheritDoc}
 255  
      */
 256  
     public ReadOnlySequence<E> copyWithout( E oldElement ) {
 257  280
         return ReadOnlySequences.copyWithout( this, oldElement );
 258  
     }
 259  
 
 260  
     /**
 261  
      * {@inheritDoc}
 262  
      */
 263  
     public int findFirst( UnaryCondition<? super E> discriminator ) {
 264  88
         return ReadOnlySequences.findFirst( this, discriminator );
 265  
     }
 266  
 
 267  
     /**
 268  
      * {@inheritDoc}
 269  
      */
 270  
     public int findLast( UnaryCondition<? super E> discriminator ) {
 271  136
         return ReadOnlySequences.findLast( this, discriminator );
 272  
     }
 273  
 
 274  
     /**
 275  
      * {@inheritDoc}
 276  
      */
 277  
     public void forEachInReverseDo( UnaryFunctor<? super E, ?> operation ) {
 278  216
         ReadOnlySequences.forEachInReverseDo( this, operation );
 279  104
     }
 280  
 
 281  
     /**
 282  
      * {@inheritDoc}
 283  
      */
 284  
     public E first() {
 285  88
         if ( isEmpty() )
 286  24
             throw new NoSuchElementException();
 287  
 
 288  64
         return begin.unwrapped();
 289  
     }
 290  
 
 291  
     /**
 292  
      * {@inheritDoc}
 293  
      */
 294  
     public void forEachInRangeDo( int start, int stop,
 295  
         UnaryFunctor<? super E, ?> operation ) {
 296  
 
 297  776
         ReadOnlySequences.forEachInRangeDo( this, start, stop, operation );
 298  672
     }
 299  
 
 300  
     /**
 301  
      * {@inheritDoc}
 302  
      */
 303  
     public void forEachInRangeDoWithIndex( int start, int stop,
 304  
         BinaryFunctor<? super Integer, ? super E, ?> operation ) {
 305  
 
 306  776
         ReadOnlySequences.forEachInRangeDoWithIndex( this, start, stop, operation );
 307  672
     }
 308  
 
 309  
     /**
 310  
      * {@inheritDoc}
 311  
      */
 312  
     public int indexOf( E target ) {
 313  272
         return ReadOnlySequences.indexOf( this, target );
 314  
     }
 315  
 
 316  
     /**
 317  
      * {@inheritDoc}
 318  
      */
 319  
     public int indexOf( ReadOnlySequence<? extends E> targetSequence, int start ) {
 320  40
         return ReadOnlySequences.indexOf( this, targetSequence, start );
 321  
     }
 322  
 
 323  
     /**
 324  
      * {@inheritDoc}
 325  
      */
 326  
     public void doWithIndex( BinaryFunctor<? super Integer, ? super E, ?> operation ) {
 327  970
         ReadOnlySequences.doWithIndex( this, operation );
 328  706
     }
 329  
 
 330  
     /**
 331  
      * {@inheritDoc}
 332  
      */
 333  
     public E last() {
 334  80
         if ( isEmpty() )
 335  24
             throw new NoSuchElementException();
 336  
 
 337  56
         return end.unwrapped();
 338  
     }
 339  
 
 340  
     /**
 341  
      * {@inheritDoc}
 342  
      */
 343  
     public ReadOnlySequence<E> reverse() {
 344  80
         return ReadOnlySequences.reverse( this );
 345  
     }
 346  
 
 347  
     /**
 348  
      * {@inheritDoc}
 349  
      */
 350  
     @Override
 351  
     public boolean equals( Object that ) {
 352  657
         return ReadOnlySequences.areSequencesEqual( this, that );
 353  
     }
 354  
 
 355  
     /**
 356  
      * {@inheritDoc}
 357  
      */
 358  
     @Override
 359  
     public int hashCode() {
 360  90
         return ReadOnlySequences.hashCode( this );
 361  
     }
 362  
 
 363  
     /**
 364  
      * {@inheritDoc}
 365  
      */
 366  
     @Override
 367  
     public String toString() {
 368  3
         return ReadOnlySequences.toString( this );
 369  
     }
 370  
 
 371  
     /**
 372  
      * {@inheritDoc}
 373  
      */
 374  
     public <T> void doWithOthers( ReadOnlySequence<? extends T> otherSequence,
 375  
         BinaryFunctor<? super E, ? super T, ?> operation ) {
 376  
 
 377  104
         ReadOnlySequences.doWithOthers( this, otherSequence, operation );
 378  80
     }
 379  
 
 380  
     /**
 381  
      * {@inheritDoc}
 382  
      */
 383  
     public void forEachDo( UnaryFunctor<? super E, ?> operation ) {
 384  1434
         if ( step.isPositive() )
 385  882
             forEachDoPositiveStep( operation );
 386  
         else
 387  552
             forEachDoNegativeStep( operation );
 388  1290
     }
 389  
 
 390  
     private void forEachDoPositiveStep( UnaryFunctor<? super E, ?> operation ) {
 391  882
         for ( OperableNumber<E> i = cast( wrap( begin.unwrapped() ) );
 392  3640
             i.lessThanOrEqualTo( end );
 393  2758
             i.incrementBy( step ) ) {
 394  
 
 395  2846
             operation.evaluate( i.unwrapped() );
 396  
         }
 397  794
     }
 398  
 
 399  
     private void forEachDoNegativeStep( UnaryFunctor<? super E, ?> operation ) {
 400  552
         for ( OperableNumber<E> i = cast( wrap( begin.unwrapped() ) );
 401  2880
             i.greaterThanOrEqualTo( end );
 402  2328
             i.incrementBy( step ) ) {
 403  
 
 404  2384
             operation.evaluate( i.unwrapped() );
 405  
         }
 406  496
     }
 407  
 
 408  
     /**
 409  
      * {@inheritDoc}
 410  
      */
 411  
     @Override
 412  
     public boolean includes( E target ) {
 413  720
         if ( target == null )
 414  0
             return false;
 415  
 
 416  720
         boolean belowMinimumPositive =
 417  
             step.isPositive() && begin.greaterThan( target );
 418  720
         boolean belowMinimumNegative =
 419  
             step.isNegative() && end.greaterThan( target );
 420  
 
 421  720
         if ( belowMinimumPositive || belowMinimumNegative )
 422  88
             return false;
 423  
 
 424  632
         return begin.negated().plus( target ).modulo( step ).isZero();
 425  
     }
 426  
 
 427  
     /**
 428  
      * {@inheritDoc}
 429  
      */
 430  
     public int size() {
 431  7231
         return size;
 432  
     }
 433  
 
 434  
     /**
 435  
      * {@inheritDoc}
 436  
      */
 437  
     @Override
 438  
     protected ExtensibleCollection<E> newEmptyExtensibleCollection() {
 439  160
         return newEmptyExtensibleResultCollection();
 440  
     }
 441  
 
 442  
     /**
 443  
      * {@inheritDoc}
 444  
      */
 445  
     @Override
 446  
     protected <R> ExtensibleCollection<R> newEmptyExtensibleResultCollection() {
 447  232
         return emptyOrderedCollection();
 448  
     }
 449  
 
 450  
     private boolean isEmptyIntervalSpecified( OperableNumber<E> from,
 451  
         OperableNumber<E> to, OperableNumber<E> by ) {
 452  
 
 453  5868
         boolean emptyDescending = from.lessThan( to ) && by.isNegative();
 454  5868
         boolean emptyAscending = from.greaterThan( to ) && by.isPositive();
 455  
 
 456  5868
         return emptyDescending || emptyAscending;
 457  
     }
 458  
 
 459  
     private int computeSize() {
 460  5868
         if ( step.isPositive() && begin.greaterThan( end ) )
 461  513
             return 0;
 462  
 
 463  5355
         if ( step.isNegative() && begin.lessThan( end ) )
 464  256
             return 0;
 465  
 
 466  5099
         return end.minus( begin ).dividedBy( step ).plus( 1 ).unwrapped().intValue();
 467  
     }
 468  
 }