strings: run v fmt (#7438)

pull/7460/head
zakuro 2020-12-22 05:00:32 +09:00 committed by GitHub
parent fade162471
commit 6c341a77f5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 55 additions and 49 deletions

View File

@ -58,6 +58,8 @@ const (
'vlib/v/vmod/', 'vlib/v/vmod/',
'vlib/gg/gg.v', 'vlib/gg/gg.v',
'vlib/os/', 'vlib/os/',
'vlib/semver/',
'vlib/strings/',
'vlib/time/', 'vlib/time/',
'vlib/builtin/array_test.v', 'vlib/builtin/array_test.v',
] ]

View File

@ -1,19 +1,18 @@
// Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved. // Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license // Use of this source code is governed by an MIT license
// that can be found in the LICENSE file. // that can be found in the LICENSE file.
module strings module strings
pub struct Builder { pub struct Builder {
mut: mut:
buf []byte buf []byte
pub mut: pub mut:
len int len int
initial_size int = 1 initial_size int = 1
} }
pub fn new_builder(initial_size int) Builder { pub fn new_builder(initial_size int) Builder {
return Builder { return Builder{
buf: make(0, initial_size, sizeof(byte)) buf: make(0, initial_size, sizeof(byte))
initial_size: initial_size initial_size: initial_size
} }
@ -26,19 +25,19 @@ pub fn (mut b Builder) write_b(data byte) {
pub fn (mut b Builder) write(s string) { pub fn (mut b Builder) write(s string) {
b.buf.push_many(s.str, s.len) b.buf.push_many(s.str, s.len)
//b.buf << []byte(s) // TODO // b.buf << []byte(s) // TODO
b.len += s.len b.len += s.len
} }
pub fn (mut b Builder) writeln(s string) { pub fn (mut b Builder) writeln(s string) {
b.buf.push_many(s.str, s.len) b.buf.push_many(s.str, s.len)
//b.buf << []byte(s) // TODO // b.buf << []byte(s) // TODO
b.buf << `\n` b.buf << `\n`
b.len += s.len + 1 b.len += s.len + 1
} }
pub fn (b Builder) str() string { pub fn (b Builder) str() string {
return unsafe { byteptr(b.buf.data).vstring_with_len(b.len) } return unsafe {byteptr(b.buf.data).vstring_with_len(b.len)}
} }
pub fn (mut b Builder) cut(n int) { pub fn (mut b Builder) cut(n int) {

View File

@ -3,8 +3,11 @@
// that can be found in the LICENSE file. // that can be found in the LICENSE file.
module strings module strings
// strings.Builder is used to efficiently append many strings to a large
// dynamically growing buffer, then use the resulting large string. Using
// a string builder is much better for performance/memory usage than doing
// constantly string concatenation.
pub struct Builder { pub struct Builder {
// TODO
pub mut: pub mut:
buf []byte buf []byte
str_calls int str_calls int
@ -12,9 +15,10 @@ pub mut:
initial_size int = 1 initial_size int = 1
} }
// 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 {
return Builder{ return Builder{
//buf: make(0, initial_size) // buf: make(0, initial_size)
buf: []byte{cap: initial_size} buf: []byte{cap: initial_size}
str_calls: 0 str_calls: 0
len: 0 len: 0
@ -22,16 +26,19 @@ pub fn new_builder(initial_size int) Builder {
} }
} }
// write_bytes appends `bytes` to the accumulated buffer
pub fn (mut b Builder) write_bytes(bytes byteptr, howmany int) { pub fn (mut b Builder) write_bytes(bytes byteptr, howmany int) {
b.buf.push_many(bytes, howmany) b.buf.push_many(bytes, howmany)
b.len += howmany b.len += howmany
} }
// write_b appends a single `data` byte to the accumulated buffer
pub fn (mut b Builder) write_b(data byte) { pub fn (mut b Builder) write_b(data byte) {
b.buf << data b.buf << data
b.len++ b.len++
} }
// write appends the string `s` to the buffer
[inline] [inline]
pub fn (mut b Builder) write(s string) { pub fn (mut b Builder) write(s string) {
if s == '' { if s == '' {
@ -45,21 +52,23 @@ pub fn (mut b Builder) write(s string) {
b.len += s.len b.len += s.len
} }
// go_back discards the last `n` bytes from the buffer
pub fn (mut b Builder) go_back(n int) { pub fn (mut b Builder) go_back(n int) {
b.buf.trim(b.buf.len-n) b.buf.trim(b.buf.len - n)
b.len -= n b.len -= n
} }
fn bytes2string(b []byte) string { fn bytes2string(b []byte) string {
mut copy := b.clone() mut copy := b.clone()
copy << byte(`\0`) copy << byte(`\0`)
res := tos(copy.data, copy.len-1) res := tos(copy.data, copy.len - 1)
return res return res
} }
// cut_last cuts the last `n` bytes from the buffer and returns them
pub fn (mut b Builder) cut_last(n int) string { pub fn (mut b Builder) cut_last(n int) string {
res := bytes2string( b.buf[b.len-n..] ) res := bytes2string(b.buf[b.len - n..])
b.buf.trim(b.buf.len-n) b.buf.trim(b.buf.len - n)
b.len -= n b.len -= n
return res return res
} }
@ -72,12 +81,14 @@ pub fn (mut b Builder) cut_to(pos int) string {
return res return res
} }
*/ */
// go_back_to resets the buffer to the given position `pos`
// NB: pos should be < than the existing buffer length.
pub fn (mut b Builder) go_back_to(pos int) { pub fn (mut b Builder) go_back_to(pos int) {
b.buf.trim(pos) b.buf.trim(pos)
b.len = pos b.len = pos
} }
// 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 { // for c in s {
@ -95,7 +106,7 @@ pub fn (b &Builder) last_n(n int) string {
if n > b.len { if n > b.len {
return '' return ''
} }
return bytes2string( b.buf[b.len-n..] ) return bytes2string(b.buf[b.len - n..])
} }
// buf == 'hello world' // buf == 'hello world'
@ -104,31 +115,30 @@ pub fn (b &Builder) after(n int) string {
if n >= b.len { if n >= b.len {
return '' return ''
} }
return bytes2string( b.buf[n..] ) return bytes2string(b.buf[n..])
} }
// str returns all of the accumulated content of the buffer.
// NB: in order to avoid memleaks and additional memory copies, after a call to b.str(), // NB: in order to avoid memleaks and additional memory copies, after a call to b.str(),
// the builder b will be empty. The returned string *owns* the accumulated data so far. // the builder b will be empty. The returned string *owns* the accumulated data so far.
pub fn (mut b Builder) str() string { pub fn (mut b Builder) str() string {
b.str_calls++ b.str_calls++
if b.str_calls > 1 { if b.str_calls > 1 {
panic('builder.str() should be called just once.\n' + panic('builder.str() should be called just once.\nIf you want to reuse a builder, call b.free() first.')
'If you want to reuse a builder, call b.free() first.')
} }
b.buf << `\0` b.buf << `\0`
s := tos(b.buf.data, b.len) s := tos(b.buf.data, b.len)
bis := b.initial_size bis := b.initial_size
//free(b.buf.data) // free(b.buf.data)
b.buf = []byte{cap: bis} b.buf = []byte{cap: bis}
b.len = 0 b.len = 0
return s return s
} }
// manually free the contents of the buffer
pub fn (mut b Builder) free() { pub fn (mut b Builder) free() {
unsafe{ unsafe {free(b.buf.data)}
free(b.buf.data) // b.buf = []byte{cap: b.initial_size}
}
//b.buf = []byte{cap: b.initial_size}
b.len = 0 b.len = 0
b.str_calls = 0 b.str_calls = 0
} }

View File

@ -23,14 +23,13 @@ fn test_sb() {
y := MyInt(20) y := MyInt(20)
sb.writeln('x = $x y = $y') sb.writeln('x = $x y = $y')
res := sb.str() res := sb.str()
assert res[res.len-1] == `\n` assert res[res.len - 1] == `\n`
println('"$res"') println('"$res"')
assert res.trim_space() == 'x = 10 y = 20' assert res.trim_space() == 'x = 10 y = 20'
// //
sb = strings.new_builder(10) sb = strings.new_builder(10)
sb.write('x = $x y = $y') sb.write('x = $x y = $y')
assert sb.str() == 'x = 10 y = 20' assert sb.str() == 'x = 10 y = 20'
$if !windows { $if !windows {
// TODO msvc bug // TODO msvc bug
sb = strings.new_builder(10) sb = strings.new_builder(10)
@ -49,7 +48,7 @@ const (
fn test_big_sb() { fn test_big_sb() {
mut sb := strings.new_builder(100) mut sb := strings.new_builder(100)
mut sb2 := strings.new_builder(10000) mut sb2 := strings.new_builder(10000)
for i in 0..maxn { for i in 0 .. maxn {
sb.writeln(i.str()) sb.writeln(i.str())
sb2.write('+') sb2.write('+')
} }
@ -62,12 +61,11 @@ fn test_big_sb() {
assert lines[98765] == '98765' assert lines[98765] == '98765'
println(sb2.len) println(sb2.len)
assert sb2.len == maxn assert sb2.len == maxn
} }
fn test_byte_write() { fn test_byte_write() {
mut sb := strings.new_builder(100) mut sb := strings.new_builder(100)
temp_str := "byte testing" temp_str := 'byte testing'
mut count := 0 mut count := 0
for word in temp_str { for word in temp_str {
sb.write_b(word) sb.write_b(word)

View File

@ -1,10 +1,11 @@
module strings module strings
// #-js // #-js
// use levenshtein distance algorithm to calculate // use levenshtein distance algorithm to calculate
// the distance between between two strings (lower is closer) // the distance between between two strings (lower is closer)
pub fn levenshtein_distance(a string, b string) int { pub fn levenshtein_distance(a string, b string) int {
mut f := [0].repeat(b.len + 1) mut f := [0].repeat(b.len + 1)
for j in 0..f.len { for j in 0 .. f.len {
f[j] = j f[j] = j
} }
for ca in a { for ca in a {
@ -15,8 +16,7 @@ pub fn levenshtein_distance(a string, b string) int {
mut mn := if f[j] + 1 <= f[j - 1] + 1 { f[j] + 1 } else { f[j - 1] + 1 } mut mn := if f[j] + 1 <= f[j - 1] + 1 { f[j] + 1 } else { f[j - 1] + 1 }
if cb != ca { if cb != ca {
mn = if mn <= fj1 + 1 { mn } else { fj1 + 1 } mn = if mn <= fj1 + 1 { mn } else { fj1 + 1 }
} } else {
else {
mn = if mn <= fj1 { mn } else { fj1 } mn = if mn <= fj1 { mn } else { fj1 }
} }
fj1 = f[j] fj1 = f[j]
@ -50,14 +50,14 @@ pub fn dice_coefficient(s1 string, s2 string) f32 {
} }
a := if s1.len > s2.len { s1 } else { s2 } a := if s1.len > s2.len { s1 } else { s2 }
b := if a == s1 { s2 } else { s1 } b := if a == s1 { s2 } else { s1 }
mut first_bigrams := map[string]int mut first_bigrams := map[string]int{}
for i in 0..a.len - 1 { for i in 0 .. a.len - 1 {
bigram := a[i..i + 2] bigram := a[i..i + 2]
q := if bigram in first_bigrams { first_bigrams[bigram] + 1 } else { 1 } q := if bigram in first_bigrams { first_bigrams[bigram] + 1 } else { 1 }
first_bigrams[bigram] = q first_bigrams[bigram] = q
} }
mut intersection_size := 0 mut intersection_size := 0
for i in 0..b.len - 1 { for i in 0 .. b.len - 1 {
bigram := b[i..i + 2] bigram := b[i..i + 2]
count := if bigram in first_bigrams { first_bigrams[bigram] } else { 0 } count := if bigram in first_bigrams { first_bigrams[bigram] } else { 0 }
if count > 0 { if count > 0 {
@ -67,4 +67,3 @@ pub fn dice_coefficient(s1 string, s2 string) f32 {
} }
return (2.0 * f32(intersection_size)) / (f32(a.len) + f32(b.len) - 2) return (2.0 * f32(intersection_size)) / (f32(a.len) + f32(b.len) - 2)
} }

View File

@ -7,10 +7,10 @@ pub fn repeat(c byte, n int) string {
} }
mut bytes := unsafe {malloc(n + 1)} mut bytes := unsafe {malloc(n + 1)}
unsafe { unsafe {
C.memset( bytes, c, n ) C.memset(bytes, c, n)
bytes[n] = `0` bytes[n] = `0`
} }
return unsafe { bytes.vstring_with_len(n) } return unsafe {bytes.vstring_with_len(n)}
} }
// strings.repeat_string - gives you `n` repetitions of the substring `s` // strings.repeat_string - gives you `n` repetitions of the substring `s`
@ -21,18 +21,18 @@ pub fn repeat_string(s string, n int) string {
return '' return ''
} }
slen := s.len slen := s.len
blen := slen*n blen := slen * n
mut bytes := unsafe {malloc(blen + 1)} mut bytes := unsafe {malloc(blen + 1)}
for bi in 0..n { for bi in 0 .. n {
bislen := bi*slen bislen := bi * slen
for si in 0..slen { for si in 0 .. slen {
unsafe { unsafe {
bytes[bislen+si] = s[si] bytes[bislen + si] = s[si]
} }
} }
} }
unsafe { unsafe {
bytes[blen] = `0` bytes[blen] = `0`
} }
return unsafe { bytes.vstring_with_len(blen) } return unsafe {bytes.vstring_with_len(blen)}
} }

View File

@ -9,9 +9,9 @@ pub fn repeat(c byte, n int) string {
} }
pub fn repeat_string(s string, n int) string { pub fn repeat_string(s string, n int) string {
/* /*
// TODO: uncomment this. It is commented for now, so that `v doc strings` works // TODO: uncomment this. It is commented for now, so that `v doc strings` works
res := # s.repeat(n) res := # s.repeat(n)
return res return res
*/ */
} }

View File

@ -1,7 +1,6 @@
module strings module strings
//import rand // import rand
// random returns a random string with `n` characters // random returns a random string with `n` characters
/* /*
pub fn random(n int) string { pub fn random(n int) string {
@ -12,4 +11,3 @@ pub fn random(n int) string {
return tos(buf) return tos(buf)
} }
*/ */