github.com/bitxmesh/gopher-lua@v0.0.0-20190327085718-93c344ef97a4/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{}
    39  	tb.Metatable = LNil
    40  	if acap != 0 {
    41  		tb.array = make([]LValue, 0, acap)
    42  	}
    43  	if hcap != 0 {
    44  		tb.strdict = make(map[string]LValue, hcap)
    45  	}
    46  	return tb
    47  }
    48  
    49  // Len returns length of this LTable.
    50  func (tb *LTable) Len() int {
    51  	if tb.array == nil {
    52  		return 0
    53  	}
    54  	var prev LValue = LNil
    55  	for i := len(tb.array) - 1; i >= 0; i-- {
    56  		v := tb.array[i]
    57  		if prev == LNil && v != LNil {
    58  			return i + 1
    59  		}
    60  		prev = v
    61  	}
    62  	return 0
    63  }
    64  
    65  // Append appends a given LValue to this LTable.
    66  func (tb *LTable) Append(value LValue) {
    67  	if value == LNil {
    68  		return
    69  	}
    70  	if tb.array == nil {
    71  		tb.array = make([]LValue, 0, defaultArrayCap)
    72  	}
    73  	tb.array = append(tb.array, value)
    74  }
    75  
    76  // Insert inserts a given LValue at position `i` in this table.
    77  func (tb *LTable) Insert(i int, value LValue) {
    78  	if tb.array == nil {
    79  		tb.array = make([]LValue, 0, defaultArrayCap)
    80  	}
    81  	if i > len(tb.array) {
    82  		tb.RawSetInt(i, value)
    83  		return
    84  	}
    85  	if i <= 0 {
    86  		tb.RawSet(LNumber(i), value)
    87  		return
    88  	}
    89  	i -= 1
    90  	tb.array = append(tb.array, LNil)
    91  	copy(tb.array[i+1:], tb.array[i:])
    92  	tb.array[i] = value
    93  }
    94  
    95  // MaxN returns a maximum number key that nil value does not exist before it.
    96  func (tb *LTable) MaxN() int {
    97  	if tb.array == nil {
    98  		return 0
    99  	}
   100  	for i := len(tb.array) - 1; i >= 0; i-- {
   101  		if tb.array[i] != LNil {
   102  			return i + 1
   103  		}
   104  	}
   105  	return 0
   106  }
   107  
   108  // Remove removes from this table the element at a given position.
   109  func (tb *LTable) Remove(pos int) LValue {
   110  	if tb.array == nil {
   111  		return LNil
   112  	}
   113  	larray := len(tb.array)
   114  	if larray == 0 {
   115  		return LNil
   116  	}
   117  	i := pos - 1
   118  	oldval := LNil
   119  	switch {
   120  	case i >= larray:
   121  		// nothing to do
   122  	case i == larray-1 || i < 0:
   123  		oldval = tb.array[larray-1]
   124  		tb.array = tb.array[:larray-1]
   125  	default:
   126  		oldval = tb.array[i]
   127  		copy(tb.array[i:], tb.array[i+1:])
   128  		tb.array[larray-1] = nil
   129  		tb.array = tb.array[:larray-1]
   130  	}
   131  	return oldval
   132  }
   133  
   134  // RawSet sets a given LValue to a given index without the __newindex metamethod.
   135  // It is recommended to use `RawSetString` or `RawSetInt` for performance
   136  // if you already know the given LValue is a string or number.
   137  func (tb *LTable) RawSet(key LValue, value LValue) {
   138  	switch v := key.(type) {
   139  	case LNumber:
   140  		if isArrayKey(v) {
   141  			if tb.array == nil {
   142  				tb.array = make([]LValue, 0, defaultArrayCap)
   143  			}
   144  			index := int(v) - 1
   145  			alen := len(tb.array)
   146  			switch {
   147  			case index == alen:
   148  				tb.array = append(tb.array, value)
   149  			case index > alen:
   150  				for i := 0; i < (index - alen); i++ {
   151  					tb.array = append(tb.array, LNil)
   152  				}
   153  				tb.array = append(tb.array, value)
   154  			case index < alen:
   155  				tb.array[index] = value
   156  			}
   157  			return
   158  		}
   159  	case LString:
   160  		tb.RawSetString(string(v), value)
   161  		return
   162  	}
   163  
   164  	tb.RawSetH(key, value)
   165  }
   166  
   167  // RawSetInt sets a given LValue at a position `key` without the __newindex metamethod.
   168  func (tb *LTable) RawSetInt(key int, value LValue) {
   169  	if key < 1 || key >= MaxArrayIndex {
   170  		tb.RawSetH(LNumber(key), value)
   171  		return
   172  	}
   173  	if tb.array == nil {
   174  		tb.array = make([]LValue, 0, 32)
   175  	}
   176  	index := key - 1
   177  	alen := len(tb.array)
   178  	switch {
   179  	case index == alen:
   180  		tb.array = append(tb.array, value)
   181  	case index > alen:
   182  		for i := 0; i < (index - alen); i++ {
   183  			tb.array = append(tb.array, LNil)
   184  		}
   185  		tb.array = append(tb.array, value)
   186  	case index < alen:
   187  		tb.array[index] = value
   188  	}
   189  }
   190  
   191  // RawSetString sets a given LValue to a given string index without the __newindex metamethod.
   192  func (tb *LTable) RawSetString(key string, value LValue) {
   193  	if tb.strdict == nil {
   194  		tb.strdict = make(map[string]LValue, defaultHashCap)
   195  	}
   196  	if tb.keys == nil {
   197  		tb.keys = []LValue{}
   198  		tb.k2i = map[LValue]int{}
   199  	}
   200  
   201  	if value == LNil {
   202  		// TODO tb.keys and tb.k2i should also be removed
   203  		delete(tb.strdict, key)
   204  	} else {
   205  		tb.strdict[key] = value
   206  		lkey := LString(key)
   207  		if _, ok := tb.k2i[lkey]; !ok {
   208  			tb.k2i[lkey] = len(tb.keys)
   209  			tb.keys = append(tb.keys, lkey)
   210  		}
   211  	}
   212  }
   213  
   214  // RawSetH sets a given LValue to a given index without the __newindex metamethod.
   215  func (tb *LTable) RawSetH(key LValue, value LValue) {
   216  	if s, ok := key.(LString); ok {
   217  		tb.RawSetString(string(s), value)
   218  		return
   219  	}
   220  	if tb.dict == nil {
   221  		tb.dict = make(map[LValue]LValue, len(tb.strdict))
   222  	}
   223  	if tb.keys == nil {
   224  		tb.keys = []LValue{}
   225  		tb.k2i = map[LValue]int{}
   226  	}
   227  
   228  	if value == LNil {
   229  		// TODO tb.keys and tb.k2i should also be removed
   230  		delete(tb.dict, key)
   231  	} else {
   232  		tb.dict[key] = value
   233  		if _, ok := tb.k2i[key]; !ok {
   234  			tb.k2i[key] = len(tb.keys)
   235  			tb.keys = append(tb.keys, key)
   236  		}
   237  	}
   238  }
   239  
   240  // RawGet returns an LValue associated with a given key without __index metamethod.
   241  func (tb *LTable) RawGet(key LValue) LValue {
   242  	switch v := key.(type) {
   243  	case LNumber:
   244  		if isArrayKey(v) {
   245  			if tb.array == nil {
   246  				return LNil
   247  			}
   248  			index := int(v) - 1
   249  			if index >= len(tb.array) {
   250  				return LNil
   251  			}
   252  			return tb.array[index]
   253  		}
   254  	case LString:
   255  		if tb.strdict == nil {
   256  			return LNil
   257  		}
   258  		if ret, ok := tb.strdict[string(v)]; ok {
   259  			return ret
   260  		}
   261  		return LNil
   262  	}
   263  	if tb.dict == nil {
   264  		return LNil
   265  	}
   266  	if v, ok := tb.dict[key]; ok {
   267  		return v
   268  	}
   269  	return LNil
   270  }
   271  
   272  // RawGetInt returns an LValue at position `key` without __index metamethod.
   273  func (tb *LTable) RawGetInt(key int) LValue {
   274  	if tb.array == nil {
   275  		return LNil
   276  	}
   277  	index := int(key) - 1
   278  	if index >= len(tb.array) || index < 0 {
   279  		return LNil
   280  	}
   281  	return tb.array[index]
   282  }
   283  
   284  // RawGet returns an LValue associated with a given key without __index metamethod.
   285  func (tb *LTable) RawGetH(key LValue) LValue {
   286  	if s, sok := key.(LString); sok {
   287  		if tb.strdict == nil {
   288  			return LNil
   289  		}
   290  		if v, vok := tb.strdict[string(s)]; vok {
   291  			return v
   292  		}
   293  		return LNil
   294  	}
   295  	if tb.dict == nil {
   296  		return LNil
   297  	}
   298  	if v, ok := tb.dict[key]; ok {
   299  		return v
   300  	}
   301  	return LNil
   302  }
   303  
   304  // RawGetString returns an LValue associated with a given key without __index metamethod.
   305  func (tb *LTable) RawGetString(key string) LValue {
   306  	if tb.strdict == nil {
   307  		return LNil
   308  	}
   309  	if v, vok := tb.strdict[string(key)]; vok {
   310  		return v
   311  	}
   312  	return LNil
   313  }
   314  
   315  // ForEach iterates over this table of elements, yielding each in turn to a given function.
   316  func (tb *LTable) ForEach(cb func(LValue, LValue)) {
   317  	if tb.array != nil {
   318  		for i, v := range tb.array {
   319  			if v != LNil {
   320  				cb(LNumber(i+1), v)
   321  			}
   322  		}
   323  	}
   324  	if tb.strdict != nil {
   325  		for k, v := range tb.strdict {
   326  			if v != LNil {
   327  				cb(LString(k), v)
   328  			}
   329  		}
   330  	}
   331  	if tb.dict != nil {
   332  		for k, v := range tb.dict {
   333  			if v != LNil {
   334  				cb(k, v)
   335  			}
   336  		}
   337  	}
   338  }
   339  
   340  // This function is equivalent to lua_next ( http://www.lua.org/manual/5.1/manual.html#lua_next ).
   341  func (tb *LTable) Next(key LValue) (LValue, LValue) {
   342  	init := false
   343  	if key == LNil {
   344  		key = LNumber(0)
   345  		init = true
   346  	}
   347  
   348  	if init || key != LNumber(0) {
   349  		if kv, ok := key.(LNumber); ok && isInteger(kv) && int(kv) >= 0 && kv < LNumber(MaxArrayIndex) {
   350  			index := int(kv)
   351  			if tb.array != nil {
   352  				for ; index < len(tb.array); index++ {
   353  					if v := tb.array[index]; v != LNil {
   354  						return LNumber(index + 1), v
   355  					}
   356  				}
   357  			}
   358  			if tb.array == nil || index == len(tb.array) {
   359  				if (tb.dict == nil || len(tb.dict) == 0) && (tb.strdict == nil || len(tb.strdict) == 0) {
   360  					return LNil, LNil
   361  				}
   362  				key = tb.keys[0]
   363  				if v := tb.RawGetH(key); v != LNil {
   364  					return key, v
   365  				}
   366  			}
   367  		}
   368  	}
   369  
   370  	for i := tb.k2i[key] + 1; i < len(tb.keys); i++ {
   371  		key := tb.keys[i]
   372  		if v := tb.RawGetH(key); v != LNil {
   373  			return key, v
   374  		}
   375  	}
   376  	return LNil, LNil
   377  }