-
Notifications
You must be signed in to change notification settings - Fork 2
/
bytes.go
225 lines (197 loc) · 7.85 KB
/
bytes.go
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
// -----------------------------------------------------------------------------
// ZR Library zr/[bytes.go]
// (c) balarabe@protonmail.com License: MIT
// -----------------------------------------------------------------------------
package zr
// # Special Constructors
// BytesAlloc(size int) Bytes
// BytesAllocUTF8(s string) Bytes
// BytesWrap(ar []byte) Bytes
//
// # Read-Only Properties / Methods (ob *Bytes)
// ) Cap() int
// ) FindByte(b byte) int
// ) GetByte(index int) byte
// ) GetChar(index int) CharSize
// ) Size() int
//
// # fmt.Stringer Interface (ob *Bytes)
// ) String() string
//
// # Methods (ob *Bytes)
// ) Append(b Bytes)
// ) AppendChar(ch rune) int
// ) GetBytes() []byte
// ) Insert(index int, data Bytes, count int) int
// ) Remove(index, count int)
// ) Reset()
// ) Resize(size int)
// ) SetByte(index int, val byte)
// ) Slice(beginIndex, endIndex int) Bytes
import (
"bytes"
"unicode/utf8"
)
// Bytes wraps an array of bytes and provides byte-manipulation methods.
type Bytes struct {
ar []byte
} // Bytes
// CharSize holds a character value and its UTF-8 encoded size in bytes.
type CharSize struct {
Val rune
Size int
} // CharSize
// -----------------------------------------------------------------------------
// # Special Constructors
// BytesAlloc creates a new Bytes object with a pre-allocated size.
func BytesAlloc(size int) Bytes {
return Bytes{ar: make([]byte, 0, size)}
} // BytesAlloc
// BytesAllocUTF8 creates a new Bytes object
// by UTF-8 encoding the string 's'.
func BytesAllocUTF8(s string) Bytes {
return Bytes{ar: []byte(s)}
} // BytesAllocUTF8
// BytesWrap creates a new Bytes object by wrapping a byte array 'data'.
func BytesWrap(ar []byte) Bytes {
return Bytes{ar: ar}
} // BytesWrap
// -----------------------------------------------------------------------------
// # Read-Only Properties / Methods (ob *Bytes)
// Cap returns the allocated capacity of this object.
func (ob *Bytes) Cap() int {
return cap(ob.ar)
} // Cap
// FindByte returns the index of the first occurrence of byte 'b'.
func (ob *Bytes) FindByte(b byte) int {
return bytes.IndexByte(ob.ar, b)
} // FindByte
// GetByte returns the byte at the specified byte index.
func (ob *Bytes) GetByte(index int) byte {
return ob.ar[index]
} // GetByte
// GetChar returns the Unicode character at the specified byte index.
// Assumes that the data is encoded in UTF-8 format.
// Note that the index is the byte index, not the character number.
func (ob *Bytes) GetChar(index int) CharSize {
r, size := utf8.DecodeRune(ob.ar[index:])
return CharSize{Val: r, Size: size}
} // GetChar
// Size returns the written size of this object. (Always less than capacity)
func (ob *Bytes) Size() int {
return len(ob.ar)
} // Size
// -----------------------------------------------------------------------------
// # fmt.Stringer Interface (ob *Bytes)
// String returns a string based on previously-written bytes
// and implements the fmt.Stringer interface.
func (ob *Bytes) String() string {
return string(ob.ar)
} // String
// -----------------------------------------------------------------------------
// # Methods (ob *Bytes)
// Append appends another Bytes object to the end of this object.
func (ob *Bytes) Append(b Bytes) {
ob.ar = append(ob.ar, b.ar...)
} // Append
// AppendChar appends a Unicode character encoded in
// UTF-8 format to the end. Returns the number of bytes
// used to encode the character. If the character is not
// valid, returns -1 and doesn't change the object.
func (ob *Bytes) AppendChar(ch rune) int {
size := utf8.RuneLen(ch)
if size == -1 {
mod.Error("utf8.RuneLen(ch) == -1")
return -1
}
var buf [utf8.UTFMax]byte
ret := utf8.EncodeRune(buf[:], ch)
ob.ar = append(ob.ar, buf[:ret]...)
return ret
} // AppendChar
// GetBytes returns a raw byte array of bytes in this object.
func (ob *Bytes) GetBytes() []byte {
return ob.ar
} // GetBytes
// Insert inserts a sequence of 'data' bytes
// at position 'index' into object.
// Returns the number of bytes inserted.
func (ob *Bytes) Insert(index int, data Bytes, count int) int {
if index < 0 || index > len(ob.ar) {
mod.Error("Index", index, "out of range; array:", len(ob.ar))
return 0
}
src := data.ar
if count != -1 {
src = data.ar[:count]
}
srcLen := len(src)
if srcLen == 0 {
return 0
}
ob.ar = append(ob.ar, src...) // grow dest. by len. of insertion
copy(ob.ar[index+srcLen:], ob.ar[index:]) // make space for insertion
copy(ob.ar[index:], src) // copy source to destination
return srcLen
} // Insert
// Remove removes 'count' bytes from position starting at 'index'.
func (ob *Bytes) Remove(index, count int) {
if index < 0 || index >= len(ob.ar) {
mod.Error("Index", index, "out of range; array:", len(ob.ar))
return
}
if count == 0 {
return
}
ob.ar = ob.ar[:index+copy(ob.ar[index:], ob.ar[index+count:])]
} // Remove
// Reset empties the contents of this object making Size() equal zero,
// but does not release the allocated memory, so Cap() remains the same.
func (ob *Bytes) Reset() {
ob.ar = ob.ar[:0]
} // Reset
// Resize resizes the Bytes object so that Size() equals 'size'.
// If the new size is smaller than the old size, the contents is truncated.
// If it is bigger, appends zeros to pad the contents.
func (ob *Bytes) Resize(size int) {
current := len(ob.ar)
if size == current {
return
}
if size < current {
ob.ar = ob.ar[:size]
} else if size > current {
extra := size - current
zeros := bytes.Repeat([]byte{0}, extra)
ob.ar = append(ob.ar, zeros...)
}
} // Resize
// SetByte _ _
func (ob *Bytes) SetByte(index int, val byte) {
IMPLEMENT()
} // SetByte
// Slice returns a Bytes object that is a slice of this
// object. The slice references the original array
// so no new memory allocation is made.
//
// beginIndex is the starting position.
// Must not be less than zero
// in which the function treats it as zero and logs an error.
//
// endIndex is the ending position, just after the last required element.
// If endIndex is -1, returns everything from beginIndex up to the end.
func (ob *Bytes) Slice(beginIndex, endIndex int) Bytes {
if beginIndex < 0 {
mod.Error("Treating beginIndex", beginIndex, "as 0")
beginIndex = 0
}
if endIndex < 0 || endIndex > len(ob.ar) {
// -1 is acceptable for endIndex
if endIndex != -1 {
mod.Error("Treating endIndex", endIndex, "as length", len(ob.ar))
}
endIndex = len(ob.ar)
}
return Bytes(Bytes{ar: ob.ar[beginIndex:endIndex]})
} // Slice
// end