blob: c0ca6476c51737106d5da63ab87e74b25ee6f914 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:math';
import 'dart:typed_data';
import 'package:collection/collection.dart';
import '../../uint8list_ops.dart';
import 'converter.dart';
// Length of a bytelist, written on edge to value node.
// Bytelist content is: {1}{timetamp}, {timestamp} is 8 bytes long.
const _nodeValueSuffixLength = 9;
const _listEquality = ListEquality();
/// Type of child.
enum ChildType {
/// Left child.
left,
/// Value stored in current node.
value,
/// Right child.
right
}
/// Class to represent path from the root to some node in OrderedList implicit tree.
class OrderedListTreePath implements Comparable<OrderedListTreePath> {
final Uint8List _data;
/// Default constructor.
OrderedListTreePath(this._data);
/// Constructor from [parent] and additional parts of path.
OrderedListTreePath.fromParent(
OrderedListTreePath parent, List<Uint8List> labels)
: this(concatListOfUint8Lists([parent._data]..addAll(labels)));
/// Creates OrderedListTreePath corresponding to tree root.
OrderedListTreePath.root() : this(Uint8List(_nodeValueSuffixLength));
/// Checks if node is a child of a [parent].
bool isDescendant(OrderedListTreePath parent) {
if (_data.length <= parent._data.length) {
return false;
}
int prefixLen = parent._data.length - _nodeValueSuffixLength;
for (int i = 0; i < prefixLen; i++) {
if (parent._data[i] != _data[i]) {
return false;
}
}
return true;
}
/// Returns path to parent implicit node, for value node.
OrderedListTreePath parentPath() {
// Remove appendix corresponding to value from path.
return OrderedListTreePath(Uint8List.fromList(
_data.getRange(0, _data.length - _nodeValueSuffixLength).toList()));
}
/// Returns OrderedListTreePath representing child of this.
OrderedListTreePath getChild(
ChildType side, Uint8List instanceId, Uint8List timestamp) {
return OrderedListTreePath.fromParent(
// ----------------
// Path to implicit node:
// 1. path to parent implicit node
parentPath(),
[
// 2. direction ([left] or [right]).
Uint8List.fromList([side.index]),
// 3. id of current instance
instanceId,
// ----------------
// Appendix for path to value:
// 1. direction ([value])
Uint8List.fromList([ChildType.value.index]),
// 2. timestamp
timestamp
]);
}
@override
int compareTo(OrderedListTreePath p) {
for (int i = 0; i < min(_data.length, p._data.length); i++) {
if (_data[i] != p._data[i]) {
return _data[i].compareTo(p._data[i]);
}
}
return _data.length.compareTo(p._data.length);
}
@override
int get hashCode => _listEquality.hash(_data);
@override
bool operator ==(dynamic p) => compareTo(p) == 0;
}
/// Converter for OrderedListTreePath.
class OrderedListTreePathConverter implements Converter<OrderedListTreePath> {
/// Constructor.
const OrderedListTreePathConverter();
@override
OrderedListTreePath get defaultValue =>
OrderedListTreePath(Uint8List(0));
@override
OrderedListTreePath deserialize(final Uint8List x) =>
OrderedListTreePath(x);
@override
Uint8List serialize(final OrderedListTreePath x) => x._data;
}
/// Public const instance of OrderedListTreePathConverter.
const OrderedListTreePathConverter orderedListTreePathConverter =
OrderedListTreePathConverter();