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

com.google.firebase.database.core.SparseSnapshotTree 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.core;

import com.google.firebase.database.snapshot.ChildKey;
import com.google.firebase.database.snapshot.ChildrenNode;
import com.google.firebase.database.snapshot.Node;

import java.util.HashMap;
import java.util.Map;

class SparseSnapshotTree {

  private Node value;
  private Map children;

  public SparseSnapshotTree() {
    this.value = null;
    this.children = null;
  }

  public void remember(Path path, Node data) {
    if (path.isEmpty()) {
      value = data;
      children = null;
    } else if (value != null) {
      value = value.updateChild(path, data);
    } else {
      if (children == null) {
        children = new HashMap<>();
      }

      ChildKey childKey = path.getFront();
      if (!children.containsKey(childKey)) {
        children.put(childKey, new SparseSnapshotTree());
      }

      SparseSnapshotTree child = children.get(childKey);
      child.remember(path.popFront(), data);
    }
  }

  public boolean forget(final Path path) {
    if (path.isEmpty()) {
      value = null;
      children = null;
      return true;
    } else {
      if (value != null) {
        if (value.isLeafNode()) {
          // non-empty path at leaf. The path leads to nowhere
          return false;
        } else {
          ChildrenNode childrenNode = (ChildrenNode) value;
          value = null;

          childrenNode.forEachChild(
              new ChildrenNode.ChildVisitor() {
                @Override
                public void visitChild(ChildKey name, Node child) {
                  remember(path.child(name), child);
                }
              });

          // We've cleared out the value and set the children. Call this method again
          // to hit the
          // next case
          return forget(path);
        }
      } else if (children != null) {
        ChildKey childKey = path.getFront();
        Path childPath = path.popFront();

        if (children.containsKey(childKey)) {
          SparseSnapshotTree child = children.get(childKey);
          boolean safeToRemove = child.forget(childPath);
          if (safeToRemove) {
            children.remove(childKey);
          }
        }

        if (children.isEmpty()) {
          children = null;
          return true;
        } else {
          return false;
        }
      } else {
        return true;
      }
    }
  }

  public void forEachTree(final Path prefixPath, final SparseSnapshotTreeVisitor visitor) {
    if (value != null) {
      visitor.visitTree(prefixPath, value);
    } else {
      this.forEachChild(
          new SparseSnapshotChildVisitor() {
            @Override
            public void visitChild(ChildKey key, SparseSnapshotTree tree) {
              tree.forEachTree(prefixPath.child(key), visitor);
            }
          });
    }
  }

  public void forEachChild(SparseSnapshotChildVisitor visitor) {
    if (children != null) {
      for (Map.Entry entry : children.entrySet()) {
        visitor.visitChild(entry.getKey(), entry.getValue());
      }
    }
  }

  public interface SparseSnapshotTreeVisitor {

    void visitTree(Path prefixPath, Node tree);
  }

  public interface SparseSnapshotChildVisitor {

    void visitChild(ChildKey key, SparseSnapshotTree tree);
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy