summaryrefslogtreecommitdiff
path: root/vendor/codeberg.org/gruf/go-bytes/bytes.go
blob: 5fef75d5606fa99869b923b314d4f60513e4be55 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
package bytes

import (
	"bytes"
	"reflect"
	"unsafe"
)

var (
	_ Bytes = &Buffer{}
	_ Bytes = bytesType{}
)

// Bytes defines a standard way of retrieving the content of a
// byte buffer of some-kind.
type Bytes interface {
	// Bytes returns the byte slice content
	Bytes() []byte

	// String returns byte slice cast directly to string, this
	// will cause an allocation but comes with the safety of
	// being an immutable Go string
	String() string

	// StringPtr returns byte slice cast to string via the unsafe
	// package. This comes with the same caveats of accessing via
	// .Bytes() in that the content is liable change and is NOT
	// immutable, despite being a string type
	StringPtr() string
}

type bytesType []byte

func (b bytesType) Bytes() []byte {
	return b
}

func (b bytesType) String() string {
	return string(b)
}

func (b bytesType) StringPtr() string {
	return BytesToString(b)
}

// ToBytes casts the provided byte slice as the simplest possible
// Bytes interface implementation
func ToBytes(b []byte) Bytes {
	return bytesType(b)
}

// Copy returns a new copy of slice b, does NOT maintain nil values
func Copy(b []byte) []byte {
	p := make([]byte, len(b))
	copy(p, b)
	return p
}

// BytesToString returns byte slice cast to string via the "unsafe" package
func BytesToString(b []byte) string {
	return *(*string)(unsafe.Pointer(&b))
}

// StringToBytes returns the string cast to string via the "unsafe" and "reflect" packages
func StringToBytes(s string) []byte {
	// thank you to https://github.com/valyala/fasthttp/blob/master/bytesconv.go
	var b []byte

	// Get byte + string headers
	bh := (*reflect.SliceHeader)(unsafe.Pointer(&b))
	sh := (*reflect.StringHeader)(unsafe.Pointer(&s))

	// Manually set bytes to string
	bh.Data = sh.Data
	bh.Len = sh.Len
	bh.Cap = sh.Len

	return b
}

// // InsertByte inserts the supplied byte into the slice at provided position
// func InsertByte(b []byte, at int, c byte) []byte {
// 	return append(append(b[:at], c), b[at:]...)
// }

// // Insert inserts the supplied byte slice into the slice at provided position
// func Insert(b []byte, at int, s []byte) []byte {
// 	return append(append(b[:at], s...), b[at:]...)
// }

// ToUpper offers a faster ToUpper implementation using a lookup table
func ToUpper(b []byte) {
	for i := 0; i < len(b); i++ {
		c := &b[i]
		*c = toUpperTable[*c]
	}
}

// ToLower offers a faster ToLower implementation using a lookup table
func ToLower(b []byte) {
	for i := 0; i < len(b); i++ {
		c := &b[i]
		*c = toLowerTable[*c]
	}
}

// HasBytePrefix returns whether b has the provided byte prefix
func HasBytePrefix(b []byte, c byte) bool {
	return (len(b) > 0) && (b[0] == c)
}

// HasByteSuffix returns whether b has the provided byte suffix
func HasByteSuffix(b []byte, c byte) bool {
	return (len(b) > 0) && (b[len(b)-1] == c)
}

// HasBytePrefix returns b without the provided leading byte
func TrimBytePrefix(b []byte, c byte) []byte {
	if HasBytePrefix(b, c) {
		return b[1:]
	}
	return b
}

// TrimByteSuffix returns b without the provided trailing byte
func TrimByteSuffix(b []byte, c byte) []byte {
	if HasByteSuffix(b, c) {
		return b[:len(b)-1]
	}
	return b
}

// Compare is a direct call-through to standard library bytes.Compare()
func Compare(b, s []byte) int {
	return bytes.Compare(b, s)
}

// Contains is a direct call-through to standard library bytes.Contains()
func Contains(b, s []byte) bool {
	return bytes.Contains(b, s)
}

// TrimPrefix is a direct call-through to standard library bytes.TrimPrefix()
func TrimPrefix(b, s []byte) []byte {
	return bytes.TrimPrefix(b, s)
}

// TrimSuffix is a direct call-through to standard library bytes.TrimSuffix()
func TrimSuffix(b, s []byte) []byte {
	return bytes.TrimSuffix(b, s)
}

// Equal is a direct call-through to standard library bytes.Equal()
func Equal(b, s []byte) bool {
	return bytes.Equal(b, s)
}

// EqualFold is a direct call-through to standard library bytes.EqualFold()
func EqualFold(b, s []byte) bool {
	return bytes.EqualFold(b, s)
}

// Fields is a direct call-through to standard library bytes.Fields()
func Fields(b []byte) [][]byte {
	return bytes.Fields(b)
}

// FieldsFunc is a direct call-through to standard library bytes.FieldsFunc()
func FieldsFunc(b []byte, fn func(rune) bool) [][]byte {
	return bytes.FieldsFunc(b, fn)
}

// HasPrefix is a direct call-through to standard library bytes.HasPrefix()
func HasPrefix(b, s []byte) bool {
	return bytes.HasPrefix(b, s)
}

// HasSuffix is a direct call-through to standard library bytes.HasSuffix()
func HasSuffix(b, s []byte) bool {
	return bytes.HasSuffix(b, s)
}

// Index is a direct call-through to standard library bytes.Index()
func Index(b, s []byte) int {
	return bytes.Index(b, s)
}

// IndexByte is a direct call-through to standard library bytes.IndexByte()
func IndexByte(b []byte, c byte) int {
	return bytes.IndexByte(b, c)
}

// IndexAny is a direct call-through to standard library bytes.IndexAny()
func IndexAny(b []byte, s string) int {
	return bytes.IndexAny(b, s)
}

// IndexRune is a direct call-through to standard library bytes.IndexRune()
func IndexRune(b []byte, r rune) int {
	return bytes.IndexRune(b, r)
}

// IndexFunc is a direct call-through to standard library bytes.IndexFunc()
func IndexFunc(b []byte, fn func(rune) bool) int {
	return bytes.IndexFunc(b, fn)
}

// LastIndex is a direct call-through to standard library bytes.LastIndex()
func LastIndex(b, s []byte) int {
	return bytes.LastIndex(b, s)
}

// LastIndexByte is a direct call-through to standard library bytes.LastIndexByte()
func LastIndexByte(b []byte, c byte) int {
	return bytes.LastIndexByte(b, c)
}

// LastIndexAny is a direct call-through to standard library bytes.LastIndexAny()
func LastIndexAny(b []byte, s string) int {
	return bytes.LastIndexAny(b, s)
}

// LastIndexFunc is a direct call-through to standard library bytes.LastIndexFunc()
func LastIndexFunc(b []byte, fn func(rune) bool) int {
	return bytes.LastIndexFunc(b, fn)
}

// Replace is a direct call-through to standard library bytes.Replace()
func Replace(b, s, r []byte, c int) []byte {
	return bytes.Replace(b, s, r, c)
}

// ReplaceAll is a direct call-through to standard library bytes.ReplaceAll()
func ReplaceAll(b, s, r []byte) []byte {
	return bytes.ReplaceAll(b, s, r)
}

// Split is a direct call-through to standard library bytes.Split()
func Split(b, s []byte) [][]byte {
	return bytes.Split(b, s)
}

// SplitAfter is a direct call-through to standard library bytes.SplitAfter()
func SplitAfter(b, s []byte) [][]byte {
	return bytes.SplitAfter(b, s)
}

// SplitN is a direct call-through to standard library bytes.SplitN()
func SplitN(b, s []byte, c int) [][]byte {
	return bytes.SplitN(b, s, c)
}

// SplitAfterN is a direct call-through to standard library bytes.SplitAfterN()
func SplitAfterN(b, s []byte, c int) [][]byte {
	return bytes.SplitAfterN(b, s, c)
}

// NewReader is a direct call-through to standard library bytes.NewReader()
func NewReader(b []byte) *bytes.Reader {
	return bytes.NewReader(b)
}