1 -- An array that keeps itself sorted.
2 local create
= QuestHelper
.create
3 local insert
= table.insert
4 local erase
= table.remove
5 local floor = math
.floor
6 local sort = table.sort
8 -- The metatable for SortedList objects.
11 function SortedList
:onCreate(cmp
)
12 assert(type(cmp
) == "function", "Expected function to perform less than comparisons.")
13 rawset(self
, "cmp", cmp
)
17 function SortedList
:sort()
18 sort(self
, rawget(self
, "cmp"))
21 -- Inserts a value into the table.
22 -- Will try to insert as close to the back of the list as possible, to reduce the number of values
23 -- that need to be shifted.
24 -- Returns the index the value was inserted at.
25 function SortedList
:insert(value
)
26 local cmp
= rawget(self
, "cmp")
27 local mn
, mx
= 1, #self
+1
30 local m
= floor((mn
+mx
)*0.5)
32 if cmp(value
, rawget(self
, m
)) then
39 insert(self
, mn
, value
)
43 -- Inserts a value into the table, searching the indexes [mn,mx).
44 -- The inserted value must be greater or equal to the value at index mn, and less than the value at mx.
45 -- mx should be the a valid index, or one past the last valid.
46 -- Will try to insert as close to mx as possible, to reduce the number of values
47 -- that need to be shifted.
48 -- Returns the index the value was inserted at.
49 function SortedList
:insert2(value
, mn
, mx
)
50 local cmp
= rawget(self
, "cmp")
53 local m
= floor((mn
+mx
)*0.5)
55 if cmp(value
, rawget(self
, m
)) then
62 insert(self
, mn
, value
)
66 -- Erases a value from the table.
67 -- The thing you're erasing must exist.
68 -- Care is taken to remove the actual value and not mearly something equal to it.
69 -- Returns the upper bound of value, which you can use for reference if you intend to reinsert the value later.
70 function SortedList
:erase(value
)
71 local cmp
= rawget(self
, "cmp")
72 local mn
, mx
= 1, #self
+1
75 local m
= floor((mn
+mx
)*0.5)
77 if cmp(value
, rawget(self
, m
)) then
84 -- Subtracting 1, because it will be shifted by calling erase.
88 local k
= rawget(self
, mn
)
94 assert(k
, "Value should exist.")
99 -- Returns lower and upper bound for value.
100 -- Lower bound is the first occurance of the variable, if it exists in the list.
101 -- Upper bound is the index of the lowest value greater than value.
102 -- If the lower and upper bound are equal, then value doesn't exist in the list.
103 function SortedList
:find(value
)
104 local cmp
= rawget(self
, "cmp")
105 local lmn
, lmx
= 1, #self
+1
106 local hmn
, hmx
= lmn
, lmx
109 local m
= floor((lmn
+lmx
)*0.5)
110 local v
= rawget(self
, m
)
112 if cmp(v
, value
) then
115 elseif cmp(value
, v
) then
123 local m
= floor((lmn
+lmx
)*0.5)
124 local v
= rawget(self
, m
)
126 if cmp(rawget(self
, m
), value
) then
135 local m
= floor((hmn
+hmx
)*0.5)
137 if cmp(value
, rawget(self
, m
)) then
149 -- Returns lower bound for value. If value exists in the list, returned index will be its first occurance.
150 function SortedList
:lower(value
)
151 local cmp
= rawget(self
, "cmp")
152 local mn
, mx
= 1, #self
+1
155 local m
= floor((mn
+mx
)*0.5)
157 if cmp(rawget(self
, m
), value
) then
167 -- Returns upper bound for value. If values exists, it will be the index directly before this one.
168 function SortedList
:upper(value
)
169 local cmp
= rawget(self
, "cmp")
170 local mn
, mx
= 1, #self
+1
173 local m
= floor((mn
+mx
)*0.5)
175 if cmp(value
, rawget(self
, m
)) then
185 SortedList
.__index
= function(list
, key
)
186 return rawget(list
, key
) or rawget(SortedList
, key
)
189 local function createSortedList(cmp
)
190 return create(SortedList
, cmp
)
193 QuestHelper
.createSortedList
= createSortedList