2022-12-17 11:18:48 +03:00
|
|
|
package apple
|
|
|
|
|
2022-12-17 22:26:40 +03:00
|
|
|
import (
|
|
|
|
"golang.org/x/exp/constraints"
|
|
|
|
)
|
|
|
|
|
2022-12-17 11:18:48 +03:00
|
|
|
// PosLoopDetector is used for detecting loops when writing decoders, and can
|
|
|
|
// short-circuit infinite recursion that can cause stack overflows.
|
2022-12-17 22:26:40 +03:00
|
|
|
type PosLoopDetector[T constraints.Integer] []T
|
2022-12-17 11:18:48 +03:00
|
|
|
|
|
|
|
// Push adds the current offset to the stack and executes the supplied
|
|
|
|
// detection function
|
2022-12-17 22:26:40 +03:00
|
|
|
func (pld *PosLoopDetector[T]) Push(offset T, detect func()) {
|
2022-12-17 11:18:48 +03:00
|
|
|
for _, o := range *pld {
|
|
|
|
if offset == o {
|
|
|
|
detect()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*pld = append(*pld, offset)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Pop removes the most recently added offset from the stack.
|
2022-12-17 22:26:40 +03:00
|
|
|
func (pld *PosLoopDetector[T]) Pop() {
|
2022-12-17 11:18:48 +03:00
|
|
|
*pld = (*pld)[:len(*pld)-1]
|
|
|
|
}
|
|
|
|
|
|
|
|
// PushAndPop adds the current offset to the stack, executes the supplied
|
|
|
|
// detection function, and returns the Pop method. A good usage of this is to
|
|
|
|
// pair this method call with a defer statement.
|
2022-12-17 22:36:16 +03:00
|
|
|
func (pld *PosLoopDetector[T]) PushAndPop(offset T, detect func()) func() {
|
|
|
|
pld.Push(offset, detect)
|
2022-12-17 11:18:48 +03:00
|
|
|
return pld.Pop
|
|
|
|
}
|