-
-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
transientcontainers: add TransientQueue #30
Add type and a 'TransientQueue' global function.
- Loading branch information
Showing
10 changed files
with
409 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package transientcontainers | ||
|
||
import ( | ||
"github.com/inoxlang/inox/internal/core" | ||
"github.com/inoxlang/inox/internal/core/symbolic" | ||
transientsymb "github.com/inoxlang/inox/internal/globals/transientcontainers/symbolic" | ||
"github.com/inoxlang/inox/internal/globals/transientcontainers/transientqueue" | ||
|
||
"github.com/inoxlang/inox/internal/help" | ||
) | ||
|
||
var () | ||
|
||
func init() { | ||
core.RegisterSymbolicGoFunctions([]any{ | ||
transientqueue.NewQueue, func(ctx *symbolic.Context, elements symbolic.Iterable) *transientsymb.TransientQueue { | ||
return &transientsymb.TransientQueue{} | ||
}, | ||
}) | ||
|
||
help.RegisterHelpValues(map[string]any{}) | ||
} | ||
|
||
func NewTransientContainersNamespace() map[string]core.Value { | ||
return map[string]core.Value{ | ||
"TransientQueue": core.ValOf(transientqueue.NewQueue), | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
package transientcontainers | ||
|
||
import ( | ||
"github.com/inoxlang/inox/internal/core/symbolic" | ||
) | ||
|
||
var ( | ||
QUEUE_PROPNAMES = []string{"enqueue", "dequeue", "peek"} | ||
_ = []symbolic.Iterable{(*TransientQueue)(nil)} | ||
_ = []symbolic.PotentiallySharable{(*TransientQueue)(nil)} | ||
) | ||
|
||
type TransientQueue struct { | ||
symbolic.UnassignablePropsMixin | ||
shared bool | ||
} | ||
|
||
func (*TransientQueue) Test(v symbolic.Value, state symbolic.RecTestCallState) bool { | ||
state.StartCall() | ||
defer state.FinishCall() | ||
|
||
_, ok := v.(*TransientQueue) | ||
return ok | ||
} | ||
|
||
func (*TransientQueue) Enqueue(ctx *symbolic.Context, elem symbolic.Value) { | ||
if ok, reason := symbolic.IsSharableOrClonable(elem); !ok { | ||
if reason != "" { | ||
reason = ": " + reason | ||
} | ||
ctx.AddSymbolicGoFunctionError("passed value is not sharable nor clonable" + reason) | ||
} | ||
} | ||
|
||
func (*TransientQueue) Dequeue(ctx *symbolic.Context) (symbolic.Value, *symbolic.Bool) { | ||
return symbolic.ANY, nil | ||
} | ||
|
||
func (*TransientQueue) Peek(ctx *symbolic.Context) (symbolic.Value, *symbolic.Bool) { | ||
return symbolic.ANY, nil | ||
} | ||
|
||
func (*TransientQueue) IteratorElementKey() symbolic.Value { | ||
return symbolic.ANY | ||
} | ||
|
||
func (*TransientQueue) IteratorElementValue() symbolic.Value { | ||
return symbolic.ANY | ||
} | ||
|
||
func (*TransientQueue) WidestOfType() symbolic.Value { | ||
return &TransientQueue{} | ||
} |
48 changes: 48 additions & 0 deletions
48
internal/globals/transientcontainers/symbolic/queue_value_impl.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
package transientcontainers | ||
|
||
import ( | ||
"github.com/inoxlang/inox/internal/core/symbolic" | ||
"github.com/inoxlang/inox/internal/prettyprint" | ||
) | ||
|
||
func (q *TransientQueue) IsMutable() bool { | ||
return true | ||
} | ||
|
||
func (q *TransientQueue) GetGoMethod(name string) (*symbolic.GoFunction, bool) { | ||
switch name { | ||
case "enqueue": | ||
return symbolic.WrapGoMethod(q.Enqueue), true | ||
case "dequeue": | ||
return symbolic.WrapGoMethod(q.Dequeue), true | ||
case "peek": | ||
return symbolic.WrapGoMethod(q.Peek), true | ||
} | ||
return nil, false | ||
} | ||
|
||
func (q *TransientQueue) Prop(name string) symbolic.Value { | ||
return symbolic.GetGoMethodOrPanic(name, q) | ||
} | ||
|
||
func (*TransientQueue) PropertyNames() []string { | ||
return QUEUE_PROPNAMES | ||
} | ||
|
||
func (*TransientQueue) PrettyPrint(w prettyprint.PrettyPrintWriter, config *prettyprint.PrettyPrintConfig) { | ||
w.WriteName("transient-queue") | ||
} | ||
|
||
func (q *TransientQueue) IsSharable() (bool, string) { | ||
return true, "" | ||
} | ||
|
||
func (q *TransientQueue) Share(originState *symbolic.State) symbolic.PotentiallySharable { | ||
copy := *q | ||
copy.shared = true | ||
return © | ||
} | ||
|
||
func (q *TransientQueue) IsShared() bool { | ||
return q.shared | ||
} |
39 changes: 39 additions & 0 deletions
39
internal/globals/transientcontainers/transientqueue/iterator.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package transientqueue | ||
|
||
import ( | ||
"github.com/inoxlang/inox/internal/core" | ||
"github.com/inoxlang/inox/internal/globals/containers/common" | ||
"github.com/inoxlang/inox/internal/memds" | ||
) | ||
|
||
func (s *TransientQueue) Iterator(ctx *core.Context, config core.IteratorConfiguration) core.Iterator { | ||
var it *memds.ArrayQueueIterator[core.Value] | ||
if s.threadUnsafe != nil { | ||
it = s.threadUnsafe.Iterator() | ||
} else { | ||
it = s.threadSafe.Iterator() | ||
} | ||
var next core.Value | ||
|
||
return config.CreateIterator(&common.CollectionIterator{ | ||
HasNext_: func(ci *common.CollectionIterator, ctx *core.Context) bool { | ||
if next == nil { | ||
if !it.Next() { | ||
return false | ||
} | ||
next = it.Value() | ||
} | ||
return true | ||
}, | ||
Next_: func(ci *common.CollectionIterator, ctx *core.Context) bool { | ||
next = nil | ||
return true | ||
}, | ||
Key_: func(ci *common.CollectionIterator, ctx *core.Context) core.Value { | ||
return core.Int(it.Index()) | ||
}, | ||
Value_: func(ci *common.CollectionIterator, ctx *core.Context) core.Value { | ||
return it.Value() | ||
}, | ||
}) | ||
} |
38 changes: 38 additions & 0 deletions
38
internal/globals/transientcontainers/transientqueue/share.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package transientqueue | ||
|
||
import ( | ||
"github.com/inoxlang/inox/internal/core" | ||
"github.com/inoxlang/inox/internal/memds" | ||
) | ||
|
||
// PotentiallySharable impl for TransientQueue | ||
|
||
func (*TransientQueue) IsSharable(originState *core.GlobalState) (bool, string) { | ||
return true, "" | ||
} | ||
|
||
func (q *TransientQueue) Share(originState *core.GlobalState) { | ||
threadSafeQueue := memds.NewTSArrayQueue[core.Value]() | ||
|
||
q.threadUnsafe.ForEachElem(func(i int, e core.Value) error { | ||
shared, err := core.ShareOrClone(e, originState) | ||
if err != nil { | ||
panic(err) | ||
} | ||
threadSafeQueue.Enqueue(shared) | ||
return nil | ||
}) | ||
|
||
q.threadUnsafe = nil | ||
q.threadSafe = threadSafeQueue | ||
} | ||
|
||
func (q *TransientQueue) IsShared() bool { | ||
return q.threadSafe != nil | ||
} | ||
|
||
func (*TransientQueue) ForceLock() { | ||
} | ||
|
||
func (*TransientQueue) ForceUnlock() { | ||
} |
58 changes: 58 additions & 0 deletions
58
internal/globals/transientcontainers/transientqueue/transient_queue.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
package transientqueue | ||
|
||
import ( | ||
"github.com/inoxlang/inox/internal/core" | ||
"github.com/inoxlang/inox/internal/memds" | ||
) | ||
|
||
var _ = core.PotentiallySharable((*TransientQueue)(nil)) | ||
|
||
func NewQueue(ctx *core.Context, elements core.Iterable) *TransientQueue { | ||
queue := &TransientQueue{ | ||
threadUnsafe: memds.NewArrayQueue[core.Value](), | ||
} | ||
|
||
it := elements.Iterator(ctx, core.IteratorConfiguration{}) | ||
for it.Next(ctx) { | ||
e := it.Value(ctx) | ||
queue.Enqueue(ctx, e) | ||
} | ||
|
||
return queue | ||
} | ||
|
||
type TransientQueue struct { | ||
threadUnsafe *memds.ArrayQueue[core.Value] //set to nil when shared | ||
threadSafe *memds.TSArrayQueue[core.Value] //set if shared | ||
} | ||
|
||
func (q *TransientQueue) Enqueue(ctx *core.Context, elem core.Value) { | ||
if q.threadUnsafe != nil { | ||
q.threadUnsafe.Enqueue(elem) | ||
return | ||
} | ||
//thread safe | ||
elem, err := core.ShareOrClone(elem, ctx.GetClosestState()) | ||
if err != nil { | ||
panic(err) | ||
} | ||
q.threadSafe.Enqueue(elem) | ||
} | ||
|
||
func (q *TransientQueue) Dequeue(ctx *core.Context) (core.Value, core.Bool) { | ||
if q.threadUnsafe != nil { | ||
e, ok := q.threadUnsafe.Dequeue() | ||
return e, core.Bool(ok) | ||
} | ||
e, ok := q.threadSafe.Dequeue() | ||
return e, core.Bool(ok) | ||
} | ||
|
||
func (q *TransientQueue) Peek(ctx *core.Context) (core.Value, core.Bool) { | ||
if q.threadUnsafe != nil { | ||
e, ok := q.threadUnsafe.Peek() | ||
return e, core.Bool(ok) | ||
} | ||
e, ok := q.threadSafe.Peek() | ||
return e, core.Bool(ok) | ||
} |
72 changes: 72 additions & 0 deletions
72
internal/globals/transientcontainers/transientqueue/transient_queue_test.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
package transientqueue | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/inoxlang/inox/internal/core" | ||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestTransientQueue(t *testing.T) { | ||
ctx := core.NewContexWithEmptyState(core.ContextConfig{}, nil) | ||
defer ctx.CancelGracefully() | ||
|
||
q := NewQueue(ctx, core.NewWrappedValueList()) | ||
|
||
//Add a sharable1 element and a clonable element. | ||
sharable1 := core.NewObjectFromMapNoInit(core.ValMap{}) | ||
clonable1 := core.NewWrappedValueList(core.Int(1)) | ||
|
||
q.Enqueue(ctx, sharable1) | ||
q.Enqueue(ctx, clonable1) | ||
|
||
//Elements added to an unshared queue should not be shared. | ||
if !assert.False(t, sharable1.IsShared()) { | ||
return | ||
} | ||
|
||
//Sharing the queue should cause the elements to be shared or cloned. | ||
q.Share(ctx.GetClosestState()) | ||
|
||
if !assert.True(t, sharable1.IsShared()) { | ||
return | ||
} | ||
|
||
//Shared queues should or clone added elements. | ||
sharable2 := core.NewObjectFromMapNoInit(core.ValMap{}) | ||
clonable2 := core.NewWrappedValueList(core.Int(2)) | ||
|
||
q.Enqueue(ctx, sharable2) | ||
q.Enqueue(ctx, clonable2) | ||
|
||
//Dequeue and check elements. | ||
first, ok := q.Dequeue(ctx) | ||
if !assert.True(t, bool(ok)) { | ||
return | ||
} | ||
|
||
assert.Same(t, sharable1, first) | ||
|
||
second, ok := q.Dequeue(ctx) | ||
if !assert.True(t, bool(ok)) { | ||
return | ||
} | ||
|
||
assert.NotSame(t, clonable1, second) | ||
assert.True(t, clonable1.Equal(ctx, second, map[uintptr]uintptr{}, 0)) | ||
|
||
third, ok := q.Dequeue(ctx) | ||
if !assert.True(t, bool(ok)) { | ||
return | ||
} | ||
|
||
assert.Same(t, sharable2, third) | ||
|
||
fourth, ok := q.Dequeue(ctx) | ||
if !assert.True(t, bool(ok)) { | ||
return | ||
} | ||
|
||
assert.NotSame(t, clonable2, fourth) | ||
assert.True(t, clonable2.Equal(ctx, fourth, map[uintptr]uintptr{}, 0)) | ||
} |
Oops, something went wrong.