Skip to content

Commit ec333c0

Browse files
committed
Fix edge cases in GenerateMovements() and OptimizeMovements() interaction
Now GenerateMovements() generate all movements blindly, and depend on the optimization done by OptimizeMovements() to remove reduntant actions.
1 parent c067551 commit ec333c0

File tree

2 files changed

+64
-30
lines changed

2 files changed

+64
-30
lines changed

assets/pango/movement/movement.go

Lines changed: 11 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -254,8 +254,6 @@ func (o PositionBefore) Move(entries []Movable, existing []Movable) ([]MoveActio
254254
return nil, err
255255
}
256256

257-
slog.Debug("PositionBefore.Move()", "existing", existing, "expected", expected, "entries", entries)
258-
259257
actions, err := GenerateMovements(existing, expected, entries, ActionWhereBefore, o.Pivot, o.Directly)
260258
if err != nil {
261259
return nil, err
@@ -292,23 +290,11 @@ func updateSimulatedIdxMap(idxMap *map[Movable]int, moved Movable, startingIdx i
292290
func OptimizeMovements(existing []Movable, expected []Movable, entries []Movable, actions []MoveAction, position Position) []MoveAction {
293291
simulated := make([]Movable, len(existing))
294292
copy(simulated, existing)
295-
296293
simulatedIdxMap := createIdxMapFor(simulated)
297-
expectedIdxMap := createIdxMapFor(expected)
298294

299295
var optimized []MoveAction
300-
301-
switch position.(type) {
302-
case PositionBefore, PositionAfter:
303-
default:
304-
return actions
305-
}
306-
307296
for _, action := range actions {
308297
currentIdx := simulatedIdxMap[action.Movable]
309-
if currentIdx == expectedIdxMap[action.Movable] {
310-
continue
311-
}
312298

313299
var targetIdx int
314300
switch action.Where {
@@ -317,11 +303,13 @@ func OptimizeMovements(existing []Movable, expected []Movable, entries []Movable
317303
case ActionWhereBottom:
318304
targetIdx = len(simulated) - 1
319305
case ActionWhereBefore:
320-
targetIdx = simulatedIdxMap[action.Destination] - 1
306+
targetIdx = simulatedIdxMap[action.Destination]
321307
case ActionWhereAfter:
322308
targetIdx = simulatedIdxMap[action.Destination] + 1
323309
}
324310

311+
slog.Debug("OptimizeMovements()", "action", action, "currentIdx", currentIdx, "targetIdx", targetIdx)
312+
325313
if targetIdx != currentIdx {
326314
optimized = append(optimized, action)
327315
simulatedIdxMap[action.Movable] = targetIdx
@@ -346,11 +334,7 @@ func GenerateMovements(existing []Movable, expected []Movable, entries []Movable
346334
var movements []MoveAction
347335
var previous Movable
348336
for _, elt := range entries {
349-
slog.Debug("GenerateMovements()", "elt", elt, "existing", existingIdxMap[elt], "expected", expectedIdxMap[elt], "len(expected)", len(expected))
350-
// If existing index for the element matches the expected one, skip it over
351-
if existingIdxMap[elt] == expectedIdxMap[elt] {
352-
continue
353-
}
337+
slog.Debug("GeneraveMovements()", "elt", elt, "existing", existingIdxMap[elt], "expected", expectedIdxMap[elt])
354338

355339
if previous != nil {
356340
movements = append(movements, MoveAction{
@@ -392,10 +376,10 @@ func GenerateMovements(existing []Movable, expected []Movable, entries []Movable
392376
eltExpectedIdx := expectedIdxMap[elt]
393377
pivot = expected[eltExpectedIdx+1]
394378
where = ActionWhereBefore
395-
// if previous was nil (we are processing the first element in entries set)
396-
// and selected pivot is part of the entries set it means the order of entries
397-
// changes between existing and expected sets. If direct move has been requested,
398-
// we need to find the correct pivot point for the move.
379+
// If previous was nil (we are processing the first element in entries set)
380+
// and selected pivot is part of the entries set, it means the order of elements
381+
// changes between existing adn expected sets. In this case the actual pivot
382+
// is element from expected set that follows all moved elements.
399383
if _, ok := entriesIdxMap[pivot]; ok && directly {
400384
// The actual pivot for the move is the element that follows all elements
401385
// from the existing set.
@@ -406,6 +390,7 @@ func GenerateMovements(existing []Movable, expected []Movable, entries []Movable
406390
return nil, ErrInvalidMovementPlan
407391
}
408392
pivot = expected[pivotIdx]
393+
409394
}
410395
}
411396

@@ -419,7 +404,7 @@ func GenerateMovements(existing []Movable, expected []Movable, entries []Movable
419404

420405
}
421406

422-
slog.Debug("GeneraveMovements()", "movements", movements)
407+
slog.Debug("GenerateMovements()", "movements", movements)
423408

424409
return movements, nil
425410
}
@@ -464,14 +449,14 @@ func (o PositionBottom) GetExpected(entries []Movable, existing []Movable) ([]Mo
464449
}
465450

466451
func (o PositionBottom) Move(entries []Movable, existing []Movable) ([]MoveAction, error) {
467-
slog.Debug("PositionBottom.Move())", "entries", entries, "existing", existing)
468452
expected, err := o.GetExpected(entries, existing)
469453
if err != nil {
470454
return nil, err
471455
}
472456

473457
actions, err := GenerateMovements(existing, expected, entries, ActionWhereBottom, nil, false)
474458
if err != nil {
459+
slog.Debug("PositionBottom()", "err", err)
475460
return nil, err
476461
}
477462
return OptimizeMovements(existing, expected, entries, actions, o), nil
@@ -487,7 +472,6 @@ func MoveGroups(existing []Movable, movements []Movement) ([]MoveAction, error)
487472
for idx := range len(movements) - 1 {
488473
position := movements[idx].Position
489474
entries := movements[idx].Entries
490-
slog.Debug("MoveGroups()", "position", position, "existing", existing, "entries", entries)
491475
result, err := position.GetExpected(entries, expected)
492476
if err != nil {
493477
if !errors.Is(err, errNoMovements) {
@@ -500,7 +484,6 @@ func MoveGroups(existing []Movable, movements []Movement) ([]MoveAction, error)
500484

501485
entries := movements[len(movements)-1].Entries
502486
position := movements[len(movements)-1].Position
503-
slog.Debug("MoveGroups()", "position", position, "expected", expected, "entries", entries)
504487
return position.Move(entries, expected)
505488
}
506489

assets/pango/movement/movement_test.go

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ var _ = Describe("MoveGroup()", func() {
7171
moves, err := movement.MoveGroup(movement.PositionTop{}, entries, existing)
7272
Expect(err).ToNot(HaveOccurred())
7373

74+
// '((E 'top nil)(B 'after E)(C 'after B)(D 'after C))
75+
// 'A element stays in place
7476
Expect(moves).To(HaveLen(4))
7577
})
7678
})
@@ -189,9 +191,54 @@ var _ = Describe("MoveGroup()", func() {
189191
})
190192
})
191193
})
194+
195+
// '(A E B C D) -> '(A B C D E) => '(E 'bottom nil) / '(E 'after D)
196+
197+
// PositionSomewhereBefore PositionDirectlyBefore
198+
// '(C B 'before E, directly)
199+
// '(A B C D E) -> '(A D C B E) -> '(B 'before E)
200+
// '(A B C D E) -> '(A C B D E) -> '(B 'after C)
201+
192202
Context("With PositionBefore used as position", func() {
193203
existing := asMovable([]string{"A", "B", "C", "D", "E"})
204+
Context("when doing a direct move with entries reordering", func() {
205+
It("should put reordered entries directly before pivot point", func() {
206+
// '(A B C D E) -> '(A D C B E)
207+
entries := asMovable([]string{"C", "B"})
208+
moves, err := movement.MoveGroup(
209+
movement.PositionBefore{Directly: true, Pivot: Mock{"E"}},
210+
entries, existing,
211+
)
212+
213+
Expect(err).ToNot(HaveOccurred())
214+
Expect(moves).To(HaveLen(2))
215+
216+
Expect(moves[0].Movable.EntryName()).To(Equal("C"))
217+
Expect(moves[0].Where).To(Equal(movement.ActionWhereBefore))
218+
Expect(moves[0].Destination.EntryName()).To(Equal("E"))
219+
220+
Expect(moves[1].Movable.EntryName()).To(Equal("B"))
221+
Expect(moves[1].Where).To(Equal(movement.ActionWhereAfter))
222+
Expect(moves[1].Destination.EntryName()).To(Equal("C"))
223+
})
224+
})
225+
Context("when doing a non direct move with entries reordering", func() {
226+
It("should reorder entries in-place without moving them around", func() {
227+
// '(A B C D E) -> '(A C B D E)
228+
entries := asMovable([]string{"C", "B"})
229+
moves, err := movement.MoveGroup(
230+
movement.PositionBefore{Directly: false, Pivot: Mock{"E"}},
231+
entries, existing,
232+
)
233+
234+
Expect(err).ToNot(HaveOccurred())
235+
Expect(moves).To(HaveLen(1))
194236

237+
Expect(moves[0].Movable.EntryName()).To(Equal("C"))
238+
Expect(moves[0].Where).To(Equal(movement.ActionWhereBefore))
239+
Expect(moves[0].Destination.EntryName()).To(Equal("B"))
240+
})
241+
})
195242
Context("when direct position relative to the pivot is not required", func() {
196243
Context("and moved entries are already before pivot point", func() {
197244
It("should not generate any move actions", func() {
@@ -249,8 +296,8 @@ var _ = Describe("MoveGroup()", func() {
249296
Expect(moves).To(HaveLen(1))
250297

251298
Expect(moves[0].Movable.EntryName()).To(Equal("C"))
252-
Expect(moves[0].Where).To(Equal(movement.ActionWhereBefore))
253-
Expect(moves[0].Destination.EntryName()).To(Equal("B"))
299+
Expect(moves[0].Where).To(Equal(movement.ActionWhereAfter))
300+
Expect(moves[0].Destination.EntryName()).To(Equal("A"))
254301
})
255302
})
256303
})
@@ -355,6 +402,10 @@ var _ = Describe("Movement benchmarks", func() {
355402

356403
Expect(err).ToNot(HaveOccurred())
357404
Expect(moves).To(HaveLen(6))
405+
406+
Expect(moves[0].Movable.EntryName()).To(Equal("90"))
407+
Expect(moves[0].Where).To(Equal(movement.ActionWhereBefore))
408+
Expect(moves[0].Destination.EntryName()).To(Equal("100"))
358409
})
359410
})
360411
})

0 commit comments

Comments
 (0)