diff --git a/gcollection/gstack/stack.go b/gcollection/gstack/stack.go new file mode 100644 index 0000000..d2ef695 --- /dev/null +++ b/gcollection/gstack/stack.go @@ -0,0 +1,80 @@ +// Package gstack +// Author: hyphen +// Copyright 2024 hyphen. All rights reserved. +// Create-time: 2024/1/3 +package gstack + +import ( + "github.com/hyphennn/glamda/internal" +) + +type node[T any] struct { + val T + next *node[T] +} + +type Stack[T any] struct { + top *node[T] + size int +} + +func NewStack[T any]() *Stack[T] { + return &Stack[T]{nil, 0} +} + +func (s *Stack[T]) Size() int { + return s.size +} + +func (s *Stack[T]) Push(t T) { + s.top = &node[T]{t, s.top} + s.size++ +} + +func (s *Stack[T]) PushN(ts ...T) { + for _, t := range ts { + s.Push(t) + } +} + +func (s *Stack[T]) Pop() (T, bool) { + if s.top == nil { + return internal.Zero[T](), false + } + ot := s.top + s.top = s.top.next + s.size-- + return ot.val, true +} + +func (s *Stack[T]) PopN(n int) []T { + ret := []T{} + for i := 0; i < n; i++ { + v, ok := s.Pop() + if !ok { + break + } + ret = append(ret, v) + } + return ret +} + +func (s *Stack[T]) Peek() (T, bool) { + if s.top == nil { + return internal.Zero[T](), false + } + return s.top.val, true +} + +func (s *Stack[T]) PeekN(n int) []T { + ptr := s.top + ret := []T{} + for i := 0; i < n; i++ { + if ptr == nil { + break + } + ret = append(ret, ptr.val) + ptr = ptr.next + } + return ret +} diff --git a/gcollection/gstack/stack_test.go b/gcollection/gstack/stack_test.go new file mode 100644 index 0000000..db9840e --- /dev/null +++ b/gcollection/gstack/stack_test.go @@ -0,0 +1,39 @@ +// Package gstack +// Author: hyphen +// Copyright 2024 hyphen. All rights reserved. +// Create-time: 2024/1/3 +package gstack + +import ( + "testing" + + "github.com/hyphennn/glamda/internal/assert" +) + +func TestStack(t *testing.T) { + stk := NewStack[int]() + stk.PushN([]int{1, 1, 4, 5, 1, 4}...) + stk.Push(1) + v, ok := stk.Peek() + vs := stk.PeekN(5) + assert.Equal(t, v, 1) + assert.True(t, ok) + assert.Equal(t, stk.Size(), 7) + assert.Equal(t, vs, []int{1, 4, 1, 5, 4}) + v, ok = stk.Pop() + assert.Equal(t, v, 1) + assert.True(t, ok) + assert.Equal(t, stk.Size(), 6) + vs = stk.PopN(5) + assert.Equal(t, vs, []int{4, 1, 5, 4, 1}) + assert.Equal(t, stk.Size(), 1) + assert.Equal(t, stk.PeekN(3), []int{1}) + v, ok = stk.Pop() + v, ok = stk.Pop() + assert.Equal(t, v, 0) + assert.False(t, ok) + stk.Push(1) + v, ok = stk.Pop() + assert.Equal(t, v, 1) + assert.True(t, ok) +} diff --git a/gutils/gutils.go b/gutils/gutils.go new file mode 100644 index 0000000..b227af0 --- /dev/null +++ b/gutils/gutils.go @@ -0,0 +1,153 @@ +// Package gutils +// Author: hyphen +// Copyright 2023 hyphen. All rights reserved. +// Create-time: 2023/12/4 +package gutils + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "sync" + + "github.com/hyphennn/glamda/internal" +) + +func TernaryForm[T any](cond bool, tureVal, falseVal T) T { + if cond { + return tureVal + } + return falseVal +} + +type Pair[F, S any] struct { + First F + Second S +} + +func MakePair[F, S any](f F, s S) *Pair[F, S] { + return &Pair[F, S]{First: f, Second: s} +} + +func (p *Pair[F, S]) Split() (F, S) { + return p.First, p.Second +} + +func FastAssert[T any](v any) T { + t, ok := v.(T) + if !ok { + return internal.Zero[T]() + } + return t +} + +func MustDo[K, V any](key K, fc func(K) (V, error)) V { + return MustEasyDo(func() (V, error) { + return fc(key) + }) +} + +func MustDoCtx[K, V any](ctx context.Context, key K, fc func(context.Context, K) (V, error)) V { + return MustEasyDo(func() (V, error) { + return fc(ctx, key) + }) +} + +func MustEasyDo[V any](fc func() (V, error)) V { + v, err := fc() + if err != nil { + return internal.Zero[V]() + } + return v +} + +type ch[T any] chan T + +type SafeChan[T any] struct { + ch[T] + once sync.Once +} + +func NewSafeChan[T any](size ...int) *SafeChan[T] { + if len(size) == 0 { + return &SafeChan[T]{make(chan T), sync.Once{}} + } + return &SafeChan[T]{make(chan T, size[0]), sync.Once{}} +} + +func (s *SafeChan[T]) Listen() (t T) { + t = <-s.ch + return +} + +func (s *SafeChan[T]) Send(t T) { + s.ch <- t +} + +func (s *SafeChan[T]) Close() { + s.once.Do(func() { + close(s.ch) + }) +} + +func Paging[T any](arr []T, offset, limit int) []T { + return arr[TernaryForm((offset)*limit <= len(arr), (offset)*limit, len(arr)):TernaryForm((offset+1)*limit <= len(arr), (offset+1)*limit, len(arr))] +} + +var client = &http.Client{} + +func AccessResp(ctx context.Context, url string, method string, header map[string]string, param map[string]string, + body any, setAuthorization func(*http.Request)) (*http.Response, error) { + return access(ctx, url, method, header, param, body, setAuthorization) +} + +func Access[T any](ctx context.Context, url string, method string, header map[string]string, param map[string]string, + body any, setAuthorization func(*http.Request), isSuccess func(response *http.Response) bool) (T, error) { + var ret T + resp, err := access(ctx, url, method, header, param, body, setAuthorization) + if err != nil { + return ret, fmt.Errorf("access %s failed: %w", url, err) + } + defer resp.Body.Close() + respBody, err := ioutil.ReadAll(resp.Body) + if err != nil { + return ret, fmt.Errorf("read resp body failed: %w", err) + } + if isSuccess != nil && !isSuccess(resp) { + return ret, fmt.Errorf("is success return false: %s", string(respBody)) + } + err = json.Unmarshal(respBody, &ret) + if err != nil { + return ret, fmt.Errorf("unmarshal resp body failed: %w", err) + } + return ret, nil +} + +func access(ctx context.Context, url string, method string, header map[string]string, param map[string]string, + body any, setAuthorization func(*http.Request)) (*http.Response, error) { + bodyJSON, err := json.Marshal(body) + if err != nil { + return nil, err + } + bodyReader := bytes.NewReader(bodyJSON) + req, err := http.NewRequestWithContext(ctx, method, url, bodyReader) + if setAuthorization != nil { + setAuthorization(req) + } + q := req.URL.Query() + for k, v := range param { + q.Add(k, v) + } + req.URL.RawQuery = q.Encode() + for k, v := range header { + req.Header.Add(k, v) + } + resp, err := client.Do(req) + if err != nil { + return nil, fmt.Errorf("access %s failed: %w", url, err) + } + return resp, nil +} diff --git a/gutils/lutils.go b/gutils/lutils.go deleted file mode 100644 index 3163be1..0000000 --- a/gutils/lutils.go +++ /dev/null @@ -1,93 +0,0 @@ -// Package gutils -// Author: hyphen -// Copyright 2023 hyphen. All rights reserved. -// Create-time: 2023/12/4 -package gutils - -import ( - "context" - "sync" - - "github.com/hyphennn/glamda/internal" -) - -func TernaryForm[T any](cond bool, tureVal, falseVal T) T { - if cond { - return tureVal - } - return falseVal -} - -type Pair[F, S any] struct { - First F - Second S -} - -func MakePair[F, S any](f F, s S) *Pair[F, S] { - return &Pair[F, S]{First: f, Second: s} -} - -func (p *Pair[F, S]) Split() (F, S) { - return p.First, p.Second -} - -func FastAssert[T any](v any) T { - t, ok := v.(T) - if !ok { - return internal.Zero[T]() - } - return t -} - -func MustDo[K, V any](key K, fc func(K) (V, error)) V { - return MustEasyDo(func() (V, error) { - return fc(key) - }) -} - -func MustDoCtx[K, V any](ctx context.Context, key K, fc func(context.Context, K) (V, error)) V { - return MustEasyDo(func() (V, error) { - return fc(ctx, key) - }) -} - -func MustEasyDo[V any](fc func() (V, error)) V { - v, err := fc() - if err != nil { - return internal.Zero[V]() - } - return v -} - -type ch[T any] chan T - -type SafeChan[T any] struct { - ch[T] - once sync.Once -} - -func NewSafeChan[T any](size ...int) *SafeChan[T] { - if len(size) == 0 { - return &SafeChan[T]{make(chan T), sync.Once{}} - } - return &SafeChan[T]{make(chan T, size[0]), sync.Once{}} -} - -func (s *SafeChan[T]) Listen() (t T) { - t = <-s.ch - return -} - -func (s *SafeChan[T]) Send(t T) { - s.ch <- t -} - -func (s *SafeChan[T]) Close() { - s.once.Do(func() { - close(s.ch) - }) -} - -func Paging[T any](arr []T, offset, limit int) []T { - return arr[TernaryForm((offset)*limit <= len(arr), (offset)*limit, len(arr)):TernaryForm((offset+1)*limit <= len(arr), (offset+1)*limit, len(arr))] -} diff --git a/gvalue/lvalue.go b/gvalue/gvalue.go similarity index 100% rename from gvalue/lvalue.go rename to gvalue/gvalue.go