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

com.google.firebase.database.collection.LLRBValueNode Maven / Gradle / Ivy

/*
 * Copyright 2017 Google 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 com.google.firebase.database.collection;

import java.util.Comparator;

public abstract class LLRBValueNode implements LLRBNode {

  private final K key;
  private final V value;
  private final LLRBNode right;
  private LLRBNode left;

  LLRBValueNode(K key, V value, LLRBNode left, LLRBNode right) {
    this.key = key;
    this.value = value;
    this.left = left == null ? LLRBEmptyNode.getInstance() : left;
    this.right = right == null ? LLRBEmptyNode.getInstance() : right;
  }

  private static Color oppositeColor(LLRBNode node) {
    return node.isRed() ? Color.BLACK : Color.RED;
  }

  @Override
  public LLRBNode getLeft() {
    return left;
  }

  // For use by the builder, which is package local
  void setLeft(LLRBNode left) {
    this.left = left;
  }

  @Override
  public LLRBNode getRight() {
    return right;
  }

  @Override
  public K getKey() {
    return key;
  }

  @Override
  public V getValue() {
    return value;
  }

  protected abstract Color getColor();

  protected abstract LLRBValueNode copy(
      K key, V value, LLRBNode left, LLRBNode right);

  @Override
  public LLRBValueNode copy(
      K key, V value, Color color, LLRBNode left, LLRBNode right) {
    K newKey = key == null ? this.key : key;
    V newValue = value == null ? this.value : value;
    LLRBNode newLeft = left == null ? this.left : left;
    LLRBNode newRight = right == null ? this.right : right;
    if (color == Color.RED) {
      return new LLRBRedValueNode<>(newKey, newValue, newLeft, newRight);
    } else {
      return new LLRBBlackValueNode<>(newKey, newValue, newLeft, newRight);
    }
  }

  @Override
  public LLRBNode insert(K key, V value, Comparator comparator) {
    int cmp = comparator.compare(key, this.key);
    LLRBValueNode n;
    if (cmp < 0) {
      // new key is less than current key
      LLRBNode newLeft = this.left.insert(key, value, comparator);
      n = copy(null, null, newLeft, null);
    } else if (cmp == 0) {
      // same key
      n = copy(key, value, null, null);
    } else {
      // new key is greater than current key
      LLRBNode newRight = this.right.insert(key, value, comparator);
      n = copy(null, null, null, newRight);
    }
    return n.fixUp();
  }

  @Override
  public LLRBNode remove(K key, Comparator comparator) {
    LLRBValueNode n = this;

    if (comparator.compare(key, n.key) < 0) {
      if (!n.left.isEmpty() && !n.left.isRed() && !((LLRBValueNode) n.left).left.isRed()) {
        n = n.moveRedLeft();
      }
      n = n.copy(null, null, n.left.remove(key, comparator), null);
    } else {
      if (n.left.isRed()) {
        n = n.rotateRight();
      }

      if (!n.right.isEmpty() && !n.right.isRed() && !((LLRBValueNode) n.right).left.isRed()) {
        n = n.moveRedRight();
      }

      if (comparator.compare(key, n.key) == 0) {
        if (n.right.isEmpty()) {
          return LLRBEmptyNode.getInstance();
        } else {
          LLRBNode smallest = n.right.getMin();
          n =
              n.copy(
                  smallest.getKey(),
                  smallest.getValue(),
                  null,
                  ((LLRBValueNode) n.right).removeMin());
        }
      }
      n = n.copy(null, null, null, n.right.remove(key, comparator));
    }
    return n.fixUp();
  }

  @Override
  public boolean isEmpty() {
    return false;
  }

  @Override
  public LLRBNode getMin() {
    if (left.isEmpty()) {
      return this;
    } else {
      return left.getMin();
    }
  }

  @Override
  public LLRBNode getMax() {
    if (right.isEmpty()) {
      return this;
    } else {
      return right.getMax();
    }
  }

  @Override
  public int count() {
    return left.count() + 1 + right.count();
  }

  @Override
  public void inOrderTraversal(NodeVisitor visitor) {
    left.inOrderTraversal(visitor);
    visitor.visitEntry(key, value);
    right.inOrderTraversal(visitor);
  }

  @Override
  public boolean shortCircuitingInOrderTraversal(ShortCircuitingNodeVisitor visitor) {
    if (left.shortCircuitingInOrderTraversal(visitor)) {
      if (visitor.shouldContinue(key, value)) {
        return right.shortCircuitingInOrderTraversal(visitor);
      }
    }
    return false;
  }

  @Override
  public boolean shortCircuitingReverseOrderTraversal(ShortCircuitingNodeVisitor visitor) {
    if (right.shortCircuitingReverseOrderTraversal(visitor)) {
      if (visitor.shouldContinue(key, value)) {
        return left.shortCircuitingReverseOrderTraversal(visitor);
      }
    }
    return false;
  }

  private LLRBNode removeMin() {
    if (left.isEmpty()) {
      return LLRBEmptyNode.getInstance();
    } else {
      LLRBValueNode n = this;
      if (!n.getLeft().isRed() && !n.getLeft().getLeft().isRed()) {
        n = n.moveRedLeft();
      }

      n = n.copy(null, null, ((LLRBValueNode) n.left).removeMin(), null);
      return n.fixUp();
    }
  }

  private LLRBValueNode moveRedLeft() {
    LLRBValueNode n = colorFlip();
    if (n.getRight().getLeft().isRed()) {
      n = n.copy(null, null, null, ((LLRBValueNode) n.getRight()).rotateRight());
      n = n.rotateLeft();
      n = n.colorFlip();
    }
    return n;
  }

  private LLRBValueNode moveRedRight() {
    LLRBValueNode n = colorFlip();
    if (n.getLeft().getLeft().isRed()) {
      n = n.rotateRight();
      n = n.colorFlip();
    }
    return n;
  }

  private LLRBValueNode fixUp() {
    LLRBValueNode n = this;
    if (n.right.isRed() && !n.left.isRed()) {
      n = n.rotateLeft();
    }
    if (n.left.isRed() && ((LLRBValueNode) (n.left)).left.isRed()) {
      n = n.rotateRight();
    }
    if (n.left.isRed() && n.right.isRed()) {
      n = n.colorFlip();
    }
    return n;
  }

  private LLRBValueNode rotateLeft() {
    LLRBValueNode newLeft =
        this.copy(null, null, Color.RED, null, ((LLRBValueNode) (this.right)).left);
    return (LLRBValueNode) this.right.copy(null, null, this.getColor(), newLeft, null);
  }

  private LLRBValueNode rotateRight() {
    LLRBValueNode newRight =
        this.copy(null, null, Color.RED, ((LLRBValueNode) (this.left)).right, null);
    return (LLRBValueNode) this.left.copy(null, null, this.getColor(), null, newRight);
  }

  private LLRBValueNode colorFlip() {
    LLRBNode newLeft = this.left.copy(null, null, oppositeColor(this.left), null, null);
    LLRBNode newRight = this.right.copy(null, null, oppositeColor(this.right), null, null);

    return this.copy(null, null, oppositeColor(this), newLeft, newRight);
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy