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

Commit 1f4dd2f

Browse files
committed
com.livecode.list: Add "offset of _ before _ in _" accessor.
Add a new operation on lists: the offset of <tNeedle> before <tPosition> in <tList> This looks for an subsequence equal to <tNeedle> in the subsequence of <tList> ending at the 1-based index <tPosition> (exclusive). It returns the 1-based index in <tList> 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> before <tPosition> in <tList> the last offset of <tNeedle> before <tPosition> in <tList> <tNeedle> must be a List.
1 parent b0028c1 commit 1f4dd2f

3 files changed

Lines changed: 137 additions & 0 deletions

File tree

libscript/src/list.mlc

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ public foreign handler MCListEvalIndexOfElementBefore(in IsLast as CBool, in Nee
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>"
8282
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>"
83+
public foreign handler MCListEvalOffsetOfListBefore(in IsLast as CBool, in Needle as List, in Before as LCIndex, in Haystack as List, out Index as LCUIndex) as undefined binds to "<builtin>"
8384

8485
--
8586

@@ -1043,4 +1044,41 @@ begin
10431044
MCListEvalOffsetOfListAfter(IsLast, Needle, After, Haystack, output)
10441045
end syntax
10451046

1047+
/*
1048+
Summary: Find the first or last occurrence of <Needle> within the head of <Haystack>
1049+
1050+
Needle: An expression which evaluates to List.
1051+
Before: An expression which evaluates to a valid index in Target.
1052+
Target: An expression which evaluates to a List.
1053+
1054+
Returns: Returns the index in <Haystack>.
1055+
1056+
Example:
1057+
variable tVar as List
1058+
variable tOffset as Number
1059+
put ["a", "b", "c", "d", "b","c"]
1060+
put the offset of ["b","c"] before 5 in tVar into tOffset
1061+
--tOffset contains 2
1062+
1063+
put the first offset of ["b","c"] before 6 in tVar into tOffset
1064+
--tOffset contains 2
1065+
1066+
Description:
1067+
1068+
Use `the offset of… before` to find where a particular sub-list occurs
1069+
within a list. <Haystack> is scanned for a sequence of elements that
1070+
are equal to the elements of <Needle>, stopping before the position
1071+
<Before>, and the position of the start of the sequence found is
1072+
returned. If no sub-list of <Haystack> before the position <Before>
1073+
is equal to <Needle>, the return value is 0. If neither "first" nor
1074+
"last" is specified, the last matching subsequence is found.
1075+
1076+
Tags: Lists
1077+
*/
1078+
syntax ListOffsetBefore is prefix operator with precedence 1
1079+
"the" ( "first" <IsLast=false> | "last" <IsLast=true> | <IsLast=true> ) "offset" "of" <Needle: Expression> "before" <Before: Expression> "in" <Haystack: Expression>
1080+
begin
1081+
MCListEvalOffsetOfListBefore(IsLast, Needle, Before, Haystack, output)
1082+
end syntax
1083+
10461084
end module

libscript/src/module-list.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -589,6 +589,30 @@ MCListEvalOffsetOfListAfter (bool p_is_last,
589589
r_output);
590590
}
591591

592+
extern "C" MC_DLLEXPORT void
593+
MCListEvalOffsetOfListBefore (bool p_is_last,
594+
MCProperListRef p_needle,
595+
index_t p_before,
596+
MCProperListRef p_haystack,
597+
uindex_t & r_output)
598+
{
599+
uindex_t t_start, t_count;
600+
if (p_before == 0)
601+
{
602+
t_start = UINDEX_MAX;
603+
} else if (!MCChunkGetExtentsOfElementChunkByExpressionInRange (p_haystack,
604+
nil, p_before, true, false, true, t_start, t_count))
605+
{
606+
MCErrorCreateAndThrow (kMCGenericErrorTypeInfo, "reason",
607+
MCSTR("chunk index out of range"), nil);
608+
return;
609+
}
610+
611+
MCListEvalOffsetOfListInRange (p_is_last, p_needle, p_haystack,
612+
MCRangeMake(0, t_start),
613+
r_output);
614+
}
615+
592616
////////////////////////////////////////////////////////////////////////////////////////////////////
593617

594618
#ifdef _TEST

tests/lcb/stdlib/list.lcb

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -639,5 +639,80 @@ public handler TestOffsetAfterZero()
639639
test "last offset after (+ve, 0)" when the last offset of [true,false] after 0 in t is tNoAfter
640640
end handler
641641

