1/* 2 * ReverseRope.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 * A rope representing the reversal of character sequence. 33 * Internal implementation only. 34 * @author Amin Ahmad 35 */ 36public final class ReverseRope extends AbstractRope { 37 38 private final Rope rope; 39 private final byte depth; 40 41 /** 42 * Constructs a new rope from an underlying rope. 43 * <p> 44 * Balancing algorithm works optimally when only FlatRopes or 45 * SubstringRopes are supplied. Framework must guarantee this 46 * as no runtime check is performed. 47 * @param rope 48 */ 49 public ReverseRope(final Rope rope) { 50 this.rope = rope; 51 this.depth = (byte) (RopeUtilities.INSTANCE.depth(rope) + 1); 52 } 53 54 @Override 55 public char charAt(final int index) { 56 return this.rope.charAt(this.length() - index - 1); 57 } 58 59 @Override 60 public byte depth() { 61 return this.depth; 62 } 63 64 @Override 65 public Iterator<Character> iterator(final int start) { 66 if (start < 0 || start > this.length()) 67 throw new IndexOutOfBoundsException("Rope index out of range: " + start); 68 return new Iterator<Character>() { 69 int current = start; 70 @Override 71 public boolean hasNext() { 72 return this.current < ReverseRope.this.length(); 73 } 74 75 @Override 76 public Character next() { 77 return ReverseRope.this.charAt(this.current++); 78 } 79 80 @Override 81 public void remove() { 82 throw new UnsupportedOperationException("Rope iterator is read-only."); 83 } 84 }; 85 } 86 87 @Override 88 public int length() { 89 return this.rope.length(); 90 } 91 92 @Override 93 public Rope reverse() { 94 return this.rope; 95 } 96 97 public Iterator<Character> reverseIterator(final int start) { 98 if (start < 0 || start > this.length()) 99 throw new IndexOutOfBoundsException("Rope index out of range: " + start); 100 return new Iterator<Character>() { 101 int current = ReverseRope.this.length() - start; 102 @Override 103 public boolean hasNext() { 104 return this.current > 0; 105 } 106 107 @Override 108 public Character next() { 109 return ReverseRope.this.charAt(--this.current); 110 } 111 112 @Override 113 public void remove() { 114 throw new UnsupportedOperationException("Rope iterator is read-only."); 115 } 116 }; 117 } 118 119 @Override 120 public Rope subSequence(final int start, final int end) { 121 if (start == 0 && end == this.length()) 122 return this; 123 return this.rope.subSequence(this.length() - end, this.length() - start).reverse(); 124 } 125 126 @Override 127 public void write(final Writer out) throws IOException { 128 this.write(out, 0, this.length()); 129 } 130 131 @Override 132 public void write(final Writer out, final int offset, final int length) throws IOException { 133 if (offset < 0 || offset + length > this.length()) 134 throw new IndexOutOfBoundsException("Rope index out of bounds:" + (offset < 0 ? offset: offset + length)); 135 for (int j=offset; j<offset + length; ++j) 136 out.write(this.charAt(j)); 137 } 138} 139