/* * Copyright (C) 2007 SQL Explorer Development Team * http://sourceforge.net/projects/eclipsesql * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package net.sourceforge.sqlexplorer.util; import java.util.Iterator; /** * Implements CharSequence over a section of an existing StringBuffer; * note that it does not duplicate the buffer, just provides a view * onto a subsection of the StringBuffer. * * The idea is that as we tokenize and parse queries, we can use instances * of BackedCharSequence to record where the runs of characters for that * particular token or query are, without having to duplicate the underlying * textual data. This is not solely for memory conservation - because tokens * overlap queries, we are able to manipulate the tokens and queries after * tokenizing/parsing is complete (EG structured comments). * * @author John Spackman */ public class BackedCharSequence implements CharSequence, Iterable<Character> { protected StringBuffer buffer; protected int start; protected int end; public BackedCharSequence(StringBuffer buffer, int start, int end) { super(); if (start > end || start < 0) throw new StringIndexOutOfBoundsException(); this.buffer = buffer; this.start = start; this.end = end; } public Iterator<Character> iterator() { return new Iterator<Character>() { private int pos = start; public boolean hasNext() { return pos < end; } public Character next() { return buffer.charAt(pos++); } public void remove() { throw new UnsupportedOperationException(); } }; } /** * Returns a String of the section we represent */ public String toString() { return buffer.substring(start, end); } /** * Creates a sequence starting with this and ending with the sequence * in end; note that both this and end MUST have the same buffer instance * @param end * @return */ public BackedCharSequence outerSequence(BackedCharSequence end) { if (end.buffer != buffer) throw new IllegalArgumentException("Cannot form outer sequence from different buffers"); return new BackedCharSequence(buffer, this.start, end.end); } /** * Creates a sequence on the buffer with the given points; can be larger or smaller, but * must be within the buffer * @param start * @param end * @return */ public BackedCharSequence superSequence(int start, int end) { if (start < 0 || end > buffer.length()) throw new IllegalArgumentException("Cannot super-size to larger than the buffer"); return new BackedCharSequence(buffer, start, end); } /** * Creates a sequence on the buffer starting at start * @param start * @return */ public BackedCharSequence superSequence(int start) { if (start < 0) throw new IllegalArgumentException("Cannot super-size to larger than the buffer"); return new BackedCharSequence(buffer, start, end); } /** * Determines whether <code>that</code> is completely contained in our buffer * @param that * @return */ public boolean contains(BackedCharSequence that) { if (buffer != that.buffer) return false; return start <= that.start && end >= that.end; } /** * Adjusts the start and end positions by adding an offset * @param offset amount to adjust by, can be negative */ public void applyOffset(int offset) { if (end + offset > buffer.length()) throw new IllegalArgumentException("Cannot offset beyond the size of the buffer"); if (start + offset < 0) throw new IllegalArgumentException("Cannot offset beyond the start of the buffer"); start += offset; end += offset; } /** * @return the start */ public int getStart() { return start; } /** * @return the end */ public int getEnd() { return end; } /* (non-JavaDoc) * @see java.lang.CharSequence#charAt(int) */ public char charAt(int index) { if (index < 0 || end <= start + index) throw new StringIndexOutOfBoundsException(); return buffer.charAt(start + index); } /* (non-JavaDoc) * @see java.lang.CharSequence#length() */ public int length() { return end - start; } /* (non-JavaDoc) * @see java.lang.CharSequence#subSequence(int,int) */ public CharSequence subSequence(int start, int end) { if (this.end <= this.start + end || end < start || start < 0) throw new StringIndexOutOfBoundsException(); return new BackedCharSequence(buffer, this.start + start, this.start + end); } }