1/* 2 * SubstringRope.java 3 * Copyright (C) 2007 Amin Ahmad. 4 * 5 * This file is part of Java Ropes. 6 * 7 * Java Ropes is free software: you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation, either version 3 of the License, or 10 * (at your option) any later version. 11 * 12 * Java Ropes is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with Java Ropes. If not, see <http://www.gnu.org/licenses/>. 19 * 20 * Amin Ahmad can be contacted at amin.ahmad@gmail.com or on the web at 21 * www.ahmadsoft.org. 22 */ 23package org.ahmadsoft.ropes.impl; 24 25import java.io.IOException; 26import java.io.Writer; 27import java.util.Iterator; 28 29import org.ahmadsoft.ropes.Rope; 30 31/** 32 * Represents a lazily-evaluated substring of another rope. For performance 33 * reasons, the target rope must be a <code>FlatRope</code>. 34 * @author aahmad 35 */ 36public class SubstringRope extends AbstractRope { 37 38 private final FlatRope rope; 39 private final int offset; 40 private final int length; 41 42 public SubstringRope(final FlatRope rope, final int offset, final int length) { 43 if (length < 0 || offset < 0 || offset + length > rope.length()) 44 throw new IndexOutOfBoundsException("Invalid substring offset (" + offset + ") and length (" + length + ") for underlying rope with length " + rope.length()); 45 46 this.rope = rope; 47 this.offset = offset; 48 this.length = length; 49 } 50 51 @Override 52 public char charAt(final int index) { 53 if (index >= this.length()) 54 throw new IndexOutOfBoundsException("Rope index out of range: " + index); 55 56 return this.rope.charAt(this.offset + index); 57 } 58 59 @Override 60 public byte depth() { 61 return RopeUtilities.INSTANCE.depth(getRope()); 62 } 63 64 int getOffset() { 65 return this.offset; 66 } 67 68 /** 69 * Returns the rope underlying this one. 70 * @return the rope underlying this one. 71 */ 72 public Rope getRope() { 73 return this.rope; 74 } 75 76 @Override 77 public Iterator<Character> iterator(final int start) { 78 if (start < 0 || start > this.length()) 79 throw new IndexOutOfBoundsException("Rope index out of range: " + start); 80 return new Iterator<Character>() { 81 82 final Iterator<Character> u = SubstringRope.this.getRope().iterator(SubstringRope.this.getOffset() + start); 83 int position = start; 84 85 @Override 86 public boolean hasNext() { 87 return this.position < SubstringRope.this.length(); 88 } 89 90 @Override 91 public Character next() { 92 ++this.position; 93 return this.u.next(); 94 } 95 96 @Override 97 public void remove() { 98 this.u.remove(); 99 } 100 101 }; 102 } 103 104 @Override 105 public int length() { 106 return this.length; 107 } 108 109 @Override 110 public Rope reverse() { 111 return new ReverseRope(this); 112 } 113 114 @Override 115 public Iterator<Character> reverseIterator(final int start) { 116 if (start < 0 || start > this.length()) 117 throw new IndexOutOfBoundsException("Rope index out of range: " + start); 118 return new Iterator<Character>() { 119 final Iterator<Character> u = SubstringRope.this.getRope().reverseIterator(SubstringRope.this.getRope().length() - SubstringRope.this.getOffset() - SubstringRope.this.length() + start); 120 int position = SubstringRope.this.length() - start; 121 122 @Override 123 public boolean hasNext() { 124 return this.position > 0; 125 } 126 127 @Override 128 public Character next() { 129 --this.position; 130 return this.u.next(); 131 } 132 133 @Override 134 public void remove() { 135 this.u.remove(); 136 } 137 }; 138 } 139 140 @Override 141 public Rope subSequence(final int start, final int end) { 142 if (start == 0 && end == this.length()) 143 return this; 144 return new SubstringRope(this.rope, this.offset + start, end-start); 145 } 146 147 @Override 148 public String toString() { 149 return this.rope.toString(this.offset, this.length); 150 } 151 152 @Override 153 public void write(final Writer out) throws IOException { 154 this.rope.write(out, this.offset, this.length); 155 } 156 157 @Override 158 public void write(final Writer out, final int offset, final int length) throws IOException { 159 this.rope.write(out, this.offset + offset, length); 160 } 161} 162