7 signature BUFFER = |
7 signature BUFFER = |
8 sig |
8 sig |
9 type T |
9 type T |
10 val empty: T |
10 val empty: T |
11 val is_empty: T -> bool |
11 val is_empty: T -> bool |
12 val chunks: T -> string list |
|
13 val content: T -> string |
12 val content: T -> string |
14 val add: string -> T -> T |
13 val add: string -> T -> T |
|
14 val output: T -> (string -> unit) -> unit |
15 val markup: Markup.T -> (T -> T) -> T -> T |
15 val markup: Markup.T -> (T -> T) -> T -> T |
16 val output: T -> BinIO.outstream -> unit |
|
17 end; |
16 end; |
18 |
17 |
19 structure Buffer: BUFFER = |
18 structure Buffer: BUFFER = |
20 struct |
19 struct |
21 |
20 |
22 abstype T = Buffer of {chunk_size: int, chunk: string list, buffer: string list} |
21 abstype T = Buffer of string list |
23 with |
22 with |
24 |
23 |
25 val empty = Buffer {chunk_size = 0, chunk = [], buffer = []}; |
24 val empty = Buffer []; |
26 |
25 |
27 fun is_empty (Buffer {chunk, buffer, ...}) = null chunk andalso null buffer; |
26 fun is_empty (Buffer xs) = null xs; |
28 |
27 |
29 local |
28 fun add "" buf = buf |
30 val chunk_limit = 4096; |
29 | add x (Buffer xs) = Buffer (x :: xs); |
31 |
30 |
32 fun add_chunk [] buffer = buffer |
31 fun content (Buffer xs) = implode (rev xs); |
33 | add_chunk chunk buffer = implode (rev chunk) :: buffer; |
|
34 in |
|
35 |
32 |
36 fun chunks (Buffer {chunk, buffer, ...}) = rev (add_chunk chunk buffer); |
33 fun output (Buffer xs) out = List.app out (rev xs); |
37 |
|
38 val content = implode o chunks; |
|
39 |
|
40 fun add x (buf as Buffer {chunk_size, chunk, buffer}) = |
|
41 let val n = size x in |
|
42 if n = 0 then buf |
|
43 else if n + chunk_size < chunk_limit then |
|
44 Buffer {chunk_size = n + chunk_size, chunk = x :: chunk, buffer = buffer} |
|
45 else |
|
46 Buffer {chunk_size = 0, chunk = [], |
|
47 buffer = |
|
48 if n < chunk_limit |
|
49 then add_chunk (x :: chunk) buffer |
|
50 else x :: add_chunk chunk buffer} |
|
51 end; |
|
52 |
|
53 end; |
|
54 |
34 |
55 end; |
35 end; |
56 |
36 |
57 fun markup m body = |
37 fun markup m body = |
58 let val (bg, en) = Markup.output m |
38 let val (bg, en) = Markup.output m |
59 in add bg #> body #> add en end; |
39 in add bg #> body #> add en end; |
60 |
40 |
61 fun output buf stream = |
|
62 List.app (fn s => BinIO.output (stream, Byte.stringToBytes s)) (chunks buf); |
|
63 |
|
64 end; |
41 end; |