mirror of
https://gitee.com/rulego/streamsql.git
synced 2025-07-05 15:49:14 +00:00
重构
This commit is contained in:
@ -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)
|
||||
}
|
@ -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)
|
||||
}
|
@ -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)
|
||||
}
|
@ -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))
|
||||
}
|
@ -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))
|
||||
}
|
@ -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
|
||||
}
|
||||
|
||||
// 原子重置head,tail和count的值
|
||||
atomic.StoreInt32(&q.head, tail)
|
||||
atomic.StoreInt32(&q.count, q.count-sliceLen)
|
||||
}
|
||||
|
||||
// Reset 清空队列中的所有元素,但不释放内存空间,只是重置队列的状态
|
||||
func (q *Queue) Reset() {
|
||||
// 原子重置head,tail和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())
|
||||
}
|
Reference in New Issue
Block a user