forge (work in progress): copy ptr package from go-schema
This commit is contained in:
parent
fc5f140059
commit
1487629123
4 changed files with 339 additions and 0 deletions
38
common/ptr/ptr.go
Normal file
38
common/ptr/ptr.go
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
// Package ptr provides a generic interface for accessing an ordered
|
||||||
|
// collection of values sequentially, updating it and appending to it
|
||||||
|
// using a pointer (or cursor) type that keeps track of the current
|
||||||
|
// position. There are also implementations based on single
|
||||||
|
// scalar values, object attributes, or accessors.
|
||||||
|
package ptr
|
||||||
|
|
||||||
|
type Ptr[V any] interface {
|
||||||
|
Append(V) Ptr[V]
|
||||||
|
Insert(V, int) Ptr[V]
|
||||||
|
Next() Ptr[V]
|
||||||
|
Value() V
|
||||||
|
Set(V) Ptr[V]
|
||||||
|
Size() int
|
||||||
|
Started() bool
|
||||||
|
Seek(int) Ptr[V]
|
||||||
|
Reset() Ptr[V]
|
||||||
|
Clone() Ptr[V]
|
||||||
|
New() Ptr[V]
|
||||||
|
Copy() Ptr[V]
|
||||||
|
}
|
||||||
|
|
||||||
|
// generic functions
|
||||||
|
|
||||||
|
func New[V any](p Ptr[V]) Ptr[V] {
|
||||||
|
np := p.Clone()
|
||||||
|
np.Reset()
|
||||||
|
return np
|
||||||
|
}
|
||||||
|
|
||||||
|
func Copy[V any](p, np Ptr[V]) Ptr[V] {
|
||||||
|
op := p.New()
|
||||||
|
for op.Next() != nil {
|
||||||
|
np.Append(op.Value())
|
||||||
|
}
|
||||||
|
np.Reset()
|
||||||
|
return np
|
||||||
|
}
|
130
common/ptr/scalar.go
Normal file
130
common/ptr/scalar.go
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
package ptr
|
||||||
|
|
||||||
|
// scb: scalar base / common stuff
|
||||||
|
|
||||||
|
type scb[V any] struct {
|
||||||
|
started bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *scb[V]) Size() int {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *scb[V]) Started() bool {
|
||||||
|
return p.started
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *scb[V]) Append(v V) Ptr[V] {
|
||||||
|
p.started = true
|
||||||
|
return p.Set(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *scb[V]) Insert(v V, pos int) Ptr[V] {
|
||||||
|
return p.Append(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *scb[V]) Next() Ptr[V] {
|
||||||
|
if p.started {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
p.started = true
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *scb[V]) Value() V {
|
||||||
|
var v V
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *scb[V]) Set(v V) Ptr[V] {
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *scb[V]) Seek(i int) Ptr[V] {
|
||||||
|
p.started = true
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *scb[V]) Reset() Ptr[V] {
|
||||||
|
p.started = false
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *scb[V]) Clone() Ptr[V] {
|
||||||
|
return &scb[V]{p.started}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *scb[V]) New() Ptr[V] {
|
||||||
|
return New[V](p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *scb[V]) Copy() Ptr[V] {
|
||||||
|
return Copy[V](p, &scb[V]{false})
|
||||||
|
}
|
||||||
|
|
||||||
|
// scalar implementation using a value pointer
|
||||||
|
|
||||||
|
func NewScalar[V any]() Ptr[V] {
|
||||||
|
var v V
|
||||||
|
return NewVP(&v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewVP[V any](vp *V) Ptr[V] {
|
||||||
|
get := func() V {
|
||||||
|
return *vp
|
||||||
|
}
|
||||||
|
set := func(v V) {
|
||||||
|
*vp = v
|
||||||
|
}
|
||||||
|
return NewAcc(get, set)
|
||||||
|
}
|
||||||
|
|
||||||
|
// scalar implementation using accessor functions
|
||||||
|
|
||||||
|
type acc[V any] struct {
|
||||||
|
*scb[V]
|
||||||
|
getter func() V
|
||||||
|
setter func(v V)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAcc[V any](g func() V, s func(v V)) *acc[V] {
|
||||||
|
return &acc[V]{
|
||||||
|
getter: g,
|
||||||
|
setter: s,
|
||||||
|
scb: &scb[V]{false},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *acc[V]) Append(v V) Ptr[V] {
|
||||||
|
p.started = true
|
||||||
|
return p.Set(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *acc[V]) Insert(v V, pos int) Ptr[V] {
|
||||||
|
return p.Append(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *acc[V]) Value() V {
|
||||||
|
return p.getter()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *acc[V]) Set(v V) Ptr[V] {
|
||||||
|
p.setter(v)
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *acc[V]) Clone() Ptr[V] {
|
||||||
|
return &acc[V]{
|
||||||
|
getter: p.getter,
|
||||||
|
setter: p.setter,
|
||||||
|
scb: &scb[V]{p.started},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *acc[V]) New() Ptr[V] {
|
||||||
|
return New[V](p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *acc[V]) Copy() Ptr[V] {
|
||||||
|
return Copy[V](p, NewScalar[V]())
|
||||||
|
}
|
94
common/ptr/slice.go
Normal file
94
common/ptr/slice.go
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
package ptr
|
||||||
|
|
||||||
|
// slice-based implementation
|
||||||
|
|
||||||
|
type sliceseq[V any] []V
|
||||||
|
|
||||||
|
type sptr[V any] struct {
|
||||||
|
seq *sliceseq[V]
|
||||||
|
offset int
|
||||||
|
}
|
||||||
|
|
||||||
|
func newSliceSeq[V any]() *sliceseq[V] {
|
||||||
|
return &sliceseq[V]{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSlice[V any]() *sptr[V] {
|
||||||
|
return &sptr[V]{
|
||||||
|
seq: newSliceSeq[V](),
|
||||||
|
offset: -1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ptr methods
|
||||||
|
|
||||||
|
func (p *sptr[V]) Append(v V) Ptr[V] {
|
||||||
|
*p.seq = append(*p.seq, v)
|
||||||
|
p.offset = len(*p.seq) - 1
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *sptr[V]) Insert(v V, pos int) Ptr[V] {
|
||||||
|
lidx := len(*p.seq) - 1
|
||||||
|
if lidx < pos {
|
||||||
|
return p.Append(v)
|
||||||
|
}
|
||||||
|
*p.seq = append(*p.seq, (*p.seq)[lidx])
|
||||||
|
for i := lidx; i > pos; i -= 1 {
|
||||||
|
(*p.seq)[i] = (*p.seq)[i-1]
|
||||||
|
}
|
||||||
|
(*p.seq)[pos] = v
|
||||||
|
p.offset = pos
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *sptr[V]) Next() Ptr[V] {
|
||||||
|
if p.offset < len(*p.seq)-1 {
|
||||||
|
p.offset += 1
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *sptr[V]) Value() V {
|
||||||
|
return (*p.seq)[p.offset]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *sptr[V]) Set(v V) Ptr[V] {
|
||||||
|
(*p.seq)[p.offset] = v
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *sptr[V]) Size() int {
|
||||||
|
return len(*p.seq)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *sptr[V]) Started() bool {
|
||||||
|
return p.offset >= 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *sptr[V]) Seek(i int) Ptr[V] {
|
||||||
|
p.offset = i
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *sptr[V]) Reset() Ptr[V] {
|
||||||
|
p.offset = -1
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *sptr[V]) Clone() Ptr[V] {
|
||||||
|
return &sptr[V]{
|
||||||
|
seq: p.seq,
|
||||||
|
offset: p.offset,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *sptr[V]) New() Ptr[V] {
|
||||||
|
return New[V](p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *sptr[V]) Copy() Ptr[V] {
|
||||||
|
np := NewSlice[V]()
|
||||||
|
return Copy[V](p, np)
|
||||||
|
}
|
|
@ -3,6 +3,7 @@ package scopes_test
|
||||||
import (
|
import (
|
||||||
tbase "testing"
|
tbase "testing"
|
||||||
|
|
||||||
|
"git.sr.ht/~cco/go-scopes/common/ptr"
|
||||||
"git.sr.ht/~cco/go-scopes/common/stack"
|
"git.sr.ht/~cco/go-scopes/common/stack"
|
||||||
"git.sr.ht/~cco/go-scopes/common/testing"
|
"git.sr.ht/~cco/go-scopes/common/testing"
|
||||||
"git.sr.ht/~cco/go-scopes/common/voc"
|
"git.sr.ht/~cco/go-scopes/common/voc"
|
||||||
|
@ -12,6 +13,9 @@ func TestCommon(tb *tbase.T) {
|
||||||
t := testing.SetUp(tb)
|
t := testing.SetUp(tb)
|
||||||
t.Run("stack", StackTest)
|
t.Run("stack", StackTest)
|
||||||
t.Run("voc", VocTest)
|
t.Run("voc", VocTest)
|
||||||
|
t.Run("ptr-value", PtrValuePointerTest)
|
||||||
|
t.Run("ptr-scalar", PtrScalarTest)
|
||||||
|
t.Run("ptr-slice", PtrSliceTest)
|
||||||
}
|
}
|
||||||
|
|
||||||
func StackTest(t *testing.T) {
|
func StackTest(t *testing.T) {
|
||||||
|
@ -42,3 +46,76 @@ func VocTest(t *testing.T) {
|
||||||
m = v1.Lookup("two")
|
m = v1.Lookup("two")
|
||||||
t.AssertEqual(m.IsNothing(), true)
|
t.AssertEqual(m.IsNothing(), true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func PtrValuePointerTest(t *testing.T) {
|
||||||
|
var v int
|
||||||
|
var sp1 ptr.Ptr[int] = ptr.NewVP[int](&v)
|
||||||
|
sp1.Append(11)
|
||||||
|
t.AssertEqual(sp1.Value(), 11)
|
||||||
|
t.AssertEqual(sp1.Next(), nil)
|
||||||
|
sp2 := sp1.Copy()
|
||||||
|
t.AssertEqual(sp2.Value(), 11)
|
||||||
|
sp2.Set(42)
|
||||||
|
t.AssertEqual(sp2.Value(), 42)
|
||||||
|
t.AssertEqual(sp1.Value(), 11)
|
||||||
|
sp3 := sp1.Clone()
|
||||||
|
t.AssertEqual(sp3.Value(), 11)
|
||||||
|
sp3.Set(46)
|
||||||
|
t.AssertEqual(sp3.Value(), 46)
|
||||||
|
t.AssertEqual(sp1.Value(), 46)
|
||||||
|
}
|
||||||
|
|
||||||
|
func PtrScalarTest(t *testing.T) {
|
||||||
|
var sp1 ptr.Ptr[int] = ptr.NewScalar[int]()
|
||||||
|
sp1.Append(11)
|
||||||
|
t.AssertEqual(sp1.Value(), 11)
|
||||||
|
t.AssertEqual(sp1.Next(), nil)
|
||||||
|
sp2 := sp1.Copy()
|
||||||
|
t.AssertEqual(sp2.Value(), 11)
|
||||||
|
sp2.Set(42)
|
||||||
|
t.AssertEqual(sp2.Value(), 42)
|
||||||
|
t.AssertEqual(sp1.Value(), 11)
|
||||||
|
sp3 := sp1.Clone()
|
||||||
|
t.AssertEqual(sp3.Value(), 11)
|
||||||
|
sp3.Set(46)
|
||||||
|
t.AssertEqual(sp3.Value(), 46)
|
||||||
|
t.AssertEqual(sp1.Value(), 46)
|
||||||
|
}
|
||||||
|
|
||||||
|
func PtrSliceTest(t *testing.T) {
|
||||||
|
var sp1 ptr.Ptr[int] = ptr.NewSlice[int]()
|
||||||
|
sp1.Append(11)
|
||||||
|
t.AssertEqual(sp1.Value(), 11)
|
||||||
|
t.AssertEqual(sp1.Next(), nil)
|
||||||
|
sp1.Append(12)
|
||||||
|
t.AssertEqual(sp1.Size(), 2)
|
||||||
|
sp1.Reset()
|
||||||
|
t.AssertEqual(sp1.Next().Value(), 11)
|
||||||
|
t.AssertEqual(sp1.Value(), 11)
|
||||||
|
sp1.Append(13)
|
||||||
|
t.AssertEqual(sp1.Value(), 13)
|
||||||
|
sp2 := sp1.Clone()
|
||||||
|
t.AssertEqual(sp2.Value(), 13)
|
||||||
|
sp2.Set(31)
|
||||||
|
t.AssertEqual(sp2.Value(), 31)
|
||||||
|
t.AssertEqual(sp1.Value(), 31)
|
||||||
|
sp1.Append(14)
|
||||||
|
t.AssertEqual(sp1.Size(), 4)
|
||||||
|
t.AssertEqual(sp2.Size(), 4)
|
||||||
|
t.AssertEqual(sp1.Value(), 14)
|
||||||
|
t.AssertEqual(sp2.Value(), 31)
|
||||||
|
sp3 := sp2.New()
|
||||||
|
sp3.Next()
|
||||||
|
t.AssertEqual(sp3.Value(), 11)
|
||||||
|
sp3.Append(15)
|
||||||
|
t.AssertEqual(sp1.Size(), 5)
|
||||||
|
sp1.Next()
|
||||||
|
t.AssertEqual(sp1.Value(), 15)
|
||||||
|
t.AssertEqual(sp1.Size(), 5)
|
||||||
|
sp1.Insert(99, 1)
|
||||||
|
t.AssertEqual(sp1.Value(), 99)
|
||||||
|
sp1.Next()
|
||||||
|
t.AssertEqual(sp1.Value(), 12)
|
||||||
|
sp1.Reset()
|
||||||
|
t.AssertEqual(sp1.Next().Value(), 11)
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue