88
99import Foundation
1010
11- typealias CompareStrategy = ( IndentLevel , ColumnCount , Width , RibbonWidth ) -> ( SimpleDoc , SimpleDoc ) -> SimpleDoc
11+ typealias CompareStrategy = ( IndentLevel , ColumnCount , Width , RibbonWidth ) -> ( SimpleDoc , ( ) -> SimpleDoc ) -> SimpleDoc
12+
13+ indirect enum List < T> {
14+ case Nil
15+ case Cons( T , List < T > )
16+ }
17+
1218// TODO: Tune this datastructure to increase render performance
1319// Good properties:
1420// fast prepend
1521// fast (head, rest) decomposition
1622// shared substructure
1723// The obvious choice is a linked list, but maybe a clever sequence
18- // could be better
19- typealias Docs = [ ( Int , Doc ) ]
24+ // could be better. Also, perhaps not using the enum-list will speed
25+ // things up more.
26+ typealias Docs = List < ( Int , Doc ) >
2027
2128extension Doc {
2229 func renderPrettyDefault( ) -> SimpleDoc {
@@ -40,9 +47,10 @@ extension Doc {
4047 z: ( IndentLevel , ColumnCount ) -> SimpleDoc ,
4148 indentationDocs: Docs
4249 ) -> SimpleDoc {
43- if let head = indentationDocs. first {
50+ switch indentationDocs {
51+ case . Nil: return z ( currNesting, currColumn)
52+ case let . Cons( head, rest) :
4453 let ( indent, doc) = head
45- let rest = Array ( indentationDocs. dropFirst ( ) )
4654
4755 switch doc {
4856 case . empty:
@@ -56,41 +64,40 @@ extension Doc {
5664 case . _line:
5765 return SimpleDoc . line ( indent: indent, best ( currNesting: indent, currColumn: indent, z: z, indentationDocs: rest) )
5866 case let . flatAlt( primary, whenFlattened: _) :
59- return best ( currNesting: currNesting, currColumn: currColumn, z: z, indentationDocs: [ ( indent, primary) ] + rest)
67+ return best ( currNesting: currNesting, currColumn: currColumn, z: z, indentationDocs: . Cons ( ( indent, primary) , rest) )
6068 case let . concat( d1, d2) :
61- return best ( currNesting: currNesting, currColumn: currColumn, z: z, indentationDocs: [ ( indent, d1) , ( indent, d2) ] + rest)
69+ return best ( currNesting: currNesting, currColumn: currColumn, z: z, indentationDocs: . Cons ( ( indent, d1) , . Cons ( ( indent, d2) , rest) ) )
6270 case let . nest( indent_, d) :
6371 let newIndent = indent + indent_
64- return best ( currNesting: currNesting, currColumn: currColumn, z: z, indentationDocs: [ ( newIndent, d) ] + rest)
72+ return best ( currNesting: currNesting, currColumn: currColumn, z: z, indentationDocs: . Cons ( ( newIndent, d) , rest) )
6573 case let . union( longerLines, shorterLines) :
6674 return compareStrategy (
6775 currNesting,
6876 currColumn,
6977 pageWidth,
7078 ribbonChars
7179 ) (
72- best ( currNesting: currNesting, currColumn: currColumn, z: z, indentationDocs: [ ( indent, longerLines) ] + rest) ,
73- best ( currNesting: currNesting, currColumn: currColumn, z: z, indentationDocs: [ ( indent, shorterLines) ] + rest)
80+ best ( currNesting: currNesting, currColumn: currColumn, z: z, indentationDocs: . Cons( ( indent, longerLines) , rest) ) ,
81+ /// Laziness is needed here to prevent horrible performance!
82+ { ( ) in best ( currNesting: currNesting, currColumn: currColumn, z: z, indentationDocs: . Cons( ( indent, shorterLines) , rest) ) }
7483 )
7584 case let . column( f) :
76- return best ( currNesting: currNesting, currColumn: currColumn, z: z, indentationDocs: [ ( indent, f ( currColumn) ) ] + rest)
85+ return best ( currNesting: currNesting, currColumn: currColumn, z: z, indentationDocs: . Cons ( ( indent, f ( currColumn) ) , rest) )
7786 case let . nesting( f) :
78- return best ( currNesting: currNesting, currColumn: currColumn, z: z, indentationDocs: [ ( indent, f ( indent) ) ] + rest)
87+ return best ( currNesting: currNesting, currColumn: currColumn, z: z, indentationDocs: . Cons ( ( indent, f ( indent) ) , rest) )
7988 case let . columns( f) :
80- return best ( currNesting: currNesting, currColumn: currColumn, z: z, indentationDocs: [ ( indent, f ( . some( pageWidth) ) ) ] + rest)
89+ return best ( currNesting: currNesting, currColumn: currColumn, z: z, indentationDocs: . Cons ( ( indent, f ( . some( pageWidth) ) ) , rest) )
8190 case let . ribbon( f) :
82- return best ( currNesting: currNesting, currColumn: currColumn, z: z, indentationDocs: [ ( indent, f ( . some( ribbonChars) ) ) ] + rest)
91+ return best ( currNesting: currNesting, currColumn: currColumn, z: z, indentationDocs: . Cons ( ( indent, f ( . some( ribbonChars) ) ) , rest) )
8392 }
84- } else {
85- return z ( currNesting, currColumn)
8693 }
8794 }
8895
89- return best ( currNesting: 0 , currColumn: 0 , z: { _, _ in SimpleDoc . empty } , indentationDocs: [ ( 0 , self ) ] )
96+ return best ( currNesting: 0 , currColumn: 0 , z: { _, _ in SimpleDoc . empty } , indentationDocs: . Cons ( ( 0 , self ) , . Nil ) )
9097 }
9198
9299 /// Compares the first two lines of the documents
93- static func nicest1( nesting: IndentLevel , column: ColumnCount , pageWidth: Width , ribbonWidth: RibbonWidth ) -> ( SimpleDoc , SimpleDoc ) -> SimpleDoc {
100+ static func nicest1( nesting: IndentLevel , column: ColumnCount , pageWidth: Width , ribbonWidth: RibbonWidth ) -> ( SimpleDoc , ( ) -> SimpleDoc ) -> SimpleDoc {
94101 return { d1, d2 in
95102 let wid = min ( pageWidth - column, ribbonWidth - column + nesting)
96103
@@ -109,7 +116,7 @@ extension Doc {
109116 if fits ( prefix: min ( nesting, column) , w: wid, doc: d1) {
110117 return d1
111118 } else {
112- return d2
119+ return d2 ( )
113120 }
114121 }
115122 }
0 commit comments