@Override public NavigableMap<Long, Long> findGtEqIds(Dictionary<Long> otherDict) { NavigableMap<Long, Long> res = new TreeMap<>(); if (otherDict instanceof ArrayCompressedLongDictionary) { CompressedLongArray<?> otherSortedValues = ((ArrayCompressedLongDictionary) otherDict).sortedValues; if (sortedValues.size() == 0 || otherSortedValues.size() == 0) return res; // good case: we can traverse the two arrays simultaneously and only need to store O(1) in // memory. int posThis = 0; int posOther = 0; long decompressedThis = sortedValues.get(posThis); long decompressedOther = otherSortedValues.get(posOther); while (decompressedThis < decompressedOther && posThis < sortedValues.size() - 1) decompressedThis = sortedValues.get(++posThis); boolean doBreak = false; while (!doBreak) { while (decompressedThis > decompressedOther) { // "inner while loop" if (posOther == otherSortedValues.size() - 1) { while (posThis < sortedValues.size()) res.put((long) posThis++, (long) -(posOther + 1)); doBreak = true; break; } decompressedOther = otherSortedValues.get(++posOther); } if (!doBreak) { if (decompressedThis == decompressedOther) { res.put((long) posThis, (long) posOther); } else { // we know: decompressedOther > decompressedThis // but: in previous run of "inner while loop", decompressedOther < decompressedThis. // so: mark posThis as being greater than the previous posOther, restore position in // other dict and proceed // 'this' one forward. If in the next loop, decompressedThis is still >= the next item // in other, then we // will visit this very same execution again right away. decompressedOther = otherSortedValues.get(--posOther); res.put((long) posThis, (long) -(posOther + 1)); } if (posThis == sortedValues.size() - 1) doBreak = true; else decompressedThis = sortedValues.get(++posThis); } } } else if (otherDict instanceof ConstantLongDictionary) { long otherId = ((ConstantLongDictionary) otherDict).getId(); long otherValue = ((ConstantLongDictionary) otherDict).getDecompressedValue(); Long ourGtEqId = findGtEqIdOfValue(otherValue); if (ourGtEqId != null) { if (ourGtEqId < 0) { ourGtEqId = -(ourGtEqId + 1); otherId = -(otherId + 1); } res.put(ourGtEqId, otherId); if (otherId > 0) otherId = -(otherId + 1); for (long ourId = ourGtEqId + 1; ourId < sortedValues.size(); ourId++) res.put(ourId, otherId); } } else if (otherDict instanceof EmptyLongDictionary) { // noop. } else { // Bad case: decompress whole array. long[] decompressedValues = sortedValues.decompressedArray(); for (int i = 0; i < decompressedValues.length; i++) { Long otherId = otherDict.findLtEqIdOfValue(decompressedValues[i]); if (otherId == null) break; res.put((long) i, otherId); } } return res; }
@Override public NavigableMap<Long, Long> findLtEqIds(Dictionary<Long> otherDict) { NavigableMap<Long, Long> res = new TreeMap<>(); if (otherDict instanceof ArrayCompressedLongDictionary) { CompressedLongArray<?> otherSortedValues = ((ArrayCompressedLongDictionary) otherDict).sortedValues; if (sortedValues.size() == 0 || otherSortedValues.size() == 0) return res; // good case: we can traverse the two arrays simultaneously and only need to store O(1) in // memory. int posThis = 0; int posOther = 0; long decompressedThis = sortedValues.get(posThis); long decompressedOther = otherSortedValues.get(posOther); boolean doBreak = false; while (!doBreak) { while (decompressedThis > decompressedOther) { if (posOther == otherSortedValues.size() - 1) { doBreak = true; break; } decompressedOther = otherSortedValues.get(++posOther); } if (!doBreak) { if (decompressedThis == decompressedOther) res.put((long) posThis, (long) posOther); else // we know: decompressedThis < decompressedOther res.put((long) posThis, (long) -(posOther + 1)); if (posThis == sortedValues.size() - 1) // done processing doBreak = true; else // move this one further decompressedThis = sortedValues.get(++posThis); } } } else if (otherDict instanceof ConstantLongDictionary) { long otherId = ((ConstantLongDictionary) otherDict).getId(); long otherValue = ((ConstantLongDictionary) otherDict).getDecompressedValue(); Long ourLtEqId = findLtEqIdOfValue(otherValue); if (ourLtEqId != null) { if (ourLtEqId < 0) { ourLtEqId = -(ourLtEqId + 1); otherId = -(otherId + 1); } res.put(ourLtEqId, otherId); if (otherId > 0) otherId = -(otherId + 1); for (long ourId = 0; ourId < ourLtEqId; ourId++) res.put(ourId, otherId); } } else if (otherDict instanceof EmptyLongDictionary) { // noop. } else { // Bad case: decompress whole array. long[] decompressedValues = sortedValues.decompressedArray(); for (int i = 0; i < decompressedValues.length; i++) { Long otherId = otherDict.findGtEqIdOfValue(decompressedValues[i]); if (otherId == null) break; res.put((long) i, otherId); } } return res; }
@Override public NavigableMap<Long, Long> findEqualIds(Dictionary<Long> otherDict) { NavigableMap<Long, Long> res = new TreeMap<>(); if (otherDict instanceof ArrayCompressedLongDictionary) { CompressedLongArray<?> otherSortedValues = ((ArrayCompressedLongDictionary) otherDict).sortedValues; if (sortedValues.size() == 0 || otherSortedValues.size() == 0) return res; // good case: we can traverse the two arrays simultaneously and only need to store O(1) in // memory. int posThis = 0; int posOther = 0; long decompressedThis = sortedValues.get(posThis); long decompressedOther = otherSortedValues.get(posOther); while (posThis < sortedValues.size() && posOther < otherSortedValues.size()) { // move 'posThis' right until decompressedThis is >= decompressedOther while (posThis < sortedValues.size() - 1 && decompressedThis < decompressedOther) decompressedThis = sortedValues.get(++posThis); // move 'posOther' right until decompressedOther is >= decompressedThis while (posOther < otherSortedValues.size() - 1 && decompressedOther < decompressedThis) decompressedOther = otherSortedValues.get(++posOther); // validate if we have a match if (decompressedThis == decompressedOther) { res.put((long) posThis++, (long) posOther++); if (posThis < sortedValues.size() && posOther < otherSortedValues.size()) { decompressedThis = sortedValues.get(posThis); decompressedOther = otherSortedValues.get(posOther); } } else if ((posThis == sortedValues.size() - 1 && decompressedThis < decompressedOther) || (posThis == sortedValues.size() - 1 && posOther == otherSortedValues.size() - 1)) break; } } else if (otherDict instanceof ConstantLongDictionary) { long otherId = ((ConstantLongDictionary) otherDict).getId(); long otherValue = ((ConstantLongDictionary) otherDict).getDecompressedValue(); try { long ourId = findIdOfValue(otherValue); res.put(ourId, otherId); } catch (IllegalArgumentException e) { // swallow, return empty dict. } } else if (otherDict instanceof EmptyLongDictionary) { // noop. } else { // Bad case: decompress whole array (should not happen, though) long[] decompressedValues = sortedValues.decompressedArray(); Long[] otherIds = otherDict.findIdsOfValues( LongStream.of(decompressedValues).mapToObj(Long::valueOf).toArray(l -> new Long[l])); for (int i = 0; i < decompressedValues.length; i++) { Long otherId = otherIds[i]; if (otherId != -1L) res.put((long) i, otherId); } } return res; }