Skip to content

Commit 3795e4d

Browse files
committed
fix: remove key from tb.keys and tb.k2i
1 parent 4b55230 commit 3795e4d

File tree

2 files changed

+267
-3
lines changed

2 files changed

+267
-3
lines changed

table.go

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -208,19 +208,36 @@ func (tb *LTable) RawSetString(key string, value LValue) {
208208
tb.k2i = map[LValue]int{}
209209
}
210210

211+
lkey := LString(key)
211212
if value == LNil {
212-
// TODO tb.keys and tb.k2i should also be removed
213213
delete(tb.strdict, key)
214+
tb.deleteKeyFromKeys(lkey)
215+
delete(tb.k2i, lkey)
214216
} else {
215217
tb.strdict[key] = value
216-
lkey := LString(key)
217218
if _, ok := tb.k2i[lkey]; !ok {
218219
tb.k2i[lkey] = len(tb.keys)
219220
tb.keys = append(tb.keys, lkey)
220221
}
221222
}
222223
}
223224

225+
func (tb *LTable) deleteKeyFromKeys(key LValue) {
226+
idx, ok := tb.k2i[key]
227+
if !ok {
228+
return
229+
}
230+
231+
lastIdx := len(tb.keys) - 1
232+
if idx != lastIdx {
233+
lastKey := tb.keys[lastIdx]
234+
tb.keys[idx] = lastKey
235+
tb.k2i[lastKey] = idx
236+
}
237+
238+
tb.keys = tb.keys[:lastIdx]
239+
}
240+
224241
// RawSetH sets a given LValue to a given index without the __newindex metamethod.
225242
func (tb *LTable) RawSetH(key LValue, value LValue) {
226243
if s, ok := key.(LString); ok {
@@ -236,8 +253,9 @@ func (tb *LTable) RawSetH(key LValue, value LValue) {
236253
}
237254

238255
if value == LNil {
239-
// TODO tb.keys and tb.k2i should also be removed
240256
delete(tb.dict, key)
257+
tb.deleteKeyFromKeys(key)
258+
delete(tb.k2i, key)
241259
} else {
242260
tb.dict[key] = value
243261
if _, ok := tb.k2i[key]; !ok {

table_test.go

Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,3 +231,249 @@ func TestTableForEach(t *testing.T) {
231231
}
232232
})
233233
}
234+
235+
func TestLTable_RawSetString(t *testing.T) {
236+
type input struct {
237+
key string
238+
value LValue
239+
}
240+
241+
tests := []struct {
242+
name string
243+
input []input
244+
strdictExpectedLength int
245+
expectedKeys []LValue
246+
}{
247+
{
248+
name: "input received as expected",
249+
input: []input{
250+
{
251+
key: "a",
252+
value: LString("a"),
253+
},
254+
{
255+
key: "b",
256+
value: LString("b"),
257+
},
258+
{
259+
key: "c",
260+
value: LString("c"),
261+
},
262+
{
263+
key: "d",
264+
value: LString("d"),
265+
},
266+
},
267+
strdictExpectedLength: 4,
268+
expectedKeys: []LValue{
269+
LString("a"), LString("b"), LString("c"), LString("d"),
270+
},
271+
},
272+
{
273+
name: "key removed from the middle",
274+
input: []input{
275+
{
276+
key: "a",
277+
value: LString("a"),
278+
},
279+
{
280+
key: "b",
281+
value: LString("b"),
282+
},
283+
{
284+
key: "c",
285+
value: LString("c"),
286+
},
287+
{
288+
key: "d",
289+
value: LString("d"),
290+
},
291+
{
292+
key: "c",
293+
value: LNil,
294+
},
295+
},
296+
strdictExpectedLength: 3,
297+
expectedKeys: []LValue{
298+
LString("a"), LString("b"), LString("d"),
299+
},
300+
},
301+
{
302+
name: "key removed from the end",
303+
input: []input{
304+
{
305+
key: "a",
306+
value: LString("a"),
307+
},
308+
{
309+
key: "b",
310+
value: LString("b"),
311+
},
312+
{
313+
key: "c",
314+
value: LString("c"),
315+
},
316+
{
317+
key: "d",
318+
value: LString("d"),
319+
},
320+
{
321+
key: "d",
322+
value: LNil,
323+
},
324+
},
325+
strdictExpectedLength: 3,
326+
expectedKeys: []LValue{
327+
LString("a"), LString("b"), LString("c"),
328+
},
329+
},
330+
}
331+
for _, tt := range tests {
332+
t.Run(tt.name, func(t *testing.T) {
333+
tb := newLTable(0, 0)
334+
for _, v := range tt.input {
335+
tb.RawSetString(v.key, v.value)
336+
}
337+
if len(tb.strdict) != tt.strdictExpectedLength {
338+
t.Error("Expected length", tt.strdictExpectedLength, "got", len(tb.strdict))
339+
}
340+
341+
if len(tb.k2i) != tt.strdictExpectedLength {
342+
t.Error("Expected length", tt.strdictExpectedLength, "got", len(tb.k2i))
343+
}
344+
345+
if len(tb.keys) != tt.strdictExpectedLength {
346+
t.Error("Expected length", tt.strdictExpectedLength, "got", len(tb.keys))
347+
}
348+
349+
for i, v := range tb.keys {
350+
if v != tt.expectedKeys[i] {
351+
t.Error("Expected", tt.expectedKeys[i], "got", v)
352+
}
353+
}
354+
})
355+
}
356+
}
357+
358+
func TestLTable_RawGetH(t *testing.T) {
359+
type input struct {
360+
key LValue
361+
value LValue
362+
}
363+
364+
tests := []struct {
365+
name string
366+
input []input
367+
strdictExpectedLength int
368+
expectedKeys []LValue
369+
}{
370+
{
371+
name: "input received as expected",
372+
input: []input{
373+
{
374+
key: LString("a"),
375+
value: LString("a"),
376+
},
377+
{
378+
key: LString("b"),
379+
value: LString("b"),
380+
},
381+
{
382+
key: LString("c"),
383+
value: LString("c"),
384+
},
385+
{
386+
key: LString("d"),
387+
value: LString("d"),
388+
},
389+
},
390+
strdictExpectedLength: 4,
391+
expectedKeys: []LValue{
392+
LString("a"), LString("b"), LString("c"), LString("d"),
393+
},
394+
},
395+
{
396+
name: "key removed from the middle, expect removal from keys and k2i",
397+
input: []input{
398+
{
399+
key: LString("a"),
400+
value: LString("a"),
401+
},
402+
{
403+
key: LString("b"),
404+
value: LString("b"),
405+
},
406+
{
407+
key: LString("c"),
408+
value: LString("c"),
409+
},
410+
{
411+
key: LString("d"),
412+
value: LString("d"),
413+
},
414+
{
415+
key: LString("c"),
416+
value: LNil,
417+
},
418+
},
419+
strdictExpectedLength: 3,
420+
expectedKeys: []LValue{
421+
LString("a"), LString("b"), LString("d"),
422+
},
423+
},
424+
{
425+
name: "key removed from the end, expect removal from keys and k2i",
426+
input: []input{
427+
{
428+
key: LString("a"),
429+
value: LString("a"),
430+
},
431+
{
432+
key: LString("b"),
433+
value: LString("b"),
434+
},
435+
{
436+
key: LString("c"),
437+
value: LString("c"),
438+
},
439+
{
440+
key: LString("d"),
441+
value: LString("d"),
442+
},
443+
{
444+
key: LString("d"),
445+
value: LNil,
446+
},
447+
},
448+
strdictExpectedLength: 3,
449+
expectedKeys: []LValue{
450+
LString("a"), LString("b"), LString("c"),
451+
},
452+
},
453+
}
454+
for _, tt := range tests {
455+
t.Run(tt.name, func(t *testing.T) {
456+
tb := newLTable(0, 0)
457+
for _, v := range tt.input {
458+
tb.RawSetH(v.key, v.value)
459+
}
460+
if len(tb.strdict) != tt.strdictExpectedLength {
461+
t.Error("Expected length", tt.strdictExpectedLength, "got", len(tb.strdict))
462+
}
463+
464+
if len(tb.k2i) != tt.strdictExpectedLength {
465+
t.Error("Expected length", tt.strdictExpectedLength, "got", len(tb.k2i))
466+
}
467+
468+
if len(tb.keys) != tt.strdictExpectedLength {
469+
t.Error("Expected length", tt.strdictExpectedLength, "got", len(tb.keys))
470+
}
471+
472+
for i, v := range tb.keys {
473+
if v != tt.expectedKeys[i] {
474+
t.Error("Expected", tt.expectedKeys[i], "got", v)
475+
}
476+
}
477+
})
478+
}
479+
}

0 commit comments

Comments
 (0)