magicstring

package module
Version: v1.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 26, 2022 License: MIT Imports: 5 Imported by: 0

README

Magic String

Go Go Doc Go Report Coverage Status

This magicstring package is designed to attach arbitrary data to a Go built-in string type and read the data later. The string with attached data is called "magic string" here.

Usage

Attach data and then read it

Call Attach to attach data to a string and Read to read the attached data in the magic string. Read is thread-safe and extremely fast.

type T struct {
    Name string
}

s1 := "Hello, world!"
data := &T{Name: "Kanon"}
s2 := Attach(s1, data)

attached := Read(s2).(*T)
fmt.Println(s1 == s2)         // true
fmt.Println(attached == data) // true
Check whether a string is a magic string

Call Is if we want to know whether a string is a magic string, .

s1 := "ordinary string"
s2 := Attach("magic string", 123)
s3 := s2
s4 := fmt.Sprint(s2)

fmt.Println(Is(s1)) // false
fmt.Println(Is(s2)) // true
fmt.Println(Is(s3)) // true
fmt.Println(Is(s4)) // false
Replace the attached data

Call Replace if we want to replace the attached data to a new one in a magic string. As Replace modifies the payload in a magic string, this call will affect all copies of this magic string and is not thread-safe.

s := Attach("magic string", 123)
fmt.Println(Read(s)) // 123

success := Replace(s, "replaced")
fmt.Println(success) // true
fmt.Println(Read(s)) // replaced
Copy a magic string

In general, we can use a magic string like an ordinary string. The attached data will be kept during all kinds of assignments. However, if we copy the content of a string to a buffer and create a new string from the buffer, we will lose the attached data.

s1 := Attach("magic string", 123)
buf := make([]byte, len(s1))
copy(buf, s1)
s2 := string(buf)

fmt.Println(Is(s1)) // true
fmt.Println(Is(s2)) // false

The simplest way to create an ordinary string from a magic string is to call Detach. This function is optimized for ordinary strings. If a string is not a magic string, the Detach simply returns the string to avoid an unnecessary memory allocation and memory copy.

Slice a magic string

A magic string cannot be sliced by built-in slice expression. If we want to keep the attachment in a magic string, we must call Slice to slice it. If a string is not a magic string, Slice just works the same as slice expression.

Performance

Memory allocation is highly optimized for small strings. The maximum size of a small string is 18,408 bytes right now. It's the maximum size of memory span classes, which is 18,432 bytes provided by runtime.ReadMemStats(), minus the size of magic string payload struct, which is 24 bytes right now.

Here is the performance data running on my MacBook.

goos: darwin
goarch: amd64
pkg: github.com/huandu/go-magicstring
cpu: Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
BenchmarkAttachSmallString-12       12312567     83.78 ns/op       32 B/op   1 allocs/op
BenchmarkAttachLarge1MBString-12        8511    165978 ns/op  1057046 B/op   3 allocs/op
BenchmarkReplaceSmallString-12      225952905    5.329 ns/op        0 B/op   0 allocs/op
BenchmarkReplaceLarge1MBString-12   228580016    5.268 ns/op        0 B/op   0 allocs/op
BenchmarkReadSmallString-12         312613485    3.915 ns/op        0 B/op   0 allocs/op
BenchmarkReadLarge1MBString-12      301951902    3.964 ns/op        0 B/op   0 allocs/op

License

This package is licensed under MIT license. See LICENSE for details.

Documentation

Overview

This `magicstring` package is designed to attach arbitrary data to a Go built-in `string` type and read the data later. The string with attached data is called "magic string" here.

Example (DestroyMagicString)
magicString := Attach("magic string", 123)
buf := make([]byte, len(magicString))
copy(buf, magicString)
ordinaryString := string(buf)
detachedString := Detach(magicString)

fmt.Println(Is(magicString))
fmt.Println(Is(ordinaryString))
fmt.Println(Is(detachedString))
Output:

true
false
false

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Attach

func Attach(str string, data interface{}) string

Attach associates a newly allocated string with data. The value of the returned string is guaranteed to be identical to str.

Example
type T struct {
	Name string
}
s1 := "Hello, world!"
data := &T{Name: "Kanon"}
s2 := Attach(s1, data)

attached := Read(s2).(*T)
fmt.Println(s1 == s2)
fmt.Println(attached == data)
Output:

true
true

func Detach

func Detach(str string) string

Detach returns a new string without any attached data. If str is an ordinary string, Detach just simply returns str.

func Is

func Is(str string) bool

Is checks if there is any data attached to str.

Example
s1 := "ordinary string"
s2 := Attach("magic string", 123)
s3 := s2
s4 := fmt.Sprint(s2)

fmt.Println(Is(s1))
fmt.Println(Is(s2))
fmt.Println(Is(s3))
fmt.Println(Is(s4))
Output:

false
true
true
false

func Read

func Read(str string) interface{}

Read reads the attached data inside the str. If there is no such data, it returns nil.

func Replace added in v1.0.2

func Replace(str string, data interface{}) bool

Replace replaces the attached data in str if str is a magic string. If str is an ordinary string, Replace creates a magic string with data.

Replace returns true if the data is replaced, false if not.

Example
s := Attach("magic string", 123)
fmt.Println(Read(s))

success := Replace(s, "replaced")
fmt.Println(success)
fmt.Println(Read(s))
Output:

123
true
replaced

func Slice added in v1.1.0

func Slice(str string, begin, end int) (sliced string)

Slice returns a result of str[begin:end]. If str is a magic string with attachment, the returned string references the same attachment of str.

Types

This section is empty.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL