@@ -3,60 +3,58 @@ module stringbuffer
33import effekt
44import bytearray
55
6- interface StringBuffer {
7- def write(str: String): Unit
8- def flush() : String
9- }
6+ effect flush(): String
7+
8+ def stringBuffer { program: () => Unit / write } : String =
9+ flushableStringBuffer { program(); do flush() }
1010
11- def stringBuffer [A] { prog: => A / StringBuffer }: A = {
11+ def flushableStringBuffer [A] { program: () => A / { write, flush } }: A = {
1212 val initialCapacity = 128
1313 var buffer = bytearray::allocate(initialCapacity)
1414 // next free index to write to
15- var pos = 0
15+ var position = 0
1616
17- def ensureCapacity(sizeToAdd : Int): Unit = {
18- val cap = buffer.size - pos
19- if (sizeToAdd <= cap ) ()
17+ def ensureCapacity(required : Int): Unit = {
18+ val capacity = buffer.size - position
19+ if (required <= capacity ) ()
2020 else {
2121 // Double the capacity while ensuring the required capacity
22- val newSize = max(buffer.size * 2, buffer.size + sizeToAdd )
22+ val newSize = max(buffer.size * 2, buffer.size + required )
2323 buffer = buffer.resize(newSize)
2424 }
2525 }
2626
27- try { prog() }
28- with StringBuffer {
29- def write(str) = {
30- val bytes = fromString(str)
31- ensureCapacity(bytes.size)
32- bytes.foreach { b =>
33- buffer.set(pos, b)
34- pos = pos + 1
35- }
36- resume(())
37- }
38- def flush() = {
39- // resize (& copy) buffer to strip trailing zeros that otherwise would be converted into 0x00 characters
40- val str = bytearray::resize(buffer, pos).toString()
41- // NOTE: Keep the `buffer` as-is (no wipe, no realloc),
42- // just reset the `pos` in case we want to use it again.
43- pos = 0
44- resume(str)
27+ try {
28+ program()
29+ } with write { string =>
30+ val bytes = fromString(string)
31+ ensureCapacity(bytes.size)
32+ bytes.foreach { b =>
33+ buffer.set(position, b)
34+ position = position + 1
4535 }
36+ resume(())
37+ } with flush {
38+ val string = buffer.resize(position).toString()
39+ position = 0
40+ resume(string)
4641 }
4742}
4843
44+ def splicing[T] { writer: T => Unit } { program: () => Unit / splice[T] }: Unit =
45+ try { program() } with splice[T] { t => resume(writer(t)) }
46+
47+
4948/// Handler for string interpolation using a string buffer
50- def s { prog : () => Unit / { literal , splice[String] } }: String =
49+ def s { program : () => Unit / { write , splice[String] } }: String =
5150 stringBuffer {
52- try { prog(); do flush () }
51+ try { program () }
5352 with splice[String] { x => resume(do write(x)) }
54- with literal { s => resume(do write(s)) }
5553 }
5654
5755namespace examples {
5856 def main() = {
59- with stringBuffer
57+ with flushableStringBuffer
6058
6159 do write("hello")
6260 do write(", world")
0 commit comments