Skip to content

Commit 065e7b7

Browse files
committed
Add SequencesExt!RemoveFirst and RemoveFirstMatch.
1 parent 580efdc commit 065e7b7

File tree

3 files changed

+91
-0
lines changed

3 files changed

+91
-0
lines changed

modules/SequencesExt.tla

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,24 @@ RemoveAt(s, i) ==
169169
(**************************************************************************)
170170
SubSeq(s, 1, i-1) \o SubSeq(s, i+1, Len(s))
171171

172+
RemoveFirst(s, e) ==
173+
(************************************************************************)
174+
(* The sequence s with the first occurrence of e removed or s *)
175+
(* iff e \notin Range(s) *)
176+
(************************************************************************)
177+
IF \E i \in 1..Len(s): s[i] = e
178+
THEN RemoveAt(s, SelectInSeq(s, LAMBDA v: v = e))
179+
ELSE s
180+
181+
RemoveFirstMatch(s, Test(_)) ==
182+
(************************************************************************)
183+
(* The sequence s with the first element removed s.t. Test(e) or s *)
184+
(* iff e \notin Range(s) *)
185+
(************************************************************************)
186+
IF \E i \in 1..Len(s): Test(s[i])
187+
THEN RemoveAt(s, SelectInSeq(s, Test))
188+
ELSE s
189+
172190
-----------------------------------------------------------------------------
173191

174192
Cons(elt, seq) ==

modules/tlc2/overrides/SequencesExt.java

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
* Markus Alexander Kuppe - initial API and implementation
2626
******************************************************************************/
2727

28+
import java.util.ArrayList;
29+
2830
import org.apache.commons.lang3.StringUtils;
2931

3032
import tla2sany.semantic.ExprOrOpArgNode;
@@ -535,6 +537,64 @@ public static Value SelectLastInSubSeq(final Value s, final Value f, final Value
535537
}
536538
return IntValue.ValZero;
537539
}
540+
541+
@TLAPlusOperator(identifier = "RemoveFirst", module = "SequencesExt", warn = false)
542+
public static Value removeFirst(final Value s, final Value e) {
543+
final TupleValue seq = (TupleValue) s.toTuple();
544+
if (seq == null) {
545+
throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR,
546+
new String[] { "first", "RemoveFirst", "sequence", Values.ppr(s.toString()) });
547+
}
548+
549+
final ArrayList<Value> val = new ArrayList<>(seq.elems.length);
550+
551+
boolean found = false;
552+
for (int i = 0; i < seq.elems.length; i++) {
553+
if (!found && seq.elems[i].equals(e)) {
554+
found = true;
555+
} else {
556+
val.add(seq.elems[i]);
557+
}
558+
}
559+
560+
return new TupleValue(val.toArray(Value[]::new));
561+
}
562+
563+
@TLAPlusOperator(identifier = "RemoveFirstMatch", module = "SequencesExt", warn = false)
564+
public static Value removeFirstMatch(final Value s, final Value test) {
565+
final TupleValue seq = (TupleValue) s.toTuple();
566+
if (seq == null) {
567+
throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR,
568+
new String[] { "first", "RemoveFirstMatch", "sequence", Values.ppr(s.toString()) });
569+
}
570+
if (!(test instanceof Applicable)) {
571+
throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR,
572+
new String[] { "second", "RemoveFirstMatch", "function", Values.ppr(test.toString()) });
573+
}
574+
final Applicable ftest = (Applicable) test;
575+
final Value[] args = new Value[1];
576+
577+
final ArrayList<Value> val = new ArrayList<>(seq.elems.length);
578+
579+
boolean found = false;
580+
for (int i = 0; i < seq.elems.length; i++) {
581+
if (!found) {
582+
args[0] = seq.elems[i];
583+
final Value bval = ftest.apply(args, EvalControl.Clear);
584+
if (!(bval instanceof IBoolValue)) {
585+
throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, new String[] { "second", "RemoveFirstMatch",
586+
"boolean-valued function", Values.ppr(test.toString()) });
587+
}
588+
if (((BoolValue) bval).val) {
589+
found = true;
590+
continue;
591+
}
592+
}
593+
val.add(seq.elems[i]);
594+
}
595+
596+
return new TupleValue(val.toArray(Value[]::new));
597+
}
538598

539599
/*
540600
Suffixes(s) ==

tests/SequencesExtTests.tla

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,5 +369,18 @@ ASSUME AssertEq(Suffixes(<<>>), {<<>>})
369369
ASSUME AssertEq(Suffixes(<<1>>), {<<>>, <<1>>})
370370
ASSUME AssertEq(Suffixes(<<1,2>>), {<<>>, <<1,2>>, <<2>>})
371371
ASSUME AssertEq(Suffixes(<<1,2,3>>), {<<>>, <<3>>, <<2,3>>, <<1,2,3>>})
372+
-----------------------------------------------------------------------------
373+
374+
ASSUME AssertEq(RemoveFirst(<<>>, 1), <<>>)
375+
ASSUME AssertEq(RemoveFirst(<<1>>, 1), <<>>)
376+
ASSUME AssertEq(RemoveFirst(<<1,2>>, 1), <<2>>)
377+
ASSUME AssertEq(RemoveFirst(<<1,2,1>>, 1), <<2,1>>)
378+
ASSUME AssertEq(RemoveFirst(<<1,2,1,2>>, 2), <<1,1,2>>)
379+
380+
ASSUME AssertEq(RemoveFirstMatch(<<>>, LAMBDA e: e = 1), <<>>)
381+
ASSUME AssertEq(RemoveFirstMatch(<<1>>, LAMBDA e: e = 1), <<>>)
382+
ASSUME AssertEq(RemoveFirstMatch(<<1,2>>, LAMBDA e: e = 1), <<2>>)
383+
ASSUME AssertEq(RemoveFirstMatch(<<1,2,1>>, LAMBDA e: e = 1), <<2,1>>)
384+
ASSUME AssertEq(RemoveFirstMatch(<<1,2,1,2>>, LAMBDA e: e = 2), <<1,1,2>>)
372385

373386
=============================================================================

0 commit comments

Comments
 (0)