strings: reduce time spent in Builder.writeln (very frequently called)

master
Delyan Angelov 2022-05-07 10:37:25 +03:00
parent 7ecd65221e
commit b53b1cc7cb
No known key found for this signature in database
GPG Key ID: 66886C0F12D595ED
1 changed files with 16 additions and 18 deletions

View File

@ -12,7 +12,9 @@ pub type Builder = []u8
// new_builder returns a new string builder, with an initial capacity of `initial_size` // new_builder returns a new string builder, with an initial capacity of `initial_size`
pub fn new_builder(initial_size int) Builder { pub fn new_builder(initial_size int) Builder {
mut res := Builder([]u8{cap: initial_size}) mut res := Builder([]u8{cap: initial_size})
unsafe { res.flags.set(.noslices) } unsafe {
res.flags = .noslices
}
return res return res
} }
@ -87,7 +89,7 @@ pub fn (mut b Builder) drain_builder(mut other Builder, other_new_cap int) {
// Note: it can panic, if there are not enough bytes in the strings builder yet. // Note: it can panic, if there are not enough bytes in the strings builder yet.
[inline] [inline]
pub fn (b &Builder) byte_at(n int) u8 { pub fn (b &Builder) byte_at(n int) u8 {
return unsafe { (&[]u8(b))[n] } return unsafe { &u8(b.data)[n] }
} }
// write appends the string `s` to the buffer // write appends the string `s` to the buffer
@ -145,14 +147,15 @@ pub fn (mut b Builder) go_back_to(pos int) {
// writeln appends the string `s`, and then a newline character. // writeln appends the string `s`, and then a newline character.
[inline] [inline]
pub fn (mut b Builder) writeln(s string) { pub fn (mut b Builder) writeln(s string) {
// for c in s { new_len := b.len + s.len + 1
// b.buf << c b.ensure_cap(new_len)
// } unsafe {
&u8(b.data)[new_len - 1] = u8(`\n`)
if s.len > 0 { if s.len > 0 {
unsafe { b.push_many(s.str, s.len) } vmemcpy(&u8(b.data) + b.len, s.str, s.len)
}
b.len = new_len
} }
// b.buf << []u8(s) // TODO
b << u8(`\n`)
} }
// last_n(5) returns 'world' // last_n(5) returns 'world'
@ -190,19 +193,14 @@ pub fn (mut b Builder) str() string {
// ensure_cap ensures that the buffer has enough space for at least `n` bytes by growing the buffer if necessary // ensure_cap ensures that the buffer has enough space for at least `n` bytes by growing the buffer if necessary
pub fn (mut b Builder) ensure_cap(n int) { pub fn (mut b Builder) ensure_cap(n int) {
// code adapted from vlib/builtin/array.v
if n <= b.cap { if n <= b.cap {
return return
} }
new_data := unsafe { malloc(u64(n) * u64(b.element_size)) }
new_data := vcalloc(n * b.element_size) if b.data != 0 {
if b.data != voidptr(0) { unsafe { vmemcpy(new_data, b.data, b.len) }
unsafe { vmemcpy(new_data, b.data, b.len * b.element_size) }
// TODO: the old data may be leaked when no GC is used (ref-counting?)
if b.flags.has(.noslices) {
unsafe { free(b.data) } unsafe { free(b.data) }
} }
}
unsafe { unsafe {
b.data = new_data b.data = new_data
b.offset = 0 b.offset = 0