Skip to content

Commit a81437b

Browse files
committed
com.livecode.list: Add "index of _ after _ in _" accessor.
Add a new operation on lists: the index of <tNeedle> after <tPosition> in <tList> This looks for an element equal to <tNeedle> in the subsequence of <tList> starting at the 1-based index <tPosition> (exclusive). It returns the 1-based index relative to <tPosition>, or 0 if no element of of the subsequence is equal to <tNeedle>. There are two variants of the operation: the first index of <tNeedle> after <tPosition> in <tList> the last index of <tNeedle> after <tPosition> in <tList> If <tNeedle> is a list, it is considered as an element of <tList> not as a subsequence of <tList>.
1 parent bc3a548 commit a81437b

3 files changed

Lines changed: 130 additions & 0 deletions

File tree

libscript/src/list.mlc

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ public foreign handler MCListExecDeleteFirstElementOf(inout Target as List) as u
7575
public foreign handler MCListExecDeleteLastElementOf(inout Target as List) as undefined binds to "<builtin>"
7676

7777
public foreign handler MCListEvalIndexOfElement(in IsLast as CBool, in Needle as any, in Haystack as List, out Index as LCUIndex) as undefined binds to "<builtin>"
78+
public foreign handler MCListEvalIndexOfElementAfter(in IsLast as CBool, in Needle as any, in After as LCIndex, in Haystack as List, out Index as LCUIndex) as undefined binds to "<builtin>"
7879

7980
--
8081

@@ -893,4 +894,38 @@ begin
893894
MCListEvalIndexOfElement(IsLast, Needle, Haystack, output)
894895
end syntax
895896

897+
/*
898+
Summary: Find the first or last occurrence of <Needle> within the tail of <Haystack>
899+
900+
Needle: An expression which evaluates to any value.
901+
After: An expression which evaluates to a valid index in Target.
902+
Target: An expression which evaluates to a list.
903+
904+
Returns: Returns the index in <Haystack> relative to <After>.
905+
906+
Example:
907+
variable tVar as List
908+
variable tOffset as Number
909+
put ["a", "b", "c", "d", "b"]
910+
put the index of "b" after 1 in tVar into tOffset
911+
--tOffset contains 1
912+
913+
put the last index of "b" after 2 in tVar into tOffset
914+
--tOffset contains 3
915+
916+
Description:
917+
Use `the index of… after` to find where particular elements occur
918+
within a list. Starting from but not including the position <After>,
919+
<Haystack> is scanned for an element that is equal to <Needle>, and
920+
the position relative to <After> of the element found is returned. If
921+
no element of <Haystack> is equal to <Needle>, the return value is 0.
922+
923+
Tags: Lists
924+
*/
925+
syntax ListIndexAfter is prefix operator with precedence 1
926+
"the" ( "first" <IsLast=false> | "last" <IsLast=true> | <IsLast=false> ) "index" "of" <Needle: Expression> "after" <After: Expression> "in" <Haystack: Expression>
927+
begin
928+
MCListEvalIndexOfElementAfter(IsLast, Needle, After, Haystack, output)
929+
end syntax
930+
896931
end module

libscript/src/module-list.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,28 @@ MCListEvalIndexOfElement (bool p_is_last,
481481
MCListEvalIndexOfElementInRange (p_is_last, p_needle, p_haystack, t_range, r_output);
482482
}
483483

484+
extern "C" MC_DLLEXPORT void
485+
MCListEvalIndexOfElementAfter (bool p_is_last,
486+
MCValueRef p_needle,
487+
index_t p_after,
488+
MCProperListRef p_haystack,
489+
uindex_t & r_output)
490+
{
491+
uindex_t t_start, t_count;
492+
if (!MCChunkGetExtentsOfElementChunkByExpressionInRange (p_haystack, nil,
493+
p_after, true, true, false, t_start, t_count) &&
494+
p_after != 0)
495+
{
496+
MCErrorCreateAndThrow (kMCGenericErrorTypeInfo, "reason",
497+
MCSTR("chunk index out of range"), nil);
498+
return;
499+
}
500+
501+
MCListEvalIndexOfElementInRange (p_is_last, p_needle, p_haystack,
502+
MCRangeMake(t_start + t_count, UINDEX_MAX),
503+
r_output);
504+
}
505+
484506
////////////////////////////////////////////////////////////////////////////////////////////////////
485507

