Merge branch 'fixes' into main/gingo-test
[ryzomcore.git] / ryzom / common / data_common / r2 / r2_misc.lua
blobd85744bd0f805600380357be2c962c79383b0f21
1 -- This file contains a set of miscellanous functions that don't fit in any other place
2 -- TODO nico : could be useful outside r2 -> export this
5 ---------------
6 -- FUNCTIONS --
7 ---------------
10 ------------------------------------------------------------------------------------------------------------
11 -- equivalent of the ? : C operator, execpt that the 2 sides are evaluated before assignement
12 function select(cond, valueForTrue, valueForFalse)
13 if cond then
14 return valueForTrue
15 else
16 return valueForFalse
17 end
18 end
21 ------------------------------------------------------------------------------------------------------------
22 -- execute a function for each key pair in a table
23 function forEach(table, fn)
24 local i, v = next(table,nil) -- get first index of "o" and its value
25 while i do
26 fn(i, v)
27 i, v = next(table,i) -- get next index and its value
28 end
29 end
32 ------------------------------------------------------------------------------------------------------------
33 -- whatever
34 table.setn = function(table, n)
35 assert(table)
36 local mt = getmetatable(table)
37 if mt ~= nil then
38 if mt.__next ~= nil then
39 table.Size = n
40 end
41 end
42 end
44 ------------------------------------------------------------------------------------------------------------
45 -- extension to table library : remove all content of a table without deleting the table object
46 function table.clear(tbl)
47 while next(tbl) do
48 tbl[next(tbl)] = nil
49 end
50 table.setn(tbl, 0)
51 end
53 ------------------------------------------------------------------------------------------------------------
54 -- extension to table library : merge the content of two table remove the element, remove fields with duplicated keys (except for number)
55 function table.merge(tbl1, tbl2)
56 local k, v = next(tbl2)
57 while k do
58 if (type(k) == "number") then
59 table.insert(tbl1, v)
60 else
61 tbl1[k] = v
62 end
63 k, v = next(tbl2, k)
64 end
65 end
67 ------------------------------------------------------------------------------------------------------------
68 -- Addtion to the string library : test wether a string match with the given pattern (returns true is so)
69 function string.match(str, pattern)
70 assert( type(str) == "string")
71 if (str == nil) then
72 debugInfo(debug.traceback())
73 assert(0)
74 end
75 local startPos, endPos = string.find(str, pattern)
76 if startPos == nil then return false end
77 return startPos == 1 and endPos == string.len(str)
78 end
80 ------------------------------------------------------------------------------------------------------------
81 -- clone content of a table
82 function clone(t)
83 local new = {}
84 local i, v = next(t, nil)
85 while i do
86 if (type(v)=="table") then v= clone(v) end
87 new[i] = v
88 i, v = next(t, i)
89 end
90 return new
91 end
93 ------------------------------------------------------------------------------------------------------------
94 -- Test if 2 values are equal
95 -- If values are table, then a member wise comparison is done
96 function isEqual(lhs, rhs)
97 if type(lhs) ~= type(rhs) then return false end
98 if type(lhs) == "table" then
99 local lk, lv = next(lhs) -- keys
100 local rk, rv = next(rhs) -- values
101 while lk and rk do
102 if not isEqual(lk, rk) then
103 return false
105 if not isEqual(lv, rv) then
106 return false
108 lk, lv = next(lhs, lk)
109 rk, rv = next(rhs, rk)
111 if lk ~= nil or rk ~= nil then
112 return false
113 -- not same table length
115 return true
116 else
117 return lhs == rhs
121 ------------------------------------------------------------------------------------------------------------
122 -- Test if 2 values are equal
123 -- If values are table, then a member wise comparison is done
124 -- special : function pointer are ignored and considered equals
125 function isEqualIgnoreFunctions(lhs, rhs)
126 if type(lhs) ~= type(rhs) then return false end
127 if type(lhs) == "table" then
128 local lk, lv = next(lhs) -- keys
129 local rk, rv = next(rhs) -- values
130 while lk and rk do
131 if not isEqualIgnoreFunctions(lk, rk) then
132 return false
134 if not isEqualIgnoreFunctions(lv, rv) then
135 return false
137 lk, lv = next(lhs, lk)
138 rk, rv = next(rhs, rk)
140 if lk ~= nil or rk ~= nil then
141 return false
142 -- not same table length
144 return true
145 elseif type(lhs) == "function" then
146 return true
147 else
148 return lhs == rhs
153 ------------------------------------------------------------------------------------------------------------
154 -- clone of a table, but with a depth of 1 ...
155 function shallowClone(t)
156 local new = {}
157 local i, v = next(t, nil)
158 while i do
159 new[i] = v
160 i, v = next(t, i)
162 return new
165 -------------------------------------------------------------------------------------------------
166 -- If args 'value' is nil then the arg 'default' is returned, else the actual 'value' is return
167 function defaulting(value, default)
168 if value == nil then
169 return default
170 else
171 return value
176 -------------------------------------------------------------------------------------------------
177 -- return clamped value. Min and/or max are ignotred if null
178 function clamp(value, min, max)
179 local result = value
180 if min then result = math.max(min, result) end
181 if max then result = math.min(max, result) end
182 return result
183 end
185 -------------------------------------------------------------------------------------------------
186 -- enclose a string by double quotes
187 function strify(str)
188 return [["]] .. tostring(str) .. [["]]
189 end
191 -------------------------------------------------------------------------------------------------
192 -- enclose a string by double quotes
193 function strifyXml(str)
194 local strxml = string.gsub(tostring(str), ">", ">")
195 strxml = string.gsub(strxml, "<", "&lt;")
196 strxml = string.gsub(strxml, "&", "&amp;")
197 strxml = string.gsub(strxml, "'", "&apos;")
198 strxml = string.gsub(strxml, '"', "&quot;")
199 return [["]] .. strxml .. [["]]
200 end
202 ------------------------------------------------------------------------------------------------------------
203 -- snap a position to ground, returning the z snapped coordinate
204 function r2:snapZToGround(x, y)
205 local x1, y1, z1 = r2:snapPosToGround(x, y)
206 return z1
209 -------------------------------------------------------------------------------------------------
211 --built an ordered table from a table whose index are strings
212 --example :
214 --table =
216 --"bar" = test(),
217 --"foo" = { "hello" },
218 --"abc" = 10,
221 --result = sortAlphabeticaly(table)
224 --result is an integer indexed table :
226 -- -- index = { sorted key, value }
227 -- 1 = { "abc", 10 },
228 -- 2 = { "bar", test() },
229 -- 3 = { "foo", { "hello" } }
233 function sortAlphabetically(src)
234 local sortedTable = {}
235 local index = 1
236 for k, v in pairs(src) do
237 sortedTable[index] = { key = k, value = v }
238 index = index + 1
239 end
240 local function comp(val1, val2)
241 return val1.key < val2.key
243 table.sort(sortedTable, comp)
244 return sortedTable
247 ----------
248 -- INIT --
249 ----------
251 -- redefine the 'next' function of lua to use a "__next" function in the metatable
252 -- useful to traverse C++ objects that are exposed to lua through the use of the metatable
253 assert(next ~= nil) -- default lib should have been opened
255 if oldNextFunction == nil then
256 oldNextFunction = next
258 next = function(table, key)
259 assert(table)
260 local mt = getmetatable(table)
261 if mt ~= nil then
262 if mt.__next ~= nil then
263 return mt.__next(table, key)
266 -- tmp
267 --if type(table) ~= "table" then
268 -- debugInfo(debug.traceback())
269 -- debugInfo("'next' expect a table (or user data with __next metamethod) as its first parameter")
270 -- return
271 --end
272 -- else use default 'next' function
273 return oldNextFunction(table, key)
278 -- assert(table.getn ~= nil) -- default lib should have been opened
280 --if oldTableGetnFunction == nil then
281 -- oldTableGetnFunction = table.getn
282 --end
284 --table.getn = function(table)
285 -- assert(table)
286 -- local mt = getmetatable(table)
287 -- if mt ~= nil then
288 -- if mt.__next ~= nil then
289 -- return table.Size
290 -- end
291 -- end
292 -- return oldTableGetnFunction(table)
293 --end
296 table.getn = function(table)
297 assert(table)
298 local mt = getmetatable(table)
299 if mt ~= nil then
300 if mt.__next ~= nil then
301 return table.Size
304 return #table
309 -- redefine the hardcoded 'pairs' function to use the redefined 'next'
310 -- hardcoded version uses the C version of next, not the lua one if it has been redefined
312 if oldPairsFunction ~= nil then
313 pairs = oldPairsFunction
316 if oldPairsFunction == nil then
317 oldPairsFunction = pairs
320 if true then
321 -- TODO nico : bad init of editor if I name this 'pairs' directly (don't know why), so named it 'specPairs' and used
322 -- 'specPairs' when I must iterate over C++ objects ...
323 specPairs = function(table)
324 local function iterFunc(table, key)
325 return next(table, key)
327 return iterFunc, table
331 function r2.assert (param)
332 if not param then assert(nil) end
333 return param
336 function r2.isTable(node)
337 if not node then return false end
339 if type(node) == "table" then
340 return true
341 elseif type(node) == "userdata" then
342 local mt = getmetatable(node)
343 if mt~= nil and mt.__next ~= nil then
344 return true
345 end
347 return false