/*
* Copyright 2015 Terracotta, Inc., a Software AG company.
*
* 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.terracotta.offheapstore.disk.storage;
import org.terracotta.offheapstore.util.AATreeSet.AbstractTreeNode;
import org.terracotta.offheapstore.util.AATreeSet.Node;
Class that represents the regions held within this set.
/**
* Class that represents the regions held within this set.
*/
class Region extends AbstractTreeNode<Region> implements Comparable<Comparable<?>> {
private long start;
private long end;
private long availableBitSet;
Region(long value) {
this(value, value);
}
Creates a region containing the given range of values (inclusive).
/**
* Creates a region containing the given range of values (inclusive).
*/
Region(long start, long end) {
this.start = start;
this.end = end;
updateAvailable();
}
Create a shallow copy of a region.
The new Region has NULL left and right children.
/**
* Create a shallow copy of a region.
* <p>
* The new Region has NULL left and right children.
*/
Region(Region r) {
this(r.start(), r.end());
}
long available() {
if (getLeft().getPayload() == null && getRight().getPayload() == null) {
return availableHere();
} else {
return availableBitSet;
}
}
long availableHere() {
long bits = 0;
for (int i = 0; i < Long.SIZE - 1; i++) {
long size = 1L << i;
long mask = size - 1;
long a = (start + mask) & ~mask;
if ((end - a + 1) >= size) {
bits |= size;
}
}
return bits;
}
private void updateAvailable() {
Region left = getLeft().getPayload();
Region right = getRight().getPayload();
long leftAvailable = left == null ? 0 : left.available();
long rightAvailable = right == null ? 0 : right.available();
availableBitSet = availableHere() | leftAvailable | rightAvailable;
}
@Override
public void setLeft(Node<Region> l) {
super.setLeft(l);
updateAvailable();
}
@Override
public void setRight(Node<Region> r) {
super.setRight(r);
updateAvailable();
}
{@inheritDoc}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
return "Range(" + this.start + "," + this.end + ")" + " available:" + Long.toBinaryString(this.availableHere());
}
Returns the size of this range (the number of values within its bounds).
/**
* Returns the size of this range (the number of values within its bounds).
*/
public long size() {
// since it is all inclusive
return isNull() ? 0 : this.end - this.start + 1;
}
protected boolean isNull() {
return this.start > this.end;
}
public Region remove(Region r) {
if (r.start < this.start || r.end > this.end) {
throw new AssertionError("Ranges : Illegal value passed to remove : " + this + " remove called for : " + r);
}
if (this.start == r.start) {
this.start = r.end + 1;
updateAvailable();
return null;
} else if (this.end == r.end) {
this.end = r.start - 1;
updateAvailable();
return null;
} else {
Region newRegion = new Region(r.end + 1, this.end);
this.end = r.start - 1;
updateAvailable();
return newRegion;
}
}
Merge the supplied region into this region (if they are adjoining).
Params: - r – region to merge
/**
* Merge the supplied region into this region (if they are adjoining).
*
* @param r region to merge
*/
public void merge(Region r) {
if (this.start == r.end + 1) {
this.start = r.start;
} else if (this.end == r.start - 1) {
this.end = r.end;
} else {
throw new AssertionError("Ranges : Merge called on non contiguous values : [this]:" + this + " and " + r);
}
updateAvailable();
}
Order this region relative to another.
/**
* Order this region relative to another.
*/
@Override
public int compareTo(Comparable<?> other) {
if (other instanceof Region) {
Region r = (Region) other;
if (this.start < r.start) {
return -1;
} else if (this.end > r.end) {
return 1;
} else {
return 0;
}
} else if (other instanceof Long) {
Long l = (Long) other;
if (l > end) {
return -1;
} else if (l < start) {
return 1;
} else {
return 0;
}
} else {
throw new AssertionError();
}
}
@Override
public boolean equals(Object other) {
if (other instanceof Region) {
Region r = (Region) other;
return (this.start == r.start) && (this.end == r.end);
} else {
throw new AssertionError();
}
}
@Override
public int hashCode() {
return (3 * (int) this.start) ^ (7 * (int) (this.start >>> Integer.SIZE))
^ (5 * (int) this.end) ^ (11 * (int) (this.end >>> Integer.SIZE));
}
@Override
public Region getPayload() {
return this;
}
@Override
public void swapPayload(Node<Region> other) {
if (other instanceof Region) {
Region r = (Region) other;
long temp = this.start;
this.start = r.start;
r.start = temp;
temp = this.end;
this.end = r.end;
r.end = temp;
updateAvailable();
} else {
throw new AssertionError();
}
}
Returns the start of this range (inclusive).
/**
* Returns the start of this range (inclusive).
*/
public long start() {
return start;
}
public long end() {
return end;
}
}