This commit is contained in:
rulego-team
2025-03-04 19:02:25 +08:00
parent 08db81ba62
commit 443dd9de28
66 changed files with 1851 additions and 5188 deletions

View File

@ -1,109 +0,0 @@
/*
* Copyright 2024 The RuleGo Authors.
*
* 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 attribute
import (
"reflect"
)
// BoolSliceValue converts a bool slice into an array with same elements as slice.
func BoolSliceValue(v []bool) interface{} {
var zero bool
cp := reflect.New(reflect.ArrayOf(len(v), reflect.TypeOf(zero)))
copy(cp.Elem().Slice(0, len(v)).Interface().([]bool), v)
return cp.Elem().Interface()
}
// Int64SliceValue converts an int64 slice into an array with same elements as slice.
func Int64SliceValue(v []int64) interface{} {
var zero int64
cp := reflect.New(reflect.ArrayOf(len(v), reflect.TypeOf(zero)))
copy(cp.Elem().Slice(0, len(v)).Interface().([]int64), v)
return cp.Elem().Interface()
}
// Float64SliceValue converts a float64 slice into an array with same elements as slice.
func Float64SliceValue(v []float64) interface{} {
var zero float64
cp := reflect.New(reflect.ArrayOf(len(v), reflect.TypeOf(zero)))
copy(cp.Elem().Slice(0, len(v)).Interface().([]float64), v)
return cp.Elem().Interface()
}
// StringSliceValue converts a string slice into an array with same elements as slice.
func StringSliceValue(v []string) interface{} {
var zero string
cp := reflect.New(reflect.ArrayOf(len(v), reflect.TypeOf(zero)))
copy(cp.Elem().Slice(0, len(v)).Interface().([]string), v)
return cp.Elem().Interface()
}
// AsBoolSlice converts a bool array into a slice into with same elements as array.
func AsBoolSlice(v interface{}) []bool {
rv := reflect.ValueOf(v)
if rv.Type().Kind() != reflect.Array {
return nil
}
var zero bool
correctLen := rv.Len()
correctType := reflect.ArrayOf(correctLen, reflect.TypeOf(zero))
cpy := reflect.New(correctType)
_ = reflect.Copy(cpy.Elem(), rv)
return cpy.Elem().Slice(0, correctLen).Interface().([]bool)
}
// AsInt64Slice converts an int64 array into a slice into with same elements as array.
func AsInt64Slice(v interface{}) []int64 {
rv := reflect.ValueOf(v)
if rv.Type().Kind() != reflect.Array {
return nil
}
var zero int64
correctLen := rv.Len()
correctType := reflect.ArrayOf(correctLen, reflect.TypeOf(zero))
cpy := reflect.New(correctType)
_ = reflect.Copy(cpy.Elem(), rv)
return cpy.Elem().Slice(0, correctLen).Interface().([]int64)
}
// AsFloat64Slice converts a float64 array into a slice into with same elements as array.
func AsFloat64Slice(v interface{}) []float64 {
rv := reflect.ValueOf(v)
if rv.Type().Kind() != reflect.Array {
return nil
}
var zero float64
correctLen := rv.Len()
correctType := reflect.ArrayOf(correctLen, reflect.TypeOf(zero))
cpy := reflect.New(correctType)
_ = reflect.Copy(cpy.Elem(), rv)
return cpy.Elem().Slice(0, correctLen).Interface().([]float64)
}
// AsStringSlice converts a string array into a slice into with same elements as array.
func AsStringSlice(v interface{}) []string {
rv := reflect.ValueOf(v)
if rv.Type().Kind() != reflect.Array {
return nil
}
var zero string
correctLen := rv.Len()
correctType := reflect.ArrayOf(correctLen, reflect.TypeOf(zero))
cpy := reflect.New(correctType)
_ = reflect.Copy(cpy.Elem(), rv)
return cpy.Elem().Slice(0, correctLen).Interface().([]string)
}

View File

@ -1,63 +0,0 @@
/*
* Copyright 2024 The RuleGo Authors.
*
* 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 cast
import (
"fmt"
"strconv"
)
func ToFloat(x any) float64 {
switch x := x.(type) {
case float32:
return float64(x)
case float64:
return x
case int:
return float64(x)
case int8:
return float64(x)
case int16:
return float64(x)
case int32:
return float64(x)
case int64:
return float64(x)
case uint:
return float64(x)
case uint8:
return float64(x)
case uint16:
return float64(x)
case uint32:
return float64(x)
case uint64:
return float64(x)
case string:
f, err := strconv.ParseFloat(x, 64)
if err != nil {
panic(fmt.Sprintf("invalid operation: float(%s)", x))
}
return f
default:
panic(fmt.Sprintf("invalid operation: float(%T)", x))
}
}
func ToString(arg any) string {
return fmt.Sprintf("%v", arg)
}

View File

@ -1,72 +0,0 @@
/*
* Copyright 2024 The RuleGo Authors.
*
* 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 compress
import (
"bytes"
"encoding/binary"
"fmt"
"log"
"github.com/golang/snappy"
)
// float64ToByte converts a slice of float64 to a slice of byte
func float64ToByte(data []float64) []byte {
buf := new(bytes.Buffer)
err := binary.Write(buf, binary.LittleEndian, data)
if err != nil {
log.Fatal(err)
}
return buf.Bytes()
}
// byteToFloat64 converts a slice of byte to a slice of float64
func byteToFloat64(data []byte) []float64 {
buf := bytes.NewReader(data)
var result []float64
err := binary.Read(buf, binary.LittleEndian, &result)
if err != nil {
log.Fatal(err)
}
return result
}
func main() {
// create a slice of float64
data := []float64{3.14, 3.14, 3.15, 3.16, 3.17}
fmt.Println("Original data:", data)
// convert it to []byte
dataByte := float64ToByte(data)
fmt.Println("Data as []byte:", dataByte)
// compress it using snappy
compressed := snappy.Encode(nil, dataByte)
fmt.Println("Compressed data:", compressed)
// decompress it using snappy
decompressed, err := snappy.Decode(nil, compressed)
if err != nil {
log.Fatal(err)
}
fmt.Println("Decompressed data:", decompressed)
// convert it back to []float64
dataFloat64 := byteToFloat64(decompressed)
fmt.Println("Data as []float64:", dataFloat64)
}

View File

@ -1,41 +0,0 @@
package compress
import (
"math"
"unsafe"
)
func BoolToRaw(b bool) uint64 { // nolint:revive // b is not a control flag.
if b {
return 1
}
return 0
}
func RawToBool(r uint64) bool {
return r != 0
}
func Int64ToRaw(i int64) uint64 {
return uint64(i)
}
func RawToInt64(r uint64) int64 {
return int64(r)
}
func Float64ToRaw(f float64) uint64 {
return math.Float64bits(f)
}
func RawToFloat64(r uint64) float64 {
return math.Float64frombits(r)
}
func RawPtrToFloat64Ptr(r *uint64) *float64 {
return (*float64)(unsafe.Pointer(r))
}
func RawPtrToInt64Ptr(r *uint64) *int64 {
return (*int64)(unsafe.Pointer(r))
}

View File

@ -1,85 +0,0 @@
/*
* Copyright 2023 The RuleGo Authors.
*
* 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 rsql
import (
"fmt"
"github.com/expr-lang/expr"
"github.com/montanaflynn/stats"
"testing"
"time"
)
//type Env struct {
// Posts []Post `expr:"posts"`
//}
//
//func (Env) Format(t time.Time) string {
// return t.Format(time.RFC822)
//}
type Post struct {
Name string
Body string
Date time.Time
}
func TestExpr(t *testing.T) {
env := map[string]interface{}{
"greet": "Hello, %v!",
"names": []string{"world", "you"},
"sprintf": fmt.Sprintf,
"name": "WORLd",
"name2": "我们",
"name3": "5oiR5Lus",
"foo": 100.2,
"bar": 2004,
"post": Post{Name: "lala", Body: "aa"},
}
//code := `(foo + bar)/2`
//code := `duration("1m")`
code := `fromBase64(name3)`
program, err := expr.Compile(code, expr.Env(env), expr.AllowUndefinedVariables())
if err != nil {
panic(err)
}
output, err := expr.Run(program, env)
if err != nil {
panic(err)
}
fmt.Println(output)
}
func TestStat(t *testing.T) {
// start with some source data to use
data := []float64{1.0, 2.1, 3.2, 4.823, 4.1, 5.8}
//随机生成100W数据
for i := 0; i < 10000000; i++ {
data = append(data, float64(i))
}
// you could also use different types like this
// data := stats.LoadRawData([]int{1, 2, 3, 4, 5})
// data := stats.LoadRawData([]interface{}{1.1, "2", 3})
// etc...
//计算耗时
start := time.Now()
median, _ := stats.StandardDeviation(data)
fmt.Printf("%f", median)
fmt.Println("\n", time.Since(start))
}

View File

@ -1,196 +0,0 @@
/*
* Copyright 2024 The RuleGo Authors.
*
* 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 queue
import (
"errors"
"fmt"
"sync/atomic"
)
type snapshot struct {
head int32 // 队首的索引使用int32类型方便原子操作
tail int32 // 队尾的索引使用int32类型方便原子操作
count int32 // 队列中元素的个数使用int32类型方便原子操作
}
type Queue struct {
data []float64 // 存储数据的切片
head int32 // 队首的索引使用int32类型方便原子操作
tail int32 // 队尾的索引使用int32类型方便原子操作
cap int32 // 队列的大小使用int32类型方便原子操作
count int32 // 队列中元素的个数使用int32类型方便原子操作
buffer []float64 // 缓冲切片,用于复用
}
// NewCircleQueue 创建一个指定大小的环形队列
func NewCircleQueue(size int) *Queue {
return &Queue{
data: make([]float64, size),
head: 0,
tail: 0,
cap: int32(size),
count: 0,
buffer: make([]float64, size), // 初始化缓冲切片
}
}
// IsEmpty 判断队列是否为空
func (q *Queue) IsEmpty() bool {
return atomic.LoadInt32(&q.count) == 0 // 原子读取count的值
}
// IsFull 判断队列是否已满
func (q *Queue) IsFull() bool {
return atomic.LoadInt32(&q.count) == q.cap // 原子读取count和size的值
}
// Push 向队尾添加一个元素,如果队列已满,返回错误
func (q *Queue) Push(x float64) error {
for {
if q.IsFull() {
// 队列满时,返回错误
return errors.New("queue is full")
}
tail := atomic.LoadInt32(&q.tail) // 原子读取tail的值
next := (tail + 1) % q.cap // 计算下一个tail的值
if atomic.CompareAndSwapInt32(&q.tail, tail, next) { // 原子比较并交换tail的值如果成功则表示没有其他协程修改过tail
q.data[tail] = x // 写入数据
atomic.AddInt32(&q.count, 1) // 原子增加count的值
return nil // 返回nil表示成功
}
// 否则表示有其他协程修改了tail重新尝试
}
}
// Pop 从队首删除一个元素,并返回它
func (q *Queue) Pop() (float64, bool) {
for {
if q.IsEmpty() {
// 队列空时,返回错误
return 0, false
}
head := atomic.LoadInt32(&q.head) // 原子读取head的值
next := (head + 1) % q.cap // 计算下一个head的值
if atomic.CompareAndSwapInt32(&q.head, head, next) { // 原子比较并交换head的值如果成功则表示没有其他协程修改过head
x := q.data[head] // 读取数据
atomic.AddInt32(&q.count, -1) // 原子减少count的值
return x, true // 返回数据和成功标志
}
// 否则表示有其他协程修改了head重新尝试
}
}
// Back 返回队尾元素,不出队
func (q *Queue) Back() (float64, bool) {
if q.IsEmpty() {
// 队列空时,返回错误
return 0, false
}
// 队尾元素的索引是 (q.tail - 1 + q.cap) % q.cap
tail := atomic.LoadInt32(&q.tail) // 原子读取tail的值
x := q.data[(tail-1+q.cap)%q.cap]
return x, true
}
// PopAll 返回并删除队列中的所有元素,并重置队列的状态
func (q *Queue) PopAll() []float64 {
if q.IsEmpty() {
// 队列空时,返回空切片
return nil
}
// 复用缓冲切片,避免内存浪费
slice := q.buffer
if q.head < q.tail {
// 队列中的元素是连续的,直接截取切片
slice = slice[:q.tail-q.head]
copy(slice, q.data[q.head:q.tail])
} else {
// 队列中的元素是环形的,需要拼接两部分切片
slice = slice[:q.cap-q.head+q.tail]
copy(slice, append(q.data[q.head:], q.data[:q.tail]...))
}
//重置队列的状态
q.Reset()
return slice
}
// RemoveRange 删除队列中的指定范围元素
func (q *Queue) RemoveRange(head, tail int32) {
if q.IsEmpty() {
return
}
var sliceLen int32
if head < tail {
sliceLen = tail - head
} else {
sliceLen = q.cap - head + tail
}
// 原子重置headtail和count的值
atomic.StoreInt32(&q.head, tail)
atomic.StoreInt32(&q.count, q.count-sliceLen)
}
// Reset 清空队列中的所有元素,但不释放内存空间,只是重置队列的状态
func (q *Queue) Reset() {
// 原子重置headtail和count的值
atomic.StoreInt32(&q.head, 0)
atomic.StoreInt32(&q.tail, 0)
atomic.StoreInt32(&q.count, 0)
}
func (q *Queue) Count() int32 {
return q.count
}
// Print 打印队列中的元素
func (q *Queue) Print() {
fmt.Println("队列中的元素:")
for i := int32(0); i < atomic.LoadInt32(&q.count); i++ { // 原子读取count的值
fmt.Printf("%f ", q.data[(atomic.LoadInt32(&q.head)+i)%q.cap]) // 原子读取head的值
}
fmt.Println()
}
func main() {
// 创建一个大小为 5 的环形队列
q := NewCircleQueue(5)
// 向队列中添加元素
q.Push(1.1)
q.Push(2.2)
q.Push(3.3)
q.Push(4.4)
q.Push(5.5)
// 打印队列中的元素
q.Print()
// 从队列中删除元素
x, ok := q.Pop()
if ok {
fmt.Println("删除的元素:", x)
}
// 打印队列中的元素
q.Print()
// 向队列中添加元素
q.Push(6)
// 打印队列中的元素
q.Print()
q.Push(7)
q.Print()
fmt.Println(q.Back())
}