Skip to content

Commit

Permalink
feat: add more
Browse files Browse the repository at this point in the history
  • Loading branch information
thinkgos committed Apr 27, 2024
1 parent c85f8fc commit 3959e80
Show file tree
Hide file tree
Showing 20 changed files with 1,071 additions and 37 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

# Dependency directories (remove the comment below to include it)
# vendor/
.idea
.vscode

# Go workspace file
go.work
70 changes: 70 additions & 0 deletions .goreleaser.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# This is an example .goreleaser.yml file with some sensible defaults.
# Make sure to check the documentation at https://goreleaser.com

# The lines below are called `modelines`. See `:help modeline`
# Feel free to remove those if you don't want/need to use them.
# yaml-language-server: $schema=https://goreleaser.com/static/schema.json
# vim: set ts=2 sw=2 tw=0 fo=cnqoj

version: 1

env:
- GO111MODULE=on

snapshot:
name_template: "{{ incpatch .Version }}-next"

# before:
# hooks:
# # You may remove this if you don't use go modules.
# - go mod tidy
# # you may remove this if you don't need go generate
# - go generate ./...

builds:
- main: .
env:
- CGO_ENABLED=0
goos:
- linux
- windows
- darwin
goarch:
- amd64
- arm64
- "386"
- arm
goarm:
- "7"
mod_timestamp: "{{ .CommitTimestamp }}"
flags:
- -trimpath
ldflags:
- -s -w
# If true, skip the build. for library projects.
skip: true

archives:
- name_template: >-
{{ .ProjectName }}_
{{- .Os }}_
{{- if eq .Arch "amd64" }}x86_64
{{- else if eq .Arch "386" }}i386
{{- else }}{{ .Arch }}{{ end }}
{{- if .Arm }}v{{ .Arm }}{{ end }}'
format_overrides:
- goos: windows
format: zip
checksum:
name_template: "checksums.txt"

changelog:
sort: asc
filters:
exclude:
- "^docs:"
- "^test:"
# modelines, feel free to remove those if you don't want/use them:
# yaml-language-server: $schema=https://goreleaser.com/static/schema.json
# vim: set ts=2 sw=2 tw=0 fo=cnqoj
1 change: 1 addition & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@

Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
Expand Down
43 changes: 8 additions & 35 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,37 +1,10 @@
# proc

`proc` annotation syntax.

[![Go.Dev reference](https://img.shields.io/badge/go.dev-reference-blue?logo=go&logoColor=white)](https://pkg.go.dev/github.com/thinkgos/proc?tab=doc)
[![codecov](https://codecov.io/gh/thinkgos/proc/branch/main/graph/badge.svg)](https://codecov.io/gh/thinkgos/proc)
[![Tests](https://github.com/thinkgos/proc/actions/workflows/ci.yml/badge.svg)](https://github.com/thinkgos/proc/actions/workflows/ci.yml)
[![Go Report Card](https://goreportcard.com/badge/github.com/thinkgos/proc)](https://goreportcard.com/report/github.com/thinkgos/proc)
[![License](https://img.shields.io/github/license/thinkgos/proc)](https://github.com/thinkgos/proc/raw/main/LICENSE)
[![Tag](https://img.shields.io/github/v/tag/thinkgos/proc)](https://github.com/thinkgos/proc/tags)

basic syntax:

- `#[ident]`: headless syntax
- `#[ident(name1=value1,name2=value2)]`: no headless syntax

`ident`is a identity, `name=value` slice in the `()`.
`value` support the following syntax

- `string`: `"hello"`
- `integer`: `123`
- `float`: `1.0`
- `bool`: `true`,`false`
- `Object`: `{k1="v1",k2="v2"}`, in the object is `name=value` slice too.
- `string slice`: `["hello","world"]`
- `integer slice`: `[123,12,1]`
- `float slice`: `[1.0,1.1,1.2]`, ***NOTE***: the first value in slice must be a float type, like `[1,1.1,1.2]` will parsed as integer slice, then failure.
- `bool slice`: `[true,false,true]`
- `map[string]Value`: `{k1="v1", k2="v2"}`, the value can be the defined.

example:

- `#[ident]`
- `#[ident(k1=1,k2="2")]`
- `#[ident(k1=[1,2,3],k2=["1","2","3"])]`
- `#[ident(k1="hello",k2=["1","2","3"])]`
- `#[ident(k1={k2="v2",k3="v3"})]`
`proc` Universal toolkit.

[![Go.Dev reference](https://img.shields.io/badge/go.dev-reference-blue?logo=go&logoColor=white)](https://pkg.go.dev/github.com/things-go/proc?tab=doc)
[![codecov](https://codecov.io/gh/things-go/proc/branch/main/graph/badge.svg)](https://codecov.io/gh/things-go/proc)
[![Tests](https://github.com/things-go/proc/actions/workflows/ci.yml/badge.svg)](https://github.com/things-go/proc/actions/workflows/ci.yml)
[![Go Report Card](https://goreportcard.com/badge/github.com/things-go/proc)](https://goreportcard.com/report/github.com/things-go/proc)
[![License](https://img.shields.io/github/license/things-go/proc)](https://github.com/things-go/proc/raw/main/LICENSE)
[![Tag](https://img.shields.io/github/v/tag/things-go/proc)](https://github.com/things-go/proc/tags)
124 changes: 124 additions & 0 deletions collection/sliding_window/sliding_window.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package collection

import (
"sync"
"time"
)

var initTime = time.Now().AddDate(-1, 0, 0)

// SlidingWindowOption customize the SlidingWindow.
type SlidingWindowOption func(*SlidingWindow)

// IgnoreCurrentBucket ignore current bucket.
func IgnoreCurrentBucket() SlidingWindowOption {
return func(s *SlidingWindow) {
s.ignoreCurrent = true
}
}

// SlidingWindow defines a Sliding window to calculate the events in buckets with time interval.
type SlidingWindow struct {
rw sync.RWMutex
ignoreCurrent bool
interval time.Duration
lastTime time.Duration // start time of the last bucket

offset int
size int
buckets []*Bucket
}

// NewSlidingWindow returns a SlidingWindow that with size buckets and time interval,
// use opts to customize the SlidingWindow.
func NewSlidingWindow(size int, interval time.Duration, opts ...SlidingWindowOption) *SlidingWindow {
if size < 1 {
panic("collection: size must be greater than 0")
}
buckets := make([]*Bucket, size)
for i := 0; i < size; i++ {
buckets[i] = new(Bucket)
}
w := &SlidingWindow{
ignoreCurrent: false,
interval: interval,
lastTime: time.Since(initTime),
offset: 0,
size: size,
buckets: buckets,
}
for _, opt := range opts {
opt(w)
}
return w
}

// Add adds value to current bucket.
func (s *SlidingWindow) Add(v float64) *SlidingWindow {
s.rw.Lock()
defer s.rw.Unlock()
s.updateOffset()
s.buckets[s.offset%s.size].add(v)
return s
}

// Reduce runs fn on all buckets, ignore current bucket if ignoreCurrent was set.
func (s *SlidingWindow) Reduce(fn func(b *Bucket)) {
s.rw.RLock()
defer s.rw.RUnlock()

var diff int
span := s.span()
// ignore current bucket, because of partial data
if span == 0 && s.ignoreCurrent {
diff = s.size - 1
} else {
diff = s.size - span
}
if diff > 0 {
offset := (s.offset + span + 1) % s.size
for i := 0; i < diff; i++ {
fn(s.buckets[(offset+i)%s.size])
}
}
}

func (s *SlidingWindow) span() int {
offset := int((time.Since(initTime) - s.lastTime) / s.interval)
if offset >= 0 && offset < s.size {
return offset
}
return s.size
}

func (s *SlidingWindow) updateOffset() {
span := s.span()
offset := s.offset
// reset expired buckets
for i := 0; i < span; i++ {
s.buckets[(offset+i+1)%s.size].reset()
}

s.offset = (offset + span) % s.size
cur := time.Since(initTime)
// align to interval time boundary
s.lastTime = cur - (cur-s.lastTime)%s.interval
}

// Bucket defines the bucket that holds sum and num of additions.
type Bucket struct {
sum float64
count int64
}

func (b *Bucket) add(v float64) {
b.sum += v
b.count++
}

func (b *Bucket) reset() {
b.sum = 0
b.count = 0
}
func (b *Bucket) Sum() float64 { return b.sum }
func (b *Bucket) Count() int64 { return b.count }
Loading

0 comments on commit 3959e80

Please sign in to comment.