summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main/java/bjc/data/FlatMapIterator.java52
-rw-r--r--src/main/java/bjc/functypes/MapBuilder.java132
2 files changed, 184 insertions, 0 deletions
diff --git a/src/main/java/bjc/data/FlatMapIterator.java b/src/main/java/bjc/data/FlatMapIterator.java
new file mode 100644
index 0000000..47bc06c
--- /dev/null
+++ b/src/main/java/bjc/data/FlatMapIterator.java
@@ -0,0 +1,52 @@
+package bjc.data;
+
+import java.util.*;
+import java.util.function.Function;
+
+/**
+ * Create an iterator that applies a flat-map function
+ *
+ * @author bjcul
+ *
+ * @param <T1> The source type
+ * @param <T2> The output type
+ *
+ */
+public class FlatMapIterator<T1, T2> implements Iterator<T2> {
+ private Function<T1, Iterator<T2>> action;
+
+ private Iterator<T1> source;
+ private Iterator<T2> output;
+ /**
+ * Create a new flat-map iterator
+ *
+ * @param source The source iterator
+ * @param action The action to apply to the iterator
+ */
+ public FlatMapIterator(Iterator<T1> source, Function<T1, Iterator<T2>> action) {
+ this.source = source;
+ this.action = action;
+
+ }
+
+ @Override
+ public boolean hasNext() {
+ if (output != null && output.hasNext()) return true;
+ while (source.hasNext()) {
+ output = action.apply(source.next());
+ if (output.hasNext()) return true;
+ }
+ return false;
+ }
+
+ @Override
+ public T2 next() {
+ if (output != null && output.hasNext()) return output.next();
+ while (source.hasNext()) {
+ output = action.apply(source.next());
+ if (output.hasNext()) return output.next();
+ }
+ throw new NoSuchElementException();
+ }
+
+}
diff --git a/src/main/java/bjc/functypes/MapBuilder.java b/src/main/java/bjc/functypes/MapBuilder.java
new file mode 100644
index 0000000..1fa98e2
--- /dev/null
+++ b/src/main/java/bjc/functypes/MapBuilder.java
@@ -0,0 +1,132 @@
+package bjc.functypes;
+
+import java.util.*;
+import java.util.function.Function;
+
+import bjc.funcdata.Freezable;
+import bjc.funcdata.ObjectFrozen;
+
+/**
+ * Functional interface for a generic builder using a map
+ *
+ * @author bjcul
+ *
+ * @param <K> Key type of the map
+ * @param <V> Value type of the map
+ * @param <R> Result type of the builder
+ */
+public interface MapBuilder<K, V, R> extends Freezable<MapBuilder<K, V, R>> {
+ /**
+ * Build an instance using the current map
+ *
+ * @return An instance constructed using the map
+ */
+ R build();
+
+ /**
+ * Add a value to the map
+ *
+ * @param key The key to add
+ * @param value The value to add
+ *
+ * @return The builder, for chaining
+ */
+ MapBuilder<K, V, R> add(K key, V value);
+
+ /**
+ * Remove a value from the map
+ *
+ * @param key The key to remove
+ *
+ * @return The removed value
+ */
+ V remove(K key);
+
+ /**
+ * Clear the contents of the map
+ */
+ void clear();
+
+ /**
+ * Get the internal map.
+ *
+ * @return The internal map
+ */
+ Map<K, V> getMap();
+
+ /**
+ * Create a new map-builder from a function
+ *
+ * @param <K> The key type of the map
+ * @param <V> The value type of the map
+ * @param <R> The result of the builder
+ *
+ * @param f The building function
+ *
+ * @return A map-builder using the function
+ */
+ static <K, V, R> MapBuilder<K, V, R> from(Function<Map<K, V>, R> f) {
+ return new FunctionalMapBuilder<>(f);
+ }
+}
+
+final class FunctionalMapBuilder<K, V, R> implements MapBuilder<K, V, R> {
+ private final Function<Map<K, V>, R> f;
+ private Map<K, V> mep = new HashMap<>();
+
+ private boolean frozen = false;
+
+ FunctionalMapBuilder(Function<Map<K, V>, R> f) {
+ this.f = f;
+ }
+
+ @Override
+ public R build() {
+ return f.apply(mep);
+ }
+
+ @Override
+ public MapBuilder<K, V, R> add(K key, V value) {
+ if (frozen) throw new ObjectFrozen();
+
+ mep.put(key, value);
+ return this;
+ }
+
+ @Override
+ public V remove(K key) {
+ if (frozen) throw new ObjectFrozen();
+
+ return mep.remove(key);
+ }
+
+ @Override
+ public void clear() {
+ if (frozen) throw new ObjectFrozen();
+
+ mep.clear();
+ }
+
+ @Override
+ public Map<K, V> getMap() {
+ if (frozen) return Collections.unmodifiableMap(mep);
+ return mep;
+ }
+
+ @Override
+ public boolean freeze() {
+ frozen = true;
+ return true;
+ }
+
+ @Override
+ public boolean thaw() {
+ frozen = false;
+ return true;
+ }
+
+ @Override
+ public boolean isFrozen() {
+ return frozen;
+ }
+} \ No newline at end of file