/*
* SubstringRope.java
* Copyright (C) 2007 Amin Ahmad.
*
* This file is part of Java Ropes.
*
* Java Ropes is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Java Ropes is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Java Ropes. If not, see .
*
* Amin Ahmad can be contacted at amin.ahmad@gmail.com or on the web at
* www.ahmadsoft.org.
*/
package org.ahmadsoft.ropes.impl;
import java.io.IOException;
import java.io.Writer;
import java.util.Iterator;
import org.ahmadsoft.ropes.Rope;
/**
* Represents a lazily-evaluated substring of another rope. For performance
* reasons, the target rope must be a FlatRope
.
* @author aahmad
*/
public class SubstringRope extends AbstractRope {
private final FlatRope rope;
private final int offset;
private final int length;
public SubstringRope(final FlatRope rope, final int offset, final int length) {
if (length < 0 || offset < 0 || offset + length > rope.length())
throw new IndexOutOfBoundsException("Invalid substring offset (" + offset + ") and length (" + length + ") for underlying rope with length " + rope.length());
this.rope = rope;
this.offset = offset;
this.length = length;
}
@Override
public char charAt(final int index) {
if (index >= this.length())
throw new IndexOutOfBoundsException("Rope index out of range: " + index);
return this.rope.charAt(this.offset + index);
}
@Override
public byte depth() {
return RopeUtilities.INSTANCE.depth(getRope());
}
int getOffset() {
return this.offset;
}
/**
* Returns the rope underlying this one.
* @return the rope underlying this one.
*/
public Rope getRope() {
return this.rope;
}
@Override
public Iterator iterator(final int start) {
if (start < 0 || start > this.length())
throw new IndexOutOfBoundsException("Rope index out of range: " + start);
return new Iterator() {
final Iterator u = SubstringRope.this.getRope().iterator(SubstringRope.this.getOffset() + start);
int position = start;
@Override
public boolean hasNext() {
return this.position < SubstringRope.this.length();
}
@Override
public Character next() {
++this.position;
return this.u.next();
}
@Override
public void remove() {
this.u.remove();
}
};
}
@Override
public int length() {
return this.length;
}
@Override
public Rope reverse() {
return new ReverseRope(this);
}
@Override
public Iterator reverseIterator(final int start) {
if (start < 0 || start > this.length())
throw new IndexOutOfBoundsException("Rope index out of range: " + start);
return new Iterator() {
final Iterator u = SubstringRope.this.getRope().reverseIterator(SubstringRope.this.getRope().length() - SubstringRope.this.getOffset() - SubstringRope.this.length() + start);
int position = SubstringRope.this.length() - start;
@Override
public boolean hasNext() {
return this.position > 0;
}
@Override
public Character next() {
--this.position;
return this.u.next();
}
@Override
public void remove() {
this.u.remove();
}
};
}
@Override
public Rope subSequence(final int start, final int end) {
if (start == 0 && end == this.length())
return this;
return new SubstringRope(this.rope, this.offset + start, end-start);
}
@Override
public String toString() {
return this.rope.toString(this.offset, this.length);
}
@Override
public void write(final Writer out) throws IOException {
this.rope.write(out, this.offset, this.length);
}
@Override
public void write(final Writer out, final int offset, final int length) throws IOException {
this.rope.write(out, this.offset + offset, length);
}
}