642+
----------------------------------------------------------------
643+
644+
handler TestOffsetBefore_InvalidPositive()
645+
return the offset of [true] before 3 in [true]
646+
end handler
647+
handler TestOffsetBefore_InvalidNegative()
648+
return the offset of [true] before -2 in [true]
649+
end handler
650+
handler TestFirstOffsetBefore_InvalidPositive()
651+
return the first offset of [true] before 3 in [true]
652+
end handler
653+
handler TestFirstOffsetBefore_InvalidNegative()
654+
return the first offset of [true] before -2 in [true]
655+
end handler
656+
handler TestLastOffsetBefore_InvalidPositive()
657+
return the last offset of [true] before 3 in [true]
658+
end handler
659+
handler TestLastOffsetBefore_InvalidNegative()
660+
return the last offset of [true] before -2 in [true]
661+
end handler
662+
public handler TestOffsetBefore()
663+
variable t
664+
put [true, false, true, true, false] into t
665+
666+
test "offset before (+ve)" when the offset of [true,false] before 4 in t is 1
667+
test "offset before (-ve)" when the offset of [true,false] before -2 in t is 1
668+
test "offset before (+ve, limit)" when the offset of [true,false] before 6 in t is 4
669+
test "offset before (+ve, missing)" when the offset of [false,true] before 2 in t is 0
670+
test "offset before (-ve, missing)" when the offset of [false,true] before -4 in t is 0
671+
672+
MCUnitTestHandlerThrows(TestOffsetBefore_InvalidPositive, "offset before (+ve, invalid)")
673+
MCUnitTestHandlerThrows(TestOffsetBefore_InvalidNegative, "offset before (-ve, invalid)")
674+
end handler
675+
public handler TestFirstOffsetBefore()
676+
variable t
677+
put [true, false, true, true, false] into t
678+
679+
test "first offset before (+ve)" when the first offset of [true,false] before 5 in t is 1
680+
test "first offset before (-ve)" when the first offset of [true,false] before -1 in t is 1
681+
test "first offset before (+ve, limit)" when the first offset of [true,false] before 6 in t is 1
682+
test "first offset before (+ve, missing)" when the first offset of [false,true] before 2 in t is 0
683+
test "first offset before (-ve, missing)" when the first offset of [false,true] before -4 in t is 0
684+
685+
MCUnitTestHandlerThrows(TestFirstOffsetBefore_InvalidPositive, "first offset before (+ve, invalid)")
686+
MCUnitTestHandlerThrows(TestFirstOffsetBefore_InvalidNegative, "first offset before (-ve, invalid)")
687+
end handler
688+
public handler TestLastOffsetBefore()
689+
variable t
690+
put [true, false, true, true, false] into t
691+
692+
test "last offset before (+ve)" when the last offset of [true,false] before 4 in t is 1
693+
test "last offset before (-ve)" when the last offset of [true,false] before -2 in t is 1
694+
test "last offset before (+ve, limit)" when the last offset of [true,false] before 6 in t is 4
695+
test "last offset before (+ve, missing)" when the last offset of [false,true] before 2 in t is 0
696+
test "last offset before (-ve, missing)" when the last offset of [false,true] before -4 in t is 0
697+
698+
MCUnitTestHandlerThrows(TestLastOffsetBefore_InvalidPositive, "last offset before (+ve, invalid)")
699+
MCUnitTestHandlerThrows(TestLastOffsetBefore_InvalidNegative, "last offset before (-ve, invalid)")
700+
end handler
701+
public handler TestOffsetBeforeZero()
702+
-- "offset of _ before 0 in _" should be equivalent to "last offset of _ in _"
703+
variable t
704+
put [true, false, true, true, false] into t
705+
variable tNoBefore
706+
707+
put the last offset of [true,false] in t into tNoBefore
708+
test "offset before (+ve, 0)" when the offset of [true,false] before 0 in t is tNoBefore
709+
710+
put the first offset of [true,false] in t into tNoBefore
711+
test "first offset before (+ve, 0)" when the first offset of [true,false] before 0 in t is tNoBefore
712+
713+
put the last offset of [true,false] in t into tNoBefore
714+
test "last offset before (+ve, 0)" when the last offset of [true,false] before 0 in t is tNoBefore
715+
end handler
716+
642717

643718
end module

0 commit comments

Comments
 (0)