Coverage Report - net.wotonomy.foundation.NSRange
 
Classes in this File Line Coverage Branch Coverage Complexity
NSRange
12% 
0% 
3.211
 
 1  
 /*
 2  
 Wotonomy: OpenStep design patterns for pure Java applications.
 3  
 Copyright (C) 2000 Blacksmith, Inc.
 4  
 
 5  
 This library is free software; you can redistribute it and/or
 6  
 modify it under the terms of the GNU Lesser General Public
 7  
 License as published by the Free Software Foundation; either
 8  
 version 2.1 of the License, or (at your option) any later version.
 9  
 
 10  
 This library is distributed in the hope that it will be useful,
 11  
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 12  
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 13  
 Lesser General Public License for more details.
 14  
 
 15  
 You should have received a copy of the GNU Lesser General Public
 16  
 License along with this library; if not, see http://www.gnu.org
 17  
 */
 18  
 
 19  
 package net.wotonomy.foundation;
 20  
 
 21  
 /**
 22  
 * A pure java implementation of NSRange.
 23  
 * An NSRange represents a range of numbers
 24  
 * having a starting location and spanning a
 25  
 * length.
 26  
 *
 27  
 * @author michael@mpowers.net
 28  
 * @author $Author: cgruber $
 29  
 * @version $Revision: 920 $
 30  
 */
 31  1
 public class NSRange implements Cloneable
 32  
 {
 33  
     /**
 34  
     * An empty range.
 35  
     */
 36  9
     public static final NSRange ZeroRange = new NSRange();
 37  
     
 38  
     protected int loc;
 39  
     protected int len;
 40  
 
 41  
     /**
 42  
     * Default constructor produces an empty range.
 43  
     */
 44  
     public NSRange ()
 45  
     {
 46  9
             this( 0, 0 ); 
 47  9
     }
 48  
     
 49  
     /**
 50  
     * Produces a range with the specified location and length.
 51  
     */
 52  10
     public NSRange (int location, int length)
 53  80
     {
 54  90
             loc = location;
 55  90
             len = length;
 56  90
     }
 57  
     
 58  
     /**
 59  
     * Produces a range that has the same location and length as 
 60  
     * the specified range.
 61  
     */
 62  
     public NSRange (NSRange aRange)
 63  
     {
 64  0
             this( aRange.location(), aRange.length() );
 65  0
     }
 66  
 
 67  
     /**
 68  
     * Returns the location of this range.
 69  
     */
 70  
     public int location ()
 71  
     {
 72  360
             return loc;
 73  
     }
 74  
     
 75  
     /**
 76  
     * Returns the length of this range.
 77  
     */
 78  
     public int length ()
 79  
     {
 80  135
             return len;
 81  
     }
 82  
     
 83  
     /**
 84  
     * Returns the maximum extent of the range.  This number is 
 85  
     * one more than the last position in the range.
 86  
     */
 87  
     public int maxRange ()
 88  
     {
 89  90
             return location() + length() -1;
 90  
     }
 91  
     
 92  
     /**
 93  
     * Returns whether this is an empty range, therefore
 94  
     * whether the length is zero.
 95  
     */
 96  
     public boolean isEmpty ()
 97  
     {
 98  0
             return ( length() == 0 );
 99  
     }
 100  
     
 101  
     /**
 102  
     * Returns whether the specified location is contained
 103  
     * within this range.
 104  
     */
 105  
     public boolean locationInRange (int location)
 106  
     {
 107  0
             if ( location < location() ) return false;
 108  0
             if ( location >= maxRange() ) return false;
 109  0
             return true;
 110  
     }
 111  
     
 112  
     /**
 113  
     * Returns whether the specified range is equal to this range.
 114  
     */
 115  
     public boolean isEqualToRange (NSRange aRange)
 116  
     {
 117  0
             if ( aRange == null ) return false;
 118  0
             return ( ( aRange.location() == location() ) 
 119  0
                     &&   ( aRange.length() == length() ) );
 120  
     }
 121  
 
 122  
     /**
 123  
     * Returns whether the specified object is equal to this range.
 124  
         */
 125  
     public boolean equals (Object anObject)
 126  
     {
 127  0
             if ( anObject instanceof NSRange ) 
 128  0
                     return isEqualToRange( (NSRange) anObject );
 129  0
                 return false;
 130  
     }
 131  
 
 132  
     /**
 133  
     * Returns a hashCode. 
 134  
         */
 135  
     public int hashCode ()
 136  
     {
 137  
             // TODO: Test this logic.
 138  0
             return ( location() << 2 ) & length(); // bitwise ops never my forte 
 139  
     }
 140  
 
 141  
     /**
 142  
     * Returns a string representation of this range.
 143  
         */
 144  
     public String toString ()
 145  
     {
 146  0
             return "[NSRange: location = " + location() 
 147  0
                     + "; length = " + length() + "]";
 148  
     }
 149  
 
 150  
     /**
 151  
     * Returns the union of this range and the specified range, if any.
 152  
     * Gaps are filled, so the result is the smallest starting position
 153  
     * and the largest ending position.
 154  
         */
 155  
     public NSRange rangeByUnioningRange (NSRange aRange)
 156  
     {
 157  0
             if ( aRange == null ) return this;
 158  
     
 159  
             // TODO: Test this logic.    
 160  0
                 int resultLoc = Math.min( this.location(), aRange.location() );
 161  0
                 int resultLen = Math.max( this.location() + this.length(), 
 162  0
                         aRange.location() + aRange.length() ) - resultLoc;
 163  0
                 return new NSRange( resultLoc, resultLen );
 164  
     }        
 165  
 
 166  
     /**
 167  
     * Returns the intersection of this range and the specified range,
 168  
     * if any.  If no intersection, returns an empty range.
 169  
         */
 170  
     public NSRange rangeByIntersectingRange (NSRange aRange)
 171  
     {
 172  
             // TODO: Test this logic.    
 173  0
             if ( ! intersectsRange( aRange ) ) return ZeroRange;
 174  0
             int start = Math.max( this.location(), aRange.location() );
 175  0
             int end = Math.min( this.location() + this.length(), 
 176  0
                     aRange.location() + aRange.length() );
 177  0
                 return new NSRange( start, end - start );
 178  
     }
 179  
 
 180  
     /**
 181  
     * Returns whether the specified range overlaps
 182  
     * at any point with this range.
 183  
         */
 184  
     public boolean intersectsRange (NSRange aRange)
 185  
     {
 186  
             // TODO: Test this logic.    
 187  0
             if ( aRange == null ) return false;
 188  0
             if ( ( this.location() >= aRange.location() ) 
 189  0
                 &&   ( this.location() < aRange.location() + aRange.length() ) )
 190  0
                         return true;
 191  0
             if ( ( aRange.location() >= this.location() ) 
 192  0
                 &&   ( aRange.location() < this.location() + this.length() ) )
 193  0
                         return true;
 194  0
                 return false;
 195  
     }
 196  
 
 197  
     /**
 198  
     * Returns whether this range is completely 
 199  
     * contained within the specified range.
 200  
         */
 201  
     public boolean isSubrangeOfRange (NSRange aRange)
 202  
     {
 203  
             // TODO: Test this logic.    
 204  0
             if ( aRange == null ) return false;
 205  0
             if ( ( this.location() >= aRange.location() ) 
 206  0
             &&   ( this.maxRange() <= aRange.maxRange() ) )
 207  0
                     return true;
 208  0
                 return false;
 209  
     }
 210  
 
 211  
     /**
 212  
     * Eliminates any intersections between this range and the specified
 213  
     * range.  This produces two ranges, either of which may be empty.
 214  
     * These two ranges are returned by modifying the supplied second
 215  
     * and third parameters.
 216  
         */
 217  
     public void subtractRange (NSRange aRange, 
 218  
             NSMutableRange firstResult, NSMutableRange secondResult)
 219  
     {
 220  0
             if ( aRange == null ) return;
 221  
             
 222  
             // TODO: Test this logic.
 223  
             // no intersection: return this and aRange without calculation
 224  0
             if ( ! intersectsRange( aRange ) ) 
 225  
             { 
 226  0
                     if ( firstResult != null )
 227  
                     {
 228  0
                 firstResult.setLocation( this.location() );
 229  0
                 firstResult.setLength( this.length() );
 230  
                     }
 231  0
                     if ( secondResult != null )
 232  
                     {
 233  0
                 secondResult.setLocation( aRange.location() );
 234  0
                 secondResult.setLength( aRange.location() );
 235  
                     }
 236  0
                     return;
 237  
             }
 238  
             
 239  
             // TODO: Test this logic.
 240  
             // this range is completely contained by other range
 241  0
             if ( isSubrangeOfRange( aRange ) )
 242  
             { 
 243  0
                         if ( firstResult != null )
 244  
                     {
 245  0
                 firstResult.setLocation( aRange.location() );
 246  0
                 firstResult.setLength( this.location() - aRange.location() );
 247  
                     }
 248  0
                     if ( secondResult != null )
 249  
                     {
 250  0
                 secondResult.setLocation( this.maxRange() );
 251  0
                 secondResult.setLength( 
 252  0
                                         aRange.maxRange() - this.maxRange() - 1 ); // test this
 253  
                     }
 254  0
                     return;
 255  
             }
 256  
 
 257  
             // TODO: Test this logic.
 258  
             // other range is completely contained by this range
 259  0
             if ( aRange.isSubrangeOfRange( this ) )
 260  
             { 
 261  0
                         if ( firstResult != null )
 262  
                     {
 263  0
                 firstResult.setLocation( this.location() );
 264  0
                 firstResult.setLength( aRange.location() - this.location() );
 265  
                     }
 266  0
                     if ( secondResult != null )
 267  
                     {
 268  0
                 secondResult.setLocation( aRange.maxRange() );
 269  0
                 secondResult.setLength( 
 270  0
                                         this.maxRange() - aRange.maxRange() - 1 ); // test this
 271  
                     }
 272  0
                     return;
 273  
             }
 274  
             
 275  
             // TODO: Test this logic.
 276  
             // ranges intersect: remove only the intersection
 277  
             
 278  
             NSRange firstRange, secondRange;
 279  0
             if ( this.location() <= aRange.location() )
 280  
             {
 281  0
                     firstRange = this;
 282  0
                     secondRange = aRange;        
 283  0
             }
 284  
             else
 285  
             {
 286  0
                     firstRange = aRange;
 287  0
                     secondRange = this;        
 288  
             }
 289  
             
 290  0
         if ( firstResult != null )
 291  
         {
 292  0
             firstResult.setLocation( firstRange.location() );
 293  0
             firstResult.setLength( 
 294  0
                             secondRange.location() - firstRange.location() );
 295  
         }
 296  0
         if ( secondResult != null )
 297  
         {
 298  0
             secondResult.setLocation( firstRange.maxRange() );
 299  0
             secondResult.setLength(
 300  0
                 secondRange.maxRange() - aRange.maxRange() - 1 ); // test this
 301  
         }
 302  0
         return;
 303  
 
 304  
     }
 305  
 
 306  
     /**
 307  
     * Returns a copy of this range.
 308  
         */
 309  
     public Object clone ()
 310  
     {
 311  0
             return new NSRange( location(), length() );
 312  
     }
 313  
 
 314  
     /**
 315  
     * Parses a range from a string of the form "{x,y}" where
 316  
     * x is the location and y is the length.  If not parsable,
 317  
     * an IllegalArgumentException is thrown.
 318  
         */
 319  
     public static NSRange fromString (String aString)
 320  
     {
 321  
             // TODO: Test this logic.    
 322  
             try
 323  
             {
 324  0
             java.util.StringTokenizer tokens =
 325  0
                 new java.util.StringTokenizer( aString, "{,}" );
 326  0
                         int loc = Integer.parseInt( tokens.nextToken() );
 327  0
                         int len = Integer.parseInt( tokens.nextToken() );
 328  0
                         return new NSRange( loc, len );
 329  
             }
 330  0
             catch ( Exception exc )
 331  
             {
 332  0
                     throw new IllegalArgumentException( exc.toString() );
 333  
             }
 334  
     }
 335  
     
 336  
 }
 337  
 
 338  
 /*
 339  
  * $Log$
 340  
  * Revision 1.2  2006/02/16 13:15:00  cgruber
 341  
  * Check in all sources in eclipse-friendly maven-enabled packages.
 342  
  *
 343  
  * Revision 1.1.1.1  2000/12/21 15:47:42  mpowers
 344  
  * Contributing wotonomy.
 345  
  *
 346  
  * Revision 1.3  2000/12/20 16:25:38  michael
 347  
  * Added log to all files.
 348  
  *
 349  
  *
 350  
  */
 351