Skip to content

Commit 07a11b8

Browse files
craig[bot]knz
andcommitted
Merge #27256
27256: pretty: make the code clearer and faster r=knz a=knz ``` name old time/op new time/op delta PrettyData-16 1.79s ±31% 0.13s ± 3% -92.50% (p=0.008 n=5+5) name old alloc/op new alloc/op delta PrettyData-16 630MB ± 1% 24MB ± 0% -96.15% (p=0.008 n=5+5) name old allocs/op new allocs/op delta PrettyData-16 4.27M ± 0% 0.01M ± 0% -99.74% (p=0.008 n=5+5) ``` Co-authored-by: Raphael 'kena' Poss <knz@cockroachlabs.com>
2 parents ca68afa + fe13c4a commit 07a11b8

File tree

3 files changed

+225
-173
lines changed

3 files changed

+225
-173
lines changed

pkg/util/pretty/document.go

Lines changed: 48 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,20 @@
2828
// side. The paper then describes various performance improvements that reduce
2929
// the search space of the best function such that it can complete in O(n)
3030
// instead of O(n^2) time, where n is the number of nodes.
31+
//
32+
// For example code with SQL to experiment further, refer to
33+
// https://github.com/knz/prettier/
34+
//
3135
package pretty
3236

3337
import (
3438
"fmt"
3539
)
3640

37-
// Doc represents a document as described by the referenced paper.
41+
// Doc represents a document as described by the type "DOC" in the
42+
// referenced paper. This is the abstract representation constructed
43+
// by the pretty-printing code.
3844
type Doc interface {
39-
// All Docs can uniquely convert themselves into a string so they can be
40-
// memoized during better calculation.
41-
String() string
4245
isDoc()
4346
}
4447

@@ -48,81 +51,70 @@ func (nilDoc) isDoc() {}
4851
func (concat) isDoc() {}
4952
func (nest) isDoc() {}
5053
func (union) isDoc() {}
51-
func (textX) isDoc() {}
52-
func (lineX) isDoc() {}
53-
54-
func (d text) String() string { return fmt.Sprintf("(%q)", string(d)) }
55-
func (line) String() string { return "LINE" }
56-
func (nilDoc) String() string { return "NIL" }
57-
func (d concat) String() string { return fmt.Sprintf("(%s :<> %s)", d.a, d.b) }
58-
func (d nest) String() string { return fmt.Sprintf("(NEST %d %s)", d.n, d.d) }
59-
func (d union) String() string { return fmt.Sprintf("(%s :<|> %s)", d.x, d.y) }
60-
func (d textX) String() string { return fmt.Sprintf("(%q TEXTX %s)", d.s, d.d) }
61-
func (d lineX) String() string { return fmt.Sprintf("(%q LINEX %s)", d.s, d.d) }
6254

55+
//
56+
// Implementations of Doc ("DOC" in paper).
57+
//
58+
59+
// nilDoc represents NIL :: DOC -- the empty doc.
6360
type nilDoc struct{}
6461

65-
// Nil is the empty Doc.
62+
// Nil is the NIL constructor.
6663
var Nil nilDoc
6764

65+
// text represents (TEXT s) :: DOC -- a simple text string.
6866
type text string
6967

70-
// Text creates a string Doc.
68+
// Text is the TEXT constructor.
7169
func Text(s string) Doc {
7270
return text(s)
7371
}
7472

73+
// line represents LINE :: DOC -- a "soft line" that can be flattened to a space.
7574
type line struct{}
7675

77-
// Line is either a newline or a space if flattened onto a single line.
76+
// Line is the LINE constructor.
7877
var Line line
7978

79+
// concat represents (DOC <> DOC) :: DOC -- the concatenation of two docs.
8080
type concat struct {
8181
a, b Doc
8282
}
8383

84-
// fnNotNil runs returns fn(a, b). nil (the Go value) is converted to Nil (the
85-
// Doc). If either Doc is Nil, the other Doc is returned without invoking fn.
86-
func concatFn(a, b Doc, fn func(Doc, Doc) Doc) Doc {
87-
if a == nil {
88-
a = Nil
89-
}
90-
if b == nil {
91-
b = Nil
92-
}
93-
if a == Nil {
94-
return b
95-
}
96-
if b == Nil {
97-
return a
98-
}
99-
return fn(a, b)
84+
// Concat is the <> constructor.
85+
// This uses simplifyNil to avoid actually inserting NIL docs
86+
// in the abstract tree.
87+
func Concat(a, b Doc) Doc {
88+
return simplifyNil(a, b, func(a, b Doc) Doc { return concat{a, b} })
10089
}
10190

102-
// Concat concatenates two Docs.
103-
func Concat(a, b Doc) Doc {
104-
return concatFn(a, b, func(a, b Doc) Doc {
105-
return concat{a, b}
106-
})
91+
// nest represents (NEST Int DOC) :: DOC -- nesting a doc "under" another.
92+
// NEST indents d by s at effective length n. len(s) does not have to be
93+
// n. This allows s to be a tab character and n can be a tab width.
94+
type nest struct {
95+
n int
96+
s string
97+
d Doc
10798
}
10899

109-
// Fill concatenates a list of docs with spaces if possible,
110-
// otherwise with newlines.
111-
// See linked paper pp 14-15.
112-
// func Fill(d ...Doc) Doc {
113-
// switch len(d) {
114-
// case 0:
115-
// return Nil
116-
// case 1:
117-
// return d[0]
118-
// default:
119-
// rest := Fill(d[1:]...)
120-
// return union{
121-
// ConcatSpace(flatten(d[0]), rest),
122-
// ConcatLine(d[0], rest),
123-
// }
124-
// }
125-
// }
100+
// Nest is the NEST constructor.
101+
func Nest(n int, s string, d Doc) Doc {
102+
return nest{n, s, d}
103+
}
104+
105+
// union represents (DOC <|> DOC) :: DOC -- the union of two docs.
106+
// <|> is really the union of two sets of layouts. x and y must flatten to the
107+
// same layout. Additionally, no first line of a document in x is shorter
108+
// than some first line of a document in y; or, equivalently, every first
109+
// line in x is at least as long as every first line in y.
110+
//
111+
// The main use of the union is via the Group operator defined below.
112+
//
113+
// We do not provide a public constructor as this type is not
114+
// exported.
115+
type union struct {
116+
x, y Doc
117+
}
126118

127119
// Group will format d on one line if possible.
128120
func Group(d Doc) Doc {
@@ -149,35 +141,3 @@ func flatten(d Doc) Doc {
149141
panic(fmt.Errorf("unknown type: %T", d))
150142
}
151143
}
152-
153-
type nest struct {
154-
n int
155-
s string
156-
d Doc
157-
}
158-
159-
// Nest indents d by s at effective length n. len(s) does not have to be
160-
// n. This allows s to be a tab character and n can be a tab width.
161-
func Nest(n int, s string, d Doc) Doc {
162-
return nest{n, s, d}
163-
}
164-
165-
// Doc types below are not directly accessible to users.
166-
167-
// union is the union of two sets of layouts. x and y must flatten to the
168-
// same layout. Additionally, no first line of a document in x is shorter
169-
// than some first line of a document in y; or, equivalently, every first
170-
// line in x is at least as long as every first line in y.
171-
type union struct {
172-
x, y Doc
173-
}
174-
175-
type textX struct {
176-
s string
177-
d Doc
178-
}
179-
180-
type lineX struct {
181-
s string
182-
d Doc
183-
}

0 commit comments

Comments
 (0)