Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3879)

Unified Diff: lib/src/rule_set.dart

Issue 1255643002: New, simpler and faster line splitter. (Closed) Base URL: https://github.com/dart-lang/dart_style.git@master
Patch Set: Optimize nesting. Reformat. Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « lib/src/rule/rule.dart ('k') | pubspec.yaml » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: lib/src/rule_set.dart
diff --git a/lib/src/rule_set.dart b/lib/src/rule_set.dart
new file mode 100644
index 0000000000000000000000000000000000000000..362fad186436ccb0b9b9c3e3e7af8a806c29b000
--- /dev/null
+++ b/lib/src/rule_set.dart
@@ -0,0 +1,157 @@
+// 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.rule_set;
+
+import 'rule/rule.dart';
+
+/// An optimized data structure for storing a set of values for some rules.
+///
+/// This conceptually behaves roughly like a `Map<Rule, int>`, but is much
+/// faster since it avoids hashing. Instead, it assumes the line splitter has
+/// provided an ordered list of [Rule]s and that each rule's [index] field has
+/// been set to point to the rule in the list.
+///
+/// Internally, this then just stores the values in a sparse list whose indices
+/// are the indices of the rules.
+class RuleSet {
+ List<int> _values;
+
+ RuleSet(int numRules) : this._(new List(numRules));
+
+ RuleSet._(this._values);
+
+ /// Returns `true` of [rule] is bound in this set.
+ bool contains(Rule rule) => _values[rule.index] != null;
+
+ /// Gets the bound value for [rule] or `0` if it is not bound.
+ int getValue(Rule rule) {
+ var value = _values[rule.index];
+ if (value != null) return value;
+
+ return 0;
+ }
+
+ /// Invokes [callback] for each rule in [rules] with the rule's value, which
+ /// will be `null` if it is not bound.
+ void forEach(List<Rule> rules, callback(Rule rule, int value)) {
+ var i = 0;
+ for (var rule in rules) {
+ var value = _values[i];
+ if (value != null) callback(rule, value);
+ i++;
+ }
+ }
+
+ /// Creates a new [RuleSet] with the same bound rule values as this one.
+ RuleSet clone() => new RuleSet._(_values.toList(growable: false));
+
+ /// Binds [rule] to [value] then checks to see if that violates any
+ /// constraints.
+ ///
+ /// Returns `true` if all constraints between the bound rules are valid. Even
+ /// if not, this still modifies the [RuleSet].
+ ///
+ /// If an unbound rule gets constrained to `-1` (meaning it must split, but
+ /// can split any way it wants), invokes [onSplitRule] with it.
+ bool tryBind(List<Rule> rules, Rule rule, int value, onSplitRule(Rule rule)) {
+ _values[rule.index] = value;
+
+ // Test this rule against the other rules being bound.
+ for (var other in rules) {
+ if (rule == other) continue;
+
+ var otherValue = _values[other.index];
+ var constraint = rule.constrain(value, other);
+
+ if (otherValue == null) {
+ // The other rule is unbound, so see if we can constrain it eagerly to
+ // a value now.
+ if (constraint == -1) {
+ // If we know the rule has to split and there's only one way it can,
+ // just bind that.
+ if (other.numValues == 2) {
+ if (!tryBind(rules, other, 1, onSplitRule)) return false;
+ } else {
+ onSplitRule(other);
+ }
+ } else if (constraint != null) {
+ // Bind the other rule to its value and recursively propagate its
+ // constraints.
+ if (!tryBind(rules, other, constraint, onSplitRule)) return false;
+ }
+ } else {
+ // It's already bound, so see if the new rule's constraint disallows
+ // that value.
+ if (constraint == -1) {
+ if (otherValue == 0) return false;
+ } else if (constraint != null) {
+ if (otherValue != constraint) return false;
+ }
+
+ // See if the other rule's constraint allows us to use this value.
+ constraint = other.constrain(otherValue, rule);
+ if (constraint == -1) {
+ if (value == 0) return false;
+ } else if (constraint != null) {
+ if (value != constraint) return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ String toString() =>
+ _values.map((value) => value == null ? "?" : value).join(" ");
+}
+
+/// For each chunk, this tracks if it has been split and, if so, what the
+/// chosen column is for the following line.
+///
+/// Internally, this uses a list where each element corresponds to the column
+/// of the chunk at that index in the chunk list, or `null` if that chunk did
+/// not split. This had about a 10% perf improvement over using a [Set] of
+/// splits.
+class SplitSet {
+ List<int> _columns;
+
+ /// The cost of the solution that led to these splits.
+ int get cost => _cost;
+ int _cost;
+
+ /// Creates a new empty split set for a line with [numChunks].
+ SplitSet(int numChunks) : _columns = new List(numChunks - 1);
+
+ /// Marks the line after chunk [index] as starting at [column].
+ void add(int index, int column) {
+ _columns[index] = column;
+ }
+
+ /// Returns `true` if the chunk at [splitIndex] should be split.
+ bool shouldSplitAt(int index) =>
+ index < _columns.length && _columns[index] != null;
+
+ /// Gets the zero-based starting column for the chunk at [index].
+ int getColumn(int index) => _columns[index];
+
+ /// Sets the resulting [cost] for the splits.
+ ///
+ /// This can only be called once.
+ void setCost(int cost) {
+ assert(_cost == null);
+ _cost = cost;
+ }
+
+ String toString() {
+ var result = [];
+ for (var i = 0; i < _columns.length; i++) {
+ if (_columns[i] != null) {
+ result.add("$i:${_columns[i]}");
+ }
+ }
+
+ return result.join(" ");
+ }
+}
« no previous file with comments | « lib/src/rule/rule.dart ('k') | pubspec.yaml » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698