///|
struct Buffer {
mut buf : FixedArray[UInt16]
mut len : Int
}
///|
pub fn buffer(capacity? : Int = 0) -> Buffer {
Buffer::new(capacity~)
}
///|
pub fn Buffer::new(capacity? : Int = 0) -> Buffer {
let cap = if capacity < 0 { 0 } else { capacity }
Buffer::{ buf: FixedArray::make(cap, 0), len: 0 }
}
///|
pub impl Default for Buffer with default() -> Buffer {
Buffer::new()
}
///|
pub fn Buffer::length(self : Buffer) -> Int {
self.len
}
///|
pub fn Buffer::capacity(self : Buffer) -> Int {
self.buf.length()
}
///|
fn Buffer::grow(self : Buffer, by~ : Int) -> Unit {
let new_len = self.len + by
let mut cap = self.buf.length()
if new_len <= cap {
return
}
if cap == 0 {
cap = 8
}
while new_len > cap {
cap *= 2
}
let new_buf : FixedArray[UInt16] = FixedArray::make(cap, 0)
new_buf.unsafe_blit(0, self.buf, 0, self.len)
self.buf = new_buf
}
///|
pub fn Buffer::write_codeunit(self : Buffer, value : UInt16) -> Unit {
self.grow(by=1)
self.buf.unsafe_set(self.len, value)
self.len += 1
}
///|
pub fn Buffer::write_codepoint(self : Buffer, value : @codepoint.CodePoint) -> Unit {
let value = value.to_int()
self.grow(by=2)
match value {
0x0000..=0xFFFF => {
self.buf.unsafe_set(self.len, value.to_uint16())
self.len += 1
}
0x10000..=0x10FFFF => {
let v = value - 0x10000
let high = 0xD800 + ((v >> 10) & 0x3FF)
let low = 0xDC00 + (v & 0x3FF)
self.buf.unsafe_set(self.len, high.to_uint16())
self.buf.unsafe_set(self.len + 1, low.to_uint16())
self.len += 2
}
_ => abort("Code point out of range")
}
}
///|
pub fn Buffer::write_char(self : Buffer, value : Char) -> Unit {
match value {
'\u{0000}'..='\u{FFFF}' => {
self.grow(by=1)
self.buf.unsafe_set(self.len, value.to_int().to_uint16())
self.len += 1
}
'\u{10000}'..='\u{10FFFF}' => {
let v = value.to_int() - 0x10000
let high = 0xD800 + ((v >> 10) & 0x3FF)
let low = 0xDC00 + (v & 0x3FF)
self.grow(by=2)
self.buf.unsafe_set(self.len, high.to_uint16())
self.buf.unsafe_set(self.len + 1, low.to_uint16())
self.len += 2
}
}
}
///|
pub fn Buffer::write_string(self : Buffer, value : String) -> Unit {
let len = value.length()
self.grow(by=len)
for i in 0.. Wtf16 {
let len = self.len
let buf : FixedArray[UInt16] = FixedArray::make(len, 0)
buf.unsafe_blit(0, self.buf, 0, len)
Wtf16(buf)
}