Skip to content
This repository was archived by the owner on Jun 15, 2023. It is now read-only.

Commit 3cd561a

Browse files
authored
Printer: make propagateForcedBreaks allocation-free (#325)
Instead of returning a copy of the doc with some `IfBreak`s resolved, make doc mutable to mark when an `IfBreak` has been resolved to the first branch. This makes the function allocation-free, but with side effects on the doc.
1 parent f27e107 commit 3cd561a

File tree

1 file changed

+34
-33
lines changed

1 file changed

+34
-33
lines changed

src/res_doc.ml

Lines changed: 34 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ type t =
1515
| Text of string
1616
| Concat of t list
1717
| Indent of t
18-
| IfBreaks of {yes: t; no: t}
18+
| IfBreaks of {yes: t; no: t; mutable broken: bool} (* when broken is true, treat as the yes branch *)
1919
| LineSuffix of t
2020
| LineBreak of lineStyle
21-
| Group of {shouldBreak: bool; doc: t}
21+
| Group of {mutable shouldBreak: bool; doc: t}
2222
| CustomLayout of t list
2323
| BreakParent
2424

@@ -43,7 +43,7 @@ let rec _concat acc l =
4343
let concat l = Concat(_concat [] l)
4444

4545
let indent d = Indent d
46-
let ifBreaks t f = IfBreaks {yes = t; no = f}
46+
let ifBreaks t f = IfBreaks {yes = t; no = f; broken = false}
4747
let lineSuffix d = LineSuffix d
4848
let group d = Group {shouldBreak = false; doc = d}
4949
let breakableGroup ~forceBreak d = Group {shouldBreak = forceBreak; doc = d}
@@ -66,55 +66,52 @@ let rbracket = Text "]"
6666
let question = Text "?"
6767
let tilde = Text "~"
6868
let equal = Text "="
69-
let trailingComma = IfBreaks {yes = comma; no = nil}
69+
let trailingComma = ifBreaks comma nil
7070
let doubleQuote = Text "\""
7171

7272
let propagateForcedBreaks doc =
7373
let rec walk doc = match doc with
7474
| Text _ | Nil | LineSuffix _ ->
75-
(false, doc)
75+
false
7676
| BreakParent ->
77-
(true, Nil)
77+
true
7878
| LineBreak (Hard | Literal) ->
79-
(true, doc)
79+
true
8080
| LineBreak (Classic | Soft) ->
81-
(false, doc)
81+
false
8282
| Indent children ->
83-
let (childForcesBreak, newChildren) = walk children in
84-
(childForcesBreak, Indent newChildren)
85-
| IfBreaks {yes = trueDoc; no = falseDoc} ->
86-
let (falseForceBreak, falseDoc) = walk falseDoc in
83+
let childForcesBreak = walk children in
84+
childForcesBreak
85+
| IfBreaks ({yes = trueDoc; no = falseDoc} as ib) ->
86+
let falseForceBreak = walk falseDoc in
8787
if falseForceBreak then
88-
let (_, trueDoc) = walk trueDoc in
89-
(true, trueDoc)
88+
let _ = walk trueDoc in
89+
ib.broken <- true;
90+
true
9091
else
91-
let forceBreak, trueDoc = walk trueDoc in
92-
(forceBreak, IfBreaks {yes = trueDoc; no = falseDoc})
93-
| Group {shouldBreak = forceBreak; doc = children} ->
94-
let (childForcesBreak, newChildren) = walk children in
92+
let forceBreak = walk trueDoc in
93+
forceBreak
94+
| Group ({shouldBreak = forceBreak; doc = children} as gr) ->
95+
let childForcesBreak = walk children in
9596
let shouldBreak = forceBreak || childForcesBreak in
96-
(shouldBreak, Group {shouldBreak; doc = newChildren})
97+
gr.shouldBreak <- shouldBreak;
98+
shouldBreak
9799
| Concat children ->
98-
let (forceBreak, newChildren) = List.fold_left (fun (forceBreak, newChildren) child ->
99-
let (childForcesBreak, newChild) = walk child in
100-
(forceBreak || childForcesBreak, newChild::newChildren)
101-
) (false, []) children
102-
in
103-
(forceBreak, Concat (List.rev newChildren))
100+
List.fold_left (fun forceBreak child ->
101+
let childForcesBreak = walk child in
102+
forceBreak || childForcesBreak
103+
) false children
104104
| CustomLayout children ->
105105
(* When using CustomLayout, we don't want to propagate forced breaks
106106
* from the children up. By definition it picks the first layout that fits
107107
* otherwise it takes the last of the list.
108108
* However we do want to propagate forced breaks in the sublayouts. They
109109
* might need to be broken. We just don't propagate them any higher here *)
110-
let children = match walk (Concat children) with
111-
| (_, Concat children) -> children
112-
| _ -> assert false
113-
in
114-
(false, CustomLayout children)
110+
let _ = walk (Concat children) in
111+
false
115112
in
116-
let (_, processedDoc) = walk doc in
117-
processedDoc
113+
let _ = walk doc in
114+
()
118115

119116
(* See documentation in interface file *)
120117
let rec willBreak doc = match doc with
@@ -153,6 +150,7 @@ let fits w stack =
153150
| Break, LineBreak _ -> result := Some true
154151
| _, Group {shouldBreak = true; doc} -> calculate indent Break doc
155152
| _, Group {doc} -> calculate indent mode doc
153+
| _, IfBreaks {yes = breakDoc; broken = true} -> calculate indent mode breakDoc
156154
| Break, IfBreaks {yes = breakDoc} -> calculate indent mode breakDoc
157155
| Flat, IfBreaks {no = flatDoc} -> calculate indent mode flatDoc
158156
| _, Concat docs -> calculateConcat indent mode docs
@@ -180,7 +178,7 @@ let fits w stack =
180178
calculateAll stack
181179

182180
let toString ~width doc =
183-
let doc = propagateForcedBreaks doc in
181+
propagateForcedBreaks doc;
184182
let buffer = MiniBuffer.create 1000 in
185183

186184
let rec process ~pos lineSuffices stack =
@@ -199,6 +197,8 @@ let toString ~width doc =
199197
process ~pos lineSuffices (List.append ops rest)
200198
| Indent doc ->
201199
process ~pos lineSuffices ((ind + 2, mode, doc)::rest)
200+
| IfBreaks {yes = breakDoc; broken = true} ->
201+
process ~pos lineSuffices ((ind, mode, breakDoc)::rest)
202202
| IfBreaks {yes = breakDoc; no = flatDoc} ->
203203
if mode = Break then
204204
process ~pos lineSuffices ((ind, mode, breakDoc)::rest)
@@ -309,6 +309,7 @@ let debug t =
309309
softLine;
310310
text ")";
311311
]
312+
| IfBreaks {yes = trueDoc; broken = true} -> toDoc trueDoc
312313
| IfBreaks {yes = trueDoc; no = falseDoc} ->
313314
group(
314315
concat [

0 commit comments

Comments
 (0)