Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * Copyright (C) 2012 The Guava Authors
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   * http://www.apache.org/licenses/LICENSE-2.0
   *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 package com.google.common.collect;
 
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.base.Predicates.compose;
 import static com.google.common.base.Predicates.in;
 import static com.google.common.base.Predicates.not;
 
 
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
An implementation of RangeMap based on a TreeMap, supporting all optional operations.

Like all RangeMap implementations, this supports neither null keys nor null values.

Author(s):
Louis Wasserman
Since:
14.0
 
 @GwtIncompatible("NavigableMap")
 public final class TreeRangeMap<K extends Comparable, V> implements RangeMap<K, V> {
 
   private final NavigableMap<Cut<K>, RangeMapEntry<K, V>> entriesByLowerBound;
 
   public static <K extends Comparable, V> TreeRangeMap<K, V> create() {
     return new TreeRangeMap<K, V>();
   }
 
   private TreeRangeMap() {
     this. = Maps.newTreeMap();
   }
 
   private static final class RangeMapEntry<K extends Comparable, V>
       extends AbstractMapEntry<Range<K>, V> {
     private final Range<K> range;
     private final V value;
 
     RangeMapEntry(Cut<K> lowerBoundCut<K> upperBound, V value) {
       this(Range.create(lowerBoundupperBound), value);
     }
 
     RangeMapEntry(Range<K> range, V value) {
       this. = range;
       this. = value;
     }
 
     @Override
     public Range<K> getKey() {
       return ;
     }
 
     @Override
     public V getValue() {
       return ;
     }
 
     public boolean contains(K value) {
       return .contains(value);
     }
 
     Cut<K> getLowerBound() {
       return .;
     }
 
    Cut<K> getUpperBound() {
      return .;
    }
  }
  public V get(K key) {
    Entry<Range<K>, V> entry = getEntry(key);
    return (entry == null) ? null : entry.getValue();
  }
  public Entry<Range<K>, V> getEntry(K key) {
    Map.Entry<Cut<K>, RangeMapEntry<K, V>> mapEntry =
        .floorEntry(Cut.belowValue(key));
    if (mapEntry != null && mapEntry.getValue().contains(key)) {
      return mapEntry.getValue();
    } else {
      return null;
    }
  }
  public void put(Range<K> range, V value) {
    if (!range.isEmpty()) {
      checkNotNull(value);
      remove(range);
      .put(range.lowerBoundnew RangeMapEntry<K, V>(rangevalue));
    }
  }
  public void putAll(RangeMap<K, V> rangeMap) {
    for (Map.Entry<Range<K>, V> entry : rangeMap.asMapOfRanges().entrySet()) {
      put(entry.getKey(), entry.getValue());
    }
  }
  public void clear() {
  }
  public Range<K> span() {
    Entry<Cut<K>, RangeMapEntry<K, V>> firstEntry = .firstEntry();
    Entry<Cut<K>, RangeMapEntry<K, V>> lastEntry = .lastEntry();
    if (firstEntry == null) {
      throw new NoSuchElementException();
    }
    return Range.create(
        firstEntry.getValue().getKey().,
        lastEntry.getValue().getKey().);
  }
  private void putRangeMapEntry(Cut<K> lowerBoundCut<K> upperBound, V value) {
    .put(lowerBoundnew RangeMapEntry<K, V>(lowerBoundupperBoundvalue));
  }
  public void remove(Range<K> rangeToRemove) {
    if (rangeToRemove.isEmpty()) {
      return;
    }
    /*
     * The comments for this method will use [ ] to indicate the bounds of rangeToRemove and ( ) to
     * indicate the bounds of ranges in the range map.
     */
    Map.Entry<Cut<K>, RangeMapEntry<K, V>> mapEntryBelowToTruncate =
        .lowerEntry(rangeToRemove.lowerBound);
    if (mapEntryBelowToTruncate != null) {
      // we know ( [
      RangeMapEntry<K, V> rangeMapEntry = mapEntryBelowToTruncate.getValue();
      if (rangeMapEntry.getUpperBound().compareTo(rangeToRemove.lowerBound) > 0) {
        // we know ( [ )
        if (rangeMapEntry.getUpperBound().compareTo(rangeToRemove.upperBound) > 0) {
          // we know ( [ ] ), so insert the range ] ) back into the map --
          // it's being split apart
          putRangeMapEntry(rangeToRemove.upperBoundrangeMapEntry.getUpperBound(),
              mapEntryBelowToTruncate.getValue().getValue());
        }
        // overwrite mapEntryToTruncateBelow with a truncated range
        putRangeMapEntry(rangeMapEntry.getLowerBound(), rangeToRemove.lowerBound,
            mapEntryBelowToTruncate.getValue().getValue());
      }
    }
    Map.Entry<Cut<K>, RangeMapEntry<K, V>> mapEntryAboveToTruncate =
        .lowerEntry(rangeToRemove.upperBound);
    if (mapEntryAboveToTruncate != null) {
      // we know ( ]
      RangeMapEntry<K, V> rangeMapEntry = mapEntryAboveToTruncate.getValue();
      if (rangeMapEntry.getUpperBound().compareTo(rangeToRemove.upperBound) > 0) {
        // we know ( ] ), and since we dealt with truncating below already,
        // we know [ ( ] )
        putRangeMapEntry(rangeToRemove.upperBoundrangeMapEntry.getUpperBound(),
            mapEntryAboveToTruncate.getValue().getValue());
        .remove(rangeToRemove.lowerBound);
      }
    }
    .subMap(rangeToRemove.lowerBoundrangeToRemove.upperBound).clear();
  }
  public Map<Range<K>, V> asMapOfRanges() {
    return new AsMapOfRanges();
  }
  private final class AsMapOfRanges extends AbstractMap<Range<K>, V> {
    @Override
    public boolean containsKey(@Nullable Object key) {
      return get(key) != null;
    }
    @Override
    public V get(@Nullable Object key) {
      if (key instanceof Range) {
        Range<?> range = (Range<?>) key;
        RangeMapEntry<K, V> rangeMapEntry = .get(range.lowerBound);
        if (rangeMapEntry != null && rangeMapEntry.getKey().equals(range)) {
          return rangeMapEntry.getValue();
        }
      }
      return null;
    }
    @Override
    public Set<Entry<Range<K>, V>> entrySet() {
      return new AbstractSet<Entry<Range<K>, V>>() {
        @SuppressWarnings("unchecked"// it's safe to upcast iterators
        @Override
        public Iterator<Entry<Range<K>, V>> iterator() {
          return (Iterator.values().iterator();
        }
        @Override
        public int size() {
          return .size();
        }
      };
    }
  }
  
  public RangeMap<K, V> subRangeMap(Range<K> subRange) {
    if (subRange.equals(Range.all())) {
      return this;
    } else {
      return new SubRangeMap(subRange);
    }
  }
  
  @SuppressWarnings("unchecked")
  private RangeMap<K, V> emptySubRangeMap() {
    return ;
  }
  
  private static final RangeMap EMPTY_SUB_RANGE_MAP = 
      new RangeMap() {
        @Override
        @Nullable
        public Object get(Comparable key) {
          return null;
        }
        @Override
        @Nullable
        public Entry<RangeObjectgetEntry(Comparable key) {
          return null;
        }
        @Override
        public Range span() {
          throw new NoSuchElementException();
        }
        @Override
        public void put(Range rangeObject value) {
          checkNotNull(range);
          throw new IllegalArgumentException(
              "Cannot insert range " + range + " into an empty subRangeMap");
        }
        @Override
        public void putAll(RangeMap rangeMap) {
          if (!rangeMap.asMapOfRanges().isEmpty()) {
            throw new IllegalArgumentException(
                "Cannot putAll(nonEmptyRangeMap) into an empty " + "subRangeMap");
          }
        }
        @Override
        public void clear() {}
        @Override
        public void remove(Range range) {
          checkNotNull(range);
        }
        @Override
        public Map<RangeObjectasMapOfRanges() {
          return Collections.emptyMap();
        }
        @Override
        public RangeMap subRangeMap(Range range) {
          checkNotNull(range);
          return this;
        }
      };
  
  private class SubRangeMap implements RangeMap<K, V> {
    private final Range<K> subRange;
    
    SubRangeMap(Range<K> subRange) {
      this. = subRange;
    }
    @Override
    @Nullable
    public V get(K key) {
      return .contains(key)
          ? TreeRangeMap.this.get(key)
          : null;
    }
    @Override
    @Nullable
    public Entry<Range<K>, V> getEntry(K key) {
      if (.contains(key)) {
        Entry<Range<K>, V> entry = TreeRangeMap.this.getEntry(key);
        if (entry != null) {
          return Maps.immutableEntry(entry.getKey().intersection(), entry.getValue());
        }
      }
      return null;
    }
    @Override
    public Range<K> span() {
      Cut<K> lowerBound;
      Entry<Cut<K>, RangeMapEntry<K, V>> lowerEntry =
      if (lowerEntry != null && 
          lowerEntry.getValue().getUpperBound().compareTo(.) > 0) {
        lowerBound = .;
      } else {
        lowerBound = .ceilingKey(.);
        if (lowerBound == null || lowerBound.compareTo(.) >= 0) {
          throw new NoSuchElementException();
        }
      }
      
      Cut<K> upperBound;
      Entry<Cut<K>, RangeMapEntry<K, V>> upperEntry = 
      if (upperEntry == null) {
        throw new NoSuchElementException();
      } else if (upperEntry.getValue().getUpperBound().compareTo(.) >= 0) {
        upperBound = .;
      } else {
        upperBound = upperEntry.getValue().getUpperBound();
      }
      return Range.create(lowerBoundupperBound);
    }
    @Override
    public void put(Range<K> range, V value) {
      checkArgument(.encloses(range), 
          "Cannot put range %s into a subRangeMap(%s)"range);
      TreeRangeMap.this.put(rangevalue);
    }
    @Override
    public void putAll(RangeMap<K, V> rangeMap) {
      if (rangeMap.asMapOfRanges().isEmpty()) {
        return;
      }
      Range<K> span = rangeMap.span();
      checkArgument(.encloses(span), 
          "Cannot putAll rangeMap with span %s into a subRangeMap(%s)"span);
      TreeRangeMap.this.putAll(rangeMap);
    }
    @Override
    public void clear() {
      TreeRangeMap.this.remove();
    }
    @Override
    public void remove(Range<K> range) {
      if (range.isConnected()) {
        TreeRangeMap.this.remove(range.intersection());
      }
    }
    @Override
    public RangeMap<K, V> subRangeMap(Range<K> range) {
      if (!range.isConnected()) {
        return emptySubRangeMap();
      } else {
        return TreeRangeMap.this.subRangeMap(range.intersection());
      }
    }
    @Override
    public Map<Range<K>, V> asMapOfRanges() {
      return new SubRangeMapAsMap();
    }
    @Override
    public boolean equals(@Nullable Object o) {
      if (o instanceof RangeMap) {
        RangeMap<?, ?> rangeMap = (RangeMap<?, ?>) o;
        return asMapOfRanges().equals(rangeMap.asMapOfRanges());
      }
      return false;
    }
    @Override
    public int hashCode() {
      return asMapOfRanges().hashCode();
    }
    @Override
    public String toString() {
      return asMapOfRanges().toString();
    }
    
    class SubRangeMapAsMap extends AbstractMap<Range<K>, V> {
      
      @Override
      public boolean containsKey(Object key) {
        return get(key) != null;
      }
      @Override
      public V get(Object key) {
        try {
          if (key instanceof Range) {
            @SuppressWarnings("unchecked"// we catch ClassCastExceptions
            Range<K> r = (Range<K>) key;
            if (!.encloses(r) || r.isEmpty()) {
              return null;
            }
            RangeMapEntry<K, V> candidate = null;
            if (r.lowerBound.compareTo(.) == 0) {
              // r could be truncated on the left
              Entry<Cut<K>, RangeMapEntry<K, V>> entry = 
                  .floorEntry(r.lowerBound);
              if (entry != null) {
                candidate = entry.getValue();
              }
            } else {
              candidate = .get(r.lowerBound);
            }
            
            if (candidate != null && candidate.getKey().isConnected()
                && candidate.getKey().intersection().equals(r)) {
              return candidate.getValue();
            }
          }
        } catch (ClassCastException e) {
          return null;
        }
        return null;
      }
      @Override
      public V remove(Object key) {
        V value = get(key);
        if (value != null) {
          @SuppressWarnings("unchecked"// it's definitely in the map, so safe
          Range<K> range = (Range<K>) key;
          TreeRangeMap.this.remove(range);
          return value;
        }
        return null;
      }
      @Override
      public void clear() {
        SubRangeMap.this.clear();
      }
      
      private boolean removeIf(Predicate<? super Entry<Range<K>, V>> predicate) {
        List<Range<K>> toRemove = Lists.newArrayList();
        for (Entry<Range<K>, V> entry : entrySet()) {
          if (predicate.apply(entry)) {
            toRemove.add(entry.getKey());
          }
        }
        for (Range<K> range : toRemove) {
          TreeRangeMap.this.remove(range);
        }
        return !toRemove.isEmpty();
      }
      @Override
      public Set<Range<K>> keySet() {
        return new Maps.KeySet<Range<K>, V>(SubRangeMapAsMap.this) {
          @Override
          public boolean remove(@Nullable Object o) {
            return SubRangeMapAsMap.this.remove(o) != null;
          }
          
          @Override
          public boolean retainAll(Collection<?> c) {
            return removeIf(compose(not(in(c)), Maps.<Range<K>>keyFunction()));
          }
        };
      }
      @Override
      public Set<Entry<Range<K>, V>> entrySet() {
        return new Maps.EntrySet<Range<K>, V>() {
          @Override
          Map<Range<K>, V> map() {
            return SubRangeMapAsMap.this;
          }
          @Override
          public Iterator<Entry<Range<K>, V>> iterator() {
            if (.isEmpty()) {
              return Iterators.emptyIterator();
            }
            Cut<K> cutToStart = Objects.firstNonNull(
                .floorKey(.),
                .);
            final Iterator<RangeMapEntry<K, V>> backingItr = 
                .tailMap(cutToStarttrue).values().iterator();
            return new AbstractIterator<Entry<Range<K>, V>>() {
              @Override
              protected Entry<Range<K>, V> computeNext() {
                while (backingItr.hasNext()) {
                  RangeMapEntry<K, V> entry = backingItr.next();
                  if (entry.getLowerBound().compareTo(.) >= 0) {
                    break;
                  } else if (entry.getUpperBound().compareTo(.) > 0) {
                    // this might not be true e.g. at the start of the iteration
                    return Maps.immutableEntry(
                        entry.getKey().intersection(), entry.getValue());
                  }
                }
                return endOfData();
              }
            };
          }
          
          @Override
          public boolean retainAll(Collection<?> c) {
            return removeIf(not(in(c)));
          }
          
          @Override
          public int size() {
            return Iterators.size(iterator());
          }
          
          @Override
          public boolean isEmpty() {
            return !iterator().hasNext();
          }
        };
      }
      
      @Override
      public Collection<V> values() {
        return new Maps.Values<Range<K>, V>(this) {          
          @Override
          public boolean removeAll(Collection<?> c) {
            return removeIf(compose(in(c), Maps.<V>valueFunction()));            
          }
          
          @Override
          public boolean retainAll(Collection<?> c) {
            return removeIf(compose(not(in(c)), Maps.<V>valueFunction()));
          }
        };
      }
    }
  }
  public boolean equals(@Nullable Object o) {
    if (o instanceof RangeMap) {
      RangeMap<?, ?> rangeMap = (RangeMap<?, ?>) o;
      return asMapOfRanges().equals(rangeMap.asMapOfRanges());
    }
    return false;
  }
  public int hashCode() {
    return asMapOfRanges().hashCode();
  }
  public String toString() {
  }
New to GrepCode? Check out our FAQ X