OLD | NEW |
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 library dart_style.src.line_splitting.rule_set; | 5 library dart_style.src.line_splitting.rule_set; |
6 | 6 |
7 import '../rule/rule.dart'; | 7 import '../rule/rule.dart'; |
8 | 8 |
9 /// An optimized data structure for storing a set of values for some rules. | 9 /// An optimized data structure for storing a set of values for some rules. |
10 /// | 10 /// |
11 /// This conceptually behaves roughly like a `Map<Rule, int>`, but is much | 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 | 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 | 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. | 14 /// been set to point to the rule in the list. |
15 /// | 15 /// |
16 /// Internally, this then just stores the values in a sparse list whose indices | 16 /// Internally, this then just stores the values in a sparse list whose indices |
17 /// are the indices of the rules. | 17 /// are the indices of the rules. |
18 class RuleSet { | 18 class RuleSet { |
19 List<int> _values; | 19 List<int> _values; |
20 | 20 |
21 RuleSet(int numRules) : this._(new List(numRules)); | 21 RuleSet(int numRules) : this._(new List(numRules)); |
22 | 22 |
23 RuleSet._(this._values); | 23 RuleSet._(this._values); |
24 | 24 |
25 /// Returns `true` of [rule] is bound in this set. | 25 /// Returns `true` of [rule] is bound in this set. |
26 bool contains(Rule rule) => _values[rule.index] != null; | 26 bool contains(Rule rule) { |
| 27 // Treat hardened rules as implicitly bound. |
| 28 if (rule.isHardened) return true; |
27 | 29 |
28 /// Gets the bound value for [rule] or `0` if it is not bound. | 30 return _values[rule.index] != null; |
| 31 } |
| 32 |
| 33 /// Gets the bound value for [rule] or [Rule.unsplit] if it is not bound. |
29 int getValue(Rule rule) { | 34 int getValue(Rule rule) { |
| 35 // Hardened rules are implicitly bound. |
| 36 if (rule.isHardened) return rule.fullySplitValue; |
| 37 |
30 var value = _values[rule.index]; | 38 var value = _values[rule.index]; |
31 if (value != null) return value; | 39 if (value != null) return value; |
32 | 40 |
33 return 0; | 41 return Rule.unsplit; |
34 } | 42 } |
35 | 43 |
36 /// Invokes [callback] for each rule in [rules] with the rule's value, which | 44 /// Invokes [callback] for each rule in [rules] with the rule's value, which |
37 /// will be `null` if it is not bound. | 45 /// will be `null` if it is not bound. |
38 void forEach(List<Rule> rules, callback(Rule rule, int value)) { | 46 void forEach(List<Rule> rules, callback(Rule rule, int value)) { |
39 var i = 0; | 47 var i = 0; |
40 for (var rule in rules) { | 48 for (var rule in rules) { |
41 var value = _values[i]; | 49 var value = _values[i]; |
42 if (value != null) callback(rule, value); | 50 if (value != null) callback(rule, value); |
43 i++; | 51 i++; |
44 } | 52 } |
45 } | 53 } |
46 | 54 |
47 /// Creates a new [RuleSet] with the same bound rule values as this one. | 55 /// Creates a new [RuleSet] with the same bound rule values as this one. |
48 RuleSet clone() => new RuleSet._(_values.toList(growable: false)); | 56 RuleSet clone() => new RuleSet._(_values.toList(growable: false)); |
49 | 57 |
50 /// Binds [rule] to [value] then checks to see if that violates any | 58 /// Binds [rule] to [value] then checks to see if that violates any |
51 /// constraints. | 59 /// constraints. |
52 /// | 60 /// |
53 /// Returns `true` if all constraints between the bound rules are valid. Even | 61 /// Returns `true` if all constraints between the bound rules are valid. Even |
54 /// if not, this still modifies the [RuleSet]. | 62 /// if not, this still modifies the [RuleSet]. |
55 /// | 63 /// |
56 /// If an unbound rule gets constrained to `-1` (meaning it must split, but | 64 /// If an unbound rule gets constrained to `-1` (meaning it must split, but |
57 /// can split any way it wants), invokes [onSplitRule] with it. | 65 /// can split any way it wants), invokes [onSplitRule] with it. |
58 bool tryBind(List<Rule> rules, Rule rule, int value, onSplitRule(Rule rule)) { | 66 bool tryBind(List<Rule> rules, Rule rule, int value, onSplitRule(Rule rule)) { |
| 67 assert(!rule.isHardened); |
| 68 |
59 _values[rule.index] = value; | 69 _values[rule.index] = value; |
60 | 70 |
61 // Test this rule against the other rules being bound. | 71 // Test this rule against the other rules being bound. |
62 for (var other in rules) { | 72 for (var other in rule.constrainedRules) { |
63 if (rule == other) continue; | 73 var otherValue; |
| 74 // Hardened rules are implicitly bound. |
| 75 if (other.isHardened) { |
| 76 otherValue = other.fullySplitValue; |
| 77 } else { |
| 78 otherValue = _values[other.index]; |
| 79 } |
64 | 80 |
65 var otherValue = _values[other.index]; | |
66 var constraint = rule.constrain(value, other); | 81 var constraint = rule.constrain(value, other); |
67 | 82 |
68 if (otherValue == null) { | 83 if (otherValue == null) { |
69 // The other rule is unbound, so see if we can constrain it eagerly to | 84 // The other rule is unbound, so see if we can constrain it eagerly to |
70 // a value now. | 85 // a value now. |
71 if (constraint == -1) { | 86 if (constraint == Rule.mustSplit) { |
72 // If we know the rule has to split and there's only one way it can, | 87 // If we know the rule has to split and there's only one way it can, |
73 // just bind that. | 88 // just bind that. |
74 if (other.numValues == 2) { | 89 if (other.numValues == 2) { |
75 if (!tryBind(rules, other, 1, onSplitRule)) return false; | 90 if (!tryBind(rules, other, 1, onSplitRule)) return false; |
76 } else { | 91 } else { |
77 onSplitRule(other); | 92 onSplitRule(other); |
78 } | 93 } |
79 } else if (constraint != null) { | 94 } else if (constraint != null) { |
80 // Bind the other rule to its value and recursively propagate its | 95 // Bind the other rule to its value and recursively propagate its |
81 // constraints. | 96 // constraints. |
82 if (!tryBind(rules, other, constraint, onSplitRule)) return false; | 97 if (!tryBind(rules, other, constraint, onSplitRule)) return false; |
83 } | 98 } |
84 } else { | 99 } else { |
85 // It's already bound, so see if the new rule's constraint disallows | 100 // It's already bound, so see if the new rule's constraint disallows |
86 // that value. | 101 // that value. |
87 if (constraint == -1) { | 102 if (constraint == Rule.mustSplit) { |
88 if (otherValue == 0) return false; | 103 if (otherValue == Rule.unsplit) return false; |
89 } else if (constraint != null) { | 104 } else if (constraint != null) { |
90 if (otherValue != constraint) return false; | 105 if (otherValue != constraint) return false; |
91 } | 106 } |
92 | 107 |
93 // See if the other rule's constraint allows us to use this value. | 108 // See if the other rule's constraint allows us to use this value. |
94 constraint = other.constrain(otherValue, rule); | 109 constraint = other.constrain(otherValue, rule); |
95 if (constraint == -1) { | 110 if (constraint == Rule.mustSplit) { |
96 if (value == 0) return false; | 111 if (value == Rule.unsplit) return false; |
97 } else if (constraint != null) { | 112 } else if (constraint != null) { |
98 if (value != constraint) return false; | 113 if (value != constraint) return false; |
99 } | 114 } |
100 } | 115 } |
101 } | 116 } |
102 | 117 |
103 return true; | 118 return true; |
104 } | 119 } |
105 | 120 |
106 String toString() => | 121 String toString() => |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
148 var result = []; | 163 var result = []; |
149 for (var i = 0; i < _columns.length; i++) { | 164 for (var i = 0; i < _columns.length; i++) { |
150 if (_columns[i] != null) { | 165 if (_columns[i] != null) { |
151 result.add("$i:${_columns[i]}"); | 166 result.add("$i:${_columns[i]}"); |
152 } | 167 } |
153 } | 168 } |
154 | 169 |
155 return result.join(" "); | 170 return result.join(" "); |
156 } | 171 } |
157 } | 172 } |
OLD | NEW |