github.com/aigarnetwork/aigar@v0.0.0-20191115204914-d59a6eb70f8e/core/vm/intpool.go (about)

     1  //  Copyright 2018 The go-ethereum Authors
     2  //  Copyright 2019 The go-aigar Authors
     3  //  This file is part of the go-aigar library.
     4  //
     5  //  The go-aigar library 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 go-aigar library 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 go-aigar library. If not, see <http://www.gnu.org/licenses/>.
    17  
    18  package vm
    19  
    20  import (
    21  	"math/big"
    22  	"sync"
    23  )
    24  
    25  var checkVal = big.NewInt(-42)
    26  
    27  const poolLimit = 256
    28  
    29  // intPool is a pool of big integers that
    30  // can be reused for all big.Int operations.
    31  type intPool struct {
    32  	pool *Stack
    33  }
    34  
    35  func newIntPool() *intPool {
    36  	return &intPool{pool: newstack()}
    37  }
    38  
    39  // get retrieves a big int from the pool, allocating one if the pool is empty.
    40  // Note, the returned int's value is arbitrary and will not be zeroed!
    41  func (p *intPool) get() *big.Int {
    42  	if p.pool.len() > 0 {
    43  		return p.pool.pop()
    44  	}
    45  	return new(big.Int)
    46  }
    47  
    48  // getZero retrieves a big int from the pool, setting it to zero or allocating
    49  // a new one if the pool is empty.
    50  func (p *intPool) getZero() *big.Int {
    51  	if p.pool.len() > 0 {
    52  		return p.pool.pop().SetUint64(0)
    53  	}
    54  	return new(big.Int)
    55  }
    56  
    57  // put returns an allocated big int to the pool to be later reused by get calls.
    58  // Note, the values as saved as is; neither put nor get zeroes the ints out!
    59  func (p *intPool) put(is ...*big.Int) {
    60  	if len(p.pool.data) > poolLimit {
    61  		return
    62  	}
    63  	for _, i := range is {
    64  		// verifyPool is a build flag. Pool verification makes sure the integrity
    65  		// of the integer pool by comparing values to a default value.
    66  		if verifyPool {
    67  			i.Set(checkVal)
    68  		}
    69  		p.pool.push(i)
    70  	}
    71  }
    72  
    73  // The intPool pool's default capacity
    74  const poolDefaultCap = 25
    75  
    76  // intPoolPool manages a pool of intPools.
    77  type intPoolPool struct {
    78  	pools []*intPool
    79  	lock  sync.Mutex
    80  }
    81  
    82  var poolOfIntPools = &intPoolPool{
    83  	pools: make([]*intPool, 0, poolDefaultCap),
    84  }
    85  
    86  // get is looking for an available pool to return.
    87  func (ipp *intPoolPool) get() *intPool {
    88  	ipp.lock.Lock()
    89  	defer ipp.lock.Unlock()
    90  
    91  	if len(poolOfIntPools.pools) > 0 {
    92  		ip := ipp.pools[len(ipp.pools)-1]
    93  		ipp.pools = ipp.pools[:len(ipp.pools)-1]
    94  		return ip
    95  	}
    96  	return newIntPool()
    97  }
    98  
    99  // put a pool that has been allocated with get.
   100  func (ipp *intPoolPool) put(ip *intPool) {
   101  	ipp.lock.Lock()
   102  	defer ipp.lock.Unlock()
   103  
   104  	if len(ipp.pools) < cap(ipp.pools) {
   105  		ipp.pools = append(ipp.pools, ip)
   106  	}
   107  }