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

Commit b0028c1

Browse files
committed
com.livecode.list: Add "offset of _ after _ in _" accessor.
Add a new operation on lists: the offset of <tNeedle> after <tPosition> in <tList> This looks for an subsequence 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> of the first element of the matching subsequence, or 0 if no matching subsequence is found. There are two variants of the operation: the first offset of <tNeedle> after <tPosition> in <tList> the last offset of <tNeedle> after <tPosition> in <tList> <tNeedle> must be a List.
1 parent 14a3d5a commit b0028c1

3 files changed

Lines changed: 138 additions & 1 deletion

File tree

libscript/src/list.mlc

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ public foreign handler MCListEvalIndexOfElementAfter(in IsLast as CBool, in Need
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

8181
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+
public foreign handler MCListEvalOffsetOfListAfter(in IsLast as CBool, in Needle as List, in After as LCIndex, in Haystack as List, out Index as LCUIndex) as undefined binds to "<builtin>"
8283

8384
--
8485

@@ -991,7 +992,7 @@ Use `the offset of` to find where a particular sub-list occurs within
991992
a list. <Haystack> is scanned for a sequence of elements that are
992993
equal to the elements of <Needle>, and the position of the start of
993994
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+
"last offset" are specified, the index of the first matching sub-list
995996
found is returned. If no sub-list of <Haystack> is equal to <Needle>,
996997
the return value is 0.
997998

@@ -1003,4 +1004,43 @@ begin
10031004
MCListEvalOffsetOfList(IsLast, Needle, Haystack, output)
10041005
end syntax
10051006

1007+
/*
1008+
Summary: Find the first or last occurrence of <Needle> within the tail of <Haystack>
1009+
1010+
Needle: An expression which evaluates to any list.
1011+
After: An expression which evaluates to a valid index in Target.
1012+
Target: An expression which evaluates to a list.
1013+
1014+
Returns: Returns the index in <Haystack> relative to <After>.
1015+
1016+
Example:
1017+
variable tVar as List
1018+
variable tOffset as Number
1019+
put ["a", "b", "c", "d", "b", "c"]
1020+
put the offset of ["b","c"] after 1 in tVar into tOffset
1021+
--tOffset contains 1
1022+
1023+
put the last offset of ["b","c"] after 1 in tVar into tOffset
1024+
--tOffset contains 4
1025+
1026+
Description:
1027+
1028+
Use `the offset of… after` to find where a particular sub-list occurs
1029+
within a list. Starting from but not including the position <After>,
1030+
<Haystack> is scanned for an sequence of elements that are equal to
1031+
the elements of <Needle>, and the position relative to <After> of the
1032+
start of the sequence found is returned. If neither the "first
1033+
offset" nor "last offset" are specified, the position of the first
1034+
matching sub-list found is returned. If no sub-list of <Haystack>
1035+
starting after the position <After> is equal to <Needle>, the return
1036+
value is 0.
1037+
1038+
Tags: Lists
1039+
*/
1040+
syntax ListOffsetAfter is prefix operator with precedence 1
1041+
"the" ( "first" <IsLast=false> | "last" <IsLast=true> | <IsLast=false> ) "offset" "of" <Needle: Expression> "after" <After: Expression> "in" <Haystack: Expression>
1042+
begin
1043+
MCListEvalOffsetOfListAfter(IsLast, Needle, After, Haystack, output)
1044+
end syntax
1045+
10061046
end module

libscript/src/module-list.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,28 @@ MCListEvalOffsetOfList (bool p_is_last,
567567
MCListEvalOffsetOfListInRange (p_is_last, p_needle, p_haystack, t_range, r_output);
568568
}
569569

570+
extern "C" MC_DLLEXPORT void
571+
MCListEvalOffsetOfListAfter (bool p_is_last,
572+
MCProperListRef p_needle,
573+
index_t p_after,
574+
MCProperListRef p_haystack,
575+
uindex_t & r_output)
576+
{
577+
uindex_t t_start, t_count;
578+
if (!MCChunkGetExtentsOfElementChunkByExpressionInRange (p_haystack, nil,
579+
p_after, true, true, false, t_start, t_count) &&
580+
p_after != 0)
581+
{
582+
MCErrorCreateAndThrow (kMCGenericErrorTypeInfo, "reason",
583+
MCSTR("chunk index out of range"), nil);
584+
return;
585+
}
586+
587+
MCListEvalOffsetOfListInRange (p_is_last, p_needle, p_haystack,
588+
MCRangeMake(t_start + t_count, UINDEX_MAX),
589+
r_output);
590+
}
591+
570592
////////////////////////////////////////////////////////////////////////////////////////////////////
571593

572594
#ifdef _TEST

tests/lcb/stdlib/list.lcb

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -564,5 +564,80 @@ public handler TestOffset()
564564
test "offset (empty)" when the offset of [] in t is 0
565565
end handler
566566

567+
----------------------------------------------------------------
568+
569+
handler TestOffsetAfter_InvalidPositive()
570+
return the offset of [true] after 2 in [true]
571+
end handler
572+
handler TestOffsetAfter_InvalidNegative()
573+
return the offset of [true] after -3 in [true]
574+
end handler
575+
handler TestFirstOffsetAfter_InvalidPositive()
576+
return the first offset of [true] after 2 in [true]
577+
end handler
578+
handler TestFirstOffsetAfter_InvalidNegative()
579+
return the first offset of [true] after -3 in [true]
580+
end handler
581+
handler TestLastOffsetAfter_InvalidPositive()
582+
return the last offset of [true] after 2 in [true]
583+
end handler
584+
handler TestLastOffsetAfter_InvalidNegative()
585+
return the last offset of [true] after -3 in [true]
586+
end handler
587+
public handler TestOffsetAfter()
588+
variable t
589+
put [true, false, true, true, false] into t
590+
591+
test "offset after (+ve)" when the offset of [true,false] after 1 in t is 3
592+
test "offset after (-ve)" when the offset of [true,false] after -5 in t is 3
593+
test "offset after (-ve, limit)" when the offset of [true,false] after -6 in t is 1
594+
test "offset after (+ve, missing)" when the offset of [false,true] after 2 in t is 0
595+
test "offset after (-ve, missing)" when the offset of [false,true] after -4 in t is 0
596+
597+
MCUnitTestHandlerThrows(TestOffsetAfter_InvalidPositive, "offset after (+ve, invalid)")
598+
MCUnitTestHandlerThrows(TestOffsetAfter_InvalidNegative, "offset after (-ve, invalid)")
599+
end handler
600+
public handler TestFirstOffsetAfter()
601+
variable t
602+
put [true, false, true, true, false] into t
603+
604+
test "first offset after (+ve)" when the first offset of [true,false] after 1 in t is 3
605+
test "first offset after (-ve)" when the first offset of [true,false] after -5 in t is 3
606+
test "first offset after (-ve, limit)" when the first offset of [true,false] after -6 in t is 1
607+
test "first offset after (+ve, missing)" when the first offset of [false,true] after 2 in t is 0
608+
test "first offset after (-ve, missing)" when the first offset of [false,true] after -4 in t is 0
609+
610+
MCUnitTestHandlerThrows(TestFirstOffsetAfter_InvalidPositive, "first offset after (+ve, invalid)")
611+
MCUnitTestHandlerThrows(TestFirstOffsetAfter_InvalidNegative, "first offset after (-ve, invalid)")
612+
end handler
613+
public handler TestLastOffsetAfter()
614+
variable t
615+
put [true, false, true, true, false] into t
616+
617+
test "last offset after (+ve)" when the last offset of [true] after 1 in t is 3
618+
test "last offset after (-ve)" when the last offset of [true] after -5 in t is 3
619+
test "last offset after (-ve, limit)" when the last offset of [true] after -6 in t is 4
620+
test "last offset after (+ve, missing)" when the last offset of [true] after 4 in t is 0
621+
test "last offset after (-ve, missing)" when the last offset of [true] after -2 in t is 0
622+
623+
MCUnitTestHandlerThrows(TestLastOffsetAfter_InvalidPositive, "last offset after (+ve, invalid)")
624+
MCUnitTestHandlerThrows(TestLastOffsetAfter_InvalidNegative, "last offset after (-ve, invalid)")
625+
end handler
626+
public handler TestOffsetAfterZero()
627+
-- "offset of _ after 0 in _" should be equivalent to "offset of _ in _"
628+
variable t
629+
put [true, false, true, true, false] into t
630+
variable tNoAfter
631+
632+
put the offset of [true,false] in t into tNoAfter
633+
test "offset after (+ve, 0)" when the offset of [true,false] after 0 in t is tNoAfter
634+
635+
put the first offset of [true,false] in t into tNoAfter
636+
test "first offset after (+ve, 0)" when the first offset of [true,false] after 0 in t is tNoAfter
637+
638+
put the last offset of [true,false] in t into tNoAfter
639+
test "last offset after (+ve, 0)" when the last offset of [true,false] after 0 in t is tNoAfter
640+
end handler
641+
567642

568643
end module

0 commit comments

Comments
 (0)