28
28
*/
29
29
public class Capacity {
30
30
31
+ // Pre-allocate a common instance for performance
32
+ private static final Capacity ZERO = new Capacity (new int [1 ]);
33
+
31
34
/**
32
35
* Adds up two capacities, i.e. sums up each and every capacity dimension, and returns the resulting Capacity.
33
36
* <p>
@@ -40,11 +43,20 @@ public class Capacity {
40
43
*/
41
44
public static Capacity addup (Capacity cap1 , Capacity cap2 ) {
42
45
if (cap1 == null || cap2 == null ) throw new NullPointerException ("arguments must not be null" );
43
- Capacity .Builder capacityBuilder = Capacity .Builder .newInstance ();
44
- for (int i = 0 ; i < Math .max (cap1 .getNuOfDimensions (), cap2 .getNuOfDimensions ()); i ++) {
45
- capacityBuilder .addDimension (i , cap1 .get (i ) + cap2 .get (i ));
46
+
47
+ // Special case handling for better performance
48
+ if (cap1 .isZero ()) return copyOf (cap2 );
49
+ if (cap2 .isZero ()) return copyOf (cap1 );
50
+
51
+ int maxDimension = Math .max (cap1 .getNuOfDimensions (), cap2 .getNuOfDimensions ());
52
+ int [] newDimensions = new int [maxDimension ];
53
+
54
+ // Process all dimensions in one loop
55
+ for (int i = 0 ; i < maxDimension ; i ++) {
56
+ newDimensions [i ] = cap1 .get (i ) + cap2 .get (i );
46
57
}
47
- return capacityBuilder .build ();
58
+
59
+ return new Capacity (newDimensions );
48
60
}
49
61
50
62
/**
@@ -54,16 +66,22 @@ public static Capacity addup(Capacity cap1, Capacity cap2) {
54
66
* @param cap2subtract capacity to subtract
55
67
* @return new capacity
56
68
* @throws NullPointerException if one of the args is null
57
- * @throws IllegalStateException if number of capacityDimensions of cap1 and cap2 are different (i.e. <code>cap1.getNuOfDimension() != cap2.getNuOfDimension()</code>).
58
69
*/
59
70
public static Capacity subtract (Capacity cap , Capacity cap2subtract ) {
60
71
if (cap == null || cap2subtract == null ) throw new NullPointerException ("arguments must not be null" );
61
- Capacity .Builder capacityBuilder = Capacity .Builder .newInstance ();
62
- for (int i = 0 ; i < Math .max (cap .getNuOfDimensions (), cap2subtract .getNuOfDimensions ()); i ++) {
63
- int dimValue = cap .get (i ) - cap2subtract .get (i );
64
- capacityBuilder .addDimension (i , dimValue );
72
+
73
+ // Special case handling for better performance
74
+ if (cap2subtract .isZero ()) return copyOf (cap );
75
+
76
+ int maxDimension = Math .max (cap .getNuOfDimensions (), cap2subtract .getNuOfDimensions ());
77
+ int [] newDimensions = new int [maxDimension ];
78
+
79
+ // Process all dimensions in one loop
80
+ for (int i = 0 ; i < maxDimension ; i ++) {
81
+ newDimensions [i ] = cap .get (i ) - cap2subtract .get (i );
65
82
}
66
- return capacityBuilder .build ();
83
+
84
+ return new Capacity (newDimensions );
67
85
}
68
86
69
87
/**
@@ -75,12 +93,18 @@ public static Capacity subtract(Capacity cap, Capacity cap2subtract) {
75
93
*/
76
94
public static Capacity invert (Capacity cap2invert ) {
77
95
if (cap2invert == null ) throw new NullPointerException ("arguments must not be null" );
78
- Capacity .Builder capacityBuilder = Capacity .Builder .newInstance ();
96
+
97
+ // Special case handling for better performance
98
+ if (cap2invert .isZero ()) return ZERO ;
99
+
100
+ int [] newDimensions = new int [cap2invert .getNuOfDimensions ()];
101
+
102
+ // Process all dimensions in one loop
79
103
for (int i = 0 ; i < cap2invert .getNuOfDimensions (); i ++) {
80
- int dimValue = cap2invert .get (i ) * -1 ;
81
- capacityBuilder .addDimension (i , dimValue );
104
+ newDimensions [i ] = -cap2invert .get (i );
82
105
}
83
- return capacityBuilder .build ();
106
+
107
+ return new Capacity (newDimensions );
84
108
}
85
109
86
110
/**
@@ -98,14 +122,19 @@ public static Capacity invert(Capacity cap2invert) {
98
122
public static double divide (Capacity numerator , Capacity denominator ) {
99
123
int nuOfDimensions = 0 ;
100
124
double sumQuotients = 0.0 ;
101
- for (int index = 0 ; index < Math .max (numerator .getNuOfDimensions (), denominator .getNuOfDimensions ()); index ++) {
102
- if (numerator .get (index ) != 0 && denominator .get (index ) == 0 ) {
125
+ int maxDim = Math .max (numerator .getNuOfDimensions (), denominator .getNuOfDimensions ());
126
+
127
+ for (int index = 0 ; index < maxDim ; index ++) {
128
+ int num = numerator .get (index );
129
+ int denom = denominator .get (index );
130
+
131
+ if (num != 0 && denom == 0 ) {
103
132
throw new IllegalArgumentException ("numerator > 0 and denominator = 0. cannot divide by 0" );
104
- } else if (numerator . get ( index ) == 0 && denominator . get ( index ) == 0 ) {
133
+ } else if (num == 0 && denom == 0 ) {
105
134
continue ;
106
135
} else {
107
136
nuOfDimensions ++;
108
- sumQuotients += (double ) numerator . get ( index ) / (double ) denominator . get ( index ) ;
137
+ sumQuotients += (double ) num / (double ) denom ;
109
138
}
110
139
}
111
140
if (nuOfDimensions > 0 ) return sumQuotients / (double ) nuOfDimensions ;
@@ -120,7 +149,11 @@ public static double divide(Capacity numerator, Capacity denominator) {
120
149
*/
121
150
public static Capacity copyOf (Capacity capacity ) {
122
151
if (capacity == null ) return null ;
123
- return new Capacity (capacity );
152
+ if (capacity .isZero ()) return ZERO ;
153
+
154
+ int [] newDimensions = new int [capacity .getNuOfDimensions ()];
155
+ System .arraycopy (capacity .dimensions , 0 , newDimensions , 0 , capacity .getNuOfDimensions ());
156
+ return new Capacity (newDimensions );
124
157
}
125
158
126
159
/**
@@ -129,11 +162,9 @@ public static Capacity copyOf(Capacity capacity) {
129
162
* @author schroeder
130
163
*/
131
164
public static class Builder {
132
-
133
- /**
134
- * default is 1 dimension with size of zero
135
- */
136
- private int [] dimensions = new int [1 ];
165
+ private static final int DEFAULT_CAPACITY = 10 ;
166
+ private int [] dimensions ;
167
+ private int maxIndex = -1 ;
137
168
138
169
/**
139
170
* Returns a new instance of Capacity with one dimension and a value/size of 0
@@ -145,6 +176,18 @@ public static Builder newInstance() {
145
176
}
146
177
147
178
Builder () {
179
+ dimensions = new int [DEFAULT_CAPACITY ];
180
+ }
181
+
182
+ /**
183
+ * Sets initial capacity for more efficient building when dimension count is known
184
+ *
185
+ * @param capacity the initial capacity
186
+ * @return this builder
187
+ */
188
+ public Builder withCapacity (int capacity ) {
189
+ this .dimensions = new int [capacity ];
190
+ return this ;
148
191
}
149
192
150
193
/**
@@ -158,20 +201,25 @@ public static Builder newInstance() {
158
201
* @return this builder
159
202
*/
160
203
public Builder addDimension (int index , int dimValue ) {
161
- if (index < dimensions .length ) {
162
- dimensions [index ] = dimValue ;
163
- } else {
164
- int requiredSize = index + 1 ;
165
- int [] newDimensions = new int [requiredSize ];
166
- copy (dimensions , newDimensions );
167
- newDimensions [index ] = dimValue ;
168
- this .dimensions = newDimensions ;
204
+ ensureCapacity (index + 1 );
205
+ dimensions [index ] = dimValue ;
206
+ if (index > maxIndex ) {
207
+ maxIndex = index ;
169
208
}
170
209
return this ;
171
210
}
172
211
173
- private void copy (int [] from , int [] to ) {
174
- System .arraycopy (from , 0 , to , 0 , dimensions .length );
212
+ /**
213
+ * Ensures the dimensions array has sufficient capacity
214
+ * Grows by factor 1.5x for better amortized performance
215
+ */
216
+ private void ensureCapacity (int requiredSize ) {
217
+ if (requiredSize > dimensions .length ) {
218
+ int newSize = Math .max (requiredSize , dimensions .length + (dimensions .length >> 1 ));
219
+ int [] newDimensions = new int [newSize ];
220
+ System .arraycopy (dimensions , 0 , newDimensions , 0 , dimensions .length );
221
+ dimensions = newDimensions ;
222
+ }
175
223
}
176
224
177
225
/**
@@ -180,28 +228,44 @@ private void copy(int[] from, int[] to) {
180
228
* @return Capacity
181
229
*/
182
230
public Capacity build () {
183
- return new Capacity (this );
184
- }
231
+ // Special case for empty or zero-only capacity
232
+ boolean isZero = true ;
233
+ for (int i = 0 ; i <= maxIndex ; i ++) {
234
+ if (dimensions [i ] != 0 ) {
235
+ isZero = false ;
236
+ break ;
237
+ }
238
+ }
185
239
240
+ if (isZero && maxIndex < 0 ) {
241
+ return ZERO ;
242
+ }
186
243
244
+ // Create right-sized array for the final capacity
245
+ int [] rightSizedDimensions = new int [maxIndex + 1 ];
246
+ System .arraycopy (dimensions , 0 , rightSizedDimensions , 0 , maxIndex + 1 );
247
+ return new Capacity (rightSizedDimensions );
248
+ }
187
249
}
188
250
189
- private int [] dimensions ;
251
+ private final int [] dimensions ;
252
+ private final boolean isZero ; // Cache for quick zero checks
190
253
191
254
/**
192
- * copy constructor
193
- *
194
- * @param capacity capacity to be copied
255
+ * Private constructor that takes ownership of the provided array
195
256
*/
196
- private Capacity (Capacity capacity ) {
197
- this .dimensions = new int [capacity .getNuOfDimensions ()];
198
- for (int i = 0 ; i < capacity .getNuOfDimensions (); i ++) {
199
- this .dimensions [i ] = capacity .get (i );
200
- }
201
- }
257
+ private Capacity (int [] dimensions ) {
258
+ this .dimensions = dimensions ;
202
259
203
- private Capacity (Builder builder ) {
204
- dimensions = builder .dimensions ;
260
+ // Precompute if this capacity is all zeros
261
+ boolean allZeros = true ;
262
+ for (int dim : dimensions ) {
263
+ if (dim != 0 ) {
264
+ allZeros = false ;
265
+ break ;
266
+ }
267
+ }
268
+ this .isZero = allZeros ;
205
269
}
206
270
207
271
/**
@@ -213,7 +277,6 @@ public int getNuOfDimensions() {
213
277
return dimensions .length ;
214
278
}
215
279
216
-
217
280
/**
218
281
* Returns value of capacity-dimension with specified index.
219
282
* <p>
@@ -236,7 +299,10 @@ public int get(int index) {
236
299
*/
237
300
public boolean isLessOrEqual (Capacity toCompare ) {
238
301
if (toCompare == null ) throw new NullPointerException ();
239
- for (int i = 0 ; i < this .getNuOfDimensions (); i ++) {
302
+
303
+ // We can't use isZero as a fast path since dimensions can be negative
304
+ int maxDim = Math .max (this .getNuOfDimensions (), toCompare .getNuOfDimensions ());
305
+ for (int i = 0 ; i < maxDim ; i ++) {
240
306
if (this .get (i ) > toCompare .get (i )) return false ;
241
307
}
242
308
return true ;
@@ -251,12 +317,24 @@ public boolean isLessOrEqual(Capacity toCompare) {
251
317
*/
252
318
public boolean isGreaterOrEqual (Capacity toCompare ) {
253
319
if (toCompare == null ) throw new NullPointerException ();
254
- for (int i = 0 ; i < Math .max (this .getNuOfDimensions (), toCompare .getNuOfDimensions ()); i ++) {
320
+
321
+ // We can't use isZero as a fast path since dimensions can be negative
322
+ int maxDim = Math .max (this .getNuOfDimensions (), toCompare .getNuOfDimensions ());
323
+ for (int i = 0 ; i < maxDim ; i ++) {
255
324
if (this .get (i ) < toCompare .get (i )) return false ;
256
325
}
257
326
return true ;
258
327
}
259
328
329
+ /**
330
+ * Check if this is a zero capacity (all dimensions are zero)
331
+ *
332
+ * @return true if all dimensions are zero
333
+ */
334
+ public boolean isZero () {
335
+ return isZero ;
336
+ }
337
+
260
338
@ Override
261
339
public String toString () {
262
340
StringBuilder string = new StringBuilder ("[noDimensions=" + getNuOfDimensions () + "]" );
@@ -275,20 +353,35 @@ public String toString() {
275
353
*/
276
354
public static Capacity max (Capacity cap1 , Capacity cap2 ) {
277
355
if (cap1 == null || cap2 == null ) throw new IllegalArgumentException ("arg must not be null" );
278
- Capacity .Builder toReturnBuilder = Capacity .Builder .newInstance ();
279
- for (int i = 0 ; i < Math .max (cap1 .getNuOfDimensions (), cap2 .getNuOfDimensions ()); i ++) {
280
- toReturnBuilder .addDimension (i , Math .max (cap1 .get (i ), cap2 .get (i )));
356
+
357
+ int maxDim = Math .max (cap1 .getNuOfDimensions (), cap2 .getNuOfDimensions ());
358
+ int [] newDimensions = new int [maxDim ];
359
+
360
+ for (int i = 0 ; i < maxDim ; i ++) {
361
+ newDimensions [i ] = Math .max (cap1 .get (i ), cap2 .get (i ));
281
362
}
282
- return toReturnBuilder .build ();
363
+
364
+ return new Capacity (newDimensions );
283
365
}
284
366
367
+ /**
368
+ * Return the minimum, i.e. the minimum of each capacity dimension.
369
+ *
370
+ * @param cap1 first capacity to compare
371
+ * @param cap2 second capacity to compare
372
+ * @return capacity minimum of each capacity dimension
373
+ */
285
374
public static Capacity min (Capacity cap1 , Capacity cap2 ) {
286
375
if (cap1 == null || cap2 == null ) throw new IllegalArgumentException ("arg must not be null" );
287
- Capacity .Builder toReturnBuilder = Capacity .Builder .newInstance ();
288
- for (int i = 0 ; i < Math .max (cap1 .getNuOfDimensions (), cap2 .getNuOfDimensions ()); i ++) {
289
- toReturnBuilder .addDimension (i , Math .min (cap1 .get (i ), cap2 .get (i )));
376
+
377
+ int maxDim = Math .max (cap1 .getNuOfDimensions (), cap2 .getNuOfDimensions ());
378
+ int [] newDimensions = new int [maxDim ];
379
+
380
+ for (int i = 0 ; i < maxDim ; i ++) {
381
+ newDimensions [i ] = Math .min (cap1 .get (i ), cap2 .get (i ));
290
382
}
291
- return toReturnBuilder .build ();
383
+
384
+ return new Capacity (newDimensions );
292
385
}
293
386
294
387
@ Override
0 commit comments