This commit is contained in:
@@ -0,0 +1,164 @@
|
|||||||
|
package dataext
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"iter"
|
||||||
|
)
|
||||||
|
|
||||||
|
// OrderedMap is like a normal map[TKey, TVal] - but its elements stay in order
|
||||||
|
type OrderedMap[TKey comparable, TVal any] struct {
|
||||||
|
m map[TKey]*TVal
|
||||||
|
a []TKey
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewOrderedMap[TKey comparable, TVal any](cap int) *OrderedMap[TKey, TVal] {
|
||||||
|
return &OrderedMap[TKey, TVal]{
|
||||||
|
m: make(map[TKey]*TVal, cap),
|
||||||
|
a: make([]TKey, 0, cap),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OrderedMap[TKey, TVal]) Get(key TKey) (TVal, bool) {
|
||||||
|
v, ok := o.m[key]
|
||||||
|
if ok {
|
||||||
|
return *v, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
return *new(TVal), false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OrderedMap[TKey, TVal]) GetOrNil(key TKey) *TVal {
|
||||||
|
v, ok := o.m[key]
|
||||||
|
if ok {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OrderedMap[TKey, TVal]) GetOrDefault(key TKey, defaultVal TVal) TVal {
|
||||||
|
v, ok := o.m[key]
|
||||||
|
if ok {
|
||||||
|
return *v
|
||||||
|
}
|
||||||
|
|
||||||
|
return defaultVal
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add adds the new value to the map
|
||||||
|
// At the end of the map-ordering (even if key already exists, its then "moved" to the end)
|
||||||
|
// returns true if key already existed
|
||||||
|
func (o *OrderedMap[TKey, TVal]) Add(key TKey, val TVal) bool {
|
||||||
|
if _, ok := o.m[key]; ok {
|
||||||
|
o.remFromArray(key)
|
||||||
|
o.m[key] = &val
|
||||||
|
o.a = append(o.a, key)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
o.m[key] = &val
|
||||||
|
o.a = append(o.a, key)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddOrReplace adds the new value to the map
|
||||||
|
// Normally at the end of the map, but if teh key already exists, its only replaced
|
||||||
|
// returns true if key already existed
|
||||||
|
func (o *OrderedMap[TKey, TVal]) AddOrReplace(key TKey, val TVal) bool {
|
||||||
|
if _, ok := o.m[key]; ok {
|
||||||
|
o.m[key] = &val
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
o.m[key] = &val
|
||||||
|
o.a = append(o.a, key)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OrderedMap[TKey, TVal]) Remove(key TKey) bool {
|
||||||
|
if _, ok := o.m[key]; ok {
|
||||||
|
o.remFromArray(key)
|
||||||
|
delete(o.m, key)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OrderedMap[TKey, TVal]) Iterate() iter.Seq[TVal] {
|
||||||
|
return func(yield func(TVal) bool) {
|
||||||
|
for _, v := range o.a {
|
||||||
|
if !yield(*o.m[v]) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OrderedMap[TKey, TVal]) IterateKeys() iter.Seq[TKey] {
|
||||||
|
return func(yield func(TKey) bool) {
|
||||||
|
for _, v := range o.a {
|
||||||
|
if !yield(v) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OrderedMap[TKey, TVal]) Array() []TVal {
|
||||||
|
res := make([]TVal, len(o.a))
|
||||||
|
for i, v := range o.a {
|
||||||
|
res[i] = *o.m[v]
|
||||||
|
}
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OrderedMap[TKey, TVal]) Keys() []TKey {
|
||||||
|
res := make([]TKey, len(o.a))
|
||||||
|
for i, v := range o.a {
|
||||||
|
res[i] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OrderedMap[TKey, TVal]) Clear() {
|
||||||
|
mapCap := max(len(o.m), cap(o.a))
|
||||||
|
o.m = make(map[TKey]*TVal, mapCap)
|
||||||
|
o.a = make([]TKey, 0, mapCap)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OrderedMap[TKey, TVal]) Size() int {
|
||||||
|
return len(o.a)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OrderedMap[TKey, TVal]) Capacity() int {
|
||||||
|
return min(cap(o.a), len(o.m))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OrderedMap[TKey, TVal]) Contains(key TKey) bool {
|
||||||
|
_, ok := o.m[key]
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OrderedMap[TKey, TVal]) IndexOf(key TKey) int {
|
||||||
|
for i, v := range o.a {
|
||||||
|
if v == key {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OrderedMap[TKey, TVal]) remFromArray(key TKey) {
|
||||||
|
for i, v := range o.a {
|
||||||
|
if v == key {
|
||||||
|
o.a = append(o.a[:i], o.a[i+1:]...)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
panic(fmt.Sprintf("Failed to remove key from OrderedMap -- key '%v' not found", key))
|
||||||
|
}
|
||||||
@@ -0,0 +1,358 @@
|
|||||||
|
package dataext
|
||||||
|
|
||||||
|
import (
|
||||||
|
"slices"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"git.blackforestbytes.com/BlackForestBytes/goext/tst"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestOrderedMapNew(t *testing.T) {
|
||||||
|
m := NewOrderedMap[string, int](4)
|
||||||
|
|
||||||
|
tst.AssertEqual(t, m.Size(), 0)
|
||||||
|
tst.AssertArrayEqual(t, m.Keys(), []string{})
|
||||||
|
tst.AssertArrayEqual(t, m.Array(), []int{})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOrderedMapAddAndGet(t *testing.T) {
|
||||||
|
m := NewOrderedMap[string, int](0)
|
||||||
|
|
||||||
|
tst.AssertFalse(t, m.Add("a", 1))
|
||||||
|
tst.AssertFalse(t, m.Add("b", 2))
|
||||||
|
tst.AssertFalse(t, m.Add("c", 3))
|
||||||
|
|
||||||
|
tst.AssertEqual(t, m.Size(), 3)
|
||||||
|
|
||||||
|
v, ok := m.Get("a")
|
||||||
|
tst.AssertTrue(t, ok)
|
||||||
|
tst.AssertEqual(t, v, 1)
|
||||||
|
|
||||||
|
v, ok = m.Get("b")
|
||||||
|
tst.AssertTrue(t, ok)
|
||||||
|
tst.AssertEqual(t, v, 2)
|
||||||
|
|
||||||
|
v, ok = m.Get("c")
|
||||||
|
tst.AssertTrue(t, ok)
|
||||||
|
tst.AssertEqual(t, v, 3)
|
||||||
|
|
||||||
|
v, ok = m.Get("missing")
|
||||||
|
tst.AssertFalse(t, ok)
|
||||||
|
tst.AssertEqual(t, v, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOrderedMapOrderPreserved(t *testing.T) {
|
||||||
|
m := NewOrderedMap[string, int](0)
|
||||||
|
|
||||||
|
m.Add("first", 1)
|
||||||
|
m.Add("second", 2)
|
||||||
|
m.Add("third", 3)
|
||||||
|
m.Add("fourth", 4)
|
||||||
|
|
||||||
|
tst.AssertArrayEqual(t, m.Keys(), []string{"first", "second", "third", "fourth"})
|
||||||
|
tst.AssertArrayEqual(t, m.Array(), []int{1, 2, 3, 4})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOrderedMapAddMovesExistingToEnd(t *testing.T) {
|
||||||
|
m := NewOrderedMap[string, int](0)
|
||||||
|
|
||||||
|
m.Add("a", 1)
|
||||||
|
m.Add("b", 2)
|
||||||
|
m.Add("c", 3)
|
||||||
|
|
||||||
|
tst.AssertTrue(t, m.Add("a", 10))
|
||||||
|
|
||||||
|
tst.AssertArrayEqual(t, m.Keys(), []string{"b", "c", "a"})
|
||||||
|
tst.AssertArrayEqual(t, m.Array(), []int{2, 3, 10})
|
||||||
|
|
||||||
|
v, ok := m.Get("a")
|
||||||
|
tst.AssertTrue(t, ok)
|
||||||
|
tst.AssertEqual(t, v, 10)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOrderedMapAddOrReplaceKeepsOrder(t *testing.T) {
|
||||||
|
m := NewOrderedMap[string, int](0)
|
||||||
|
|
||||||
|
m.Add("a", 1)
|
||||||
|
m.Add("b", 2)
|
||||||
|
m.Add("c", 3)
|
||||||
|
|
||||||
|
tst.AssertTrue(t, m.AddOrReplace("b", 99))
|
||||||
|
|
||||||
|
tst.AssertArrayEqual(t, m.Keys(), []string{"a", "b", "c"})
|
||||||
|
tst.AssertArrayEqual(t, m.Array(), []int{1, 99, 3})
|
||||||
|
|
||||||
|
v, ok := m.Get("b")
|
||||||
|
tst.AssertTrue(t, ok)
|
||||||
|
tst.AssertEqual(t, v, 99)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOrderedMapAddOrReplaceNew(t *testing.T) {
|
||||||
|
m := NewOrderedMap[string, int](0)
|
||||||
|
|
||||||
|
tst.AssertFalse(t, m.AddOrReplace("a", 1))
|
||||||
|
tst.AssertFalse(t, m.AddOrReplace("b", 2))
|
||||||
|
|
||||||
|
tst.AssertArrayEqual(t, m.Keys(), []string{"a", "b"})
|
||||||
|
tst.AssertArrayEqual(t, m.Array(), []int{1, 2})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOrderedMapGetOrNil(t *testing.T) {
|
||||||
|
m := NewOrderedMap[string, int](0)
|
||||||
|
m.Add("a", 42)
|
||||||
|
|
||||||
|
v := m.GetOrNil("a")
|
||||||
|
if v == nil {
|
||||||
|
t.Errorf("expected non-nil pointer")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
tst.AssertEqual(t, *v, 42)
|
||||||
|
|
||||||
|
v = m.GetOrNil("missing")
|
||||||
|
if v != nil {
|
||||||
|
t.Errorf("expected nil pointer")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOrderedMapGetOrDefault(t *testing.T) {
|
||||||
|
m := NewOrderedMap[string, int](0)
|
||||||
|
m.Add("a", 42)
|
||||||
|
|
||||||
|
tst.AssertEqual(t, m.GetOrDefault("a", -1), 42)
|
||||||
|
tst.AssertEqual(t, m.GetOrDefault("missing", -1), -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOrderedMapRemove(t *testing.T) {
|
||||||
|
m := NewOrderedMap[string, int](0)
|
||||||
|
|
||||||
|
m.Add("a", 1)
|
||||||
|
m.Add("b", 2)
|
||||||
|
m.Add("c", 3)
|
||||||
|
|
||||||
|
tst.AssertTrue(t, m.Remove("b"))
|
||||||
|
|
||||||
|
tst.AssertEqual(t, m.Size(), 2)
|
||||||
|
tst.AssertArrayEqual(t, m.Keys(), []string{"a", "c"})
|
||||||
|
tst.AssertArrayEqual(t, m.Array(), []int{1, 3})
|
||||||
|
|
||||||
|
_, ok := m.Get("b")
|
||||||
|
tst.AssertFalse(t, ok)
|
||||||
|
tst.AssertFalse(t, m.Contains("b"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOrderedMapRemoveMissing(t *testing.T) {
|
||||||
|
m := NewOrderedMap[string, int](0)
|
||||||
|
|
||||||
|
m.Add("a", 1)
|
||||||
|
tst.AssertFalse(t, m.Remove("missing"))
|
||||||
|
|
||||||
|
tst.AssertEqual(t, m.Size(), 1)
|
||||||
|
tst.AssertArrayEqual(t, m.Keys(), []string{"a"})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOrderedMapRemoveFirstAndLast(t *testing.T) {
|
||||||
|
m := NewOrderedMap[string, int](0)
|
||||||
|
|
||||||
|
m.Add("a", 1)
|
||||||
|
m.Add("b", 2)
|
||||||
|
m.Add("c", 3)
|
||||||
|
m.Add("d", 4)
|
||||||
|
|
||||||
|
tst.AssertTrue(t, m.Remove("a"))
|
||||||
|
tst.AssertTrue(t, m.Remove("d"))
|
||||||
|
|
||||||
|
tst.AssertArrayEqual(t, m.Keys(), []string{"b", "c"})
|
||||||
|
tst.AssertArrayEqual(t, m.Array(), []int{2, 3})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOrderedMapContains(t *testing.T) {
|
||||||
|
m := NewOrderedMap[string, int](0)
|
||||||
|
m.Add("a", 1)
|
||||||
|
|
||||||
|
tst.AssertTrue(t, m.Contains("a"))
|
||||||
|
tst.AssertFalse(t, m.Contains("b"))
|
||||||
|
|
||||||
|
m.Remove("a")
|
||||||
|
tst.AssertFalse(t, m.Contains("a"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOrderedMapIndexOf(t *testing.T) {
|
||||||
|
m := NewOrderedMap[string, int](0)
|
||||||
|
m.Add("a", 1)
|
||||||
|
m.Add("b", 2)
|
||||||
|
m.Add("c", 3)
|
||||||
|
|
||||||
|
tst.AssertEqual(t, m.IndexOf("a"), 0)
|
||||||
|
tst.AssertEqual(t, m.IndexOf("b"), 1)
|
||||||
|
tst.AssertEqual(t, m.IndexOf("c"), 2)
|
||||||
|
tst.AssertEqual(t, m.IndexOf("missing"), -1)
|
||||||
|
|
||||||
|
m.Add("a", 10) // moves to end
|
||||||
|
tst.AssertEqual(t, m.IndexOf("a"), 2)
|
||||||
|
tst.AssertEqual(t, m.IndexOf("b"), 0)
|
||||||
|
tst.AssertEqual(t, m.IndexOf("c"), 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOrderedMapClear(t *testing.T) {
|
||||||
|
m := NewOrderedMap[string, int](0)
|
||||||
|
m.Add("a", 1)
|
||||||
|
m.Add("b", 2)
|
||||||
|
m.Add("c", 3)
|
||||||
|
|
||||||
|
m.Clear()
|
||||||
|
|
||||||
|
tst.AssertEqual(t, m.Size(), 0)
|
||||||
|
tst.AssertArrayEqual(t, m.Keys(), []string{})
|
||||||
|
tst.AssertArrayEqual(t, m.Array(), []int{})
|
||||||
|
tst.AssertFalse(t, m.Contains("a"))
|
||||||
|
|
||||||
|
m.Add("x", 99)
|
||||||
|
tst.AssertEqual(t, m.Size(), 1)
|
||||||
|
tst.AssertArrayEqual(t, m.Keys(), []string{"x"})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOrderedMapSize(t *testing.T) {
|
||||||
|
m := NewOrderedMap[string, int](0)
|
||||||
|
tst.AssertEqual(t, m.Size(), 0)
|
||||||
|
|
||||||
|
m.Add("a", 1)
|
||||||
|
tst.AssertEqual(t, m.Size(), 1)
|
||||||
|
|
||||||
|
m.Add("b", 2)
|
||||||
|
tst.AssertEqual(t, m.Size(), 2)
|
||||||
|
|
||||||
|
m.Add("a", 10) // replaces, size stays
|
||||||
|
tst.AssertEqual(t, m.Size(), 2)
|
||||||
|
|
||||||
|
m.AddOrReplace("b", 20) // replaces, size stays
|
||||||
|
tst.AssertEqual(t, m.Size(), 2)
|
||||||
|
|
||||||
|
m.Remove("a")
|
||||||
|
tst.AssertEqual(t, m.Size(), 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOrderedMapIterate(t *testing.T) {
|
||||||
|
m := NewOrderedMap[string, int](0)
|
||||||
|
m.Add("a", 1)
|
||||||
|
m.Add("b", 2)
|
||||||
|
m.Add("c", 3)
|
||||||
|
|
||||||
|
got := make([]int, 0)
|
||||||
|
for v := range m.Iterate() {
|
||||||
|
got = append(got, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
tst.AssertArrayEqual(t, got, []int{1, 2, 3})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOrderedMapIterateBreak(t *testing.T) {
|
||||||
|
m := NewOrderedMap[string, int](0)
|
||||||
|
m.Add("a", 1)
|
||||||
|
m.Add("b", 2)
|
||||||
|
m.Add("c", 3)
|
||||||
|
|
||||||
|
got := make([]int, 0)
|
||||||
|
for v := range m.Iterate() {
|
||||||
|
got = append(got, v)
|
||||||
|
if v == 2 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tst.AssertArrayEqual(t, got, []int{1, 2})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOrderedMapIterateKeys(t *testing.T) {
|
||||||
|
m := NewOrderedMap[string, int](0)
|
||||||
|
m.Add("a", 1)
|
||||||
|
m.Add("b", 2)
|
||||||
|
m.Add("c", 3)
|
||||||
|
|
||||||
|
got := make([]string, 0)
|
||||||
|
for k := range m.IterateKeys() {
|
||||||
|
got = append(got, k)
|
||||||
|
}
|
||||||
|
|
||||||
|
tst.AssertArrayEqual(t, got, []string{"a", "b", "c"})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOrderedMapIterateKeysBreak(t *testing.T) {
|
||||||
|
m := NewOrderedMap[string, int](0)
|
||||||
|
m.Add("a", 1)
|
||||||
|
m.Add("b", 2)
|
||||||
|
m.Add("c", 3)
|
||||||
|
|
||||||
|
got := make([]string, 0)
|
||||||
|
for k := range m.IterateKeys() {
|
||||||
|
got = append(got, k)
|
||||||
|
if k == "b" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tst.AssertArrayEqual(t, got, []string{"a", "b"})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOrderedMapArrayIsCopy(t *testing.T) {
|
||||||
|
m := NewOrderedMap[string, int](0)
|
||||||
|
m.Add("a", 1)
|
||||||
|
m.Add("b", 2)
|
||||||
|
|
||||||
|
arr := m.Array()
|
||||||
|
arr[0] = 999
|
||||||
|
|
||||||
|
tst.AssertArrayEqual(t, m.Array(), []int{1, 2})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOrderedMapKeysIsCopy(t *testing.T) {
|
||||||
|
m := NewOrderedMap[string, int](0)
|
||||||
|
m.Add("a", 1)
|
||||||
|
m.Add("b", 2)
|
||||||
|
|
||||||
|
keys := m.Keys()
|
||||||
|
keys[0] = "zzz"
|
||||||
|
|
||||||
|
tst.AssertArrayEqual(t, m.Keys(), []string{"a", "b"})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOrderedMapIntKey(t *testing.T) {
|
||||||
|
m := NewOrderedMap[int, string](0)
|
||||||
|
m.Add(3, "three")
|
||||||
|
m.Add(1, "one")
|
||||||
|
m.Add(2, "two")
|
||||||
|
|
||||||
|
tst.AssertArrayEqual(t, m.Keys(), []int{3, 1, 2})
|
||||||
|
tst.AssertArrayEqual(t, m.Array(), []string{"three", "one", "two"})
|
||||||
|
|
||||||
|
v, ok := m.Get(1)
|
||||||
|
tst.AssertTrue(t, ok)
|
||||||
|
tst.AssertEqual(t, v, "one")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOrderedMapStress(t *testing.T) {
|
||||||
|
m := NewOrderedMap[int, int](0)
|
||||||
|
|
||||||
|
for i := 0; i < 100; i++ {
|
||||||
|
m.Add(i, i*10)
|
||||||
|
}
|
||||||
|
tst.AssertEqual(t, m.Size(), 100)
|
||||||
|
|
||||||
|
for i := 0; i < 100; i++ {
|
||||||
|
v, ok := m.Get(i)
|
||||||
|
tst.AssertTrue(t, ok)
|
||||||
|
tst.AssertEqual(t, v, i*10)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < 50; i++ {
|
||||||
|
m.Remove(i * 2)
|
||||||
|
}
|
||||||
|
tst.AssertEqual(t, m.Size(), 50)
|
||||||
|
|
||||||
|
expected := make([]int, 0, 50)
|
||||||
|
for i := 0; i < 50; i++ {
|
||||||
|
expected = append(expected, i*2+1)
|
||||||
|
}
|
||||||
|
keys := m.Keys()
|
||||||
|
slices.Sort(keys)
|
||||||
|
tst.AssertArrayEqual(t, keys, expected)
|
||||||
|
}
|
||||||
@@ -41,7 +41,7 @@ require (
|
|||||||
github.com/klauspost/compress v1.18.6 // indirect
|
github.com/klauspost/compress v1.18.6 // indirect
|
||||||
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
|
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
|
||||||
github.com/leodido/go-urn v1.4.0 // indirect
|
github.com/leodido/go-urn v1.4.0 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
github.com/mattn/go-colorable v0.1.15 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.22 // indirect
|
github.com/mattn/go-isatty v0.0.22 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
|
|||||||
@@ -74,6 +74,8 @@ github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
|||||||
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||||
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
|
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
|
||||||
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
||||||
|
github.com/mattn/go-colorable v0.1.15 h1:+u9SLTRGnXv73cEsnsmoZBom+dMU88B2M0aDcWy0/jY=
|
||||||
|
github.com/mattn/go-colorable v0.1.15/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
||||||
github.com/mattn/go-isatty v0.0.21 h1:xYae+lCNBP7QuW4PUnNG61ffM4hVIfm+zUzDuSzYLGs=
|
github.com/mattn/go-isatty v0.0.21 h1:xYae+lCNBP7QuW4PUnNG61ffM4hVIfm+zUzDuSzYLGs=
|
||||||
github.com/mattn/go-isatty v0.0.21/go.mod h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJlRFqopa4=
|
github.com/mattn/go-isatty v0.0.21/go.mod h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJlRFqopa4=
|
||||||
github.com/mattn/go-isatty v0.0.22 h1:j8l17JJ9i6VGPUFUYoTUKPSgKe/83EYU2zBC7YNKMw4=
|
github.com/mattn/go-isatty v0.0.22 h1:j8l17JJ9i6VGPUFUYoTUKPSgKe/83EYU2zBC7YNKMw4=
|
||||||
|
|||||||
+2
-2
@@ -1,5 +1,5 @@
|
|||||||
package goext
|
package goext
|
||||||
|
|
||||||
const GoextVersion = "0.0.642"
|
const GoextVersion = "0.0.643"
|
||||||
|
|
||||||
const GoextVersionTimestamp = "2026-05-27T17:18:10+0200"
|
const GoextVersionTimestamp = "2026-05-30T00:07:10+0200"
|
||||||
|
|||||||
Reference in New Issue
Block a user