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