You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

442 lines
7.8 KiB

// ------------------------------------------------------------------------
// Project atila
// Active Thing (activething.com) git.activething.com/go
//
// File name buffer.go
// Created by DEV
// Modified 16/01/2024
//
// Copyright 2024 activething.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 bfrs
import (
"btes/chrs"
"bytes"
"io"
"unicode/utf8"
)
type (
ABuffer struct {
data []byte
off int
ini [64]byte
lastOp operation
}
)
func NewABuffer() *ABuffer {
return &ABuffer{} }
func (b *ABuffer) Len() int {
return len(b.data) - b.off }
func (b *ABuffer) Cap() int {
return cap(b.data) }
func (b *ABuffer) isEmpty() bool {
return len(b.data) <= b.off }
func (b *ABuffer) Bytes() []byte {
return b.data[b.off:] }
func (b *ABuffer) String() string {
if b == nil {
return "<nil>"
}
return string(b.data[b.off:])
}
func (b *ABuffer) Reset() {
b.data = b.data[:0]
b.off = 0
b.lastOp = opInvalid
}
func (b *ABuffer) Truncate(size int) {
if size == 0 {
b.Reset()
return
}
b.lastOp = opInvalid
if size < 0 || size > b.Len() {
panic(G.ErrOutOfRange)
}
b.data = b.data[:b.off+size]
}
func (b *ABuffer) Read(data []byte) (count int, err error) {
b.lastOp = opInvalid
if b.isEmpty() {
b.Reset()
if len(data) == 0 {
return 0, nil
}
return 0, io.EOF
}
count = copy(data, b.data[b.off:])
b.off += count
if count > 0 {
b.lastOp = opRead
}
return count, nil
}
func (b *ABuffer) ReadFrom(reader io.Reader) (count int64, err error) {
b.lastOp = opInvalid
for {
i := b.tryGrowByStrategy(MinRead)
b.data = b.data[:i]
m, e := reader.Read(b.data[i:cap(b.data)])
if m < 0 {
panic(G.ErrNegativeRead)
}
b.data = b.data[:i+m]
count += int64(m)
if e == io.EOF {
return count, nil
}
if e != nil {
return count, e
}
}
}
func (b *ABuffer) ReadByte() (byte, error) {
if b.isEmpty() {
b.Reset()
return 0, io.EOF
}
c := b.data[b.off]
b.off++
b.lastOp = opRead
return c, nil
}
func (b *ABuffer) ReadBytes(delimiter byte) (result []byte, er error) {
slice, er := b.readSlice(delimiter)
result = append(result, slice...)
return result, er
}
func (b *ABuffer) ReadString(delimiter byte) (result string, err error) {
slice, err := b.readSlice(delimiter)
return string(slice), err
}
func (b *ABuffer) ReadRune() (run rune, size int, err error) {
if b.isEmpty() {
b.Reset()
return 0, 0, io.EOF
}
c := b.data[b.off]
if c < utf8.RuneSelf {
b.off++
b.lastOp = opRune
return rune(c), 1, nil
}
r, n := utf8.DecodeRune(b.data[b.off:])
b.off += n
b.lastOp = operation(n)
return r, n, nil
}
func (b *ABuffer) readSlice(delimiter byte) (ln []byte, er error) {
i := bytes.IndexByte(b.data[b.off:], delimiter)
end := b.off + i + 1
if i < 0 {
end = len(b.data)
er = io.EOF
}
ln = b.data[b.off:end]
b.off = end
b.lastOp = opRead
return ln, er
}
func (b *ABuffer) UnreadRune() error {
if b.lastOp <= opInvalid {
return G.ErrUnreadInvalid
}
if b.off >= int(b.lastOp) {
b.off -= int(b.lastOp)
}
b.lastOp = opInvalid
return nil
}
func (b *ABuffer) UnreadByte() error {
if b.lastOp == opInvalid {
return G.ErrUnreadInvalid
}
b.lastOp = opInvalid
if b.off > 0 {
b.off--
}
return nil
}
func (b *ABuffer) AppendWith(appender Appender) {
b.lastOp = opInvalid
if appender != nil {
b.data = appender.Append(b.data)
}
}
func (b *ABuffer) Write(value []byte) (int, error) {
b.lastOp = opInvalid
return copy(b.data[b.tryGrow(len(value)):], value), nil
}
func (b *ABuffer) W (value []byte) {
b.lastOp = opInvalid
copy(b.data[b.tryGrow(len(value)):], value)
}
// WOQ With Optional Quoted
func (b *ABuffer) WOQ (add bool, quote byte, value []byte) {
b.lastOp = opInvalid
if !add {
copy(b.data[b.tryGrow(len(value)):], value)
return
}
b.WriteByte(quote)
sz := b.tryGrow(len(value)+2)
copy(b.data[sz:],value)
b.WriteByte(quote)
}
func (b *ABuffer) WriteHTML(source []byte) {
st := 0
for i, c := range source {
if c == '<' || c == '>' || c == '&' {
if st < i {
b.W(source[st:i])
}
b.WriteString(`\u00`)
b.WriteByte(chrs.G.HEX[c>>4])
b.WriteByte(chrs.G.HEX[c&0xF])
st = i + 1
} else if c == 0xE2 && i+2 < len(source) && source[i+1] == 0x80 && source[i+2]&^1 == 0xA8 {
if st < i {
b.W(source[st:i])
}
b.WriteString(`\u202`)
b.WriteByte(chrs.G.HEX[source[i+2]&0xF])
st = i + 3
}
}
if st < len(source) {
b.W(source[st:])
}
/*
st := 0
for i,c := range source {
if c == '<' || c == '>' || c == '&' {
if st < i {
b.W(source[st:i])
}
b.WriteString(`\u00`)
b.WriteByte(chrs.G.HEX[c>>4])
b.WriteByte(chrs.G.HEX[c&0xF])
st = i + 1
}
if c == 0xE2 && i+2 < len(source) && source[i+1] == 0x80 && source[i+2]&^1 == 0xA8 {
if st < i {
b.W(source[st:i])
}
b.WriteString(`\u202`)
b.WriteByte(chrs.G.HEX[source[i+2]&0xF])
st = i + 3
}
if st < len(source) {
b.W(source[st:])
}
}
*/
}
func (b *ABuffer) WriteByte(value byte) {
b.lastOp = opInvalid
b.data[b.tryGrow(1)] = value
}
func (b *ABuffer) Write2Byte(valueA, valueB byte) {
b.lastOp = opInvalid
p := b.tryGrow(2)
b.data[p] = valueA
b.data[p+1] = valueB
}
func (b *ABuffer) WriteString(value string) {
b.W([]byte(value)) }
func (b *ABuffer) WriteTo(writer io.Writer) (int64, error) {
return b.writeTo(writer, false) }
func (b *ABuffer) FlushTo(writer io.Writer) (int64, error) {
return b.writeTo(writer, true) }
func (b *ABuffer) writeTo(writer io.Writer, reset bool) (count int64, err error) {
if reset {
b.lastOp = opInvalid
}
if nBytes := b.Len(); nBytes > 0 {
m, e := writer.Write(b.data[b.off:])
if m > nBytes {
panic(G.ErrWriteCount)
}
b.off += m
count = int64(m)
if e != nil {
return count, e
}
if m != nBytes {
return count, G.ErrTooShort
}
}
if reset {
b.Reset()
}
return count, nil
}
func (b *ABuffer) tryGrow(size int) int {
m := len(b.data)
if size <= cap(b.data)-m {
b.data = b.data[:m+size]
return m
}
m = b.Len()
if m == 0 && b.off != 0 {
b.Reset()
}
if i, ok := b.tryGrowByResize(size); ok {
return i
}
if b.data == nil && size <= len(b.ini) {
b.data = b.ini[:size]
return 0
}
c := cap(b.data)
if size <= c/2-m {
copy(b.data, b.data[b.off:])
} else if c > maxInt-c-size {
panic(G.ErrTooLarge)
} else {
buf := makeSlice(2*c + size)
copy(buf, b.data[b.off:])
b.data = buf
}
b.off = 0
b.data = b.data[:m+size]
return m
}
func (b *ABuffer) tryGrowByResize(size int) (int, bool) {
if l := len(b.data); size <= cap(b.data)-l {
b.data = b.data[:l+size]
return l, true
}
return 0, false
}
func (b *ABuffer) tryGrowByStrategy(size int) int {
m := len(b.data)
if m == 0 && b.off != 0 {
b.Reset()
}
if i, ok := b.tryGrowByResize(size); ok {
return i
}
if b.data == nil && size <= len(b.ini) {
b.data = b.ini[:size]
return 0
}
c := cap(b.data)
if size <= c/2-m {
copy(b.data, b.data[b.off:])
} else if c > maxInt-c-size {
panic(G.ErrTooLarge)
} else {
buf := makeSlice(2*c + size)
copy(buf, b.data[b.off:])
b.data = buf
}
b.off = 0
b.data = b.data[:m+size]
return m
}
func makeSlice(size int) (result []byte) {
dn := false
defer func(d *bool) {
if !(*d) && recover() != nil {
panic(G.ErrTooLarge)
}
}(&dn)
result = make([]byte, size)
dn = true
return
}

Powered by TurnKey Linux.