// The CMLeonOS Project (https://github.com/Leonmmcoset/CMLeonOS)
// Copyright (C) 2025-present LeonOS 2 Developer Team
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
#define LUA_COMPAT_UNPACK
namespace UniLua
{
using StringBuilder = System.Text.StringBuilder;
internal class LuaTableLib
{
public const string LIB_NAME = "table";
public static int OpenLib( ILuaState lua )
{
NameFuncPair[] define = new NameFuncPair[]
{
new NameFuncPair( "concat", TBL_Concat ),
new NameFuncPair( "maxn", TBL_MaxN ),
new NameFuncPair( "insert", TBL_Insert ),
new NameFuncPair( "pack", TBL_Pack ),
new NameFuncPair( "unpack", TBL_Unpack ),
new NameFuncPair( "remove", TBL_Remove ),
new NameFuncPair( "sort", TBL_Sort ),
};
lua.L_NewLib( define );
#if LUA_COMPAT_UNPACK
// _G.unpack = table.unpack
lua.GetField( -1, "unpack" );
lua.SetGlobal( "unpack" );
#endif
return 1;
}
private static int TBL_Concat( ILuaState lua )
{
string sep = lua.L_OptString( 2, "" );
lua.L_CheckType( 1, LuaType.LUA_TTABLE );
int i = lua.L_OptInt( 3, 1 );
int last = lua.L_Opt(4, lua.L_Len(1));
StringBuilder sb = new StringBuilder();
for( ; i max ) max = v;
}
}
lua.PushNumber( max );
return 1;
}
private static int AuxGetN( ILuaState lua, int n )
{
lua.L_CheckType( n, LuaType.LUA_TTABLE );
return lua.L_Len( n );
}
private static int TBL_Insert( ILuaState lua )
{
int e = AuxGetN(lua, 1) + 1; // first empty element
int pos; // where to insert new element
switch( lua.GetTop() )
{
case 2: // called with only 2 arguments
{
pos = e; // insert new element at the end
break;
}
case 3:
{
pos = lua.L_CheckInteger(2); // 2nd argument is the position
if( pos > e ) e = pos; // `grow' array if necessary
for( int i=e; i>pos; --i ) // move up elements
{
lua.RawGetI( 1, i-1 );
lua.RawSetI( 1, i ); // t[i] = t[i-1]
}
break;
}
default:
{
return lua.L_Error( "wrong number of arguments to 'insert'" );
}
}
lua.RawSetI( 1, pos ); // t[pos] = v
return 0;
}
private static int TBL_Remove( ILuaState lua )
{
int e = AuxGetN(lua, 1);
int pos = lua.L_OptInt( 2, e );
if( !(1 <= pos && pos <= e) ) // position is outside bounds?
return 0; // nothing to remove
lua.RawGetI(1, pos); /* result = t[pos] */
for( ; pos 0 ) // at least one element?
{
lua.PushValue( 1 );
lua.RawSetI( -2, 1 ); // insert first element
lua.Replace( 1 ); // move table into index 1
for( int i=n; i>=2; --i ) // assign other elements
lua.RawSetI( 1, i );
}
return 1; // return table
}
private static int TBL_Unpack( ILuaState lua )
{
lua.L_CheckType( 1, LuaType.LUA_TTABLE );
int i = lua.L_OptInt( 2, 1 );
int e = lua.L_OptInt( 3, lua.L_Len(1) );
if( i > e ) return 0; // empty range
int n = e - i + 1; // number of elements
if( n <= 0 || !lua.CheckStack(n) ) // n <= 0 means arith. overflow
return lua.L_Error( "too many results to unpack" );
lua.RawGetI( 1, i ); // push arg[i] (avoiding overflow problems
while( i++ < e ) // push arg[i + 1...e]
lua.RawGetI( 1, i );
return n;
}
// quick sort ////////////////////////////////////////////////////////
private static void Set2( ILuaState lua, int i, int j )
{
lua.RawSetI( 1, i );
lua.RawSetI( 1, j );
}
private static bool SortComp( ILuaState lua, int a, int b )
{
if( !lua.IsNil(2) ) // function?
{
lua.PushValue( 2 );
lua.PushValue( a-1 ); // -1 to compensate function
lua.PushValue( b-2 ); // -2 to compensate function add `a'
lua.Call( 2, 1 );
bool res = lua.ToBoolean( -1 );
lua.Pop( 1 );
return res;
}
else /// a < b?
return lua.Compare( a, b, LuaEq.LUA_OPLT );
}
private static void AuxSort( ILuaState lua, int l, int u )
{
while( l < u ) // for tail recursion
{
// sort elements a[l], a[(l+u)/2] and a[u]
lua.RawGetI( 1, l );
lua.RawGetI( 1, u );
if( SortComp( lua, -1, -2 ) ) // a[u] < a[l]?
Set2( lua, l, u );
else
lua.Pop( 2 );
if( u-l == 1 ) break; // only 2 elements
int i = (l+u) / 2;
lua.RawGetI( 1, i );
lua.RawGetI( 1, l );
if( SortComp( lua, -2, -1 ) ) // a[i] < a[l]?
Set2( lua, i, l );
else
{
lua.Pop( 1 ); // remove a[l]
lua.RawGetI( 1, u );
if( SortComp( lua, -1, -2 ) ) // a[u] < a[i]?
Set2( lua, i, u );
else
lua.Pop( 2 );
}
if( u-l == 2 ) break; // only 3 arguments
lua.RawGetI( 1, i ); // Pivot
lua.PushValue( -1 );
lua.RawGetI( 1, u-1 );
Set2(lua, i, u-1);
/* a[l] <= P == a[u-1] <= a[u], only need to sort from l+1 to u-2 */
i = l;
int j = u-1;
for (;;) { /* invariant: a[l..i] <= P <= a[j..u] */
/* repeat ++i until a[i] >= P */
lua.RawGetI( 1, ++i );
while( SortComp(lua, -1, -2) )
{
if (i>=u) lua.L_Error( "invalid order function for sorting" );
lua.Pop(1); /* remove a[i] */
lua.RawGetI( 1, ++i );
}
/* repeat --j until a[j] <= P */
lua.RawGetI( 1, --j );
while ( SortComp(lua, -3, -1) ) {
if (j<=l) lua.L_Error( "invalid order function for sorting" );
lua.Pop(1); /* remove a[j] */
lua.RawGetI( 1, --j );
}
if (j