package edu.berkeley.cs.succinct.buffers; import edu.berkeley.cs.succinct.StorageMode; import edu.berkeley.cs.succinct.SuccinctTable; import edu.berkeley.cs.succinct.util.container.Range; import java.io.DataInputStream; import java.nio.ByteBuffer; import java.util.*; public class SuccinctTableBuffer extends SuccinctIndexedFileBuffer implements SuccinctTable { /** * Constructor to initialize SuccinctIndexedBuffer from input byte array and offsets corresponding to records. * * @param input The input byte array. * @param offsets Offsets corresponding to records. */ public SuccinctTableBuffer(byte[] input, int[] offsets) { super(input, offsets); } /** * Constructor to load the data from persisted Succinct data-structures. * * @param path Path to load data from. * @param storageMode Mode in which data is stored (In-memory or Memory-mapped) */ public SuccinctTableBuffer(String path, StorageMode storageMode) { super(path, storageMode); } /** * Constructor to load the data from a DataInputStream. * * @param is Input stream to load the data from */ public SuccinctTableBuffer(DataInputStream is) { super(is); } /** * Constructor to load the data from a ByteBuffer. * * @param buf Input buffer to load the data from */ public SuccinctTableBuffer(ByteBuffer buf) { super(buf); } /** * Perform multiple searches with different query types and return the intersection of the results. * * @param queryTypes The QueryType corresponding to each query * @param queries The actual query parameters associated with each query * @return The records matching the multi-search queries. */ @Override public Integer[] recordMultiSearchIds(SuccinctTable.QueryType[] queryTypes, byte[][][] queries) { assert (queryTypes.length == queries.length); Set<Integer> recordIds = new HashSet<>(); if (queries.length == 0) { throw new IllegalArgumentException("recordMultiSearchIds called with empty queries"); } // Get all ranges ArrayList<Range> ranges = new ArrayList<>(); for (int qid = 0; qid < queries.length; qid++) { Range range; switch (queryTypes[qid]) { case Search: { range = bwdSearch(queries[qid][0]); break; } case RangeSearch: { byte[] queryBegin = queries[qid][0]; byte[] queryEnd = queries[qid][1]; range = rangeSearch(queryBegin, queryEnd); break; } default: { throw new UnsupportedOperationException("Unsupported QueryType"); } } if (range.second - range.first + 1 > 0) { ranges.add(range); } else { return new Integer[0]; } } Collections.sort(ranges, new RangeSizeComparator()); // Populate the set of offsets corresponding to the first range Range firstRange = ranges.get(0); Map<Integer, Integer> counts = new HashMap<>(); { long sp = firstRange.first, ep = firstRange.second; for (long i = 0; i < ep - sp + 1; i++) { long saVal = lookupSA(sp + i); int recordId = offsetToRecordId((int) saVal); recordIds.add(recordId); counts.put(recordId, 1); } } ranges.remove(firstRange); for (Range range : ranges) { long sp = range.first, ep = range.second; for (long i = 0; i < ep - sp + 1; i++) { long saVal = lookupSA(sp + i); int recordId = offsetToRecordId((int) saVal); if (recordIds.contains(recordId)) { counts.put(recordId, counts.get(recordId) + 1); } } } return recordIds.toArray(new Integer[recordIds.size()]); } }