github.com/ontio/ontology@v1.14.4/vm/neovm/value_stack.go (about)

     1  /*
     2   * Copyright (C) 2018 The ontology Authors
     3   * This file is part of The ontology library.
     4   *
     5   * The ontology is free software: you can redistribute it and/or modify
     6   * it under the terms of the GNU Lesser General Public License as published by
     7   * the Free Software Foundation, either version 3 of the License, or
     8   * (at your option) any later version.
     9   *
    10   * The ontology is distributed in the hope that it will be useful,
    11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13   * GNU Lesser General Public License for more details.
    14   *
    15   * You should have received a copy of the GNU Lesser General Public License
    16   * along with The ontology.  If not, see <http://www.gnu.org/licenses/>.
    17   */
    18  
    19  package neovm
    20  
    21  import (
    22  	"fmt"
    23  
    24  	"github.com/ontio/ontology/vm/neovm/errors"
    25  	"github.com/ontio/ontology/vm/neovm/types"
    26  )
    27  
    28  const initialStackCap = 64 // to avoid reallocation
    29  
    30  type ValueStack struct {
    31  	data  []types.VmValue
    32  	limit int64
    33  }
    34  
    35  func NewValueStack(limit int64) *ValueStack {
    36  	return &ValueStack{
    37  		data:  make([]types.VmValue, 0, initialStackCap),
    38  		limit: limit,
    39  	}
    40  }
    41  
    42  func (self *ValueStack) Count() int {
    43  	return len(self.data)
    44  }
    45  
    46  func (self *ValueStack) Insert(index int64, t types.VmValue) error {
    47  	l := int64(len(self.data))
    48  	if l >= self.limit {
    49  		return errors.ERR_OVER_LIMIT_STACK
    50  	}
    51  	if index > l || index < 0 {
    52  		return errors.ERR_INDEX_OUT_OF_BOUND
    53  	}
    54  	index = l - index
    55  	self.data = append(self.data, t)
    56  	copy(self.data[index+1:], self.data[index:])
    57  	self.data[index] = t
    58  	return nil
    59  }
    60  
    61  func (self *ValueStack) Peek(index int64) (value types.VmValue, err error) {
    62  	l := int64(len(self.data))
    63  	if index >= l || index < 0 {
    64  		err = errors.ERR_INDEX_OUT_OF_BOUND
    65  		return
    66  	}
    67  	index = l - index
    68  	value = self.data[index-1]
    69  	return
    70  }
    71  
    72  func (self *ValueStack) Remove(index int64) (value types.VmValue, err error) {
    73  	l := int64(len(self.data))
    74  	if index >= l || index < 0 {
    75  		err = errors.ERR_INDEX_OUT_OF_BOUND
    76  		return
    77  	}
    78  	index = l - index
    79  	value = self.data[index-1]
    80  	self.data = append(self.data[:index-1], self.data[index:]...)
    81  	return
    82  }
    83  
    84  func (self *ValueStack) Set(index int, t types.VmValue) error {
    85  	l := len(self.data)
    86  	if index >= l || index < 0 {
    87  		return errors.ERR_INDEX_OUT_OF_BOUND
    88  	}
    89  	self.data[index] = t
    90  	return nil
    91  }
    92  
    93  func (self *ValueStack) Push(t types.VmValue) error {
    94  	if int64(len(self.data)) >= self.limit {
    95  		return errors.ERR_OVER_STACK_LEN
    96  	}
    97  	self.data = append(self.data, t)
    98  	return nil
    99  }
   100  
   101  func (self *ValueStack) PushMany(vals ...types.VmValue) error {
   102  	if int64(len(self.data)+len(vals)) > self.limit {
   103  		return errors.ERR_OVER_STACK_LEN
   104  	}
   105  	self.data = append(self.data, vals...)
   106  	return nil
   107  }
   108  
   109  func (self *ValueStack) PushAsArray(vals []types.VmValue) error {
   110  
   111  	if int64(len(self.data)+1) > self.limit {
   112  		return errors.ERR_OVER_STACK_LEN
   113  	}
   114  	arrayValue := types.NewArrayValue()
   115  	for _, val := range vals {
   116  		err := arrayValue.Append(val)
   117  		if err != nil {
   118  			return err
   119  		}
   120  	}
   121  	v := types.VmValueFromArrayVal(arrayValue)
   122  	self.data = append(self.data, v)
   123  	return nil
   124  }
   125  
   126  func (self *ValueStack) Pop() (value types.VmValue, err error) {
   127  	length := len(self.data)
   128  	if length == 0 {
   129  		err = errors.ERR_INDEX_OUT_OF_BOUND
   130  		return
   131  	}
   132  	value = self.data[length-1]
   133  	self.data = self.data[:length-1]
   134  	return
   135  }
   136  
   137  func (self *ValueStack) PopPair() (left, right types.VmValue, err error) {
   138  	right, err = self.Pop()
   139  	if err != nil {
   140  		return
   141  	}
   142  	left, err = self.Pop()
   143  	return
   144  }
   145  
   146  func (self *ValueStack) PopTriple() (left, middle, right types.VmValue, err error) {
   147  	middle, right, err = self.PopPair()
   148  	if err != nil {
   149  		return
   150  	}
   151  	left, err = self.Pop()
   152  	return
   153  }
   154  
   155  func (self *ValueStack) Swap(i, j int64) error {
   156  	l := int64(len(self.data))
   157  	if i >= l || i < 0 {
   158  		return errors.ERR_INDEX_OUT_OF_BOUND
   159  	}
   160  	if j >= l || j < 0 {
   161  		return errors.ERR_INDEX_OUT_OF_BOUND
   162  	}
   163  	if i == j {
   164  		return nil
   165  	}
   166  	self.data[l-i-1], self.data[l-j-1] = self.data[l-j-1], self.data[l-i-1]
   167  
   168  	return nil
   169  }
   170  
   171  func (self *ValueStack) CopyTo(stack *ValueStack) error {
   172  	if int64(len(self.data)+len(stack.data)) > stack.limit {
   173  		return errors.ERR_OVER_STACK_LEN
   174  	}
   175  	stack.data = append(stack.data, self.data...)
   176  	return nil
   177  }
   178  
   179  func (self *ValueStack) Dump() string {
   180  	data := fmt.Sprintf("stack[%d]:\n", len(self.data))
   181  	for i, item := range self.data {
   182  		i = len(self.data) - i
   183  		res := item.Dump()
   184  		data += fmt.Sprintf("%d:\t%s\n", i, res)
   185  	}
   186  	return data
   187  }