Files
wnsrc/lua/includes/extensions/table.lua
lifestorm 94063e4369 Upload
2024-08-04 22:55:00 +03:00

816 lines
18 KiB
Lua

--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
function table.Pack( ... )
return { ... }, select( "#", ... )
end
--[[---------------------------------------------------------
Name: Inherit( t, base )
Desc: Copies any missing data from base to t
-----------------------------------------------------------]]
function table.Inherit( t, base )
for k, v in pairs( base ) do
if ( t[ k ] == nil ) then t[ k ] = v end
end
t[ "BaseClass" ] = base
return t
end
--[[---------------------------------------------------------
Name: Copy(t, lookup_table)
Desc: Taken straight from http://lua-users.org/wiki/PitLibTablestuff
and modified to the new Lua 5.1 code by me.
Original function by PeterPrade!
-----------------------------------------------------------]]
function table.Copy( t, lookup_table )
if ( t == nil ) then return nil end
local copy = {}
setmetatable( copy, debug.getmetatable( t ) )
for i, v in pairs( t ) do
if ( !istable( v ) ) then
copy[ i ] = v
else
lookup_table = lookup_table or {}
lookup_table[ t ] = copy
if ( lookup_table[ v ] ) then
copy[ i ] = lookup_table[ v ] -- we already copied this table. reuse the copy.
else
copy[ i ] = table.Copy( v, lookup_table ) -- not yet copied. copy it.
end
end
end
return copy
end
--[[---------------------------------------------------------
Name: Empty( tab )
Desc: Empty a table
-----------------------------------------------------------]]
function table.Empty( tab )
for k, v in pairs( tab ) do
tab[ k ] = nil
end
end
--[[---------------------------------------------------------
Name: IsEmpty( tab )
Desc: Returns whether a table has iterable items in it, useful for non-sequential tables
-----------------------------------------------------------]]
function table.IsEmpty( tab )
return next( tab ) == nil
end
--[[---------------------------------------------------------
Name: CopyFromTo( FROM, TO )
Desc: Make TO exactly the same as FROM - but still the same table.
-----------------------------------------------------------]]
function table.CopyFromTo( from, to )
-- Erase values from table TO
table.Empty( to )
-- Copy values over
table.Merge( to, from )
end
--[[---------------------------------------------------------
Name: Merge
Desc: xx
-----------------------------------------------------------]]
function table.Merge( dest, source, forceOverride )
for k, v in pairs( source ) do
if ( !forceOverride and istable( v ) and istable( dest[ k ] ) ) then
-- don't overwrite one table with another
-- instead merge them recurisvely
table.Merge( dest[ k ], v )
else
dest[ k ] = v
end
end
return dest
end
--[[---------------------------------------------------------
Name: HasValue
Desc: Returns whether the value is in given table
-----------------------------------------------------------]]
function table.HasValue( t, val )
for k, v in pairs( t ) do
if ( v == val ) then return true end
end
return false
end
--[[---------------------------------------------------------
Name: table.Add( dest, source )
Desc: Unlike merge this adds the two tables together and discards keys.
-----------------------------------------------------------]]
function table.Add( dest, source )
-- The tables should be different otherwise this will just freeze the whole game
if ( dest == source ) then return dest end
-- At least one of them needs to be a table or this whole thing will fall on its ass
if ( !istable( source ) ) then return dest end
if ( !istable( dest ) ) then dest = {} end
for k, v in pairs( source ) do
table.insert( dest, v )
end
return dest
end
--[[---------------------------------------------------------
Name: table.SortDesc( table )
Desc: Like Lua's default sort, but descending
-----------------------------------------------------------]]
function table.SortDesc( t )
return table.sort( t, function( a, b ) return a > b end )
end
--[[---------------------------------------------------------
Name: table.SortByKey( table )
Desc: Returns a table sorted numerically by Key value
-----------------------------------------------------------]]
function table.SortByKey( t, desc )
local temp = {}
for key, _ in pairs( t ) do table.insert( temp, key ) end
if ( desc ) then
table.sort( temp, function( a, b ) return t[ a ] < t[ b ] end )
else
table.sort( temp, function( a, b ) return t[ a ] > t[ b ] end )
end
return temp
end
--[[---------------------------------------------------------
Name: table.Count( table )
Desc: Returns the number of keys in a table
-----------------------------------------------------------]]
function table.Count( t )
local i = 0
for k in pairs( t ) do i = i + 1 end
return i
end
--[[---------------------------------------------------------
Name: table.Random( table )
Desc: Return a random key
-----------------------------------------------------------]]
function table.Random( t )
local rk = math.random( 1, table.Count( t ) )
local i = 1
for k, v in pairs( t ) do
if ( i == rk ) then return v, k end
i = i + 1
end
end
--[[---------------------------------------------------------
Name: table.Shuffle( table )
Desc: Performs an inline Fisher-Yates shuffle on the table in O(n) time
-----------------------------------------------------------]]
function table.Shuffle( t )
local n = #t
for i = 1, n - 1 do
local j = math.random( i, n )
t[ i ], t[ j ] = t[ j ], t[ i ]
end
end
--[[----------------------------------------------------------------------
Name: table.IsSequential( table )
Desc: Returns true if the tables
keys are sequential
-------------------------------------------------------------------------]]
function table.IsSequential( t )
local i = 1
for key, value in pairs( t ) do
if ( t[ i ] == nil ) then return false end
i = i + 1
end
return true
end
--[[---------------------------------------------------------
Name: table.ToString( table,name,nice )
Desc: Convert a simple table to a string
table = the table you want to convert (table)
name = the name of the table (string)
nice = whether to add line breaks and indents (bool)
-----------------------------------------------------------]]
local function MakeTable( t, nice, indent, done )
local str = ""
done = done or {}
indent = indent or 0
local idt = ""
if ( nice ) then idt = string.rep( "\t", indent ) end
local nl, tab = "", ""
if ( nice ) then nl, tab = "\n", "\t" end
local sequential = table.IsSequential( t )
for key, value in pairs( t ) do
str = str .. idt .. tab .. tab
if !sequential then
if ( isnumber( key ) or isbool( key ) ) then
key = "[" .. tostring( key ) .. "]" .. tab .. "="
else
key = tostring( key ) .. tab .. "="
end
else
key = ""
end
if ( istable( value ) and !done[ value ] ) then
if ( IsColor( value ) ) then
done[ value ] = true
value = "Color(" .. value.r .. "," .. value.g .. "," .. value.b .. "," .. value.a .. ")"
str = str .. key .. tab .. value .. "," .. nl
else
done[ value ] = true
str = str .. key .. tab .. '{' .. nl .. MakeTable( value, nice, indent + 1, done )
str = str .. idt .. tab .. tab .. tab .. tab .. "}," .. nl
end
else
if ( isstring( value ) ) then
value = '"' .. tostring( value ) .. '"'
elseif ( isvector( value ) ) then
value = "Vector(" .. value.x .. "," .. value.y .. "," .. value.z .. ")"
elseif ( isangle( value ) ) then
value = "Angle(" .. value.pitch .. "," .. value.yaw .. "," .. value.roll .. ")"
else
value = tostring( value )
end
str = str .. key .. tab .. value .. "," .. nl
end
end
return str
end
function table.ToString( t, n, nice )
local nl, tab = "", ""
if ( nice ) then nl, tab = "\n", "\t" end
local str = ""
if ( n ) then str = n .. tab .. "=" .. tab end
return str .. "{" .. nl .. MakeTable( t, nice ) .. "}"
end
--[[---------------------------------------------------------
Name: table.Sanitise( table )
Desc: Converts a table containing vectors, angles, bools so it can be converted to and from keyvalues
-----------------------------------------------------------]]
function table.Sanitise( t, done )
done = done or {}
local tbl = {}
for k, v in pairs ( t ) do
if ( istable( v ) and !IsColor( v ) and !done[ v ] ) then
done[ v ] = true
tbl[ k ] = table.Sanitise( v, done )
else
if ( isvector( v ) ) then
local x, y, z = v.x, v.y, v.z
if y == 0 then y = nil end
if z == 0 then z = nil end
tbl[ k ] = { __type = "Vector", x = x, y = y, z = z }
elseif ( isangle( v ) ) then
local p, y, r = v.pitch, v.yaw, v.roll
if p == 0 then p = nil end
if y == 0 then y = nil end
if r == 0 then r = nil end
tbl[ k ] = { __type = "Angle", p = p, y = y, r = r }
elseif ( IsColor( v ) ) then
local r, g, b, a = v.r, v.g, v.b, v.a
if r == 255 then r = nil end
if g == 255 then g = nil end
if b == 255 then b = nil end
if a == 255 then a = nil end
tbl[ k ] = { __type = "Color", r = r, g = g, b = b, a = a }
elseif ( isbool( v ) ) then
tbl[ k ] = { __type = "Bool", tostring( v ) }
else
tbl[ k ] = tostring( v )
end
end
end
return tbl
end
--[[---------------------------------------------------------
Name: table.DeSanitise( table )
Desc: Converts a Sanitised table back
-----------------------------------------------------------]]
function table.DeSanitise( t, done )
done = done or {}
local tbl = {}
for k, v in pairs ( t ) do
if ( istable( v ) and !IsColor( v ) and !done[ v ] ) then
done[ v ] = true
if ( v.__type ) then
if ( v.__type == "Vector" ) then
tbl[ k ] = Vector( v.x or 0, v.y, v.z )
elseif ( v.__type == "Angle" ) then
tbl[ k ] = Angle( v.p or 0, v.y, v.r )
elseif ( v.__type == "Color" ) then
tbl[ k ] = Color( v.r or 255, v.g or 255, v.b or 255, v.a or 255 )
elseif ( v.__type == "Bool" ) then
tbl[ k ] = ( v[ 1 ] == "true" )
end
else
tbl[ k ] = table.DeSanitise( v, done )
end
else
tbl[ k ] = v
end
end
return tbl
end
function table.ForceInsert( t, v )
if ( t == nil ) then t = {} end
table.insert( t, v )
return t
end
--[[---------------------------------------------------------
Name: table.SortByMember( table )
Desc: Sorts table by named member
-----------------------------------------------------------]]
function table.SortByMember( tab, memberName, bAsc )
local TableMemberSort = function( a, b, MemberName, bReverse )
--
-- All this error checking kind of sucks, but really is needed
--
if ( !istable( a ) ) then return !bReverse end
if ( !istable( b ) ) then return bReverse end
if ( !a[ MemberName ] ) then return !bReverse end
if ( !b[ MemberName ] ) then return bReverse end
if ( isstring( a[ MemberName ] ) ) then
if ( bReverse ) then
return a[ MemberName ]:lower() < b[ MemberName ]:lower()
else
return a[ MemberName ]:lower() > b[ MemberName ]:lower()
end
end
if ( bReverse ) then
return a[ MemberName ] < b[ MemberName ]
else
return a[ MemberName ] > b[ MemberName ]
end
end
table.sort( tab, function( a, b ) return TableMemberSort( a, b, memberName, bAsc or false ) end )
end
--[[---------------------------------------------------------
Name: table.LowerKeyNames( table )
Desc: Lowercase the keynames of all tables
-----------------------------------------------------------]]
function table.LowerKeyNames( tab )
local OutTable = {}
for k, v in pairs( tab ) do
-- Recurse
if ( istable( v ) ) then
v = table.LowerKeyNames( v )
end
OutTable[ k ] = v
if ( isstring( k ) ) then
OutTable[ k ] = nil
OutTable[ string.lower( k ) ] = v
end
end
return OutTable
end
--[[---------------------------------------------------------
Name: table.CollapseKeyValue( table )
Desc: Collapses a table with keyvalue structure
-----------------------------------------------------------]]
function table.CollapseKeyValue( Table )
local OutTable = {}
for k, v in pairs( Table ) do
local Val = v.Value
if ( istable( Val ) ) then
Val = table.CollapseKeyValue( Val )
end
OutTable[ v.Key ] = Val
end
return OutTable
end
--[[---------------------------------------------------------
Name: table.ClearKeys( table, bSaveKey )
Desc: Clears the keys, converting to a numbered format
-----------------------------------------------------------]]
function table.ClearKeys( Table, bSaveKey )
local OutTable = {}
for k, v in pairs( Table ) do
if ( bSaveKey ) then
v.__key = k
end
table.insert( OutTable, v )
end
return OutTable
end
local function keyValuePairs( state )
state.Index = state.Index + 1
local keyValue = state.KeyValues[ state.Index ]
if ( !keyValue ) then return end
return keyValue.key, keyValue.val
end
local function toKeyValues( tbl )
local result = {}
for k, v in pairs( tbl ) do
table.insert( result, { key = k, val = v } )
end
return result
end
local function getKeys( tbl )
local keys = {}
for k in pairs( tbl ) do
table.insert( keys, k )
end
return keys
end
--[[---------------------------------------------------------
A Pairs function
Sorted by TABLE KEY
-----------------------------------------------------------]]
function SortedPairs( pTable, Desc )
local keys = getKeys( pTable )
if ( Desc ) then
table.sort( keys, function( a, b )
return a > b
end )
else
table.sort( keys, function( a, b )
return a < b
end )
end
local i, key
return function()
i, key = next( keys, i )
return key, pTable[key]
end
end
--[[---------------------------------------------------------
A Pairs function
Sorted by VALUE
-----------------------------------------------------------]]
function SortedPairsByValue( pTable, Desc )
local sortedTbl = toKeyValues( pTable )
if ( Desc ) then
table.sort( sortedTbl, function( a, b ) return a.val > b.val end )
else
table.sort( sortedTbl, function( a, b ) return a.val < b.val end )
end
return keyValuePairs, { Index = 0, KeyValues = sortedTbl }
end
--[[---------------------------------------------------------
A Pairs function
Sorted by Member Value (All table entries must be a table!)
-----------------------------------------------------------]]
function SortedPairsByMemberValue( pTable, pValueName, Desc )
local sortedTbl = toKeyValues( pTable )
for k, v in pairs( sortedTbl ) do
v.member = v.val[ pValueName ]
end
table.SortByMember( sortedTbl, "member", !Desc )
return keyValuePairs, { Index = 0, KeyValues = sortedTbl }
end
--[[---------------------------------------------------------
A Pairs function
-----------------------------------------------------------]]
function RandomPairs( pTable, Desc )
local sortedTbl = toKeyValues( pTable )
for k, v in pairs( sortedTbl ) do
v.rand = math.random( 1, 1000000 )
end
-- descending/ascending for a random order, really?
if ( Desc ) then
table.sort( sortedTbl, function( a, b ) return a.rand > b.rand end )
else
table.sort( sortedTbl, function( a, b ) return a.rand < b.rand end )
end
return keyValuePairs, { Index = 0, KeyValues = sortedTbl }
end
--[[---------------------------------------------------------
GetFirstKey
-----------------------------------------------------------]]
function table.GetFirstKey( t )
local k, _ = next( t )
return k
end
function table.GetFirstValue( t )
local _, v = next( t )
return v
end
function table.GetLastKey( t )
local k, _ = next( t, table.Count( t ) - 1 )
return k
end
function table.GetLastValue( t )
local _, v = next( t, table.Count( t ) - 1 )
return v
end
function table.FindNext( tab, val )
local bfound = false
for k, v in pairs( tab ) do
if ( bfound ) then return v end
if ( val == v ) then bfound = true end
end
return table.GetFirstValue( tab )
end
function table.FindPrev( tab, val )
local last = table.GetLastValue( tab )
for k, v in pairs( tab ) do
if ( val == v ) then return last end
last = v
end
return last
end
function table.GetWinningKey( tab )
local highest = -math.huge
local winner = nil
for k, v in pairs( tab ) do
if ( v > highest ) then
winner = k
highest = v
end
end
return winner
end
function table.KeyFromValue( tbl, val )
for key, value in pairs( tbl ) do
if ( value == val ) then return key end
end
end
function table.RemoveByValue( tbl, val )
local key = table.KeyFromValue( tbl, val )
if ( !key ) then return false end
if ( isnumber( key ) ) then
table.remove( tbl, key )
else
tbl[ key ] = nil
end
return key
end
function table.KeysFromValue( tbl, val )
local res = {}
for key, value in pairs( tbl ) do
if ( value == val ) then res[ #res + 1 ] = key end
end
return res
end
function table.MemberValuesFromKey( tab, key )
local res = {}
for k, v in pairs( tab ) do
if ( istable( v ) and v[ key ] != nil ) then res[ #res + 1 ] = v[ key ] end
end
return res
end
function table.Reverse( tbl )
local len = #tbl
local ret = {}
for i = len, 1, -1 do
ret[ len - i + 1 ] = tbl[ i ]
end
return ret
end
function table.ForEach( tab, funcname )
for k, v in pairs( tab ) do
funcname( k, v )
end
end
function table.GetKeys( tab )
local keys = {}
local id = 1
for k, v in pairs( tab ) do
keys[ id ] = k
id = id + 1
end
return keys
end
function table.Flip( tab )
local res = {}
for k, v in pairs( tab ) do
res[ v ] = k
end
return res
end
-- Polyfill for table.move on 32-bit
-- Don't forget to remove this when it's no longer necessary
if ( !table.move ) then
function table.move( sourceTbl, from, to, dest, destTbl )
if ( !istable( sourceTbl ) ) then error( "bad argument #1 to 'move' (table expected, got " .. type( sourceTbl ) .. ")" ) end
if ( !isnumber( from ) ) then error( "bad argument #2 to 'move' (number expected, got " .. type( from ) .. ")" ) end
if ( !isnumber( to ) ) then error( "bad argument #3 to 'move' (number expected, got " .. type( to ) .. ")" ) end
if ( !isnumber( dest ) ) then error( "bad argument #4 to 'move' (number expected, got " .. type( dest ) .. ")" ) end
if ( destTbl != nil ) then
if ( !istable( destTbl ) ) then error( "bad argument #5 to 'move' (table expected, got " .. type( destTbl ) .. ")" ) end
else
destTbl = sourceTbl
end
local buffer = { unpack( sourceTbl, from, to ) }
dest = math.floor( dest - 1 )
for i, v in ipairs( buffer ) do
destTbl[ dest + i ] = v
end
return destTbl
end
end