summaryrefslogtreecommitdiff
path: root/BJC-Utils2/src/main/java/bjc
diff options
context:
space:
mode:
Diffstat (limited to 'BJC-Utils2/src/main/java/bjc')
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/ioutils/BlockReader.java115
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/ioutils/PushbackBlockReader.java98
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/ioutils/SimpleBlockReader.java105
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/ioutils/TriggeredBlockReader.java62
4 files changed, 282 insertions, 98 deletions
diff --git a/BJC-Utils2/src/main/java/bjc/utils/ioutils/BlockReader.java b/BJC-Utils2/src/main/java/bjc/utils/ioutils/BlockReader.java
index fed74fe..f019e09 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/ioutils/BlockReader.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/ioutils/BlockReader.java
@@ -1,95 +1,37 @@
package bjc.utils.ioutils;
-import java.io.LineNumberReader;
-import java.io.Reader;
+import java.io.IOException;
import java.util.Iterator;
-import java.util.NoSuchElementException;
-import java.util.Scanner;
import java.util.function.Consumer;
-import java.util.regex.Pattern;
/**
- * Implements reading numbered blocks from a source.
+ * A source of blocks of characters, marked with line numbers as to block
+ * start/block end.
*
- * A block is a series of characters, separated by some regular expression.
- *
- * 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
+ * @author bjculkin
*
*/
-public class BlockReader implements AutoCloseable, Iterator<Block> {
- /*
- * 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 BlockReader(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);
- }
-
+public interface BlockReader extends AutoCloseable, Iterator<Block> {
/**
* Check if this reader has an available block.
*
* @return Whether or not another block is available.
*/
- public boolean hasNextBlock() {
- return blockReader.hasNext();
- }
+ boolean hasNextBlock();
/**
* Get the current block.
*
* @return The current block, or null if there is no current block.
*/
- public Block getBlock() {
- return currBlock;
- }
+ Block getBlock();
/**
* Move to the next block.
*
* @return Whether or not the next block was successfully read.
*/
- 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) {
- return false;
- }
- }
+ boolean nextBlock();
/**
* Execute an action for each remaining block.
@@ -97,11 +39,9 @@ public class BlockReader implements AutoCloseable, Iterator<Block> {
* @param action
* The action to execute for each block
*/
- public void forEachBlock(Consumer<Block> action) {
- while (hasNextBlock()) {
- nextBlock();
-
- action.accept(currBlock);
+ default void forEachBlock(Consumer<Block> action) {
+ while (hasNext()) {
+ action.accept(next());
}
}
@@ -110,40 +50,19 @@ public class BlockReader implements AutoCloseable, Iterator<Block> {
*
* @return The number of blocks read so far.
*/
- public int getBlockCount() {
- return blockNo;
- }
-
- @Override
- public void close() throws Exception {
- 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);
- }
+ int getBlockCount();
- /*
- * Iterator implementation.
- */
+ void close() throws IOException;
@Override
- public boolean hasNext() {
- return blockReader.hasNext();
+ default boolean hasNext() {
+ return hasNextBlock();
}
@Override
- public Block next() {
+ default Block next() {
nextBlock();
return getBlock();
}
-}
+} \ No newline at end of file
diff --git a/BJC-Utils2/src/main/java/bjc/utils/ioutils/PushbackBlockReader.java b/BJC-Utils2/src/main/java/bjc/utils/ioutils/PushbackBlockReader.java
new file mode 100644
index 0000000..d67e01a
--- /dev/null
+++ b/BJC-Utils2/src/main/java/bjc/utils/ioutils/PushbackBlockReader.java
@@ -0,0 +1,98 @@
+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<Block> 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/SimpleBlockReader.java b/BJC-Utils2/src/main/java/bjc/utils/ioutils/SimpleBlockReader.java
new file mode 100644
index 0000000..329effc
--- /dev/null
+++ b/BJC-Utils2/src/main/java/bjc/utils/ioutils/SimpleBlockReader.java
@@ -0,0 +1,105 @@
+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) {
+ 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
new file mode 100644
index 0000000..dd89223
--- /dev/null
+++ b/BJC-Utils2/src/main/java/bjc/utils/ioutils/TriggeredBlockReader.java
@@ -0,0 +1,62 @@
+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