github.com/hirochachacha/plua@v0.0.0-20170217012138-c82f520cc725/internal/tables/concurrent_table.go (about)

     1  package tables
     2  
     3  import (
     4  	"fmt"
     5  	"sync"
     6  
     7  	"github.com/hirochachacha/plua/internal/limits"
     8  	"github.com/hirochachacha/plua/object"
     9  )
    10  
    11  type concurrentTable struct {
    12  	a []object.Value
    13  	m *concurrentMap
    14  
    15  	sync.Mutex
    16  
    17  	mt object.Table
    18  }
    19  
    20  func NewConcurrentTableSize(asize, msize int) object.Table {
    21  	return &concurrentTable{
    22  		a: make([]object.Value, asize),
    23  		m: newConcurrentMapSize(msize),
    24  	}
    25  }
    26  
    27  func (t *concurrentTable) Type() object.Type {
    28  	return object.TTABLE
    29  }
    30  
    31  func (t *concurrentTable) String() string {
    32  	return fmt.Sprintf("table: %p", t)
    33  }
    34  
    35  func (t *concurrentTable) Len() int {
    36  	t.Lock()
    37  
    38  	n := len(t.a)
    39  
    40  	t.Unlock()
    41  
    42  	return n
    43  }
    44  
    45  func (t *concurrentTable) Get(key object.Value) object.Value {
    46  	return t.get(normKey(key))
    47  }
    48  
    49  func (t *concurrentTable) Set(key, val object.Value) {
    50  	t.set(normKey(key), val)
    51  }
    52  
    53  func (t *concurrentTable) Del(key object.Value) {
    54  	t.del(normKey(key))
    55  }
    56  
    57  func (t *concurrentTable) Next(key object.Value) (nkey, nval object.Value, ok bool) {
    58  	return t.next(normKey(key))
    59  }
    60  
    61  func (t *concurrentTable) SetList(base int, src []object.Value) {
    62  	t.setList(base, src)
    63  }
    64  
    65  func (t *concurrentTable) SetMetatable(mt object.Table) {
    66  	t.setMetatable(mt)
    67  }
    68  
    69  func (t *concurrentTable) Metatable() object.Table {
    70  	mt := t.metatable()
    71  	return mt
    72  }
    73  
    74  func (t *concurrentTable) ikey(key object.Value) (object.Integer, bool) {
    75  	if ikey, ok := key.(object.Integer); ok {
    76  		return ikey, !(int64(ikey) > limits.MaxInt || int64(ikey) < limits.MinInt)
    77  	}
    78  
    79  	if nkey, ok := key.(object.Number); ok {
    80  		if ikey, ok := object.ToInteger(nkey); ok {
    81  			return ikey, !(int64(ikey) > limits.MaxInt || int64(ikey) < limits.MinInt)
    82  		}
    83  	}
    84  
    85  	return 0, false
    86  }
    87  
    88  func (t *concurrentTable) get(key object.Value) object.Value {
    89  	if ikey, ok := t.ikey(key); ok {
    90  		return t.iget(ikey)
    91  	}
    92  
    93  	return t.m.Get(key)
    94  }
    95  
    96  func (t *concurrentTable) iget(ikey object.Integer) object.Value {
    97  	t.Lock()
    98  
    99  	i := int(ikey)
   100  
   101  	if 0 < i && i <= len(t.a) {
   102  		val := t.a[i-1]
   103  
   104  		t.Unlock()
   105  
   106  		return val
   107  	}
   108  
   109  	t.Unlock()
   110  
   111  	return t.m.Get(ikey)
   112  }
   113  
   114  func (t *concurrentTable) set(key, val object.Value) {
   115  	if val == nil {
   116  		t.del(key)
   117  
   118  		return
   119  	}
   120  
   121  	if ikey, ok := t.ikey(key); ok {
   122  		t.iset(ikey, val)
   123  	} else {
   124  		t.m.Set(key, val)
   125  	}
   126  }
   127  
   128  func (t *concurrentTable) iset(ikey object.Integer, val object.Value) {
   129  	t.Lock()
   130  	defer t.Unlock()
   131  
   132  	i := int(ikey)
   133  	switch {
   134  	case 0 < i && i <= len(t.a):
   135  		t.a[i-1] = val
   136  	case i == len(t.a)+1:
   137  		t.a = append(t.a, val)
   138  
   139  		// migration from map to array
   140  		for {
   141  			ikey++
   142  			val := t.m.Get(ikey)
   143  			if val == nil {
   144  				break
   145  			}
   146  			t.a = append(t.a, val)
   147  			t.m.Delete(ikey)
   148  		}
   149  	default:
   150  		t.m.Set(ikey, val)
   151  	}
   152  }
   153  
   154  func (t *concurrentTable) del(key object.Value) {
   155  	if ikey, ok := t.ikey(key); ok {
   156  		t.idel(ikey)
   157  	} else {
   158  		t.m.Delete(key)
   159  	}
   160  }
   161  
   162  func (t *concurrentTable) idel(ikey object.Integer) {
   163  	t.Lock()
   164  	defer t.Unlock()
   165  
   166  	i := int(ikey)
   167  	switch {
   168  	case 0 < i && i < len(t.a):
   169  		t.a[i-1] = nil
   170  	case 0 < i && i == len(t.a):
   171  		t.a = t.a[:len(t.a)-1]
   172  		for len(t.a) > 0 && t.a[len(t.a)-1] == nil {
   173  			t.a = t.a[:len(t.a)-1]
   174  		}
   175  	case i == len(t.a)+1:
   176  		// do nothing
   177  	default:
   178  		t.m.Delete(ikey)
   179  	}
   180  }
   181  
   182  func (t *concurrentTable) next(key object.Value) (nkey, nval object.Value, ok bool) {
   183  	t.Lock()
   184  	defer t.Unlock()
   185  
   186  	if key == nil {
   187  		for i := 0; i < len(t.a); i++ {
   188  			v := t.a[i]
   189  			if v != nil {
   190  				return object.Integer(i + 1), v, true
   191  			}
   192  		}
   193  		return t.m.Next(nil)
   194  	}
   195  
   196  	if ikey, ok := t.ikey(key); ok {
   197  		if i := int(ikey); i > 0 {
   198  			for ; i < len(t.a); i++ {
   199  				v := t.a[i]
   200  				if v != nil {
   201  					return object.Integer(i + 1), t.a[i], true
   202  				}
   203  			}
   204  			if i == len(t.a) {
   205  				return t.m.Next(nil)
   206  			}
   207  		}
   208  	}
   209  
   210  	return t.m.Next(key)
   211  }
   212  
   213  func (t *concurrentTable) setList(base int, src []object.Value) {
   214  	t.Lock()
   215  	defer t.Unlock()
   216  
   217  	if len(src) < len(t.a)-base {
   218  		copy(t.a[base:], src)
   219  	} else {
   220  		t.a = append(t.a[base:], src...)
   221  	}
   222  }
   223  
   224  func (t *concurrentTable) setMetatable(mt object.Table) {
   225  	t.mt = mt
   226  }
   227  
   228  func (t *concurrentTable) metatable() object.Table {
   229  	return t.mt
   230  }