github.com/shawnclovie/gopher-lua@v0.0.0-20200520092726-90b44ec0e2f2/table.go (about)

     1  package lua
     2  
     3  const defaultArrayCap = 32
     4  const defaultHashCap = 32
     5  
     6  type lValueArraySorter struct {
     7  	L      *LState
     8  	Fn     *LFunction
     9  	Values []LValue
    10  }
    11  
    12  func (lv lValueArraySorter) Len() int {
    13  	return len(lv.Values)
    14  }
    15  
    16  func (lv lValueArraySorter) Swap(i, j int) {
    17  	lv.Values[i], lv.Values[j] = lv.Values[j], lv.Values[i]
    18  }
    19  
    20  func (lv lValueArraySorter) Less(i, j int) bool {
    21  	if lv.Fn != nil {
    22  		lv.L.Push(lv.Fn)
    23  		lv.L.Push(lv.Values[i])
    24  		lv.L.Push(lv.Values[j])
    25  		lv.L.Call(2, 1)
    26  		return LVAsBool(lv.L.reg.Pop())
    27  	}
    28  	return lessThan(lv.L, lv.Values[i], lv.Values[j])
    29  }
    30  
    31  func newLTable(acap int, hcap int) *LTable {
    32  	if acap < 0 {
    33  		acap = 0
    34  	}
    35  	if hcap < 0 {
    36  		hcap = 0
    37  	}
    38  	tb := &LTable{Metatable: LNil}
    39  	if acap != 0 {
    40  		tb.array = make([]LValue, 0, acap)
    41  	}
    42  	if hcap != 0 {
    43  		tb.dict = make(map[LValue]lTableDictValue, hcap)
    44  		tb.keys = make([]*LValue, 0, hcap)
    45  	}
    46  	return tb
    47  }
    48  
    49  func (tb *LTable) DictionaryLen() int {
    50  	return len(tb.dict)
    51  }
    52  
    53  // Len returns length of this LTable.
    54  func (tb *LTable) Len() int {
    55  	if tb.array == nil {
    56  		return 0
    57  	}
    58  	var prev LValue = LNil
    59  	for i := len(tb.array) - 1; i >= 0; i-- {
    60  		v := tb.array[i]
    61  		if prev == LNil && v != LNil {
    62  			return i + 1
    63  		}
    64  		prev = v
    65  	}
    66  	return 0
    67  }
    68  
    69  // Append appends a given LValue to this LTable.
    70  func (tb *LTable) Append(value LValue) {
    71  	if value == LNil {
    72  		return
    73  	}
    74  	if tb.array == nil {
    75  		tb.array = make([]LValue, 0, defaultArrayCap)
    76  	}
    77  	if len(tb.array) == 0 || tb.array[len(tb.array)-1] != LNil {
    78  		tb.array = append(tb.array, value)
    79  	} else {
    80  		i := len(tb.array) - 2
    81  		for ; i >= 0; i-- {
    82  			if tb.array[i] != LNil {
    83  				break
    84  			}
    85  		}
    86  		tb.array[i+1] = value
    87  	}
    88  }
    89  
    90  // Insert inserts a given LValue at position `i` in this table.
    91  func (tb *LTable) Insert(i int, value LValue) {
    92  	if tb.array == nil {
    93  		tb.array = make([]LValue, 0, defaultArrayCap)
    94  	}
    95  	if i > len(tb.array) {
    96  		tb.RawSetInt(i, value)
    97  		return
    98  	}
    99  	if i <= 0 {
   100  		tb.RawSet(LNumber(i), value)
   101  		return
   102  	}
   103  	i -= 1
   104  	tb.array = append(tb.array, LNil)
   105  	copy(tb.array[i+1:], tb.array[i:])
   106  	tb.array[i] = value
   107  }
   108  
   109  // MaxN returns a maximum number key that nil value does not exist before it.
   110  func (tb *LTable) MaxN() int {
   111  	if tb.array == nil {
   112  		return 0
   113  	}
   114  	for i := len(tb.array) - 1; i >= 0; i-- {
   115  		if tb.array[i] != LNil {
   116  			return i + 1
   117  		}
   118  	}
   119  	return 0
   120  }
   121  
   122  // Remove removes from this table the element at a given position.
   123  func (tb *LTable) Remove(pos int) LValue {
   124  	if tb.array == nil {
   125  		return LNil
   126  	}
   127  	larray := len(tb.array)
   128  	if larray == 0 {
   129  		return LNil
   130  	}
   131  	i := pos - 1
   132  	oldval := LNil
   133  	switch {
   134  	case i >= larray:
   135  		// nothing to do
   136  	case i == larray-1 || i < 0:
   137  		oldval = tb.array[larray-1]
   138  		tb.array = tb.array[:larray-1]
   139  	default:
   140  		oldval = tb.array[i]
   141  		copy(tb.array[i:], tb.array[i+1:])
   142  		tb.array[larray-1] = nil
   143  		tb.array = tb.array[:larray-1]
   144  	}
   145  	return oldval
   146  }
   147  
   148  // RawSet sets a given LValue to a given index without the __newindex metamethod.
   149  // It is recommended to use `RawSetString` or `RawSetInt` for performance
   150  // if you already know the given LValue is a string or number.
   151  func (tb *LTable) RawSet(key LValue, value LValue) {
   152  	if v, ok := key.(LNumber); ok && isArrayKey(v) {
   153  		tb.RawSetInt(int(v), value)
   154  	} else {
   155  		tb.RawSetH(key, value)
   156  	}
   157  }
   158  
   159  // RawSetInt sets a given LValue at a position `key` without the __newindex metamethod.
   160  func (tb *LTable) RawSetInt(key int, value LValue) {
   161  	if key < 1 || key >= MaxArrayIndex {
   162  		tb.RawSetH(LNumber(key), value)
   163  		return
   164  	}
   165  	if tb.array == nil {
   166  		tb.array = make([]LValue, 0, defaultArrayCap)
   167  	}
   168  	index := key - 1
   169  	alen := len(tb.array)
   170  	switch {
   171  	case index == alen:
   172  		tb.array = append(tb.array, value)
   173  	case index > alen:
   174  		for i := 0; i < (index - alen); i++ {
   175  			tb.array = append(tb.array, LNil)
   176  		}
   177  		tb.array = append(tb.array, value)
   178  	case index < alen:
   179  		tb.array[index] = value
   180  	}
   181  }
   182  
   183  // RawSetString sets a given LValue to a given string index without the __newindex metamethod.
   184  func (tb *LTable) RawSetString(key string, value LValue) {
   185  	tb.RawSetH(LString(key), value)
   186  }
   187  
   188  // RawSetH sets a given LValue to a given index without the __newindex metamethod.
   189  func (tb *LTable) RawSetH(key LValue, value LValue) {
   190  	if tb.dict == nil {
   191  		tb.dict = make(map[LValue]lTableDictValue, defaultHashCap)
   192  	}
   193  	if tb.keys == nil {
   194  		tb.keys = make([]*LValue, 0, defaultHashCap)
   195  	}
   196  	if value == LNil {
   197  		// TODO tb.keys and tb.k2i should also be removed
   198  		delete(tb.dict, key)
   199  	} else {
   200  		tv := lTableDictValue{value: value}
   201  		if oldTV, ok := tb.dict [key]; ok {
   202  			tv.keyIndex = oldTV.keyIndex
   203  		} else {
   204  			tv.keyIndex = len(tb.keys)
   205  			tb.keys = append(tb.keys, &key)
   206  		}
   207  		tb.dict[key] = tv
   208  	}
   209  }
   210  
   211  // RawGet returns an LValue associated with a given key without __index metamethod.
   212  func (tb *LTable) RawGet(key LValue) LValue {
   213  	if v, ok := key.(LNumber); ok && isArrayKey(v) {
   214  		return tb.RawGetInt(int(v))
   215  	}
   216  	return tb.RawGetH(key)
   217  }
   218  
   219  // RawGetInt returns an LValue at position `key` without __index metamethod.
   220  func (tb *LTable) RawGetInt(key int) LValue {
   221  	if tb.array == nil {
   222  		return LNil
   223  	}
   224  	index := int(key) - 1
   225  	if index >= len(tb.array) || index < 0 {
   226  		return LNil
   227  	}
   228  	return tb.array[index]
   229  }
   230  
   231  // RawGet returns an LValue associated with a given key without __index metamethod.
   232  func (tb *LTable) RawGetH(key LValue) LValue {
   233  	if tb.dict == nil {
   234  		return LNil
   235  	}
   236  	if v, ok := tb.dict[key]; ok {
   237  		return v.value
   238  	}
   239  	return LNil
   240  }
   241  
   242  // RawGetString returns an LValue associated with a given key without __index metamethod.
   243  func (tb *LTable) RawGetString(key string) LValue {
   244  	return tb.RawGetH(LString(key))
   245  }
   246  
   247  // ForEach iterates over this table of elements, yielding each in turn to a given function.
   248  func (tb *LTable) ForEach(cb func(LValue, LValue)) {
   249  	if tb.array != nil {
   250  		for i, v := range tb.array {
   251  			if v != LNil {
   252  				cb(LNumber(i+1), v)
   253  			}
   254  		}
   255  	}
   256  	if tb.dict != nil {
   257  		for k, v := range tb.dict {
   258  			if v.value != LNil {
   259  				cb(k, v.value)
   260  			}
   261  		}
   262  	}
   263  }
   264  
   265  // This function is equivalent to lua_next ( http://www.lua.org/manual/5.1/manual.html#lua_next ).
   266  func (tb *LTable) Next(key LValue) (LValue, LValue) {
   267  	init := false
   268  	if key == LNil {
   269  		key = LNumber(0)
   270  		init = true
   271  	}
   272  
   273  	if init || key != LNumber(0) {
   274  		if kv, ok := key.(LNumber); ok && isInteger(kv) && int(kv) >= 0 && kv < LNumber(MaxArrayIndex) {
   275  			index := int(kv)
   276  			if tb.array != nil {
   277  				for ; index < len(tb.array); index++ {
   278  					if v := tb.array[index]; v != LNil {
   279  						return LNumber(index + 1), v
   280  					}
   281  				}
   282  			}
   283  			if tb.array == nil || index == len(tb.array) {
   284  				if (tb.dict == nil || len(tb.dict) == 0) {
   285  					return LNil, LNil
   286  				}
   287  				key = *tb.keys[0]
   288  				if v := tb.RawGetH(key); v != LNil {
   289  					return key, v
   290  				}
   291  			}
   292  		}
   293  	}
   294  
   295  	for i := tb.dict[key].keyIndex + 1; i < len(tb.keys); i++ {
   296  		key := *tb.keys[i]
   297  		if v := tb.RawGetH(key); v != LNil {
   298  			return key, v
   299  		}
   300  	}
   301  	return LNil, LNil
   302  }