package redis.util; import java.util.*; /** * Sorted by score, look up by key * <p/> * User: sam * Date: 7/29/12 * Time: 4:40 PM */ public class ZSet implements Iterable<ZSetEntry> { private static final BytesKey EMPTY = new BytesKey(new byte[0]); // A way to find an entry by key private BytesKeyObjectMap<ZSetEntry> map = new BytesKeyObjectMap<ZSetEntry>(); // A list that we keep sorted by score private List<ZSetEntry> list = new ArrayList<ZSetEntry>(); public ZSet(ZSet destination) { map.putAll(destination.map); list.addAll(destination.list); } public ZSet() { } public int size() { return list.size(); } public ZSetEntry get(byte[] member2) { return map.get(member2); } public boolean remove(byte[] member2) { return remove(new BytesKey(member2)); } @Override public Iterator<ZSetEntry> iterator() { return list.iterator(); } public ZSetEntry get(BytesKey key) { return map.get(key); } public List<ZSetEntry> list() { return list; } private static class ScoreComparator implements Comparator<ZSetEntry> { @Override public int compare(ZSetEntry o1, ZSetEntry o2) { double value = o1.getScore() - o2.getScore(); return value < 0 ? -1 : value == (o1.getKey().compareTo(o2.getKey())) ? 0 : 1; } } public void addAll(ZSet other) { for (ZSetEntry zSetEntry : other.list) { remove(zSetEntry.getKey()); add(zSetEntry.getKey(), zSetEntry.getScore()); } } public boolean remove(BytesKey key) { ZSetEntry current = map.get(key); if (current != null) { map.remove(key); int index = Collections.binarySearch(list, current); list.remove(index); } return current == null; } public boolean add(BytesKey key, double score) { ZSetEntry current = map.get(key); if (current != null) { map.remove(key); int index = Collections.binarySearch(list, current); list.remove(index); } ZSetEntry entry = new ZSetEntry(key, score); map.put(key, entry); int index = find(Collections.binarySearch(list, entry)); list.add(index, entry); return current == null; } public Iterable<ZSetEntry> subSet(final int minIndex, int maxIndex) { final int finalMaxIndex = Math.min(maxIndex, list.size() - 1); return new Iterable<ZSetEntry>() { @Override public Iterator<ZSetEntry> iterator() { return new Iterator<ZSetEntry>() { int min = minIndex; @Override public boolean hasNext() { return min <= finalMaxIndex; } @Override public ZSetEntry next() { return list.get(min++); } @Override public void remove() { } }; } }; } public boolean isEmpty() { return list.size() == 0; } public List<ZSetEntry> subSet(double min, double max) { int minIndex = find(Collections.binarySearch(list, new ZSetEntry(EMPTY, min))); int maxIndex = find(Collections.binarySearch(list, new ZSetEntry(EMPTY, max))); if (list.get(maxIndex).getScore() > max) { maxIndex = maxIndex - 1; } return list.subList(minIndex, maxIndex + 1); } private int find(int minIndex) { return minIndex < 0 ? -(minIndex + 1) : minIndex; } }