Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* 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;
}
}
}