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
104
105
106
107
108
109
|
/**
* Copyright (C) 2020, 2022, 2024, 2025 Adrien Hopkins
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package sevenUnitsGUI;
import java.util.List;
import java.util.function.Predicate;
import sevenUnits.unit.Metric;
import sevenUnits.unit.UnitPrefix;
/**
* A rule that specifies whether prefix repetition is allowed
*
* @since 2020-08-26
* @since v0.3.0
*/
public enum DefaultPrefixRepetitionRule implements Predicate<List<UnitPrefix>> {
/** Prefix repetition is never allowed; only one prefix may be used. */
NO_REPETITION {
@Override
public boolean test(List<UnitPrefix> prefixes) {
return prefixes.size() <= 1;
}
},
/** Prefix repetition is always allowed, without restrictions. */
NO_RESTRICTION {
@Override
public boolean test(List<UnitPrefix> prefixes) {
return true;
}
},
/**
* You are allowed to have any number of Yotta/Yocto followed by possibly one
* Kilo-Zetta/Milli-Zepto followed by possibly one Deca/Hecto. Same for
* reducing prefixes, don't mix magnifying and reducing. Non-metric
* (including binary) prefixes can't be repeated.
*/
COMPLEX_REPETITION {
@Override
public boolean test(List<UnitPrefix> prefixes) {
// determine whether we are magnifying or reducing
final boolean magnifying;
if (prefixes.isEmpty())
return true;
if (prefixes.get(0).getMultiplier() > 1) {
magnifying = true;
} else {
magnifying = false;
}
// if the first prefix is non-metric (including binary prefixes),
// assume we are using non-metric prefixes
// non-metric prefixes are allowed, but can't be repeated.
if (!Metric.DECIMAL_PREFIXES.contains(prefixes.get(0)))
return NO_REPETITION.test(prefixes);
var part = 0; // 0=yotta/yoctos, 1=kilo-zetta/milli-zepto,
// 2=deka,hecto,deci,centi
for (final UnitPrefix prefix : prefixes) {
// check that the current prefix is metric and appropriately
// magnifying/reducing
if (!Metric.DECIMAL_PREFIXES.contains(prefix) || (magnifying != prefix.getMultiplier() > 1))
return false;
// check if the current prefix is correct
// since part is set *after* this check, part designates the state
// of the *previous* prefix
switch (part) {
case 0:
// do nothing, any prefix is valid after a yotta
break;
case 1:
// after a kilo-zetta, only deka/hecto are valid
if (Metric.THOUSAND_PREFIXES.contains(prefix))
return false;
break;
case 2:
// deka/hecto must be the last prefix, so this is always invalid
return false;
}
// set part
if (Metric.YOTTA.equals(prefix) || Metric.YOCTO.equals(prefix)) {
part = 0;
} else if (Metric.THOUSAND_PREFIXES.contains(prefix)) {
part = 1;
} else {
part = 2;
}
}
return true;
}
};
}
|