175 lines
		
	
	
	
		
			4.3 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
			
		
		
	
	
			175 lines
		
	
	
	
		
			4.3 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
| --[[
 | |
|     https://github.com/overextended/ox_lib
 | |
| 
 | |
|     This file is licensed under LGPL-3.0 or higher <https://www.gnu.org/licenses/lgpl-3.0.en.html>
 | |
| 
 | |
|     Copyright © 2025 Linden <https://github.com/thelindat>
 | |
| ]]
 | |
| 
 | |
| -- Add additional functions to the standard table library
 | |
| 
 | |
| ---@class oxtable : tablelib
 | |
| lib.table = table
 | |
| local pairs = pairs
 | |
| 
 | |
| ---@param tbl table
 | |
| ---@param value any
 | |
| ---@return boolean
 | |
| ---Checks if tbl contains the given values. Only intended for simple values and unnested tables.
 | |
| local function contains(tbl, value)
 | |
|     if type(value) ~= 'table' then
 | |
|         for _, v in pairs(tbl) do
 | |
|             if v == value then
 | |
|                 return true
 | |
|             end
 | |
|         end
 | |
| 
 | |
|         return false
 | |
|     else
 | |
|         local set = {}
 | |
| 
 | |
|         for _, v in pairs(tbl) do
 | |
|             set[v] = true
 | |
|         end
 | |
| 
 | |
|         for _, v in pairs(value) do
 | |
|             if not set[v] then
 | |
|                 return false
 | |
|             end
 | |
|         end
 | |
| 
 | |
|         return true
 | |
|     end
 | |
| end
 | |
| 
 | |
| ---@param t1 any
 | |
| ---@param t2 any
 | |
| ---@return boolean
 | |
| ---Compares if two values are equal, iterating over tables and matching both keys and values.
 | |
| local function table_matches(t1, t2)
 | |
|     local tabletype1 = table.type(t1)
 | |
| 
 | |
|     if not tabletype1 then return t1 == t2 end
 | |
| 
 | |
|     if tabletype1 ~= table.type(t2) or (tabletype1 == 'array' and #t1 ~= #t2) then
 | |
|         return false
 | |
|     end
 | |
| 
 | |
|     for k, v1 in pairs(t1) do
 | |
|         local v2 = t2[k]
 | |
|         if v2 == nil or not table_matches(v1, v2) then
 | |
|             return false
 | |
|         end
 | |
|     end
 | |
| 
 | |
|     for k in pairs(t2) do
 | |
|         if t1[k] == nil then
 | |
|             return false
 | |
|         end
 | |
|     end
 | |
| 
 | |
|     return true
 | |
| end
 | |
| 
 | |
| ---@generic T
 | |
| ---@param tbl T
 | |
| ---@return T
 | |
| ---Recursively clones a table to ensure no table references.
 | |
| local function table_deepclone(tbl)
 | |
|     tbl = table.clone(tbl)
 | |
| 
 | |
|     for k, v in pairs(tbl) do
 | |
|         if type(v) == 'table' then
 | |
|             tbl[k] = table_deepclone(v)
 | |
|         end
 | |
|     end
 | |
| 
 | |
|     return tbl
 | |
| end
 | |
| 
 | |
| ---@param t1 table
 | |
| ---@param t2 table
 | |
| ---@param addDuplicateNumbers boolean? add duplicate number keys together if true, replace if false. Defaults to true.
 | |
| ---@return table
 | |
| ---Merges two tables together. Defaults to adding duplicate keys together if they are numbers, otherwise they are overriden.
 | |
| local function table_merge(t1, t2, addDuplicateNumbers)
 | |
|     addDuplicateNumbers = addDuplicateNumbers == nil or addDuplicateNumbers
 | |
|     for k, v2 in pairs(t2) do
 | |
|         local v1 = t1[k]
 | |
|         local type1 = type(v1)
 | |
|         local type2 = type(v2)
 | |
| 
 | |
|         if type1 == 'table' and type2 == 'table' then
 | |
|             table_merge(v1, v2, addDuplicateNumbers)
 | |
|         elseif addDuplicateNumbers and (type1 == 'number' and type2 == 'number') then
 | |
|             t1[k] = v1 + v2
 | |
|         else
 | |
|             t1[k] = v2
 | |
|         end
 | |
|     end
 | |
| 
 | |
|     return t1
 | |
| end
 | |
| 
 | |
| ---@param tbl table
 | |
| ---@return table
 | |
| ---Shuffles the elements of a table randomly using the Fisher-Yates algorithm.
 | |
| local function shuffle(tbl)
 | |
|     local len = #tbl
 | |
|     for i = len, 2, -1 do
 | |
|         local j = math.random(i)
 | |
|         tbl[i], tbl[j] = tbl[j], tbl[i]
 | |
|     end
 | |
|     return tbl
 | |
| end
 | |
| 
 | |
| table.contains = contains
 | |
| table.matches = table_matches
 | |
| table.deepclone = table_deepclone
 | |
| table.merge = table_merge
 | |
| table.shuffle = shuffle
 | |
| 
 | |
| local frozenNewIndex = function(self) error(('cannot set values on a frozen table (%s)'):format(self), 2) end
 | |
| local _rawset = rawset
 | |
| 
 | |
| ---@param tbl table
 | |
| ---@param index any
 | |
| ---@param value any
 | |
| ---@return table
 | |
| function rawset(tbl, index, value)
 | |
|     if table.isfrozen(tbl) then
 | |
|         frozenNewIndex(tbl)
 | |
|     end
 | |
| 
 | |
|     return _rawset(tbl, index, value)
 | |
| end
 | |
| 
 | |
| ---Makes a table read-only, preventing further modification. Unfrozen tables stored within `tbl` are still mutable.
 | |
| ---@generic T : table
 | |
| ---@param tbl T
 | |
| ---@return T
 | |
| function table.freeze(tbl)
 | |
|     local copy = table.clone(tbl)
 | |
|     local metatbl = getmetatable(tbl)
 | |
| 
 | |
|     table.wipe(tbl)
 | |
|     setmetatable(tbl, {
 | |
|         __index = metatbl and setmetatable(copy, metatbl) or copy,
 | |
|         __metatable = 'readonly',
 | |
|         __newindex = frozenNewIndex,
 | |
|         __len = function() return #copy end,
 | |
|         ---@diagnostic disable-next-line: redundant-return-value
 | |
|         __pairs = function() return next, copy end,
 | |
|     })
 | |
| 
 | |
|     return tbl
 | |
| end
 | |
| 
 | |
| ---Return true if `tbl` is set as read-only.
 | |
| ---@param tbl table
 | |
| ---@return boolean
 | |
| function table.isfrozen(tbl)
 | |
|     return getmetatable(tbl) == 'readonly'
 | |
| end
 | |
| 
 | |
| return lib.table
 | 
