1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
-- Copyright 2025 David Vazgenovich Shakaryan
local mp_utils = require('mp.utils')
local util = {}
function util.copy_table(t)
local u = {}
for k, v in pairs(t) do
u[k] = v
end
return u
end
function util.reverse(t)
for i = 1, #t/2 do
t[i], t[#t-i+1] = t[#t-i+1], t[i]
end
end
function util.strip(str)
return (str:gsub('^%s*(.-)%s*$', '%1'))
end
function util.strip_ne(str)
if str == nil then
return nil
end
local str = util.strip(tostring(str))
return str ~= '' and str or nil
end
-- skips over utf8 continuation bytes (10xxxxxx)
-- valid positions range from 1 to #str + 1 (*after* the last byte)
function util.utf8_seek(str, pos, n)
local step = n > 0 and 1 or -1
local test = n > 0
and function() return pos > #str end
or function() return pos <= 1 end
while n ~= 0 and not test() do
repeat
pos = pos + step
until test() or bit.band(str:byte(pos), 0xc0) ~= 0x80
n = n - step
end
return pos
end
-- wraps string into a table of strings. spaces are not removed, resulting in
-- width-1 visible chars; newlines and end of string are handled similarly for
-- consistency. words longer than width are not broken. optional cont_width can
-- be specified to use a different width for continuation lines.
function util.wrap(str, width, cont_width)
local t = {}
local start, stop = 0, 0
while stop < #str do
local i = str:find('[ \n]', stop + 1) or #str + 1
if i - start >= width then
t[#t+1] = str:sub(start, stop)
start = stop + 1
if cont_width then
width = cont_width
end
end
stop = i
if str:byte(stop) == 10 or stop >= #str then
t[#t+1] = str:sub(start, stop - 1) .. ' '
start = stop + 1
end
end
return t
end
function util.read_json_file(path)
local f = io.open(path, 'r')
if not f then
return {}
end
local json = f:read('*all')
f:close()
return mp_utils.parse_json(json)
end
function util.write_json_file(path, data)
local f = io.open(path, 'w')
f:write(mp_utils.format_json(data), '\n')
f:close()
end
-- merges tables `t' and `u', using key `k' for identity. the order from `u' is
-- always respected, preserving the relative order from `t' when possible.
function util.stable_kmerge(t, u, k)
local pos = {}
for i, v in ipairs(u) do
pos[v[k]] = i
end
local res = {}
local seen = {}
local function append(v)
if not seen[v[k]] then
res[#res+1] = v
seen[v[k]] = true
end
end
local ind = 1
for _, v in ipairs(t) do
if pos[v[k]] then
while ind <= pos[v[k]] do
append(u[ind])
ind = ind + 1
end
end
append(v)
end
for i = ind, #u do
append(u[i])
end
return res
end
return util
|