Исходники и презентации
This commit is contained in:
BIN
lessons/strings/.DS_Store
vendored
Normal file
BIN
lessons/strings/.DS_Store
vendored
Normal file
Binary file not shown.
30
lessons/strings/allocations/main.go
Normal file
30
lessons/strings/allocations/main.go
Normal file
@ -0,0 +1,30 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var result string
|
||||
|
||||
func Concat(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
result = "Hello" + " world"
|
||||
}
|
||||
}
|
||||
|
||||
func Conversion(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
result = string([]byte("Hello world"))
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
b1 := testing.Benchmark(Concat)
|
||||
fmt.Println("b1:", b1.AllocsPerOp()) // 0
|
||||
fmt.Println("b1:", b1.AllocedBytesPerOp()) // 0
|
||||
|
||||
b2 := testing.Benchmark(Conversion)
|
||||
fmt.Println("b2:", b2.AllocsPerOp()) // 1
|
||||
fmt.Println("b2:", b2.AllocedBytesPerOp()) // 16
|
||||
}
|
||||
17
lessons/strings/append_and_copy/main.go
Normal file
17
lessons/strings/append_and_copy/main.go
Normal file
@ -0,0 +1,17 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
hello := []byte("Hello ")
|
||||
world := "world!"
|
||||
|
||||
helloWorld1 := append(hello, world...) // sugar
|
||||
fmt.Println(string(helloWorld1))
|
||||
|
||||
helloWorld2 := make([]byte, len(hello)+len(world))
|
||||
copy(helloWorld2, hello)
|
||||
|
||||
copy(helloWorld2[len(hello):], world) // sugar
|
||||
fmt.Println(string(helloWorld2))
|
||||
}
|
||||
39
lessons/strings/bce_optimization/bench_test.go
Normal file
39
lessons/strings/bce_optimization/bench_test.go
Normal file
@ -0,0 +1,39 @@
|
||||
package main
|
||||
|
||||
import "testing"
|
||||
|
||||
// go test -gcflags="-d=ssa/check_bce" -bench=. bench_test.go
|
||||
|
||||
func process1(data string) []byte {
|
||||
return []byte{
|
||||
data[0], // Found IsInBounds
|
||||
data[1], // Found IsInBounds
|
||||
data[2], // Found IsInBounds
|
||||
data[3], // Found IsInBounds
|
||||
}
|
||||
}
|
||||
|
||||
func process2(data string) []byte {
|
||||
return []byte{
|
||||
data[3], // Found IsInBounds
|
||||
data[2],
|
||||
data[1],
|
||||
data[0],
|
||||
}
|
||||
}
|
||||
|
||||
var Result []byte
|
||||
|
||||
func BenchmarkProcess1(b *testing.B) {
|
||||
data := "Hello world"
|
||||
for i := 0; i < b.N; i++ {
|
||||
Result = process1(data)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkProcess2(b *testing.B) {
|
||||
data := "Hello world"
|
||||
for i := 0; i < b.N; i++ {
|
||||
Result = process2(data)
|
||||
}
|
||||
}
|
||||
12
lessons/strings/byte_address/main.go
Normal file
12
lessons/strings/byte_address/main.go
Normal file
@ -0,0 +1,12 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func main() {
|
||||
str := "hello"
|
||||
pointer := unsafe.StringData(str[4:5])
|
||||
fmt.Println(pointer, string(*pointer))
|
||||
}
|
||||
32
lessons/strings/byte_slice_to_string/comparison_test.go
Normal file
32
lessons/strings/byte_slice_to_string/comparison_test.go
Normal file
@ -0,0 +1,32 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// go test -bench=. -benchmem comparison_test.go
|
||||
|
||||
func Convert(data []byte) string {
|
||||
if len(data) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
return unsafe.String(unsafe.SliceData(data), len(data))
|
||||
}
|
||||
|
||||
var Result string
|
||||
|
||||
func BenchmarkConvertion(b *testing.B) {
|
||||
slice := []byte("Hello world!!!")
|
||||
for i := 0; i < b.N; i++ {
|
||||
Result = string(slice)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkUnsafeConvertion(b *testing.B) {
|
||||
slice := []byte("Hello world!!!")
|
||||
for i := 0; i < b.N; i++ {
|
||||
Result = Convert(slice)
|
||||
}
|
||||
}
|
||||
13
lessons/strings/const_strings/main.go
Normal file
13
lessons/strings/const_strings/main.go
Normal file
@ -0,0 +1,13 @@
|
||||
package main
|
||||
|
||||
import "unsafe"
|
||||
|
||||
func main() {
|
||||
const str1 string = "example"
|
||||
const str2 string = "example"
|
||||
const str3 string = "another example"
|
||||
|
||||
println(unsafe.StringData(str1))
|
||||
println(unsafe.StringData(str2))
|
||||
println(unsafe.StringData(str3))
|
||||
}
|
||||
29
lessons/strings/conversion_deprecated/main.go
Normal file
29
lessons/strings/conversion_deprecated/main.go
Normal file
@ -0,0 +1,29 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
/*
|
||||
type SliceHeader struct {
|
||||
Data unsafe.Pointer
|
||||
Len int
|
||||
Cap int
|
||||
}
|
||||
|
||||
type StringHeader struct {
|
||||
Data unsafe.Pointer
|
||||
Len int
|
||||
}
|
||||
*/
|
||||
|
||||
func ToStringDeprecated(data []byte) string {
|
||||
return *(*string)(unsafe.Pointer(&data))
|
||||
}
|
||||
|
||||
func main() {
|
||||
data := []byte{'h', 'e', 'l', 'l', 'o'}
|
||||
str := ToStringDeprecated(data)
|
||||
fmt.Println(str)
|
||||
}
|
||||
46
lessons/strings/conversion_optimizations/main.go
Normal file
46
lessons/strings/conversion_optimizations/main.go
Normal file
@ -0,0 +1,46 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func rangeWithoutAllocation() {
|
||||
var str = "world"
|
||||
for range []byte(str) { // no allocation with copy
|
||||
}
|
||||
}
|
||||
|
||||
func workWithMapsWithoutAllocation() {
|
||||
key := []byte{'k', 'e', 'y'}
|
||||
|
||||
data := map[string]string{}
|
||||
|
||||
data[string(key)] = "value" // allocation with copy
|
||||
_ = data[string(key)] // no allocation with copy
|
||||
}
|
||||
|
||||
func comparisonAndConcatenation1() {
|
||||
var x = []byte{1023: 'x'}
|
||||
var y = []byte{1023: 'y'}
|
||||
|
||||
if string(x) != string(y) { // no allocation with copy
|
||||
s := (" " + string(x) + string(y))[1:] // no allocation with copy
|
||||
_ = s
|
||||
}
|
||||
}
|
||||
|
||||
func comparisonAndConcatenation2() {
|
||||
var x = []byte{1023: 'x'}
|
||||
var y = []byte{1023: 'y'}
|
||||
|
||||
if string(x) != string(y) { // no allocation with copy
|
||||
s := string(x) + string(y) // allocation with copy
|
||||
_ = s
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println(testing.AllocsPerRun(1, comparisonAndConcatenation1)) // 1
|
||||
fmt.Println(testing.AllocsPerRun(1, comparisonAndConcatenation2)) // 3
|
||||
}
|
||||
63
lessons/strings/cow_string/main.go
Normal file
63
lessons/strings/cow_string/main.go
Normal file
@ -0,0 +1,63 @@
|
||||
package main
|
||||
|
||||
// Copy-On-Write
|
||||
type COWString struct {
|
||||
data []byte
|
||||
refs *int
|
||||
}
|
||||
|
||||
func NewString(values ...byte) COWString {
|
||||
return COWString{
|
||||
data: values,
|
||||
refs: new(int),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *COWString) Length() int {
|
||||
return len(s.data)
|
||||
}
|
||||
|
||||
func (s *COWString) Capacity() int {
|
||||
return cap(s.data)
|
||||
}
|
||||
|
||||
func (s *COWString) ToString() string {
|
||||
return string(s.data) // copying...
|
||||
}
|
||||
|
||||
func (s *COWString) Get(idx int) byte {
|
||||
// without bound checking
|
||||
return s.data[idx]
|
||||
}
|
||||
|
||||
func (s *COWString) Set(idx int, value byte) {
|
||||
// without bound checking
|
||||
|
||||
if *s.refs > 0 {
|
||||
s.data = append([]byte(nil), s.data...)
|
||||
}
|
||||
|
||||
s.data[idx] = value
|
||||
}
|
||||
|
||||
func (s *COWString) Copy() COWString {
|
||||
(*s.refs)++
|
||||
return COWString{
|
||||
data: s.data,
|
||||
refs: s.refs,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *COWString) Append(values ...byte) {
|
||||
if *s.refs > 0 {
|
||||
s.data = append([]byte(nil), s.data...)
|
||||
}
|
||||
|
||||
s.data = append(s.data, values...)
|
||||
}
|
||||
|
||||
func main() {
|
||||
str := NewString([]byte("Hello world")...)
|
||||
temp := str
|
||||
_ = temp
|
||||
}
|
||||
11
lessons/strings/encodings/main.go
Normal file
11
lessons/strings/encodings/main.go
Normal file
@ -0,0 +1,11 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
// incorrect code points
|
||||
data := []rune{0x0011FFFF, 0x0012FFFF}
|
||||
str := string(data)
|
||||
|
||||
fmt.Println(str)
|
||||
}
|
||||
17
lessons/strings/interpreted_and_raw_strings/main.go
Normal file
17
lessons/strings/interpreted_and_raw_strings/main.go
Normal file
@ -0,0 +1,17 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
interpreted := "\nHello\nworld!\n"
|
||||
raw := `\nHello\nworld!\n`
|
||||
|
||||
fmt.Println(interpreted)
|
||||
fmt.Println(raw)
|
||||
|
||||
interpretedData := []byte("\n")
|
||||
rawData := []byte(`\n`)
|
||||
|
||||
fmt.Println("interpretedData:", interpretedData)
|
||||
fmt.Println("rawData:", rawData)
|
||||
}
|
||||
38
lessons/strings/leak_with_string/main.go
Normal file
38
lessons/strings/leak_with_string/main.go
Normal file
@ -0,0 +1,38 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func printAllocs() {
|
||||
var m runtime.MemStats
|
||||
runtime.ReadMemStats(&m)
|
||||
fmt.Printf("%d MB\n", m.Alloc/1024/1024)
|
||||
}
|
||||
|
||||
func findSequence(data string) string {
|
||||
for i := 0; i < len(data)-1; i++ {
|
||||
if data[i] == '\n' && data[i+1] == '\t' {
|
||||
return data[i+2 : i+22]
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func main() {
|
||||
data := make([]byte, 1<<30)
|
||||
// let's imagine that data was read from a file
|
||||
|
||||
str := unsafe.String(unsafe.SliceData(data), len(data))
|
||||
sequence := findSequence(str)
|
||||
_ = sequence // using of sequence later
|
||||
|
||||
printAllocs()
|
||||
runtime.GC()
|
||||
printAllocs()
|
||||
|
||||
runtime.KeepAlive(data)
|
||||
}
|
||||
22
lessons/strings/letter_frequencies/main.go
Normal file
22
lessons/strings/letter_frequencies/main.go
Normal file
@ -0,0 +1,22 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func CalculateFrequencies(str string) {
|
||||
frequencies := [26]int{}
|
||||
for _, letter := range str {
|
||||
letterIdx := letter - 'a'
|
||||
frequencies[letterIdx]++
|
||||
}
|
||||
|
||||
for letterIdx, frequency := range frequencies {
|
||||
if frequency != 0 {
|
||||
letter := 'a' + letterIdx
|
||||
fmt.Printf("%c = %d\n", letter, frequency)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
CalculateFrequencies("aabaacdb")
|
||||
}
|
||||
8
lessons/strings/letter_order/main.go
Normal file
8
lessons/strings/letter_order/main.go
Normal file
@ -0,0 +1,8 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
fmt.Println('w' - 'a') // 119 - 97
|
||||
fmt.Println('o' - 'a') // 111 - 97
|
||||
}
|
||||
15
lessons/strings/mutate_string_1/main.go
Normal file
15
lessons/strings/mutate_string_1/main.go
Normal file
@ -0,0 +1,15 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func main() {
|
||||
data := []byte("Hello world")
|
||||
strData := unsafe.String(unsafe.SliceData(data), len(data))
|
||||
|
||||
fmt.Println(strData)
|
||||
data[0] = 'W'
|
||||
fmt.Println(strData)
|
||||
}
|
||||
26
lessons/strings/mutate_string_2/main.go
Normal file
26
lessons/strings/mutate_string_2/main.go
Normal file
@ -0,0 +1,26 @@
|
||||
package main
|
||||
|
||||
import "unsafe"
|
||||
|
||||
func action() {}
|
||||
|
||||
func main() {
|
||||
var str = "go"
|
||||
newStr := str + "-go"
|
||||
|
||||
strData := unsafe.StringData(str)
|
||||
newStrData := unsafe.StringData(newStr)
|
||||
|
||||
println("action:", action)
|
||||
println("strData:", strData)
|
||||
println("newStrData:", newStrData)
|
||||
|
||||
slice := unsafe.Slice(strData, len(str))
|
||||
newSlice := unsafe.Slice(newStrData, len(newStr))
|
||||
|
||||
newSlice[0] = 'G'
|
||||
println("newStr:", newStr)
|
||||
|
||||
slice[0] = 'G'
|
||||
println("str:", str)
|
||||
}
|
||||
27
lessons/strings/range_ascii_vs_utf8/speed_test.go
Normal file
27
lessons/strings/range_ascii_vs_utf8/speed_test.go
Normal file
@ -0,0 +1,27 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
// go test -bench=. speed_test.go
|
||||
|
||||
func BenchmarkByRangeBytes(b *testing.B) {
|
||||
text := []byte("aaaabbbbccccddddeeeeffff")
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
for _, _ = range text {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkByRangeStringUTF8(b *testing.B) {
|
||||
text := "aaaabbbbccccddddeeeeffff"
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
for _, _ = range text {
|
||||
}
|
||||
}
|
||||
}
|
||||
39
lessons/strings/rune_to_bytes_test/perf_test.go
Normal file
39
lessons/strings/rune_to_bytes_test/perf_test.go
Normal file
@ -0,0 +1,39 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
func RunesToBytes(rs []rune) []byte {
|
||||
n := 0
|
||||
for _, r := range rs {
|
||||
n += utf8.RuneLen(r)
|
||||
}
|
||||
|
||||
n, bs := 0, make([]byte, n)
|
||||
for _, r := range rs {
|
||||
n += utf8.EncodeRune(bs[n:], r)
|
||||
}
|
||||
|
||||
return bs
|
||||
}
|
||||
|
||||
// go test -bench=. -benchmem perf_test.go
|
||||
|
||||
var Result []byte
|
||||
var str string = "€€€v€wqeqwwerrerrqw12313123€€€v€€€€v€€€€v€€€€v€"
|
||||
|
||||
func BenchmarkConversion(b *testing.B) {
|
||||
rs := []rune(str + "sdfsfs€€€v€€€€v€23423423")
|
||||
for i := 0; i < b.N; i++ {
|
||||
Result = RunesToBytes(rs)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkConversionWithStr(b *testing.B) {
|
||||
rs := []rune(str + "sdfsfs€€€v€€€€v€23423423")
|
||||
for i := 0; i < b.N; i++ {
|
||||
Result = []byte(string(rs))
|
||||
}
|
||||
}
|
||||
33
lessons/strings/runes_to_bytes/main.go
Normal file
33
lessons/strings/runes_to_bytes/main.go
Normal file
@ -0,0 +1,33 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
func Runes2Bytes(rs []rune) []byte {
|
||||
n := 0
|
||||
for _, r := range rs {
|
||||
n += utf8.RuneLen(r)
|
||||
}
|
||||
|
||||
n, bs := 0, make([]byte, n)
|
||||
for _, r := range rs {
|
||||
n += utf8.EncodeRune(bs[n:], r)
|
||||
}
|
||||
|
||||
return bs
|
||||
}
|
||||
|
||||
func main() {
|
||||
s := "Hello world!!!"
|
||||
|
||||
bs := []byte(s) // string -> []byte
|
||||
s = string(bs) // []byte -> string
|
||||
|
||||
rs := []rune(s) // string -> []rune
|
||||
s = string(rs) // []rune -> string
|
||||
|
||||
rs = bytes.Runes(bs) // []byte -> []rune
|
||||
bs = Runes2Bytes(rs) // []rune -> []byte
|
||||
}
|
||||
27
lessons/strings/speed_comparison/comparison_test.go
Normal file
27
lessons/strings/speed_comparison/comparison_test.go
Normal file
@ -0,0 +1,27 @@
|
||||
package main
|
||||
|
||||
import "testing"
|
||||
|
||||
// go test -bench=. comparison_test.go
|
||||
|
||||
func BenchmarkComparison(b *testing.B) {
|
||||
bs := make([]byte, 1<<26)
|
||||
s0 := string(bs)
|
||||
s1 := string(bs)
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = s0 == s1
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkComparisonOptimized(b *testing.B) {
|
||||
bs := make([]byte, 1<<26)
|
||||
s0 := string(bs)
|
||||
s1 := s0
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = s0 == s1
|
||||
}
|
||||
}
|
||||
45
lessons/strings/speed_concatenation/concatenation_test.go
Normal file
45
lessons/strings/speed_concatenation/concatenation_test.go
Normal file
@ -0,0 +1,45 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// go test -bench=. concatenation_test.go
|
||||
|
||||
func BenchmarkConcatenationWithSprintf(b *testing.B) {
|
||||
s0 := "str1"
|
||||
s1 := "str2"
|
||||
s2 := "str3"
|
||||
s3 := "str4"
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = fmt.Sprintf("%s%s%s%s", s0, s1, s2, s3)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkConcatenationWithOperatorPlus(b *testing.B) {
|
||||
s0 := "str1"
|
||||
s1 := "str2"
|
||||
s2 := "str3"
|
||||
s3 := "str4"
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = s0 + s1 + s2 + s3
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkConcatenationWithJoin(b *testing.B) {
|
||||
s0 := "str1"
|
||||
s1 := "str2"
|
||||
s2 := "str3"
|
||||
s3 := "str4"
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = strings.Join([]string{s0, s1, s2, s3}, "")
|
||||
}
|
||||
}
|
||||
38
lessons/strings/string_builder/speed_test.go
Normal file
38
lessons/strings/string_builder/speed_test.go
Normal file
@ -0,0 +1,38 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// go test -bench=. speed_test.go
|
||||
|
||||
func BenchmarkSimpleConcatenation(b *testing.B) {
|
||||
str := "test"
|
||||
for i := 0; i < b.N; i++ {
|
||||
str += "test"
|
||||
}
|
||||
|
||||
_ = str
|
||||
}
|
||||
|
||||
func BenchmarkConcatenationWithStringBuilder(b *testing.B) {
|
||||
builder := strings.Builder{}
|
||||
builder.WriteString("test")
|
||||
for i := 0; i < b.N; i++ {
|
||||
builder.WriteString("test")
|
||||
}
|
||||
|
||||
_ = builder.String()
|
||||
}
|
||||
|
||||
func BenchmarkConcatenationWithStringBuilderOptimized(b *testing.B) {
|
||||
builder := strings.Builder{}
|
||||
builder.Grow(4 + b.N*4)
|
||||
builder.WriteString("test")
|
||||
for i := 0; i < b.N; i++ {
|
||||
builder.WriteString("test")
|
||||
}
|
||||
|
||||
_ = builder.String()
|
||||
}
|
||||
18
lessons/strings/string_builder_copy/main.go
Normal file
18
lessons/strings/string_builder_copy/main.go
Normal file
@ -0,0 +1,18 @@
|
||||
package main
|
||||
|
||||
import "strings"
|
||||
|
||||
func firstWay() {
|
||||
old := strings.Builder{}
|
||||
// manipulating with old..
|
||||
new := old
|
||||
_ = new
|
||||
}
|
||||
|
||||
func secondWay() {
|
||||
old := strings.Builder{}
|
||||
// manipulating with old..
|
||||
new := strings.Builder{}
|
||||
new.WriteString(old.String())
|
||||
_ = new
|
||||
}
|
||||
53
lessons/strings/string_builder_implementation/main.go
Normal file
53
lessons/strings/string_builder_implementation/main.go
Normal file
@ -0,0 +1,53 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
type Builder struct {
|
||||
buffer []byte
|
||||
}
|
||||
|
||||
func NewBuilder() Builder {
|
||||
return Builder{}
|
||||
}
|
||||
|
||||
func (b *Builder) Grow(capacity int) {
|
||||
if capacity < 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if capacity < len(b.buffer) {
|
||||
b.buffer = b.buffer[:capacity]
|
||||
return
|
||||
}
|
||||
|
||||
buffer := make([]byte, len(b.buffer), capacity)
|
||||
copy(buffer, b.buffer)
|
||||
b.buffer = buffer
|
||||
}
|
||||
|
||||
func (b *Builder) Write(symbol byte) {
|
||||
b.buffer = append(b.buffer, symbol)
|
||||
}
|
||||
|
||||
func (b *Builder) At(index int) *byte {
|
||||
if index < 0 || index >= len(b.buffer) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &b.buffer[index]
|
||||
}
|
||||
|
||||
func (b *Builder) String() string {
|
||||
return string(b.buffer)
|
||||
}
|
||||
|
||||
func main() {
|
||||
builder := NewBuilder()
|
||||
builder.Grow(3)
|
||||
|
||||
builder.Write('a')
|
||||
builder.Write('b')
|
||||
builder.Write('c')
|
||||
|
||||
fmt.Println(builder.String())
|
||||
}
|
||||
29
lessons/strings/string_implementation/main.go
Normal file
29
lessons/strings/string_implementation/main.go
Normal file
@ -0,0 +1,29 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
var table = map[uint8]byte{
|
||||
0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: 'e',
|
||||
5: 'f', 6: 'g', 7: 'h', 8: 'i', 9: 'j',
|
||||
10: 'k', 11: 'l', 12: 'm', 13: 'n', 14: 'o',
|
||||
15: 'p', 16: 'q', 17: 'r', 18: 's', 19: 't',
|
||||
20: 'u', 21: 'v', 22: 'w', 23: 'x', 24: 'y',
|
||||
25: 'z',
|
||||
}
|
||||
|
||||
func printText(text []uint8) {
|
||||
for _, codeNumber := range text {
|
||||
symbol, found := table[codeNumber]
|
||||
if !found {
|
||||
fmt.Printf("#incorrect code symbol: %d\n", codeNumber)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("%q", symbol)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
text := []uint8{7, 4, 11, 11, 14}
|
||||
printText(text)
|
||||
}
|
||||
10
lessons/strings/string_len/main.go
Normal file
10
lessons/strings/string_len/main.go
Normal file
@ -0,0 +1,10 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
str1 := "hello"
|
||||
str2 := "汉hello"
|
||||
|
||||
fmt.Println(len(str1), len(str2))
|
||||
}
|
||||
32
lessons/strings/string_to_byte_slice/comparison_test.go
Normal file
32
lessons/strings/string_to_byte_slice/comparison_test.go
Normal file
@ -0,0 +1,32 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// go test -bench=. -benchmem comparison_test.go
|
||||
|
||||
func Convert(str string) []byte {
|
||||
if len(str) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return unsafe.Slice(unsafe.StringData(str), len(str))
|
||||
}
|
||||
|
||||
var Result []byte
|
||||
|
||||
func BenchmarkConvertion(b *testing.B) {
|
||||
str := "Hello world!!!"
|
||||
for i := 0; i < b.N; i++ {
|
||||
Result = []byte(str)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkUnsafeConvertion(b *testing.B) {
|
||||
str := "Hello world!!!"
|
||||
for i := 0; i < b.N; i++ {
|
||||
Result = Convert(str)
|
||||
}
|
||||
}
|
||||
27
lessons/strings/strings_operations/main.go
Normal file
27
lessons/strings/strings_operations/main.go
Normal file
@ -0,0 +1,27 @@
|
||||
package main
|
||||
|
||||
func writeToStringSymbol() {
|
||||
str := "hello"
|
||||
// str[0] = 'H' -> compilation error
|
||||
_ = str
|
||||
}
|
||||
|
||||
func rewriteString() {
|
||||
str := "hello"
|
||||
str = "world"
|
||||
// str[0] = 'H' -> compilation error
|
||||
_ = str
|
||||
}
|
||||
|
||||
func takeStringSymbolAddress() {
|
||||
str := "hello"
|
||||
// pointer := &str[0] -> compilation error
|
||||
_ = str
|
||||
}
|
||||
|
||||
func slicingString() {
|
||||
/*
|
||||
const str = "hello"
|
||||
_ = str[0:10] -> compilation error
|
||||
*/
|
||||
}
|
||||
15
lessons/strings/strings_range/main.go
Normal file
15
lessons/strings/strings_range/main.go
Normal file
@ -0,0 +1,15 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
text := "Sr, привет 世界"
|
||||
for idx, symbol := range text { // range []rune(text)
|
||||
fmt.Printf("%d-%c ", idx, symbol)
|
||||
}
|
||||
|
||||
fmt.Println()
|
||||
for i := 0; i < len(text); i++ { // range []byte(text)
|
||||
fmt.Printf("%d-%c ", i, text[i])
|
||||
}
|
||||
}
|
||||
9
lessons/strings/substring/main.go
Normal file
9
lessons/strings/substring/main.go
Normal file
@ -0,0 +1,9 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
str := "字Hello"
|
||||
substr := str[:6]
|
||||
fmt.Println(substr)
|
||||
}
|
||||
13
lessons/strings/trim_right_and_trim_suffix/main.go
Normal file
13
lessons/strings/trim_right_and_trim_suffix/main.go
Normal file
@ -0,0 +1,13 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func main() {
|
||||
str := "oxo123oxo"
|
||||
fmt.Println("TrimRight:", strings.TrimRight(str, "xo"))
|
||||
fmt.Println("TrimSuffix:", strings.TrimSuffix(str, "xo"))
|
||||
// also for strings.TrimLeft() and strings.TrimPrefix()
|
||||
}
|
||||
50
lessons/strings/unique/bench_test.go
Normal file
50
lessons/strings/unique/bench_test.go
Normal file
@ -0,0 +1,50 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"unique"
|
||||
)
|
||||
|
||||
// go test -bench=. bench_test.go
|
||||
|
||||
var str1 = `Lorem ipsum dolor sit amet, consectetur adipiscing elit,
|
||||
sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
|
||||
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris
|
||||
nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in
|
||||
reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
|
||||
pariatur. Excepteur sint occaecat cupidatat non proident, sunt
|
||||
in culpa qui officia deserunt mollit anim id est laborum`
|
||||
|
||||
var str2 = `Lorem ipsum dolor sit amet, consectetur adipiscing elit,
|
||||
sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
|
||||
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris
|
||||
nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in
|
||||
reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
|
||||
pariatur. Excepteur sint occaecat cupidatat non proident, sunt
|
||||
in culpa qui officia deserunt mollit anim id est laborum`
|
||||
|
||||
var Result bool
|
||||
|
||||
// describe about:
|
||||
// - space optimization
|
||||
// - other types
|
||||
// - synchronization
|
||||
|
||||
func BenchmarkConversion(b *testing.B) {
|
||||
handle1 := unique.Make(str1 + "!!!")
|
||||
handle2 := unique.Make(str2 + "!!!")
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
Result = handle1 == handle2
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkConversionWithStr(b *testing.B) {
|
||||
sstr1 := str1 + "!!!"
|
||||
sstr2 := str2 + "!!!"
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
Result = sstr1 == sstr2
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user