Passed
Push — master ( e98a28...c17e98 )
by Vincent
14:51 queued 24s
created

map(NonNegativeIntUnaryOperator)   A

Complexity

Conditions 2

Size

Total Lines 8
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 6
c 0
b 0
f 0
dl 0
loc 8
ccs 5
cts 5
cp 1
crap 2
rs 10
1
/*
2
 * This file is part of ArakneUtils.
3
 *
4
 * ArakneUtils is free software: you can redistribute it and/or modify
5
 * it under the terms of the GNU Lesser General Public License as published by
6
 * the Free Software Foundation, either version 3 of the License, or
7
 * (at your option) any later version.
8
 *
9
 * ArakneUtils is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 * GNU Lesser General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU Lesser General Public License
15
 * along with ArakneUtils.  If not, see <https://www.gnu.org/licenses/>.
16
 *
17
 * Copyright (c) 2017-2021 Vincent Quatrevieux
18
 */
19
20
package fr.arakne.utils.value;
21
22
import org.checkerframework.checker.index.qual.NonNegative;
23
import org.checkerframework.checker.nullness.qual.Nullable;
24
import org.checkerframework.dataflow.qual.Pure;
25
26
import java.util.Objects;
27
import java.util.function.IntUnaryOperator;
28
29
/**
30
 * Integer interval, min and max included
31
 * min and max can be equals
32
 *
33
 * Note: This is an immutable value object
34
 */
35
public final class Interval {
36
    private final @NonNegative int min;
37
    private final @NonNegative int max;
38
39
    /**
40
     * @param min Minimal value of the interval
41
     * @param max Maximal value of the interval
42
     *
43
     * @throws IllegalArgumentException When max is lower than min
44
     */
45 1
    public Interval(@NonNegative int min, @NonNegative int max) {
46 1
        if (max < min) {
47 1
            throw new IllegalArgumentException("max must be higher than min");
48
        }
49
50 1
        this.min = min;
51 1
        this.max = max;
52 1
    }
53
54
    /**
55
     * The minimal value of the interval
56
     *
57
     * @return The min value
58
     */
59
    @Pure
60
    public @NonNegative int min() {
61 1
        return min;
62
    }
63
64
    /**
65
     * The maximal value of the interval
66
     *
67
     * @return The max value
68
     */
69
    @Pure
70
    public @NonNegative int max() {
71 1
        return max;
72
    }
73
74
    /**
75
     * Compute the average value of the interface
76
     * The average is `min + max / 2`
77
     *
78
     * @return The average, in double
79
     */
80
    @Pure
81
    public double average() {
82 1
        return (min + max) / 2d;
83
    }
84
85
    /**
86
     * Compute the interval amplitude
87
     * The amplitude is the size of the interval (i.e. `max - min`)
88
     * If the interval is a singleton, the amplitude is 0
89
     *
90
     * @return The amplitude. Must be a positive integer
91
     */
92
    @Pure
93
    @SuppressWarnings("return") // max is always >= to min
94
    public @NonNegative int amplitude() {
95 1
        return max - min;
96
    }
97
98
    /**
99
     * Check if the value is contained into the interval
100
     * The interval is inclusive
101
     *
102
     * @param value The value to check
103
     *
104
     * @return true if value is in the interface
105
     */
106
    @Pure
107
    public boolean contains(int value) {
108 1
        return value >= min && value <= max;
109
    }
110
111
    /**
112
     * Check if the current interval is a singleton (i.e. `min == max`)
113
     *
114
     * @return true if it's a singleton
115
     */
116
    @Pure
117
    public boolean isSingleton() {
118 1
        return min == max;
119
    }
120
121
    /**
122
     * Modify the end of the interval
123
     * The returned interval will be [min, max + modifier]
124
     * If the new end is lower than the min (i.e. -modifier higher than max - min), the interval [min, min] will be returned
125
     *
126
     * @param modifier The modifier value. If positive will increase max, if negative will decrease
127
     *
128
     * @return The new interval
129
     */
130
    public Interval modify(int modifier) {
131 1
        if (modifier == 0 || (min == max && modifier < 0)) {
132 1
            return this;
133
        }
134
135 1
        return new Interval(min, Math.max(max + modifier, min));
136
    }
137
138
    /**
139
     * Apply value transformer to the interval boundaries
140
     * If the Interval is a singleton, the transformer will be applied only once
141
     * The transformer may change the boundary order (ex: if the transformer reverse values), the result Interval will be reordered
142
     *
143
     * @param transformer The boundary transformation process
144
     *
145
     * @return The new transformed interval
146
     */
147
    public Interval map(NonNegativeIntUnaryOperator transformer) {
148 1
        if (isSingleton()) {
149 1
            return Interval.of(transformer.applyAsInt(min));
150
        }
151
152 1
        return Interval.of(
153 1
            transformer.applyAsInt(min),
154 1
            transformer.applyAsInt(max)
155
        );
156
    }
157
158
    @Override
159
    public String toString() {
160 1
        return "[" + min + ", " + max + "]";
161
    }
162
163
    @Override
164
    public boolean equals(@Nullable Object obj) {
165 1
        if (!(obj instanceof Interval)) {
166 1
            return false;
167
        }
168
169 1
        final Interval other = (Interval) obj;
170
171 1
        return other.min == min && other.max == max;
172
    }
173
174
    @Override
175
    public int hashCode() {
176 1
        return Objects.hash(min, max);
177
    }
178
179
    /**
180
     * Create a singleton interval
181
     *
182
     * @param value The interval value
183
     *
184
     * @return The new Interval instance
185
     */
186
    public static Interval of(@NonNegative int value) {
187 1
        return new Interval(value, value);
188
    }
189
190
    /**
191
     * Create an interval with unordered boundaries
192
     * The two boundaries will be ordered to create a valid interval
193
     *
194
     * @param a First boundary of the interval
195
     * @param b Second boundary of the interval
196
     *
197
     * @return The new Interval instance
198
     */
199
    public static Interval of(@NonNegative int a, @NonNegative int b) {
200 1
        if (a > b) {
201 1
            return new Interval(b, a);
202
        }
203
204 1
        return new Interval(a, b);
205
    }
206
207
    /**
208
     * Duplicate of {@link IntUnaryOperator} but for NonNegative integer
209
     */
210
    @FunctionalInterface
211
    public interface NonNegativeIntUnaryOperator {
212
        /**
213
         * Applies this operator to the given operand.
214
         *
215
         * @param operand the operand
216
         * @return the operator result
217
         */
218
        public @NonNegative int applyAsInt(@NonNegative int operand);
219
    }
220
}
221