feat: add PE2
This commit is contained in:
parent
44c87f3500
commit
1b99ba182d
4
.gitignore
vendored
4
.gitignore
vendored
@ -6,4 +6,6 @@ checkstyle.jar
|
||||
cs2030_checks.xml
|
||||
*.swp
|
||||
|
||||
Lab6/docs
|
||||
Lab6/docs
|
||||
|
||||
.vscode/
|
||||
|
171
cs2030s/PE2/plab0124/CS2030STest.java
Normal file
171
cs2030s/PE2/plab0124/CS2030STest.java
Normal file
@ -0,0 +1,171 @@
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Supplier;
|
||||
import javax.tools.DiagnosticCollector;
|
||||
import javax.tools.SimpleJavaFileObject;
|
||||
import javax.tools.ToolProvider;
|
||||
|
||||
/**
|
||||
* A helper class to test CS2030S labs.
|
||||
*/
|
||||
class CS2030STest {
|
||||
|
||||
private static final String ANSI_RESET = "\u001B[0m";
|
||||
private static final String ANSI_RED = "\u001B[31m";
|
||||
private static final String ANSI_GREEN = "\u001B[32m";
|
||||
|
||||
private void ok() {
|
||||
System.out.println(".. " + ANSI_GREEN + "ok" + ANSI_RESET);
|
||||
}
|
||||
|
||||
private void fail() {
|
||||
System.out.println(".. " + ANSI_RED + "failed" + ANSI_RESET);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if two objects are equals.
|
||||
*
|
||||
* @param test A description of the test.
|
||||
* @param output The output from an expression.
|
||||
* @param expect The expected output from that expression.
|
||||
* @return this object.
|
||||
*/
|
||||
public CS2030STest expect(String test, Object output, Object expect) {
|
||||
System.out.print(test);
|
||||
if ((expect == null && output == null) || output.equals(expect)) {
|
||||
ok();
|
||||
} else {
|
||||
fail();
|
||||
System.out.println(" expected: " + expect);
|
||||
System.out.println(" got this: " + output);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if a given supplier produces a given object.
|
||||
*
|
||||
* @param <T> The type of object the given task will produce.
|
||||
* @param test A description of the test.
|
||||
* @param task The task to run.
|
||||
* @param expect The expected output from that expression.
|
||||
* @return this object.
|
||||
*/
|
||||
public <T> CS2030STest expect(String test, Supplier<T> task, Object expect) {
|
||||
System.out.print(test);
|
||||
try {
|
||||
T output = CompletableFuture.supplyAsync(() -> {
|
||||
try {
|
||||
return task.get();
|
||||
} catch (Throwable e) {
|
||||
// shouldn't reach here
|
||||
fail();
|
||||
System.out.println(" with exception: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
).get(1, TimeUnit.SECONDS);
|
||||
if ((expect == null && output == null) || output.equals(expect)) {
|
||||
ok();
|
||||
} else {
|
||||
fail();
|
||||
System.out.println(" expected: " + expect);
|
||||
System.out.println(" got this: " + output);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
fail();
|
||||
System.out.println(" with exception: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if a given producer returns a value. Wrapper around expect(..)
|
||||
* to simplify caller.
|
||||
*
|
||||
* @param <T> The type of object the given task will produce.
|
||||
* @param test A description of the test.
|
||||
* @param task The task to run.
|
||||
* @param expect The expected output from that expression.
|
||||
* @return this object.
|
||||
*/
|
||||
public <T> CS2030STest expectReturn(String test, Supplier<T> task, Object expect) {
|
||||
return this.expect(test + " returns " + expect, task, expect);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if an expression throws an exception.
|
||||
*
|
||||
* @param test A description of the test.
|
||||
* @param task A lambda expression of the expression.
|
||||
* @param expectedE A exception instance of the same type as the expected one.
|
||||
* @return this object.
|
||||
*/
|
||||
public CS2030STest expectException(String test, Runnable task, Exception expectedE) {
|
||||
System.out.print(test + " throws " + expectedE.getClass().getSimpleName());
|
||||
boolean gotException = false;
|
||||
try {
|
||||
task.run();
|
||||
} catch (Throwable e) {
|
||||
if (e.getClass().equals(expectedE.getClass())) {
|
||||
gotException = true;
|
||||
}
|
||||
}
|
||||
if (gotException) {
|
||||
ok();
|
||||
} else {
|
||||
fail();
|
||||
System.out.println(" did not catch expected exception " + expectedE.getClass());
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if an expression compiles with/without error.
|
||||
*
|
||||
* @param test A description of the test.
|
||||
* @param statement The java statement to compile
|
||||
* @param success Whether the statement is expected to compile or not
|
||||
* (true if yes; false otherwise)
|
||||
* @return this object.
|
||||
*/
|
||||
public CS2030STest expectCompile(String test, String statement, boolean success) {
|
||||
System.out.print(test);
|
||||
|
||||
class Code extends SimpleJavaFileObject {
|
||||
final String code;
|
||||
|
||||
Code(String code) {
|
||||
super(URI.create("string:///TestCompile.java"), Kind.SOURCE);
|
||||
this.code = "class TestCompile {void test(){\n " + code + ";\n}}";
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getCharContent(boolean ignoreEncodingErrors) {
|
||||
return code;
|
||||
}
|
||||
}
|
||||
|
||||
boolean noError = ToolProvider
|
||||
.getSystemJavaCompiler()
|
||||
.getTask(null, null, new DiagnosticCollector<>(), null, null,
|
||||
List.of(new Code(statement)))
|
||||
.call();
|
||||
|
||||
if (noError != success) {
|
||||
fail();
|
||||
if (!success) {
|
||||
System.out.println(" expected compilation error but it compiles fine.");
|
||||
} else {
|
||||
System.out.println(" expected the statement to compile without errors but it does not.");
|
||||
}
|
||||
} else {
|
||||
ok();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
11
cs2030s/PE2/plab0124/MyTest.java
Normal file
11
cs2030s/PE2/plab0124/MyTest.java
Normal file
@ -0,0 +1,11 @@
|
||||
import cs2030s.fp.Saveable;
|
||||
import cs2030s.fp.Immutator;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.List;
|
||||
|
||||
class MyTest {
|
||||
public static void main(String[] args){
|
||||
Immutator<Saveable<Integer>, Object> hash = o -> Saveable.<Integer>of(o.hashCode() + 10);
|
||||
Saveable.<Number>of(4).flatMap2(hash);
|
||||
}
|
||||
}
|
43
cs2030s/PE2/plab0124/Pair.java
Normal file
43
cs2030s/PE2/plab0124/Pair.java
Normal file
@ -0,0 +1,43 @@
|
||||
/**
|
||||
* CS2030S PE2
|
||||
* AY2022/23 Semester 2.
|
||||
*
|
||||
* @author A0253252M
|
||||
**/
|
||||
class Pair<T,S> {
|
||||
private T fst;
|
||||
private S snd;
|
||||
public Pair(T fst, S snd) {
|
||||
this.fst = fst;
|
||||
this.snd = snd;
|
||||
}
|
||||
public T getFst() {
|
||||
return this.fst;
|
||||
}
|
||||
public S getSnd() {
|
||||
return this.snd;
|
||||
}
|
||||
public void setFst(T fst) {
|
||||
this.fst = fst;
|
||||
}
|
||||
public void setSnd(S snd) {
|
||||
this.snd = snd;
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return "(" + this.fst + ", " + this.snd + ")";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if(!(obj instanceof Pair<?,?>)) {
|
||||
return false;
|
||||
}
|
||||
Pair<?,?> pr = (Pair<?,?>) obj;
|
||||
return this.fst.equals(pr.fst) &&
|
||||
this.snd.equals(pr.snd);
|
||||
}
|
||||
}
|
43
cs2030s/PE2/plab0124/Streaming.java
Normal file
43
cs2030s/PE2/plab0124/Streaming.java
Normal file
@ -0,0 +1,43 @@
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* CS2030S PE2
|
||||
* AY2022/23 Semester 1.
|
||||
*
|
||||
* @author A0253252M
|
||||
**/
|
||||
|
||||
public class Streaming {
|
||||
public static Stream<Integer> evenTriangular(int n) {
|
||||
return Stream.iterate(1, i -> i + 1)
|
||||
.map(i -> i * (i + 1) / 2)
|
||||
.filter(i -> i % 2 == 0)
|
||||
.limit(n);
|
||||
}
|
||||
|
||||
// return a list of positive divisors for n
|
||||
// go down from n,
|
||||
public static boolean isPerfect(int n) {
|
||||
return Stream.iterate(n - 1, i -> i - 1)
|
||||
.takeWhile(i -> i > 0)
|
||||
.filter(i -> n % i == 0)
|
||||
.reduce(0, (x, y) -> x + y) == n;
|
||||
}
|
||||
|
||||
public static List<Integer> allPerfect(int start, int end) {
|
||||
return Stream.iterate(start, i -> i + 1)
|
||||
.takeWhile(i -> i <= end)
|
||||
.filter(i -> isPerfect(i))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static <T> List<T> decode(Stream<Pair<Integer, T>> stream) {
|
||||
return stream.flatMap(p ->
|
||||
Stream.generate(() -> p.getSnd()).limit(p.getFst())
|
||||
)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
100
cs2030s/PE2/plab0124/Test1.java
Normal file
100
cs2030s/PE2/plab0124/Test1.java
Normal file
@ -0,0 +1,100 @@
|
||||
import cs2030s.fp.Saveable;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
class Test1 {
|
||||
public static void main(String[] args) {
|
||||
CS2030STest i = new CS2030STest();
|
||||
|
||||
i.expectCompile("Saveable<String> u = Saveable.of(\"PE2\") compiles",
|
||||
"cs2030s.fp.Saveable<String> u = cs2030s.fp.Saveable.of(\"PE2\")",
|
||||
true);
|
||||
|
||||
i.expectReturn("Saveable.of(\"PE2\").toString()",
|
||||
() -> Saveable.of("PE2").toString(),
|
||||
"Saveable[PE2]");
|
||||
|
||||
i.expectReturn("Saveable.of(\"PE2\").map(x -> x + \"!\");",
|
||||
() -> Saveable.of("PE2").map(x -> x + "!").toString(),
|
||||
"Saveable[PE2!]");
|
||||
|
||||
i.expectReturn("Saveable.of(\"PE2\").map(x -> x + \"!\").map(x -> x + \"?\");",
|
||||
() -> Saveable.of("PE2").map(x -> x + "!").map(x -> x + "?").toString(),
|
||||
"Saveable[PE2!?]");
|
||||
|
||||
i.expectReturn("Saveable.of(\"PE2\").map(x -> x + \"!\").undo()",
|
||||
() -> Saveable.of("PE2").map(x -> x + "!").undo().toString(),
|
||||
"Saveable[PE2]");
|
||||
|
||||
i.expectReturn("Saveable.of(\"PE2\").map(x -> x + \"!\").undo().map(x -> x + \"?\")",
|
||||
() -> Saveable.of("PE2").map(x -> x + "!").undo().map(x -> x + "?").toString(),
|
||||
"Saveable[PE2?]");
|
||||
|
||||
i.expectReturn("Saveable.of(\"PE2\").map(x -> x + \"!\").undo().map(x -> x + \"?\").undo()",
|
||||
() -> Saveable.of("PE2").map(x -> x + "!").undo().map(x -> x + "?").undo().toString(),
|
||||
"Saveable[PE2]");
|
||||
|
||||
i.expectReturn("Saveable.of(\"PE2\").map(x -> x + \"!\").map(x -> x + \"?\").undo()",
|
||||
() -> Saveable.of("PE2").map(x -> x + "!").map(x -> x + "?").undo().toString(),
|
||||
"Saveable[PE2!]");
|
||||
|
||||
i.expectReturn("Saveable.of(\"PE2\").map(x -> x + \"!\").map(x -> x + \"?\").undo().undo()",
|
||||
() -> Saveable.of("PE2").map(x -> x + "!").map(x -> x + "?").undo().undo().toString(),
|
||||
"Saveable[PE2]");
|
||||
|
||||
i.expectException("Saveable.of(\"PE2\").map(x -> x + \"!\").map(x -> x + \"?\")" +
|
||||
".undo().undo().undo()",
|
||||
() -> Saveable.of("PE2").map(x -> x + "!").map(x -> x + "?").undo().undo().undo(),
|
||||
new NoSuchElementException());
|
||||
|
||||
i.expectException("Saveable.of(\"PE2\").undo()",
|
||||
() -> Saveable.of("PE2").undo(),
|
||||
new NoSuchElementException());
|
||||
|
||||
// with redo
|
||||
i.expectReturn("Saveable.of(\"PE2\").map(x -> x + \"!\").undo()",
|
||||
() -> Saveable.of("PE2").map(x -> x + "!").undo().toString(),
|
||||
"Saveable[PE2]");
|
||||
|
||||
i.expectReturn("Saveable.of(\"PE2\").map(x -> x + \"!\").undo().redo()",
|
||||
() -> Saveable.of("PE2").map(x -> x + "!").undo().redo().toString(),
|
||||
"Saveable[PE2!]");
|
||||
|
||||
i.expectReturn("Saveable.of(\"PE2\").map(x -> x + \"!\").undo().redo().map(x -> x + \"?\")",
|
||||
() -> Saveable.of("PE2").map(x -> x + "!").undo().redo().map(x -> x + "?").toString(),
|
||||
"Saveable[PE2!?]");
|
||||
|
||||
i.expectException("Saveable.of(\"PE2\").map(x -> x + \"!\").undo().map(x -> x + \"?\")" +
|
||||
".redo()",
|
||||
() -> Saveable.of("PE2").map(x -> x + "!").undo().map(x -> x + "?").redo(),
|
||||
new NoSuchElementException());
|
||||
|
||||
i.expectReturn("Saveable.of(\"PE2\").map(x -> x + \"!\").map(x -> x + \"?\").undo().redo()",
|
||||
() -> Saveable.of("PE2").map(x -> x + "!").map(x -> x + "?").undo().redo().toString(),
|
||||
"Saveable[PE2!?]");
|
||||
|
||||
i.expectReturn("Saveable.of(\"PE2\").map(x -> x + \"!\").undo().map(x -> x + \"?\").undo().redo()",
|
||||
() -> Saveable.of("PE2").map(x -> x + "!").undo().map(x -> x + "?").undo().redo().toString(),
|
||||
"Saveable[PE2?]");
|
||||
|
||||
i.expectReturn("Saveable.of(\"PE2\").map(x -> x + \"!\").map(x -> x + \"?\")" +
|
||||
".undo().undo().redo()",
|
||||
() -> Saveable.of("PE2").map(x -> x + "!").map(x -> x + "?").undo().undo().redo()
|
||||
.toString(),
|
||||
"Saveable[PE2!]");
|
||||
|
||||
i.expectReturn("Saveable.of(\"PE2\").map(x -> x + \"!\").map(x -> x + \"?\")" +
|
||||
".undo().undo().redo().redo()",
|
||||
() -> Saveable.of("PE2").map(x -> x + "!").map(x -> x + "?").undo().undo().redo().redo()
|
||||
.toString(),
|
||||
"Saveable[PE2!?]");
|
||||
|
||||
i.expectException("Saveable.of(\"PE2\").map(x -> x + \"!\").undo().redo().redo()",
|
||||
() -> Saveable.of("PE2").map(x -> x + "!").map(x -> x + "?").undo().redo().redo(),
|
||||
new NoSuchElementException());
|
||||
|
||||
i.expectCompile("Saveable<Number> x = Saveable.<Number>of(4).map(hash); compiles",
|
||||
"cs2030s.fp.Immutator<Integer,Object> hash = o -> o.hashCode();\n" +
|
||||
"cs2030s.fp.Saveable<Number> x = cs2030s.fp.Saveable.<Number>of(4).map(hash);",
|
||||
true);
|
||||
}
|
||||
}
|
27
cs2030s/PE2/plab0124/Test1.jsh
Normal file
27
cs2030s/PE2/plab0124/Test1.jsh
Normal file
@ -0,0 +1,27 @@
|
||||
import cs2030s.fp.Immutator
|
||||
import cs2030s.fp.Saveable
|
||||
|
||||
Saveable<String> u = Saveable.of("PE2")
|
||||
u.map(x -> x + "!")
|
||||
u.map(x -> x + "!").map(x -> x + "?")
|
||||
|
||||
u.map(x -> x + "!").undo()
|
||||
u.map(x -> x + "!").undo().map(x -> x + "?")
|
||||
u.map(x -> x + "!").map(x -> x + "?").undo()
|
||||
u.map(x -> x + "!").undo().map(x -> x + "?").undo()
|
||||
u.map(x -> x + "!").map(x -> x + "?").undo().undo()
|
||||
u.map(x -> x + "!").map(x -> x + "?").undo().undo().undo()
|
||||
u.undo()
|
||||
|
||||
u.map(x -> x + "!").undo()
|
||||
u.map(x -> x + "!").undo().redo()
|
||||
u.map(x -> x + "!").undo().redo().map(x -> x + "?")
|
||||
u.map(x -> x + "!").undo().map(x -> x + "?").redo()
|
||||
u.map(x -> x + "!").map(x -> x + "?").undo().redo()
|
||||
u.map(x -> x + "!").undo().map(x -> x + "?").undo().redo()
|
||||
u.map(x -> x + "!").map(x -> x + "?").undo().undo().redo()
|
||||
u.map(x -> x + "!").map(x -> x + "?").undo().undo().redo().redo()
|
||||
u.map(x -> x + "!").undo().redo().redo()
|
||||
|
||||
Immutator<Integer,Object> hash = o -> o.hashCode();
|
||||
Saveable<Number> x = Saveable.<Number>of(4).map(hash); // should compile
|
36
cs2030s/PE2/plab0124/Test2.java
Normal file
36
cs2030s/PE2/plab0124/Test2.java
Normal file
@ -0,0 +1,36 @@
|
||||
import cs2030s.fp.Saveable;
|
||||
|
||||
class Test2 {
|
||||
public static void main(String[] args) {
|
||||
CS2030STest i = new CS2030STest();
|
||||
|
||||
i.expectReturn("Saveable.of(10).equals(Saveable.of(10))",
|
||||
() -> Saveable.of(10).equals(Saveable.of(10)),
|
||||
true);
|
||||
|
||||
i.expectReturn("Saveable.of(10).map(x -> x + 4).equals(Saveable.of(14))",
|
||||
() -> Saveable.of(10).map(x -> x + 4).equals(Saveable.of(14)),
|
||||
true);
|
||||
i.expectReturn("Saveable.of(10).map(x -> x + 4).equals(Saveable.of(10).map(x -> x + 4))",
|
||||
() -> Saveable.of(10).map(x -> x + 4).equals(Saveable.of(10).map(x -> x + 4)),
|
||||
true);
|
||||
i.expectReturn("Saveable.of(10).map(x -> x + 4).undo().equals(Saveable.of(14))",
|
||||
() -> Saveable.of(10).map(x -> x + 4).undo().equals(Saveable.of(14)),
|
||||
false);
|
||||
i.expectReturn("Saveable.of(10).map(x -> x + 4).undo().equals(Saveable.of(10).map(x -> x + 4)" +
|
||||
".undo())",
|
||||
() -> Saveable.of(10).map(x -> x + 4).undo().equals(Saveable.of(10).map(x -> x + 4).undo()),
|
||||
true);
|
||||
i.expectReturn("Saveable.of(10).map(x -> x + 4).undo().redo().equals(Saveable.of(10)" +
|
||||
".map(x -> x + 4))",
|
||||
() -> Saveable.of(10).map(x -> x + 4).undo().redo().equals(Saveable.of(10).map(x -> x + 4)),
|
||||
true);
|
||||
i.expectReturn("Saveable.of(10).map(x -> x + 4).map(x -> x).equals(Saveable.of(4)" +
|
||||
".map(x -> x + 10)",
|
||||
() -> Saveable.of(10).map(x -> x + 4).equals(Saveable.of(4).map(x -> x + 10)),
|
||||
true);
|
||||
i.expectReturn("Saveable.of(\"hi\").equals(Saveable.of(new String(\"hi\")))",
|
||||
() -> Saveable.of("hi").equals(Saveable.of(new String("hi"))),
|
||||
true);
|
||||
}
|
||||
}
|
11
cs2030s/PE2/plab0124/Test2.jsh
Normal file
11
cs2030s/PE2/plab0124/Test2.jsh
Normal file
@ -0,0 +1,11 @@
|
||||
import cs2030s.fp.Saveable
|
||||
|
||||
Saveable<Integer> u = Saveable.of(10)
|
||||
u.equals(u)
|
||||
u.map(x -> x + 4).equals(u.map(x -> x + 4))
|
||||
u.map(x -> x + 4).undo().equals(Saveable.of(14))
|
||||
u.map(x -> x + 4).undo().equals(u.map(x -> x + 4).undo())
|
||||
u.map(x -> x + 4).undo().redo().equals(u.map(x -> x + 4))
|
||||
u.map(x -> x + 4).equals(Saveable.of(4).map(x -> x + 10))
|
||||
|
||||
Saveable.of("hi").equals(Saveable.of(new String("hi")));
|
84
cs2030s/PE2/plab0124/Test3.java
Normal file
84
cs2030s/PE2/plab0124/Test3.java
Normal file
@ -0,0 +1,84 @@
|
||||
import cs2030s.fp.Immutator;
|
||||
import cs2030s.fp.Saveable;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
class Test3 {
|
||||
public static void main(String[] args) {
|
||||
CS2030STest i = new CS2030STest();
|
||||
|
||||
System.out.println("Immutator<Saveable<Integer>, Integer> f = " +
|
||||
"x -> Saveable.of(x).map(y -> y + 1).map(y -> y + 10);");
|
||||
Immutator<Saveable<Integer>, Integer> f =
|
||||
x -> Saveable.of(x).map(y -> y + 1).map(y -> y + 10);
|
||||
|
||||
i.expectReturn("Saveable.of(0).flatMap1(f)",
|
||||
() -> Saveable.of(0).flatMap1(f).toString(),
|
||||
"Saveable[11]");
|
||||
|
||||
i.expectReturn("Saveable.of(0).flatMap1(f).flatMap1(f)",
|
||||
() -> Saveable.of(0).flatMap1(f).flatMap1(f).toString(),
|
||||
"Saveable[22]");
|
||||
|
||||
i.expectReturn("Saveable.of(0).flatMap1(f).undo()",
|
||||
() -> Saveable.of(0).flatMap1(f).undo().toString(),
|
||||
"Saveable[1]");
|
||||
|
||||
i.expectReturn("Saveable.of(0).flatMap1(f).undo().undo()",
|
||||
() -> Saveable.of(0).flatMap1(f).undo().undo().toString(),
|
||||
"Saveable[0]");
|
||||
|
||||
i.expectReturn("Saveable.of(0).flatMap1(f).flatMap1(f).undo()",
|
||||
() -> Saveable.of(0).flatMap1(f).flatMap1(f).undo().toString(),
|
||||
"Saveable[12]");
|
||||
|
||||
i.expectReturn("Saveable.of(0).flatMap1(f).flatMap1(f).undo().undo()",
|
||||
() -> Saveable.of(0).flatMap1(f).flatMap1(f).undo().undo().toString(),
|
||||
"Saveable[11]");
|
||||
|
||||
i.expectException("Saveable.of(0).flatMap1(f).flatMap1(f).undo().undo().undo()",
|
||||
() -> Saveable.of(0).flatMap1(f).flatMap1(f).undo().undo().undo().toString(),
|
||||
new NoSuchElementException());
|
||||
|
||||
i.expectReturn("Saveable.of(0).flatMap2(f)",
|
||||
() -> Saveable.of(0).flatMap2(f).toString(),
|
||||
"Saveable[11]");
|
||||
|
||||
i.expectReturn("Saveable.of(0).flatMap2(f).flatMap2(f)",
|
||||
() -> Saveable.of(0).flatMap2(f).flatMap2(f).toString(),
|
||||
"Saveable[22]");
|
||||
|
||||
i.expectReturn("Saveable.of(0).flatMap2(f).undo()",
|
||||
() -> Saveable.of(0).flatMap2(f).undo().toString(),
|
||||
"Saveable[0]");
|
||||
i.expectException("Saveable.of(0).flatMap2(f).undo().undo()",
|
||||
() -> Saveable.of(0).flatMap2(f).undo().undo(),
|
||||
new NoSuchElementException());
|
||||
|
||||
i.expectReturn("Saveable.of(0).flatMap2(f).flatMap2(f).undo()",
|
||||
() -> Saveable.of(0).flatMap2(f).flatMap2(f).undo().toString(),
|
||||
"Saveable[11]");
|
||||
|
||||
i.expectReturn("Saveable.of(0).flatMap2(f).flatMap2(f).undo().undo()",
|
||||
() -> Saveable.of(0).flatMap2(f).flatMap2(f).undo().undo().toString(),
|
||||
"Saveable[0]");
|
||||
|
||||
i.expectException("Saveable.of(0).flatMap2(f).flatMap2(f).undo().undo().undo()",
|
||||
() -> Saveable.of(0).flatMap2(f).flatMap2(f).undo().undo().undo().toString(),
|
||||
new NoSuchElementException());
|
||||
|
||||
System.out.println("Immutator<Saveable<Integer>, Object> hash = " +
|
||||
"o -> Saveable.<Integer>of(o.hashCode() + 10);");
|
||||
Immutator<Saveable<Integer>, Object> hash = o -> Saveable.<Integer>of(o.hashCode() + 10);
|
||||
|
||||
i.expectCompile("Saveable.<Number>of(4).flatMap1(hash);",
|
||||
"cs2030s.fp.Immutator<cs2030s.fp.Saveable<Integer>, Object> hash = " +
|
||||
"o -> cs2030s.fp.Saveable.<Integer>of(o.hashCode() + 10);\n" +
|
||||
"cs2030s.fp.Saveable.<Number>of(4).flatMap1(hash);",
|
||||
true);
|
||||
i.expectCompile("Saveable.<Number>of(4).flatMap2(hash);",
|
||||
"cs2030s.fp.Immutator<cs2030s.fp.Saveable<Integer>, Object> hash = " +
|
||||
"o -> cs2030s.fp.Saveable.<Integer>of(o.hashCode() + 10);\n" +
|
||||
"cs2030s.fp.Saveable.<Number>of(4).flatMap2(hash);",
|
||||
true);
|
||||
}
|
||||
}
|
26
cs2030s/PE2/plab0124/Test3.jsh
Normal file
26
cs2030s/PE2/plab0124/Test3.jsh
Normal file
@ -0,0 +1,26 @@
|
||||
import cs2030s.fp.Immutator;
|
||||
import cs2030s.fp.Saveable;
|
||||
|
||||
Immutator<Saveable<Integer>, Integer> f = x -> Saveable.of(x).map(y -> y + 1).map(y -> y + 10);
|
||||
Saveable<Integer> zero = Saveable.of(0)
|
||||
zero.flatMap1(f)
|
||||
zero.flatMap1(f).flatMap1(f)
|
||||
|
||||
zero.flatMap1(f).undo()
|
||||
zero.flatMap1(f).undo().undo()
|
||||
zero.flatMap1(f).flatMap1(f).undo()
|
||||
zero.flatMap1(f).flatMap1(f).undo().undo()
|
||||
zero.flatMap1(f).flatMap1(f).undo().undo().undo()
|
||||
|
||||
zero.flatMap2(f)
|
||||
zero.flatMap2(f).flatMap2(f)
|
||||
|
||||
zero.flatMap2(f).undo()
|
||||
zero.flatMap2(f).undo().undo()
|
||||
zero.flatMap2(f).flatMap2(f).undo()
|
||||
zero.flatMap2(f).flatMap2(f).undo().undo()
|
||||
zero.flatMap2(f).flatMap2(f).undo().undo().undo()
|
||||
|
||||
Immutator<Saveable<Integer>, Object> hash = o -> Saveable.<Integer>of(o.hashCode() + 10);
|
||||
Saveable.<Number>of(4).flatMap1(hash); // should compile
|
||||
Saveable.<Number>of(4).flatMap2(hash); // should compile
|
20
cs2030s/PE2/plab0124/Test4.java
Normal file
20
cs2030s/PE2/plab0124/Test4.java
Normal file
@ -0,0 +1,20 @@
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.List;
|
||||
|
||||
class Test4 {
|
||||
public static void main(String[] args) {
|
||||
CS2030STest i = new CS2030STest();
|
||||
|
||||
i.expectReturn("Streaming.evenTriangular(5).count()",
|
||||
() -> Streaming.evenTriangular(5).count(),
|
||||
5L);
|
||||
|
||||
i.expectReturn("Streaming.evenTriangular(5).collect(Collectors.toList())",
|
||||
() -> Streaming.evenTriangular(5).collect(Collectors.toList()),
|
||||
List.of(6,10,28,36,66));
|
||||
|
||||
i.expectReturn("Streaming.evenTriangular(10).collect(Collectors.toList())",
|
||||
() -> Streaming.evenTriangular(10).collect(Collectors.toList()),
|
||||
List.of(6,10,28,36,66,78,120,136,190,210));
|
||||
}
|
||||
}
|
8
cs2030s/PE2/plab0124/Test4.jsh
Normal file
8
cs2030s/PE2/plab0124/Test4.jsh
Normal file
@ -0,0 +1,8 @@
|
||||
/open Pair.java
|
||||
/open Streaming.java
|
||||
|
||||
Streaming.evenTriangular(5).count();
|
||||
Streaming.evenTriangular(5).forEach(System.out::println);
|
||||
Streaming.evenTriangular(5).toArray();
|
||||
Streaming.evenTriangular(10).forEach(System.out::println);
|
||||
Streaming.evenTriangular(5).collect(Collectors.toList());
|
56
cs2030s/PE2/plab0124/Test5.java
Normal file
56
cs2030s/PE2/plab0124/Test5.java
Normal file
@ -0,0 +1,56 @@
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.List;
|
||||
|
||||
class Test5 {
|
||||
public static void main(String[] args) {
|
||||
CS2030STest i = new CS2030STest();
|
||||
|
||||
i.expectReturn("Streaming.isPerfect(4)",
|
||||
() -> Streaming.isPerfect(4),
|
||||
false);
|
||||
|
||||
i.expectReturn("Streaming.isPerfect(5)",
|
||||
() -> Streaming.isPerfect(5),
|
||||
false);
|
||||
|
||||
i.expectReturn("Streaming.isPerfect(6)",
|
||||
() -> Streaming.isPerfect(6),
|
||||
true);
|
||||
|
||||
i.expectReturn("Streaming.isPerfect(7)",
|
||||
() -> Streaming.isPerfect(7),
|
||||
false);
|
||||
|
||||
i.expectReturn("Streaming.isPerfect(8)",
|
||||
() -> Streaming.isPerfect(8),
|
||||
false);
|
||||
|
||||
i.expectReturn("Streaming.isPerfect(26)",
|
||||
() -> Streaming.isPerfect(26),
|
||||
false);
|
||||
|
||||
i.expectReturn("Streaming.isPerfect(27)",
|
||||
() -> Streaming.isPerfect(27),
|
||||
false);
|
||||
|
||||
i.expectReturn("Streaming.isPerfect(28)",
|
||||
() -> Streaming.isPerfect(28),
|
||||
true);
|
||||
|
||||
i.expectReturn("Streaming.isPerfect(29)",
|
||||
() -> Streaming.isPerfect(29),
|
||||
false);
|
||||
|
||||
i.expectReturn("Streaming.isPerfect(30)",
|
||||
() -> Streaming.isPerfect(30),
|
||||
false);
|
||||
|
||||
i.expectReturn("Streaming.allPerfect(1, 10)",
|
||||
() -> Streaming.allPerfect(1, 10),
|
||||
List.of(6));
|
||||
|
||||
i.expectReturn("Streaming.allPerfect(1, 100)",
|
||||
() -> Streaming.allPerfect(1, 100),
|
||||
List.of(6, 28));
|
||||
}
|
||||
}
|
17
cs2030s/PE2/plab0124/Test5.jsh
Normal file
17
cs2030s/PE2/plab0124/Test5.jsh
Normal file
@ -0,0 +1,17 @@
|
||||
/open Pair.java
|
||||
/open Streaming.java
|
||||
|
||||
Streaming.isPerfect(4);
|
||||
Streaming.isPerfect(5);
|
||||
Streaming.isPerfect(6);
|
||||
Streaming.isPerfect(7);
|
||||
Streaming.isPerfect(8);
|
||||
|
||||
Streaming.isPerfect(26);
|
||||
Streaming.isPerfect(27);
|
||||
Streaming.isPerfect(28);
|
||||
Streaming.isPerfect(29);
|
||||
Streaming.isPerfect(30);
|
||||
|
||||
Streaming.allPerfect(1, 10);
|
||||
Streaming.allPerfect(1, 100);
|
52
cs2030s/PE2/plab0124/Test6.jsh
Normal file
52
cs2030s/PE2/plab0124/Test6.jsh
Normal file
@ -0,0 +1,52 @@
|
||||
/open Pair.java
|
||||
/open Streaming.java
|
||||
|
||||
List<Integer> intList1 = List.of(
|
||||
1, 1, 1, 2, 2, 1, 1, 1, 1, 4, 3, 3
|
||||
)
|
||||
List<Integer> intList2 = List.of(
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
|
||||
)
|
||||
List<String> strList1 = List.of(
|
||||
"A", "A", "A", "B", "B", "A",
|
||||
"A", "A", "A", "R", "Z", "Z"
|
||||
)
|
||||
List<String> strList2 = List.of(
|
||||
"A", "A", "A", "A", "A", "A",
|
||||
"A", "A", "A", "A", "A", "A"
|
||||
)
|
||||
List<Pair<Integer,Integer>> pairLst1 = List.of(
|
||||
new Pair<Integer, Integer>(3, 1),
|
||||
new Pair<Integer, Integer>(2, 2),
|
||||
new Pair<Integer, Integer>(4, 1),
|
||||
new Pair<Integer, Integer>(1, 4),
|
||||
new Pair<Integer, Integer>(2, 3)
|
||||
)
|
||||
List<Pair<Integer,Integer>> pairLst2 = List.of(
|
||||
new Pair<Integer, Integer>(12, 1)
|
||||
)
|
||||
List<Pair<Integer,String>> pairLst3 = List.of(
|
||||
new Pair<Integer, String>(3, "A"),
|
||||
new Pair<Integer, String>(2, "B"),
|
||||
new Pair<Integer, String>(4, "A"),
|
||||
new Pair<Integer, String>(1, "R"),
|
||||
new Pair<Integer, String>(2, "Z")
|
||||
)
|
||||
List<Pair<Integer,String>> pairLst4 = List.of(
|
||||
new Pair<Integer, String>(12, "A")
|
||||
)
|
||||
|
||||
Streaming.decode(pairLst1.stream())
|
||||
Streaming.decode(pairLst2.stream())
|
||||
Streaming.decode(pairLst3.stream())
|
||||
Streaming.decode(pairLst4.stream())
|
||||
|
||||
Streaming.decode(pairLst1.stream()).equals(intList1)
|
||||
Streaming.decode(pairLst2.stream()).equals(intList2)
|
||||
Streaming.decode(pairLst3.stream()).equals(strList1)
|
||||
Streaming.decode(pairLst4.stream()).equals(strList2)
|
||||
|
||||
Streaming.decode(pairLst1.stream()).equals(intList2)
|
||||
Streaming.decode(pairLst2.stream()).equals(intList1)
|
||||
Streaming.decode(pairLst3.stream()).equals(strList2)
|
||||
Streaming.decode(pairLst4.stream()).equals(strList1)
|
91
cs2030s/PE2/plab0124/Test7.java
Normal file
91
cs2030s/PE2/plab0124/Test7.java
Normal file
@ -0,0 +1,91 @@
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.List;
|
||||
|
||||
class Test7 {
|
||||
public static void main(String[] args) {
|
||||
CS2030STest i = new CS2030STest();
|
||||
|
||||
List<Integer> intList1 = List.of(
|
||||
1, 1, 1, 2, 2, 1, 1, 1, 1, 4, 3, 3
|
||||
);
|
||||
List<Integer> intList2 = List.of(
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
|
||||
);
|
||||
List<String> strList1 = List.of(
|
||||
"A", "A", "A", "B", "B", "A",
|
||||
"A", "A", "A", "R", "Z", "Z"
|
||||
);
|
||||
List<String> strList2 = List.of(
|
||||
"A", "A", "A", "A", "A", "A",
|
||||
"A", "A", "A", "A", "A", "A"
|
||||
);
|
||||
List<Pair<Integer,Integer>> pairLst1 = List.of(
|
||||
new Pair<Integer, Integer>(3, 1),
|
||||
new Pair<Integer, Integer>(2, 2),
|
||||
new Pair<Integer, Integer>(4, 1),
|
||||
new Pair<Integer, Integer>(1, 4),
|
||||
new Pair<Integer, Integer>(2, 3)
|
||||
);
|
||||
List<Pair<Integer,Integer>> pairLst2 = List.of(
|
||||
new Pair<Integer, Integer>(12, 1)
|
||||
);
|
||||
List<Pair<Integer,String>> pairLst3 = List.of(
|
||||
new Pair<Integer, String>(3, "A"),
|
||||
new Pair<Integer, String>(2, "B"),
|
||||
new Pair<Integer, String>(4, "A"),
|
||||
new Pair<Integer, String>(1, "R"),
|
||||
new Pair<Integer, String>(2, "Z")
|
||||
);
|
||||
List<Pair<Integer,String>> pairLst4 = List.of(
|
||||
new Pair<Integer, String>(12, "A")
|
||||
);
|
||||
|
||||
i.expectReturn("Streaming.decode(pairLst1.stream().parallel())",
|
||||
() -> Streaming.decode(pairLst1.stream().parallel()),
|
||||
intList1);
|
||||
|
||||
i.expectReturn("Streaming.decode(pairLst2.stream().parallel())",
|
||||
() -> Streaming.decode(pairLst2.stream().parallel()),
|
||||
intList2);
|
||||
|
||||
i.expectReturn("Streaming.decode(pairLst3.stream().parallel())",
|
||||
() -> Streaming.decode(pairLst3.stream().parallel()),
|
||||
strList1);
|
||||
|
||||
i.expectReturn("Streaming.decode(pairLst4.stream().parallel())",
|
||||
() -> Streaming.decode(pairLst4.stream().parallel()),
|
||||
strList2);
|
||||
|
||||
i.expectReturn("Streaming.decode(pairLst1.stream().parallel()).equals(intList1)",
|
||||
() -> Streaming.decode(pairLst1.stream().parallel()).equals(intList1),
|
||||
true);
|
||||
|
||||
i.expectReturn("Streaming.decode(pairLst2.stream().parallel()).equals(intList2)",
|
||||
() -> Streaming.decode(pairLst2.stream().parallel()).equals(intList2),
|
||||
true);
|
||||
|
||||
i.expectReturn("Streaming.decode(pairLst3.stream().parallel()).equals(strList1)",
|
||||
() -> Streaming.decode(pairLst3.stream().parallel()).equals(strList1),
|
||||
true);
|
||||
|
||||
i.expectReturn("Streaming.decode(pairLst4.stream().parallel()).equals(strList2)",
|
||||
() -> Streaming.decode(pairLst4.stream().parallel()).equals(strList2),
|
||||
true);
|
||||
|
||||
i.expectReturn("Streaming.decode(pairLst1.stream().parallel()).equals(intList2)",
|
||||
() -> Streaming.decode(pairLst1.stream().parallel()).equals(intList2),
|
||||
false);
|
||||
|
||||
i.expectReturn("Streaming.decode(pairLst2.stream().parallel()).equals(intList1)",
|
||||
() -> Streaming.decode(pairLst2.stream().parallel()).equals(intList1),
|
||||
false);
|
||||
|
||||
i.expectReturn("Streaming.decode(pairLst3.stream().parallel()).equals(strList2)",
|
||||
() -> Streaming.decode(pairLst3.stream().parallel()).equals(strList2),
|
||||
false);
|
||||
|
||||
i.expectReturn("Streaming.decode(pairLst4.stream().parallel()).equals(strList1)",
|
||||
() -> Streaming.decode(pairLst4.stream().parallel()).equals(strList1),
|
||||
false);
|
||||
}
|
||||
}
|
52
cs2030s/PE2/plab0124/Test7.jsh
Normal file
52
cs2030s/PE2/plab0124/Test7.jsh
Normal file
@ -0,0 +1,52 @@
|
||||
/open Pair.java
|
||||
/open Streaming.java
|
||||
|
||||
List<Integer> intList1 = List.of(
|
||||
1, 1, 1, 2, 2, 1, 1, 1, 1, 4, 3, 3
|
||||
)
|
||||
List<Integer> intList2 = List.of(
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
|
||||
)
|
||||
List<String> strList1 = List.of(
|
||||
"A", "A", "A", "B", "B", "A",
|
||||
"A", "A", "A", "R", "Z", "Z"
|
||||
)
|
||||
List<String> strList2 = List.of(
|
||||
"A", "A", "A", "A", "A", "A",
|
||||
"A", "A", "A", "A", "A", "A"
|
||||
)
|
||||
List<Pair<Integer,Integer>> pairLst1 = List.of(
|
||||
new Pair<Integer, Integer>(3, 1),
|
||||
new Pair<Integer, Integer>(2, 2),
|
||||
new Pair<Integer, Integer>(4, 1),
|
||||
new Pair<Integer, Integer>(1, 4),
|
||||
new Pair<Integer, Integer>(2, 3)
|
||||
)
|
||||
List<Pair<Integer,Integer>> pairLst2 = List.of(
|
||||
new Pair<Integer, Integer>(12, 1)
|
||||
)
|
||||
List<Pair<Integer,String>> pairLst3 = List.of(
|
||||
new Pair<Integer, String>(3, "A"),
|
||||
new Pair<Integer, String>(2, "B"),
|
||||
new Pair<Integer, String>(4, "A"),
|
||||
new Pair<Integer, String>(1, "R"),
|
||||
new Pair<Integer, String>(2, "Z")
|
||||
)
|
||||
List<Pair<Integer,String>> pairLst4 = List.of(
|
||||
new Pair<Integer, String>(12, "A")
|
||||
)
|
||||
|
||||
Streaming.decode(pairLst1.stream().parallel())
|
||||
Streaming.decode(pairLst2.stream().parallel())
|
||||
Streaming.decode(pairLst3.stream().parallel())
|
||||
Streaming.decode(pairLst4.stream().parallel())
|
||||
|
||||
Streaming.decode(pairLst1.stream().parallel()).equals(intList1)
|
||||
Streaming.decode(pairLst2.stream().parallel()).equals(intList2)
|
||||
Streaming.decode(pairLst3.stream().parallel()).equals(strList1)
|
||||
Streaming.decode(pairLst4.stream().parallel()).equals(strList2)
|
||||
|
||||
Streaming.decode(pairLst1.stream().parallel()).equals(intList2)
|
||||
Streaming.decode(pairLst2.stream().parallel()).equals(intList1)
|
||||
Streaming.decode(pairLst3.stream().parallel()).equals(strList2)
|
||||
Streaming.decode(pairLst4.stream().parallel()).equals(strList1)
|
20
cs2030s/PE2/plab0124/cs2030s/fp/Immutator.java
Normal file
20
cs2030s/PE2/plab0124/cs2030s/fp/Immutator.java
Normal file
@ -0,0 +1,20 @@
|
||||
package cs2030s.fp;
|
||||
|
||||
/**
|
||||
* Represent a function that immutate one value into another, possible of different types.
|
||||
* CS2030S
|
||||
* AY22/23 Semester 1
|
||||
*
|
||||
* @param <R> The type of the result value.
|
||||
* @param <P> The type of the input value.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface Immutator<R, P> {
|
||||
/**
|
||||
* The functional method to immutate the value p.
|
||||
*
|
||||
* @param p The input value.
|
||||
* @return The value after applying the given immutation on p.
|
||||
*/
|
||||
R invoke(P p);
|
||||
}
|
156
cs2030s/PE2/plab0124/cs2030s/fp/Saveable.java
Normal file
156
cs2030s/PE2/plab0124/cs2030s/fp/Saveable.java
Normal file
@ -0,0 +1,156 @@
|
||||
/**
|
||||
* CS2030S PE2
|
||||
* AY2022/23 Semester 1.
|
||||
*
|
||||
* @author A0253252M
|
||||
**/
|
||||
|
||||
package cs2030s.fp;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
/**
|
||||
* Saveable is a container which allows us to have an undo / redo history over the value in the box.
|
||||
*
|
||||
* @param <T> the type of the value in the box
|
||||
**/
|
||||
|
||||
public class Saveable<T> {
|
||||
/**
|
||||
* The history of changes made to T.
|
||||
**/
|
||||
List<T> list;
|
||||
|
||||
/**
|
||||
* The current position in history.
|
||||
**/
|
||||
int index = 0;
|
||||
|
||||
private Saveable(List<T> list, int index) {
|
||||
this.list = list;
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new Saveable of type T.
|
||||
* @param <T> The type of the value in Saveable
|
||||
* @param value The value to be stored in Saveable
|
||||
* @return The new Saveable created
|
||||
**/
|
||||
|
||||
public static <T> Saveable<T> of(T value) {
|
||||
return new Saveable<T>(List.of(value), 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps the value in Saveable and creates a "checkpoint".
|
||||
* This will allow for undo to be called on it.
|
||||
* @param mapper The function to modify the value in the Saveable
|
||||
* @return The new Saveable created with a undo history attached
|
||||
**/
|
||||
public Saveable<T> map(Immutator<? extends T, ? super T> mapper) {
|
||||
T newVal = mapper.invoke(this.get());
|
||||
|
||||
List<T> newList = new ArrayList<>();
|
||||
for (int i = 0; i <= this.index; i++) {
|
||||
newList.add(this.list.get(i));
|
||||
}
|
||||
|
||||
newList.add(newVal);
|
||||
return new Saveable<>(newList, this.index + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Undo's the last operation done on the saveable. If no previous history
|
||||
* exists, it throws an NoSuchElementException.
|
||||
*
|
||||
* @return The Saveable with the last map rolled back
|
||||
**/
|
||||
public Saveable<T> undo() {
|
||||
if (this.index <= 0) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
return new Saveable<>(this.list, this.index - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Goes back forward in time to undo the last undo. If no future history
|
||||
* exists, it throws a NoSuchElementException.
|
||||
*
|
||||
* @return The Saveable with the last undo rolled back
|
||||
**/
|
||||
public Saveable<T> redo() {
|
||||
if (this.index >= this.list.size() - 1) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
|
||||
return new Saveable<>(this.list, this.index + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Flatmap1 maps the value from T to Saveable. It keeps the
|
||||
* history of the Saveable returned by mapper
|
||||
*
|
||||
* @param mapper The function to map from type T to Saveable
|
||||
* @return The Saveable with the last undo rolled back
|
||||
**/
|
||||
public Saveable<T> flatMap1(Immutator<
|
||||
? extends Saveable<? extends T>,
|
||||
? super T> mapper) {
|
||||
|
||||
// This cast is ok, as it is casting ? extends Saveable to Saveable, which
|
||||
// is ok, and also ? extends T to T, which is also ok.
|
||||
@SuppressWarnings("unchecked")
|
||||
Saveable<T> result = (Saveable<T>) mapper.invoke(this.get());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flatmap2 maps the value from T to Saveable. It keeps the
|
||||
* history of original Saveable.
|
||||
*
|
||||
* @param mapper The function to map from type T to Saveable
|
||||
* @return The Saveable with the last undo rolled back
|
||||
**/
|
||||
public Saveable<T> flatMap2(Immutator<
|
||||
? extends Saveable<? extends T>,
|
||||
? super T> mapper) {
|
||||
|
||||
// This cast is ok, as it is casting ? extends Saveable to Saveable, which
|
||||
// is ok, and also ? extends T to T, which is also ok.
|
||||
@SuppressWarnings("unchecked")
|
||||
Saveable<T> result = (Saveable<T>) mapper.invoke(this.get());
|
||||
|
||||
Saveable<T> tmp = this.map(i -> result.get());
|
||||
return tmp;
|
||||
}
|
||||
|
||||
private T get() {
|
||||
return this.list.get(this.index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Saveable[" + this.get() + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o instanceof Saveable<?>) {
|
||||
Saveable<?> tmp = (Saveable<?>) o;
|
||||
if (tmp.get() == this.get()) {
|
||||
return true;
|
||||
}
|
||||
if (tmp.get().equals(this.get())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user