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

Commit e1da9a0

Browse files
committed
com.livecode.list: Add "index of _ before _ in _" accessor.
Add a new operation on lists: the index of <tNeedle> before <tPosition> in <tList> This looks for an element equal to <tNeedle> in the subsequence of <tList> ending at the 1-based index <tPosition> (exclusive). It returns the 1-based index, 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> before <tPosition> in <tList> the last index of <tNeedle> before <tPosition> in <tList> If <tNeedle> is a list, it is considered as an element of <tList> not as a subsequence of <tList>.
1 parent a81437b commit e1da9a0

3 files changed

Lines changed: 140 additions & 0 deletions

File tree

libscript/src/list.mlc

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ public foreign handler MCListExecDeleteLastElementOf(inout Target as List) as un
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>"
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>"
79+
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>"
7980

8081
--
8182

@@ -928,4 +929,39 @@ begin
928929
MCListEvalIndexOfElementAfter(IsLast, Needle, After, Haystack, output)
929930
end syntax
930931

932+
/*
933+
Summary: Find the first or last occurrence of <Needle> within the head of <Haystack>
934+
935+
Needle: An expression which evaluates to any value.
936+
Before: An expression which evaluates to a valid index in Target.
937+
Target: An expression which evaluates to a list.
938+
939+
Returns: Returns the index in <Haystack>.
940+
941+
Example:
942+
variable tVar as List
943+
variable tOffset as Number
944+
put ["a", "b", "c", "d", "b"]
945+
put the index of "b" before 2 in tVar into tOffset
946+
--tOffset contains 0
947+
948+
put the first index of "b" before 5 in tVar into tOffset
949+
--tOffset contains 2
950+
951+
Description:
952+
Use `the index of… before` to find where particular elements occur
953+
within a list. <Haystack> is scanned for an element that is equal to
954+
<Needle>, stopping before the position <Before>, and the position of
955+
the element found is returned. If no element of <Haystack> is equal
956+
to <Needle>, the return value is 0. If neither "first" nor "last" is
957+
specified, the last matching element is found.
958+
959+
Tags: Lists
960+
*/
961+
syntax ListIndexBefore is prefix operator with precedence 1
962+
"the" ( "first" <IsLast=false> | "last" <IsLast=true> | <IsLast=true> ) "index" "of" <Needle: Expression> "before" <Before: Expression> "in" <Haystack: Expression>
963+
begin
964+
MCListEvalIndexOfElementBefore(IsLast, Needle, Before, Haystack, output)
965+
end syntax
966+
931967
end module

libscript/src/module-list.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -503,6 +503,30 @@ MCListEvalIndexOfElementAfter (bool p_is_last,
503503
r_output);
504504
}
505505

506+
extern "C" MC_DLLEXPORT void
507+
MCListEvalIndexOfElementBefore (bool p_is_last,
508+
MCValueRef p_needle,
509+
index_t p_before,
510+
MCProperListRef p_haystack,
511+
uindex_t & r_output)
512+
{
513+
uindex_t t_start, t_count;
514+
if (p_before == 0)
515+
{
516+
t_start = UINDEX_MAX;
517+
} else if (!MCChunkGetExtentsOfElementChunkByExpressionInRange (p_haystack,
518+
nil, p_before, true, false, true, t_start, t_count))
519+
{
520+
MCErrorCreateAndThrow (kMCGenericErrorTypeInfo, "reason",
521+
MCSTR("chunk index out of range"), nil);
522+
return;
523+
}
524+
525+
MCListEvalIndexOfElementInRange (p_is_last, p_needle, p_haystack,
526+
MCRangeMake(0, t_start),
527+
r_output);
528+
}
529+
506530
////////////////////////////////////////////////////////////////////////////////////////////////////
507531

508532
#ifdef _TEST

tests/lcb/stdlib/list.lcb

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,8 @@ public handler TestRepeatElement()
376376
test "repeat element (count)" when tCount is 4
377377
end handler
378378

379+
----------------------------------------------------------------
380+
-- Finding indices
379381
----------------------------------------------------------------
380382

381383
public handler TestIndex()
@@ -392,6 +394,8 @@ public handler TestIndex()
392394
test "index (empty)" when the index of 1 in [] is 0
393395
end handler
394396

