Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Check for both points when moving within viewport #15

Merged
merged 3 commits into from
Nov 13, 2024
Merged
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
25 changes: 14 additions & 11 deletions grid.go
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ func (p *page[T]) writeTile(grid *Grid[T], idx uint8, after Value) {
Point: at,
Value: after,
},
}, p.point, at)
}, p.point)
}
}

Expand All @@ -291,7 +291,7 @@ func (p *page[T]) mergeTile(grid *Grid[T], idx uint8, fn func(Value) Value) Valu
Point: at,
Value: after,
},
}, p.point, at)
}, p.point)
}

// Return the merged tile data
Expand Down Expand Up @@ -372,9 +372,15 @@ func (t Tile[T]) Range(fn func(T) error) error {

// Observers iterates over all views observing this tile
func (t Tile[T]) Observers(fn func(view Observer[T])) {
if t.data.IsObserved() {
t.grid.observers.Each1(fn, t.data.point, t.Point())
if !t.data.IsObserved() {
return
}

t.grid.observers.Each1(func(sub Observer[T]) {
if sub.Viewport().Contains(t.Point()) {
fn(sub)
}
}, t.data.point)
}

// Add adds object to the set
Expand All @@ -394,7 +400,7 @@ func (t Tile[T]) Add(v T) {
Value: value,
},
Add: v,
}, t.data.point, at)
}, t.data.point)
}
}

Expand All @@ -415,7 +421,7 @@ func (t Tile[T]) Del(v T) {
Value: value,
},
Del: v,
}, t.data.point, at)
}, t.data.point)
}
}

Expand Down Expand Up @@ -449,16 +455,13 @@ func (t Tile[T]) Move(v T, dst Point) bool {

switch {
case t.data == d.data || !d.data.IsObserved():
t.grid.observers.Notify1(update, t.data.point, t.Point())
t.grid.observers.Notify1(update, t.data.point)
case !t.data.IsObserved():
t.grid.observers.Notify1(update, d.data.point, d.Point())
t.grid.observers.Notify1(update, d.data.point)
default:
t.grid.observers.Notify2(update, [2]Point{
t.data.point,
d.data.point,
}, [2]Point{
t.Point(),
d.Point(),
})
}
return true
Expand Down
30 changes: 16 additions & 14 deletions view.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,32 +191,36 @@ func (p *pubsub[T]) Unsubscribe(page Point, sub Observer[T]) bool {
}

// Notify notifies listeners of an update that happened.
func (p *pubsub[T]) Notify1(ev *Update[T], page, at Point) {
func (p *pubsub[T]) Notify1(ev *Update[T], page Point) {
p.Each1(func(sub Observer[T]) {
sub.onUpdate(ev)
}, page, at)
viewport := sub.Viewport()
if viewport.Contains(ev.New.Point) || viewport.Contains(ev.Old.Point) {
sub.onUpdate(ev)
}
}, page)
}

// Notify notifies listeners of an update that happened.
func (p *pubsub[T]) Notify2(ev *Update[T], pages, locs [2]Point) {
func (p *pubsub[T]) Notify2(ev *Update[T], pages [2]Point) {
p.Each2(func(sub Observer[T]) {
sub.onUpdate(ev)
}, pages, locs)
viewport := sub.Viewport()
if viewport.Contains(ev.New.Point) || viewport.Contains(ev.Old.Point) {
sub.onUpdate(ev)
}
}, pages)
}

