/*
* 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);
}
}