@@ -24,6 +24,8 @@ this software and associated documentation files (the "Software"), to deal in
2424package unquietcode .tools .esm ;
2525
2626import unquietcode .tools .esm .routing .StateRouter ;
27+ import unquietcode .tools .esm .sequences .Pattern ;
28+ import unquietcode .tools .esm .sequences .PatternBuilder ;
2729
2830import java .util .*;
2931import java .util .concurrent .*;
@@ -46,7 +48,7 @@ public class GenericStateMachine<T extends State> implements StateMachine<T> {
4648 // sequence matching
4749 private int maxRecent = 0 ;
4850 private final Queue <StateContainer > recentStates = new ArrayDeque <>();
49- private final Set <PatternMatcher > matchers = new HashSet <>();
51+ private final Set <PatternMatcher < T > > matchers = new HashSet <>();
5052
5153 // global handlers
5254 private final Set <StateHandler <T >> globalOnEntryHandlers = new HashSet <>();
@@ -159,9 +161,11 @@ private void doPatternMatching(StateContainer nextState) {
159161 final List <StateContainer > recent
160162 = Collections .unmodifiableList (new ArrayList <>(recentStates ));
161163
162- for (PatternMatcher matcher : matchers ) {
163- if (matcher .matches (recent )) {
164- matcher .handler .onMatch (matcher .pattern );
164+ for (PatternMatcher <T > matcher : matchers ) {
165+ Optional <List <T >> matches = matcher .matches (recent );
166+
167+ if (matches .isPresent ()) {
168+ matcher .handler .onMatch (matches .get ());
165169 }
166170 }
167171 }
@@ -400,29 +404,35 @@ public T route(T current, T next) {
400404 }
401405
402406 @ Override
403- public synchronized HandlerRegistration onSequence (List <T > pattern , SequenceHandler <T > handler ) {
404- List <State > _pattern = Collections .<State >unmodifiableList (pattern );
405- final PatternMatcher matcher = new PatternMatcher (_pattern , handler );
407+ public HandlerRegistration onSequence (Pattern <T > pattern , SequenceHandler <T > handler ) {
408+ final PatternMatcher <T > matcher = new PatternMatcher <>(pattern , handler );
406409 matchers .add (matcher );
407- maxRecent = Math .max (maxRecent , pattern .size ());
408410
409- return new HandlerRegistration () {
410- public void unregister () {
411- matchers .remove (matcher );
412- }
411+ // recalculate the cache size on add
412+ maxRecent = Math .max (maxRecent , pattern .length ());
413+
414+ return () -> {
415+ matchers .remove (matcher );
416+
417+ // recalculate the cache size on remove
418+ Optional <Integer > max = matchers .stream ()
419+ .map (e -> e .pattern .length ())
420+ .max (Integer ::compareTo );
421+
422+ maxRecent = max .orElse (0 );
413423 };
414424 }
415425
416426 @ Override
417427 @ SuppressWarnings ("unchecked" )
418428 public synchronized boolean addTransition (T fromState , T toState ) {
419- return addTransitions (null , true , fromState , Arrays . asList (toState ));
429+ return addTransitions (null , true , fromState , Collections . singletonList (toState ));
420430 }
421431
422432 @ Override
423433 @ SuppressWarnings ("unchecked" )
424434 public synchronized boolean addTransition (T fromState , T toState , TransitionHandler <T > callback ) {
425- return addTransitions (callback , true , fromState , Arrays . asList (toState ));
435+ return addTransitions (callback , true , fromState , Collections . singletonList (toState ));
426436 }
427437
428438 @ Override
@@ -516,14 +526,13 @@ public String toString() {
516526 }
517527
518528 int i = 1 ;
519- Map <StateWrapper , StateContainer > sortedStates = new TreeMap <StateWrapper , StateContainer >(states );
529+ Map <StateWrapper , StateContainer > sortedStates = new TreeMap <>(states );
520530
521531 for (Map .Entry <StateWrapper , StateContainer > entry : sortedStates .entrySet ()) {
522532 sb .append ("\t " ).append (fullString (entry .getKey ().state )).append (" : {" );
523533
524534 int j = 1 ;
525- Map <StateContainer , Transition > sortedTransitions
526- = new TreeMap <StateContainer , Transition >(entry .getValue ().transitions );
535+ Map <StateContainer , Transition > sortedTransitions = new TreeMap <>(entry .getValue ().transitions );
527536
528537 for (Transition t : sortedTransitions .values ()) {
529538 sb .append (fullString (t .next .state ));
@@ -556,9 +565,9 @@ private StateContainer getState(T token) {
556565
557566 private static class StateContainer implements Comparable <StateContainer > {
558567 final State state ;
559- final Map <StateContainer , Transition > transitions = new HashMap <StateContainer , Transition >();
560- final Set <StateHandler > entryActions = new HashSet <StateHandler >();
561- final Set <StateHandler > exitActions = new HashSet <StateHandler >();
568+ final Map <StateContainer , Transition > transitions = new HashMap <>();
569+ final Set <StateHandler > entryActions = new HashSet <>();
570+ final Set <StateHandler > exitActions = new HashSet <>();
562571
563572 StateContainer (State state ) {
564573 this .state = state ;
@@ -617,7 +626,7 @@ public int hashCode() {
617626
618627 private static class Transition {
619628 final StateContainer next ;
620- final Set <TransitionHandler > callbacks = new HashSet <TransitionHandler >();
629+ final Set <TransitionHandler > callbacks = new HashSet <>();
621630
622631 Transition (StateContainer next ) {
623632 this .next = next ;
@@ -635,38 +644,48 @@ private static class Transition {
635644// }
636645 }
637646
638- private static class PatternMatcher {
639- private final List < State > pattern ;
647+ private static class PatternMatcher < T > {
648+ private final Pattern < T > pattern ;
640649 private final SequenceHandler handler ;
641650
642- PatternMatcher (List < State > pattern , SequenceHandler handler ) {
651+ PatternMatcher (Pattern < T > pattern , SequenceHandler handler ) {
643652 this .pattern = pattern ;
644653 this .handler = handler ;
645654 }
646655
647- boolean matches (List <StateContainer > states ) {
648- for (int i = pattern .size () - 1 ; i >= 0 ; --i ) {
649- int j = states .size () - (pattern .size () - i );
656+ Optional <List <T >> matches (List <StateContainer > states ) {
657+ List <T > matches = new ArrayList <>();
658+ List <Object > patternStates = this .pattern .pattern ();
659+
660+ for (int i = patternStates .size () - 1 ; i >= 0 ; --i ) {
661+ int j = states .size () - (patternStates .size () - i );
650662
651663 if (j < 0 ) {
652- return false ;
664+ return Optional . empty () ;
653665 }
654666
655- State matchState = pattern .get (i );
667+ Object matchState = patternStates .get (i );
656668 State recentState = states .get (j ).state ;
657669
658- if (matchState == null ) {
670+ if (PatternBuilder .isWildcard (matchState )) {
671+ // nothing, do no state checking
672+ } else if (matchState == null ) {
659673 if (recentState != null ) {
660- return false ;
674+ return Optional . empty () ;
661675 }
662676 } else if (recentState == null ) {
663- return false ;
677+ return Optional . empty () ;
664678 } else if (!matchState .equals (recentState )) {
665- return false ;
679+ return Optional . empty () ;
666680 }
681+
682+ @ SuppressWarnings ("unchecked" )
683+ T recentState_ = (T ) recentState ;
684+ matches .add (recentState_ );
667685 }
668686
669- return true ;
687+ Collections .reverse (matches );
688+ return Optional .of (matches );
670689 }
671690 }
672691
0 commit comments