| Index: dart_style/lib/src/line_splitting/solve_state_queue.dart
|
| diff --git a/dart_style/lib/src/line_splitting/solve_state_queue.dart b/dart_style/lib/src/line_splitting/solve_state_queue.dart
|
| deleted file mode 100644
|
| index 2247cb3cb3c3aeebf8de15021163b8a954d4ab0c..0000000000000000000000000000000000000000
|
| --- a/dart_style/lib/src/line_splitting/solve_state_queue.dart
|
| +++ /dev/null
|
| @@ -1,248 +0,0 @@
|
| -// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
|
| -// for details. All rights reserved. Use of this source code is governed by a
|
| -// BSD-style license that can be found in the LICENSE file.
|
| -
|
| -library dart_style.src.line_splitting.solve_state_queue;
|
| -
|
| -import 'line_splitter.dart';
|
| -import 'solve_state.dart';
|
| -
|
| -/// A priority queue of [SolveStates] to consider while line splitting.
|
| -///
|
| -/// This is based on the [HeapPriorityQueue] class from the "collection"
|
| -/// package, but is modified to handle the "overlap" logic that allows one
|
| -/// [SolveState] to supercede another.
|
| -///
|
| -/// States are stored internally in a heap ordered by cost, the number of
|
| -/// overflow characters. When a new state is added to the heap, it will be
|
| -/// discarded, or a previously enqueued one will be discarded, if two overlap.
|
| -class SolveStateQueue {
|
| - /// Initial capacity of a queue when created, or when added to after a [clear].
|
| - /// Number can be any positive value. Picking a size that gives a whole
|
| - /// number of "tree levels" in the heap is only done for aesthetic reasons.
|
| - static const int _INITIAL_CAPACITY = 7;
|
| -
|
| - LineSplitter _splitter;
|
| -
|
| - /// List implementation of a heap.
|
| - List<SolveState> _queue = new List<SolveState>(_INITIAL_CAPACITY);
|
| -
|
| - /// Number of elements in queue.
|
| - /// The heap is implemented in the first [_length] entries of [_queue].
|
| - int _length = 0;
|
| -
|
| - bool get isNotEmpty => _length != 0;
|
| -
|
| - void bindSplitter(LineSplitter splitter) {
|
| - // Only do this once.
|
| - assert(_splitter == null);
|
| -
|
| - _splitter = splitter;
|
| - }
|
| -
|
| - /// Add [state] to the queue.
|
| - ///
|
| - /// Grows the capacity if the backing list is full.
|
| - void add(SolveState state) {
|
| - if (_tryOverlap(state)) return;
|
| -
|
| - if (_length == _queue.length) {
|
| - var newCapacity = _queue.length * 2 + 1;
|
| - if (newCapacity < _INITIAL_CAPACITY) newCapacity = _INITIAL_CAPACITY;
|
| -
|
| - var newQueue = new List<SolveState>(newCapacity);
|
| - newQueue.setRange(0, _length, _queue);
|
| - _queue = newQueue;
|
| - }
|
| -
|
| - _bubbleUp(state, _length++);
|
| - }
|
| -
|
| - SolveState removeFirst() {
|
| - assert(_length > 0);
|
| -
|
| - // Remove the highest priority state.
|
| - var result = _queue[0];
|
| - _length--;
|
| -
|
| - // Fill the gap with the one at the end of the list and re-heapify.
|
| - if (_length > 0) {
|
| - var last = _queue[_length];
|
| - _queue[_length] = null;
|
| - _bubbleDown(last, 0);
|
| - }
|
| -
|
| - return result;
|
| - }
|
| -
|
| - /// Orders this state relative to [other].
|
| - ///
|
| - /// This is a best-first ordering that prefers cheaper states even if they
|
| - /// overflow because this ensures it finds the best solution first as soon as
|
| - /// it finds one that fits in the page so it can early out.
|
| - int _compare(SolveState a, SolveState b) {
|
| - // TODO(rnystrom): It may be worth sorting by the estimated lowest number
|
| - // of overflow characters first. That doesn't help in cases where there is
|
| - // a solution that fits, but may help in corner cases where there is no
|
| - // fitting solution.
|
| -
|
| - var comparison = _compareScore(a, b);
|
| - if (comparison != 0) return comparison;
|
| -
|
| - return _compareRules(a, b);
|
| - }
|
| -
|
| - /// Compares the overflow and cost of [a] to [b].
|
| - int _compareScore(SolveState a, SolveState b) {
|
| - if (a.splits.cost != b.splits.cost) {
|
| - return a.splits.cost.compareTo(b.splits.cost);
|
| - }
|
| -
|
| - return a.overflowChars.compareTo(b.overflowChars);
|
| - }
|
| -
|
| - /// Distinguish states based on the rule values just so that states with the
|
| - /// same cost range but different rule values don't get considered identical
|
| - /// and inadvertantly merged.
|
| - int _compareRules(SolveState a, SolveState b) {
|
| - for (var rule in _splitter.rules) {
|
| - var aValue = a.getValue(rule);
|
| - var bValue = b.getValue(rule);
|
| -
|
| - if (aValue != bValue) return aValue.compareTo(bValue);
|
| - }
|
| -
|
| - // The way SolveStates are expanded should guarantee that we never generate
|
| - // the exact same state twice. Getting here implies that that failed.
|
| - throw "unreachable";
|
| - }
|
| -
|
| - /// Determines if any already enqueued state overlaps [state].
|
| - ///
|
| - /// If so, chooses the best and discards the other. Returns `true` in this
|
| - /// case. Otherwise, returns `false`.
|
| - bool _tryOverlap(SolveState state) {
|
| - if (_length == 0) return false;
|
| -
|
| - // Count positions from one instead of zero. This gives the numbers some
|
| - // nice properties. For example, all right children are odd, their left
|
| - // sibling is even, and the parent is found by shifting right by one.
|
| - // Valid range for position is [1.._length], inclusive.
|
| - var position = 1;
|
| -
|
| - // Pre-order depth first search, omit child nodes if the current node has
|
| - // lower priority than [object], because all nodes lower in the heap will
|
| - // also have lower priority.
|
| - do {
|
| - var index = position - 1;
|
| - var enqueued = _queue[index];
|
| -
|
| - var comparison = _compareScore(enqueued, state);
|
| -
|
| - if (comparison == 0) {
|
| - var overlap = enqueued.compareOverlap(state);
|
| - if (overlap < 0) {
|
| - // The old state is better, so just discard the new one.
|
| - return true;
|
| - } else if (overlap > 0) {
|
| - // The new state is better than the enqueued one, so replace it.
|
| - _queue[index] = state;
|
| - return true;
|
| - } else {
|
| - // We can't merge them, so sort by their bound rule values.
|
| - comparison = _compareRules(enqueued, state);
|
| - }
|
| - }
|
| -
|
| - if (comparison < 0) {
|
| - // Element may be in subtree. Continue with the left child, if any.
|
| - var leftChildPosition = position * 2;
|
| - if (leftChildPosition <= _length) {
|
| - position = leftChildPosition;
|
| - continue;
|
| - }
|
| - }
|
| -
|
| - // Find the next right sibling or right ancestor sibling.
|
| - do {
|
| - while (position.isOdd) {
|
| - // While position is a right child, go to the parent.
|
| - position >>= 1;
|
| - }
|
| -
|
| - // Then go to the right sibling of the left child.
|
| - position += 1;
|
| - } while (position > _length); // Happens if last element is a left child.
|
| - } while (position != 1); // At root again. Happens for right-most element.
|
| -
|
| - return false;
|
| - }
|
| -
|
| - /// Place [element] in heap at [index] or above.
|
| - ///
|
| - /// Put element into the empty cell at `index`. While the `element` has
|
| - /// higher priority than the parent, swap it with the parent.
|
| - void _bubbleUp(SolveState element, int index) {
|
| - while (index > 0) {
|
| - var parentIndex = (index - 1) ~/ 2;
|
| - var parent = _queue[parentIndex];
|
| -
|
| - if (_compare(element, parent) > 0) break;
|
| -
|
| - _queue[index] = parent;
|
| - index = parentIndex;
|
| - }
|
| -
|
| - _queue[index] = element;
|
| - }
|
| -
|
| - /// Place [element] in heap at [index] or above.
|
| - ///
|
| - /// Put element into the empty cell at `index`. While the `element` has lower
|
| - /// priority than either child, swap it with the highest priority child.
|
| - void _bubbleDown(SolveState element, int index) {
|
| - var rightChildIndex = index * 2 + 2;
|
| -
|
| - while (rightChildIndex < _length) {
|
| - var leftChildIndex = rightChildIndex - 1;
|
| - var leftChild = _queue[leftChildIndex];
|
| - var rightChild = _queue[rightChildIndex];
|
| -
|
| - var comparison = _compare(leftChild, rightChild);
|
| - var minChildIndex;
|
| - var minChild;
|
| -
|
| - if (comparison < 0) {
|
| - minChild = leftChild;
|
| - minChildIndex = leftChildIndex;
|
| - } else {
|
| - minChild = rightChild;
|
| - minChildIndex = rightChildIndex;
|
| - }
|
| -
|
| - comparison = _compare(element, minChild);
|
| -
|
| - if (comparison <= 0) {
|
| - _queue[index] = element;
|
| - return;
|
| - }
|
| -
|
| - _queue[index] = minChild;
|
| - index = minChildIndex;
|
| - rightChildIndex = index * 2 + 2;
|
| - }
|
| -
|
| - var leftChildIndex = rightChildIndex - 1;
|
| - if (leftChildIndex < _length) {
|
| - var child = _queue[leftChildIndex];
|
| - var comparison = _compare(element, child);
|
| -
|
| - if (comparison > 0) {
|
| - _queue[index] = child;
|
| - index = leftChildIndex;
|
| - }
|
| - }
|
| -
|
| - _queue[index] = element;
|
| - }
|
| -}
|
|
|