Skip to content

Commit

Permalink
add some ideas
Browse files Browse the repository at this point in the history
  • Loading branch information
hopeAbounds committed Apr 23, 2022
1 parent b336e32 commit dec5791
Show file tree
Hide file tree
Showing 15 changed files with 1,062 additions and 1 deletion.
23 changes: 23 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# env
.idea/

# dependencies
/node_modules

# production
/build

# generated files
.docusaurus
.cache-loader

# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2022 周北海

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,11 @@
# toolkit
frequently used repetitive code. Some are my new ideas, and some are others' new ideas
记录一些经常使用到的但是重复的代码,其中有一些是我的新想法,有一些是其他人的新想法。已发布 Go Modules,可以直接通过下述直接引入到自己的工程中。

```bash
go install github.com/choubeihai/toolkit@latest
```

## 感谢

- panjf2000
- smallnest
23 changes: 23 additions & 0 deletions byteconv/byteconv.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package byteconv

import (
"reflect"
"unsafe"
)

// BytesToString 在不需要额外内存分配的情况下,将字节切片转化为字符串
func BytesToString(b []byte) string {
/* #nosec G103 */
return *(*string)(unsafe.Pointer(&b))
}

// StringToBytes 在不需要额外内存分配的情况下,将字符串转化为字节切片
func StringToBytes(s string) (b []byte) {
/* #nosec G103 */
sh := (*reflect.StringHeader)(unsafe.Pointer(&s))
/* #nosec G103 */
bh := (*reflect.SliceHeader)(unsafe.Pointer(&b))

bh.Data, bh.Len, bh.Cap = sh.Data, sh.Len, sh.Len
return b
}
5 changes: 5 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module github.com/hopeAbounds/toolkit

go 1.17

require github.com/valyala/bytebufferpool v1.0.0
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
172 changes: 172 additions & 0 deletions listbuffer/listbuffer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
package listbuffer

import "github.com/hopeAbounds/toolkit/pool/bytebuffer"

type ByteBuffer struct {
Buf *bytebuffer.ByteBuffer
next *ByteBuffer
}

// Len 返回 ByteBuffer 的长度
func (b *ByteBuffer) Len() int {
if b.Buf == nil {
return -1
}
return b.Buf.Len()
}

// IsEmpty ByteBuffer是否为空
func (b *ByteBuffer) IsEmpty() bool {
if b.Buf == nil {
return true
}
return b.Buf.Len() == 0
}

// ListBuffer is a linked list of ByteBuffer.
type ListBuffer struct {
bs [][]byte
head *ByteBuffer
tail *ByteBuffer
size int
bytes int64 // the total size of the link list of ByteBuffer
}

// Pop returns and removes the head of l. If l is empty, it returns nil.
func (l *ListBuffer) Pop() *ByteBuffer {
if l.head == nil {
return nil
}
b := l.head
l.head = b.next
if l.head == nil {
l.tail = nil
}
b.next = nil
l.size--
l.bytes -= int64(b.Buf.Len())
return b
}

// PushFront adds the new node to the head of l.
func (l *ListBuffer) PushFront(b *ByteBuffer) {
if b == nil {
return
}
if l.head == nil {
b.next = nil
l.tail = b
} else {
b.next = l.head
}
l.head = b
l.size++
l.bytes += int64(b.Buf.Len())
}

// PushBack adds a new node to the tail of l.
func (l *ListBuffer) PushBack(b *ByteBuffer) {
if b == nil {
return
}
if l.tail == nil {
l.head = b
} else {
l.tail.next = b
}
b.next = nil
l.tail = b
l.size++
l.bytes += int64(b.Buf.Len())
}

// PushBytesFront is a wrapper of PushFront, which accepts []byte as its argument.
func (l *ListBuffer) PushBytesFront(p []byte) {
if len(p) == 0 {
return
}
bb := bytebuffer.Get()
_, _ = bb.Write(p)
l.PushFront(&ByteBuffer{Buf: bb})
}

// PushBytesBack is a wrapper of PushBack, which accepts []byte as its argument.
func (l *ListBuffer) PushBytesBack(p []byte) {
if len(p) == 0 {
return
}
bb := bytebuffer.Get()
_, _ = bb.Write(p)
l.PushBack(&ByteBuffer{Buf: bb})
}

// PeekBytesList assembles the [][]byte based on the list of ByteBuffer,
// it won't remove these nodes from l until DiscardBytes() is called.
func (l *ListBuffer) PeekBytesList() [][]byte {
l.bs = l.bs[:0]
for iter := l.head; iter != nil; iter = iter.next {
l.bs = append(l.bs, iter.Buf.B)
}
return l.bs
}

