/* * Copyright 1999-2006 University of Chicago * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.dcache.ftp.client; /** * Represents a range of integers. * The name reflects the fact that it is used with FTP extended mode restart markers, * where it represents a range of transfered bytes. **/ public class ByteRange { /** * lower range limit **/ public long from; /** * upper range limit **/ public long to; /** * @param from lower range limit * @param to upper range limit * @throws IllegalArgumentException if to < from **/ public ByteRange(long from, long to) { if (to < from) { throw new IllegalArgumentException( "Range upper boundary smaller than lower boundary"); } this.from = from; this.to = to; } /** * @return true if both object logically represent the same range * (even if they are two separate ByteRange instances) **/ public boolean equals(Object other) { if (this == other) { return true; } if (other instanceof ByteRange) { ByteRange otherObj = (ByteRange) other; return (this.to == otherObj.to && this.from == otherObj.from); } else { return false; } } public int hashCode() { return (int) (this.to + this.from); } /** * copying constructor */ public ByteRange(ByteRange src) { this.copy(src); } private void copy(ByteRange other) { this.from = other.from; this.to = other.to; } public static final int THIS_BELOW = 1; public static final int ADJACENT = 2; public static final int THIS_SUPERSET = 3; public static final int THIS_SUBSET = 4; public static final int THIS_ABOVE = 5; /** * If this range can be consolidated with the other one, * modify this range so that it represents the result of merging * this and the other range. * The parameter object remains intact. * Return value indicates what operation has been performed. * <ul> * <li> If the two ranges were separate, then this range will remain unchanged. * The return value will be THIS_BELOW if this range is below the other * range, or THIS_ABOVE in the other case. * <li>If this range was a superset of the other, * then this range remains unchanged and THIS_SUPERSET will be returned. * A special case of this situation is when both ranges were equal. * <li>If other range was a superset of this, OTHER_SUPERSET will be returned. * <li>Otherwise ADJACENT is returned, meaning that merge was possible * but no range is a superset of the other. * </ul> * Note that two ranges are considered separate if there is at least * one integer between them. For instance, "1-3" and "5-7" are separate * but "1-3" and "4-7" are adjacent because merge is possible. **/ public int merge(final ByteRange other) { /* notation: t = this range o = other range - = the common subset of both Thus there are 13 cases: o t ot o-t o- o-o -t - -o t-t t- t-o to t o */ if (other.from < this.from) { if (other.to + 1 < this.from) { // o t return THIS_ABOVE; } this.from = other.from; if (this.to <= other.to) { // o- // o-o this.to = other.to; return THIS_SUBSET; } // ot // o-t } else { if (this.to + 1 < other.from) { // t o return THIS_BELOW; } if (other.to <= this.to) { // -t // - // t-t // t- return THIS_SUPERSET; } this.to = other.to; if (other.from == this.from) { // -o return THIS_SUBSET; } // t- //to } return ADJACENT; } public String toString() { return Long.toString(from) + "-" + Long.toString(to); } }