// Each iterates over each observer in a page
func (p *pubsub[T]) Each1(fn func(sub Observer[T]), page, at Point) {
func (p *pubsub[T]) Each1(fn func(sub Observer[T]), page Point) {
if v, ok := p.m.Load(page.Integer()); ok {
v.(*observers[T]).Each(func(sub Observer[T]) {
if sub.Viewport().Contains(at) {
fn(sub)
}
fn(sub)
})
}
}

// Each2 iterates over each observer in a page
func (p *pubsub[T]) Each2(fn func(sub Observer[T]), pages, locs [2]Point) {
func (p *pubsub[T]) Each2(fn func(sub Observer[T]), pages [2]Point) {
targets := p.tmp.Get().(map[Observer[T]]struct{})
clear(targets)
defer p.tmp.Put(targets)
Expand All @@ -232,9 +236,7 @@ func (p *pubsub[T]) Each2(fn func(sub Observer[T]), pages, locs [2]Point) {

// Invoke the callback for each observer, once
for sub := range targets {
if sub.Viewport().Contains(locs[0]) || sub.Viewport().Contains(locs[1]) {
fn(sub)
}
fn(sub)
}
}

Expand Down
70 changes: 37 additions & 33 deletions view_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ BenchmarkView/move-24 16141 74408 ns/op 0 B/op 0
*/
func BenchmarkView(b *testing.B) {
m := mapFrom("300x300.png")
v := NewView[string, string](m, "view 1")
v := NewView(m, "view 1")
v.Resize(NewRect(100, 0, 200, 100), nil)

go func() {
Expand Down Expand Up @@ -99,38 +99,6 @@ func TestView(t *testing.T) {
assert.Equal(t, 0, len(v.Inbox))
}

/*
func TestObservers(t *testing.T) {
ev := newObservers[uint32]()
assert.NotNil(t, ev)

// Subscriber which does nothing
var sub1 fakeView[uint32] = func(e *Update[uint32]) {}
ev.Subscribe(&sub1)

// Counting subscriber
var count int
var sub2 fakeView[uint32] = func(e *Update[uint32]) {
count += int(e.X)
}
ev.Subscribe(&sub2)

ev.Notify(&Update[uint32]{Point: At(1, 0)})
ev.Notify(&Update[uint32]{Point: At(2, 0)})
ev.Notify(&Update[uint32]{Point: At(3, 0)})

for count < 6 {
time.Sleep(1 * time.Millisecond)
}

assert.Equal(t, 6, count)
ev.Unsubscribe(&sub2)

ev.Notify(&Update[uint32]{Point: At(2, 0)})
assert.Equal(t, 6, count)
}
*/

func TestUpdates_Simple(t *testing.T) {
m := mapFrom("300x300.png")
c := counter(0)
Expand Down Expand Up @@ -317,6 +285,42 @@ func TestView_MoveTo(t *testing.T) {
assert.NoError(t, v.Close())
}

func TestView_Updates(t *testing.T) {
m := mapFrom("300x300.png")
v := NewView(m, "view 1")
v.Resize(NewRect(10, 10, 15, 15), nil)

move := func(x1, y1, x2, y2 int16) {
at, _ := m.At(x1, y1)
at.Move("A", At(x2, y2))

assert.Equal(t, Update[string]{
Old: ValueAt{Point: At(x1, y1)},
New: ValueAt{Point: At(x2, y2)},
Del: "A", Add: "A",
}, <-v.Inbox)
}

move(9, 12, 10, 12) // Enter from left edge
move(10, 12, 9, 12) // Exit to left edge
move(15, 12, 14, 12) // Enter from right edge
move(14, 12, 15, 12) // Exit to right edge
move(12, 9, 12, 10) // Enter from top edge
move(12, 10, 12, 9) // Exit to top edge
move(12, 15, 12, 14) // Enter from bottom edge
move(12, 14, 12, 15) // Exit to bottom edge
move(9, 9, 10, 10) // Enter from top-left diagonal
move(10, 10, 9, 9) // Exit to top-left diagonal
move(15, 9, 14, 10) // Enter from top-right diagonal
move(14, 10, 15, 9) // Exit to top-right diagonal
move(9, 15, 10, 14) // Enter from bottom-left diagonal
move(10, 14, 9, 15) // Exit to bottom-left diagonal
move(15, 15, 14, 14) // Enter from bottom-right diagonal
move(14, 14, 15, 15) // Exit to bottom-right diagonal

assert.NoError(t, v.Close())
}

func TestSizeUpdate(t *testing.T) {
assert.Equal(t, 24, int(unsafe.Sizeof(Update[uint32]{})))
}
Expand Down
Loading