Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,3 +150,10 @@ To propose a new idea or package, please open an issue or discussion with:
## License

[MIT](./LICENSE)

---

## TODO common repo

- [ ] Add linter in ci
- [ ] Add go sec in ci
2 changes: 1 addition & 1 deletion concurrency/go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/lif0/pkg/concurrency

go 1.22
go 1.19

require github.com/stretchr/testify v1.11.1

Expand Down
2 changes: 1 addition & 1 deletion sync/go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/lif0/pkg/sync

go 1.18
go 1.19

require (
github.com/petermattis/goid v0.0.0-20250904145737-900bdf8bb490
Expand Down
8 changes: 4 additions & 4 deletions sync/reentrant_mutex_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package sync

import (
"math/rand/v2"
"math/rand"
"sync"
"testing"
"time"
Expand Down Expand Up @@ -72,7 +72,7 @@ func TestMutualExclusion(t *testing.T) {
defer wg.Done()

rm.Lock()
v[rand.N[int](10e9)]++
v[rand.Intn(10e9)]++
defer rm.Unlock()
}()
}
Expand Down Expand Up @@ -233,7 +233,7 @@ func TestMutexPerformance(t *testing.T) {
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
mx.Lock()
v[rand.N[int](10e9)]++
v[rand.Intn(10e9)]++
mx.Unlock()
}
})
Expand All @@ -250,7 +250,7 @@ func TestMutexPerformance(t *testing.T) {
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
mx.Lock()
v[rand.N[int](10e9)]++
v[rand.Intn(10e9)]++
mx.Unlock()
}
})
Expand Down
7 changes: 7 additions & 0 deletions utils/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed
### Changed

## [v2.1.0] 2025-11-XX
### Added
- Set minimum go version as 1.23
- Add struct OrderedMap[K]V;
### Fixed
### Changed

## [v2.0.0] 2025-10-23
### Added
- Set minimum go version as 1.22
Expand Down
58 changes: 57 additions & 1 deletion utils/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
- [Examples](#-examples)
- [Package: `errx`](#-package-errx)
- [MultiError](#multierror)
- [Package: `typex`](#-package-typex)
- [OrderedMap](#multierror)
- [Roadmap](#️-roadmap)
- [License](#-license)

Expand All @@ -34,7 +36,7 @@ For full documentation, see [https://pkg.go.dev/github.com/lif0/pkg/utils](https

## ⚙️ Requirements

- **go 1.22 or higher**
- **go 1.23 or higher**

## 📦 Installation

Expand Down Expand Up @@ -169,6 +171,8 @@ size := EstimatePayloadOf(&arr)

## 📚 Package `errx`

Provide additional feature for error.

### MultiError

MultiError is a slice of errors implementing the error interface.
Expand Down Expand Up @@ -210,6 +214,58 @@ for _, job := range jobs {
return me.MaybeUnwrap()
```

## 📚 Package `typex`

Provide additional golang type.

### OrderedMap

OrderedMap is a map[Type]Type1-like collection that preserves the order in which keys were inserted. It behaves like a regular map but allows deterministic iteration over its elements.

Useful:
Imagine you are making a closer or graceful shutdown lib, and you need to register/unregister some functions/service in it, and finally handle them in the order they were added. Use it structure. You are welcome🤗

The structure provide provice

#### API

| Func | Complexity (time / mem) |
| -------------------------------------------------------------- | ---------------------------- |
| `(m *OrderedMap[K, V]) Get(key K) (V, bool)` | O(1) / O(1) |
| `(m *OrderedMap[K, V]) Put(key K, value V)` | O(1) / O(1) |
| `(m *OrderedMap[K, V]) Delete(key K)` | O(1) / O(1) |
| `(m *OrderedMap[K, V]) GetValues() []V` | O(N) / O(N) |
| `(m *OrderedMap[K, V]) Iter() []V` | for i,v := range m.Iter() {} |
| `Delete[K comparable, V any](m *OrderedMap[K, V], key K)` | O(1) / O(1) |


#### Benchmark

???

#### Examples

```go
import "github.com/lif0/pkg/utils/typex"


func main() {
m := typex.NewOrderedMap[string, int]()

m.Put("key", 10)

v, ok := m.Get("key") // v = 10

m.Delete("key") // or build-in func typex.Delete(m, "key")

for i,v := range m.Iter() {
fmt.Println(i,v)
}

fmt.Println( len( m.GetValues() ) ) // will be print '0'
}
```

## 🗺️ Roadmap

The future direction of this package is community-driven! Ideas and contributions are highly welcome.
Expand Down
2 changes: 1 addition & 1 deletion utils/go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/lif0/pkg/utils

go 1.22
go 1.19

require github.com/stretchr/testify v1.11.1

Expand Down
83 changes: 83 additions & 0 deletions utils/internal/linked_list.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package internal

type LinkedList[T any] struct {
size int
head *Node[T]
tail *Node[T]
}

type Node[T any] struct {
Val T
Prev *Node[T]
Next *Node[T]
}

// Remove ...
// time: O(1); mem: O(1)
func (l *LinkedList[T]) Remove(node *Node[T]) {
if node == nil {
return
}

// If a previous node exists, link it to the next one, skipping the current node.
if node.Prev != nil {
node.Prev.Next = node.Next
}

// If a next node exists, set its previous pointer to the current node’s previous.
if node.Next != nil {
node.Next.Prev = node.Prev
}

// if the node and the head is equal, set to head node's next.
if node == l.head {
l.head = l.head.Next
}

// if the node and the tail is equal, set to tail node's previous.
if node == l.tail {
l.tail = l.tail.Prev
}

l.size -= 1
}

// Append ...
// time: O(1); mem: O(1)
func (l *LinkedList[T]) Append(node *Node[T]) {
if l.tail == nil {
l.head = node
l.tail = node
} else {
l.tail.Next = node
node.Prev = l.tail
l.tail = node
}

l.size += 1
}

// GetHead ...
// time: O(1); mem: O(1)
func (l *LinkedList[T]) GetHead() *Node[T] {
return l.head
}

// Len ...
// time: O(1); mem: O(1)
func (l *LinkedList[T]) Len() int {
return l.size
}

// Iter ...
func (l *LinkedList[T]) Iter() func(func(int, T) bool) {
return func(yield func(int, T) bool) {
i := 0
for n := l.head; n != nil; n = n.Next {
if !yield(i, n.Val) {
return
}
i++
}
}
}
Loading
Loading