From 16e4bbca7367a0bfd38593aefb6d35c093b73bc6 Mon Sep 17 00:00:00 2001 From: Ruslan Sennov Date: Tue, 25 Aug 2015 18:55:40 +0300 Subject: [PATCH] Infinite loop in Function* fixed --- generator/Generator.scala | 32 ++++++++++++++++--- .../main/java/javaslang/CheckedFunction1.java | 15 +++++++-- .../main/java/javaslang/CheckedFunction2.java | 11 +++++-- .../main/java/javaslang/CheckedFunction3.java | 11 +++++-- .../main/java/javaslang/CheckedFunction4.java | 11 +++++-- .../main/java/javaslang/CheckedFunction5.java | 11 +++++-- .../main/java/javaslang/CheckedFunction6.java | 11 +++++-- .../main/java/javaslang/CheckedFunction7.java | 11 +++++-- .../main/java/javaslang/CheckedFunction8.java | 11 +++++-- src-gen/main/java/javaslang/Function1.java | 15 +++++++-- src-gen/main/java/javaslang/Function2.java | 11 +++++-- src-gen/main/java/javaslang/Function3.java | 11 +++++-- src-gen/main/java/javaslang/Function4.java | 11 +++++-- src-gen/main/java/javaslang/Function5.java | 11 +++++-- src-gen/main/java/javaslang/Function6.java | 11 +++++-- src-gen/main/java/javaslang/Function7.java | 11 +++++-- src-gen/main/java/javaslang/Function8.java | 11 +++++-- .../java/javaslang/CheckedFunction0Test.java | 9 ++++++ .../java/javaslang/CheckedFunction1Test.java | 9 ++++++ .../java/javaslang/CheckedFunction2Test.java | 9 ++++++ .../java/javaslang/CheckedFunction3Test.java | 9 ++++++ .../java/javaslang/CheckedFunction4Test.java | 9 ++++++ .../java/javaslang/CheckedFunction5Test.java | 9 ++++++ .../java/javaslang/CheckedFunction6Test.java | 9 ++++++ .../java/javaslang/CheckedFunction7Test.java | 9 ++++++ .../java/javaslang/CheckedFunction8Test.java | 9 ++++++ .../test/java/javaslang/Function0Test.java | 9 ++++++ .../test/java/javaslang/Function1Test.java | 9 ++++++ .../test/java/javaslang/Function2Test.java | 9 ++++++ .../test/java/javaslang/Function3Test.java | 9 ++++++ .../test/java/javaslang/Function4Test.java | 9 ++++++ .../test/java/javaslang/Function5Test.java | 9 ++++++ .../test/java/javaslang/Function6Test.java | 9 ++++++ .../test/java/javaslang/Function7Test.java | 9 ++++++ .../test/java/javaslang/Function8Test.java | 9 ++++++ 35 files changed, 326 insertions(+), 52 deletions(-) diff --git a/generator/Generator.scala b/generator/Generator.scala index 39aa494ed0..5d503da88d 100644 --- a/generator/Generator.scala +++ b/generator/Generator.scala @@ -505,12 +505,26 @@ def generateMainClasses(): Unit = { return ($className$fullGenerics & Memoized) Lazy.of($mappingFunction)::get; """ else if (i == 1) xs""" final Lazy forNull = Lazy.of($forNull); - final ${im.getType("java.util.Map")}<$generics, R> cache = new ${im.getType("java.util.concurrent.ConcurrentHashMap")}<>(); - return ($className$fullGenerics & Memoized) t1 -> (t1 == null) ? forNull.get() : cache.computeIfAbsent(t1, $mappingFunction); + final Object lock = new Object(); + final ${im.getType("java.util.Map")}<$generics, R> cache = new ${im.getType("java.util.HashMap")}<>(); + return ($className$fullGenerics & Memoized) t1 -> { + if (t1 == null) { + return forNull.get(); + } else { + synchronized (lock) { + return cache.computeIfAbsent(t1, $mappingFunction); + } + } + }; """ else xs""" - final ${im.getType("java.util.Map")}, R> cache = new ${im.getType("java.util.concurrent.ConcurrentHashMap")}<>(); + final Object lock = new Object(); + final ${im.getType("java.util.Map")}, R> cache = new ${im.getType("java.util.HashMap")}<>(); final ${checked.gen("Checked")}Function1, R> tupled = tupled(); - return ($className$fullGenerics & Memoized) ($params) -> cache.computeIfAbsent(Tuple.of($params), $mappingFunction); + return ($className$fullGenerics & Memoized) ($params) -> { + synchronized (lock) { + return cache.computeIfAbsent(Tuple.of($params), $mappingFunction); + } + }; """ } } @@ -759,6 +773,7 @@ def generateTestClasses(): Unit = { val test = im.getType("org.junit.Test") val assertThat = im.getStatic("org.assertj.core.api.Assertions.assertThat") + val recFuncF1 = if (i == 0) "11;" else s"i1 <= 0 ? i1 : $className.recurrent2.apply(${(1 to i).gen(j => s"i$j" + (j == 1).gen(s" - 1"))(", ")}) + 1;" def curriedType(max: Int, function: String): String = { if (max == 0) { @@ -885,6 +900,15 @@ def generateTestClasses(): Unit = { $assertThat(memo.isMemoized()).isTrue(); } + private static $name$i<${(1 to i + 1).gen(j => "Integer")(", ")}> recurrent1 = (${(1 to i).gen(j => s"i$j")(", ")}) -> $recFuncF1 + private static $name$i<${(1 to i + 1).gen(j => "Integer")(", ")}> recurrent2 = $className.recurrent1.memoized(); + + @$test + public void shouldCalculatedRecursively()${checked.gen(" throws Throwable")} { + assertThat(recurrent1.apply(${(1 to i).gen(j => "11")(", ")})).isEqualTo(11); + ${(i > 0).gen(s"assertThat(recurrent1.apply(${(1 to i).gen(j => "22")(", ")})).isEqualTo(22);")} + } + @$test public void shouldComposeWithAndThen() { final $name$i<$generics> f = ($functionArgs) -> null; diff --git a/src-gen/main/java/javaslang/CheckedFunction1.java b/src-gen/main/java/javaslang/CheckedFunction1.java index 690356f44d..31ed01c03b 100644 --- a/src-gen/main/java/javaslang/CheckedFunction1.java +++ b/src-gen/main/java/javaslang/CheckedFunction1.java @@ -9,9 +9,9 @@ G E N E R A T O R C R A F T E D \*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/ +import java.util.HashMap; import java.util.Map; import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; import javaslang.control.Try; /** @@ -139,8 +139,17 @@ default CheckedFunction1 memoized() { return this; } else { final Lazy forNull = Lazy.of(Try.of(() -> apply(null))::get); - final Map cache = new ConcurrentHashMap<>(); - return (CheckedFunction1 & Memoized) t1 -> (t1 == null) ? forNull.get() : cache.computeIfAbsent(t1, t -> Try.of(() -> this.apply(t)).get()); + final Object lock = new Object(); + final Map cache = new HashMap<>(); + return (CheckedFunction1 & Memoized) t1 -> { + if (t1 == null) { + return forNull.get(); + } else { + synchronized (lock) { + return cache.computeIfAbsent(t1, t -> Try.of(() -> this.apply(t)).get()); + } + } + }; } } diff --git a/src-gen/main/java/javaslang/CheckedFunction2.java b/src-gen/main/java/javaslang/CheckedFunction2.java index 07b619214e..f00693764e 100644 --- a/src-gen/main/java/javaslang/CheckedFunction2.java +++ b/src-gen/main/java/javaslang/CheckedFunction2.java @@ -9,9 +9,9 @@ G E N E R A T O R C R A F T E D \*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/ +import java.util.HashMap; import java.util.Map; import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; import javaslang.control.Try; /** @@ -147,9 +147,14 @@ default CheckedFunction2 memoized() { if (this instanceof Memoized) { return this; } else { - final Map, R> cache = new ConcurrentHashMap<>(); + final Object lock = new Object(); + final Map, R> cache = new HashMap<>(); final CheckedFunction1, R> tupled = tupled(); - return (CheckedFunction2 & Memoized) (t1, t2) -> cache.computeIfAbsent(Tuple.of(t1, t2), t -> Try.of(() -> tupled.apply(t)).get()); + return (CheckedFunction2 & Memoized) (t1, t2) -> { + synchronized (lock) { + return cache.computeIfAbsent(Tuple.of(t1, t2), t -> Try.of(() -> tupled.apply(t)).get()); + } + }; } } diff --git a/src-gen/main/java/javaslang/CheckedFunction3.java b/src-gen/main/java/javaslang/CheckedFunction3.java index 2396d93765..f69e4c12fb 100644 --- a/src-gen/main/java/javaslang/CheckedFunction3.java +++ b/src-gen/main/java/javaslang/CheckedFunction3.java @@ -9,9 +9,9 @@ G E N E R A T O R C R A F T E D \*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/ +import java.util.HashMap; import java.util.Map; import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; import javaslang.control.Try; /** @@ -167,9 +167,14 @@ default CheckedFunction3 memoized() { if (this instanceof Memoized) { return this; } else { - final Map, R> cache = new ConcurrentHashMap<>(); + final Object lock = new Object(); + final Map, R> cache = new HashMap<>(); final CheckedFunction1, R> tupled = tupled(); - return (CheckedFunction3 & Memoized) (t1, t2, t3) -> cache.computeIfAbsent(Tuple.of(t1, t2, t3), t -> Try.of(() -> tupled.apply(t)).get()); + return (CheckedFunction3 & Memoized) (t1, t2, t3) -> { + synchronized (lock) { + return cache.computeIfAbsent(Tuple.of(t1, t2, t3), t -> Try.of(() -> tupled.apply(t)).get()); + } + }; } } diff --git a/src-gen/main/java/javaslang/CheckedFunction4.java b/src-gen/main/java/javaslang/CheckedFunction4.java index 3e155cdc5c..21f1d09815 100644 --- a/src-gen/main/java/javaslang/CheckedFunction4.java +++ b/src-gen/main/java/javaslang/CheckedFunction4.java @@ -9,9 +9,9 @@ G E N E R A T O R C R A F T E D \*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/ +import java.util.HashMap; import java.util.Map; import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; import javaslang.control.Try; /** @@ -188,9 +188,14 @@ default CheckedFunction4 memoized() { if (this instanceof Memoized) { return this; } else { - final Map, R> cache = new ConcurrentHashMap<>(); + final Object lock = new Object(); + final Map, R> cache = new HashMap<>(); final CheckedFunction1, R> tupled = tupled(); - return (CheckedFunction4 & Memoized) (t1, t2, t3, t4) -> cache.computeIfAbsent(Tuple.of(t1, t2, t3, t4), t -> Try.of(() -> tupled.apply(t)).get()); + return (CheckedFunction4 & Memoized) (t1, t2, t3, t4) -> { + synchronized (lock) { + return cache.computeIfAbsent(Tuple.of(t1, t2, t3, t4), t -> Try.of(() -> tupled.apply(t)).get()); + } + }; } } diff --git a/src-gen/main/java/javaslang/CheckedFunction5.java b/src-gen/main/java/javaslang/CheckedFunction5.java index ccc2a4500e..569e4e6441 100644 --- a/src-gen/main/java/javaslang/CheckedFunction5.java +++ b/src-gen/main/java/javaslang/CheckedFunction5.java @@ -9,9 +9,9 @@ G E N E R A T O R C R A F T E D \*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/ +import java.util.HashMap; import java.util.Map; import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; import javaslang.control.Try; /** @@ -210,9 +210,14 @@ default CheckedFunction5 memoized() { if (this instanceof Memoized) { return this; } else { - final Map, R> cache = new ConcurrentHashMap<>(); + final Object lock = new Object(); + final Map, R> cache = new HashMap<>(); final CheckedFunction1, R> tupled = tupled(); - return (CheckedFunction5 & Memoized) (t1, t2, t3, t4, t5) -> cache.computeIfAbsent(Tuple.of(t1, t2, t3, t4, t5), t -> Try.of(() -> tupled.apply(t)).get()); + return (CheckedFunction5 & Memoized) (t1, t2, t3, t4, t5) -> { + synchronized (lock) { + return cache.computeIfAbsent(Tuple.of(t1, t2, t3, t4, t5), t -> Try.of(() -> tupled.apply(t)).get()); + } + }; } } diff --git a/src-gen/main/java/javaslang/CheckedFunction6.java b/src-gen/main/java/javaslang/CheckedFunction6.java index 4795a4c5e2..974d3c783b 100644 --- a/src-gen/main/java/javaslang/CheckedFunction6.java +++ b/src-gen/main/java/javaslang/CheckedFunction6.java @@ -9,9 +9,9 @@ G E N E R A T O R C R A F T E D \*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/ +import java.util.HashMap; import java.util.Map; import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; import javaslang.control.Try; /** @@ -233,9 +233,14 @@ default CheckedFunction6 memoized() { if (this instanceof Memoized) { return this; } else { - final Map, R> cache = new ConcurrentHashMap<>(); + final Object lock = new Object(); + final Map, R> cache = new HashMap<>(); final CheckedFunction1, R> tupled = tupled(); - return (CheckedFunction6 & Memoized) (t1, t2, t3, t4, t5, t6) -> cache.computeIfAbsent(Tuple.of(t1, t2, t3, t4, t5, t6), t -> Try.of(() -> tupled.apply(t)).get()); + return (CheckedFunction6 & Memoized) (t1, t2, t3, t4, t5, t6) -> { + synchronized (lock) { + return cache.computeIfAbsent(Tuple.of(t1, t2, t3, t4, t5, t6), t -> Try.of(() -> tupled.apply(t)).get()); + } + }; } } diff --git a/src-gen/main/java/javaslang/CheckedFunction7.java b/src-gen/main/java/javaslang/CheckedFunction7.java index f6081d0733..b4a8fd95c8 100644 --- a/src-gen/main/java/javaslang/CheckedFunction7.java +++ b/src-gen/main/java/javaslang/CheckedFunction7.java @@ -9,9 +9,9 @@ G E N E R A T O R C R A F T E D \*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/ +import java.util.HashMap; import java.util.Map; import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; import javaslang.control.Try; /** @@ -257,9 +257,14 @@ default CheckedFunction7 memoized() { if (this instanceof Memoized) { return this; } else { - final Map, R> cache = new ConcurrentHashMap<>(); + final Object lock = new Object(); + final Map, R> cache = new HashMap<>(); final CheckedFunction1, R> tupled = tupled(); - return (CheckedFunction7 & Memoized) (t1, t2, t3, t4, t5, t6, t7) -> cache.computeIfAbsent(Tuple.of(t1, t2, t3, t4, t5, t6, t7), t -> Try.of(() -> tupled.apply(t)).get()); + return (CheckedFunction7 & Memoized) (t1, t2, t3, t4, t5, t6, t7) -> { + synchronized (lock) { + return cache.computeIfAbsent(Tuple.of(t1, t2, t3, t4, t5, t6, t7), t -> Try.of(() -> tupled.apply(t)).get()); + } + }; } } diff --git a/src-gen/main/java/javaslang/CheckedFunction8.java b/src-gen/main/java/javaslang/CheckedFunction8.java index 6deba51916..2d0bb2d013 100644 --- a/src-gen/main/java/javaslang/CheckedFunction8.java +++ b/src-gen/main/java/javaslang/CheckedFunction8.java @@ -9,9 +9,9 @@ G E N E R A T O R C R A F T E D \*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/ +import java.util.HashMap; import java.util.Map; import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; import javaslang.control.Try; /** @@ -282,9 +282,14 @@ default CheckedFunction8 memoized() { if (this instanceof Memoized) { return this; } else { - final Map, R> cache = new ConcurrentHashMap<>(); + final Object lock = new Object(); + final Map, R> cache = new HashMap<>(); final CheckedFunction1, R> tupled = tupled(); - return (CheckedFunction8 & Memoized) (t1, t2, t3, t4, t5, t6, t7, t8) -> cache.computeIfAbsent(Tuple.of(t1, t2, t3, t4, t5, t6, t7, t8), t -> Try.of(() -> tupled.apply(t)).get()); + return (CheckedFunction8 & Memoized) (t1, t2, t3, t4, t5, t6, t7, t8) -> { + synchronized (lock) { + return cache.computeIfAbsent(Tuple.of(t1, t2, t3, t4, t5, t6, t7, t8), t -> Try.of(() -> tupled.apply(t)).get()); + } + }; } } diff --git a/src-gen/main/java/javaslang/Function1.java b/src-gen/main/java/javaslang/Function1.java index 97b9c152eb..fc538fb5d7 100644 --- a/src-gen/main/java/javaslang/Function1.java +++ b/src-gen/main/java/javaslang/Function1.java @@ -9,9 +9,9 @@ G E N E R A T O R C R A F T E D \*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/ +import java.util.HashMap; import java.util.Map; import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; /** @@ -139,8 +139,17 @@ default Function1 memoized() { return this; } else { final Lazy forNull = Lazy.of(() -> apply(null)); - final Map cache = new ConcurrentHashMap<>(); - return (Function1 & Memoized) t1 -> (t1 == null) ? forNull.get() : cache.computeIfAbsent(t1, this::apply); + final Object lock = new Object(); + final Map cache = new HashMap<>(); + return (Function1 & Memoized) t1 -> { + if (t1 == null) { + return forNull.get(); + } else { + synchronized (lock) { + return cache.computeIfAbsent(t1, this::apply); + } + } + }; } } diff --git a/src-gen/main/java/javaslang/Function2.java b/src-gen/main/java/javaslang/Function2.java index 211ba1921a..83b9facb60 100644 --- a/src-gen/main/java/javaslang/Function2.java +++ b/src-gen/main/java/javaslang/Function2.java @@ -9,9 +9,9 @@ G E N E R A T O R C R A F T E D \*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/ +import java.util.HashMap; import java.util.Map; import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; import java.util.function.BiFunction; /** @@ -147,9 +147,14 @@ default Function2 memoized() { if (this instanceof Memoized) { return this; } else { - final Map, R> cache = new ConcurrentHashMap<>(); + final Object lock = new Object(); + final Map, R> cache = new HashMap<>(); final Function1, R> tupled = tupled(); - return (Function2 & Memoized) (t1, t2) -> cache.computeIfAbsent(Tuple.of(t1, t2), tupled::apply); + return (Function2 & Memoized) (t1, t2) -> { + synchronized (lock) { + return cache.computeIfAbsent(Tuple.of(t1, t2), tupled::apply); + } + }; } } diff --git a/src-gen/main/java/javaslang/Function3.java b/src-gen/main/java/javaslang/Function3.java index b221777eef..aa8690b5b2 100644 --- a/src-gen/main/java/javaslang/Function3.java +++ b/src-gen/main/java/javaslang/Function3.java @@ -9,9 +9,9 @@ G E N E R A T O R C R A F T E D \*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/ +import java.util.HashMap; import java.util.Map; import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; /** * Represents a function with three arguments. @@ -166,9 +166,14 @@ default Function3 memoized() { if (this instanceof Memoized) { return this; } else { - final Map, R> cache = new ConcurrentHashMap<>(); + final Object lock = new Object(); + final Map, R> cache = new HashMap<>(); final Function1, R> tupled = tupled(); - return (Function3 & Memoized) (t1, t2, t3) -> cache.computeIfAbsent(Tuple.of(t1, t2, t3), tupled::apply); + return (Function3 & Memoized) (t1, t2, t3) -> { + synchronized (lock) { + return cache.computeIfAbsent(Tuple.of(t1, t2, t3), tupled::apply); + } + }; } } diff --git a/src-gen/main/java/javaslang/Function4.java b/src-gen/main/java/javaslang/Function4.java index d52d9b93c9..1445ecb64a 100644 --- a/src-gen/main/java/javaslang/Function4.java +++ b/src-gen/main/java/javaslang/Function4.java @@ -9,9 +9,9 @@ G E N E R A T O R C R A F T E D \*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/ +import java.util.HashMap; import java.util.Map; import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; /** * Represents a function with 4 arguments. @@ -187,9 +187,14 @@ default Function4 memoized() { if (this instanceof Memoized) { return this; } else { - final Map, R> cache = new ConcurrentHashMap<>(); + final Object lock = new Object(); + final Map, R> cache = new HashMap<>(); final Function1, R> tupled = tupled(); - return (Function4 & Memoized) (t1, t2, t3, t4) -> cache.computeIfAbsent(Tuple.of(t1, t2, t3, t4), tupled::apply); + return (Function4 & Memoized) (t1, t2, t3, t4) -> { + synchronized (lock) { + return cache.computeIfAbsent(Tuple.of(t1, t2, t3, t4), tupled::apply); + } + }; } } diff --git a/src-gen/main/java/javaslang/Function5.java b/src-gen/main/java/javaslang/Function5.java index 44a3884395..0ddd320e56 100644 --- a/src-gen/main/java/javaslang/Function5.java +++ b/src-gen/main/java/javaslang/Function5.java @@ -9,9 +9,9 @@ G E N E R A T O R C R A F T E D \*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/ +import java.util.HashMap; import java.util.Map; import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; /** * Represents a function with 5 arguments. @@ -209,9 +209,14 @@ default Function5 memoized() { if (this instanceof Memoized) { return this; } else { - final Map, R> cache = new ConcurrentHashMap<>(); + final Object lock = new Object(); + final Map, R> cache = new HashMap<>(); final Function1, R> tupled = tupled(); - return (Function5 & Memoized) (t1, t2, t3, t4, t5) -> cache.computeIfAbsent(Tuple.of(t1, t2, t3, t4, t5), tupled::apply); + return (Function5 & Memoized) (t1, t2, t3, t4, t5) -> { + synchronized (lock) { + return cache.computeIfAbsent(Tuple.of(t1, t2, t3, t4, t5), tupled::apply); + } + }; } } diff --git a/src-gen/main/java/javaslang/Function6.java b/src-gen/main/java/javaslang/Function6.java index a0e4c5dc3d..751bba4fc8 100644 --- a/src-gen/main/java/javaslang/Function6.java +++ b/src-gen/main/java/javaslang/Function6.java @@ -9,9 +9,9 @@ G E N E R A T O R C R A F T E D \*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/ +import java.util.HashMap; import java.util.Map; import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; /** * Represents a function with 6 arguments. @@ -232,9 +232,14 @@ default Function6 memoized() { if (this instanceof Memoized) { return this; } else { - final Map, R> cache = new ConcurrentHashMap<>(); + final Object lock = new Object(); + final Map, R> cache = new HashMap<>(); final Function1, R> tupled = tupled(); - return (Function6 & Memoized) (t1, t2, t3, t4, t5, t6) -> cache.computeIfAbsent(Tuple.of(t1, t2, t3, t4, t5, t6), tupled::apply); + return (Function6 & Memoized) (t1, t2, t3, t4, t5, t6) -> { + synchronized (lock) { + return cache.computeIfAbsent(Tuple.of(t1, t2, t3, t4, t5, t6), tupled::apply); + } + }; } } diff --git a/src-gen/main/java/javaslang/Function7.java b/src-gen/main/java/javaslang/Function7.java index ea5ae2e3cf..e9804b5974 100644 --- a/src-gen/main/java/javaslang/Function7.java +++ b/src-gen/main/java/javaslang/Function7.java @@ -9,9 +9,9 @@ G E N E R A T O R C R A F T E D \*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/ +import java.util.HashMap; import java.util.Map; import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; /** * Represents a function with 7 arguments. @@ -256,9 +256,14 @@ default Function7 memoized() { if (this instanceof Memoized) { return this; } else { - final Map, R> cache = new ConcurrentHashMap<>(); + final Object lock = new Object(); + final Map, R> cache = new HashMap<>(); final Function1, R> tupled = tupled(); - return (Function7 & Memoized) (t1, t2, t3, t4, t5, t6, t7) -> cache.computeIfAbsent(Tuple.of(t1, t2, t3, t4, t5, t6, t7), tupled::apply); + return (Function7 & Memoized) (t1, t2, t3, t4, t5, t6, t7) -> { + synchronized (lock) { + return cache.computeIfAbsent(Tuple.of(t1, t2, t3, t4, t5, t6, t7), tupled::apply); + } + }; } } diff --git a/src-gen/main/java/javaslang/Function8.java b/src-gen/main/java/javaslang/Function8.java index 1435332a3e..0aea256dba 100644 --- a/src-gen/main/java/javaslang/Function8.java +++ b/src-gen/main/java/javaslang/Function8.java @@ -9,9 +9,9 @@ G E N E R A T O R C R A F T E D \*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/ +import java.util.HashMap; import java.util.Map; import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; /** * Represents a function with 8 arguments. @@ -281,9 +281,14 @@ default Function8 memoized() { if (this instanceof Memoized) { return this; } else { - final Map, R> cache = new ConcurrentHashMap<>(); + final Object lock = new Object(); + final Map, R> cache = new HashMap<>(); final Function1, R> tupled = tupled(); - return (Function8 & Memoized) (t1, t2, t3, t4, t5, t6, t7, t8) -> cache.computeIfAbsent(Tuple.of(t1, t2, t3, t4, t5, t6, t7, t8), tupled::apply); + return (Function8 & Memoized) (t1, t2, t3, t4, t5, t6, t7, t8) -> { + synchronized (lock) { + return cache.computeIfAbsent(Tuple.of(t1, t2, t3, t4, t5, t6, t7, t8), tupled::apply); + } + }; } } diff --git a/src-gen/test/java/javaslang/CheckedFunction0Test.java b/src-gen/test/java/javaslang/CheckedFunction0Test.java index c81394d806..3766195075 100644 --- a/src-gen/test/java/javaslang/CheckedFunction0Test.java +++ b/src-gen/test/java/javaslang/CheckedFunction0Test.java @@ -80,6 +80,15 @@ public void shouldRecognizeMemoizedFunctions() { assertThat(memo.isMemoized()).isTrue(); } + private static CheckedFunction0 recurrent1 = () -> 11; + private static CheckedFunction0 recurrent2 = CheckedFunction0Test.recurrent1.memoized(); + + @Test + public void shouldCalculatedRecursively() throws Throwable { + assertThat(recurrent1.apply()).isEqualTo(11); + + } + @Test public void shouldComposeWithAndThen() { final CheckedFunction0 f = () -> null; diff --git a/src-gen/test/java/javaslang/CheckedFunction1Test.java b/src-gen/test/java/javaslang/CheckedFunction1Test.java index ecb6c15e4f..94c28d759d 100644 --- a/src-gen/test/java/javaslang/CheckedFunction1Test.java +++ b/src-gen/test/java/javaslang/CheckedFunction1Test.java @@ -108,6 +108,15 @@ public void shouldRecognizeMemoizedFunctions() { assertThat(memo.isMemoized()).isTrue(); } + private static CheckedFunction1 recurrent1 = (i1) -> i1 <= 0 ? i1 : CheckedFunction1Test.recurrent2.apply(i1 - 1) + 1; + private static CheckedFunction1 recurrent2 = CheckedFunction1Test.recurrent1.memoized(); + + @Test + public void shouldCalculatedRecursively() throws Throwable { + assertThat(recurrent1.apply(11)).isEqualTo(11); + assertThat(recurrent1.apply(22)).isEqualTo(22); + } + @Test public void shouldComposeWithAndThen() { final CheckedFunction1 f = (o1) -> null; diff --git a/src-gen/test/java/javaslang/CheckedFunction2Test.java b/src-gen/test/java/javaslang/CheckedFunction2Test.java index cc1e7b885b..ef14f28f8a 100644 --- a/src-gen/test/java/javaslang/CheckedFunction2Test.java +++ b/src-gen/test/java/javaslang/CheckedFunction2Test.java @@ -114,6 +114,15 @@ public void shouldRecognizeMemoizedFunctions() { assertThat(memo.isMemoized()).isTrue(); } + private static CheckedFunction2 recurrent1 = (i1, i2) -> i1 <= 0 ? i1 : CheckedFunction2Test.recurrent2.apply(i1 - 1, i2) + 1; + private static CheckedFunction2 recurrent2 = CheckedFunction2Test.recurrent1.memoized(); + + @Test + public void shouldCalculatedRecursively() throws Throwable { + assertThat(recurrent1.apply(11, 11)).isEqualTo(11); + assertThat(recurrent1.apply(22, 22)).isEqualTo(22); + } + @Test public void shouldComposeWithAndThen() { final CheckedFunction2 f = (o1, o2) -> null; diff --git a/src-gen/test/java/javaslang/CheckedFunction3Test.java b/src-gen/test/java/javaslang/CheckedFunction3Test.java index 8db6d6124f..7985e76f23 100644 --- a/src-gen/test/java/javaslang/CheckedFunction3Test.java +++ b/src-gen/test/java/javaslang/CheckedFunction3Test.java @@ -120,6 +120,15 @@ public void shouldRecognizeMemoizedFunctions() { assertThat(memo.isMemoized()).isTrue(); } + private static CheckedFunction3 recurrent1 = (i1, i2, i3) -> i1 <= 0 ? i1 : CheckedFunction3Test.recurrent2.apply(i1 - 1, i2, i3) + 1; + private static CheckedFunction3 recurrent2 = CheckedFunction3Test.recurrent1.memoized(); + + @Test + public void shouldCalculatedRecursively() throws Throwable { + assertThat(recurrent1.apply(11, 11, 11)).isEqualTo(11); + assertThat(recurrent1.apply(22, 22, 22)).isEqualTo(22); + } + @Test public void shouldComposeWithAndThen() { final CheckedFunction3 f = (o1, o2, o3) -> null; diff --git a/src-gen/test/java/javaslang/CheckedFunction4Test.java b/src-gen/test/java/javaslang/CheckedFunction4Test.java index 549ce84fac..6c5d1488f4 100644 --- a/src-gen/test/java/javaslang/CheckedFunction4Test.java +++ b/src-gen/test/java/javaslang/CheckedFunction4Test.java @@ -126,6 +126,15 @@ public void shouldRecognizeMemoizedFunctions() { assertThat(memo.isMemoized()).isTrue(); } + private static CheckedFunction4 recurrent1 = (i1, i2, i3, i4) -> i1 <= 0 ? i1 : CheckedFunction4Test.recurrent2.apply(i1 - 1, i2, i3, i4) + 1; + private static CheckedFunction4 recurrent2 = CheckedFunction4Test.recurrent1.memoized(); + + @Test + public void shouldCalculatedRecursively() throws Throwable { + assertThat(recurrent1.apply(11, 11, 11, 11)).isEqualTo(11); + assertThat(recurrent1.apply(22, 22, 22, 22)).isEqualTo(22); + } + @Test public void shouldComposeWithAndThen() { final CheckedFunction4 f = (o1, o2, o3, o4) -> null; diff --git a/src-gen/test/java/javaslang/CheckedFunction5Test.java b/src-gen/test/java/javaslang/CheckedFunction5Test.java index 3e88812484..b72f4fa27b 100644 --- a/src-gen/test/java/javaslang/CheckedFunction5Test.java +++ b/src-gen/test/java/javaslang/CheckedFunction5Test.java @@ -132,6 +132,15 @@ public void shouldRecognizeMemoizedFunctions() { assertThat(memo.isMemoized()).isTrue(); } + private static CheckedFunction5 recurrent1 = (i1, i2, i3, i4, i5) -> i1 <= 0 ? i1 : CheckedFunction5Test.recurrent2.apply(i1 - 1, i2, i3, i4, i5) + 1; + private static CheckedFunction5 recurrent2 = CheckedFunction5Test.recurrent1.memoized(); + + @Test + public void shouldCalculatedRecursively() throws Throwable { + assertThat(recurrent1.apply(11, 11, 11, 11, 11)).isEqualTo(11); + assertThat(recurrent1.apply(22, 22, 22, 22, 22)).isEqualTo(22); + } + @Test public void shouldComposeWithAndThen() { final CheckedFunction5 f = (o1, o2, o3, o4, o5) -> null; diff --git a/src-gen/test/java/javaslang/CheckedFunction6Test.java b/src-gen/test/java/javaslang/CheckedFunction6Test.java index 06cd985ffa..3a07c282bb 100644 --- a/src-gen/test/java/javaslang/CheckedFunction6Test.java +++ b/src-gen/test/java/javaslang/CheckedFunction6Test.java @@ -138,6 +138,15 @@ public void shouldRecognizeMemoizedFunctions() { assertThat(memo.isMemoized()).isTrue(); } + private static CheckedFunction6 recurrent1 = (i1, i2, i3, i4, i5, i6) -> i1 <= 0 ? i1 : CheckedFunction6Test.recurrent2.apply(i1 - 1, i2, i3, i4, i5, i6) + 1; + private static CheckedFunction6 recurrent2 = CheckedFunction6Test.recurrent1.memoized(); + + @Test + public void shouldCalculatedRecursively() throws Throwable { + assertThat(recurrent1.apply(11, 11, 11, 11, 11, 11)).isEqualTo(11); + assertThat(recurrent1.apply(22, 22, 22, 22, 22, 22)).isEqualTo(22); + } + @Test public void shouldComposeWithAndThen() { final CheckedFunction6 f = (o1, o2, o3, o4, o5, o6) -> null; diff --git a/src-gen/test/java/javaslang/CheckedFunction7Test.java b/src-gen/test/java/javaslang/CheckedFunction7Test.java index 2da130ed64..21ac4d7d38 100644 --- a/src-gen/test/java/javaslang/CheckedFunction7Test.java +++ b/src-gen/test/java/javaslang/CheckedFunction7Test.java @@ -144,6 +144,15 @@ public void shouldRecognizeMemoizedFunctions() { assertThat(memo.isMemoized()).isTrue(); } + private static CheckedFunction7 recurrent1 = (i1, i2, i3, i4, i5, i6, i7) -> i1 <= 0 ? i1 : CheckedFunction7Test.recurrent2.apply(i1 - 1, i2, i3, i4, i5, i6, i7) + 1; + private static CheckedFunction7 recurrent2 = CheckedFunction7Test.recurrent1.memoized(); + + @Test + public void shouldCalculatedRecursively() throws Throwable { + assertThat(recurrent1.apply(11, 11, 11, 11, 11, 11, 11)).isEqualTo(11); + assertThat(recurrent1.apply(22, 22, 22, 22, 22, 22, 22)).isEqualTo(22); + } + @Test public void shouldComposeWithAndThen() { final CheckedFunction7 f = (o1, o2, o3, o4, o5, o6, o7) -> null; diff --git a/src-gen/test/java/javaslang/CheckedFunction8Test.java b/src-gen/test/java/javaslang/CheckedFunction8Test.java index 0304ac2936..17aaa70caa 100644 --- a/src-gen/test/java/javaslang/CheckedFunction8Test.java +++ b/src-gen/test/java/javaslang/CheckedFunction8Test.java @@ -150,6 +150,15 @@ public void shouldRecognizeMemoizedFunctions() { assertThat(memo.isMemoized()).isTrue(); } + private static CheckedFunction8 recurrent1 = (i1, i2, i3, i4, i5, i6, i7, i8) -> i1 <= 0 ? i1 : CheckedFunction8Test.recurrent2.apply(i1 - 1, i2, i3, i4, i5, i6, i7, i8) + 1; + private static CheckedFunction8 recurrent2 = CheckedFunction8Test.recurrent1.memoized(); + + @Test + public void shouldCalculatedRecursively() throws Throwable { + assertThat(recurrent1.apply(11, 11, 11, 11, 11, 11, 11, 11)).isEqualTo(11); + assertThat(recurrent1.apply(22, 22, 22, 22, 22, 22, 22, 22)).isEqualTo(22); + } + @Test public void shouldComposeWithAndThen() { final CheckedFunction8 f = (o1, o2, o3, o4, o5, o6, o7, o8) -> null; diff --git a/src-gen/test/java/javaslang/Function0Test.java b/src-gen/test/java/javaslang/Function0Test.java index ad24d65dc2..d0006a6d68 100644 --- a/src-gen/test/java/javaslang/Function0Test.java +++ b/src-gen/test/java/javaslang/Function0Test.java @@ -80,6 +80,15 @@ public void shouldRecognizeMemoizedFunctions() { assertThat(memo.isMemoized()).isTrue(); } + private static Function0 recurrent1 = () -> 11; + private static Function0 recurrent2 = Function0Test.recurrent1.memoized(); + + @Test + public void shouldCalculatedRecursively() { + assertThat(recurrent1.apply()).isEqualTo(11); + + } + @Test public void shouldComposeWithAndThen() { final Function0 f = () -> null; diff --git a/src-gen/test/java/javaslang/Function1Test.java b/src-gen/test/java/javaslang/Function1Test.java index 52747fa5df..4a88f97038 100644 --- a/src-gen/test/java/javaslang/Function1Test.java +++ b/src-gen/test/java/javaslang/Function1Test.java @@ -108,6 +108,15 @@ public void shouldRecognizeMemoizedFunctions() { assertThat(memo.isMemoized()).isTrue(); } + private static Function1 recurrent1 = (i1) -> i1 <= 0 ? i1 : Function1Test.recurrent2.apply(i1 - 1) + 1; + private static Function1 recurrent2 = Function1Test.recurrent1.memoized(); + + @Test + public void shouldCalculatedRecursively() { + assertThat(recurrent1.apply(11)).isEqualTo(11); + assertThat(recurrent1.apply(22)).isEqualTo(22); + } + @Test public void shouldComposeWithAndThen() { final Function1 f = (o1) -> null; diff --git a/src-gen/test/java/javaslang/Function2Test.java b/src-gen/test/java/javaslang/Function2Test.java index 1d09c2a1ad..3ffbd1c394 100644 --- a/src-gen/test/java/javaslang/Function2Test.java +++ b/src-gen/test/java/javaslang/Function2Test.java @@ -114,6 +114,15 @@ public void shouldRecognizeMemoizedFunctions() { assertThat(memo.isMemoized()).isTrue(); } + private static Function2 recurrent1 = (i1, i2) -> i1 <= 0 ? i1 : Function2Test.recurrent2.apply(i1 - 1, i2) + 1; + private static Function2 recurrent2 = Function2Test.recurrent1.memoized(); + + @Test + public void shouldCalculatedRecursively() { + assertThat(recurrent1.apply(11, 11)).isEqualTo(11); + assertThat(recurrent1.apply(22, 22)).isEqualTo(22); + } + @Test public void shouldComposeWithAndThen() { final Function2 f = (o1, o2) -> null; diff --git a/src-gen/test/java/javaslang/Function3Test.java b/src-gen/test/java/javaslang/Function3Test.java index c859468278..8bc36db703 100644 --- a/src-gen/test/java/javaslang/Function3Test.java +++ b/src-gen/test/java/javaslang/Function3Test.java @@ -120,6 +120,15 @@ public void shouldRecognizeMemoizedFunctions() { assertThat(memo.isMemoized()).isTrue(); } + private static Function3 recurrent1 = (i1, i2, i3) -> i1 <= 0 ? i1 : Function3Test.recurrent2.apply(i1 - 1, i2, i3) + 1; + private static Function3 recurrent2 = Function3Test.recurrent1.memoized(); + + @Test + public void shouldCalculatedRecursively() { + assertThat(recurrent1.apply(11, 11, 11)).isEqualTo(11); + assertThat(recurrent1.apply(22, 22, 22)).isEqualTo(22); + } + @Test public void shouldComposeWithAndThen() { final Function3 f = (o1, o2, o3) -> null; diff --git a/src-gen/test/java/javaslang/Function4Test.java b/src-gen/test/java/javaslang/Function4Test.java index 6e722ddf76..38de5a2389 100644 --- a/src-gen/test/java/javaslang/Function4Test.java +++ b/src-gen/test/java/javaslang/Function4Test.java @@ -126,6 +126,15 @@ public void shouldRecognizeMemoizedFunctions() { assertThat(memo.isMemoized()).isTrue(); } + private static Function4 recurrent1 = (i1, i2, i3, i4) -> i1 <= 0 ? i1 : Function4Test.recurrent2.apply(i1 - 1, i2, i3, i4) + 1; + private static Function4 recurrent2 = Function4Test.recurrent1.memoized(); + + @Test + public void shouldCalculatedRecursively() { + assertThat(recurrent1.apply(11, 11, 11, 11)).isEqualTo(11); + assertThat(recurrent1.apply(22, 22, 22, 22)).isEqualTo(22); + } + @Test public void shouldComposeWithAndThen() { final Function4 f = (o1, o2, o3, o4) -> null; diff --git a/src-gen/test/java/javaslang/Function5Test.java b/src-gen/test/java/javaslang/Function5Test.java index a284b9ad18..7e02e23639 100644 --- a/src-gen/test/java/javaslang/Function5Test.java +++ b/src-gen/test/java/javaslang/Function5Test.java @@ -132,6 +132,15 @@ public void shouldRecognizeMemoizedFunctions() { assertThat(memo.isMemoized()).isTrue(); } + private static Function5 recurrent1 = (i1, i2, i3, i4, i5) -> i1 <= 0 ? i1 : Function5Test.recurrent2.apply(i1 - 1, i2, i3, i4, i5) + 1; + private static Function5 recurrent2 = Function5Test.recurrent1.memoized(); + + @Test + public void shouldCalculatedRecursively() { + assertThat(recurrent1.apply(11, 11, 11, 11, 11)).isEqualTo(11); + assertThat(recurrent1.apply(22, 22, 22, 22, 22)).isEqualTo(22); + } + @Test public void shouldComposeWithAndThen() { final Function5 f = (o1, o2, o3, o4, o5) -> null; diff --git a/src-gen/test/java/javaslang/Function6Test.java b/src-gen/test/java/javaslang/Function6Test.java index 4e88668340..af305b088b 100644 --- a/src-gen/test/java/javaslang/Function6Test.java +++ b/src-gen/test/java/javaslang/Function6Test.java @@ -138,6 +138,15 @@ public void shouldRecognizeMemoizedFunctions() { assertThat(memo.isMemoized()).isTrue(); } + private static Function6 recurrent1 = (i1, i2, i3, i4, i5, i6) -> i1 <= 0 ? i1 : Function6Test.recurrent2.apply(i1 - 1, i2, i3, i4, i5, i6) + 1; + private static Function6 recurrent2 = Function6Test.recurrent1.memoized(); + + @Test + public void shouldCalculatedRecursively() { + assertThat(recurrent1.apply(11, 11, 11, 11, 11, 11)).isEqualTo(11); + assertThat(recurrent1.apply(22, 22, 22, 22, 22, 22)).isEqualTo(22); + } + @Test public void shouldComposeWithAndThen() { final Function6 f = (o1, o2, o3, o4, o5, o6) -> null; diff --git a/src-gen/test/java/javaslang/Function7Test.java b/src-gen/test/java/javaslang/Function7Test.java index 069094ae28..badfcd87d7 100644 --- a/src-gen/test/java/javaslang/Function7Test.java +++ b/src-gen/test/java/javaslang/Function7Test.java @@ -144,6 +144,15 @@ public void shouldRecognizeMemoizedFunctions() { assertThat(memo.isMemoized()).isTrue(); } + private static Function7 recurrent1 = (i1, i2, i3, i4, i5, i6, i7) -> i1 <= 0 ? i1 : Function7Test.recurrent2.apply(i1 - 1, i2, i3, i4, i5, i6, i7) + 1; + private static Function7 recurrent2 = Function7Test.recurrent1.memoized(); + + @Test + public void shouldCalculatedRecursively() { + assertThat(recurrent1.apply(11, 11, 11, 11, 11, 11, 11)).isEqualTo(11); + assertThat(recurrent1.apply(22, 22, 22, 22, 22, 22, 22)).isEqualTo(22); + } + @Test public void shouldComposeWithAndThen() { final Function7 f = (o1, o2, o3, o4, o5, o6, o7) -> null; diff --git a/src-gen/test/java/javaslang/Function8Test.java b/src-gen/test/java/javaslang/Function8Test.java index d8c6e8b483..cf2cfb41cb 100644 --- a/src-gen/test/java/javaslang/Function8Test.java +++ b/src-gen/test/java/javaslang/Function8Test.java @@ -150,6 +150,15 @@ public void shouldRecognizeMemoizedFunctions() { assertThat(memo.isMemoized()).isTrue(); } + private static Function8 recurrent1 = (i1, i2, i3, i4, i5, i6, i7, i8) -> i1 <= 0 ? i1 : Function8Test.recurrent2.apply(i1 - 1, i2, i3, i4, i5, i6, i7, i8) + 1; + private static Function8 recurrent2 = Function8Test.recurrent1.memoized(); + + @Test + public void shouldCalculatedRecursively() { + assertThat(recurrent1.apply(11, 11, 11, 11, 11, 11, 11, 11)).isEqualTo(11); + assertThat(recurrent1.apply(22, 22, 22, 22, 22, 22, 22, 22)).isEqualTo(22); + } + @Test public void shouldComposeWithAndThen() { final Function8 f = (o1, o2, o3, o4, o5, o6, o7, o8) -> null;