op: introduce CallOp

We'd like to improve the API of Flex, Stack and similar layouts
that use MacroOps internall. Unfortunately, the

  func (m MacroOp) Add(o *Ops)

method causes the MacroOp to be allocated on the heap, ruining the
nice garbage-free property of layouts.

Fortunately, layouts don't need the feature that caused the heap
allocation: invoking operation lists different than the current.

CallOp separates the invoke-different-list semantic from MacroOp,
in preparation for removing the feature from MacroOp.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
Elias Naur
2019-12-11 22:53:50 +01:00
parent 9114dbe759
commit 06217c5320
3 changed files with 58 additions and 1 deletions
+4 -1
View File
@@ -26,6 +26,7 @@ const (
TypeAux
TypeClip
TypeProfile
TypeCall
)
const (
@@ -47,6 +48,7 @@ const (
TypeAuxLen = 1
TypeClipLen = 1 + 4*4
TypeProfileLen = 1
TypeCallLen = 1
)
func (t OpType) Size() int {
@@ -69,12 +71,13 @@ func (t OpType) Size() int {
TypeAuxLen,
TypeClipLen,
TypeProfileLen,
TypeCallLen,
}[t-firstOpIndex]
}
func (t OpType) NumRefs() int {
switch t {
case TypeMacro, TypeKeyInput, TypePointerInput, TypeProfile:
case TypeMacro, TypeKeyInput, TypePointerInput, TypeProfile, TypeCall:
return 1
case TypeImage:
return 2
+32
View File
@@ -38,6 +38,11 @@ type macroOp struct {
pc pc
}
// Shadow of op.CallOp.
type callOp struct {
ops *op.Ops
}
type pc struct {
data int
refs int
@@ -94,6 +99,24 @@ func (r *Reader) Decode() (EncodedOp, bool) {
block := r.stack[len(r.stack)-1]
n += block.endPC.data - r.pc.data - opconst.TypeAuxLen
data = data[:n]
case opconst.TypeCall:
var op callOp
op.decode(data, refs)
endPC := pc{
data: len(op.ops.Data()),
refs: len(op.ops.Refs()),
}
retPC := r.pc
retPC.data += n
retPC.refs += nrefs
r.stack = append(r.stack, macro{
ops: r.ops,
retPC: retPC,
endPC: endPC,
})
r.pc = pc{}
r.ops = op.ops
continue
case opconst.TypeMacro:
var op macroOp
op.decode(data, refs)
@@ -148,6 +171,15 @@ func (op *opMacroDef) decode(data []byte) {
}
}
func (m *callOp) decode(data []byte, refs []interface{}) {
if opconst.OpType(data[0]) != opconst.TypeCall {
panic("invalid op")
}
*m = callOp{
ops: refs[0].(*op.Ops),
}
}
func (m *macroOp) decode(data []byte, refs []interface{}) {
if opconst.OpType(data[0]) != opconst.TypeMacro {
panic("invalid op")
+22
View File
@@ -45,6 +45,12 @@ The StackOp saves the current state to the state stack and restores it later:
// Restore the previous transform.
stack.Pop()
The CallOp invokes another operation list:
ops := new(op.Ops)
ops2 := new(op.Ops)
op.CallOp{Ops: ops2}.Add(ops)
The MacroOp records a list of operations to be executed later:
ops := new(op.Ops)
@@ -105,6 +111,13 @@ type MacroOp struct {
pc pc
}
// CallOp invokes all the operations from a separate
// operations list.
type CallOp struct {
// Ops is the list of operations to invoke.
Ops *Ops
}
// InvalidateOp requests a redraw at the given time. Use
// the zero value to request an immediate redraw.
type InvalidateOp struct {
@@ -134,6 +147,15 @@ type pc struct {
refs int
}
// Add the call to the operation list.
func (c CallOp) Add(o *Ops) {
if c.Ops == nil {
return
}
data := o.Write(opconst.TypeCallLen, c.Ops)
data[0] = byte(opconst.TypeCall)
}
// Push (save) the current operations state.
func (s *StackOp) Push(o *Ops) {
if s.active {