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