397+
----------------------------------------------------------------
398+
395399
handler TestIndexAfter_InvalidPositive()
396400
return the index of true after 2 in [true]
397401
end handler
@@ -465,4 +469,80 @@ public handler TestIndexAfterZero()
465469
test "last index after (+ve, 0)" when the last index of true after 0 in t is tNoAfter
466470
end handler
467471

472+
----------------------------------------------------------------
473+
474+
handler TestIndexBefore_InvalidPositive()
475+
return the index of true before 3 in [true]
476+
end handler
477+
handler TestIndexBefore_InvalidNegative()
478+
return the index of true before -2 in [true]
479+
end handler
480+
handler TestFirstIndexBefore_InvalidPositive()
481+
return the first index of true before 3 in [true]
482+
end handler
483+
handler TestFirstIndexBefore_InvalidNegative()
484+
return the first index of true before -2 in [true]
485+
end handler
486+
handler TestLastIndexBefore_InvalidPositive()
487+
return the last index of true before 3 in [true]
488+
end handler
489+
handler TestLastIndexBefore_InvalidNegative()
490+
return the last index of true before -2 in [true]
491+
end handler
492+
public handler TestIndexBefore()
493+
variable t
494+
put [false, true, true, false, true] into t
495+
496+
test "index before (+ve)" when the index of true before 4 in t is 3
497+
test "index before (-ve)" when the index of true before -2 in t is 3
498+
test "index before (+ve, limit)" when the index of true before 6 in t is 5
499+
test "index before (+ve, missing)" when the index of true before 2 in t is 0
500+
test "index before (-ve, missing)" when the index of true before -4 in t is 0
501+
502+
MCUnitTestHandlerThrows(TestIndexBefore_InvalidPositive, "index before (+ve, invalid)")
503+
MCUnitTestHandlerThrows(TestIndexBefore_InvalidNegative, "index before (-ve, invalid)")
504+
end handler
505+
public handler TestFirstIndexBefore()
506+
variable t
507+
put [false, true, true, false, true] into t
508+
509+
test "first index before (+ve)" when the first index of true before 4 in t is 2
510+
test "first index before (-ve)" when the first index of true before -2 in t is 2
511+
test "first index before (+ve, limit)" when the first index of true before 6 in t is 2
512+
test "first index before (+ve, missing)" when the first index of true before 2 in t is 0
513+
test "first index before (-ve, missing)" when the first index of true before -4 in t is 0
514+
515+
MCUnitTestHandlerThrows(TestFirstIndexBefore_InvalidPositive, "first index before (+ve, invalid)")
516+
MCUnitTestHandlerThrows(TestFirstIndexBefore_InvalidNegative, "first index before (-ve, invalid)")
517+
end handler
518+
public handler TestLastIndexBefore()
519+
variable t
520+
put [false, true, true, false, true] into t
521+
522+
test "last index before (+ve)" when the last index of true before 4 in t is 3
523+
test "last index before (-ve)" when the last index of true before -2 in t is 3
524+
test "last index before (+ve, limit)" when the last index of true before 6 in t is 5
525+
test "last index before (+ve, missing)" when the last index of true before 2 in t is 0
526+
test "last index before (-ve, missing)" when the last index of true before -4 in t is 0
527+
528+
MCUnitTestHandlerThrows(TestLastIndexBefore_InvalidPositive, "last index before (+ve, invalid)")
529+
MCUnitTestHandlerThrows(TestLastIndexBefore_InvalidNegative, "last index before (-ve, invalid)")
530+
end handler
531+
public handler TestIndexBeforeZero()
532+
-- "index of _ before 0 in _" should be equivalent to
533+
-- "last index of _ in _"
534+
variable t
535+
put [false, true, true, false, true] into t
536+
variable tNoBefore
537+
538+
put the last index of true in t into tNoBefore
539+
test "index before (+ve, 0)" when the index of true before 0 in t is tNoBefore
540+
541+
put the first index of true in t into tNoBefore
542+
test "first index before (+ve, 0)" when the first index of true before 0 in t is tNoBefore
543+
544+
put the last index of true in t into tNoBefore
545+
test "last index before (+ve, 0)" when the last index of true before 0 in t is tNoBefore
546+
end handler
547+
468548
end module

0 commit comments

Comments
 (0)