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