diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 97907d021927fa62d49d85349f4555d3a7ed2156..0c16d1afa53d24841833d143bc0dc4b1f9fda5cb 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -39,3 +39,4 @@ include: - local: "/java-monades/.gitlab-ci.yml" - local: "/java-diamond/.gitlab-ci.yml" - local: "/diamond-ts/.gitlab-ci.yml" + - local: "/java-memoizers/.gitlab-ci.yml" diff --git a/java-memoizers/.gitlab-ci.yml b/java-memoizers/.gitlab-ci.yml new file mode 100644 index 0000000000000000000000000000000000000000..bf70e5c652bb3ff97e3769dff29d9f8620831e86 --- /dev/null +++ b/java-memoizers/.gitlab-ci.yml @@ -0,0 +1,11 @@ +package-java-memoizers: + variables: + PROJECT_FOLDER: "java-memoizers" + extends: .java + only: + refs: + - master + - merge_requests + changes: + - ".gitlab-common-ci.yml" + - "java-memoizers/**/*" diff --git a/java-memoizers/pom.xml b/java-memoizers/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..04edddc26b78a50d84ecad4cbded8ca2558a1030 --- /dev/null +++ b/java-memoizers/pom.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <version>1.0.0</version> + <groupId>fr.ippon.kata</groupId> + <artifactId>java-parent</artifactId> + <relativePath>../java-parent</relativePath> + </parent> + + <version>1.0.0-SNAPSHOT</version> + <artifactId>java-memoizers</artifactId> + + <name>JavaMemoizers</name> + + <developers> + <developer> + <email>arey@ippon.fr</email> + <name>Anthont REY</name> + </developer> + <developer> + <email>cdamon@ippon.fr</email> + <name>Colin DAMON</name> + </developer> + </developers> +</project> diff --git a/java-memoizers/readme.md b/java-memoizers/readme.md new file mode 100644 index 0000000000000000000000000000000000000000..bd80d3bfb51b47cfcacab2a14b423042d4c280d3 --- /dev/null +++ b/java-memoizers/readme.md @@ -0,0 +1,9 @@ +# Java memoizer + +Implémentation de memoizers en Java + +- **Auteurs** : Anthony REY et Colin DAMON +- **Date** : 18/06/2021 +- **Langage** : Java +- **Niveau** : Enervé +- **Replay** : [Twitch](https://www.twitch.tv/videos/1059837117) diff --git a/java-memoizers/src/main/java/fr/craft/memoizer/Memoizers.java b/java-memoizers/src/main/java/fr/craft/memoizer/Memoizers.java new file mode 100644 index 0000000000000000000000000000000000000000..52c14a61ed06456609d23acd9fc6e08908b5c7c1 --- /dev/null +++ b/java-memoizers/src/main/java/fr/craft/memoizer/Memoizers.java @@ -0,0 +1,42 @@ +package fr.craft.memoizer; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Function; +import java.util.function.Supplier; + +public final class Memoizers { + + private Memoizers() {} + + public static <Result> Supplier<Result> of(Supplier<Result> supplier) { + return () -> of(dummy -> supplier.get()).apply(null); + } + + public static <Input, Result> Function<Input, Result> of(Function<Input, Result> function) { + return new MemoizedFunction<>(function); + } + + private static class MemoizedFunction<Input, Result> implements Function<Input, Result> { + + private final Function<Input, Result> function; + private final Map<MemoizedInput<Input>, MemoizedResult<Result>> results = new ConcurrentHashMap<>(); + + public MemoizedFunction(Function<Input, Result> function) { + this.function = function; + } + + @Override + public Result apply(Input input) { + return results.computeIfAbsent(new MemoizedInput<>(input), this::toMemoizedResult).result(); + } + + private MemoizedResult<Result> toMemoizedResult(MemoizedInput<Input> input) { + return new MemoizedResult<>(function.apply(input.input())); + } + + private static record MemoizedInput<Input>(Input input) {} + + private static record MemoizedResult<Result>(Result result) {} + } +} diff --git a/java-memoizers/src/test/java/fr/craft/memoizer/MemoizersTest.java b/java-memoizers/src/test/java/fr/craft/memoizer/MemoizersTest.java new file mode 100644 index 0000000000000000000000000000000000000000..856cca95f6a82b41f52fef9c49a2aded16a87929 --- /dev/null +++ b/java-memoizers/src/test/java/fr/craft/memoizer/MemoizersTest.java @@ -0,0 +1,63 @@ +package fr.craft.memoizer; + +import static org.assertj.core.api.Assertions.*; + +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Function; +import java.util.function.Supplier; +import org.junit.jupiter.api.Test; + +class MemoizersTest { + + @Test + void shouldGetFunctionResult() { + Function<Double, Double> memoizer = Memoizers.of(d -> d * d); + + assertThat(memoizer.apply(2D)).isEqualTo(4D); + } + + @Test + void shouldMemoizeFunctionResult() { + AtomicInteger result = new AtomicInteger(); + + Function<Object, Integer> memoizer = Memoizers.of(d -> result.incrementAndGet()); + + assertThat(memoizer.apply(1)).isEqualTo(memoizer.apply(1)); + assertThat(memoizer.apply(1)).isNotEqualTo(memoizer.apply(2)); + } + + @Test + void shouldMemoizeNullResult() { + NullFactory factory = new NullFactory(); + Function<Object, String> memoizer = Memoizers.of(factory); + + memoizer.apply(1); + memoizer.apply(1); + + assertThat(factory.callsCount()).isEqualTo(1); + assertThat(memoizer.apply(1)).isNull(); + } + + @Test + void shouldMemoizeSupplier() { + Supplier<String> supplier = Memoizers.of(() -> "Pouet"); + + assertThat(supplier.get()).isEqualTo("Pouet"); + } + + private static class NullFactory implements Function<Object, String> { + + private final AtomicInteger callsCount = new AtomicInteger(); + + public int callsCount() { + return callsCount.get(); + } + + @Override + public String apply(Object input) { + callsCount.incrementAndGet(); + + return null; + } + } +} diff --git a/readme.md b/readme.md index 2da8b8368036b87028c8c7484bb2275b7447cc89..92959e1494258b38e38dae96f9d23cff0bd340da 100644 --- a/readme.md +++ b/readme.md @@ -86,6 +86,7 @@ Un kata de code est un petit exercice pensé pour s'entrainer jusqu'à maitriser - [Concurrence en Java](/java-concurrence) - [Try monade](/try-monade) +- [Memoizers](/java-memoizers) ### Bon Chance