Skip to content

Commit 9fceaa6

Browse files
committed
Счетчик. Простая модель
1 parent bedf328 commit 9fceaa6

1 file changed

Lines changed: 92 additions & 0 deletions

File tree

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package ru.mifi.practice.voln.features;
2+
3+
import lombok.Builder;
4+
5+
import java.time.LocalDateTime;
6+
import java.util.HashMap;
7+
import java.util.Map;
8+
import java.util.Optional;
9+
10+
public interface CountRange {
11+
12+
Optional<Long> add(long countId, long userId, long delta);
13+
14+
Optional<Long> userValue(long countId, long userId);
15+
16+
Optional<Long> countValue(long countId, long userId);
17+
18+
final class Default implements CountRange {
19+
private static final Value EMPTY = new Value(0, -1, null);
20+
private final Map<Long, Count> counts = new HashMap<>();
21+
private final Map<Key, Value> values = new HashMap<>();
22+
23+
private static int indexOf(long[] ranges, long value) {
24+
if (value < ranges[0]) {
25+
return 0;
26+
}
27+
for (int i = 1; i < ranges.length; i++) {
28+
if (value > ranges[i - 1] && value < ranges[i]) {
29+
return i;
30+
}
31+
}
32+
return ranges.length - 1;
33+
}
34+
35+
@Override
36+
public Optional<Long> userValue(long countId, long userId) {
37+
return Optional.ofNullable(values.get(new Key(countId, userId))).map(Value::value);
38+
}
39+
40+
@Override
41+
public Optional<Long> add(long countId, long userId, long delta) {
42+
Count count = this.counts.get(countId);
43+
if (count == null) {
44+
return Optional.empty();
45+
} else if (delta <= 0) {
46+
return Optional.empty();
47+
}
48+
Key key = new Key(countId, userId);
49+
Value value = values.computeIfAbsent(key, k -> EMPTY.copy());
50+
long[] ranges = count.ranges;
51+
int lastIt = indexOf(count.ranges, value.value);
52+
int newIt = indexOf(ranges, value.value + delta);
53+
value = value.toBuilder().value(value.value + delta).updatedAt(LocalDateTime.now()).build();
54+
values.put(key, value);
55+
if (lastIt < newIt) {
56+
return Optional.of(count.values[newIt]);
57+
}
58+
return Optional.empty();
59+
}
60+
61+
@Override
62+
public Optional<Long> countValue(long countId, long userId) {
63+
Count count = this.counts.get(countId);
64+
if (count == null) {
65+
return Optional.empty();
66+
}
67+
Key key = new Key(countId, userId);
68+
Value value = values.computeIfAbsent(key, k -> EMPTY.copy());
69+
int index = indexOf(count.ranges, value.value);
70+
return Optional.of(count.values[index]);
71+
}
72+
73+
private record Key(long rangesId, long userId) {
74+
}
75+
}
76+
77+
78+
@Builder(toBuilder = true)
79+
record Value(long value, long accepted, LocalDateTime updatedAt) {
80+
private Value copy() {
81+
return new Value(value, accepted, updatedAt);
82+
}
83+
}
84+
85+
record Count(long id, String name, long[] ranges, long[] values) {
86+
public Count {
87+
if (ranges.length != values.length) {
88+
throw new IllegalArgumentException("Размер диапазонов и размер значений должен совпадать");
89+
}
90+
}
91+
}
92+
}

0 commit comments

Comments
 (0)