From bf9737ae3c61c638dca3a40ca847e784ddd750f3 Mon Sep 17 00:00:00 2001 From: bculkin2442 Date: Sat, 13 Oct 2018 15:40:10 -0400 Subject: Pull out levelSplit/levelContains levelSplit/levelContains from the StringUtils class are now instead in the new LevelSplitter class in ioutils. This is so that new features of varying sorts can be added to those functions without cluttering up StringUtils. --- .../main/java/bjc/utils/funcutils/StringUtils.java | 217 +---------------- .../main/java/bjc/utils/ioutils/LevelSplitter.java | 260 +++++++++++++++++++++ 2 files changed, 261 insertions(+), 216 deletions(-) create mode 100644 base/src/main/java/bjc/utils/ioutils/LevelSplitter.java diff --git a/base/src/main/java/bjc/utils/funcutils/StringUtils.java b/base/src/main/java/bjc/utils/funcutils/StringUtils.java index 8e75f79..e8558c7 100644 --- a/base/src/main/java/bjc/utils/funcutils/StringUtils.java +++ b/base/src/main/java/bjc/utils/funcutils/StringUtils.java @@ -7,6 +7,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import bjc.utils.data.BooleanToggle; +import bjc.utils.ioutils.LevelSplitter; import bjc.utils.parserutils.TokenUtils; import com.ibm.icu.text.BreakIterator; @@ -254,220 +255,4 @@ public class StringUtils { } return strings; } - - public static boolean levelContains(String haystack, String... needles) { - int nestLevel = 0; - int i = 0; - - boolean prevCharWasSlash = false; - boolean inString = false; - - char stringEnder = ' '; - - while(i < haystack.length()) { - if(inString == false && nestLevel == 0) { - for(String needle : needles) { - if(haystack.regionMatches(i, needle, 0, needle.length())) { - return true; - } - } - } - - if(inString) { - if(prevCharWasSlash == true) { - prevCharWasSlash = false; - } else if (haystack.charAt(i) == stringEnder) { - inString = false; - } - } else { - switch(haystack.charAt(i)) { - case '\'': - inString = true; - stringEnder = '\''; - break; - case '\"': - inString = true; - stringEnder = '\"'; - break; - case '(': - case '[': - case '{': - case '<': - nestLevel += 1; - break; - case ')': - case ']': - case '}': - case '>': - nestLevel = Math.max(0, nestLevel - 1); - break; - } - } - - i += 1; - } - - return false; - } - - public static List levelSplit(String phrase, String... splits) { - return levelSplit(phrase, false, splits); - } - - public static List levelSplit(String phrase, boolean keepDelims, String... splits) { - String work = phrase; - - List strangs = new ArrayList<>(); - - int nestLevel = 0; - int i = 0; - - boolean prevCharWasSlash = false; - boolean inString = false; - - char stringEnder = ' '; - - // Shortcut empty strings - if(phrase.equals("")) { - strangs.add(""); - - return strangs; - } - - while(i < work.length()) { - if(inString == false && nestLevel == 0) { - for(String split : splits) { - if(work.regionMatches(i, split, 0, split.length())) { - strangs.add(work.substring(0, i)); - - if(keepDelims) strangs.add(split); - - work = work.substring(i + split.length()); - i = 0; - - continue; - } - } - } - - if(inString) { - if(prevCharWasSlash == true) { - prevCharWasSlash = false; - } else if (work.charAt(i) == stringEnder) { - inString = false; - } - } else { - /* - * @TODO Ben Culkin 9/4/18 - * - * This currently crashes if the string ends - * with one of the delimiters in question. - */ - switch(work.charAt(i)) { - case '\'': - inString = true; - stringEnder = '\''; - break; - case '\"': - inString = true; - stringEnder = '\"'; - break; - case '(': - case '[': - case '{': - case '<': - nestLevel += 1; - break; - case ')': - case ']': - case '}': - case '>': - nestLevel = Math.max(0, nestLevel - 1); - break; - } - } - - i += 1; - } - - strangs.add(work); - - return strangs; - } - - public static List levelSplitRX(String phrase, String patt) { - return levelSplit(phrase, false, patt); - } - - // @TODO @FIXME - // - // This doesn't seem like its working - public static List levelSplitRX(String phrase, boolean keepDelims, String patt) { - Pattern pat = Pattern.compile(patt); - - String work = phrase; - Matcher mat = pat.matcher(work); - - List strangs = new ArrayList<>(); - - int nestLevel = 0; - int i = 0; - - boolean prevCharWasSlash = false; - boolean inString = false; - - char stringEnder = ' '; - - while(i < work.length()) { - if(inString == false && nestLevel == 0) { - if(mat.find(i)) { - strangs.add(work.substring(0, i)); - if(keepDelims) strangs.add(mat.group()); - work = work.substring(mat.end()); - i = 0; - - mat = pat.matcher(work); - - continue; - } - } - - if(inString) { - if(prevCharWasSlash == true) { - prevCharWasSlash = false; - } else if (work.charAt(i) == stringEnder) { - inString = false; - } - } else { - switch(work.charAt(i)) { - case '\'': - inString = true; - stringEnder = '\''; - break; - case '\"': - inString = true; - stringEnder = '\"'; - break; - case '(': - case '[': - case '{': - case '<': - nestLevel += 1; - break; - case ')': - case ']': - case '}': - case '>': - nestLevel = Math.max(0, nestLevel - 1); - break; - } - } - - i += 1; - } - - strangs.add(work); - - return strangs; - } } diff --git a/base/src/main/java/bjc/utils/ioutils/LevelSplitter.java b/base/src/main/java/bjc/utils/ioutils/LevelSplitter.java new file mode 100644 index 0000000..7de0e28 --- /dev/null +++ b/base/src/main/java/bjc/utils/ioutils/LevelSplitter.java @@ -0,0 +1,260 @@ +package bjc.utils.ioutils; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Splits a string on a delimiter, respecting grouping delimiters. + * + * By default, grouping delimiters are (), [], {}, and <>, as well as single and + * double quoted strings. + * + * @author bjculkin + * + */ +public class LevelSplitter { + /** + * Defaultly configured level splitter. + */ + public final static LevelSplitter def = new LevelSplitter(); + + /** + * Check if a string contains any one of a specified number of things, + * respecting groups. + * + * @param haystack + * The string to look in. + * @param needles + * The strings to look for. + * @return Whether or not any of the strings were contained outside of + * groups. + */ + public boolean levelContains(String haystack, String... needles) { + int nestLevel = 0; + int i = 0; + + boolean prevCharWasSlash = false; + boolean inString = false; + + char stringEnder = ' '; + + while (i < haystack.length()) { + if (inString == false && nestLevel == 0) { + for (String needle : needles) { + if (haystack.regionMatches(i, needle, 0, needle.length())) { + return true; + } + } + } + + if (inString) { + if (prevCharWasSlash == true) { + prevCharWasSlash = false; + } else if (haystack.charAt(i) == stringEnder) { + inString = false; + } + } else { + switch (haystack.charAt(i)) { + case '\'': + inString = true; + stringEnder = '\''; + break; + case '\"': + inString = true; + stringEnder = '\"'; + break; + case '(': + case '[': + case '{': + case '<': + nestLevel += 1; + break; + case ')': + case ']': + case '}': + case '>': + nestLevel = Math.max(0, nestLevel - 1); + break; + } + } + + i += 1; + } + + return false; + } + + /** + * Split a string, respecting groups. + * + * @param phrase + * The string to split. + * @param keepDelims + * Whether or not to include the delimiters in the + * results. + * @param splits + * The strings to split on. + * @return A list of split strings. If keepDelims is true, it also + * includes the delimiters in between the split strings. + */ + public List levelSplit(String phrase, boolean keepDelims, String... splits) { + String work = phrase; + + List strangs = new ArrayList<>(); + + int nestLevel = 0; + int i = 0; + + boolean prevCharWasSlash = false; + boolean inString = false; + + char stringEnder = ' '; + + // Shortcut empty strings + if (phrase.equals("")) { + strangs.add(""); + + return strangs; + } + + while (i < work.length()) { + if (inString == false && nestLevel == 0) { + for (String split : splits) { + if (work.regionMatches(i, split, 0, split.length())) { + strangs.add(work.substring(0, i)); + + if (keepDelims) strangs.add(split); + + work = work.substring(i + split.length()); + i = 0; + + continue; + } + } + } + + if (inString) { + if (prevCharWasSlash == true) { + prevCharWasSlash = false; + } else if (work.charAt(i) == stringEnder) { + inString = false; + } + } else { + /* + * @TODO Ben Culkin 9/4/18 + * + * This currently crashes if the string ends + * with one of the delimiters in question. + */ + switch (work.charAt(i)) { + case '\'': + inString = true; + stringEnder = '\''; + break; + case '\"': + inString = true; + stringEnder = '\"'; + break; + case '(': + case '[': + case '{': + case '<': + nestLevel += 1; + break; + case ')': + case ']': + case '}': + case '>': + nestLevel = Math.max(0, nestLevel - 1); + break; + } + } + + i += 1; + } + + strangs.add(work); + + return strangs; + } + + // @TODO @FIXME + // + // This doesn't seem like its working + @SuppressWarnings("javadoc") + public List levelSplitRX(String phrase, String patt) { + return levelSplit(phrase, false, patt); + } + + @SuppressWarnings("javadoc") + public List levelSplitRX(String phrase, boolean keepDelims, String patt) { + Pattern pat = Pattern.compile(patt); + + String work = phrase; + Matcher mat = pat.matcher(work); + + List strangs = new ArrayList<>(); + + int nestLevel = 0; + int i = 0; + + boolean prevCharWasSlash = false; + boolean inString = false; + + char stringEnder = ' '; + + while (i < work.length()) { + if (inString == false && nestLevel == 0) { + if (mat.find(i)) { + strangs.add(work.substring(0, i)); + if (keepDelims) strangs.add(mat.group()); + work = work.substring(mat.end()); + i = 0; + + mat = pat.matcher(work); + + continue; + } + } + + if (inString) { + if (prevCharWasSlash == true) { + prevCharWasSlash = false; + } else if (work.charAt(i) == stringEnder) { + inString = false; + } + } else { + switch (work.charAt(i)) { + case '\'': + inString = true; + stringEnder = '\''; + break; + case '\"': + inString = true; + stringEnder = '\"'; + break; + case '(': + case '[': + case '{': + case '<': + nestLevel += 1; + break; + case ')': + case ']': + case '}': + case '>': + nestLevel = Math.max(0, nestLevel - 1); + break; + } + } + + i += 1; + } + + strangs.add(work); + + return strangs; + } +} -- cgit v1.2.3 From 327c2a35bde7a13d77f343464e41e19e4a214790 Mon Sep 17 00:00:00 2001 From: bculkin2442 Date: Sat, 13 Oct 2018 15:51:53 -0400 Subject: General cleanup and documentation. Cleanup files, and add missing comments in places. --- .../main/java/bjc/utils/cli/objects/DefineCLI.java | 1 - .../bjc/utils/cli/objects/DelimSplitterCLI.java | 1 - .../components/MemoryComponentRepository.java | 25 +- base/src/main/java/bjc/utils/data/IPair.java | 67 ++--- .../main/java/bjc/utils/esodata/DefaultList.java | 38 ++- .../main/java/bjc/utils/esodata/DoubleSided.java | 6 + base/src/main/java/bjc/utils/esodata/MapSet.java | 81 +++++++ base/src/main/java/bjc/utils/esodata/Tape.java | 26 +- base/src/main/java/bjc/utils/funcdata/IList.java | 112 +++++---- .../main/java/bjc/utils/funcutils/ListUtils.java | 132 +++++----- .../main/java/bjc/utils/funcutils/SetUtils.java | 24 +- .../main/java/bjc/utils/funcutils/StringUtils.java | 1 - .../main/java/bjc/utils/gen/WeightedRandom.java | 113 +++++++-- base/src/main/java/bjc/utils/ioutils/MirrorDB.java | 25 +- .../main/java/bjc/utils/ioutils/ReportWriter.java | 270 ++++++++++++++++++--- .../main/java/bjc/utils/ioutils/blocks/Block.java | 61 ++--- .../splitter/ConfigurableTokenSplitter.java | 105 +++++--- .../parserutils/splitter/SimpleTokenSplitter.java | 2 +- .../bjc/utils/test/ioutils/ReportWriterTest.java | 4 +- .../bjc/utils/ioutils/format/CLParameters.java | 6 +- 20 files changed, 807 insertions(+), 293 deletions(-) diff --git a/base/src/main/java/bjc/utils/cli/objects/DefineCLI.java b/base/src/main/java/bjc/utils/cli/objects/DefineCLI.java index 3a03d18..108f90b 100644 --- a/base/src/main/java/bjc/utils/cli/objects/DefineCLI.java +++ b/base/src/main/java/bjc/utils/cli/objects/DefineCLI.java @@ -2,7 +2,6 @@ package bjc.utils.cli.objects; import bjc.utils.funcutils.StringUtils; -import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; diff --git a/base/src/main/java/bjc/utils/cli/objects/DelimSplitterCLI.java b/base/src/main/java/bjc/utils/cli/objects/DelimSplitterCLI.java index 8b27ab7..9bf6ee6 100644 --- a/base/src/main/java/bjc/utils/cli/objects/DelimSplitterCLI.java +++ b/base/src/main/java/bjc/utils/cli/objects/DelimSplitterCLI.java @@ -3,7 +3,6 @@ package bjc.utils.cli.objects; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; -import java.io.InputStream; import java.util.Arrays; import java.util.HashMap; import java.util.LinkedList; diff --git a/base/src/main/java/bjc/utils/components/MemoryComponentRepository.java b/base/src/main/java/bjc/utils/components/MemoryComponentRepository.java index 658aaa1..a4b8dda 100644 --- a/base/src/main/java/bjc/utils/components/MemoryComponentRepository.java +++ b/base/src/main/java/bjc/utils/components/MemoryComponentRepository.java @@ -2,21 +2,44 @@ package bjc.utils.components; import bjc.utils.funcdata.IMap; -public class MemoryComponentRepository implements IComponentRepository { +/** + * A repository of components stored in memory. + * + * @author bjculkin + * + * @param + */ +public class MemoryComponentRepository + implements IComponentRepository { private final IMap repo; private final String source; + /** + * Create a new memory component repository. + * + * @param repo + * The set of components to use. + */ public MemoryComponentRepository(IMap repo) { this(repo, "memory"); } + /** + * Create a new memory component repository. + * + * @param repo + * The set of components to use. + * @param source + * Where the components came from. + */ public MemoryComponentRepository(IMap repo, String source) { this.repo = repo; this.source = source; } + @Override public IMap getAll() { return repo; } diff --git a/base/src/main/java/bjc/utils/data/IPair.java b/base/src/main/java/bjc/utils/data/IPair.java index 907cf3d..886bf7c 100644 --- a/base/src/main/java/bjc/utils/data/IPair.java +++ b/base/src/main/java/bjc/utils/data/IPair.java @@ -12,10 +12,10 @@ import bjc.utils.funcdata.theory.Bifunctor; * @author ben * * @param - * The type of the left side of the pair. + * The type of the left side of the pair. * * @param - * The type of the right side of the pair. + * The type of the right side of the pair. * */ public interface IPair extends Bifunctor { @@ -23,13 +23,13 @@ public interface IPair extends Bifunctor - * The type of the bound left. + * The type of the bound left. * * @param - * The type of the bound right. + * The type of the bound right. * * @param binder - * The function to bind with. + * The function to bind with. * * @return The bound pair. */ @@ -40,10 +40,10 @@ public interface IPair extends Bifunctor - * The type of the bound value. + * The type of the bound value. * * @param leftBinder - * The function to use to bind. + * The function to use to bind. * * @return A pair with the left type bound. */ @@ -54,10 +54,10 @@ public interface IPair extends Bifunctor - * The type of the bound value. + * The type of the bound value. * * @param rightBinder - * The function to use to bind. + * The function to use to bind. * * @return A pair with the right type bound. */ @@ -68,13 +68,13 @@ public interface IPair extends Bifunctor - * The left type of the other pair. + * The left type of the other pair. * * @param - * The right type of the other pair. + * The right type of the other pair. * * @param otherPair - * The pair to combine with. + * The pair to combine with. * * @return The pairs, pairwise combined together. */ @@ -87,25 +87,25 @@ public interface IPair extends Bifunctor - * The type of the left value of the other pair. + * The type of the left value of the other pair. * * @param - * The type of the right value of the other pair. + * The type of the right value of the other pair. * * @param - * The type of the left value of the combined pair. + * The type of the left value of the combined pair. * * @param - * The type of the right value of the combined pair. + * The type of the right value of the combined pair. * * @param otherPair - * The other pair to combine with. + * The other pair to combine with. * * @param leftCombiner - * The function to combine the left values with. + * The function to combine the left values with. * * @param rightCombiner - * The function to combine the right values with. + * The function to combine the right values with. * * @return A pair with its values combined. */ @@ -119,7 +119,7 @@ public interface IPair extends Bifunctor consumer) { merge((leftValue, rightValue) -> { @@ -133,7 +133,7 @@ public interface IPair extends Bifunctor LeftBifunctorMap fmapLeft( final Function func) { return argumentPair -> { - if(!(argumentPair instanceof IPair)) { + if (!(argumentPair instanceof IPair)) { final String msg = "This function can only be applied to instances of IPair"; throw new IllegalArgumentException(msg); @@ -149,7 +149,7 @@ public interface IPair extends Bifunctor RightBifunctorMap fmapRight( final Function func) { return argumentPair -> { - if(!(argumentPair instanceof IPair)) { + if (!(argumentPair instanceof IPair)) { final String msg = "This function can only be applied to instances of IPair"; throw new IllegalArgumentException(msg); @@ -187,10 +187,11 @@ public interface IPair extends Bifunctor - * The new type of the left part of the pair. + * The new type of the left part of the pair. * * @param mapper - * The function to use to transform the left part of the pair. + * The function to use to transform the left part of the + * pair. * * @return The pair, with its left part transformed. */ @@ -202,10 +203,11 @@ public interface IPair extends Bifunctor - * The new type of the right part of the pair. + * The new type of the right part of the pair. * * @param mapper - * The function to use to transform the right part of the pair. + * The function to use to transform the right part of the + * pair. * * @return The pair, with its right part transformed. */ @@ -215,15 +217,24 @@ public interface IPair extends Bifunctor - * The type of the single value. + * The type of the single value. * * @param merger - * The function to use for merging. + * The function to use for merging. * * @return The pair, merged into a single value. */ public MergedType merge(BiFunction merger); + /** + * Static pair constructor. + * + * @param left + * The left side of the pair. + * @param right + * The right side of the pair. + * @return A pair, with the specified left/right side. + */ public static IPair pair(T1 left, T2 right) { return new Pair<>(left, right); } diff --git a/base/src/main/java/bjc/utils/esodata/DefaultList.java b/base/src/main/java/bjc/utils/esodata/DefaultList.java index 235a1a8..4d3d1dc 100644 --- a/base/src/main/java/bjc/utils/esodata/DefaultList.java +++ b/base/src/main/java/bjc/utils/esodata/DefaultList.java @@ -8,6 +8,8 @@ import java.util.List; * A list that has a default value that out-of-bounds accesses return. * * @author Ben Culkin + * @param + * The type of the values contained in the list. */ public class DefaultList extends AbstractList { /* @@ -20,33 +22,67 @@ public class DefaultList extends AbstractList { * bounds, but what are you going to do? */ - private ValueType defVal; private List backing; + /** + * Create a new DefaultList. + */ public DefaultList() { this(new ArrayList<>(), null); } + /** + * Create a new DefaultList, with a set default value. + * + * @param defVal + * The default value for the list. + */ public DefaultList(ValueType defVal) { this(new ArrayList<>(), defVal); } + /** + * Create a new DefaultList, with a specific backing list. + * + * @param backer + * The backing list to use. + * + */ public DefaultList(List backer) { this(backer, null); } + /** + * Create a new DefaultList, with a set default value. + * + * @param backer + * The backing list to use. + * + * @param defVal + * The default value for the list. + */ public DefaultList(List backer, ValueType defVal) { this.defVal = defVal; this.backing = backer; } + /** + * Get the default value. + * + * @return The default value. + */ public ValueType getDefault() { return defVal; } + /** + * Set the default value. + * + * @param defVal The default value. + */ public void setDefault(ValueType defVal) { this.defVal = defVal; } diff --git a/base/src/main/java/bjc/utils/esodata/DoubleSided.java b/base/src/main/java/bjc/utils/esodata/DoubleSided.java index 83b7c77..2c57332 100644 --- a/base/src/main/java/bjc/utils/esodata/DoubleSided.java +++ b/base/src/main/java/bjc/utils/esodata/DoubleSided.java @@ -1,5 +1,11 @@ package bjc.utils.esodata; +/** + * Interface for a double-sided object. + * + * @author bjculkin + * + */ public interface DoubleSided { /** * Flips the object. diff --git a/base/src/main/java/bjc/utils/esodata/MapSet.java b/base/src/main/java/bjc/utils/esodata/MapSet.java index 94d7700..16def9e 100644 --- a/base/src/main/java/bjc/utils/esodata/MapSet.java +++ b/base/src/main/java/bjc/utils/esodata/MapSet.java @@ -6,49 +6,115 @@ import java.util.HashMap; import java.util.Map; import java.util.Set; +/** + * A string-keyed set of maps. + * + * @author bjculkin + * + * @param + * The key type of the maps. + * @param + * The value type of the maps. + */ public class MapSet extends AbstractMap { private Map> backing; private Map currentMap = null; + /** + * Create a new set of maps. + */ public MapSet() { backing = new HashMap<>(); } + /** + * Create a new set of maps, with the specified set of maps. + * + * @param back + * The set of maps to use. + */ public MapSet(Map> back) { backing = back; } + /** + * Add a keyed map. + * + * @param key + * The key for the map. + * @param map + * The map itself. + */ public void addMap(String key, Map map) { backing.put(key, map); } + /** + * Clear out the contents of the set + */ public void clearMap() { currentMap = null; backing.clear(); } + /** + * Check if there is a map attached to the specified key. + * + * @param key + * The key to look for. + * @return Whether or not there is anything attached to the key. + */ public boolean containsMap(String key) { return backing.containsKey(key); } + /** + * Get the map attached to a specified key. + * + * @param key + * The key to look for. + * @return The map attached to the key. + */ public Map getMap(String key) { return backing.get(key); } + /** + * Get all of the backing entries. + * + * @return The backing entries. + */ public Set>> getMapEntries() { return backing.entrySet(); } + /** + * Get all of the keys. + * + * @return The keys currently in use. + */ public Set getMapKeys() { return backing.keySet(); } + /** + * Get all of the keyed maps. + * + * @return The keyed maps. + */ public Collection> getMapValues() { return backing.values(); } + /** + * Set the current map. + * + * @param key + * The key to use as the current map. + * @return False if there is no map attached to the key, true otherwise. + */ public boolean setMap(String key) { if (!backing.containsKey(key)) return false; @@ -57,6 +123,13 @@ public class MapSet extends AbstractMap return true; } + /** + * Sets the current map, or creates a new one if there isn't one + * attached to that key. + * + * @param key + * The key to use as the current map. + */ public void setCreateMap(String key) { if (!backing.containsKey(key)) { currentMap = new HashMap<>(); @@ -69,6 +142,14 @@ public class MapSet extends AbstractMap currentMap = backing.get(key); } + /** + * Set the current map, or bind a map to it. + * + * @param key + * The key to set or bind. + * @param map + * The map to bind to the key if it isn't present. + */ public void setPutMap(String key, Map map) { if (!backing.containsKey(key)) { currentMap = map; diff --git a/base/src/main/java/bjc/utils/esodata/Tape.java b/base/src/main/java/bjc/utils/esodata/Tape.java index 41b0ce7..0835f7e 100644 --- a/base/src/main/java/bjc/utils/esodata/Tape.java +++ b/base/src/main/java/bjc/utils/esodata/Tape.java @@ -8,7 +8,7 @@ package bjc.utils.esodata; * unbounded to the right, but in practice bounded by available memory. * * @param - * The element type of the tape. + * The element type of the tape. * * @author bjculkin */ @@ -24,7 +24,7 @@ public interface Tape { * Set the item the tape is currently on. * * @param itm - * The new value for the tape item. + * The new value for the tape item. */ void item(T itm); @@ -46,7 +46,7 @@ public interface Tape { * Insert an element before the current item. * * @param itm - * The item to add. + * The item to add. */ void insertBefore(T itm); @@ -54,7 +54,7 @@ public interface Tape { * Insert an element after the current item. * * @param itm - * The item to insert. + * The item to insert. */ void insertAfter(T itm); @@ -90,7 +90,7 @@ public interface Tape { * that would exceed zero don't move the cursor at all. * * @param amt - * The amount to attempt to move the cursor left. + * The amount to attempt to move the cursor left. * * @return True if the cursor was moved left. */ @@ -107,14 +107,28 @@ public interface Tape { * Move the cursor the specified amount right. * * @param amt - * The amount to move the cursor right by. + * The amount to move the cursor right by. * * @return Whether the cursor was moved right. */ boolean right(int amt); + /** + * Seek to an absolute position on the tape. + * + * @param pos + * The position to seek to. + * @return Whether or not the tape successfully seeked to that position. + */ boolean seekTo(int pos); + /** + * Check if this tape is at its end. + * + * Equivalent to checking if position() == size(). + * + * @return Whether or not the tape is at its end. + */ default boolean atEnd() { return position() == size(); } diff --git a/base/src/main/java/bjc/utils/funcdata/IList.java b/base/src/main/java/bjc/utils/funcdata/IList.java index 12eaf2f..c2f247b 100644 --- a/base/src/main/java/bjc/utils/funcdata/IList.java +++ b/base/src/main/java/bjc/utils/funcdata/IList.java @@ -18,14 +18,14 @@ import bjc.utils.functypes.ID; * @author ben * * @param - * The type in this list + * The type in this list */ public interface IList extends Iterable { /** * Add an item to this list. * * @param item - * The item to add to this list. + * The item to add to this list. * * @return Whether the item was added to the list successfully.. */ @@ -35,7 +35,7 @@ public interface IList extends Iterable { * Add all of the elements in the provided list to this list. * * @param items - * The list of items to add. + * The list of items to add. * * @return True if every item was successfully added to the list, false * otherwise. @@ -48,7 +48,7 @@ public interface IList extends Iterable { * Add all of the elements in the provided array to this list. * * @param items - * The array of items to add. + * The array of items to add. * * @return True if every item was successfully added to the list, false * otherwise. @@ -57,7 +57,7 @@ public interface IList extends Iterable { default boolean addAll(final ContainedType... items) { boolean succ = true; - for(final ContainedType item : items) { + for (final ContainedType item : items) { final boolean addSucc = add(item); succ = succ ? addSucc : false; @@ -71,7 +71,7 @@ public interface IList extends Iterable { * predicate. * * @param matcher - * The predicate to use for checking. + * The predicate to use for checking. * * @return Whether all of the elements of the list match the specified * predicate. @@ -82,7 +82,7 @@ public interface IList extends Iterable { * Check if any of the elements in this list match the specified list. * * @param matcher - * The predicate to use for checking. + * The predicate to use for checking. * * @return Whether any element in the list matches the provided * predicate. @@ -93,13 +93,13 @@ public interface IList extends Iterable { * Reduce the contents of this list using a collector. * * @param - * The intermediate accumulation type. + * The intermediate accumulation type. * * @param - * The final, reduced type. + * The final, reduced type. * * @param collector - * The collector to use for reduction. + * The collector to use for reduction. * * @return The reduced list. */ @@ -126,16 +126,16 @@ public interface IList extends Iterable { * list and the combined one. * * @param - * The type of the second list. + * The type of the second list. * * @param - * The type of the combined list. + * The type of the combined list. * * @param list - * The list to combine with. + * The list to combine with. * * @param combiner - * The function to use for combining element pairs. + * The function to use for combining element pairs. * * @return A new list containing the merged pairs of lists. */ @@ -146,7 +146,7 @@ public interface IList extends Iterable { * Check if the list contains the specified item. * * @param item - * The item to see if it is contained. + * The item to see if it is contained. * * @return Whether or not the specified item is in the list. */ @@ -166,7 +166,18 @@ public interface IList extends Iterable { */ ContainedType last(); + /** + * Remove and return the first element from the list. + * + * @return The first element from the list. + */ ContainedType popFirst(); + + /** + * Remove and return the last element from the list. + * + * @return The last element from the list. + */ ContainedType popLast(); /** @@ -176,10 +187,10 @@ public interface IList extends Iterable { * Does not change the underlying list. * * @param - * The type of the flattened list. + * The type of the flattened list. * * @param expander - * The function to apply to each member of the list. + * The function to apply to each member of the list. * * @return A new list containing the flattened results of applying the * provided function. @@ -190,7 +201,7 @@ public interface IList extends Iterable { * Apply a given action for each member of the list. * * @param action - * The action to apply to each member of the list. + * The action to apply to each member of the list. */ @Override void forEach(Consumer action); @@ -199,8 +210,8 @@ public interface IList extends Iterable { * Apply a given function to each element in the list and its index. * * @param action - * The function to apply to each element in the list and its - * index. + * The function to apply to each element in the list and + * its index. */ void forEachIndexed(BiConsumer action); @@ -208,7 +219,7 @@ public interface IList extends Iterable { * Retrieve a value in the list by its index. * * @param index - * The index to retrieve a value from. + * The index to retrieve a value from. * * @return The value at the specified index in the list. */ @@ -218,7 +229,7 @@ public interface IList extends Iterable { * Retrieve a list containing all elements matching a predicate. * * @param predicate - * The predicate to match by. + * The predicate to match by. * * @return A list containing all elements that match the predicate. */ @@ -245,10 +256,10 @@ public interface IList extends Iterable { * Does not change the underlying list. * * @param - * The type of the transformed list. + * The type of the transformed list. * * @param transformer - * The function to apply to each element in the list. + * The function to apply to each element in the list. * * @return A new list containing the mapped elements of this list. */ @@ -258,10 +269,10 @@ public interface IList extends Iterable { * Zip two lists into a list of pairs. * * @param - * The type of the second list. + * The type of the second list. * * @param list - * The list to use as the left side of the pair. + * The list to use as the left side of the pair. * * @return A list containing pairs of this element and the specified * list. @@ -272,7 +283,8 @@ public interface IList extends Iterable { * Partition this list into a list of sublists. * * @param partitionSize - * The size of elements to put into each one of the sublists. + * The size of elements to put into each one of the + * sublists. * * @return A list partitioned into partitions of size partitionSize. The * last partition may not be completely full if the size of the @@ -284,7 +296,7 @@ public interface IList extends Iterable { * Prepend an item to the list. * * @param item - * The item to prepend to the list. + * The item to prepend to the list. */ void prepend(ContainedType item); @@ -292,11 +304,11 @@ public interface IList extends Iterable { * Prepend an array of items to the list. * * @param items - * The items to prepend to the list. + * The items to prepend to the list. */ @SuppressWarnings("unchecked") default void prependAll(final ContainedType... items) { - for(final ContainedType item : items) { + for (final ContainedType item : items) { prepend(item); } } @@ -316,7 +328,7 @@ public interface IList extends Iterable { * generator. * * @param rnd - * The random number generator to use. + * The random number generator to use. * * @return A random element from this list. */ @@ -326,21 +338,21 @@ public interface IList extends Iterable { * Reduce this list to a single value, using a accumulative approach. * * @param - * The in-between type of the values + * The in-between type of the values * * @param - * The final value type + * The final value type * * @param initial - * The initial value of the accumulative state. + * The initial value of the accumulative state. * * @param accumulator - * The function to use to combine a list element with the - * accumulative state. + * The function to use to combine a list element with the + * accumulative state. * * @param transformer - * The function to use to convert the accumulative state into a - * final result. + * The function to use to convert the accumulative state + * into a final result. * * @return A single value condensed from this list and transformed into * its final state. @@ -353,14 +365,14 @@ public interface IList extends Iterable { * Reduce this list to a single value, using a accumulative approach. * * @param - * The in-between type of the values. + * The in-between type of the values. * * @param initial - * The initial value of the accumulative state. + * The initial value of the accumulative state. * * @param accumulator - * The function to use to combine a list element with the - * accumulative state. + * The function to use to combine a list element with the + * accumulative state. * * @return A single value condensed from this list. */ @@ -373,7 +385,7 @@ public interface IList extends Iterable { * Remove all elements that match a given predicate. * * @param predicate - * The predicate to use to determine elements to delete. + * The predicate to use to determine elements to delete. * * @return Whether there was anything that satisfied the predicate. */ @@ -383,7 +395,7 @@ public interface IList extends Iterable { * Remove all parameters that match a given parameter. * * @param element - * The object to remove all matching copies of. + * The object to remove all matching copies of. */ void removeMatching(ContainedType element); @@ -398,11 +410,11 @@ public interface IList extends Iterable { * hand. * * @param key - * The key to search for. + * The key to search for. * * @param comparator - * The way to compare elements for searching. Pass null to use - * the natural ordering for E. + * The way to compare elements for searching. Pass null + * to use the natural ordering for E. * * @return The element if it is in this list, or null if it is not. */ @@ -415,8 +427,8 @@ public interface IList extends Iterable { * Does change the underlying list. * * @param comparator - * The way to compare elements for sorting. Pass null to use E's - * natural ordering + * The way to compare elements for sorting. Pass null to + * use E's natural ordering */ void sort(Comparator comparator); @@ -431,7 +443,7 @@ public interface IList extends Iterable { * Convert this list into an array. * * @param type - * The type of array to return. + * The type of array to return. * * @return The list, as an array. */ diff --git a/base/src/main/java/bjc/utils/funcutils/ListUtils.java b/base/src/main/java/bjc/utils/funcutils/ListUtils.java index 55e0afa..b99c8a0 100644 --- a/base/src/main/java/bjc/utils/funcutils/ListUtils.java +++ b/base/src/main/java/bjc/utils/funcutils/ListUtils.java @@ -25,12 +25,12 @@ public class ListUtils { * spaces. * * @param input - * The list of tokens to collapse. + * The list of tokens to collapse. * * @return The collapsed string of tokens. */ public static String collapseTokens(final IList input) { - if(input == null) throw new NullPointerException("Input must not be null"); + if (input == null) throw new NullPointerException("Input must not be null"); return collapseTokens(input, ""); } @@ -40,32 +40,32 @@ public class ListUtils { * separator after each token. * * @param input - * The list of tokens to collapse. + * The list of tokens to collapse. * * @param seperator - * The separator to use for separating tokens. + * The separator to use for separating tokens. * * @return The collapsed string of tokens. */ public static String collapseTokens(final IList input, final String seperator) { - if(input == null) { + if (input == null) { throw new NullPointerException("Input must not be null"); - } else if(seperator == null) { + } else if (seperator == null) { throw new NullPointerException("Seperator must not be null"); } - if(input.getSize() < 1) { + if (input.getSize() < 1) { return ""; - } else if(input.getSize() == 1) { + } else if (input.getSize() == 1) { return input.first(); } else { final StringBuilder state = new StringBuilder(); int i = 1; - for(final String itm : input.toIterable()) { + for (final String itm : input.toIterable()) { state.append(itm); - if(i != input.getSize()) { + if (i != input.getSize()) { state.append(seperator); } @@ -80,17 +80,17 @@ public class ListUtils { * Select a number of random items from the list without replacement. * * @param - * The type of items to select. + * The type of items to select. * * @param list - * The list to select from. + * The list to select from. * * @param number - * The number of items to selet. + * The number of items to selet. * * @param rng - * A function that creates a random number from 0 to the desired - * number. + * A function that creates a random number from 0 to the + * desired number. * * @return A new list containing the desired number of items randomly * selected from the specified list without replacement. @@ -104,7 +104,7 @@ public class ListUtils { final Iterator itr = list.toIterable().iterator(); E element = null; - for(final int index = 0; itr.hasNext(); element = itr.next()) { + for (final int index = 0; itr.hasNext(); element = itr.next()) { /* n - m */ final int winningChance = number - selected.getSize(); @@ -112,7 +112,7 @@ public class ListUtils { final int totalChance = total - (index - 1); /* Probability of selecting the t+1'th element */ - if(NumberUtils.isProbable(winningChance, totalChance, rng)) { + if (NumberUtils.isProbable(winningChance, totalChance, rng)) { selected.add(element); } } @@ -124,17 +124,17 @@ public class ListUtils { * Select a number of random items from the list, with replacement. * * @param - * The type of items to select. + * The type of items to select. * * @param list - * The list to select from. + * The list to select from. * * @param number - * The number of items to select. + * The number of items to select. * * @param rng - * A function that creates a random number from 0 to the desired - * number. + * A function that creates a random number from 0 to the + * desired number. * * @return A new list containing the desired number of items randomly * selected from the specified list. @@ -143,7 +143,7 @@ public class ListUtils { final Function rng) { final IList selected = new FunctionalList<>(new ArrayList<>(number)); - for(int i = 0; i < number; i++) { + for (int i = 0; i < number; i++) { selected.add(list.randItem(rng)); } @@ -155,26 +155,27 @@ public class ListUtils { * for more than one element in a partition. * * @param - * The type of elements in the list to partition. + * The type of elements in the list to partition. * * @param input - * The list to partition. + * The list to partition. * * @param counter - * The function to determine the count for each element for. + * The function to determine the count for each element + * for. * * @param partitionSize - * The number of elements to put in each partition. + * The number of elements to put in each partition. * * @return A list partitioned according to the above rules. */ public static IList> groupPartition(final IList input, final Function counter, final int partitionSize) { - if(input == null) { + if (input == null) { throw new NullPointerException("Input list must not be null"); - } else if(counter == null) { + } else if (counter == null) { throw new NullPointerException("Counter must not be null"); - } else if(partitionSize < 1 || partitionSize > input.getSize()) { + } else if (partitionSize < 1 || partitionSize > input.getSize()) { final String fmt = "%d is not a valid partition size. Must be between 1 and %d"; final String msg = String.format(fmt, partitionSize, input.getSize()); @@ -190,11 +191,11 @@ public class ListUtils { final GroupPartIteration it = new GroupPartIteration<>(returned, rejected, partitionSize, counter); /* Run up to a certain number of passes. */ - for(int numberOfIterations = 0; numberOfIterations < MAX_NTRIESPART + for (int numberOfIterations = 0; numberOfIterations < MAX_NTRIESPART && !rejected.isEmpty(); numberOfIterations++) { input.forEach(it); - if(rejected.isEmpty()) { + if (rejected.isEmpty()) { /* Nothing was rejected, so we're done. */ return returned; } @@ -212,10 +213,10 @@ public class ListUtils { * Merge the contents of a bunch of lists together into a single list. * * @param - * The type of value in this lists. + * The type of value in this lists. * * @param lists - * The values in the lists to merge. + * The values in the lists to merge. * * @return A list containing all the elements of the lists. */ @@ -223,8 +224,8 @@ public class ListUtils { public static IList mergeLists(final IList... lists) { final IList returned = new FunctionalList<>(); - for(final IList list : lists) { - for(final E itm : list.toIterable()) { + for (final IList list : lists) { + for (final E itm : list.toIterable()) { returned.add(itm); } } @@ -236,24 +237,24 @@ public class ListUtils { * Pad the provided list out to the desired size. * * @param - * The type of elements in the list. + * The type of elements in the list. * * @param list - * The list to pad out. + * The list to pad out. * * @param counter - * The function to count elements with. + * The function to count elements with. * * @param size - * The desired size of the list. + * The desired size of the list. * * @param padder - * The function to get elements to pad with. + * The function to get elements to pad with. * * @return The list, padded to the desired size. * * @throws IllegalArgumentException - * If the list couldn't be padded to the desired size. + * If the list couldn't be padded to the desired size. */ public static IList padList(final IList list, final Function counter, final int size, final Supplier padder) { @@ -261,22 +262,22 @@ public class ListUtils { final IList returned = new FunctionalList<>(); - for(final E itm : list.toIterable()) { + for (final E itm : list.toIterable()) { count += counter.apply(itm); returned.add(itm); } - if(count % size != 0) { + if (count % size != 0) { /* We need to pad */ int needed = count % size; int threshold = 0; - while(needed > 0 && threshold <= MAX_NTRIESPART) { + while (needed > 0 && threshold <= MAX_NTRIESPART) { final E val = padder.get(); final int newCount = counter.apply(val); - if(newCount <= needed) { + if (newCount <= needed) { returned.add(val); threshold = 0; @@ -287,7 +288,7 @@ public class ListUtils { } } - if(threshold > MAX_NTRIESPART) { + if (threshold > MAX_NTRIESPART) { final String fmt = "Heuristic (more than %d iterations of attempting to pad) detected an unpaddable list. (%s)\nPartially padded list: %S"; final String msg = String.format(fmt, MAX_NTRIESPART, list.toString(), @@ -300,11 +301,18 @@ public class ListUtils { return returned; } + /** + * Convert a list of longs into an array of longs. + * + * @param list + * The list to convert. + * @return The list as an array. + */ public static long[] toPrimitive(List list) { long[] res = new long[list.size()]; int idx = 0; - for(long val : list) { + for (long val : list) { res[idx] = val; idx += 1; @@ -320,7 +328,7 @@ public class ListUtils { * pg 322) * * @param list - * The list to generate permutations from. + * The list to generate permutations from. * @return The list of permutations of the list. */ public static List> permuteList(List list) { @@ -329,17 +337,17 @@ public class ListUtils { /* * Special-case small usages. */ - if(list.size() == 0) { + if (list.size() == 0) { return permutes; } - if(list.size() == 1) { + if (list.size() == 1) { permutes.add(list); return permutes; } - if(list.size() == 2) { + if (list.size() == 2) { T elm1 = list.get(0); T elm2 = list.get(1); @@ -363,13 +371,13 @@ public class ListUtils { int[] auxC = new int[list.size()]; int[] auxO = new int[list.size()]; - for(int i = 0; i < list.size(); i++) { + for (int i = 0; i < list.size(); i++) { auxC[i] = 0; auxO[i] = 1; } List currentPermute = new ArrayList<>(list.size()); - for(T elm : list) { + for (T elm : list) { currentPermute.add(elm); } permutes.add(currentPermute); @@ -377,18 +385,18 @@ public class ListUtils { int j = list.size() - 1; int s = 0; - while(true) { + while (true) { int q = auxC[j] + auxO[j]; - if(q < 0) { + if (q < 0) { auxO[j] = -auxO[j]; j -= 1; continue; } - if(q == j) { - if(j == 0) break; + if (q == j) { + if (j == 0) break; s += 1; @@ -406,7 +414,7 @@ public class ListUtils { auxC[j] = q; currentPermute = new ArrayList<>(list.size()); - for(T elm : list) { + for (T elm : list) { currentPermute.add(elm); } permutes.add(currentPermute); @@ -418,12 +426,6 @@ public class ListUtils { return permutes; } - private static List> powerList(List list) { - List> results = new LinkedList<>(); - - return results; - } - private static void swapList(List list, int a, int b) { T tmp = list.get(a); diff --git a/base/src/main/java/bjc/utils/funcutils/SetUtils.java b/base/src/main/java/bjc/utils/funcutils/SetUtils.java index eac417c..d57ac00 100644 --- a/base/src/main/java/bjc/utils/funcutils/SetUtils.java +++ b/base/src/main/java/bjc/utils/funcutils/SetUtils.java @@ -5,10 +5,21 @@ import java.util.HashSet; import java.util.List; import java.util.Set; +/** + * Various utility functions dealing with sets. + * @author bjculkin + * + */ public class SetUtils { + /** + * Create a power-set (set of all subsets) of a given set. + * @param originalSet The set to create a power-set of. + * @return The power-set of the set. + */ public static Set> powerSet(Set originalSet) { Set> sets = new HashSet>(); + // Special-case empty input if (originalSet.isEmpty()) { sets.add(new HashSet()); return sets; @@ -16,13 +27,18 @@ public class SetUtils { List list = new ArrayList(originalSet); + // Add original set to list. T head = list.get(0); + // Trim leading element from set. Set rest = new HashSet(list.subList(1, list.size())); - for (Set set : powerSet(rest)) { + Set> remSets = powerSet(rest); + + for (Set set : remSets) { Set newSet = new HashSet(); + // Create a new set with the removed element. newSet.add(head); newSet.addAll(set); @@ -33,6 +49,12 @@ public class SetUtils { return sets; } + /** + * Utility method for set construction. + * @param elms The elements to stick in the set. + * @return A set containing the specified elements. + */ + @SafeVarargs public static Set toSet(T... elms) { Set set = new HashSet<>(); diff --git a/base/src/main/java/bjc/utils/funcutils/StringUtils.java b/base/src/main/java/bjc/utils/funcutils/StringUtils.java index e8558c7..7a4ee20 100644 --- a/base/src/main/java/bjc/utils/funcutils/StringUtils.java +++ b/base/src/main/java/bjc/utils/funcutils/StringUtils.java @@ -7,7 +7,6 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import bjc.utils.data.BooleanToggle; -import bjc.utils.ioutils.LevelSplitter; import bjc.utils.parserutils.TokenUtils; import com.ibm.icu.text.BreakIterator; diff --git a/base/src/main/java/bjc/utils/gen/WeightedRandom.java b/base/src/main/java/bjc/utils/gen/WeightedRandom.java index 405d685..71de333 100644 --- a/base/src/main/java/bjc/utils/gen/WeightedRandom.java +++ b/base/src/main/java/bjc/utils/gen/WeightedRandom.java @@ -2,9 +2,7 @@ package bjc.utils.gen; import java.util.Random; -import bjc.utils.data.IHolder; import bjc.utils.data.IPair; -import bjc.utils.data.Identity; import bjc.utils.data.Pair; import bjc.utils.funcdata.FunctionalList; import bjc.utils.funcdata.IList; @@ -16,7 +14,7 @@ import bjc.utils.funcdata.IList; * @author ben * * @param - * The type of values that are randomly selected. + * The type of values that are randomly selected. */ public class WeightedRandom { private final IList> values; @@ -29,17 +27,18 @@ public class WeightedRandom { private final static Random BASE = new Random(); private boolean exhaust; + /** * Create a new weighted random generator with the specified source of * randomness. * * @param src - * The source of randomness to use. + * The source of randomness to use. */ public WeightedRandom(Random src) { values = new FunctionalList<>(); - if(src == null) throw new NullPointerException("Source of randomness must not be null"); + if (src == null) throw new NullPointerException("Source of randomness must not be null"); source = src; } @@ -63,10 +62,10 @@ public class WeightedRandom { * Add a probability for a specific result to be given. * * @param chance - * The chance to get this result. + * The chance to get this result. * * @param result - * The result to get when the chance comes up. + * The result to get when the chance comes up. */ public void addProbability(final int chance, final E result) { values.add(new Pair<>(chance, result)); @@ -83,15 +82,20 @@ public class WeightedRandom { return generateValue(source); } + /** + * Generate a random value, using the specified Random. + * + * @param rn + * The Random instance to use. + * @return A random value. + */ public E generateValue(Random rn) { int target = rn.nextInt(totalChance); - int i = 0; - - for(IPair val : values) { + for (IPair val : values) { int prob = val.getLeft(); - if(target < prob) { - if(exhaust) { + if (target < prob) { + if (exhaust) { totalChance -= val.getLeft(); values.removeMatching(val); } @@ -100,11 +104,11 @@ public class WeightedRandom { } target -= prob; - i += 1; } return null; } + /** * Return a list of values that can be generated by this generator * @@ -124,17 +128,41 @@ public class WeightedRandom { return values; } + /** + * Get a descending value. + * + * Descending values are quite simple. You have a 1 in factor chance to + * advance to the next value, otherwise, the current value is the one + * returned. + * + * @param factor + * The descent factor to use. + * @return A random value. + */ public E getDescent(int factor) { return getDescent(factor, source); } + /** + * Get a descending value. + * + * Descending values are quite simple. You have a 1 in factor chance to + * advance to the next value, otherwise, the current value is the one + * returned. + * + * @param factor + * The descent factor to use. + * @param rn + * The Random instance to use. + * @return A random value. + */ public E getDescent(int factor, Random rn) { - if(values.getSize() == 0) return null; + if (values.getSize() == 0) return null; - for(IPair val : values) { - if(rn.nextInt(factor) == 0) continue; + for (IPair val : values) { + if (rn.nextInt(factor) == 0) continue; - if(exhaust) { + if (exhaust) { totalChance -= val.getLeft(); values.removeMatching(val); @@ -144,29 +172,61 @@ public class WeightedRandom { } IPair val = values.getByIndex(values.getSize() - 1); - if(exhaust) values.removeMatching(val); + if (exhaust) values.removeMatching(val); return val.getRight(); } + /** + * Get a value, treating this as a set of binomial trials. + * + * Essentially, the system rolls a bound-sided dice trials times, and + * marks a success for every roll less than or equal to target. + * + * @param target + * The number to roll at or under. + * @param bound + * The maximum roll value. + * @param trials + * The number of times to roll. + * @return The value at the index corresponding to the number of + * successes. + */ public E getBinomial(int target, int bound, int trials) { return getBinomial(target, bound, trials, source); } + /** + * Get a value, treating this as a set of binomial trials. + * + * Essentially, the system rolls a bound-sided dice trials times, and + * marks a success for every roll less than or equal to target. + * + * @param target + * The number to roll at or under. + * @param bound + * The maximum roll value. + * @param trials + * The number of times to roll. + * @param rn + * The Random instance to use. + * @return The value at the index corresponding to the number of + * successes. + */ public E getBinomial(int target, int bound, int trials, Random rn) { - if(values.getSize() == 0) return null; + if (values.getSize() == 0) return null; int numSuc = 0; - for(int i = 0; i < trials; i++) { - /* + for (int i = 0; i < trials; i++) { + /* * Adjust for zero, because it's easy to think of this * as rolling a bound-sided dice and marking a success * for every roll less than or equal to target. */ int num = rn.nextInt(bound) + 1; - if(num <= target) { + if (num <= target) { //System.err.printf("\t\tTRACE: mark binomial success (%d <= 1d%d, %d)\n", target, bound, num); numSuc += 1; } @@ -174,7 +234,7 @@ public class WeightedRandom { //System.err.printf("\tTRACE: got %d success for binomial trials (%d <= 1d%d, %d times)\n", numSuc, target, bound, trials); IPair val = values.getByIndex(Math.min(numSuc, values.getSize() - 1)); - if(exhaust) { + if (exhaust) { totalChance -= val.getLeft(); values.removeMatching(val); @@ -183,9 +243,14 @@ public class WeightedRandom { return val.getRight(); } + /** + * Return a new WeightedRandom that is exhaustible (only returns one value once). + * + * @return A new WeightedRandom that is exhaustible. + */ public WeightedRandom exhaustible() { IList> lst = new FunctionalList<>(); - for(IPair val : values) { + for (IPair val : values) { lst.add(val); } diff --git a/base/src/main/java/bjc/utils/ioutils/MirrorDB.java b/base/src/main/java/bjc/utils/ioutils/MirrorDB.java index 230f2f0..1ddcab6 100644 --- a/base/src/main/java/bjc/utils/ioutils/MirrorDB.java +++ b/base/src/main/java/bjc/utils/ioutils/MirrorDB.java @@ -1,15 +1,22 @@ package bjc.utils.ioutils; import java.io.InputStream; -import java.io.IOException; - import java.util.HashMap; import java.util.Map; import java.util.Scanner; +/** + * A database for describing mirrored characters. + * + * @author bjculkin + * + */ public class MirrorDB { private Map mirrored; + /** + * Create a new database of mirrored characters. + */ public MirrorDB() { mirrored = new HashMap<>(); @@ -42,10 +49,24 @@ public class MirrorDB { } } + /** + * Check if a string can be mirrored. + * + * @param mir + * The string to check for mirroring. + * @return Whether or not the given string can be mirrored. + */ public boolean canMirror(String mir) { return mirrored.containsKey(mir); } + /** + * Mirror a string. + * + * @param mir + * The string to mirror. + * @return The mirrored version of the string. + */ public String mirror(String mir) { return mirrored.get(mir); } diff --git a/base/src/main/java/bjc/utils/ioutils/ReportWriter.java b/base/src/main/java/bjc/utils/ioutils/ReportWriter.java index 647d4fe..ea7c8cf 100644 --- a/base/src/main/java/bjc/utils/ioutils/ReportWriter.java +++ b/base/src/main/java/bjc/utils/ioutils/ReportWriter.java @@ -5,29 +5,46 @@ import java.io.Writer; import bjc.utils.esodata.DefaultList; +/** + * A writer with support for some formatting operations, such as autoindentation + * and pagination. + * + * @author bjculkin + * + */ public class ReportWriter extends Writer { + /* + * Storage of indentation values. + */ private static class IndentVal { + // # of character positions indentStr occupies public int indentStrPos; + // String that is printed for the indent. public String indentStr; + // Indent string w/ tabs replaced with spaces public String indentStrSpacedTabs; public IndentVal() { } } + // Writer to print to private Writer contained; - // # of character positions indentStr occupies + // Current indentation level private int indentLevel; + // Current # of columns the indentation occupies private int indentPos = 0; + // The indentation values to use private DefaultList iVals; - private IndentVal defIVal; + // The default indentation value. + private IndentVal defIVal; // # of char. positions to the tab - private int tabEqv = 8; - // @NOTE 9/17/19 + private int tabEqv = 8; + // @NOTE 9/17/18 // // Consider adding support for both the vertical tab, and variable tab // stops. @@ -35,86 +52,192 @@ public class ReportWriter extends Writer { // For variable tab stops, decide between a set of numbers saying 'This // level tab is counted as X spaces' and a set of numbers saying 'A tab // advances to the next tab stop that has not been passed' + + // The total count of lines printed private int linesWritten = 0; - private int linePos = 0; + // The current position in the line + private int linePos = 0; + // The number of newlines to print for every newline encountered. private int lineSpacing = 1; - private int pageLine = 0; - private int pageNum = 0; + // The current line on the page + private int pageLine = 0; + // The current page number + private int pageNum = 0; + // The number of lines per page private int linesPerPage = 20; + // Whether or not to print tabs as spaces. private boolean printTabsAsSpaces; + // Whether or not the last character was a newline private boolean lastCharWasNL; - private char lastChar; + // The last character encountered + private char lastChar; // Really wish java had public `readonly` properties. I wouldn't even // care if that was a restriction that was only enforced by the compiler + + /** + * Get the current indent level. + * + * @return The current indent level. + */ public int getLevel() { return indentLevel; } + /** + * Get the current line-spacing. + * + * This is the number of blank lines to print out every time a blank + * line is encountered in the input, and is set to 1 by default. + * + * @return The current line spacing. + */ public int getLineSpacing() { return lineSpacing; } + /** + * Get the current line on the page. + * + * @return The current line on the page. + */ public int getPageLine() { return pageLine; } + /** + * Get the current page number. + * + * @return The current page number. + */ public int getPageNum() { return pageNum; } + /** + * Get the number of lines per page. + * + * @return The number of lines per page. + */ public int getLinesPerPage() { return linesPerPage; } + /** + * Get the current indent position. + * + * This is the count of columns the indentation occupies. + * + * @return The current indent position. + */ public int getIndentPos() { return indentPos; } + /** + * Get the string of the default indentation value. + * + * @return The string for the default indentation value. + */ public String getString() { return defIVal.indentStr; } + /** + * Get the string of a specific indentation value. + * + * @param lvl + * The level to get the value for. + * @return The string for the specified indentation value. + */ public String getString(int lvl) { return iVals.get(lvl).indentStr; } + /** + * Get the number of spaces to a tab. + * + * @return The number of spaces to a tab. + */ public int getTabEqv() { return tabEqv; } + /** + * Get the total number of lines written. + * + * @return The total number of lines written. + */ public int getLinesWritter() { return linesWritten; } + /** + * Get the current position in the line. + * + * @return The current position in the line. + */ public int getLinePos() { return linePos; } + /** + * Get the last character printed. + * + * @return The last character printed. + */ public char getLastChar() { return lastChar; } + /** + * Get the contained writer. + * + * @return The contained writer. + */ public Writer getWriter() { return contained; } + /** + * Check if the last character was a newline. + * + * @return Was the last character a new line? + */ public boolean isLastCharNL() { return lastCharWasNL; } + /** + * Check if tabs are being printed as spaces. + * + * @return Are tabs being printed as spaces? + */ public boolean isPrintingTabsAsSpaces() { return printTabsAsSpaces; } + /** + * Set the line spacing. + * + * @param spacing + * The number of lines to print for every blank line + * encountered. + */ public void setLineSpacing(int spacing) { lineSpacing = spacing; } + /** + * Set whether tabs are being printed as spaces. + * + * @param tabsAsSpaces + * Whether to print tabs as spaces. + */ public void setPrintTabsAsSpaces(boolean tabsAsSpaces) { printTabsAsSpaces = tabsAsSpaces; @@ -122,6 +245,12 @@ public class ReportWriter extends Writer { refreshIndents(-1); } + /** + * Set the number of lines per page. + * + * @param lines + * The number of lines per page. + */ public void setLinesPerPage(int lines) { linesPerPage = lines; @@ -141,10 +270,22 @@ public class ReportWriter extends Writer { } } + /** + * Set the current indentation level. + * + * @param level + * The indentation level. + */ public void setLevel(int level) { indentLevel = level; } + /** + * Set the current amount of spaces per tab. + * + * @param eqv + * The amount of spaces per tab. + */ public void setTabEqv(int eqv) { tabEqv = eqv; @@ -157,12 +298,30 @@ public class ReportWriter extends Writer { // Weirdness may occur if the indent string has a // newline in it, since that newline won't be considered // to exist by the IndentWriter + + /** + * Set the default indentation string to use. + * + * NOTE: Using a string that contains a newline may cause weirdness of + * various sorts to happen. + * + * @param str + * The string to use for default indentation. + */ public void setString(String str) { defIVal.indentStr = str; refreshIndents(-2); } + /** + * Set the indentation string for a specific indentation level. + * + * @param lvl + * The level to set the indentation string for. + * @param str + * The indentation string to use. + */ public void setString(int lvl, String str) { iVals.get(lvl).indentStr = str; @@ -174,6 +333,14 @@ public class ReportWriter extends Writer { // Pass a index to refresh that level // Pass -1 to refresh all indexes // Pass -2 to refresh the default index + /** + * Refresh the indentation settings. + * + * @param lvl + * The level of indents to refresh. Passing a number >= 0 + * refreshes that level, -1 refreshes every level, and -2 + * refreshes just the default indentation. + */ private void refreshIndents(int lvl) { if (lvl == -2) { refreshIndent(defIVal); @@ -181,21 +348,24 @@ public class ReportWriter extends Writer { for (IndentVal ival : iVals) { refreshIndent(ival); } + + refreshIndent(defIVal); } else { refreshIndent(iVals.get(lvl)); } } + // Refresh an indent val to respect current settings private void refreshIndent(IndentVal vl) { vl.indentStrPos = 0; int indentLength = vl.indentStr.length(); StringBuilder conv = new StringBuilder(); - for(int i = 0; i < indentLength; i++) { + for (int i = 0; i < indentLength; i++) { char c = vl.indentStr.charAt(i); - if(c == '\t') { - for(int j = 0; j < tabEqv; j++) { + if (c == '\t') { + for (int j = 0; j < tabEqv; j++) { conv.append(' '); } @@ -209,25 +379,30 @@ public class ReportWriter extends Writer { vl.indentStrSpacedTabs = conv.toString(); } + /** + * Duplicate this writers settings. + * @param contents The internal writer to use. + * @return A new writer, sharing this ones settings, but writing to the provided Writer instead. + */ public ReportWriter duplicate(Writer contents) { ReportWriter rw = new ReportWriter(contents); - rw.iVals = iVals; - rw.defIVal = defIVal; + rw.iVals = iVals; + rw.defIVal = defIVal; rw.indentLevel = indentLevel; - rw.indentPos = indentPos; + rw.indentPos = indentPos; rw.tabEqv = tabEqv; rw.linesWritten = linesWritten; - rw.linePos = linePos; - rw.lineSpacing = lineSpacing; + rw.linePos = linePos; + rw.lineSpacing = lineSpacing; rw.printTabsAsSpaces = printTabsAsSpaces; - rw.pageLine = pageLine; - rw.pageNum = pageNum; + rw.pageLine = pageLine; + rw.pageNum = pageNum; rw.linesPerPage = linesPerPage; // @NOTE 9/5/18 @@ -238,10 +413,20 @@ public class ReportWriter extends Writer { return rw; } + /** + * Create a new ReportWriter. + * @param write The place to write to. + */ public ReportWriter(Writer write) { this(write, 0, "\t"); } + /** + * Create a new ReportWriter with the specified default indentation values. + * @param write The place to write to. + * @param level The current indentation level. + * @param indentStr The indentation string. + */ public ReportWriter(Writer write, int level, String indentStr) { super(); @@ -250,19 +435,30 @@ public class ReportWriter extends Writer { indentLevel = level; defIVal = new IndentVal(); - iVals = new DefaultList<>(defIVal); + iVals = new DefaultList<>(defIVal); setString(indentStr); } + /** + * Indent a specific number of levels. + * @param lvl The number of levels to indent. + */ public void indent(int lvl) { indentLevel += lvl; } + /** + * Indent one level. + */ public void indent() { indent(1); } + /** + * Dedent a specific number of levels. + * @param lvl The number of levels to dedent. + */ public void dedent(int lvl) { // @NOTE 9/5/18 // @@ -271,10 +467,18 @@ public class ReportWriter extends Writer { indentLevel = Math.max(0, indentLevel - lvl); } + /** + * Dedent 1 level. + */ public void dedent() { dedent(1); } + /** + * Writes a buffer to the output, then clears it. + * @param sb The buffer to write and clear. + * @throws IOException If something goes wrong writing the buffer. + */ public void writeBuffer(StringBuffer sb) throws IOException { write(sb.toString()); @@ -289,14 +493,14 @@ public class ReportWriter extends Writer { // next page, or just printing the actual form-feed and hoping whatever // reading software handles it properly private void writePage() { - pageNum += 1; + pageNum += 1; pageLine -= linesPerPage; } private void writeNL(char c) throws IOException { // Count lines written linesWritten += lineSpacing; - pageLine += lineSpacing; + pageLine += lineSpacing; lastCharWasNL = true; @@ -317,41 +521,40 @@ public class ReportWriter extends Writer { writePage(); } - - linePos = 0; + linePos = 0; indentPos = 0; } @Override public void write(char[] cbuf, int off, int len) throws IOException { // Skip empty writes - if(len == 0) return; + if (len == 0) return; // Last character was a new line, print the indent string - if(lastCharWasNL) { + if (lastCharWasNL) { lastCharWasNL = false; printIndents(); } - for(int i = 0; i < len; i++) { + for (int i = 0; i < len; i++) { int idx = i + off; char c = cbuf[idx]; - if(c == '\n' || c == '\r' || (c == '\n' && lastChar != '\r') || c == '\f') { + if (c == '\n' || c == '\r' || (c == '\n' && lastChar != '\r') || c == '\f') { writeNL(c); } else { - if(lastCharWasNL) { + if (lastCharWasNL) { lastCharWasNL = false; printIndents(); } - if(c == '\t') { + if (c == '\t') { linePos += tabEqv; - for(int j = 0; j < tabEqv; j++) { + for (int j = 0; j < tabEqv; j++) { contained.write(' '); } } else { @@ -368,10 +571,11 @@ public class ReportWriter extends Writer { for (int j = 0; j < indentLevel; j++) { IndentVal ival = iVals.get(j); - if (printTabsAsSpaces) contained.write(ival.indentStrSpacedTabs); - else contained.write(ival.indentStr); + if (printTabsAsSpaces) + contained.write(ival.indentStrSpacedTabs); + else contained.write(ival.indentStr); - linePos += ival.indentStrPos; + linePos += ival.indentStrPos; indentPos += ival.indentStrPos; } } diff --git a/base/src/main/java/bjc/utils/ioutils/blocks/Block.java b/base/src/main/java/bjc/utils/ioutils/blocks/Block.java index 61d473c..bf0257e 100644 --- a/base/src/main/java/bjc/utils/ioutils/blocks/Block.java +++ b/base/src/main/java/bjc/utils/ioutils/blocks/Block.java @@ -27,19 +27,26 @@ public class Block { */ public final int blockNo; + /** + * The line offset number for this block. + * + * Essentially, this is the absolute number of lines that this block is + * into whatever source it came from, where as startLine and endLine are + * relative to the BlockReader this Block is from. + */ public int lineOffset; /** * Create a new block. * * @param blockNo - * The number of this block. + * The number of this block. * @param contents - * The contents of this block. + * The contents of this block. * @param startLine - * The line this block started on. + * The line this block started on. * @param endLine - * The line this block ended. + * The line this block ended. */ public Block(final int blockNo, final String contents, final int startLine, final int endLine) { this.contents = contents; @@ -48,51 +55,17 @@ public class Block { 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(final Object obj) { - if(this == obj) return true; - if(obj == null) return false; - if(!(obj instanceof Block)) return false; - - final 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() { - if(lineOffset != -1) { + if (lineOffset != -1) { String fmt = "Block #%d (from lines %d (%d) to %d (%d)), length: %d characters"; - return String.format(fmt, blockNo, startLine + lineOffset, - startLine, endLine + lineOffset, + return String.format(fmt, blockNo, startLine + lineOffset, startLine, endLine + lineOffset, endLine + lineOffset, contents.length()); - } else { - String fmt = "Block #%d (from lines %d to %d), length: %d characters"; - - return String.format(fmt, blockNo, startLine, endLine, contents.length()); } + + String fmt = "Block #%d (from lines %d to %d), length: %d characters"; + + return String.format(fmt, blockNo, startLine, endLine, contents.length()); } } diff --git a/base/src/main/java/bjc/utils/parserutils/splitter/ConfigurableTokenSplitter.java b/base/src/main/java/bjc/utils/parserutils/splitter/ConfigurableTokenSplitter.java index 2a565f2..1ca0fc1 100644 --- a/base/src/main/java/bjc/utils/parserutils/splitter/ConfigurableTokenSplitter.java +++ b/base/src/main/java/bjc/utils/parserutils/splitter/ConfigurableTokenSplitter.java @@ -16,15 +16,15 @@ import bjc.utils.funcdata.IList; * */ public class ConfigurableTokenSplitter extends SimpleTokenSplitter { - private final Set simpleDelimiters; - private final Set multipleDelimiters; - private final Set rRawDelimiters; + private final Set simpleDelimiters; + private final Set multipleDelimiters; + private final Set rRawDelimiters; /** * Create a new token splitter with blank configuration. * * @param keepDelims - * Whether or not to keep delimiters. + * Whether or not to keep delimiters. */ public ConfigurableTokenSplitter(final boolean keepDelims) { super(null, keepDelims); @@ -35,16 +35,25 @@ public class ConfigurableTokenSplitter extends SimpleTokenSplitter { rRawDelimiters = new LinkedHashSet<>(); } + private ConfigurableTokenSplitter(boolean keepDelims, Set simpleDelimiters, + Set multipleDelimiters, Set rRawDelimiters) { + super(null, keepDelims); + + this.simpleDelimiters = simpleDelimiters; + this.multipleDelimiters = multipleDelimiters; + this.rRawDelimiters = rRawDelimiters; + } + /** * Add a set of simple delimiters to this splitter. * * Simple delimiters match one occurrence of themselves as literals. * * @param simpleDelims - * The simple delimiters to add. + * The simple delimiters to add. */ public void addSimpleDelimiters(final String... simpleDelims) { - for(final String simpleDelim : simpleDelims) { + for (final String simpleDelim : simpleDelims) { simpleDelimiters.add(simpleDelim); } } @@ -56,10 +65,10 @@ public class ConfigurableTokenSplitter extends SimpleTokenSplitter { * literals. * * @param multiDelims - * The multiple delimiters to add. + * The multiple delimiters to add. */ public void addMultiDelimiters(final String... multiDelims) { - for(final String multiDelim : multiDelims) { + for (final String multiDelim : multiDelims) { multipleDelimiters.add(multiDelim); } } @@ -71,10 +80,10 @@ public class ConfigurableTokenSplitter extends SimpleTokenSplitter { * expressions. * * @param rRawDelims - * The raw delimiters to add. + * The raw delimiters to add. */ public void addRawDelimiters(final String... rRawDelims) { - for(final String rRawDelim : rRawDelims) { + for (final String rRawDelim : rRawDelims) { rRawDelimiters.add(rRawDelim); } } @@ -86,15 +95,15 @@ public class ConfigurableTokenSplitter extends SimpleTokenSplitter { public void compile() { final StringBuilder rPattern = new StringBuilder(); - for(final String rRawDelimiter : rRawDelimiters) { + for (final String rRawDelimiter : rRawDelimiters) { rPattern.append(applyFormat("rawDelim", rRawDelimiter)); } - for(final String multipleDelimiter : multipleDelimiters) { + for (final String multipleDelimiter : multipleDelimiters) { rPattern.append(applyFormat("multipleDelim", multipleDelimiter)); } - for(final String simpleDelimiter : simpleDelimiters) { + for (final String simpleDelimiter : simpleDelimiters) { rPattern.append(applyFormat("simpleDelim", simpleDelimiter)); } @@ -105,7 +114,7 @@ public class ConfigurableTokenSplitter extends SimpleTokenSplitter { @Override public IList split(final String input) { - if(spliter == null) throw new IllegalStateException("Must compile splitter before use"); + if (spliter == null) throw new IllegalStateException("Must compile splitter before use"); return super.split(input); } @@ -117,36 +126,76 @@ public class ConfigurableTokenSplitter extends SimpleTokenSplitter { return String.format(fmt, simpleDelimiters, multipleDelimiters, rRawDelimiters, spliter); } - + + /** + * Builder class for the configurable token splitter. + * + * @author bjculkin + * + */ public static class Builder { private ConfigurableTokenSplitter cts; - + + /** + * Create a new splitter builder. + * + * @param keepDelims + * Whether or not to keep the delimited splitter. + */ public Builder(boolean keepDelims) { cts = new ConfigurableTokenSplitter(keepDelims); } - - public Builder simple(String...strings) { + + /** + * Add a set of simple delimiters. + * + * @param strings + * The simple delimiters to use. + * @return The builder, for chaining. + */ + public Builder simple(String... strings) { cts.addSimpleDelimiters(strings); - + return this; } - - public Builder multiple(String...strings) { + + /** + * Add a set of multiple delimiters. + * + * @param strings + * The multiple delimiters to use. + * @return The builder, for chaining. + */ + public Builder multiple(String... strings) { cts.addMultiDelimiters(strings); - + return this; } - - public Builder raw(String...strings) { + + /** + * Add a set of raw delimiters. + * + * @param strings + * The raw delimiters to use. + * @return The builder, for chaining. + */ + public Builder raw(String... strings) { cts.addRawDelimiters(strings); - + return this; } - + + /** + * Build the splitter. + * + * @return The built splitter. + */ public ConfigurableTokenSplitter build() { - cts.compile(); + ConfigurableTokenSplitter ret = new ConfigurableTokenSplitter(cts.keepDelim, + cts.simpleDelimiters, cts.multipleDelimiters, cts.rRawDelimiters); + ret.compile(); - return cts; + return ret; } } } diff --git a/base/src/main/java/bjc/utils/parserutils/splitter/SimpleTokenSplitter.java b/base/src/main/java/bjc/utils/parserutils/splitter/SimpleTokenSplitter.java index 4e97008..9eb2d48 100644 --- a/base/src/main/java/bjc/utils/parserutils/splitter/SimpleTokenSplitter.java +++ b/base/src/main/java/bjc/utils/parserutils/splitter/SimpleTokenSplitter.java @@ -15,7 +15,7 @@ import bjc.utils.ioutils.RegexStringEditor; public class SimpleTokenSplitter implements TokenSplitter { protected Pattern spliter; - private final boolean keepDelim; + protected final boolean keepDelim; /** * Create a new simple token splitter. diff --git a/base/src/test/java/bjc/utils/test/ioutils/ReportWriterTest.java b/base/src/test/java/bjc/utils/test/ioutils/ReportWriterTest.java index 11e104c..afb5448 100644 --- a/base/src/test/java/bjc/utils/test/ioutils/ReportWriterTest.java +++ b/base/src/test/java/bjc/utils/test/ioutils/ReportWriterTest.java @@ -19,9 +19,7 @@ import org.junit.Test; public class ReportWriterTest { @Test public void testWriteString() { - ReportWriter rw = new ReportWriter(new StringWriter()); - - try { + try (ReportWriter rw = new ReportWriter(new StringWriter())) { rw.write("foo"); assertEquals("foo", rw.toString()); diff --git a/clformat/src/main/java/bjc/utils/ioutils/format/CLParameters.java b/clformat/src/main/java/bjc/utils/ioutils/format/CLParameters.java index 427bc4e..2d85c6f 100644 --- a/clformat/src/main/java/bjc/utils/ioutils/format/CLParameters.java +++ b/clformat/src/main/java/bjc/utils/ioutils/format/CLParameters.java @@ -62,12 +62,12 @@ public class CLParameters { } /** - * Creates a set of parameters from an array of parameters. + * Creates a set of parameters from a parameter string. * * Mostly, this just fills in V and # parameters. * - * @param params - * The parameters of the directive. + * @param unsplit + * The string to parse parameters from * @param dirParams * The parameters of the format string. * -- cgit v1.2.3 From d5915c773f9e8c65126f2fd2ea03a6b47f2aa9b7 Mon Sep 17 00:00:00 2001 From: bculkin2442 Date: Sun, 14 Oct 2018 11:46:19 -0400 Subject: Cleanup --- base/src/main/java/bjc/utils/ioutils/ReportWriter.java | 2 +- base/src/main/java/bjc/utils/ioutils/blocks/SerialBlockReader.java | 3 +++ base/src/main/java/bjc/utils/math/NumberUtils.java | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/base/src/main/java/bjc/utils/ioutils/ReportWriter.java b/base/src/main/java/bjc/utils/ioutils/ReportWriter.java index ea7c8cf..4eb5aef 100644 --- a/base/src/main/java/bjc/utils/ioutils/ReportWriter.java +++ b/base/src/main/java/bjc/utils/ioutils/ReportWriter.java @@ -542,7 +542,7 @@ public class ReportWriter extends Writer { char c = cbuf[idx]; - if (c == '\n' || c == '\r' || (c == '\n' && lastChar != '\r') || c == '\f') { + if ((c == '\n' && lastChar != '\r') || c == '\n' || c == '\r' || c == '\f') { writeNL(c); } else { if (lastCharWasNL) { diff --git a/base/src/main/java/bjc/utils/ioutils/blocks/SerialBlockReader.java b/base/src/main/java/bjc/utils/ioutils/blocks/SerialBlockReader.java index 02483c1..66ebd66 100644 --- a/base/src/main/java/bjc/utils/ioutils/blocks/SerialBlockReader.java +++ b/base/src/main/java/bjc/utils/ioutils/blocks/SerialBlockReader.java @@ -2,6 +2,7 @@ package bjc.utils.ioutils.blocks; import java.io.IOException; import java.util.Deque; +import java.util.LinkedList; /** * Provides a means of concatenating two block readers. @@ -21,6 +22,8 @@ public class SerialBlockReader implements BlockReader { * The readers to pull from, in the order to pull from them. */ public SerialBlockReader(final BlockReader... readers) { + readerQueue = new LinkedList<>(); + for(final BlockReader reader : readers) { readerQueue.add(reader); } diff --git a/base/src/main/java/bjc/utils/math/NumberUtils.java b/base/src/main/java/bjc/utils/math/NumberUtils.java index 5c8ec7e..7dc2ff3 100644 --- a/base/src/main/java/bjc/utils/math/NumberUtils.java +++ b/base/src/main/java/bjc/utils/math/NumberUtils.java @@ -436,6 +436,7 @@ public class NumberUtils { StringBuilder pad = new StringBuilder(); if(work.length() < mincols) { + @SuppressWarnings("unused") int padCount = 0; for(int i = work.length(); i < mincols; i++) { // @NOTE 9/6/18 :CommaPad -- cgit v1.2.3 From a78d2f10f8142af6a4e557588c06546e2231eb3f Mon Sep 17 00:00:00 2001 From: bculkin2442 Date: Sun, 14 Oct 2018 13:06:40 -0400 Subject: Move tests --- .../main/java/bjc/utils/ioutils/LevelSplitter.java | 14 ++ .../java/bjc/utils/ioutils/ReportWriterTest.java | 30 ++++ .../java/bjc/utils/parserutils/TokenUtilsTest.java | 153 +++++++++++++++++++++ .../bjc/utils/test/ioutils/ReportWriterTest.java | 30 ---- .../bjc/utils/test/parserutils/TokenUtilsTest.java | 153 --------------------- 5 files changed, 197 insertions(+), 183 deletions(-) create mode 100644 base/src/test/java/bjc/utils/ioutils/ReportWriterTest.java create mode 100644 base/src/test/java/bjc/utils/parserutils/TokenUtilsTest.java delete mode 100644 base/src/test/java/bjc/utils/test/ioutils/ReportWriterTest.java delete mode 100644 base/src/test/java/bjc/utils/test/parserutils/TokenUtilsTest.java diff --git a/base/src/main/java/bjc/utils/ioutils/LevelSplitter.java b/base/src/main/java/bjc/utils/ioutils/LevelSplitter.java index 7de0e28..83b391b 100644 --- a/base/src/main/java/bjc/utils/ioutils/LevelSplitter.java +++ b/base/src/main/java/bjc/utils/ioutils/LevelSplitter.java @@ -86,6 +86,20 @@ public class LevelSplitter { return false; } + /** + * Split a string, respecting groups. + * + * @param phrase + * The string to split. + * @param splits + * The strings to split on. + * @return A list of split strings. If keepDelims is true, it also + * includes the delimiters in between the split strings. + */ + public List levelSplit(String phrase, String... splits) { + return levelSplit(phrase, false, splits); + } + /** * Split a string, respecting groups. * diff --git a/base/src/test/java/bjc/utils/ioutils/ReportWriterTest.java b/base/src/test/java/bjc/utils/ioutils/ReportWriterTest.java new file mode 100644 index 0000000..2092ae0 --- /dev/null +++ b/base/src/test/java/bjc/utils/ioutils/ReportWriterTest.java @@ -0,0 +1,30 @@ +package bjc.utils.ioutils; + +import static org.junit.Assert.*; + +import java.io.IOException; +import java.io.StringWriter; + +import bjc.utils.ioutils.ReportWriter; + +import org.junit.Test; + +/** + * Tests for ReportWriter. + * + * @author EVE + * + */ +@SuppressWarnings("javadoc") +public class ReportWriterTest { + @Test + public void testWriteString() { + try (ReportWriter rw = new ReportWriter(new StringWriter())) { + rw.write("foo"); + + assertEquals("foo", rw.toString()); + } catch (IOException ioex) { + + } + } +} diff --git a/base/src/test/java/bjc/utils/parserutils/TokenUtilsTest.java b/base/src/test/java/bjc/utils/parserutils/TokenUtilsTest.java new file mode 100644 index 0000000..08606b3 --- /dev/null +++ b/base/src/test/java/bjc/utils/parserutils/TokenUtilsTest.java @@ -0,0 +1,153 @@ +package bjc.utils.parserutils; + +import static bjc.utils.parserutils.TokenUtils.descapeString; +import static bjc.utils.parserutils.TokenUtils.removeDQuotedStrings; +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.hasItems; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +import java.util.List; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +/* + * Tests for TokenUtils + */ +@SuppressWarnings("javadoc") +public class TokenUtilsTest { + @Rule + public ExpectedException exp = ExpectedException.none(); + + /* + * Test removeDQuoted + */ + + /* + * Check handling of mismatched strings with no matching strings. + */ + @Test + public void testRemoveDQuoted_MismatchedStringNoMatch() throws IllegalArgumentException { + exp.expect(IllegalArgumentException.class); + exp.expectMessage(containsString("Opening quote was at position 0")); + + removeDQuotedStrings("\"hello"); + } + + /* + * Check handling of mismatched strings with a matching string. + */ + @Test + public void testRemoveDQuoted_MismatchedStringMatch() throws IllegalArgumentException { + exp.expect(IllegalArgumentException.class); + exp.expectMessage(containsString("Opening quote was at position 7")); + + removeDQuotedStrings("\"hello\"\""); + } + + /* + * Check handling of strings with a single embedded string. + */ + @Test + public void testRemoveDQuoted_SingleString() { + final List onSingleMatchString = removeDQuotedStrings("hello\"there\""); + + assertThat(onSingleMatchString, hasItems("hello", "\"there\"")); + } + + /* + * Check handling of strings with multiple quoted strings in a row. + */ + @Test + public void testRemoveDQuoted_MultipleSerialString() { + final List onMultipleSerialMatchString = removeDQuotedStrings("\"hello\"\"there\""); + + assertThat(onMultipleSerialMatchString, hasItems("\"hello\"", "\"there\"")); + } + + /* + * Check handling of strings with multiple interleaved strings. + */ + @Test + public void testRemoveDQuoted_MultipleInterleavedString() { + final List onMultipleInterleaveMatchString = removeDQuotedStrings("one\"two\"three\"four\""); + + assertThat(onMultipleInterleaveMatchString, hasItems("one", "\"two\"", "three", "\"four\"")); + } + + /* + * Check handling of strings without embedded strings. + */ + @Test + public void testRemoveDQuote_NoString() { + final List onNonmatchingString = removeDQuotedStrings("hello"); + + assertThat(onNonmatchingString, hasItems("hello")); + } + + /* + * Check handling of empty strings. + */ + @Test + public void testRemoveDQuote_EmptyString() { + final List onEmptyString = removeDQuotedStrings(""); + + assertThat(onEmptyString, hasItems("")); + } + + /* + * Test descapeString + */ + /* + * Check handling of empty strings. + */ + @Test + public void testDescapeString_EmptyString() { + final String onEmptyString = descapeString(""); + + assertThat(onEmptyString, is("")); + } + + /* + * Check handling of strings without escapes + */ + @Test + public void testDescapeString_NonescapeString() { + final String onNonescapeString = descapeString("hello there"); + + assertThat(onNonescapeString, is("hello there")); + } + + /* + * Check handling of strings with single escapes. + */ + @Test + public void testDescapeString_SingleEscapeString() { + final String onSingleEscapeString = descapeString("hello\\tthere"); + + assertThat(onSingleEscapeString, is("hello\tthere")); + } + + /* + * Check handling of strings with multiple escapes. + */ + @Test + public void testDescapeString_MultipleEscapeString() { + final String onMultipleEscapeString = descapeString("hello\\tthere\\tworld"); + + assertThat(onMultipleEscapeString, is("hello\tthere\tworld")); + } + + /* + * Check handling of strings with invalid single escapes. + */ + @Test + public void testDescapeString_InvalidSingleEscapeString() throws IllegalArgumentException { + exp.expect(IllegalArgumentException.class); + exp.expectMessage(containsString("at position 0")); + + descapeString("\\x"); + } +} \ No newline at end of file diff --git a/base/src/test/java/bjc/utils/test/ioutils/ReportWriterTest.java b/base/src/test/java/bjc/utils/test/ioutils/ReportWriterTest.java deleted file mode 100644 index afb5448..0000000 --- a/base/src/test/java/bjc/utils/test/ioutils/ReportWriterTest.java +++ /dev/null @@ -1,30 +0,0 @@ -package bjc.utils.test.ioutils; - -import static org.junit.Assert.*; - -import java.io.IOException; -import java.io.StringWriter; - -import bjc.utils.ioutils.ReportWriter; - -import org.junit.Test; - -/** - * Tests for ReportWriter. - * - * @author EVE - * - */ -@SuppressWarnings("javadoc") -public class ReportWriterTest { - @Test - public void testWriteString() { - try (ReportWriter rw = new ReportWriter(new StringWriter())) { - rw.write("foo"); - - assertEquals("foo", rw.toString()); - } catch (IOException ioex) { - - } - } -} diff --git a/base/src/test/java/bjc/utils/test/parserutils/TokenUtilsTest.java b/base/src/test/java/bjc/utils/test/parserutils/TokenUtilsTest.java deleted file mode 100644 index 99593ed..0000000 --- a/base/src/test/java/bjc/utils/test/parserutils/TokenUtilsTest.java +++ /dev/null @@ -1,153 +0,0 @@ -package bjc.utils.test.parserutils; - -import static bjc.utils.parserutils.TokenUtils.descapeString; -import static bjc.utils.parserutils.TokenUtils.removeDQuotedStrings; -import static org.hamcrest.CoreMatchers.containsString; -import static org.hamcrest.CoreMatchers.hasItems; -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; - -import java.util.List; - -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -/* - * Tests for TokenUtils - */ -@SuppressWarnings("javadoc") -public class TokenUtilsTest { - @Rule - public ExpectedException exp = ExpectedException.none(); - - /* - * Test removeDQuoted - */ - - /* - * Check handling of mismatched strings with no matching strings. - */ - @Test - public void testRemoveDQuoted_MismatchedStringNoMatch() throws IllegalArgumentException { - exp.expect(IllegalArgumentException.class); - exp.expectMessage(containsString("Opening quote was at position 0")); - - removeDQuotedStrings("\"hello"); - } - - /* - * Check handling of mismatched strings with a matching string. - */ - @Test - public void testRemoveDQuoted_MismatchedStringMatch() throws IllegalArgumentException { - exp.expect(IllegalArgumentException.class); - exp.expectMessage(containsString("Opening quote was at position 7")); - - removeDQuotedStrings("\"hello\"\""); - } - - /* - * Check handling of strings with a single embedded string. - */ - @Test - public void testRemoveDQuoted_SingleString() { - final List onSingleMatchString = removeDQuotedStrings("hello\"there\""); - - assertThat(onSingleMatchString, hasItems("hello", "\"there\"")); - } - - /* - * Check handling of strings with multiple quoted strings in a row. - */ - @Test - public void testRemoveDQuoted_MultipleSerialString() { - final List onMultipleSerialMatchString = removeDQuotedStrings("\"hello\"\"there\""); - - assertThat(onMultipleSerialMatchString, hasItems("\"hello\"", "\"there\"")); - } - - /* - * Check handling of strings with multiple interleaved strings. - */ - @Test - public void testRemoveDQuoted_MultipleInterleavedString() { - final List onMultipleInterleaveMatchString = removeDQuotedStrings("one\"two\"three\"four\""); - - assertThat(onMultipleInterleaveMatchString, hasItems("one", "\"two\"", "three", "\"four\"")); - } - - /* - * Check handling of strings without embedded strings. - */ - @Test - public void testRemoveDQuote_NoString() { - final List onNonmatchingString = removeDQuotedStrings("hello"); - - assertThat(onNonmatchingString, hasItems("hello")); - } - - /* - * Check handling of empty strings. - */ - @Test - public void testRemoveDQuote_EmptyString() { - final List onEmptyString = removeDQuotedStrings(""); - - assertThat(onEmptyString, hasItems("")); - } - - /* - * Test descapeString - */ - /* - * Check handling of empty strings. - */ - @Test - public void testDescapeString_EmptyString() { - final String onEmptyString = descapeString(""); - - assertThat(onEmptyString, is("")); - } - - /* - * Check handling of strings without escapes - */ - @Test - public void testDescapeString_NonescapeString() { - final String onNonescapeString = descapeString("hello there"); - - assertThat(onNonescapeString, is("hello there")); - } - - /* - * Check handling of strings with single escapes. - */ - @Test - public void testDescapeString_SingleEscapeString() { - final String onSingleEscapeString = descapeString("hello\\tthere"); - - assertThat(onSingleEscapeString, is("hello\tthere")); - } - - /* - * Check handling of strings with multiple escapes. - */ - @Test - public void testDescapeString_MultipleEscapeString() { - final String onMultipleEscapeString = descapeString("hello\\tthere\\tworld"); - - assertThat(onMultipleEscapeString, is("hello\tthere\tworld")); - } - - /* - * Check handling of strings with invalid single escapes. - */ - @Test - public void testDescapeString_InvalidSingleEscapeString() throws IllegalArgumentException { - exp.expect(IllegalArgumentException.class); - exp.expectMessage(containsString("at position 0")); - - descapeString("\\x"); - } -} \ No newline at end of file -- cgit v1.2.3 From d1d01769e7c55f7f62dc01cadf420d5f63424584 Mon Sep 17 00:00:00 2001 From: bculkin2442 Date: Sun, 14 Oct 2018 14:07:00 -0400 Subject: Testing --- .../main/java/bjc/utils/data/CircularIterator.java | 19 ++++---- .../java/bjc/utils/funcdata/FunctionalList.java | 15 ++++++- .../main/java/bjc/utils/funcutils/FileUtils.java | 20 +++++---- .../main/java/bjc/utils/funcutils/FuncUtils.java | 43 ++++++++++++++----- .../main/java/bjc/utils/funcutils/TestUtils.java | 44 +++++++++++++++++++ .../java/bjc/utils/data/BooleanToggleTest.java | 36 ++++++++++++++++ .../java/bjc/utils/data/CircularIteratorTest.java | 50 ++++++++++++++++++++++ 7 files changed, 197 insertions(+), 30 deletions(-) create mode 100644 base/src/main/java/bjc/utils/funcutils/TestUtils.java create mode 100644 base/src/test/java/bjc/utils/data/BooleanToggleTest.java create mode 100644 base/src/test/java/bjc/utils/data/CircularIteratorTest.java diff --git a/base/src/main/java/bjc/utils/data/CircularIterator.java b/base/src/main/java/bjc/utils/data/CircularIterator.java index 4558b63..9af4d87 100644 --- a/base/src/main/java/bjc/utils/data/CircularIterator.java +++ b/base/src/main/java/bjc/utils/data/CircularIterator.java @@ -8,7 +8,7 @@ import java.util.Iterator; * @author EVE * * @param - * The type of the iterable. + * The type of the iterable. */ public class CircularIterator implements Iterator { /* The iterable, and our current iterator into it. */ @@ -28,11 +28,11 @@ public class CircularIterator implements Iterator { * Create a new circular iterator. * * @param src - * The iterable to iterate from. + * The iterable to iterate from. * * @param circ - * Should we actually do circular iteration, or just repeat the - * terminal element? + * Should we actually do circular iteration, or just + * repeat the terminal element? */ public CircularIterator(final Iterable src, final boolean circ) { source = src; @@ -45,7 +45,7 @@ public class CircularIterator implements Iterator { * Create a new circular iterator that does actual circular iteration. * * @param src - * The iterable to iterate from. + * The iterable to iterate from. */ public CircularIterator(final Iterable src) { this(src, true); @@ -59,11 +59,12 @@ public class CircularIterator implements Iterator { @Override public E next() { - if(!curr.hasNext()) { - if(doCircle) { - curr = source.iterator(); - } else + if (!curr.hasNext()) { + if (!doCircle) { return curElm; + } + + curr = source.iterator(); } curElm = curr.next(); diff --git a/base/src/main/java/bjc/utils/funcdata/FunctionalList.java b/base/src/main/java/bjc/utils/funcdata/FunctionalList.java index 6953bd0..b988588 100644 --- a/base/src/main/java/bjc/utils/funcdata/FunctionalList.java +++ b/base/src/main/java/bjc/utils/funcdata/FunctionalList.java @@ -54,7 +54,20 @@ public class FunctionalList implements Cloneable, IList { wrapped.add(item); } } - + + /** + * Create a new functional list containing the specified items. + * + * Takes O(n) time, where n is the number of items specified + * + * @param items + * The items to put into this functional list. + * @return The returned list. + */ + @SafeVarargs + public static IList listOf(final T... items) { + return new FunctionalList<>(items); + } /** * Create a new functional list with the specified size. * diff --git a/base/src/main/java/bjc/utils/funcutils/FileUtils.java b/base/src/main/java/bjc/utils/funcutils/FileUtils.java index 0fd3db0..04ac6b0 100644 --- a/base/src/main/java/bjc/utils/funcutils/FileUtils.java +++ b/base/src/main/java/bjc/utils/funcutils/FileUtils.java @@ -13,26 +13,28 @@ import java.util.function.BiPredicate; */ public class FileUtils { /* - * @NOTE If it becomes necessary, write another overload for this with - * all the buttons and knobs from walkFileTree. + * @NOTE + * + * If it becomes necessary, write another overload for this with all the + * buttons and knobs from walkFileTree. */ /** * Traverse a directory recursively. This is a depth-first traversal. * * @param root - * The directory to start the traversal at. + * The directory to start the traversal at. * * @param predicate - * The predicate to determine whether or not to traverse a - * directory. + * The predicate to determine whether or not to traverse + * a directory. * * @param action - * The action to invoke upon each file in the directory. - * Returning true means to continue the traversal, returning - * false stops it. + * The action to invoke upon each file in the directory. + * Returning true means to continue the traversal, + * returning false stops it. * * @throws IOException - * If the walk throws an exception. + * If the walk throws an exception. * */ public static void traverseDirectory(final Path root, final BiPredicate predicate, diff --git a/base/src/main/java/bjc/utils/funcutils/FuncUtils.java b/base/src/main/java/bjc/utils/funcutils/FuncUtils.java index 2e55a3d..ff9fefb 100644 --- a/base/src/main/java/bjc/utils/funcutils/FuncUtils.java +++ b/base/src/main/java/bjc/utils/funcutils/FuncUtils.java @@ -1,6 +1,7 @@ package bjc.utils.funcutils; import java.util.function.BiFunction; +import java.util.function.BiPredicate; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.UnaryOperator; @@ -16,16 +17,16 @@ public class FuncUtils { * function. * * @param - * The initial type of the function. + * The initial type of the function. * * @param - * The intermediate type of the function. + * The intermediate type of the function. * * @param - * The terminal type of the function. + * The terminal type of the function. * * @param func - * The function to transform. + * The function to transform. * * @return The function transformed into a unary function returning a * function. @@ -40,13 +41,13 @@ public class FuncUtils { * Do the specified action the specified number of times. * * @param nTimes - * The number of times to do the action. + * The number of times to do the action. * * @param cons - * The action to perform. + * The action to perform. */ public static void doTimes(final int nTimes, final Consumer cons) { - for(int i = 0; i < nTimes; i++) { + for (int i = 0; i < nTimes; i++) { cons.accept(i); } } @@ -55,15 +56,35 @@ public class FuncUtils { * Return an operator that executes until it converges. * * @param op - * The operator to execute. + * The operator to execute. * * @param maxTries - * The maximum amount of times to apply the function in an - * attempt to cause it to converge. + * The maximum amount of times to apply the function in + * an attempt to cause it to converge. * * @return The requested operator. */ public static UnaryOperator converge(final UnaryOperator op, final int maxTries) { + return converge(op, (nw, old) -> nw.equals(old), maxTries); + } + + /** + * Return an operator that executes until it converges. + * + * @param op + * The operator to execute. + * @param converged + * The predicate to execute to check if the function has + * converged. + * + * @param maxTries + * The maximum amount of times to apply the function in + * an attempt to cause it to converge. + * + * @return The requested operator. + */ + public static UnaryOperator converge(final UnaryOperator op, final BiPredicate converged, + final int maxTries) { return (val) -> { T newVal = op.apply(val); T oldVal; @@ -75,7 +96,7 @@ public class FuncUtils { newVal = op.apply(newVal); tries += 1; - } while(!newVal.equals(oldVal) && tries < maxTries); + } while (!converged.test(newVal, oldVal) && tries < maxTries); return newVal; }; diff --git a/base/src/main/java/bjc/utils/funcutils/TestUtils.java b/base/src/main/java/bjc/utils/funcutils/TestUtils.java new file mode 100644 index 0000000..df44e7a --- /dev/null +++ b/base/src/main/java/bjc/utils/funcutils/TestUtils.java @@ -0,0 +1,44 @@ +package bjc.utils.funcutils; + +import static org.junit.Assert.assertEquals; + +import java.util.Collection; +import java.util.Iterator; + +/** + * Utilities for testing. + * + * @author bjculkin + * + */ +public class TestUtils { + /** + * Assert an iterator provides a particular sequence of values. + * + * @param src + * The iterator to pull values from. + * @param vals + * The values to expect from the iterator. + */ + public static void assertIteratorEquals(Iterator src, T... vals) { + for (T val : vals) { + assertEquals(val, src.next()); + } + } + + /** + * Assert an iterator provides a particular sequence of values. + * + * @param src + * The iterator to pull values from. + * @param hasMore + * The expected value of hasNext for the iterator. + * @param vals + * The values to expect from the iterator. + */ + public static void assertIteratorEquals(Iterator src, boolean hasMore, T... vals) { + assertIteratorEquals(src, vals); + + assertEquals(hasMore, src.hasNext()); + } +} diff --git a/base/src/test/java/bjc/utils/data/BooleanToggleTest.java b/base/src/test/java/bjc/utils/data/BooleanToggleTest.java new file mode 100644 index 0000000..f2b4994 --- /dev/null +++ b/base/src/test/java/bjc/utils/data/BooleanToggleTest.java @@ -0,0 +1,36 @@ +package bjc.utils.data; + +import static org.junit.Assert.*; + +import org.junit.Test; + +/** + * Test for boolean toggles. + * @author bjculkin + * + */ +public class BooleanToggleTest { + + /** + * Test that boolean toggles work right. + */ + @Test + public void test() { + BooleanToggle tog = new BooleanToggle(); + + // Check initial value is false. + assertEquals(false, tog.peek()); + // Check that 'get' returns the old value + assertEquals(false, tog.get()); + // Check that 'get' swaps the value + assertEquals(true, tog.peek()); + // Check that we can round-trip back. + assertEquals(true, tog.get()); + assertEquals(false, tog.peek()); + + tog.set(true); + + // Check set works + assertEquals(true, tog.peek()); + } +} diff --git a/base/src/test/java/bjc/utils/data/CircularIteratorTest.java b/base/src/test/java/bjc/utils/data/CircularIteratorTest.java new file mode 100644 index 0000000..c08bbb1 --- /dev/null +++ b/base/src/test/java/bjc/utils/data/CircularIteratorTest.java @@ -0,0 +1,50 @@ +package bjc.utils.data; + +import static org.junit.Assert.*; +import static bjc.utils.funcutils.TestUtils.*; + +import java.util.Arrays; +import java.util.List; + +import org.junit.Test; + +/** + * Test for circular iterators., + * + * @author bjculkin + * + */ +public class CircularIteratorTest { + + /** + * Test regular repetition of the entire iterator. + */ + @Test + public void testRegular() { + List lst = Arrays.asList("a", "b", "c"); + + CircularIterator itr = new CircularIterator<>(lst); + + // Check we get initial values correctly, and have more remaining + assertIteratorEquals(itr, true, "a", "b", "c"); + + // Check we repeat correctly, and can still repeat + assertIteratorEquals(itr, true, "a", "b", "c"); + } + + /** + * Test that the last element repeats correctly. + */ + @Test + public void testRepLast() { + List lst = Arrays.asList("a", "b", "c"); + + CircularIterator itr = new CircularIterator<>(lst, false); + + // Check we get initial values correctly, and have more remaining + assertIteratorEquals(itr, true, "a", "b", "c"); + + // Check we repeat correctly, and can still repeat + assertIteratorEquals(itr, true, "c", "c", "c"); + } +} -- cgit v1.2.3