486508
#ifdef _TEST

tests/lcb/stdlib/list.lcb

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,4 +392,77 @@ public handler TestIndex()
392392
test "index (empty)" when the index of 1 in [] is 0
393393
end handler
394394

395+
handler TestIndexAfter_InvalidPositive()
396+
return the index of true after 2 in [true]
397+
end handler
398+
handler TestIndexAfter_InvalidNegative()
399+
return the index of true after -3 in [true]
400+
end handler
401+
handler TestFirstIndexAfter_InvalidPositive()
402+
return the first index of true after 2 in [true]
403+
end handler
404+
handler TestFirstIndexAfter_InvalidNegative()
405+
return the first index of true after -3 in [true]
406+
end handler
407+
handler TestLastIndexAfter_InvalidPositive()
408+
return the last index of true after 2 in [true]
409+
end handler
410+
handler TestLastIndexAfter_InvalidNegative()
411+
return the last index of true after -3 in [true]
412+
end handler
413+
public handler TestIndexAfter()
414+
variable t
415+
put [true, false, true, true, false] into t
416+
417+
test "index after (+ve)" when the index of true after 1 in t is 2
418+
test "index after (-ve)" when the index of true after -5 in t is 2
419+
test "index after (-ve, limit)" when the index of true after -6 in t is 1
420+
test "index after (+ve, missing)" when the index of true after 4 in t is 0
421+
test "index after (-ve, missing)" when the index of true after -2 in t is 0
422+
423+
MCUnitTestHandlerThrows(TestIndexAfter_InvalidPositive, "index after (+ve, invalid)")
424+
MCUnitTestHandlerThrows(TestIndexAfter_InvalidNegative, "index after (-ve, invalid)")
425+
end handler
426+
public handler TestFirstIndexAfter()
427+
variable t
428+
put [true, false, true, true, false] into t
429+
430+
test "first index after (+ve)" when the first index of true after 1 in t is 2
431+
test "first index after (-ve)" when the first index of true after -5 in t is 2
432+
test "first index after (-ve, limit)" when the first index of true after -6 in t is 1
433+
test "first index after (+ve, missing)" when the first index of true after 4 in t is 0
434+
test "first index after (-ve, missing)" when the first index of true after -2 in t is 0
435+
436+
MCUnitTestHandlerThrows(TestFirstIndexAfter_InvalidPositive, "first index after (+ve, invalid)")
437+
MCUnitTestHandlerThrows(TestFirstIndexAfter_InvalidNegative, "first index after (-ve, invalid)")
438+
end handler
439+
public handler TestLastIndexAfter()
440+
variable t
441+
put [true, false, true, true, false] into t
442+
443+
test "last index after (+ve)" when the last index of true after 1 in t is 3
444+
test "last index after (-ve)" when the last index of true after -5 in t is 3
445+
test "last index after (-ve, limit)" when the last index of true after -6 in t is 4
446+
test "last index after (+ve, missing)" when the last index of true after 4 in t is 0
447+
test "last index after (-ve, missing)" when the last index of true after -2 in t is 0
448+
449+
MCUnitTestHandlerThrows(TestLastIndexAfter_InvalidPositive, "last index after (+ve, invalid)")
450+
MCUnitTestHandlerThrows(TestLastIndexAfter_InvalidNegative, "last index after (-ve, invalid)")
451+
end handler
452+
public handler TestIndexAfterZero()
453+
-- "index of _ after 0 in _" should be equivalent to "index of _ in _"
454+
variable t
455+
put [true, false, true, true, false] into t
456+
variable tNoAfter
457+
458+
put the index of true in t into tNoAfter
459+
test "index after (+ve, 0)" when the index of true after 0 in t is tNoAfter
460+
461+
put the first index of true in t into tNoAfter
462+
test "first index after (+ve, 0)" when the first index of true after 0 in t is tNoAfter
463+
464+
put the last index of true in t into tNoAfter
465+
test "last index after (+ve, 0)" when the last index of true after 0 in t is tNoAfter
466+
end handler
467+
395468
end module

0 commit comments

Comments
 (0)