All Downloads are FREE. Search and download functionalities are using the official Maven repository.

swim.collections.BTreeLeaf Maven / Gradle / Ivy

// Copyright 2015-2019 SWIM.AI inc.
//
// 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 swim.collections;

import java.util.AbstractMap;
import java.util.Map;
import swim.util.CombinerFunction;
import swim.util.OrderedMapCursor;

class BTreeLeaf extends BTreePage {
  final Map.Entry[] slots;
  final U fold;

  BTreeLeaf(Map.Entry[] slots, U fold) {
    this.slots = slots;
    this.fold = fold;
  }

  @Override
  public final boolean isEmpty() {
    return this.slots.length == 0;
  }

  @Override
  public final int size() {
    return this.slots.length;
  }

  @Override
  public final int arity() {
    return this.slots.length;
  }

  @Override
  public final U fold() {
    return this.fold;
  }

  @Override
  public final K minKey() {
    return this.slots[0].getKey();
  }

  @Override
  public final K maxKey() {
    return this.slots[this.slots.length - 1].getKey();
  }

  @Override
  public final boolean containsKey(Object key, BTreeContext tree) {
    return lookup(key, tree) >= 0;
  }

  @Override
  public final boolean containsValue(Object value) {
    final Map.Entry[] slots = this.slots;
    for (int i = 0, n = slots.length; i < n; i += 1) {
      if (value.equals(slots[i].getValue())) {
        return true;
      }
    }
    return false;
  }

  @Override
  public final int indexOf(Object key, BTreeContext tree) {
    return lookup(key, tree);
  }

  @Override
  public final V get(Object key, BTreeContext tree) {
    final int x = lookup(key, tree);
    if (x >= 0) {
      return this.slots[x].getValue();
    } else {
      return null;
    }
  }

  @Override
  public final Map.Entry getEntry(Object key, BTreeContext tree) {
    final int x = lookup(key, tree);
    if (x >= 0) {
      return this.slots[x];
    } else {
      return null;
    }
  }

  @Override
  public final Map.Entry getIndex(int index) {
    return this.slots[index];
  }

  @Override
  public final Map.Entry firstEntry() {
    if (this.slots.length != 0) {
      return this.slots[0];
    } else {
      return null;
    }
  }

  @Override
  public final Map.Entry lastEntry() {
    if (this.slots.length != 0) {
      return this.slots[this.slots.length - 1];
    } else {
      return null;
    }
  }

  @Override
  public final Map.Entry nextEntry(K key, BTreeContext tree) {
    int x = lookup(key, tree);
    if (x >= 0) {
      x += 1;
    } else {
      x = -(x + 1);
    }
    if (0 <= x && x < this.slots.length) {
      return this.slots[x];
    } else {
      return null;
    }
  }

  @Override
  public final Map.Entry previousEntry(K key, BTreeContext tree) {
    int x = lookup(key, tree);
    if (x >= 0) {
      x -= 1;
    } else {
      x = -(x + 2);
    }
    if (0 <= x && x < this.slots.length) {
      return this.slots[x];
    } else {
      return null;
    }
  }

  @Override
  public final BTreeLeaf updated(K key, V newValue, BTreeContext tree) {
    int x = lookup(key, tree);
    if (x >= 0) {
      return updatedSlot(x, key, newValue);
    } else {
      x = -(x + 1);
      return insertedSlot(x, key, newValue);
    }
  }

  @SuppressWarnings("unchecked")
  private BTreeLeaf updatedSlot(int x, K key, V newValue) {
    final Map.Entry[] oldSlots = this.slots;
    if (newValue != oldSlots[x].getValue()) {
      final Map.Entry[] newSlots = (Map.Entry[]) new Map.Entry[oldSlots.length];
      System.arraycopy(oldSlots, 0, newSlots, 0, oldSlots.length);
      newSlots[x] = new AbstractMap.SimpleImmutableEntry(key, newValue);
      return newLeaf(newSlots, null);
    } else {
      return this;
    }
  }

  @SuppressWarnings("unchecked")
  private BTreeLeaf insertedSlot(int x, K key, V newValue) {
    final Map.Entry[] oldSlots = this.slots;
    final int n = oldSlots.length + 1;
    final Map.Entry[] newSlots = (Map.Entry[]) new Map.Entry[n];
    System.arraycopy(oldSlots, 0, newSlots, 0, x);
    newSlots[x] = new AbstractMap.SimpleImmutableEntry(key, newValue);
    System.arraycopy(oldSlots, x, newSlots, x + 1, n - (x + 1));
    return newLeaf(newSlots, null);
  }

  @Override
  public final BTreeLeaf removed(Object key, BTreeContext tree) {
    final int x = lookup(key, tree);
    if (x >= 0) {
      if (this.slots.length > 1) {
        return removedSlot(x);
      } else {
        return BTreeLeaf.empty();
      }
    } else {
      return this;
    }
  }

