z_mirror/flib
git clone https://git.raiguard.me/z_mirror/flib
741edfb
trunk
1--- Additional utilities for working with tables. For arrays, see the `array` module. 2--- ```lua 3--- local flib_table: = require("__flib__.table") 4--- ``` 5--- @class flib_table 6local flib_table ={} 7 8--- Checks that the predicate is true for all values of the table. 9--- @generic K, V 10--- @param tbl table<K, V> 11--- @param predicate fun(value: V, key: K): boolean 12--- @return boolean 13function flib_table . all_of ( tbl , predicate ) 14for k , v in pairs ( tbl ) do 15if not predicate ( v , k ) then 16return false 17end 18end 19return true 20end 21 22--- Checks that the predicate is true at least one entry of the table. 23--- @generic K, V 24--- @param tbl table<K, V> 25--- @param predicate fun(value: V, key: K): boolean 26--- @return boolean 27function flib_table . any_of ( tbl , predicate ) 28for k , v in pairs ( tbl ) do 29if predicate ( v , k ) then 30return true 31end 32end 33return false 34end 35 36--- Recursively compares two tables for inner equality. Does not compare metatables. 37--- @generic T: table 38--- @param tbl1 T 39--- @param tbl2 T 40--- @return boolean 41function flib_table . deep_compare ( tbl1 , tbl2 ) 42if tbl1 == tbl2 then 43return true 44end 45for k , v in pairs ( tbl1 ) do 46if type ( v ) == "table" and type ( tbl2 [ k ]) == "table" then 47if not flib_table . deep_compare ( v , tbl2 [ k ]) then 48return false 49end 50else 51if v ~= tbl2 [ k ] then 52return false 53end 54end 55end 56for k in pairs ( tbl2 ) do 57if tbl1 [ k ] == nil then 58return false 59end 60end 61return true 62end 63 64--- Recursively copies the contents of a table into a new table. Does not create new copies of Factorio objects. 65--- @generic T 66--- @param tbl T 67--- @return T 68function flib_table . deep_copy ( tbl ) 69local lookup_table ={} 70local function _copy ( tbl ) 71if type ( tbl ) ~= "table" then 72return tbl 73elseif lookup_table [ tbl ] then 74return lookup_table [ tbl ] 75end 76local new_table ={} 77lookup_table [ tbl ] =new_table 78for index , value in pairs ( tbl ) do 79new_table [ _copy ( index )] =_copy ( value ) 80end 81return setmetatable ( new_table , getmetatable ( tbl )) 82end 83return _copy ( tbl ) 84end 85 86--- Recursively merges two or more tables. 87--- 88--- Values from earlier tables are overwritten by values from later tables, unless both values are tables, in which case 89--- they are recursively merged. 90--- 91--- Non-merged tables are deep-copied, so the result is brand-new. 92--- 93--- ### Examples 94--- 95--- ```lua 96--- local tbl = {foo = "bar"} 97--- log(tbl.foo) -- logs "bar" 98--- log (tbl.bar) -- errors (key is nil) 99--- tbl = table.merge{tbl, {foo = "baz", set = 3}} 100--- log(tbl.foo) -- logs "baz" 101--- log(tbl.set) -- logs "3" 102--- ``` 103--- @generic K, V 104--- @param tables table<K, V>[] An array of tables to merge. 105--- @return table<K, V> 106function flib_table . deep_merge ( tables ) 107local output ={} 108for _ , tbl in ipairs ( tables ) do 109for k , v in pairs ( tbl ) do 110if type ( v ) == "table" then 111if type ( output [ k ] or false ) == "table" then 112output [ k ] =flib_table . deep_merge ( { output [ k ], v } ) 113else 114output [ k ] =flib_table . deep_copy ( v ) 115end 116else 117output [ k ] =v 118end 119end 120end 121return output 122end 123 124--- Finds the first key of the given element in the table. The search order is determined by the `pairs()` function. 125--- 126--- ### Examples 127--- 128--- ```lua 129--- local tbl = {"foo", "bar"} 130--- local key_of_foo = table.find(tbl, "foo") -- 1 131--- local key_of_baz = table.find(tbl, "baz") -- nil 132--- ``` 133--- @generic K, V 134--- @param tbl table<K, V> The table to search. 135--- @param value V The value to match. Must have an `eq` metamethod set, otherwise will error. 136--- @return K? key The first key corresponding to `value`, if any. 137function flib_table . find ( tbl , value ) 138for k , v in pairs ( tbl ) do 139if v == value then 140return k 141end 142end 143end 144 145--- Retrieves the value at the key, or inserts the default value. 146--- @generic K, V 147--- @param table table<K, V> 148--- @param key K 149--- @param default_value V 150--- @return V 151function flib_table . get_or_insert ( table , key , default_value ) 152local value =table [ key ] 153if not value then 154table [ key ] =default_value 155return default_value 156end 157return value 158end 159 160--- Retrieves the value at the key, or inserts the default value provided by the callback. 161--- @generic K, V 162--- @param table table<K, V> 163--- @param key K 164--- @param callback fun(): V 165--- @return V 166function flib_table . get_or_insert_with ( table , key , callback ) 167local value =table [ key ] 168if not value then 169value =callback () 170table [ key ] =value 171end 172return value 173end 174 175--- Returns a new table with the keys and values of the source table inverted. Non-unique values are overwritten based 176--- on the ordering from `pairs()`. 177--- 178--- ### Examples 179--- 180--- ```lua 181--- local tbl = {"foo", "bar", "baz", set = "baz"} 182--- local inverted = table.inverted(tbl) -- {foo = 1, bar = 2, baz = "set"} 183--- ``` 184--- @generic K, V 185--- @param tbl table<K, V> 186--- @return table<V, K> 187function flib_table . inverted ( tbl ) 188local inverted ={} 189for k , v in pairs ( tbl ) do 190inverted [ v ] =k 191end 192return inverted 193end 194 195--- Transforms the values of the table in-place according to the predicate. 196--- @generic K, V, N 197--- @param tbl table<K, V> 198--- @param predicate fun(value: V, key: V): N? 199--- @return table<K, N> # The input table. 200function flib_table . map ( tbl , predicate ) 201for k , v in pairs ( tbl ) do 202tbl [ k ] =predicate ( v , k ) 203end 204return tbl 205end 206 207--- Returns a new table with the values transformed according to the predicate. 208--- 209--- ### Examples 210--- 211--- ```lua 212--- local tbl = {1, 2, 3, 4, 5} 213--- local tbl_times_ten = table.mapped(tbl, function(v) return v * 10 end) -- {10, 20, 30, 40, 50} 214--- ``` 215--- @generic K, V, N 216--- @param tbl table<K, V> 217--- @param predicate fun(value: V, key: V): N? 218--- @return table<K, N> 219function flib_table . mapped ( tbl , predicate ) 220local output ={} 221for k , v in pairs ( tbl ) do 222output [ k ] =predicate ( v , k ) 223end 224return output 225end 226 227--- "Reduce" a table's values into a single output value, using the results of a reducer function. 228--- 229--- Calls `reducer(accumulator, value, key)` on each element in the table, returning a single accumulated output value. 230--- 231--- ### Examples 232--- 233--- ```lua 234--- local tbl = {10, 20, 30, 40, 50} 235--- local sum = table.reduce(tbl, function(acc, v) return acc + v end) 236--- local sum_minus_ten = table.reduce(tbl, function(acc, v) return acc + v end, -10) 237--- ``` 238--- @generic K, V, R 239--- @param tbl table<K, V> 240--- @param reducer fun(acc: R, value: V, key: K): R 241--- @param initial_value R? The initial value for the accumulator. If not provided or is falsy, the first value in the table will be used as the initial `accumulator` value and skipped as `key`. Calling `reduce()` on an empty table without an `initial_value` will cause a crash. 242--- @return R 243function flib_table . reduce ( tbl , reducer , initial_value ) 244local accumulator =initial_value 245for key , value in pairs ( tbl ) do 246if accumulator then 247accumulator =reducer ( accumulator , value , key ) 248else 249accumulator =value 250end 251end 252return accumulator 253end 254 255--- Removes all elements from the table for which the predicate returns true. 256--- @generic K, V 257--- @param tbl table<K, V> 258--- @param predicate fun(value: V, key: K): boolean 259function flib_table . remove_if ( tbl , predicate ) 260for k , v in pairs ( tbl ) do 261if predicate ( v , k ) then 262tbl [ k ] =nil 263end 264end 265end 266 267--- Shallowly copies the contents of a table into a new table. 268--- The parent table will have a new table reference, but any subtables within it will still have the same table reference. 269--- Does not copy metatables. 270--- @generic T 271--- @param tbl T 272--- @param use_rawset boolean? Use rawset to set the values (ignores metamethods). 273--- @return T The copied table. 274function flib_table . shallow_copy ( tbl , use_rawset ) 275local output ={} 276for k , v in pairs ( tbl ) do 277if use_rawset then 278rawset ( output , k , v ) 279else 280output [ k ] =v 281end 282end 283return output 284end 285 286--- Shallowly merge two or more tables. 287--- Unlike `table.deep_merge`, this will only combine the top level of the tables. 288--- @param tables table[] 289--- @return table 290function flib_table . shallow_merge ( tables ) 291local output ={} 292for _ , tbl in pairs ( tables ) do 293for key , value in pairs ( tbl ) do 294output [ key ] =value 295end 296end 297return output 298end 299 300return flib_table