NormalizedNodeAggregator should also report empty
[controller.git] / opendaylight / md-sal / sal-distributed-datastore / src / main / java / org / opendaylight / controller / cluster / datastore / utils / UnsignedLongSet.java
index 4d4b99bbc9bd1fbc6d21a90e56aa41c2b4982382..59393a3ee0c4699e06093a2e3750170625a01257 100644 (file)
@@ -7,26 +7,20 @@
  */
 package org.opendaylight.controller.cluster.datastore.utils;
 
-import static com.google.common.base.Verify.verify;
 import static java.util.Objects.requireNonNull;
 
 import com.google.common.annotations.Beta;
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.MoreObjects;
-import com.google.common.collect.BoundType;
-import com.google.common.collect.Collections2;
-import com.google.common.collect.Range;
 import com.google.common.collect.RangeSet;
-import com.google.common.primitives.UnsignedLong;
 import java.io.DataInput;
 import java.io.DataOutput;
 import java.io.IOException;
 import java.util.Collections;
-import java.util.Iterator;
 import java.util.NavigableSet;
 import java.util.TreeSet;
 import org.eclipse.jdt.annotation.NonNull;
-import org.opendaylight.yangtools.concepts.Mutable;
+import org.opendaylight.yangtools.concepts.Immutable;
 import org.opendaylight.yangtools.concepts.WritableObjects;
 
 /**
@@ -42,51 +36,29 @@ import org.opendaylight.yangtools.concepts.WritableObjects;
 abstract class UnsignedLongSet {
     @Beta
     @VisibleForTesting
-    public static final class Entry implements Comparable<Entry>, Mutable {
-        // Note: mutable to allow efficient merges.
-        long lowerBits;
-        long upperBits;
+    public static final class Entry implements Comparable<Entry>, Immutable {
+        public final long lowerBits;
+        public final long upperBits;
 
         private Entry(final long lowerBits, final long upperBits) {
             this.lowerBits = lowerBits;
             this.upperBits = upperBits;
         }
 
-        static Entry of(final long longBits) {
+        static @NonNull Entry of(final long longBits) {
             return of(longBits, longBits);
         }
 
-        static Entry of(final long lowerBits, final long upperBits) {
+        static @NonNull Entry of(final long lowerBits, final long upperBits) {
             return new Entry(lowerBits, upperBits);
         }
 
-        static Entry of(final Range<UnsignedLong> range) {
-            verify(range.lowerBoundType() == BoundType.CLOSED && range.upperBoundType() == BoundType.OPEN,
-                "Unexpected range %s", range);
-            return of(range.lowerEndpoint().longValue(), range.upperEndpoint().longValue() - 1);
+        @NonNull Entry withLower(final long newLowerBits) {
+            return of(newLowerBits, upperBits);
         }
 
-        @VisibleForTesting
-        public UnsignedLong lower() {
-            return UnsignedLong.fromLongBits(lowerBits);
-        }
-
-        @VisibleForTesting
-        public UnsignedLong upper() {
-            return UnsignedLong.fromLongBits(upperBits);
-        }
-
-        boolean contains(final long longBits) {
-            return Long.compareUnsigned(lowerBits, longBits) <= 0 && Long.compareUnsigned(upperBits, longBits) >= 0;
-        }
-
-        Entry copy() {
-            return new Entry(lowerBits, upperBits);
-        }
-
-        // Provides compatibility with RangeSet<UnsignedLong> using [lower, upper + 1)
-        Range<UnsignedLong> toUnsigned() {
-            return Range.closedOpen(UnsignedLong.fromLongBits(lowerBits), UnsignedLong.fromLongBits(upperBits + 1));
+        @NonNull Entry withUpper(final long newUpperBits) {
+            return of(lowerBits, newUpperBits);
         }
 
         // These two methods provide the same serialization format as the one we've used to serialize
@@ -136,72 +108,35 @@ abstract class UnsignedLongSet {
         }
     }
 
-    // The idea is rather simple, we track a TreeSet of range entries, ordered by their lower bound. This means that
-    // for a contains() operation we just need the first headSet() entry. For insert operations we just update either
-    // the lower bound or the upper bound of an existing entry. When we do, we also look at prev/next entry and if they
-    // are contiguous with the updated entry, we adjust the entry once more and remove the prev/next entry.
-    private final @NonNull TreeSet<Entry> ranges;
+    // The idea is rather simple, we track a NavigableSet of range entries, ordered by their lower bound. This means
+    // that for a contains() operation we just need the first headSet() entry. For insert operations we just update
+    // either the lower bound or the upper bound of an existing entry. When we do, we also look at prev/next entry and
+    // if they are contiguous with the updated entry, we adjust the entry once more and remove the prev/next entry.
+    private final @NonNull NavigableSet<Entry> ranges;
 
-    UnsignedLongSet(final TreeSet<Entry> ranges) {
+    UnsignedLongSet(final NavigableSet<Entry> ranges) {
         this.ranges = requireNonNull(ranges);
     }
 
-    final void addImpl(final long longBits) {
-        final var range = Entry.of(longBits);
-
-        final var headIt = headIter(range);
-        if (headIt.hasNext()) {
-            final var head = headIt.next();
-            if (head.contains(longBits)) {
-                return;
-            }
-            if (head.upperBits + 1 == longBits) {
-                head.upperBits = longBits;
-                final var tailSet = ranges.tailSet(range);
-                if (!tailSet.isEmpty()) {
-                    final var tail = tailSet.first();
-                    if (tail.lowerBits - 1 == longBits) {
-                        tail.lowerBits = head.lowerBits;
-                        headIt.remove();
-                    }
-                }
-                return;
-            }
-        }
-
-        final var tailSet = ranges.tailSet(range);
-        if (!tailSet.isEmpty()) {
-            final var tail = tailSet.first();
-            if (tail.lowerBits - 1 == longBits) {
-                tail.lowerBits = longBits;
-                return;
-            }
-        }
-
-        ranges.add(range);
-    }
-
     public final boolean contains(final long longBits) {
-        final var headIt = headIter(Entry.of(longBits));
-        return headIt.hasNext() && headIt.next().contains(longBits);
+        final var head = ranges.floor(Entry.of(longBits));
+        return head != null
+            && Long.compareUnsigned(head.lowerBits, longBits) <= 0
+            && Long.compareUnsigned(head.upperBits, longBits) >= 0;
     }
 
     public final boolean isEmpty() {
         return ranges.isEmpty();
     }
 
-    public final int size() {
+    public final int rangeSize() {
         return ranges.size();
     }
 
     public abstract @NonNull ImmutableUnsignedLongSet immutableCopy();
 
     public final @NonNull MutableUnsignedLongSet mutableCopy() {
-        return new MutableUnsignedLongSet(copyRanges());
-    }
-
-    final @NonNull TreeSet<Entry> copyRanges() {
-        return new TreeSet<>(Collections2.transform(ranges, Entry::copy));
+        return new MutableUnsignedLongSet(new TreeSet<>(ranges));
     }
 
     public final @NonNull NavigableSet<Entry> ranges() {
@@ -239,8 +174,4 @@ abstract class UnsignedLongSet {
 
         return helper.add("size", size).toString();
     }
-
-    private Iterator<Entry> headIter(final Entry range) {
-        return ranges.headSet(range, true).descendingIterator();
-    }
 }