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

Side by Side 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 unified diff | Download patch
« no previous file with comments | « lib/src/rule/rule.dart ('k') | pubspec.yaml » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 library dart_style.src.rule_set;
6
7 import 'rule/rule.dart';
8
9 /// An optimized data structure for storing a set of values for some rules.
10 ///
11 /// This conceptually behaves roughly like a `Map<Rule, int>`, but is much
12 /// faster since it avoids hashing. Instead, it assumes the line splitter has
13 /// provided an ordered list of [Rule]s and that each rule's [index] field has
14 /// been set to point to the rule in the list.
15 ///
16 /// Internally, this then just stores the values in a sparse list whose indices
17 /// are the indices of the rules.
18 class RuleSet {
19 List<int> _values;
20
21 RuleSet(int numRules) : this._(new List(numRules));
22
23 RuleSet._(this._values);
24
25 /// Returns `true` of [rule] is bound in this set.
26 bool contains(Rule rule) => _values[rule.index] != null;
27
28 /// Gets the bound value for [rule] or `0` if it is not bound.
29 int getValue(Rule rule) {
30 var value = _values[rule.index];
31 if (value != null) return value;
32
33 return 0;
34 }
35
36 /// Invokes [callback] for each rule in [rules] with the rule's value, which
37 /// will be `null` if it is not bound.
38 void forEach(List<Rule> rules, callback(Rule rule, int value)) {
39 var i = 0;
40 for (var rule in rules) {
41 var value = _values[i];
42 if (value != null) callback(rule, value);
43 i++;
44 }
45 }
46
47 /// Creates a new [RuleSet] with the same bound rule values as this one.
48 RuleSet clone() => new RuleSet._(_values.toList(growable: false));
49
50 /// Binds [rule] to [value] then checks to see if that violates any
51 /// constraints.
52 ///
53 /// Returns `true` if all constraints between the bound rules are valid. Even
54 /// if not, this still modifies the [RuleSet].
55 ///
56 /// If an unbound rule gets constrained to `-1` (meaning it must split, but
57 /// can split any way it wants), invokes [onSplitRule] with it.
58 bool tryBind(List<Rule> rules, Rule rule, int value, onSplitRule(Rule rule)) {
59 _values[rule.index] = value;
60
61 // Test this rule against the other rules being bound.
62 for (var other in rules) {
63 if (rule == other) continue;
64
65 var otherValue = _values[other.index];
66 var constraint = rule.constrain(value, other);
67
68 if (otherValue == null) {
69 // The other rule is unbound, so see if we can constrain it eagerly to
70 // a value now.
71 if (constraint == -1) {
72 // If we know the rule has to split and there's only one way it can,
73 // just bind that.
74 if (other.numValues == 2) {
75 if (!tryBind(rules, other, 1, onSplitRule)) return false;
76 } else {
77 onSplitRule(other);
78 }
79 } else if (constraint != null) {
80 // Bind the other rule to its value and recursively propagate its
81 // constraints.
82 if (!tryBind(rules, other, constraint, onSplitRule)) return false;
83 }
84 } else {
85 // It's already bound, so see if the new rule's constraint disallows
86 // that value.
87 if (constraint == -1) {
88 if (otherValue == 0) return false;
89 } else if (constraint != null) {
90 if (otherValue != constraint) return false;
91 }
92
93 // See if the other rule's constraint allows us to use this value.
94 constraint = other.constrain(otherValue, rule);
95 if (constraint == -1) {
96 if (value == 0) return false;
97 } else if (constraint != null) {
98 if (value != constraint) return false;
99 }
100 }
101 }
102
103 return true;
104 }
105
106 String toString() =>
107 _values.map((value) => value == null ? "?" : value).join(" ");
108 }
109
110 /// For each chunk, this tracks if it has been split and, if so, what the
111 /// chosen column is for the following line.
112 ///
113 /// Internally, this uses a list where each element corresponds to the column
114 /// of the chunk at that index in the chunk list, or `null` if that chunk did
115 /// not split. This had about a 10% perf improvement over using a [Set] of
116 /// splits.
117 class SplitSet {
118 List<int> _columns;
119
120 /// The cost of the solution that led to these splits.
121 int get cost => _cost;
122 int _cost;
123
124 /// Creates a new empty split set for a line with [numChunks].
125 SplitSet(int numChunks) : _columns = new List(numChunks - 1);
126
127 /// Marks the line after chunk [index] as starting at [column].
128 void add(int index, int column) {
129 _columns[index] = column;
130 }
131
132 /// Returns `true` if the chunk at [splitIndex] should be split.
133 bool shouldSplitAt(int index) =>
134 index < _columns.length && _columns[index] != null;
135
136 /// Gets the zero-based starting column for the chunk at [index].
137 int getColumn(int index) => _columns[index];
138
139 /// Sets the resulting [cost] for the splits.
140 ///
141 /// This can only be called once.
142 void setCost(int cost) {
143 assert(_cost == null);
144 _cost = cost;
145 }
146
147 String toString() {
148 var result = [];
149 for (var i = 0; i < _columns.length; i++) {
150 if (_columns[i] != null) {
151 result.add("$i:${_columns[i]}");
152 }
153 }
154
155 return result.join(" ");
156 }
157 }
OLDNEW
« 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