Skip to content
This repository was archived by the owner on Aug 31, 2021. It is now read-only.

Commit 14a3d5a

Browse files
committed
com.livecode.list: Add "offset of _ in _" accessor.
Add a new operation on lists: the offset of <tNeedle> in <tList> which returns the 1-based index of the start of the first subsequence in <tList> that is equal to <tNeedle>, or 0 if no subsequence of <tList> is equal to <tNeedle>. There are two variants of the operation: the first offset of <tNeedle> in <tList> the last offset of <tNeedle> in <tList> <tNeedle> must be a List.
1 parent 9292eae commit 14a3d5a

3 files changed

Lines changed: 99 additions & 0 deletions

File tree

libscript/src/list.mlc

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ public foreign handler MCListEvalIndexOfElement(in IsLast as CBool, in Needle as
7878
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>"
7979
public foreign handler MCListEvalIndexOfElementBefore(in IsLast as CBool, in Needle as any, in Before as LCIndex, in Haystack as List, out Index as LCUIndex) as undefined binds to "<builtin>"
8080

81+
public foreign handler MCListEvalOffsetOfList(in IsLast as CBool, in Needle as List, in Haystack as List, out Index as LCUIndex) as undefined binds to "<builtin>"
82+
8183
--
8284

8385
/*
@@ -964,4 +966,41 @@ begin
964966
MCListEvalIndexOfElementBefore(IsLast, Needle, Before, Haystack, output)
965967
end syntax
966968

969+
----------------------------------------------------------------
970+
971+
/*
972+
Summary: Find the first or last occurrence of <Needle> within <Haystack>
973+
974+
Needle: An expression which evaluates to a list.
975+
Target: An expression which evaluates to a list.
976+
977+
Returns: Returns the index from the start of <Haystack>.
978+
979+
Example:
980+
variable tVar as List
981+
variable tOffset as Number
982+
put ["a", "b", "c", "d", "b", "c"]
983+
put the offset of ["b","c"] in tVar into tOffset
984+
-- tOffset contains 2
985+
986+
put the last offset of ["b", "c"] in tVar into tOffset
987+
-- tOffset contains 5
988+
989+
Description:
990+
Use `the offset of` to find where a particular sub-list occurs within
991+
a list. <Haystack> is scanned for a sequence of elements that are
992+
equal to the elements of <Needle>, and the position of the start of
993+
the sequence found is returned. If neither the "first offset" nor
994+
"last offset" are specified, the index of the first matching seb-list
995+
found is returned. If no sub-list of <Haystack> is equal to <Needle>,
996+
the return value is 0.
997+
998+
Tags: Lists
999+
*/
1000+
syntax ListOffset is prefix operator with precedence 1
1001+
"the" ( "first" <IsLast=false> | "last" <IsLast=true> | <IsLast=false> ) "offset" "of" <Needle: Expression> "in" <Haystack: Expression>
1002+
begin
1003+
MCListEvalOffsetOfList(IsLast, Needle, Haystack, output)
1004+
end syntax
1005+
9671006
end module

libscript/src/module-list.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,46 @@ MCListEvalIndexOfElementBefore (bool p_is_last,
527527
r_output);
528528
}
529529

530+
////////////////////////////////////////////////////////////////
531+
532+
static void
533+
MCListEvalOffsetOfListInRange (bool p_is_last,
534+
MCProperListRef p_needle,
535+
MCProperListRef p_haystack,
536+
MCRange p_range,
537+
uindex_t & r_output)
538+
{
539+
if (MCProperListIsEmpty (p_haystack))
540+
{
541+
r_output = 0;
542+
return;
543+
}
544+
545+
uindex_t t_offset = 0;
546+
bool t_found = false;
547+
if (!p_is_last)
548+
t_found = MCProperListFirstOffsetOfListInRange (p_haystack, p_needle,
549+
p_range, t_offset);
550+
else
551+
t_found = MCProperListLastOffsetOfListInRange (p_haystack, p_needle,
552+
p_range, t_offset);
553+
554+
if (t_found)
555+
r_output = t_offset + 1;
556+
else
557+
r_output = 0;
558+
}
559+
560+
extern "C" MC_DLLEXPORT void
561+
MCListEvalOffsetOfList (bool p_is_last,
562+
MCProperListRef p_needle,
563+
MCProperListRef p_haystack,
564+
uindex_t & r_output)
565+
{
566+
MCRange t_range = MCRangeMake (0, UINDEX_MAX);
567+
MCListEvalOffsetOfListInRange (p_is_last, p_needle, p_haystack, t_range, r_output);
568+
}
569+
530570
////////////////////////////////////////////////////////////////////////////////////////////////////
531571

532572
#ifdef _TEST

tests/lcb/stdlib/list.lcb

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -545,4 +545,24 @@ public handler TestIndexBeforeZero()
545545
test "last index before (+ve, 0)" when the last index of true before 0 in t is tNoBefore
546546
end handler
547547

548+
----------------------------------------------------------------
549+
-- Finding subsequence offsets
550+
----------------------------------------------------------------
551+
552+
public handler TestOffset()
553+
variable t
554+
put ["x", 1, true, [], []] into t
555+
556+
test "offset" when the offset of [1, true] in t is 2
557+
test "offset (missing)" when the offset of [true, 1] in t is 0
558+
test "offset (missing, overlap start)" when the offset of [false, "x"] in t is 0
559+
test "offset (missing, overlap end)" when the offset of [[], [], false] in t is 0
560+
561+
test "first offset" when the first offset of [[]] in t is 4
562+
test "last offset" when the last offset of [[]] in t is 5
563+
564+
test "offset (empty)" when the offset of [] in t is 0
565+
end handler
566+
567+
548568
end module

0 commit comments

Comments
 (0)