github.com/xyproto/gopher-lua@v1.0.2/table.go (about)

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