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