/* XBN Java: Generically useful, non-GUI Java code. http://sourceforge.net/projects/xbnjava Copyright (C) 1997-2003, Jeff Epstein All rights reserved. Modifications: No Redistribution in binary form, with or without modifications, are permitted provided that the following conditions are met: * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * If modifications are made to source code then this license should indicate that fact in the "Modifications" section above. * Neither the author, nor the contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. [NOTE: This license contains NO advertising clause.] */ package xbn.array; import xbn.XBNObject; import xbn.array.primitive.PrimitiveArray; import xbn.array.primitive.PASString; import xbn.string.StringOrBuffer; /**

Random functions to create, manipulate and analyze arrays.

Source code:  UtilArray.java.  Unit tests:  xbn_junit.array.JUTUtilArray.java.

@version 0.9b @author Jeff Epstein, http://sourceforge.net/projects/xbnjava. **/ public class UtilArray extends XBNObject { /**

Create a UtilArray. This constructor does nothing.

**/ public UtilArray() { } /**

Get the array index in the center of the provided indexes.

@return getMiddleIdx(i_idxLeft, i_idxRight, true) **/ public int getMiddleIdx(int i_idxLeft, int i_idxRight) { return getMiddleIdx(i_idxLeft, i_idxRight, true); } /**

Get the array index in the center of the provided indexes. This is useful when doing a binary search (see BinarySearchData).

@param i_idxLeft The left-most (starting) index bound. @param i_idxRight The right-most (ending) index bound. This is an inclusive bound (meaning this index is truly the right-most index search, and not the index after it). @param b_roundLowHigh If true, then the returned value will be rounded down (this is the default behavior of int division, and is therefore more efficient). If false, the returned value is rounded up. @return -1 If i_idxRight - i_idxLeft is less than zero.
i_idxLeft If i_idxRight - i_idxLeft is equal to zero.
((i_idxLeft / i_idxRight) + i_idxLeft) If otherwise. Rounding is taken care of, depending on the value of b_roundLowHigh.. **/ public int getMiddleIdx(int i_idxLeft, int i_idxRight, boolean b_roundLowHigh) { int iTotalElements = i_idxRight - i_idxLeft; if(iTotalElements < 0) { return -1; } if(iTotalElements == 0) { return i_idxLeft; } if(b_roundLowHigh) { //Round down. return ((iTotalElements / 2) + i_idxLeft); } //Round up. double dTotalElements = (new Double(iTotalElements)).doubleValue(); double dLeftIdx = (new Double(i_idxLeft)).doubleValue(); double dIdx = (dTotalElements / (new Double(2)).doubleValue() + dLeftIdx); Double Didx = (new Double(dIdx)); //Convert the long to an int. This eliminates precision //(rounding down). int iIdx = Didx.intValue(); if((new Double(iIdx)).equals(Didx)) { //After rounding down, the number lost no precision. //In otherwords, the result of the above division //was an integer, not a decimal. return iIdx; } //The result of the division was a decimal. Round up. return (iIdx + 1); } /**

Get a shallow clone of the provided string array.

Is there any difference between "shallow" and "deep" when it comes to string arrays? My guess is, yes, there is. A deep copy would create new string elements (new String("bla")), where the shallow clone is smart enough to reference the same string objects.

@return An array that is a clone of a_string, where the array is a copy, but the elements pointed to are the same as in a_string. **/ public final String[] getAOSShallowClone(String[] a_string) { String[] as = null; if(a_string != null) { as = new String[a_string.length]; for(int i = 0; i < a_string.length; i++) { as[i] = a_string[i]; } } return as; } /**

Get a shallow clone of the provided object array.

@return An array that is a clone of a_object, where the array is a copy, but the elements pointed to are the same as in a_object. **/ public final Object[] getAOOShallowClone(Object[] a_object) { Object[] ao = null; if(a_object != null) { ao = new Object[a_object.length]; for(int i = 0; i < a_object.length; i++) { ao[i] = a_object[i]; } } return ao; } /**

Get a full (deep) copy of the provided boolean array.

@return An array that is a full (deep) copy of a_boolean. **/ public final boolean[] getAOBClone(boolean[] a_boolean) { boolean[] ab = null; if(a_boolean != null) { ab = new boolean[a_boolean.length]; for(int i = 0; i < a_boolean.length; i++) { ab[i] = a_boolean[i]; } } return ab; } /**

Get a full (deep) copy of the provided char array.

@return An array that is a full (deep) copy of a_char. **/ public final char[] getAOCClone(char[] a_char) { char[] ac = null; if(a_char != null) { ac = new char[a_char.length]; for(int i = 0; i < a_char.length; i++) { ac[i] = a_char[i]; } } return ac; } /**

Get a full (deep) copy of the provided int array.

@return An array that is a full (deep) copy of a_int. **/ public final int[] getAOIClone(int[] a_int) { int[] ai = null; if(a_int != null) { ai = new int[a_int.length]; for(int i = 0; i < a_int.length; i++) { ai[i] = a_int[i]; } } return ai; } /**

Create an AOSLookup from the string array.

@return getAOSLFromAOS(a_string, true) **/ public final AOSLookup getAOSLFromAOS(String[] a_string) { return getAOSLFromAOS(a_string, true); } /**

Create an AOSLookup from the string array.

@return getAOSLFromPA((new PASString(a_string)), b_listUnqStrs) **/ public final AOSLookup getAOSLFromAOS(String[] a_string, boolean b_listUnqStrs) { return getAOSLFromPA((new PASString(a_string)), b_listUnqStrs); } /**

Create an AOSLookup from the PrimitiveArray.

@return getAOSLFromPA(primitive_array, true) **/ public final AOSLookup getAOSLFromPA(PrimitiveArray primitive_array) { return getAOSLFromPA(primitive_array, true); } /**

Create an AOSLookup from the PrimitiveArray.

@param primitive_array The PrimitiveArray. May not be null, primitive_array.isNull must be false and primitive_array.getLength may not be zero. @return If primitive_array.wasValidated() equals true and primitive_array.getPrimitiveArrayRule().getPARDupNullLen().areDupsOk() equals false, then the AOSLCreator is created with the following constructor parameters: (false, primitive_array.getLength(), b_listUnqStrs). If either of these two conditions are not met, then the AOSLCreator is created with the constructor parameters: (true, b_listUnqStrs). The former's internal Hashtable is optimized from the start. The latter recreates (optimizes) the Hashtable after all strings have been added. **/ public final AOSLookup getAOSLFromPA(PrimitiveArray primitive_array, boolean b_listUnqStrs) { try { if(primitive_array.isNull()) { throwAX("getAOSLFromPA: primitive_array.isNull() equals true."); } if(primitive_array.getLength() < 1) { throwAX("getAOSLFromPA: primitive_array.getLength() is zero."); } } catch(NullPointerException npx) { throwAX("getAOSLFromPA: primitive_array is null."); } AOSLCreator aoslc = null; if(primitive_array.wasValidated() && !primitive_array.getPrimitiveArrayRule().getPARDupNullLen().areDupsOk()) { aoslc = new AOSLCreator(false, primitive_array.getLength(), b_listUnqStrs); } else { aoslc = new AOSLCreator(true, b_listUnqStrs); } for(int i = 0; i < primitive_array.getLength(); i++) { aoslc.addString(primitive_array.getString(i)); } aoslc.lock(); return aoslc.getAOSLookup(); } /**

Append the list of toStrings for an array of objects onto the provided StringOrBuffer.

@param str_orBfr The StringOrBuffer to append to. May not be null. @param a_object The array of objects to generate toStrings on. @param s_prefix The prefix to append before the toString list, only if a_object is non-null and at least one element in length. If null, then nothing is put before the list (meaning null is the same empty string [''], only faster). If non-null, then this is concatenated to str_orBfr before the toString list. @param s_divider The text to put between each element's toString. @param s_postfix Same as s_prefix, except this is put at the end, after the toString list. @param s_ifNull If a_object is null, then this is the (only) string appended onto str_orBfr. All other string parameters are ignored when a_object is null. @param s_ifEmpty If a_object has zero elements, then this is the (only) string appended onto str_orBfr. All other string parameters are ignored when a_object is zero elements in length. @param s_ifLmntNull When an element within a_object is null, this is the value to appended in place of that element's toString. **/ public final void appendTSList(StringOrBuffer str_orBfr, Object[] a_object, String s_prefix, String s_divider, String s_postfix, String s_ifNull, String s_ifEmpty, String s_ifLmntNull) { try { if(a_object == null) { str_orBfr.append(s_ifNull); return; } } catch(NullPointerException npx) { throwAX("appendTSList: str_orBfr is null."); } if(a_object.length == 0) { str_orBfr.append(s_ifEmpty); return; } if(s_prefix != null) { str_orBfr.append(s_prefix); } for(int i = 0; i < a_object.length; i++) { if(a_object[i] == null) { str_orBfr.append(s_ifLmntNull); } else { str_orBfr.append(a_object.toString()); } } if(s_postfix != null) { str_orBfr.append(s_postfix); } } }