1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.rng.examples.stress;
18
19 import org.apache.commons.rng.simple.RandomSource;
20
21 import picocli.CommandLine.Command;
22 import picocli.CommandLine.Mixin;
23 import picocli.CommandLine.Option;
24
25 import java.io.IOException;
26 import java.util.ArrayList;
27 import java.util.Arrays;
28 import java.util.Formatter;
29 import java.util.HashSet;
30 import java.util.List;
31 import java.util.NoSuchElementException;
32 import java.util.Scanner;
33 import java.util.concurrent.Callable;
34
35
36
37
38
39
40 @Command(name = "list",
41 description = "List random generators.")
42 class ListCommand implements Callable<Void> {
43
44 @Mixin
45 private StandardOptions reusableOptions;
46
47
48 @Option(names = {"-f", "--format"},
49 description = {"The list format (default: ${DEFAULT-VALUE}).",
50 "Valid values: ${COMPLETION-CANDIDATES}."},
51 paramLabel = "<format>")
52 private ListFormat listFormat = ListFormat.STRESS_TEST;
53
54
55 @Option(names = {"--provider"},
56 description = {"The provider type (default: ${DEFAULT-VALUE}).",
57 "Valid values: ${COMPLETION-CANDIDATES}."},
58 paramLabel = "<provider>")
59 private ProviderType providerType = ProviderType.ALL;
60
61
62 @Option(names = {"-p", "--prefix"},
63 description = {"The ID prefix.",
64 "Used for the stress test format."})
65 private String idPrefix = "";
66
67
68 @Option(names = {"-t", "--trials"},
69 description = {"The number of trials for each random generator.",
70 "Used for the stress test format."})
71 private int trials = 1;
72
73
74
75
76 enum ListFormat {
77
78 STRESS_TEST,
79
80 PLAIN
81 }
82
83
84
85
86 enum ProviderType {
87
88 ALL,
89
90 INT,
91
92 LONG,
93 }
94
95
96
97
98 @Override
99 public Void call() throws Exception {
100 LogUtils.setLogLevel(reusableOptions.logLevel);
101 StressTestDataList list = new StressTestDataList(idPrefix, trials);
102 if (providerType == ProviderType.INT) {
103 list = list.subsetIntSource();
104 } else if (providerType == ProviderType.LONG) {
105 list = list.subsetLongSource();
106 }
107
108 final StringBuilder sb = new StringBuilder();
109 switch (listFormat) {
110 case PLAIN:
111 writePlainData(sb, list);
112 break;
113 case STRESS_TEST:
114 default:
115 writeStressTestData(sb, list);
116 break;
117 }
118
119 System.out.append(sb);
120
121 return null;
122 }
123
124
125
126
127
128
129
130
131
132
133
134 static void writePlainData(Appendable appendable,
135 Iterable<StressTestData> testData) throws IOException {
136 final String newLine = System.lineSeparator();
137 for (final StressTestData data : testData) {
138 appendable.append(data.getRandomSource().name());
139 if (data.getArgs() != null) {
140 appendable.append(' ');
141 appendable.append(Arrays.toString(data.getArgs()));
142 }
143 appendable.append(newLine);
144 }
145 }
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168 static void writeStressTestData(Appendable appendable,
169 Iterable<StressTestData> testData) throws IOException {
170
171 int idWidth = 0;
172 int randomSourceWidth = 15;
173 for (final StressTestData data : testData) {
174 idWidth = Math.max(idWidth, data.getId().length());
175 randomSourceWidth = Math.max(randomSourceWidth, data.getRandomSource().name().length());
176 }
177
178 final String newLine = System.lineSeparator();
179
180 appendable.append("# Random generators list.").append(newLine);
181 appendable.append("# Any generator with no trials is ignored during testing.").append(newLine);
182 appendable.append("#").append(newLine);
183
184 String format = String.format("# %%-%ds %%-%ds trials [constructor arguments ...]%%n",
185 idWidth, randomSourceWidth);
186
187
188 @SuppressWarnings("resource")
189 final Formatter formatter = new Formatter(appendable);
190 formatter.format(format, "ID", "RandomSource");
191 format = String.format("%%-%ds %%-%ds ", idWidth + 2, randomSourceWidth);
192 for (final StressTestData data : testData) {
193 formatter.format(format, data.getId(), data.getRandomSource().name());
194 if (data.getArgs() == null) {
195 appendable.append(Integer.toString(data.getTrials()));
196 } else {
197 formatter.format("%-6d %s", data.getTrials(), Arrays.toString(data.getArgs()));
198 }
199 appendable.append(newLine);
200 }
201 formatter.flush();
202 }
203
204
205
206
207
208
209
210
211
212
213 static Iterable<StressTestData> readStressTestData(Readable readable) throws IOException {
214 final List<StressTestData> list = new ArrayList<>();
215
216
217 final HashSet<String> ids = new HashSet<>();
218
219
220 @SuppressWarnings("resource")
221 final Scanner scanner = new Scanner(readable);
222 try {
223 while (scanner.hasNextLine()) {
224
225
226
227
228
229 final String id = scanner.next();
230
231 if (id.isEmpty() || id.charAt(0) == '#') {
232 scanner.nextLine();
233 continue;
234 }
235 if (!ids.add(id)) {
236 throw new ApplicationException("Non-unique ID in strest test data: " + id);
237 }
238 final RandomSource randomSource = RandomSource.valueOf(scanner.next());
239 final int trials = scanner.nextInt();
240
241 final String arguments = scanner.nextLine().trim();
242 final Object[] args = parseArguments(randomSource, arguments);
243 list.add(new StressTestData(id, randomSource, args, trials));
244 }
245 } catch (NoSuchElementException | IllegalArgumentException ex) {
246 if (scanner.ioException() != null) {
247 throw scanner.ioException();
248 }
249 throw new ApplicationException("Failed to read stress test data", ex);
250 }
251
252 return list;
253 }
254
255
256
257
258
259
260
261
262
263
264 static Object[] parseArguments(RandomSource randomSource,
265 String arguments) {
266
267 if (arguments.isEmpty()) {
268 return null;
269 }
270
271
272
273 final int len = arguments.length();
274 if (len < 2 || arguments.charAt(0) != '[' || arguments.charAt(len - 1) != ']') {
275 throw new ApplicationException("RandomSource arguments should be an [array]: " + arguments);
276 }
277
278
279 final String[] tokens = arguments.substring(1, len - 1).split(", *");
280 final ArrayList<Object> args = new ArrayList<>();
281 for (final String token : tokens) {
282 args.add(RNGUtils.parseArgument(token));
283 }
284 return args.toArray();
285 }
286 }