/* Copyright (c) 2005 Robert Alten Simons (info@cohort.com).
* See the MIT/X-like license in LICENSE.txt.
* For more information visit www.cohort.com or contact info@cohort.com.
*/
package ucar.nc2.ogc.erddap.util;
import ucar.nc2.constants.CDM;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
/**
* StringArray is a thin shell over a String[] with methods like ArrayList's
* methods; it extends PrimitiveArray.
* All of the methods which add strings to StringArray (e.g., add()),
* use String2.canonical(), to ensure that canonical Strings are stored (to save memory
* if there are duplicates).
*
* <p>This class uses "" to represent a missing value (NaN).
*/
public class ErddapStringArray {
/** The number of active values (which may be different from the array's capacity). */
protected int size = 0;
/**
* This is the main data structure.
* This should be private, but is public so you can manipulate it if you
* promise to be careful.
* Note that if the PrimitiveArray's capacity is increased,
* the PrimitiveArray will use a different array for storage.
*/
public String[] array;
/**
* A constructor for a capacity of 8 elements. The initial 'size' will be 0.
*/
public ErddapStringArray() {
array = new String[8];
}
/**
* Reads the contents of {@code inputStream} into a StringArray. Each line of input will result in an element in
* the array.
* <p/>
* The specified stream remains open after this method returns.
*
* @param inputStream a stream with line-based content.
* @param charset the name of a supported {@link java.nio.charset.Charset charset}.
* @return a StringArray created from the stream.
* @throws IOException if an I/O error occurs
*/
public static ErddapStringArray fromInputStream(InputStream inputStream, String charset) throws IOException {
if (charset == null || charset.isEmpty()) {
charset = CDM.UTF8;
}
InputStreamReader isr = new InputStreamReader(inputStream, charset);
BufferedReader bufferedReader = new BufferedReader(isr);
ErddapStringArray sa = new ErddapStringArray();
for (String s; (s = bufferedReader.readLine()) != null; ) {
sa.add(s);
}
// Do not call BufferedReader.close() here; that would close the underlying InputStream, which is the
// responsibility of the client. This ought to be safe, as neither InputStreamReader nor BufferedReader hold any
// resources that a call to close() would make free and which the garbage collector would not make free anyway.
return sa;
}
/**
* Return the number of elements in the array.
*
* @return the number of elements in the array.
*/
public int size() {
return size;
}
/**
* This adds an item to the array (increasing 'size' by 1).
*
* @param value the value to be added to the array
*/
public void add(String value) {
if (size == array.length) //if we're at capacity
ensureCapacity(size + 1L);
array[size++] = value;
}
/**
* This ensures that the capacity is at least 'minCapacity'.
*
* @param minCapacity the minimum acceptable capacity.
* minCapacity is type long, but >= Integer.MAX_VALUE will throw exception.
*/
public void ensureCapacity(long minCapacity) {
if (array.length < minCapacity) {
//ensure minCapacity is < Integer.MAX_VALUE
ErddapMath2.ensureArraySizeOkay(minCapacity, "StringArray");
//caller may know exact number needed, so don't double above 2x current size
int newCapacity = (int)Math.min(Integer.MAX_VALUE - 1, array.length + (long)array.length);
if (newCapacity < minCapacity)
newCapacity = (int)minCapacity; //safe since checked above
String[] newArray = new String[newCapacity];
System.arraycopy(array, 0, newArray, 0, size);
array = newArray; //do last to minimize concurrency problems
}
}
/**
* This gets a specified element.
*
* @param index 0 ... size-1
*/
public String get(int index) {
if (index >= size)
throw new IllegalArgumentException(ErddapString2.ERROR + " in StringArray.get: index (" +
index + ") >= size (" + size + ").");
return array[index];
}
}