Add support for metatags to table lib methods: sort, insert, remove, unpack.

```
do   -- testing table library with metamethods
  local function test (proxy, t)
    for i = 1, 10 do
      table.insert(proxy, 1, i)
    end
    assert(#proxy == 10 and #t == 10, tostring(#proxy)..'; '..tostring(#t))
    for i = 1, 10 do
      assert(t[i] == 11 - i)
    end
    table.sort(proxy)
    for i = 1, 10 do
      assert(t[i] == i and proxy[i] == i, i..': '..tostring(proxy[i])..'; '..tostring(t[i]))
    end
    assert(table.concat(proxy, ",") == "1,2,3,4,5,6,7,8,9,10")
    for i = 1, 8 do
      assert(table.remove(proxy, 1) == i)
    end
    assert(#proxy == 2 and #t == 2)
    local a, b, c = table.unpack(proxy)
    assert(a == 9 and b == 10 and c == nil)
  end

  -- all virtual
  local t = {}
  local proxy = setmetatable({}, {
    __len = function () return #t end,
    __index = t,
    __newindex = t,
  })
  test(proxy, t)

  -- only __newindex
  local count = 0
  t = setmetatable({}, {
    __newindex = function (t,k,v) count = count + 1; rawset(t,k,v) end})
  test(t, t)
  assert(count == 10)   -- after first 10, all other sets are not new

  -- no __newindex
  t = setmetatable({}, {
    __index = function (_,k) return k + 1 end,
    __len = function (_) return 5 end})
  assert(table.concat(t, ";") == "2;3;4;5;6")

end

function check (a, f)
  f = f or function (x,y) return x<y end;
  for n = #a, 2, -1 do
    local cmp = f(a[n], a[n-1])
    if cmp then print(tostring(a)..'\n'..n..': "'..tostring(a[n])..'" < "'..tostring(a[n-1])..'"') end
    assert(not cmp)
  end
end

for b = 1, 2 do
	a = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep",
	     "Oct", "Nov", "Dec"}
	if b == 2 then a[15] = 'Aaa' a[14] = 'Iii' a[13] = 'Mmm' end
	print(#a)
	table.sort(a)
	check(a)
end
```
This commit is contained in:
Enyby
2019-11-04 07:57:49 +02:00
parent e120008f9b
commit bf663878cb
2 changed files with 22 additions and 36 deletions

View File

@@ -299,15 +299,15 @@ public class LuaTable extends LuaValue implements Metatable {
* @return The removed item, or {@link #NONE} if not removed * @return The removed item, or {@link #NONE} if not removed
*/ */
public LuaValue remove(int pos) { public LuaValue remove(int pos) {
int n = rawlen(); int n = length();
if ( pos == 0 ) if ( pos == 0 )
pos = n; pos = n;
else if (pos > n) else if (pos > n)
return NONE; return NONE;
LuaValue v = rawget(pos); LuaValue v = get(pos);
for ( LuaValue r=v; !r.isnil(); ) { for ( LuaValue r=v; !r.isnil(); ) {
r = rawget(pos+1); r = get(pos+1);
rawset(pos++, r); set(pos++, r);
} }
return v.isnil()? NONE: v; return v.isnil()? NONE: v;
} }
@@ -319,10 +319,10 @@ public class LuaTable extends LuaValue implements Metatable {
*/ */
public void insert(int pos, LuaValue value) { public void insert(int pos, LuaValue value) {
if ( pos == 0 ) if ( pos == 0 )
pos = rawlen()+1; pos = length()+1;
while ( ! value.isnil() ) { while ( ! value.isnil() ) {
LuaValue v = rawget( pos ); LuaValue v = get( pos );
rawset(pos++, value); set(pos++, value);
value = v; value = v;
} }
} }
@@ -789,40 +789,35 @@ public class LuaTable extends LuaValue implements Metatable {
if (m_metatable != null && m_metatable.useWeakValues()) { if (m_metatable != null && m_metatable.useWeakValues()) {
dropWeakArrayValues(); dropWeakArrayValues();
} }
LuaValue[] array = this.array; int n = length();
int n = array.length;
while ( n > 0 && array[n-1] == null )
--n;
if ( n > 1 ) if ( n > 1 )
heapSort(n, comparator.isnil() ? null : comparator); heapSort(n, comparator.isnil() ? null : comparator);
} }
private void heapSort(int count, LuaValue cmpfunc) { private void heapSort(int count, LuaValue cmpfunc) {
heapify(count, cmpfunc); heapify(count, cmpfunc);
LuaValue[] array = this.array; for ( int end=count; end>1; ) {
for ( int end=count-1; end>0; ) { LuaValue a = get(end); // swap(end, 1)
LuaValue a = array[end]; // swap(end, 0) set(end, get(1));
array[end] = array[0]; set(1, a);
array[0] = a; siftDown(1, --end, cmpfunc);
siftDown(0, --end, cmpfunc);
} }
} }
private void heapify(int count, LuaValue cmpfunc) { private void heapify(int count, LuaValue cmpfunc) {
for ( int start=count/2-1; start>=0; --start ) for ( int start=count/2; start>0; --start )
siftDown(start, count - 1, cmpfunc); siftDown(start, count, cmpfunc);
} }
private void siftDown(int start, int end, LuaValue cmpfunc) { private void siftDown(int start, int end, LuaValue cmpfunc) {
LuaValue[] array = this.array; for ( int root=start; root*2 <= end; ) {
for ( int root=start; root*2+1 <= end; ) { int child = root*2;
int child = root*2+1;
if (child < end && compare(child, child + 1, cmpfunc)) if (child < end && compare(child, child + 1, cmpfunc))
++child; ++child;
if (compare(root, child, cmpfunc)) { if (compare(root, child, cmpfunc)) {
LuaValue a = array[root]; // swap(root, child) LuaValue a = get(root); // swap(root, child)
array[root] = array[child]; set(root, get(child));
array[child] = a; set(child, a);
root = child; root = child;
} else } else
return; return;
@@ -830,16 +825,7 @@ public class LuaTable extends LuaValue implements Metatable {
} }
private boolean compare(int i, int j, LuaValue cmpfunc) { private boolean compare(int i, int j, LuaValue cmpfunc) {
LuaValue a, b; LuaValue a = get(i), b = get(j);
LuaValue[] array = this.array;
Metatable m_metatable = this.m_metatable;
if (m_metatable == null) {
a = array[i];
b = array[j];
} else {
a = m_metatable.arrayget(array, i);
b = m_metatable.arrayget(array, j);
}
if ( a == null || b == null ) if ( a == null || b == null )
return false; return false;
if ( cmpfunc != null ) { if ( cmpfunc != null ) {

View File

@@ -151,7 +151,7 @@ public class TableLib extends TwoArgFunction {
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
LuaTable t = args.checktable(1); LuaTable t = args.checktable(1);
// do not waste resource for calc rawlen if arg3 is not nil // do not waste resource for calc rawlen if arg3 is not nil
int len = args.arg(3).isnil() ? t.rawlen() : 0; int len = args.arg(3).isnil() ? t.length() : 0;
return t.unpack(args.optint(2, 1), args.optint(3, len)); return t.unpack(args.optint(2, 1), args.optint(3, len));
} }
} }