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

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