summaryrefslogtreecommitdiff
path: root/src/main/java/lv/enes/mc/eris_alchemy/utils/ConsList.java
blob: bbab8a61bc10a1743d2e5aa6a4b83d3fafc9dd22 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
package lv.enes.mc.eris_alchemy.utils;

import jakarta.annotation.Nonnull;

import java.util.Objects;
import java.util.Optional;
import java.util.function.Supplier;
import java.util.stream.Stream;

public sealed abstract class ConsList<E> {
	public static <E> ConsList<E> cons(E car, ConsList<E> cdr) {
		return new Cons<>(car, cdr);
	}

	public static <E> ConsList<E> nil() {
		return Nil.of();
	}

	@Nonnull
	public abstract Optional<E> car();

	@Nonnull
	public abstract ConsList<E> cdr();

	public boolean contains(E elem) {
		return stream().anyMatch(x -> Objects.equals(x, elem));
	}

	public Stream<E> stream() {
		var car = car();
		if (car.isEmpty()) {
			return Stream.empty();
		}

		return Stream.<Supplier<Stream<E>>>of(
						() -> Stream.of(car.get()),
						() -> cdr().stream()
				)
				.flatMap(Supplier::get);
	}

	@Override
	public String toString() {
		if (car().isEmpty()) {
			return "[]";
		}

		var sb = new StringBuilder("[");
		sb.append(car().get());
		stream().skip(1)
				.forEach(x -> {
					sb.append(" -> ");
					sb.append(x);
				});
		sb.append("]");
		return sb.toString();
	}

	private static final class Cons<E> extends ConsList<E> {
		private final E car;
		private final ConsList<E> cdr;

		public Cons(E car, ConsList<E> cdr) {
			this.car = car;
			this.cdr = cdr;
		}

		@Nonnull
		@Override
		public Optional<E> car() {
			return Optional.of(car);
		}

		@Nonnull
		@Override
		public ConsList<E> cdr() {
			return cdr;
		}
	}

	private static final class Nil<E> extends ConsList<E> {
		private static final Nil<?> INSTANCE = new Nil<>();

		@SuppressWarnings("unchecked")
		public static <E> Nil<E> of() {
			return (Nil<E>)INSTANCE;
		}

		private Nil(){}

		@Nonnull
		@Override
		public Optional<E> car() {
			return Optional.empty();
		}

		@Nonnull
		@Override
		public ConsList<E> cdr() {
			return Nil.of();
		}
	}
}