Skip to content

Commit

Permalink
x/stringutil
Browse files Browse the repository at this point in the history
  • Loading branch information
xushiwei committed Feb 25, 2024
1 parent be916da commit 26bfa43
Show file tree
Hide file tree
Showing 6 changed files with 238 additions and 0 deletions.
48 changes: 48 additions & 0 deletions stringutil/build.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
Copyright 2024 Qiniu Limited (qiniu.com)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package stringutil

// -----------------------------------------------------------------------------

// Builder concatenates parts of a string together.
type Builder struct {
b []byte
}

// NewBuilder creates a new Builder object.
func NewBuilder(ncap int) *Builder {
return &Builder{b: make([]byte, 0, ncap)}
}

// Add appends a string part.
func (p *Builder) Add(s string) *Builder {
p.b = append(p.b, s...)
return p
}

// AddByte appends a bytes string part.
func (p *Builder) AddByte(s ...byte) *Builder {
p.b = append(p.b, s...)
return p
}

// Build concatenates parts of a string together and returns it.
func (p *Builder) Build() string {
return String(p.b)
}

// -----------------------------------------------------------------------------
30 changes: 30 additions & 0 deletions stringutil/concat.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
Copyright 2024 Qiniu Limited (qiniu.com)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package stringutil

// Concat concatenates parts of a string together.
func Concat(parts ...string) string {
n := 0
for _, part := range parts {
n += len(part)
}
b := make([]byte, 0, n)
for _, part := range parts {
b = append(b, part...)
}
return String(b)
}
40 changes: 40 additions & 0 deletions stringutil/diff.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
Copyright 2024 Qiniu Limited (qiniu.com)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package stringutil

// Diff calculates difference of two sorted string (in ASC order).
func Diff(new, old []string) (add, del []string) {
i, j := 0, 0
for i != len(new) && j != len(old) {
if new[i] < old[j] {
add = append(add, new[i])
i++
} else if old[j] < new[i] {
del = append(del, old[j])
j++
} else {
i++
j++
}
}
if i < len(new) {
add = append(add, new[i:]...)
} else {
del = append(del, old[j:]...)
}
return
}
34 changes: 34 additions & 0 deletions stringutil/string_go121.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//go:build go1.21
// +build go1.21

/*
Copyright 2024 Qiniu Limited (qiniu.com)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package stringutil

import (
"unsafe"
)

// String returns a string value whose underlying bytes is b.
//
// Since Go strings are immutable, the bytes passed to String
// must not be modified afterwards.
func String(b []byte) string {
// Although unsafe.SliceData/String was introduced in go1.20, but
// the go version in go.mod is 1.18 so we cannot use them.
return unsafe.String(unsafe.SliceData(b), len(b))
}
24 changes: 24 additions & 0 deletions stringutil/string_mock.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//go:build !go1.21
// +build !go1.21

/*
Copyright 2024 Qiniu Limited (qiniu.com)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package stringutil

func String(b []byte) string {
return string(b)
}
62 changes: 62 additions & 0 deletions stringutil/string_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
Copyright 2024 Qiniu Limited (qiniu.com)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package stringutil

import (
"reflect"
"sort"
"testing"
)

func TestConcat(t *testing.T) {
if ret := Concat("1", "23", "!"); ret != "123!" {
t.Fatal("Concat:", ret)
}
}

func TestBuild(t *testing.T) {
if ret := NewBuilder(0).Build(); ret != "" {
t.Fatal("NewBuilder(0):", ret)
}
if ret := NewBuilder(16).Add("1").AddByte('2', '3').AddByte('!').Build(); ret != "123!" {
t.Fatal("TestBuild:", ret)
}
}

func TestDiff(t *testing.T) {
type testCase struct {
new, old []string
add, del []string
}
cases := []testCase{
{[]string{"1", "3", "2", "4"}, []string{"2"}, []string{"1", "3", "4"}, nil},
{[]string{"1", "3", "2", "4"}, []string{"5", "2"}, []string{"1", "3", "4"}, []string{"5"}},
{[]string{"1", "3", "2", "4"}, []string{"0", "5", "2"}, []string{"1", "3", "4"}, []string{"0", "5"}},
}
for _, c := range cases {
add, del := uDiff(c.new, c.old)
if !reflect.DeepEqual(add, c.add) || !reflect.DeepEqual(del, c.del) {
t.Fatal("diff:", c, "=>", add, del)
}
}
}

func uDiff(new, old []string) (add, del []string) {
sort.Strings(new)
sort.Strings(old)
return Diff(new, old)
}

0 comments on commit 26bfa43

Please sign in to comment.