github.com/cybriq/giocore@v0.0.7-0.20210703034601-cfb9cb5f3900/internal/ops/reader.go (about)

     1  // SPDX-License-Identifier: Unlicense OR MIT
     2  
     3  package ops
     4  
     5  import (
     6  	"encoding/binary"
     7  
     8  	"github.com/cybriq/giocore/f32"
     9  	"github.com/cybriq/giocore/internal/opconst"
    10  	"github.com/cybriq/giocore/op"
    11  )
    12  
    13  // Reader parses an ops list.
    14  type Reader struct {
    15  	pc        PC
    16  	stack     []macro
    17  	ops       *op.Ops
    18  	deferOps  op.Ops
    19  	deferDone bool
    20  }
    21  
    22  // EncodedOp represents an encoded op returned by
    23  // Reader.
    24  type EncodedOp struct {
    25  	Key  Key
    26  	Data []byte
    27  	Refs []interface{}
    28  }
    29  
    30  // Key is a unique key for a given op.
    31  type Key struct {
    32  	ops            *op.Ops
    33  	pc             int
    34  	version        int
    35  	sx, hx, sy, hy float32
    36  }
    37  
    38  // Shadow of op.MacroOp.
    39  type macroOp struct {
    40  	ops *op.Ops
    41  	pc  PC
    42  }
    43  
    44  // PC is an instruction counter for an operation list.
    45  type PC struct {
    46  	data int
    47  	refs int
    48  }
    49  
    50  type macro struct {
    51  	ops   *op.Ops
    52  	retPC PC
    53  	endPC PC
    54  }
    55  
    56  type opMacroDef struct {
    57  	endpc PC
    58  }
    59  
    60  // Reset start reading from the beginning of ops.
    61  func (r *Reader) Reset(ops *op.Ops) {
    62  	r.ResetAt(ops, PC{})
    63  }
    64  
    65  // ResetAt is like Reset, except it starts reading from pc.
    66  func (r *Reader) ResetAt(ops *op.Ops, pc PC) {
    67  	r.stack = r.stack[:0]
    68  	r.deferOps.Reset()
    69  	r.deferDone = false
    70  	r.pc = pc
    71  	r.ops = ops
    72  }
    73  
    74  // NewPC returns a PC representing the current instruction counter of
    75  // ops.
    76  func NewPC(ops *op.Ops) PC {
    77  	return PC{
    78  		data: len(ops.Data()),
    79  		refs: len(ops.Refs()),
    80  	}
    81  }
    82  
    83  func (k Key) SetTransform(t f32.Affine2D) Key {
    84  	sx, hx, _, hy, sy, _ := t.Elems()
    85  	k.sx = sx
    86  	k.hx = hx
    87  	k.hy = hy
    88  	k.sy = sy
    89  	return k
    90  }
    91  
    92  func (r *Reader) Decode() (EncodedOp, bool) {
    93  	if r.ops == nil {
    94  		return EncodedOp{}, false
    95  	}
    96  	deferring := false
    97  	for {
    98  		if len(r.stack) > 0 {
    99  			b := r.stack[len(r.stack)-1]
   100  			if r.pc == b.endPC {
   101  				r.ops = b.ops
   102  				r.pc = b.retPC
   103  				r.stack = r.stack[:len(r.stack)-1]
   104  				continue
   105  			}
   106  		}
   107  		data := r.ops.Data()
   108  		data = data[r.pc.data:]
   109  		refs := r.ops.Refs()
   110  		if len(data) == 0 {
   111  			if r.deferDone {
   112  				return EncodedOp{}, false
   113  			}
   114  			r.deferDone = true
   115  			// Execute deferred macros.
   116  			r.ops = &r.deferOps
   117  			r.pc = PC{}
   118  			continue
   119  		}
   120  		key := Key{ops: r.ops, pc: r.pc.data, version: r.ops.Version()}
   121  		t := opconst.OpType(data[0])
   122  		n := t.Size()
   123  		nrefs := t.NumRefs()
   124  		data = data[:n]
   125  		refs = refs[r.pc.refs:]
   126  		refs = refs[:nrefs]
   127  		switch t {
   128  		case opconst.TypeDefer:
   129  			deferring = true
   130  			r.pc.data += n
   131  			r.pc.refs += nrefs
   132  			continue
   133  		case opconst.TypeAux:
   134  			// An Aux operations is always wrapped in a macro, and
   135  			// its length is the remaining space.
   136  			block := r.stack[len(r.stack)-1]
   137  			n += block.endPC.data - r.pc.data - opconst.TypeAuxLen
   138  			data = data[:n]
   139  		case opconst.TypeCall:
   140  			if deferring {
   141  				deferring = false
   142  				// Copy macro for deferred execution.
   143  				if t.NumRefs() != 1 {
   144  					panic("internal error: unexpected number of macro refs")
   145  				}
   146  				deferData := r.deferOps.Write1(t.Size(), refs[0])
   147  				copy(deferData, data)
   148  				continue
   149  			}
   150  			var op macroOp
   151  			op.decode(data, refs)
   152  			macroData := op.ops.Data()[op.pc.data:]
   153  			if opconst.OpType(macroData[0]) != opconst.TypeMacro {
   154  				panic("invalid macro reference")
   155  			}
   156  			var opDef opMacroDef
   157  			opDef.decode(macroData[:opconst.TypeMacro.Size()])
   158  			retPC := r.pc
   159  			retPC.data += n
   160  			retPC.refs += nrefs
   161  			r.stack = append(r.stack, macro{
   162  				ops:   r.ops,
   163  				retPC: retPC,
   164  				endPC: opDef.endpc,
   165  			})
   166  			r.ops = op.ops
   167  			r.pc = op.pc
   168  			r.pc.data += opconst.TypeMacro.Size()
   169  			r.pc.refs += opconst.TypeMacro.NumRefs()
   170  			continue
   171  		case opconst.TypeMacro:
   172  			var op opMacroDef
   173  			op.decode(data)
   174  			r.pc = op.endpc
   175  			continue
   176  		}
   177  		r.pc.data += n
   178  		r.pc.refs += nrefs
   179  		return EncodedOp{Key: key, Data: data, Refs: refs}, true
   180  	}
   181  }
   182  
   183  func (op *opMacroDef) decode(data []byte) {
   184  	if opconst.OpType(data[0]) != opconst.TypeMacro {
   185  		panic("invalid op")
   186  	}
   187  	bo := binary.LittleEndian
   188  	data = data[:9]
   189  	dataIdx := int(int32(bo.Uint32(data[1:])))
   190  	refsIdx := int(int32(bo.Uint32(data[5:])))
   191  	*op = opMacroDef{
   192  		endpc: PC{
   193  			data: dataIdx,
   194  			refs: refsIdx,
   195  		},
   196  	}
   197  }
   198  
   199  func (m *macroOp) decode(data []byte, refs []interface{}) {
   200  	if opconst.OpType(data[0]) != opconst.TypeCall {
   201  		panic("invalid op")
   202  	}
   203  	data = data[:9]
   204  	bo := binary.LittleEndian
   205  	dataIdx := int(int32(bo.Uint32(data[1:])))
   206  	refsIdx := int(int32(bo.Uint32(data[5:])))
   207  	*m = macroOp{
   208  		ops: refs[0].(*op.Ops),
   209  		pc: PC{
   210  			data: dataIdx,
   211  			refs: refsIdx,
   212  		},
   213  	}
   214  }