// PeekBytesListWithBytes is like PeekBytesList but accepts [][]byte and puts them onto head.
func (l *ListBuffer) PeekBytesListWithBytes(bs ...[]byte) [][]byte {
l.bs = l.bs[:0]
for _, b := range bs {
if len(b) > 0 {
l.bs = append(l.bs, b)
}
}
for iter := l.head; iter != nil; iter = iter.next {
l.bs = append(l.bs, iter.Buf.B)
}
return l.bs
}

// DiscardBytes removes some nodes based on n.
func (l *ListBuffer) DiscardBytes(n int) {
if n <= 0 {
return
}
for n != 0 {
b := l.Pop()
if b == nil {
break
}
if n < b.Len() {
b.Buf.B = b.Buf.B[n:]
l.PushFront(b)
break
}
n -= b.Len()
bytebuffer.Put(b.Buf)
}
}

// Len returns the length of the list.
func (l *ListBuffer) Len() int {
return l.size
}

// Bytes returns the amount of bytes in this list.
func (l *ListBuffer) Bytes() int64 {
return l.bytes
}

// IsEmpty reports whether l is empty.
func (l *ListBuffer) IsEmpty() bool {
return l.head == nil
}

// Reset removes all elements from this list.
func (l *ListBuffer) Reset() {
for b := l.Pop(); b != nil; b = l.Pop() {
bytebuffer.Put(b.Buf)
}
l.head = nil
l.tail = nil
l.size = 0
l.bytes = 0
l.bs = l.bs[:0]
}
47 changes: 47 additions & 0 deletions math/math.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package math

const (
bitsize = 32 << (^uint(0) >> 63) // 64
maxintHeadBit = 1 << (bitsize - 2)
)

// IsPowerOfTwo 判断是否是2的幂次方
func IsPowerOfTwo(n int) bool {
return n&(n-1) == 0
}

// CeilToPowerOfTwo 返回数轴右侧离n最近的2的幂次方(大于等于n)
func CeilToPowerOfTwo(n int) int {
if n&maxintHeadBit != 0 && n > maxintHeadBit {
panic("argument is too large")
}
if n <= 2 {
return 2
}
n--
n = fillBits(n)
n++
return n
}

// FloorToPowerOfTwo 返回数轴左侧离n最近的2的幂次方(小于等于n)
func FloorToPowerOfTwo(n int) int {
if n <= 2 {
return 2
}
n = fillBits(n)
n >>= 1
n++
return n
}

//
func fillBits(n int) int {
n |= n >> 1
n |= n >> 2
n |= n >> 4
n |= n >> 8
n |= n >> 16
n |= n >> 32
return n
}
16 changes: 16 additions & 0 deletions pool/bytebuffer/bytebuffer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package bytebuffer

import "github.com/valyala/bytebufferpool"

// ByteBuffer 是bytebufferpool.ByteBuffer的别名.
type ByteBuffer = bytebufferpool.ByteBuffer

// Get 从pool中取出一个空的byte buffer
var Get = bytebufferpool.Get

// Put 向pool中归还 byte buffer
var Put = func(b *ByteBuffer) {
if b != nil {
bytebufferpool.Put(b)
}
}
56 changes: 56 additions & 0 deletions pool/byteslice/byteslice.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package byteslice

import (
"math"
"math/bits"
"sync"
)

var builtinPool Pool

// Pool 有32个sync.Pool,代表byte slice的长度(2的幂次方)
type Pool struct {
pools [32]sync.Pool
}

// Get 从builtinPool中返回一个长度为size的byte slice
func Get(size int) []byte {
return builtinPool.Get(size)
}

// Put 向builtinPool中归还byte slice
func Put(buf []byte) {
builtinPool.Put(buf)
}

func (p *Pool) Get(size int) []byte {
if size <= 0 {
return nil
}
if size > math.MaxInt32 {
return make([]byte, size)
}
idx := index(uint32(size))
if v := p.pools[idx].Get(); v != nil {
bp := v.(*[]byte)
return (*bp)[:size]
}
return make([]byte, 1<<idx)[:size]
}

func (p *Pool) Put(buf []byte) {
size := cap(buf)
if size == 0 || size > math.MaxInt32 {
return
}
idx := index(uint32(size))
if size != 1<<idx { // this byte slice is not from Pool.Get(), put it into the previous interval of idx
idx--
}
p.pools[idx].Put(&buf)
}

// index 返回长度为n字节的byte slice的Pool.pools下标
func index(n uint32) uint32 {
return uint32(bits.Len32(n - 1))
}
Loading

0 comments on commit dec5791

Please sign in to comment.