package com.browseengine.bobo.facets.data; import it.unimi.dsi.fastutil.longs.LongArrayList; import java.util.Iterator; import java.util.List; public class TermFixedLengthLongArrayList extends TermValueList<long[]> { protected long[] _elements = null; protected int width; private final long[] sanity; private boolean withDummy = true; public TermFixedLengthLongArrayList(int width) { super(); this.width = width; sanity = new long[width]; sanity[width - 1] = -1; } public TermFixedLengthLongArrayList(int width, int capacity) { super(capacity * width); this.width = width; sanity = new long[width]; sanity[width - 1] = -1; } protected long[] parse(String s) { long[] r = new long[width]; if (s == null || s.length() == 0) return r; String[] a = s.split(","); if (a.length != width) throw new RuntimeException(s + " is not a " + width + " fixed width long."); for (int i = 0; i < width; ++i) { r[i] = Long.parseLong(a[i]); // if (r[i] < 0) // throw new RuntimeException("We only support non-negative numbers: " + s); } return r; } @Override public boolean add(String o) { int i = 0; long cmp = 0; if (_innerList.size() == 0 && o != null) // the first value added is not null withDummy = false; long[] item = parse(o); for (i = 0; i < width; ++i) { cmp = item[i] - sanity[i]; if (cmp != 0) break; } // if (cmp<=0) // throw new // RuntimeException("Values need to be added in ascending order and we only support non-negative numbers: " // + o); for (i = 0; i < width; ++i) { if (!((LongArrayList) _innerList).add(item[i])) { if (i > 0) { ((LongArrayList) _innerList).removeElements(_innerList.size() - i, _innerList.size() - 1); } return false; } } if (_innerList.size() > width || !withDummy) for (i = 0; i < width; ++i) sanity[i] = item[i]; return true; } @Override protected List<?> buildPrimitiveList(int capacity) { _type = long[].class; return capacity > 0 ? new LongArrayList(capacity) : new LongArrayList(); } @Override public void clear() { super.clear(); } @Override public String get(int index) { index = index * width; StringBuilder sb = new StringBuilder(); sb.append(_elements[index]); int left = width; ++index; while (left > 1) { sb.append(','); sb.append(_elements[index]); --left; ++index; } return sb.toString(); } @Override public long[] getRawValue(int index) { long[] val = new long[width]; index = index * width; for (int i = 0; i < width; ++i) { val[i] = _elements[index + i]; } return val; } @Override public Iterator<String> iterator() { final Iterator<?> iter = _innerList.iterator(); return new Iterator<String>() { @Override public boolean hasNext() { return iter.hasNext(); } @Override public String next() { long[] val = new long[width]; for (int i = 0; i < width; ++i) { val[i] = (Long) iter.next(); } return format(val); } @Override public void remove() { for (int i = 0; i < width; ++i) iter.remove(); } }; } @Override public int size() { return _innerList.size() / width; } @Override public Object[] toArray() { Object[] retArray = new Object[size()]; for (int i = 0; i < retArray.length; ++i) { retArray[i] = get(i); } return retArray; } public long[][] toArray(long[][] a) { long[][] retArray = new long[size()][]; for (int i = 0; i < retArray.length; ++i) { retArray[i] = getRawValue(i); } return retArray; } @Override public String format(Object o) { if (o == null) return null; if (o instanceof String) o = parse((String) o); long[] val = (long[]) o; if (val.length == 0) return null; StringBuilder sb = new StringBuilder(); sb.append(val[0]); for (int i = 1; i < val.length; ++i) { sb.append(','); sb.append(val[i]); } return sb.toString(); } public long[] getPrimitiveValue(int index) { index = index * width; long[] r = new long[width]; if (index < _elements.length) { for (int i = 0; i < width; ++i, ++index) r[i] = _elements[index]; } else { r[width - 1] = -1; } return r; } protected int binarySearch(long[] key) { return binarySearch(key, 0, _elements.length / width - 1); } protected int binarySearch(long[] key, int low, int high) { int mid = 0; long cmp = -1; int index, i; while (low <= high) { mid = (low + high) / 2; index = mid * width; for (i = 0; i < width; ++i, ++index) { cmp = key[i] - _elements[index]; if (cmp != 0) break; } if (cmp > 0) low = mid + 1; else if (cmp < 0) high = mid - 1; else return mid; } return -(mid + 1); } @Override public int indexOf(Object o) { if (withDummy) { if (o instanceof String) o = parse((String) o); return binarySearch((long[]) o, 1, _elements.length / width - 1); } else { if (o instanceof String) o = parse((String) o); return binarySearch((long[]) o); } } public int indexOf(long[] val) { if (withDummy) { return binarySearch(val, 1, _elements.length / width - 1); } else return binarySearch(val); } @Override public int indexOfWithType(long[] val) { if (withDummy) { return binarySearch(val, 1, _elements.length / width - 1); } else return binarySearch(val); } @Override public Comparable<?> getComparableValue(int index) { return get(index); } @Override public void seal() { ((LongArrayList) _innerList).trim(); _elements = ((LongArrayList) _innerList).elements(); } public boolean contains(long[] val) { if (withDummy) { return binarySearch(val, 1, _elements.length / width - 1) >= 0; } else return binarySearch(val) >= 0; } @Override public boolean containsWithType(long[] val) { if (withDummy) { return binarySearch(val, 1, _elements.length / width - 1) >= 0; } else return binarySearch(val) >= 0; } }