  @SuppressWarnings("unchecked")
  private BTreeLeaf removedSlot(int x) {
    final Map.Entry[] oldSlots = this.slots;
    final int n = oldSlots.length - 1;
    final Map.Entry[] newSlots = (Map.Entry[]) new Map.Entry[n];
    System.arraycopy(oldSlots, 0, newSlots, 0, x);
    System.arraycopy(oldSlots, x + 1, newSlots, x, n - x);
    return newLeaf(newSlots, null);
  }

  @SuppressWarnings("unchecked")
  @Override
  public final BTreeLeaf drop(int lower, BTreeContext tree) {
    if (lower > 0) {
      final Map.Entry[] oldSlots = this.slots;
      final int k = oldSlots.length;
      if (lower < k) {
        final int n = k - lower;
        final Map.Entry[] newSlots = (Map.Entry[]) new Map.Entry[n];
        System.arraycopy(oldSlots, lower, newSlots, 0, n);
        return newLeaf(newSlots, null);
      } else {
        return BTreeLeaf.empty();
      }
    } else {
      return this;
    }
  }

  @SuppressWarnings("unchecked")
  @Override
  public final BTreeLeaf take(int upper, BTreeContext tree) {
    final Map.Entry[] oldSlots = this.slots;
    if (upper < oldSlots.length) {
      if (upper > 0) {
        final Map.Entry[] newSlots = (Map.Entry[]) new Map.Entry[upper];
        System.arraycopy(oldSlots, 0, newSlots, 0, upper);
        return newLeaf(newSlots, null);
      } else {
        return BTreeLeaf.empty();
      }
    } else {
      return this;
    }
  }

  @Override
  public final BTreePage balanced(BTreeContext tree) {
    final int n = this.slots.length;
    if (n > 1 && tree.pageShouldSplit(this)) {
      final int x = n >>> 1;
      return split(x);
    } else {
      return this;
    }
  }

  @SuppressWarnings("unchecked")
  @Override
  public final BTreeNode split(int x) {
    final BTreePage[] newPages = (BTreePage[]) new BTreePage[2];
    final BTreeLeaf newLeftPage = splitLeft(x);
    final BTreeLeaf newRightPage = splitRight(x);
    newPages[0] = newLeftPage;
    newPages[1] = newRightPage;

    final K[] newKnots = (K[]) new Object[1];
    newKnots[0] = newRightPage.minKey();

    return newNode(newPages, newKnots, null, this.slots.length);
  }

  @SuppressWarnings("unchecked")
  @Override
  public final BTreeLeaf splitLeft(int x) {
    final Map.Entry[] oldSlots = this.slots;
    final Map.Entry[] newSlots = (Map.Entry[]) new Map.Entry[x];
    System.arraycopy(oldSlots, 0, newSlots, 0, x);
    return newLeaf(newSlots, null);
  }

  @SuppressWarnings("unchecked")
  @Override
  public final BTreeLeaf splitRight(int x) {
    final Map.Entry[] oldSlots = this.slots;
    final int y = oldSlots.length - x;
    final Map.Entry[] newSlots = (Map.Entry[]) new Map.Entry[y];
    System.arraycopy(oldSlots, x, newSlots, 0, y);
    return newLeaf(newSlots, null);
  }

  @Override
  public final BTreeLeaf reduced(U identity, CombinerFunction accumulator,
                                          CombinerFunction combiner) {
    if (this.fold == null) {
      final Map.Entry[] slots = this.slots;
      U fold = identity;
      for (int i = 0, n = slots.length; i < n; i += 1) {
        fold = accumulator.combine(fold, slots[i].getValue());
      }
      return newLeaf(slots, fold);
    } else {
      return this;
    }
  }

  @Override
  public final OrderedMapCursor iterator() {
    return new BTreeLeafCursor(this.slots, 0, this.slots.length);
  }

  @Override
  public final OrderedMapCursor lastIterator() {
    return new BTreeLeafCursor(this.slots, this.slots.length, this.slots.length);
  }

  protected final int lookup(Object key, BTreeContext tree) {
    int lo = 0;
    int hi = this.slots.length - 1;
    while (lo <= hi) {
      final int mid = (lo + hi) >>> 1;
      final int order = tree.compareKey(key, this.slots[mid].getKey());
      if (order > 0) {
        lo = mid + 1;
      } else if (order < 0) {
        hi = mid - 1;
      } else {
        return mid;
      }
    }
    return -(lo + 1);
  }

  protected BTreeLeaf newLeaf(Map.Entry[] slots, U fold) {
    return new BTreeLeaf(slots, fold);
  }

  protected BTreeNode newNode(BTreePage[] pages, K[] knots, U fold, int size) {
    return new BTreeNode(pages, knots, fold, size);
  }

  private static BTreeLeaf empty;

  @SuppressWarnings("unchecked")
  public static  BTreeLeaf empty() {
    if (empty == null) {
      empty = new BTreeLeaf((Map.Entry[]) new Map.Entry[0], null);
    }
    return (BTreeLeaf) empty;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy