View Javadoc
1   /*
2    * Copyright (c) 2001-2017, Zoltan Farkas All Rights Reserved.
3    *
4    * This library is free software; you can redistribute it and/or
5    * modify it under the terms of the GNU Lesser General Public
6    * License as published by the Free Software Foundation; either
7    * version 2.1 of the License, or (at your option) any later version.
8    *
9    * This library 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 General Public License for more details.
13   *
14   * You should have received a copy of the GNU Lesser General Public
15   * License along with this program; if not, write to the Free Software
16   * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
17   *
18   * Additionally licensed with:
19   *
20   * Licensed under the Apache License, Version 2.0 (the "License");
21   * you may not use this file except in compliance with the License.
22   * You may obtain a copy of the License at
23   *
24   *      http://www.apache.org/licenses/LICENSE-2.0
25   *
26   * Unless required by applicable law or agreed to in writing, software
27   * distributed under the License is distributed on an "AS IS" BASIS,
28   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29   * See the License for the specific language governing permissions and
30   * limitations under the License.
31   */
32  package org.spf4j.base;
33  
34  import com.google.common.annotations.Beta;
35  import com.google.common.annotations.GwtCompatible;
36  import com.google.common.annotations.GwtIncompatible;
37  import com.google.common.collect.ObjectArrays;
38  import java.lang.annotation.Annotation;
39  import java.lang.reflect.Array;
40  
41  /**
42   * Array utilities.
43   *
44   * @author zoly
45   */
46  @GwtCompatible
47  public final class Arrays {
48  
49    public static final Object[] EMPTY_OBJ_ARRAY = new Object[]{};
50  
51    public static final Annotation[] EMPTY_ANNOT_ARRAY = new Annotation[]{};
52  
53    public static final Class[] EMPTY_CLASS_ARRAY = new Class[]{};
54  
55    public static final String[] EMPTY_STRING_ARRAY = new String[]{};
56  
57    public static final byte[] EMPTY_BYTE_ARRAY = new byte[]{};
58  
59    public static final char[] EMPTY_CHAR_ARRAY = new char[]{};
60  
61    public static final boolean[] EMPTY_BOOLEAN_ARRAY = new boolean[]{};
62  
63    public static final long[] EMPTY_LONG_ARRAY = new long[]{};
64  
65    public static final int[] EMPTY_INT_ARRAY = new int[]{};
66  
67    private static final int ARR_CPY_THR = 128;
68  
69    private Arrays() {
70    }
71  
72    public static double[] getColumnAsDoubles(final long[][] data, final int columnNumber) {
73      double[] result = new double[data.length];
74      for (int i = 0; i < result.length; i++) {
75        result[i] = data[i][columnNumber];
76      }
77      return result;
78    }
79  
80    public static double[] getColumn(final double[][] data, final int columnNumber) {
81      double[] result = new double[data.length];
82      for (int i = 0; i < result.length; i++) {
83        result[i] = data[i][columnNumber];
84      }
85      return result;
86    }
87  
88    public static double[] toDoubleArray(final long... larr) {
89      double[] result = new double[larr.length];
90      for (int i = 0; i < larr.length; i++) {
91        result[i] = larr[i];
92      }
93      return result;
94    }
95  
96    public static Object[] toObjectArray(final long... larr) {
97      Object[] result = new Object[larr.length];
98      for (int i = 0; i < larr.length; i++) {
99        result[i] = larr[i];
100     }
101     return result;
102   }
103 
104   public static double[] divide(final double[] arr1, final double[] arr2) {
105     double[] result = new double[arr1.length];
106     for (int i = 0; i < result.length; i++) {
107       result[i] = arr1[i] / arr2[i];
108     }
109     return result;
110   }
111 
112   public static boolean deepEquals(final Object[] a1, final Object[] a2, final int starting) {
113     return deepEquals(a1, a2, starting, a1.length);
114   }
115 
116   public static boolean deepEquals(final Object[] a1, final Object[] a2, final int starting, final int ending) {
117     if (a1 == a2) {
118       return true;
119     }
120     if (a1 == null || a2 == null) {
121       return false;
122     }
123     for (int i = starting; i < ending; i++) {
124       if (!java.util.Objects.deepEquals(a1[i], a2[i])) {
125         return false;
126       }
127     }
128     return true;
129   }
130 
131   public static boolean equals(final byte[] a, final byte[] b, final int a1,  final int b1, final int length) {
132     for (int i = a1, j = b1, k = 0; k < length; i++, j++, k++) {
133       if (a[i] != b[j]) {
134         return false;
135       }
136     }
137     return true;
138   }
139 
140 
141   public static int search(final char[] array, final char c) {
142     for (int i = 0; i < array.length; i++) {
143       if (array[i] == c) {
144         return i;
145       }
146     }
147     return -1;
148   }
149 
150   public static <T> T[] moveOfRange(final T[] original, final int from, final int to) {
151     int newLength = to - from;
152     if (newLength < 0) {
153       throw new IllegalArgumentException(from + " > " + to);
154     }
155     T[] copy = ObjectArrays.newArray(original, newLength);
156     for (int i = from, j = 0; i < to; i++, j++) {
157       copy[j] = original[i];
158       original[i] = null;
159     }
160     return copy;
161   }
162 
163   public static <T> T[] append(final T[] array, final T value) {
164     T[] result = java.util.Arrays.copyOf(array, array.length + 1);
165     result[array.length] = value;
166     return result;
167   }
168 
169   @GwtIncompatible
170   public static <T> T[] preppend(final T[] array, final T value) {
171     Class<? extends Object[]> aClass = array.getClass();
172     T[] copy = ((Object) aClass == (Object) Object[].class)
173             ? (T[]) new Object[array.length + 1]
174             : (T[]) Array.newInstance(aClass.getComponentType(), array.length + 1);
175     System.arraycopy(array, 0, copy, 1, array.length);
176 
177     copy[0] = value;
178     return copy;
179   }
180 
181   @GwtIncompatible
182   public static <T> T[] preppend(final T[] array, final T... values) {
183     Class<? extends Object[]> aClass = array.getClass();
184     T[] copy = ((Object) aClass == (Object) Object[].class)
185             ? (T[]) new Object[array.length + values.length]
186             : (T[]) Array.newInstance(aClass.getComponentType(), array.length + values.length);
187     System.arraycopy(array, 0, copy, values.length, array.length);
188     System.arraycopy(values, 0, copy, 0, values.length);
189     return copy;
190   }
191 
192   public static <T> T[] append(final T[] array, final T... values) {
193     if (values.length == 0) {
194       return array;
195     }
196     T[] result = java.util.Arrays.copyOf(array, array.length + values.length);
197     System.arraycopy(values, 0, result, array.length, values.length);
198     return result;
199   }
200 
201 
202   public static <T> T[] concat(final T[]... arrays) {
203     if (arrays.length < 2) {
204       throw new IllegalArgumentException("You should concatenate at least 2 arrays: "
205               + arrays.length);
206     }
207     int newLength = 0;
208     for (T[] arr : arrays) {
209       newLength += arr.length;
210     }
211     T[] result = ObjectArrays.newArray(arrays[0], newLength);
212     int destIdx = 0;
213     for (T[] arr : arrays) {
214       System.arraycopy(arr, 0, result, destIdx, arr.length);
215       destIdx += arr.length;
216     }
217     return result;
218   }
219 
220   public static byte[] concat(final  byte[]... arrays) {
221     if (arrays.length < 2) {
222       throw new IllegalArgumentException("You should concatenate at least 2 arrays: "
223               + arrays.length);
224     }
225     int newLength = 0;
226     for (byte[] arr : arrays) {
227       newLength += arr.length;
228     }
229     byte[] result = new byte[newLength];
230     int destIdx = 0;
231     for (byte[] arr : arrays) {
232       System.arraycopy(arr, 0, result, destIdx, arr.length);
233       destIdx += arr.length;
234     }
235     return result;
236   }
237 
238   public static <T> int indexOf(final T[] array, final T content) {
239     int result = -1;
240     for (int i = 0; i < array.length; i++) {
241       if (array[i].equals(content)) {
242         return i;
243       }
244     }
245     return result;
246   }
247 
248   /**
249    * implementation which significantly faster for large arrays (> 500).
250    */
251   @Beta
252   public static void fill(final byte[] array, final int startIdx, final int endIdx, final byte value) {
253     int len = endIdx - startIdx;
254     if (len > 0) {
255       if (endIdx > array.length || startIdx < 0) {
256         throw new IllegalArgumentException("Illegal range from " + startIdx + " to " + endIdx);
257       }
258       if (len <= ARR_CPY_THR) {
259         for (int i = startIdx; i < endIdx; i++) {
260           array[i] = value;
261         }
262       } else {
263         int fillEnd = startIdx + ARR_CPY_THR;
264         for (int i = startIdx; i < fillEnd; i++) {
265           array[i] = value;
266         }
267         array[startIdx] = value;
268         for (int i = ARR_CPY_THR; i < len; i += i) {
269           int lmi = len - i;
270           int from = startIdx + i;
271           if (lmi < i) {
272             if (lmi < ARR_CPY_THR) {
273               int xe = from + lmi;
274               for (int j = from; j < xe; j++) {
275                 array[j] = value;
276               }
277             } else {
278               System.arraycopy(array, startIdx, array, from, lmi);
279             }
280           } else {
281             System.arraycopy(array, startIdx, array, from, i);
282           }
283         }
284       }
285     } else if (len < 0) {
286       throw new IllegalArgumentException("Illegal range from " + startIdx + " to " + endIdx);
287     }
288   }
289 
290 
291   /**
292    * implementation which is significantly faster for large arrays (> 500).
293    * Bechmark results:
294    * Benchmark                                      Mode Cnt Score            Error           Units
295    * ArraysBenchmark.testSpf4jFillSmall(10)         thrpt 10 1048892782.375   ± 29976629.818  ops/s
296    * ArraysBenchmark.testjdkFillSmall(10)           thrpt 10 1046330835.509   ± 47577260.717  ops/s
297    * ArraysBenchmark.testSpf4jFillMedium(100)       thrpt 10 123724912.161    ± 4049077.779   ops/s
298    * ArraysBenchmark.testjdkFillMedium(100)         thrpt 10 124143139.498    ± 2044760.427   ops/s
299    * ArraysBenchmark.testSpf4jFillLarge(1000)       thrpt 10 20335282.192     ± 592359.181    ops/s
300    * ArraysBenchmark.testjdkFillLarge(1000)         thrpt 10 12661975.522     ± 170457.046    ops/s
301    * ArraysBenchmark.testSpf4jFillVeryLarge(10000)  thrpt 10 2767351.098      ± 74871.147     ops/s
302    * ArraysBenchmark.testjdkFillVeryLarge(10000     thrpt 10 1045099.669      ± 30044.505     ops/s
303    *
304    */
305   @Beta
306   public static <T> void fill(final T[] array, final int startIdx, final int endIdx, final T value) {
307     int len = endIdx - startIdx;
308     if (len > 0) {
309       if (endIdx > array.length || startIdx < 0) {
310         throw new IllegalArgumentException("Illegal range from " + startIdx + " to " + endIdx);
311       }
312       if (len <= ARR_CPY_THR) {
313         for (int i = startIdx; i < endIdx; i++) {
314           array[i] = value;
315         }
316       } else {
317         int fillEnd = startIdx + ARR_CPY_THR;
318         for (int i = startIdx; i < fillEnd; i++) {
319           array[i] = value;
320         }
321         array[startIdx] = value;
322         for (int i = ARR_CPY_THR; i < len; i += i) {
323           int lmi = len - i;
324           int from = startIdx + i;
325           if (lmi < i) {
326             if (lmi < ARR_CPY_THR) {
327               int xe = from + lmi;
328               for (int j = from; j < xe; j++) {
329                 array[j] = value;
330               }
331             } else {
332               System.arraycopy(array, startIdx, array, from, lmi);
333             }
334           } else {
335             System.arraycopy(array, startIdx, array, from, i);
336           }
337         }
338       }
339     } else if (len < 0) {
340       throw new IllegalArgumentException("Illegal range from " + startIdx + " to " + endIdx);
341     }
342   }
343 
344   @Beta
345   public static void fill(final char[] array, final int startIdx, final int endIdx, final char value) {
346     int len = endIdx - startIdx;
347     if (len > 0) {
348       if (endIdx > array.length || startIdx < 0) {
349         throw new IllegalArgumentException("Illegal range from " + startIdx + " to " + endIdx);
350       }
351       if (len <= ARR_CPY_THR) {
352         for (int i = startIdx; i < endIdx; i++) {
353           array[i] = value;
354         }
355       } else {
356         int fillEnd = startIdx + ARR_CPY_THR;
357         for (int i = startIdx; i < fillEnd; i++) {
358           array[i] = value;
359         }
360         array[startIdx] = value;
361         for (int i = ARR_CPY_THR; i < len; i += i) {
362           int lmi = len - i;
363           int from = startIdx + i;
364           if (lmi < i) {
365             if (lmi < ARR_CPY_THR) {
366               int xe = from + lmi;
367               for (int j = from; j < xe; j++) {
368                 array[j] = value;
369               }
370             } else {
371               System.arraycopy(array, startIdx, array, from, lmi);
372             }
373           } else {
374             System.arraycopy(array, startIdx, array, from, i);
375           }
376         }
377       }
378     } else if (len < 0) {
379       throw new IllegalArgumentException("Illegal range from " + startIdx + " to " + endIdx);
380     }
381   }
382 
383   @Beta
384   public static void fill(final int[] array, final int startIdx, final int endIdx, final int value) {
385     int len = endIdx - startIdx;
386     if (len > 0) {
387       if (endIdx > array.length || startIdx < 0) {
388         throw new IllegalArgumentException("Illegal range from " + startIdx + " to " + endIdx);
389       }
390       if (len <= ARR_CPY_THR) {
391         for (int i = startIdx; i < endIdx; i++) {
392           array[i] = value;
393         }
394       } else {
395         int fillEnd = startIdx + ARR_CPY_THR;
396         for (int i = startIdx; i < fillEnd; i++) {
397           array[i] = value;
398         }
399         array[startIdx] = value;
400         for (int i = ARR_CPY_THR; i < len; i += i) {
401           int lmi = len - i;
402           int from = startIdx + i;
403           if (lmi < i) {
404             if (lmi < ARR_CPY_THR) {
405               int xe = from + lmi;
406               for (int j = from; j < xe; j++) {
407                 array[j] = value;
408               }
409             } else {
410               System.arraycopy(array, startIdx, array, from, lmi);
411             }
412           } else {
413             System.arraycopy(array, startIdx, array, from, i);
414           }
415         }
416       }
417     } else if (len < 0) {
418       throw new IllegalArgumentException("Illegal range from " + startIdx + " to " + endIdx);
419     }
420   }
421 
422   @Beta
423   public static void fill(final long[] array, final int startIdx, final int endIdx, final long value) {
424     int len = endIdx - startIdx;
425     if (len > 0) {
426       if (endIdx > array.length || startIdx < 0) {
427         throw new IllegalArgumentException("Illegal range from " + startIdx + " to " + endIdx);
428       }
429       if (len <= ARR_CPY_THR) {
430         for (int i = startIdx; i < endIdx; i++) {
431           array[i] = value;
432         }
433       } else {
434         int fillEnd = startIdx + ARR_CPY_THR;
435         for (int i = startIdx; i < fillEnd; i++) {
436           array[i] = value;
437         }
438         array[startIdx] = value;
439         for (int i = ARR_CPY_THR; i < len; i += i) {
440           int lmi = len - i;
441           int from = startIdx + i;
442           if (lmi < i) {
443             if (lmi < ARR_CPY_THR) {
444               int xe = from + lmi;
445               for (int j = from; j < xe; j++) {
446                 array[j] = value;
447               }
448             } else {
449               System.arraycopy(array, startIdx, array, from, lmi);
450             }
451           } else {
452             System.arraycopy(array, startIdx, array, from, i);
453           }
454         }
455       }
456     } else if (len < 0) {
457       throw new IllegalArgumentException("Illegal range from " + startIdx + " to " + endIdx);
458     }
459   }
460 
461   @Beta
462   public static void fill(final double[] array, final int startIdx, final int endIdx, final double value) {
463     int len = endIdx - startIdx;
464     if (len > 0) {
465       if (endIdx > array.length || startIdx < 0) {
466         throw new IllegalArgumentException("Illegal range from " + startIdx + " to " + endIdx);
467       }
468       if (len <= ARR_CPY_THR) {
469         for (int i = startIdx; i < endIdx; i++) {
470           array[i] = value;
471         }
472       } else {
473         int fillEnd = startIdx + ARR_CPY_THR;
474         for (int i = startIdx; i < fillEnd; i++) {
475           array[i] = value;
476         }
477         array[startIdx] = value;
478         for (int i = ARR_CPY_THR; i < len; i += i) {
479           int lmi = len - i;
480           int from = startIdx + i;
481           if (lmi < i) {
482             if (lmi < ARR_CPY_THR) {
483               int xe = from + lmi;
484               for (int j = from; j < xe; j++) {
485                 array[j] = value;
486               }
487             } else {
488               System.arraycopy(array, startIdx, array, from, lmi);
489             }
490           } else {
491             System.arraycopy(array, startIdx, array, from, i);
492           }
493         }
494       }
495     } else if (len < 0) {
496       throw new IllegalArgumentException("Illegal range from " + startIdx + " to " + endIdx);
497     }
498   }
499 
500   public static byte[] charsToBytes(final char[] chars) {
501     byte[] bytes = new byte[chars.length * 2];
502     for (int i = 0, k = 0; i < chars.length; i++, k += 2) {
503       char v = chars[i];
504       bytes[k] = (byte) (0xff & (v >> 8));
505       bytes[k + 1] = (byte) (0xff & (v));
506     }
507     return bytes;
508   }
509 
510   public static char[] bytesToChars(final byte[] bytes) {
511     char[] chars = new char[bytes.length / 2];
512     for (int i = 0, k = 0; i < chars.length; i++, k += 2) {
513       char v = (char) (((0xff & (bytes[k])) << 8) | (0xff & bytes[k + 1]));
514       chars[i] = v;
515     }
516     return chars;
517   }
518 
519 }