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

com.google.firebase.database.snapshot.IndexedNode Maven / Gradle / Ivy

Go to download

This is the official Firebase Admin Java SDK. Build extraordinary native JVM apps in minutes with Firebase. The Firebase platform can power your app’s backend, user authentication, static hosting, and more.

There is a newer version: 9.3.0
Show newest version
/*
 * 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.snapshot;

import com.google.firebase.database.collection.ImmutableSortedSet;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

/**
 * Represents a node together with an index. The index and node are updated in unison. In the case
 * where the index does not affect the ordering (i.e. the ordering is identical to the key ordering)
 * this class uses a fallback index to save memory. Everything operating on the index must special
 * case the fallback index.
 */
public class IndexedNode implements Iterable {

  /**
   * This is a sentinal value, so it's fine to just use null for the comparator as it will never be
   * invoked.
   */
  private static final ImmutableSortedSet FALLBACK_INDEX =
      new ImmutableSortedSet<>(Collections.emptyList(), null);

  private final Node node;
  private final Index index;
  /**
   * The indexed set is initialized lazily for cases where we don't need to access any order
   * specific methods
   */
  private ImmutableSortedSet indexed;

  private IndexedNode(Node node, Index index) {
    this.index = index;
    this.node = node;
    // Index lazily
    this.indexed = null;
  }

  private IndexedNode(Node node, Index index, ImmutableSortedSet indexed) {
    this.index = index;
    this.node = node;
    this.indexed = indexed;
  }

  public static IndexedNode from(Node node) {
    return new IndexedNode(node, PriorityIndex.getInstance());
  }

  public static IndexedNode from(Node node, Index index) {
    return new IndexedNode(node, index);
  }

  private void ensureIndexed() {
    if (this.indexed == null) {
      // Not indexed yet, create now
      if (this.index.equals(KeyIndex.getInstance())) {
        this.indexed = FALLBACK_INDEX;
      } else {
        List children = new ArrayList<>();
        boolean sawIndexedValue = false;
        for (NamedNode entry : node) {
          sawIndexedValue = sawIndexedValue || index.isDefinedOn(entry.getNode());
          NamedNode namedNode = new NamedNode(entry.getName(), entry.getNode());
          children.add(namedNode);
        }
        if (sawIndexedValue) {
          this.indexed = new ImmutableSortedSet<>(children, index);
        } else {
          this.indexed = FALLBACK_INDEX;
        }
      }
    }
  }

  public boolean hasIndex(Index index) {
    return this.index.equals(index);
  }

  public Node getNode() {
    return this.node;
  }

  @Override
  public Iterator iterator() {
    ensureIndexed();
    if (this.indexed == FALLBACK_INDEX) {
      return this.node.iterator();
    } else {
      return this.indexed.iterator();
    }
  }

  public Iterator reverseIterator() {
    ensureIndexed();
    if (this.indexed == FALLBACK_INDEX) {
      return this.node.reverseIterator();
    } else {
      return this.indexed.reverseIterator();
    }
  }

  public IndexedNode updateChild(ChildKey key, Node child) {
    Node newNode = this.node.updateImmediateChild(key, child);
    if (this.indexed == FALLBACK_INDEX && !this.index.isDefinedOn(child)) {
      // doesn't affect the index, no need to create an index
      return new IndexedNode(newNode, this.index, FALLBACK_INDEX);
    } else if (this.indexed == null || this.indexed == FALLBACK_INDEX) {
      // No need to index yet, index lazily
      return new IndexedNode(newNode, this.index, null);
    } else {
      Node oldChild = this.node.getImmediateChild(key);
      ImmutableSortedSet newIndexed = this.indexed.remove(new NamedNode(key, oldChild));
      if (!child.isEmpty()) {
        newIndexed = newIndexed.insert(new NamedNode(key, child));
      }
      return new IndexedNode(newNode, this.index, newIndexed);
    }
  }

  public IndexedNode updatePriority(Node priority) {
    return new IndexedNode(node.updatePriority(priority), this.index, this.indexed);
  }

  public NamedNode getFirstChild() {
    if (!(this.node instanceof ChildrenNode)) {
      return null;
    } else {
      ensureIndexed();
      if (this.indexed == FALLBACK_INDEX) {
        ChildKey firstKey = ((ChildrenNode) this.node).getFirstChildKey();
        return new NamedNode(firstKey, this.node.getImmediateChild(firstKey));
      } else {
        return this.indexed.getMinEntry();
      }
    }
  }

  public NamedNode getLastChild() {
    if (!(this.node instanceof ChildrenNode)) {
      return null;
    } else {
      ensureIndexed();
      if (this.indexed == FALLBACK_INDEX) {
        ChildKey lastKey = ((ChildrenNode) this.node).getLastChildKey();
        return new NamedNode(lastKey, this.node.getImmediateChild(lastKey));
      } else {
        return this.indexed.getMaxEntry();
      }
    }
  }

  public ChildKey getPredecessorChildName(ChildKey childKey, Node childNode, Index index) {
    if (!this.index.equals(KeyIndex.getInstance()) && !this.index.equals(index)) {
      throw new IllegalArgumentException("Index not available in IndexedNode!");
    }
    ensureIndexed();
    if (this.indexed == FALLBACK_INDEX) {
      return this.node.getPredecessorChildKey(childKey);
    } else {
      NamedNode node = this.indexed.getPredecessorEntry(new NamedNode(childKey, childNode));
      return node != null ? node.getName() : null;
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy