1- // ===--- LeftCanonicalForm .cpp - Left canonical form of a rewrite path ----===//
1+ // ===--- NormalizeRewritePath .cpp - Canonical form of a rewrite path -- ----===//
22//
33// This source file is part of the Swift.org open source project
44//
@@ -144,50 +144,91 @@ bool RewriteStep::maybeSwapRewriteSteps(RewriteStep &other,
144144// / This does not change either endpoint of the path, and the path does
145145// / not necessarily need to be a loop.
146146bool RewritePath::computeFreelyReducedForm () {
147- SmallVector<RewriteStep, 4 > newSteps;
148- bool changed = false ;
149-
150- for (const auto &step : Steps) {
151- if (!newSteps.empty () &&
152- newSteps.back ().isInverseOf (step)) {
153- changed = true ;
154- newSteps.pop_back ();
155- continue ;
147+ unsigned j = 0 ;
148+
149+ for (unsigned i = 0 , e = Steps.size (); i < e; ++i) {
150+ // Pre-condition:
151+ // - Steps in the range [0, j-1] are freely reduced.
152+ // - Steps in the range [i, e-1] remain to be considered.
153+ if (j > 0 ) {
154+ // If Steps[j-1] and Steps[i] are inverses of each other,
155+ // discard both Steps[j-1] and Steps[i].
156+ const auto &otherStep = Steps[j - 1 ];
157+ const auto &step = Steps[i];
158+
159+ if (otherStep.isInverseOf (step)) {
160+ --j;
161+ continue ;
162+ }
156163 }
157164
158- newSteps.push_back (step);
165+ // Post-condition:
166+ // - Steps in the range [0, j] are freely reduced.
167+ // - Steps in the range [i+1, e-1] remain to be considered.
168+ Steps[j] = Steps[i];
169+ ++j;
159170 }
160171
161- if (!changed )
172+ if (j == Steps. size () )
162173 return false ;
163- std::swap (newSteps, Steps);
164- return changed;
174+
175+ Steps.erase (Steps.begin () + j, Steps.end ());
176+ return true ;
165177}
166178
167179// / Apply the interchange rule until fixed point (see maybeSwapRewriteSteps()).
168180bool RewritePath::computeLeftCanonicalForm (const RewriteSystem &system) {
169181 bool changed = false ;
170182
171183 for (unsigned i = 1 , e = Steps.size (); i < e; ++i) {
172- auto &prevStep = Steps[i - 1 ];
173- auto &step = Steps[i];
184+ // Pre-condition: steps in the range [0, i-1] are in left-canonical
185+ // normal form.
186+ //
187+ // If Steps[i] can be swapped with Steps[i-1], swap them, and check
188+ // if Steps[i-1] (the old Steps[i]) can be swapped with Steps[i-2],
189+ // etc.
190+ for (unsigned j = i; j >= 1 ; --j) {
191+ auto &prevStep = Steps[j - 1 ];
192+ auto &step = Steps[j];
193+
194+ if (!prevStep.maybeSwapRewriteSteps (step, system))
195+ break ;
174196
175- if (prevStep.maybeSwapRewriteSteps (step, system))
176197 changed = true ;
198+ }
199+
200+ // Post-condition: steps in the range [0, i] are in left-canonical
201+ // normal form.
177202 }
178203
179204 return changed;
180205}
181206
182207// / Compute freely-reduced left-canonical normal form of a path.
183- void RewritePath::computeNormalForm (const RewriteSystem &system) {
184- // FIXME: This can be more efficient.
185- bool changed;
186- do {
187- changed = false ;
188- changed |= computeFreelyReducedForm ();
189- changed |= computeLeftCanonicalForm (system);
190- } while (changed);
208+ bool RewritePath::computeNormalForm (const RewriteSystem &system) {
209+ // Note that computeFreelyReducedForm() and computeLeftCanonicalForm()
210+ // are both idempotent, but their composition is not.
211+
212+ // Begin by freely reducing the path.
213+ bool changed = computeFreelyReducedForm ();
214+
215+ // Then, bring it into left canonical form.
216+ while (computeLeftCanonicalForm (system)) {
217+ changed = true ;
218+
219+ // If it was not already in left-canonical form, freely reduce it
220+ // again.
221+ if (!computeFreelyReducedForm ()) {
222+ // If it was already freely reduced, then we're done, because it
223+ // is freely reduced *and* in left-canonical form.
224+ break ;
225+ }
226+
227+ // Otherwise, perform another round, since freely reducing may have
228+ // opened up new opportunities for left-canonicalization.
229+ }
230+
231+ return changed;
191232}
192233
193234// / Given a path that is a loop around the given basepoint, cancels out
@@ -227,15 +268,9 @@ bool RewritePath::computeCyclicallyReducedForm(MutableTerm &basepoint,
227268
228269// / Compute cyclically-reduced left-canonical normal form of a loop.
229270void RewriteLoop::computeNormalForm (const RewriteSystem &system) {
230- // FIXME: This can be more efficient.
231- bool changed;
232- do {
233- changed = false ;
234- changed |= Path.computeFreelyReducedForm ();
235- changed |= Path.computeCyclicallyReducedForm (Basepoint, system);
236- changed |= Path.computeLeftCanonicalForm (system);
237-
238- if (changed)
239- markDirty ();
240- } while (changed);
271+ bool changed = Path.computeNormalForm (system);
272+ changed |= Path.computeCyclicallyReducedForm (Basepoint, system);
273+
274+ if (changed)
275+ markDirty ();
241276}
0 commit comments