diff --git a/src/main/java/pro/komaru/tridot/core/struct/Structs.java b/src/main/java/pro/komaru/tridot/core/struct/Structs.java index d21879d..2ce7b7c 100644 --- a/src/main/java/pro/komaru/tridot/core/struct/Structs.java +++ b/src/main/java/pro/komaru/tridot/core/struct/Structs.java @@ -1,6 +1,7 @@ package pro.komaru.tridot.core.struct; +import pro.komaru.tridot.core.struct.data.Seq; import pro.komaru.tridot.core.struct.func.Cons; import pro.komaru.tridot.core.struct.func.Func; import pro.komaru.tridot.core.struct.func.Prov; @@ -14,6 +15,9 @@ public static Prov nil(){ return () -> null; } + public static A cast(B obj) { + return (A) obj; + } public static T or(T a, T b) { if(a == null) return b; return a; @@ -54,6 +58,11 @@ public static HashMap map(Object... objs) { } return map; } + public static A[] pop(A[] def) { + var n = Seq.with(def); + n.slice(); + return n.toArray(); + } public static HashMap revMap(HashMap mapOrig) { HashMap map = new HashMap<>(); mapOrig.forEach((k,v) -> map.put(v,k)); diff --git a/src/main/java/pro/komaru/tridot/core/struct/data/Seq.java b/src/main/java/pro/komaru/tridot/core/struct/data/Seq.java index d83efa7..751b173 100644 --- a/src/main/java/pro/komaru/tridot/core/struct/data/Seq.java +++ b/src/main/java/pro/komaru/tridot/core/struct/data/Seq.java @@ -108,6 +108,11 @@ public static Seq withArrays(Object... arrays){ return result; } + /** @see #Seq(Object[]) */ + public static Seq with(){ + return new Seq<>(); + } + /** @see #Seq(Object[]) */ public static Seq with(T... array){ return new Seq<>(array); diff --git a/src/main/java/pro/komaru/tridot/core/struct/data/tree/ContainerTree.java b/src/main/java/pro/komaru/tridot/core/struct/data/tree/ContainerTree.java new file mode 100644 index 0000000..344a070 --- /dev/null +++ b/src/main/java/pro/komaru/tridot/core/struct/data/tree/ContainerTree.java @@ -0,0 +1,198 @@ +package pro.komaru.tridot.core.struct.data.tree; + +import pro.komaru.tridot.core.struct.data.Seq; +import pro.komaru.tridot.core.struct.func.Boolf; + +import java.util.LinkedList; +import java.util.Queue; + +@SuppressWarnings("rawtypes,unchecked") +public class ContainerTree implements ITree { + private final Seq children; + private final Seq> containers; + + public ContainerTree parent = null; + + public ContainerTree() { + children = Seq.with(); + containers = Seq.with(); + } + + + /** + * Adds all elements as children of this container tree + * @param all elements to add + */ + @SafeVarargs + public final ContainerTree add(A... all) { + children.add(all); + + return this; + } + /** + * Adds element as a child of this container tree + * @param child element to add + */ + public ContainerTree add(A child) { + children.add(child); + return this; + } + + /** + * Adds element as a subcontainer of this container tree + * @param child element to add + */ + public ContainerTree add(ContainerTree child) { + containers.add(child); + child.parent = this; + return this; + } + + /** + * Adds all elements as children of this container tree if they don't exist yet + * @param all elements to add + */ + @SafeVarargs + public final ContainerTree addUnique(A... all) { + for (A a : all) { + addUnique(a); + } + return this; + } + /** + * Adds element as a child of this container tree if it doesn't exist yet + * @param child element to add + */ + public ContainerTree addUnique(A child) { + children.addUnique(child); + return this; + } + + /** + * Finds a child of this container using a filter function + * @param filter filter function + * @return child object + */ + @Override + public A child(Boolf filter) { + return children().find(filter); + } + /** + * Finds a child in all containers of this tree using a filter function + * @param filter filter function + * @return child object + */ + @Override + public A childDeep(Boolf filter,boolean depthSearch) { + A child = children().find(filter); + if(depthSearch) { + if (child == null) { + for (ITree container : containers) { + A other = container.childDeep(filter); + if (other != null) { + return other; + } + } + } + } else { + Queue> queue = new LinkedList<>(); + queue.add(this); + + while (!queue.isEmpty()) { + ContainerTree current = queue.poll(); + A other = current.children().find(filter); + if (other != null) { + return other; + } + queue.addAll(current.containers.list()); + } + } + return child; + } + + /** + * Finds a child in all containers of this tree using a filter function, in a BFS method + * @param filter filter function + * @return child object + */ + @Override + public A childDeep(Boolf filter) { + return childDeep(filter,false); + } + + /** + * Clears all tree + */ + @Override + public void clean() { + children().clear(); + containers.each(e -> e.parent = null); //bye-bye! + containers().clear(); + } + + + /** + * @return Children Seq + */ + @Override + public Seq children() { + return children; + } + + /** + * @return Children of this tree and subcontainers' children + */ + @Override + public Seq childrenDeep() { + Seq all = Seq.with(); + all.addAll(children()); + for (ITree container : containers()) + all.addAll(container.childrenDeep()); + return all; + } + + /** + * @return Subcontainer Seq + */ + public Seq> containers() { + return containers; + } + + /** + * @return All containers of this tree + */ + public Seq> containersDeep() { + Seq> all = Seq.with(); + all.addAll(containers()); + for (ContainerTree other : containers()) + all.addAll(other.containers); + return all; + } + + + @Override + public String toString() { + String name = this instanceof NamedContTree a ? a.name : "***"; + StringBuilder sb = new StringBuilder("\u001B[33m[" + name + "]\u001B[0m"); + sb.append("\n"); + for (ContainerTree cont : containers) { + Seq lines = Seq.with(cont.toString().lines().map(e -> " " + e).toList()); + if(!lines.isEmpty()) { + lines.set(0,lines.get(0).replaceFirst(" ","")); + } + sb.append("\u001B[33m-\u001B[0m"); + sb.append(String.join("\n", lines)); + sb.append("\n"); + } + for (A child : children) { + Seq lines = Seq.with(child.toString().lines().map(e -> " " + e).toList()); + if(!lines.isEmpty()) { + lines.set(0,lines.get(0).replaceFirst(" ","")); + } + sb.append("\u001B[37m*\u001B[0m"); + sb.append(String.join("\n", lines)); + sb.append("\n"); + } + return sb.toString(); + } +} diff --git a/src/main/java/pro/komaru/tridot/core/struct/data/tree/INamedTree.java b/src/main/java/pro/komaru/tridot/core/struct/data/tree/INamedTree.java new file mode 100644 index 0000000..3decc86 --- /dev/null +++ b/src/main/java/pro/komaru/tridot/core/struct/data/tree/INamedTree.java @@ -0,0 +1,5 @@ +package pro.komaru.tridot.core.struct.data.tree; + +public interface INamedTree { + String name(); +} diff --git a/src/main/java/pro/komaru/tridot/core/struct/data/tree/ITree.java b/src/main/java/pro/komaru/tridot/core/struct/data/tree/ITree.java new file mode 100644 index 0000000..c9213b0 --- /dev/null +++ b/src/main/java/pro/komaru/tridot/core/struct/data/tree/ITree.java @@ -0,0 +1,35 @@ +package pro.komaru.tridot.core.struct.data.tree; + +import pro.komaru.tridot.core.struct.data.Seq; +import pro.komaru.tridot.core.struct.func.Boolf; + +public interface ITree { + Seq children(); + Seq childrenDeep(); + + A child(Boolf filter); + + + /** + * Deepfinding a child using a filter in either BFS or DFS + * @param filter filter function + * @param depthSearch if true, then it uses DFS instead of BFS + * @return child object + */ + A childDeep(Boolf filter, boolean depthSearch); + + default A childDeep(Boolf filter) { + return childDeep(filter,false); + }; + default A child(Boolf filter, boolean deep, boolean depthSearch) { + return deep ? childDeep(filter,depthSearch) : child(filter); + } + default A child(Boolf filter, boolean deep) { + return child(filter,deep,false); + } + + /** + * Clears all tree + */ + void clean(); +} diff --git a/src/main/java/pro/komaru/tridot/core/struct/data/tree/NamedContTree.java b/src/main/java/pro/komaru/tridot/core/struct/data/tree/NamedContTree.java new file mode 100644 index 0000000..97b38a9 --- /dev/null +++ b/src/main/java/pro/komaru/tridot/core/struct/data/tree/NamedContTree.java @@ -0,0 +1,80 @@ +package pro.komaru.tridot.core.struct.data.tree; + +import pro.komaru.tridot.core.struct.Structs; +import pro.komaru.tridot.core.struct.data.Seq; + +import java.util.HashMap; + +public class NamedContTree extends ContainerTree implements INamedTree { + public final String name; + + private final HashMap PATH_CACHE = + new HashMap<>(); + + public NamedContTree(String name) { + this.name = name; + } + + @Override + public NamedContTree add(A child) { + return (NamedContTree) super.add(child); + } + + @Override + public NamedContTree add(ContainerTree child) { + return (NamedContTree) super.add(child); + } + + @Override + public NamedContTree addUnique(A child) { + return (NamedContTree) super.addUnique(child); + } + + public NamedContTree cd(boolean autoCreate, String... path) { + if(path == null || path.length == 0) return this; + if(path[0].equals("..")) return ((NamedContTree) parent).cd(autoCreate,Structs.pop(path)); + for (NamedContTree cont : namedContainers()) { + if(cont.name.equals(path[0])) + return cont.cd(autoCreate,Structs.pop(path)); + } + if(autoCreate) { + NamedContTree newTree = new NamedContTree<>(path[0]); + containers().add(newTree); + newTree.parent = this; + return newTree.cd(true,Structs.pop(path)); + } + return null; + } + public NamedContTree cd(boolean autoCreate,String path) { + return cd(autoCreate,path.split("/")); + } + public NamedContTree cd(String... path) { + return cd(true,path); + } + public NamedContTree cd(String path) { + return cd(true,path); + } + + public static void main(String[] args) { + NamedContTree main = new NamedContTree<>("main"); + main + .cd("a") + .add("A section!") + .cd("../b") + .add("B section!") + .cd("../a/c") + .add("C section!") + .cd("../..") + .add("End section!"); + System.out.println(main); + } + + public Seq> namedContainers() { + return Structs.cast(containers().select(e -> e instanceof NamedContTree)); + } + + @Override + public String name() { + return name; + } +}