1
+ package org .jooq .lambda ;
2
+
3
+ import org .jooq .lambda .tuple .Tuple4 ;
4
+
5
+ import java .util .Arrays ;
6
+ import java .util .LongSummaryStatistics ;
7
+ import java .util .function .IntConsumer ;
8
+ import java .util .function .IntUnaryOperator ;
9
+ import java .util .function .LongConsumer ;
10
+ import java .util .function .LongPredicate ;
11
+ import java .util .function .Predicate ;
12
+
13
+ /** External lambda "for"-loops. */
14
+ public class Loops {
15
+ private Loops () {}//static utils
16
+
17
+
18
+ /**
19
+ Simple loop (numberOfRepetitions .. 0].
20
+ <pre>{@code
21
+ while (numberOfRepetitions-- > 0)
22
+ body.run();
23
+ }</pre>
24
+ */
25
+ public static void loop (long numberOfRepetitions , Runnable body ) {
26
+ while (numberOfRepetitions -- > 0 ) {
27
+ body .run ();
28
+ }
29
+ }
30
+
31
+ /**
32
+ Simple while-loop (numberOfRepetitions .. 0].
33
+ <pre>{@code}
34
+ while (numberOfRepetitions-- > 0)
35
+ body.accept(numberOfRepetitions);
36
+ }</pre>
37
+ */
38
+ public static void loop (long numberOfRepetitions , LongConsumer body ) {
39
+ while (numberOfRepetitions -- > 0 ) {
40
+ body .accept (numberOfRepetitions );
41
+ }
42
+ }
43
+
44
+ /**
45
+ Simple for-loop [0 .. numberOfRepetitions).
46
+ <pre>{@code}
47
+ for (int i=0; i<max; i++)
48
+ body.accept(i);
49
+ }</pre>
50
+ */
51
+ public static void forLoop (int maxExclusive , IntConsumer body ) {
52
+ for (int i =0 ; i <maxExclusive ; i ++) {
53
+ body .accept (i );
54
+ }
55
+ }
56
+
57
+ /**
58
+ Simple loop (numberOfRepetitions .. 0] with extra condition.
59
+ <pre>{@code
60
+ while (numberOfRepetitions-- > 0 && body.test(numberOfRepetitions)) {}
61
+ }</pre>
62
+ @param body do-while Predicate: loops while it is true and numberOfRepetitions > 0
63
+ */
64
+ public static void loopWhile (long numberOfRepetitions , LongPredicate body ) {
65
+ //noinspection StatementWithEmptyBody
66
+ while (numberOfRepetitions -- > 0 && body .test (numberOfRepetitions )) {
67
+ // do while
68
+ }
69
+ }
70
+
71
+ // Ad-Hoc JMH (not for serious benchmarks)
72
+
73
+ static final long NANO = 1000_000_000L ;
74
+
75
+ /** Similar to {@link #loop(long, Runnable)}, but with metrics */
76
+ public static Tuple4 <Long , LongSummaryStatistics , Exception , String > loopMeasured (long numberOfRepetitions , Runnable body ) {
77
+ LongSummaryStatistics st = new LongSummaryStatistics ();
78
+ Exception ex = null ;
79
+ long n = System .nanoTime ();
80
+
81
+ while (numberOfRepetitions -- > 0 ) {
82
+ long t = System .nanoTime ();
83
+ try {
84
+ body .run ();
85
+ } catch (Exception showStopper ) {
86
+ ex = showStopper ;
87
+ break ;
88
+ } finally {
89
+ st .accept (System .nanoTime () - t );
90
+ }
91
+ }
92
+ n = System .nanoTime () - n ;
93
+
94
+ StringBuilder sb = new StringBuilder (200 );// ≤ ≥
95
+ sb .append ("LOOP: " ).append (st .getCount ())
96
+ .append (" nanos= " ).append (st .getSum ()).append (" ≤ " ).append (n )
97
+ .append (" ~ op/sec= " );
98
+ if (st .getSum () > 0 ) {
99
+ sb .append ((st .getCount () * NANO ) / st .getSum ()).append (" ≥ " );
100
+ }
101
+ sb .append ((st .getCount () * NANO ) / Math .max (n , 1 ));
102
+ if (st .getCount ()>0 ) {
103
+ sb .append (" ~ nano/op= " ).append (st .getSum () / st .getCount ()).append (" ≤ " ).append (n / st .getCount ());
104
+ }
105
+ sb .append (" min<avg<max= " ).append (st .getMin ())
106
+ .append (" < " ).append (st .getAverage ())
107
+ .append (" < " ).append (st .getMax ());
108
+ return new Tuple4 <>(n , st , ex , sb .toString ());
109
+ }
110
+
111
+ /** Similar to {@link #loop(long, Runnable)}, but with metrics and warm-up */
112
+ public static Tuple4 <Long , LongSummaryStatistics , Exception , String > loopMeasuredWarm (long numberOfRepetitions , Runnable body ) {
113
+ long warmCnt = Math .min (50_000 , numberOfRepetitions /10 +10 );
114
+
115
+ loop (warmCnt , body );
116
+
117
+ return loopMeasured (numberOfRepetitions , body );
118
+ }
119
+
120
+
121
+ public static class Incrementer {
122
+ protected final int [] indexes ;
123
+ private final IntUnaryOperator maxForIndex ;
124
+
125
+ /** All indexes have the same max and rotate in range [0..maxExclusive)
126
+ @param degree size of index vector = how many nested for-loops
127
+ @param maxExclusive number of repetitions: every index variable rotates in range [0..maxExclusive)
128
+ */
129
+ public Incrementer (int degree , final int maxExclusive ) {
130
+ assert degree > 0 : "degree must be > 0, but " +degree ;
131
+ assert maxExclusive > 0 : "maxExclusive must be > 0, but " +maxExclusive ;
132
+
133
+ indexes = new int [degree ];
134
+ maxForIndex = (index ) -> maxExclusive ;
135
+ init ();
136
+ }//new
137
+
138
+ /**
139
+ * Permutation with repetition. Every index has its own max.
140
+ * @param maxExclusive all indexes have their own max and rotate in range [0..maxExclusive[index])
141
+ */
142
+ public Incrementer (final int [] maxExclusive ) {
143
+ assert maxExclusive .length > 0 : "degree must be > 0, but " +maxExclusive .length ;
144
+
145
+ indexes = new int [maxExclusive .length ];
146
+ maxForIndex = (index ) -> maxExclusive [index ];
147
+ init ();
148
+ }//new
149
+
150
+ protected void init () {}
151
+
152
+ public int degree () {
153
+ return indexes .length ;
154
+ }
155
+
156
+ public int indexAt (int indexIndex ) {
157
+ return indexes [indexIndex ];
158
+ }
159
+
160
+ public int maxAt (int indexIndex ) {
161
+ return maxForIndex .applyAsInt (indexIndex );
162
+ }
163
+
164
+ @ Override public String toString () {
165
+ return "Incrementer" + Arrays .toString (indexes );
166
+ }
167
+
168
+
169
+ /**
170
+ Increments index vector (array with indexes) by 1.
171
+ E.g. for base 2: 0,0,0→0,0,1→0,1,0
172
+ Emulates one step in multi-nested-for loop.
173
+
174
+ @return we "overflowed" the array size = all indexes have reached their max-1
175
+ @see #forLoop(Predicate)
176
+ */
177
+ public boolean incrementIndexVector () {
178
+ final int len = indexes .length ;
179
+
180
+ for (int i = 0 ; i < len ; ) {
181
+ if (++indexes [i ] < maxForIndex .applyAsInt (i )) {
182
+ return false ;
183
+
184
+ } else {// overflow
185
+ indexes [i ] = 0 ;// e.g. [10]: 09 → 10
186
+ i ++;
187
+ }
188
+ }
189
+ return true ;
190
+ }
191
+
192
+ /**
193
+ * Permutation with repetition.
194
+ * @param loopBody receive this Incrementer with indexes and maxExclusive, must return boolean searchIsOver/found
195
+ * @return searchIsOver/found
196
+ */
197
+ public boolean forLoop (Predicate <Incrementer > loopBody ) {
198
+ while (true ) {
199
+ boolean found = loopBody .test (this );
200
+ if (found ) {
201
+ return true ;
202
+ }
203
+ boolean overflow = incrementIndexVector ();
204
+ if (overflow ) {
205
+ return false ;
206
+ }
207
+ }
208
+ }
209
+ }//Incrementer
210
+
211
+ }
0 commit comments