From 25382427eeafda30aa06a27f37c65fdaf8b67eba Mon Sep 17 00:00:00 2001 From: bjculkin Date: Thu, 6 Apr 2017 14:14:37 -0400 Subject: Reorganize blocks --- .../src/main/java/bjc/utils/ioutils/Block.java | 87 ----------------- .../main/java/bjc/utils/ioutils/BlockReader.java | 68 ------------- .../main/java/bjc/utils/ioutils/BlockReaders.java | 81 ---------------- .../java/bjc/utils/ioutils/LayeredBlockReader.java | 70 -------------- .../src/main/java/bjc/utils/ioutils/Prompter.java | 2 + .../bjc/utils/ioutils/PushbackBlockReader.java | 98 ------------------- .../java/bjc/utils/ioutils/SerialBlockReader.java | 98 ------------------- .../java/bjc/utils/ioutils/SimpleBlockReader.java | 107 --------------------- .../bjc/utils/ioutils/TriggeredBlockReader.java | 62 ------------ .../main/java/bjc/utils/ioutils/blocks/Block.java | 87 +++++++++++++++++ .../java/bjc/utils/ioutils/blocks/BlockReader.java | 68 +++++++++++++ .../bjc/utils/ioutils/blocks/BlockReaders.java | 81 ++++++++++++++++ .../utils/ioutils/blocks/LayeredBlockReader.java | 70 ++++++++++++++ .../utils/ioutils/blocks/PushbackBlockReader.java | 98 +++++++++++++++++++ .../utils/ioutils/blocks/SerialBlockReader.java | 98 +++++++++++++++++++ .../utils/ioutils/blocks/SimpleBlockReader.java | 107 +++++++++++++++++++++ .../utils/ioutils/blocks/TriggeredBlockReader.java | 62 ++++++++++++ 17 files changed, 673 insertions(+), 671 deletions(-) delete mode 100644 BJC-Utils2/src/main/java/bjc/utils/ioutils/Block.java delete mode 100644 BJC-Utils2/src/main/java/bjc/utils/ioutils/BlockReader.java delete mode 100644 BJC-Utils2/src/main/java/bjc/utils/ioutils/BlockReaders.java delete mode 100644 BJC-Utils2/src/main/java/bjc/utils/ioutils/LayeredBlockReader.java delete mode 100644 BJC-Utils2/src/main/java/bjc/utils/ioutils/PushbackBlockReader.java delete mode 100644 BJC-Utils2/src/main/java/bjc/utils/ioutils/SerialBlockReader.java delete mode 100644 BJC-Utils2/src/main/java/bjc/utils/ioutils/SimpleBlockReader.java delete mode 100644 BJC-Utils2/src/main/java/bjc/utils/ioutils/TriggeredBlockReader.java create mode 100644 BJC-Utils2/src/main/java/bjc/utils/ioutils/blocks/Block.java create mode 100644 BJC-Utils2/src/main/java/bjc/utils/ioutils/blocks/BlockReader.java create mode 100644 BJC-Utils2/src/main/java/bjc/utils/ioutils/blocks/BlockReaders.java create mode 100644 BJC-Utils2/src/main/java/bjc/utils/ioutils/blocks/LayeredBlockReader.java create mode 100644 BJC-Utils2/src/main/java/bjc/utils/ioutils/blocks/PushbackBlockReader.java create mode 100644 BJC-Utils2/src/main/java/bjc/utils/ioutils/blocks/SerialBlockReader.java create mode 100644 BJC-Utils2/src/main/java/bjc/utils/ioutils/blocks/SimpleBlockReader.java create mode 100644 BJC-Utils2/src/main/java/bjc/utils/ioutils/blocks/TriggeredBlockReader.java (limited to 'BJC-Utils2/src/main') diff --git a/BJC-Utils2/src/main/java/bjc/utils/ioutils/Block.java b/BJC-Utils2/src/main/java/bjc/utils/ioutils/Block.java deleted file mode 100644 index 19de1ae..0000000 --- a/BJC-Utils2/src/main/java/bjc/utils/ioutils/Block.java +++ /dev/null @@ -1,87 +0,0 @@ -package bjc.utils.ioutils; - -/** - * Represents a block of text read in from a source. - * - * @author EVE - * - */ -public class Block { - /** - * The contents of this block. - */ - public final String contents; - - /** - * The line of the source this block started on. - */ - public final int startLine; - - /** - * The line of the source this block ended on. - */ - public final int endLine; - - /** - * The number of this block. - */ - public final int blockNo; - - /** - * Create a new block. - * - * @param blockNo - * The number of this block. - * @param contents - * The contents of this block. - * @param startLine - * The line this block started on. - * @param endLine - * The line this block ended. - */ - public Block(int blockNo, String contents, int startLine, int endLine) { - this.contents = contents; - this.startLine = startLine; - this.endLine = endLine; - this.blockNo = blockNo; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - - result = prime * result + blockNo; - result = prime * result + ((contents == null) ? 0 : contents.hashCode()); - result = prime * result + endLine; - result = prime * result + startLine; - - return result; - } - - @Override - public boolean equals(Object obj) { - if(this == obj) return true; - if(obj == null) return false; - if(!(obj instanceof Block)) return false; - - Block other = (Block) obj; - - if(blockNo != other.blockNo) return false; - - if(contents == null) { - if(other.contents != null) return false; - } else if(!contents.equals(other.contents)) return false; - - if(endLine != other.endLine) return false; - if(startLine != other.startLine) return false; - - return true; - } - - @Override - public String toString() { - return String.format("Block #%d (from lines %d to %d), length: %d characters", blockNo, startLine, - endLine, contents.length()); - } -} \ No newline at end of file diff --git a/BJC-Utils2/src/main/java/bjc/utils/ioutils/BlockReader.java b/BJC-Utils2/src/main/java/bjc/utils/ioutils/BlockReader.java deleted file mode 100644 index f019e09..0000000 --- a/BJC-Utils2/src/main/java/bjc/utils/ioutils/BlockReader.java +++ /dev/null @@ -1,68 +0,0 @@ -package bjc.utils.ioutils; - -import java.io.IOException; -import java.util.Iterator; -import java.util.function.Consumer; - -/** - * A source of blocks of characters, marked with line numbers as to block - * start/block end. - * - * @author bjculkin - * - */ -public interface BlockReader extends AutoCloseable, Iterator { - /** - * Check if this reader has an available block. - * - * @return Whether or not another block is available. - */ - boolean hasNextBlock(); - - /** - * Get the current block. - * - * @return The current block, or null if there is no current block. - */ - Block getBlock(); - - /** - * Move to the next block. - * - * @return Whether or not the next block was successfully read. - */ - boolean nextBlock(); - - /** - * Execute an action for each remaining block. - * - * @param action - * The action to execute for each block - */ - default void forEachBlock(Consumer action) { - while (hasNext()) { - action.accept(next()); - } - } - - /** - * Retrieve the number of blocks that have been read so far. - * - * @return The number of blocks read so far. - */ - int getBlockCount(); - - void close() throws IOException; - - @Override - default boolean hasNext() { - return hasNextBlock(); - } - - @Override - default Block next() { - nextBlock(); - - return getBlock(); - } -} \ No newline at end of file diff --git a/BJC-Utils2/src/main/java/bjc/utils/ioutils/BlockReaders.java b/BJC-Utils2/src/main/java/bjc/utils/ioutils/BlockReaders.java deleted file mode 100644 index 3d71f52..0000000 --- a/BJC-Utils2/src/main/java/bjc/utils/ioutils/BlockReaders.java +++ /dev/null @@ -1,81 +0,0 @@ -package bjc.utils.ioutils; - -import java.io.Reader; - -/** - * Utility methods for constructing instances of {@link BlockReader} - * - * @author bjculkin - * - */ -public class BlockReaders { - /** - * Create a new simple block reader that works off a regex. - * - * @param blockDelim - * The regex that separates blocks. - * - * @param source - * The reader to get blocks from. - * - * @return A configured simple reader. - */ - public static SimpleBlockReader simple(String blockDelim, Reader source) { - return new SimpleBlockReader(blockDelim, source); - } - - /** - * Create a new pushback block reader. - * - * @param src - * The block reader to read blocks from. - * - * @return A configured pushback reader. - */ - public static PushbackBlockReader pushback(BlockReader src) { - return new PushbackBlockReader(src); - } - - /** - * Create a new triggered block reader. - * - * @param source - * The block reader to read blocks from. - * - * @param action - * The action to execute before reading a block. - * - * @return A configured triggered block reader. - */ - public static BlockReader trigger(BlockReader source, Runnable action) { - return new TriggeredBlockReader(source, action); - } - - /** - * Create a new layered block reader. - * - * @param primary - * The first source to read blocks from. - * - * @param secondary - * The second source to read blocks from. - * - * @return A configured layered block reader. - */ - public static BlockReader layered(BlockReader primary, BlockReader secondary) { - return new LayeredBlockReader(primary, secondary); - } - - /** - * Create a new serial block reader. - * - * @param readers - * The readers to pull from, in the order to pull from - * them. - * - * @return A configured serial block reader. - */ - public static BlockReader serial(BlockReader... readers) { - return new SerialBlockReader(readers); - } -} \ No newline at end of file diff --git a/BJC-Utils2/src/main/java/bjc/utils/ioutils/LayeredBlockReader.java b/BJC-Utils2/src/main/java/bjc/utils/ioutils/LayeredBlockReader.java deleted file mode 100644 index ed7a1b9..0000000 --- a/BJC-Utils2/src/main/java/bjc/utils/ioutils/LayeredBlockReader.java +++ /dev/null @@ -1,70 +0,0 @@ -package bjc.utils.ioutils; - -import java.io.IOException; - -/** - * A block reader that supports draining all the blocks from one reading before - * swapping to another. - * - * This is more a 'prioritize blocks from one over the other', than a 'read all - * the blocks from one, then all the blocks from the other'. If you need that, - * look at {@link SerialBlockReader}. - * - * @author bjculkin - * - */ -public class LayeredBlockReader implements BlockReader { - private BlockReader first; - private BlockReader second; - - private int blockNo; - - /** - * Create a new layered block reader. - * - * @param primary - * The first source to read blocks from. - * - * @param secondary - * The second source to read blocks from. - */ - public LayeredBlockReader(BlockReader primary, BlockReader secondary) { - first = primary; - second = secondary; - } - - @Override - public boolean hasNextBlock() { - return first.hasNextBlock() || second.hasNextBlock(); - } - - @Override - public Block getBlock() { - Block firstBlock = first.getBlock(); - - return firstBlock == null ? second.getBlock() : firstBlock; - } - - @Override - public boolean nextBlock() { - boolean gotFirst = first.nextBlock(); - - boolean succ = gotFirst ? gotFirst : second.nextBlock(); - - if (succ) blockNo += 1; - - return succ; - } - - @Override - public int getBlockCount() { - return blockNo; - } - - @Override - public void close() throws IOException { - second.close(); - - first.close(); - } -} \ No newline at end of file diff --git a/BJC-Utils2/src/main/java/bjc/utils/ioutils/Prompter.java b/BJC-Utils2/src/main/java/bjc/utils/ioutils/Prompter.java index ac6e558..eed53ae 100644 --- a/BJC-Utils2/src/main/java/bjc/utils/ioutils/Prompter.java +++ b/BJC-Utils2/src/main/java/bjc/utils/ioutils/Prompter.java @@ -1,5 +1,7 @@ package bjc.utils.ioutils; +import bjc.utils.ioutils.blocks.TriggeredBlockReader; + import java.io.PrintStream; /** diff --git a/BJC-Utils2/src/main/java/bjc/utils/ioutils/PushbackBlockReader.java b/BJC-Utils2/src/main/java/bjc/utils/ioutils/PushbackBlockReader.java deleted file mode 100644 index d67e01a..0000000 --- a/BJC-Utils2/src/main/java/bjc/utils/ioutils/PushbackBlockReader.java +++ /dev/null @@ -1,98 +0,0 @@ -package bjc.utils.ioutils; - -import java.io.IOException; -import java.util.Deque; -import java.util.LinkedList; - -/** - * A block reader that supports pushing blocks onto the input queue so that they - * are provided before blocks read from an input source. - * - * @author bjculkin - * - */ -public class PushbackBlockReader implements BlockReader { - private BlockReader source; - - private Deque waiting; - - private Block curBlock; - - private int blockNo; - - /** - * Create a new pushback block reader. - * - * @param src - * The block reader to use when no blocks are queued. - */ - public PushbackBlockReader(BlockReader src) { - source = src; - - waiting = new LinkedList<>(); - } - - @Override - public boolean hasNextBlock() { - return !waiting.isEmpty() || source.hasNextBlock(); - } - - @Override - public Block getBlock() { - return curBlock; - } - - @Override - public boolean nextBlock() { - if (!waiting.isEmpty()) { - curBlock = waiting.pop(); - - blockNo += 1; - - return true; - } else { - boolean succ = source.nextBlock(); - curBlock = source.getBlock(); - - if (succ) blockNo += 1; - - return succ; - } - } - - @Override - public int getBlockCount() { - return blockNo; - } - - @Override - public void close() throws IOException { - source.close(); - } - - /** - * Insert a block at the back of the queue of pending blocks. - * - * @param blk - * The block to put at the back. - */ - public void addBlock(Block blk) { - waiting.add(blk); - } - - /** - * Insert a block at the front of the queue of pending blocks. - * - * @param blk - * The block to put at the front. - */ - public void pushBlock(Block blk) { - waiting.push(blk); - } - - @Override - public String toString() { - return String.format("PushbackBlockReader [waiting=%s, curBlock=%s, blockNo=%s]", waiting, curBlock, - blockNo); - } -} \ No newline at end of file diff --git a/BJC-Utils2/src/main/java/bjc/utils/ioutils/SerialBlockReader.java b/BJC-Utils2/src/main/java/bjc/utils/ioutils/SerialBlockReader.java deleted file mode 100644 index 0ae969d..0000000 --- a/BJC-Utils2/src/main/java/bjc/utils/ioutils/SerialBlockReader.java +++ /dev/null @@ -1,98 +0,0 @@ -package bjc.utils.ioutils; - -import java.io.IOException; -import java.util.Deque; - -/** - * Provides a means of concatenating two block readers. - * - * @author bjculkin - * - */ -public class SerialBlockReader implements BlockReader { - private Deque readerQueue; - - private int blockNo; - - /** - * Create a new serial block reader. - * - * @param readers - * The readers to pull from, in the order to pull from - * them. - */ - public SerialBlockReader(BlockReader... readers) { - for (BlockReader reader : readers) { - readerQueue.add(reader); - } - } - - @Override - public boolean hasNextBlock() { - if (readerQueue.isEmpty()) return false; - - boolean hasBlock = readerQueue.peek().hasNextBlock(); - - boolean cont = hasBlock || readerQueue.isEmpty(); - - while (!cont) { - try { - readerQueue.pop().close(); - } catch (IOException ioex) { - throw new IllegalStateException("Exception thrown by discarded reader", ioex); - } - - hasBlock = readerQueue.peek().hasNextBlock(); - - cont = hasBlock || readerQueue.isEmpty(); - } - - return hasBlock; - } - - @Override - public Block getBlock() { - if (readerQueue.isEmpty()) - return null; - else return readerQueue.peek().getBlock(); - } - - @Override - public boolean nextBlock() { - if (readerQueue.isEmpty()) return false; - - boolean gotBlock = readerQueue.peek().nextBlock(); - - boolean cont = gotBlock || readerQueue.isEmpty(); - - while (!cont) { - try { - readerQueue.pop().close(); - } catch (IOException ioex) { - throw new IllegalStateException("Exception thrown by discarded reader", ioex); - } - - gotBlock = readerQueue.peek().nextBlock(); - - cont = gotBlock || readerQueue.isEmpty(); - } - - if (cont) blockNo += 1; - - return cont; - } - - @Override - public int getBlockCount() { - return blockNo; - } - - @Override - public void close() throws IOException { - while (!readerQueue.isEmpty()) { - BlockReader reader = readerQueue.pop(); - - reader.close(); - } - } -} \ No newline at end of file diff --git a/BJC-Utils2/src/main/java/bjc/utils/ioutils/SimpleBlockReader.java b/BJC-Utils2/src/main/java/bjc/utils/ioutils/SimpleBlockReader.java deleted file mode 100644 index 6b868bb..0000000 --- a/BJC-Utils2/src/main/java/bjc/utils/ioutils/SimpleBlockReader.java +++ /dev/null @@ -1,107 +0,0 @@ -package bjc.utils.ioutils; - -import java.io.IOException; -import java.io.LineNumberReader; -import java.io.Reader; -import java.util.NoSuchElementException; -import java.util.Scanner; -import java.util.regex.Pattern; - -/** - * Simple implementation of {@link BlockReader} - * - * NOTE: The EOF marker is always treated as a delimiter. You are expected to - * handle blocks that may be shorter than you expect. - * - * @author EVE - * - */ -public class SimpleBlockReader implements BlockReader { - /* - * I/O source for blocks. - */ - private LineNumberReader lnReader; - private Scanner blockReader; - - /* - * The current block. - */ - private Block currBlock; - private int blockNo; - - /** - * Create a new block reader. - * - * @param blockDelim - * The pattern that separates blocks. Note that the end - * of file is always considered to end a block. - * - * @param source - * The source to read blocks from. - */ - public SimpleBlockReader(String blockDelim, Reader source) { - lnReader = new LineNumberReader(source); - - blockReader = new Scanner(lnReader); - - String pattern = String.format("(?:%s)|\\Z", blockDelim); - Pattern pt = Pattern.compile(pattern, Pattern.MULTILINE); - - blockReader.useDelimiter(pt); - } - - @Override - public boolean hasNextBlock() { - return blockReader.hasNext(); - } - - @Override - public Block getBlock() { - return currBlock; - } - - @Override - public boolean nextBlock() { - try { - int blockStartLine = lnReader.getLineNumber(); - String blockContents = blockReader.next(); - int blockEndLine = lnReader.getLineNumber(); - blockNo += 1; - - currBlock = new Block(blockNo, blockContents, blockStartLine, blockEndLine); - - return true; - } catch (NoSuchElementException nseex) { - currBlock = null; - - return false; - } - } - - @Override - public int getBlockCount() { - return blockNo; - } - - @Override - public void close() throws IOException { - blockReader.close(); - - lnReader.close(); - } - - /** - * Set the delimiter used to separate blocks. - * - * @param delim - * The delimiter used to separate blocks. - */ - public void setDelimiter(String delim) { - blockReader.useDelimiter(delim); - } - - @Override - public String toString() { - return String.format("SimpleBlockReader [currBlock=%s, blockNo=%s]", currBlock, blockNo); - } -} diff --git a/BJC-Utils2/src/main/java/bjc/utils/ioutils/TriggeredBlockReader.java b/BJC-Utils2/src/main/java/bjc/utils/ioutils/TriggeredBlockReader.java deleted file mode 100644 index dd89223..0000000 --- a/BJC-Utils2/src/main/java/bjc/utils/ioutils/TriggeredBlockReader.java +++ /dev/null @@ -1,62 +0,0 @@ -package bjc.utils.ioutils; - -import java.io.IOException; - -/** - * A block reader that fires an action before a block is actually read. - * - * @author bjculkin - * - */ -public class TriggeredBlockReader implements BlockReader { - private BlockReader source; - - private Runnable action; - - /** - * Create a new triggered reader with the specified source/action. - * - * @param source - * The block reader to read blocks from. - * - * @param action - * The action to execute before reading a block. - */ - public TriggeredBlockReader(BlockReader source, Runnable action) { - super(); - this.source = source; - this.action = action; - } - - @Override - public boolean hasNextBlock() { - action.run(); - - return source.hasNextBlock(); - } - - @Override - public Block getBlock() { - return source.getBlock(); - } - - @Override - public boolean nextBlock() { - return source.nextBlock(); - } - - @Override - public int getBlockCount() { - return source.getBlockCount(); - } - - @Override - public void close() throws IOException { - source.close(); - } - - @Override - public String toString() { - return String.format("TriggeredBlockReader [source=%s]", source); - } -} \ No newline at end of file diff --git a/BJC-Utils2/src/main/java/bjc/utils/ioutils/blocks/Block.java b/BJC-Utils2/src/main/java/bjc/utils/ioutils/blocks/Block.java new file mode 100644 index 0000000..e92644e --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/ioutils/blocks/Block.java @@ -0,0 +1,87 @@ +package bjc.utils.ioutils.blocks; + +/** + * Represents a block of text read in from a source. + * + * @author EVE + * + */ +public class Block { + /** + * The contents of this block. + */ + public final String contents; + + /** + * The line of the source this block started on. + */ + public final int startLine; + + /** + * The line of the source this block ended on. + */ + public final int endLine; + + /** + * The number of this block. + */ + public final int blockNo; + + /** + * Create a new block. + * + * @param blockNo + * The number of this block. + * @param contents + * The contents of this block. + * @param startLine + * The line this block started on. + * @param endLine + * The line this block ended. + */ + public Block(int blockNo, String contents, int startLine, int endLine) { + this.contents = contents; + this.startLine = startLine; + this.endLine = endLine; + this.blockNo = blockNo; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + + result = prime * result + blockNo; + result = prime * result + ((contents == null) ? 0 : contents.hashCode()); + result = prime * result + endLine; + result = prime * result + startLine; + + return result; + } + + @Override + public boolean equals(Object obj) { + if(this == obj) return true; + if(obj == null) return false; + if(!(obj instanceof Block)) return false; + + Block other = (Block) obj; + + if(blockNo != other.blockNo) return false; + + if(contents == null) { + if(other.contents != null) return false; + } else if(!contents.equals(other.contents)) return false; + + if(endLine != other.endLine) return false; + if(startLine != other.startLine) return false; + + return true; + } + + @Override + public String toString() { + return String.format("Block #%d (from lines %d to %d), length: %d characters", blockNo, startLine, + endLine, contents.length()); + } +} \ No newline at end of file diff --git a/BJC-Utils2/src/main/java/bjc/utils/ioutils/blocks/BlockReader.java b/BJC-Utils2/src/main/java/bjc/utils/ioutils/blocks/BlockReader.java new file mode 100644 index 0000000..d45a4f3 --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/ioutils/blocks/BlockReader.java @@ -0,0 +1,68 @@ +package bjc.utils.ioutils.blocks; + +import java.io.IOException; +import java.util.Iterator; +import java.util.function.Consumer; + +/** + * A source of blocks of characters, marked with line numbers as to block + * start/block end. + * + * @author bjculkin + * + */ +public interface BlockReader extends AutoCloseable, Iterator { + /** + * Check if this reader has an available block. + * + * @return Whether or not another block is available. + */ + boolean hasNextBlock(); + + /** + * Get the current block. + * + * @return The current block, or null if there is no current block. + */ + Block getBlock(); + + /** + * Move to the next block. + * + * @return Whether or not the next block was successfully read. + */ + boolean nextBlock(); + + /** + * Execute an action for each remaining block. + * + * @param action + * The action to execute for each block + */ + default void forEachBlock(Consumer action) { + while (hasNext()) { + action.accept(next()); + } + } + + /** + * Retrieve the number of blocks that have been read so far. + * + * @return The number of blocks read so far. + */ + int getBlockCount(); + + void close() throws IOException; + + @Override + default boolean hasNext() { + return hasNextBlock(); + } + + @Override + default Block next() { + nextBlock(); + + return getBlock(); + } +} \ No newline at end of file diff --git a/BJC-Utils2/src/main/java/bjc/utils/ioutils/blocks/BlockReaders.java b/BJC-Utils2/src/main/java/bjc/utils/ioutils/blocks/BlockReaders.java new file mode 100644 index 0000000..ca82b51 --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/ioutils/blocks/BlockReaders.java @@ -0,0 +1,81 @@ +package bjc.utils.ioutils.blocks; + +import java.io.Reader; + +/** + * Utility methods for constructing instances of {@link BlockReader} + * + * @author bjculkin + * + */ +public class BlockReaders { + /** + * Create a new simple block reader that works off a regex. + * + * @param blockDelim + * The regex that separates blocks. + * + * @param source + * The reader to get blocks from. + * + * @return A configured simple reader. + */ + public static SimpleBlockReader simple(String blockDelim, Reader source) { + return new SimpleBlockReader(blockDelim, source); + } + + /** + * Create a new pushback block reader. + * + * @param src + * The block reader to read blocks from. + * + * @return A configured pushback reader. + */ + public static PushbackBlockReader pushback(BlockReader src) { + return new PushbackBlockReader(src); + } + + /** + * Create a new triggered block reader. + * + * @param source + * The block reader to read blocks from. + * + * @param action + * The action to execute before reading a block. + * + * @return A configured triggered block reader. + */ + public static BlockReader trigger(BlockReader source, Runnable action) { + return new TriggeredBlockReader(source, action); + } + + /** + * Create a new layered block reader. + * + * @param primary + * The first source to read blocks from. + * + * @param secondary + * The second source to read blocks from. + * + * @return A configured layered block reader. + */ + public static BlockReader layered(BlockReader primary, BlockReader secondary) { + return new LayeredBlockReader(primary, secondary); + } + + /** + * Create a new serial block reader. + * + * @param readers + * The readers to pull from, in the order to pull from + * them. + * + * @return A configured serial block reader. + */ + public static BlockReader serial(BlockReader... readers) { + return new SerialBlockReader(readers); + } +} \ No newline at end of file diff --git a/BJC-Utils2/src/main/java/bjc/utils/ioutils/blocks/LayeredBlockReader.java b/BJC-Utils2/src/main/java/bjc/utils/ioutils/blocks/LayeredBlockReader.java new file mode 100644 index 0000000..9ece6df --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/ioutils/blocks/LayeredBlockReader.java @@ -0,0 +1,70 @@ +package bjc.utils.ioutils.blocks; + +import java.io.IOException; + +/** + * A block reader that supports draining all the blocks from one reading before + * swapping to another. + * + * This is more a 'prioritize blocks from one over the other', than a 'read all + * the blocks from one, then all the blocks from the other'. If you need that, + * look at {@link SerialBlockReader}. + * + * @author bjculkin + * + */ +public class LayeredBlockReader implements BlockReader { + private BlockReader first; + private BlockReader second; + + private int blockNo; + + /** + * Create a new layered block reader. + * + * @param primary + * The first source to read blocks from. + * + * @param secondary + * The second source to read blocks from. + */ + public LayeredBlockReader(BlockReader primary, BlockReader secondary) { + first = primary; + second = secondary; + } + + @Override + public boolean hasNextBlock() { + return first.hasNextBlock() || second.hasNextBlock(); + } + + @Override + public Block getBlock() { + Block firstBlock = first.getBlock(); + + return firstBlock == null ? second.getBlock() : firstBlock; + } + + @Override + public boolean nextBlock() { + boolean gotFirst = first.nextBlock(); + + boolean succ = gotFirst ? gotFirst : second.nextBlock(); + + if (succ) blockNo += 1; + + return succ; + } + + @Override + public int getBlockCount() { + return blockNo; + } + + @Override + public void close() throws IOException { + second.close(); + + first.close(); + } +} \ No newline at end of file diff --git a/BJC-Utils2/src/main/java/bjc/utils/ioutils/blocks/PushbackBlockReader.java b/BJC-Utils2/src/main/java/bjc/utils/ioutils/blocks/PushbackBlockReader.java new file mode 100644 index 0000000..96906ae --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/ioutils/blocks/PushbackBlockReader.java @@ -0,0 +1,98 @@ +package bjc.utils.ioutils.blocks; + +import java.io.IOException; +import java.util.Deque; +import java.util.LinkedList; + +/** + * A block reader that supports pushing blocks onto the input queue so that they + * are provided before blocks read from an input source. + * + * @author bjculkin + * + */ +public class PushbackBlockReader implements BlockReader { + private BlockReader source; + + private Deque waiting; + + private Block curBlock; + + private int blockNo; + + /** + * Create a new pushback block reader. + * + * @param src + * The block reader to use when no blocks are queued. + */ + public PushbackBlockReader(BlockReader src) { + source = src; + + waiting = new LinkedList<>(); + } + + @Override + public boolean hasNextBlock() { + return !waiting.isEmpty() || source.hasNextBlock(); + } + + @Override + public Block getBlock() { + return curBlock; + } + + @Override + public boolean nextBlock() { + if (!waiting.isEmpty()) { + curBlock = waiting.pop(); + + blockNo += 1; + + return true; + } else { + boolean succ = source.nextBlock(); + curBlock = source.getBlock(); + + if (succ) blockNo += 1; + + return succ; + } + } + + @Override + public int getBlockCount() { + return blockNo; + } + + @Override + public void close() throws IOException { + source.close(); + } + + /** + * Insert a block at the back of the queue of pending blocks. + * + * @param blk + * The block to put at the back. + */ + public void addBlock(Block blk) { + waiting.add(blk); + } + + /** + * Insert a block at the front of the queue of pending blocks. + * + * @param blk + * The block to put at the front. + */ + public void pushBlock(Block blk) { + waiting.push(blk); + } + + @Override + public String toString() { + return String.format("PushbackBlockReader [waiting=%s, curBlock=%s, blockNo=%s]", waiting, curBlock, + blockNo); + } +} \ No newline at end of file diff --git a/BJC-Utils2/src/main/java/bjc/utils/ioutils/blocks/SerialBlockReader.java b/BJC-Utils2/src/main/java/bjc/utils/ioutils/blocks/SerialBlockReader.java new file mode 100644 index 0000000..2363468 --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/ioutils/blocks/SerialBlockReader.java @@ -0,0 +1,98 @@ +package bjc.utils.ioutils.blocks; + +import java.io.IOException; +import java.util.Deque; + +/** + * Provides a means of concatenating two block readers. + * + * @author bjculkin + * + */ +public class SerialBlockReader implements BlockReader { + private Deque readerQueue; + + private int blockNo; + + /** + * Create a new serial block reader. + * + * @param readers + * The readers to pull from, in the order to pull from + * them. + */ + public SerialBlockReader(BlockReader... readers) { + for (BlockReader reader : readers) { + readerQueue.add(reader); + } + } + + @Override + public boolean hasNextBlock() { + if (readerQueue.isEmpty()) return false; + + boolean hasBlock = readerQueue.peek().hasNextBlock(); + + boolean cont = hasBlock || readerQueue.isEmpty(); + + while (!cont) { + try { + readerQueue.pop().close(); + } catch (IOException ioex) { + throw new IllegalStateException("Exception thrown by discarded reader", ioex); + } + + hasBlock = readerQueue.peek().hasNextBlock(); + + cont = hasBlock || readerQueue.isEmpty(); + } + + return hasBlock; + } + + @Override + public Block getBlock() { + if (readerQueue.isEmpty()) + return null; + else return readerQueue.peek().getBlock(); + } + + @Override + public boolean nextBlock() { + if (readerQueue.isEmpty()) return false; + + boolean gotBlock = readerQueue.peek().nextBlock(); + + boolean cont = gotBlock || readerQueue.isEmpty(); + + while (!cont) { + try { + readerQueue.pop().close(); + } catch (IOException ioex) { + throw new IllegalStateException("Exception thrown by discarded reader", ioex); + } + + gotBlock = readerQueue.peek().nextBlock(); + + cont = gotBlock || readerQueue.isEmpty(); + } + + if (cont) blockNo += 1; + + return cont; + } + + @Override + public int getBlockCount() { + return blockNo; + } + + @Override + public void close() throws IOException { + while (!readerQueue.isEmpty()) { + BlockReader reader = readerQueue.pop(); + + reader.close(); + } + } +} \ No newline at end of file diff --git a/BJC-Utils2/src/main/java/bjc/utils/ioutils/blocks/SimpleBlockReader.java b/BJC-Utils2/src/main/java/bjc/utils/ioutils/blocks/SimpleBlockReader.java new file mode 100644 index 0000000..6ee1d57 --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/ioutils/blocks/SimpleBlockReader.java @@ -0,0 +1,107 @@ +package bjc.utils.ioutils.blocks; + +import java.io.IOException; +import java.io.LineNumberReader; +import java.io.Reader; +import java.util.NoSuchElementException; +import java.util.Scanner; +import java.util.regex.Pattern; + +/** + * Simple implementation of {@link BlockReader} + * + * NOTE: The EOF marker is always treated as a delimiter. You are expected to + * handle blocks that may be shorter than you expect. + * + * @author EVE + * + */ +public class SimpleBlockReader implements BlockReader { + /* + * I/O source for blocks. + */ + private LineNumberReader lnReader; + private Scanner blockReader; + + /* + * The current block. + */ + private Block currBlock; + private int blockNo; + + /** + * Create a new block reader. + * + * @param blockDelim + * The pattern that separates blocks. Note that the end + * of file is always considered to end a block. + * + * @param source + * The source to read blocks from. + */ + public SimpleBlockReader(String blockDelim, Reader source) { + lnReader = new LineNumberReader(source); + + blockReader = new Scanner(lnReader); + + String pattern = String.format("(?:%s)|\\Z", blockDelim); + Pattern pt = Pattern.compile(pattern, Pattern.MULTILINE); + + blockReader.useDelimiter(pt); + } + + @Override + public boolean hasNextBlock() { + return blockReader.hasNext(); + } + + @Override + public Block getBlock() { + return currBlock; + } + + @Override + public boolean nextBlock() { + try { + int blockStartLine = lnReader.getLineNumber(); + String blockContents = blockReader.next(); + int blockEndLine = lnReader.getLineNumber(); + blockNo += 1; + + currBlock = new Block(blockNo, blockContents, blockStartLine, blockEndLine); + + return true; + } catch (NoSuchElementException nseex) { + currBlock = null; + + return false; + } + } + + @Override + public int getBlockCount() { + return blockNo; + } + + @Override + public void close() throws IOException { + blockReader.close(); + + lnReader.close(); + } + + /** + * Set the delimiter used to separate blocks. + * + * @param delim + * The delimiter used to separate blocks. + */ + public void setDelimiter(String delim) { + blockReader.useDelimiter(delim); + } + + @Override + public String toString() { + return String.format("SimpleBlockReader [currBlock=%s, blockNo=%s]", currBlock, blockNo); + } +} diff --git a/BJC-Utils2/src/main/java/bjc/utils/ioutils/blocks/TriggeredBlockReader.java b/BJC-Utils2/src/main/java/bjc/utils/ioutils/blocks/TriggeredBlockReader.java new file mode 100644 index 0000000..cfe72c2 --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/ioutils/blocks/TriggeredBlockReader.java @@ -0,0 +1,62 @@ +package bjc.utils.ioutils.blocks; + +import java.io.IOException; + +/** + * A block reader that fires an action before a block is actually read. + * + * @author bjculkin + * + */ +public class TriggeredBlockReader implements BlockReader { + private BlockReader source; + + private Runnable action; + + /** + * Create a new triggered reader with the specified source/action. + * + * @param source + * The block reader to read blocks from. + * + * @param action + * The action to execute before reading a block. + */ + public TriggeredBlockReader(BlockReader source, Runnable action) { + super(); + this.source = source; + this.action = action; + } + + @Override + public boolean hasNextBlock() { + action.run(); + + return source.hasNextBlock(); + } + + @Override + public Block getBlock() { + return source.getBlock(); + } + + @Override + public boolean nextBlock() { + return source.nextBlock(); + } + + @Override + public int getBlockCount() { + return source.getBlockCount(); + } + + @Override + public void close() throws IOException { + source.close(); + } + + @Override + public String toString() { + return String.format("TriggeredBlockReader [source=%s]", source); + } +} \ No newline at end of file -- cgit v1.2.3