2929
3030package org .scijava .ops .engine .matcher .impl ;
3131
32- import java .lang .reflect .ParameterizedType ;
33- import java .lang .reflect .Type ;
34- import java .lang .reflect .TypeVariable ;
3532import java .util .ArrayList ;
36- import java .util .Arrays ;
3733import java .util .Collection ;
3834import java .util .Collections ;
39- import java .util .HashMap ;
4035import java .util .List ;
4136
4237import org .scijava .ops .api .OpCandidate ;
43- import org .scijava .ops .api .OpCandidate .StatusCode ;
4438import org .scijava .ops .api .OpEnvironment ;
4539import org .scijava .ops .api .OpRef ;
46- import org .scijava .ops .api .OpUtils ;
4740import org .scijava .ops .api .features .MatchingConditions ;
4841import org .scijava .ops .api .features .MatchingRoutine ;
4942import org .scijava .ops .api .features .OpMatcher ;
5043import org .scijava .ops .api .features .OpMatchingException ;
5144import org .scijava .service .AbstractService ;
52- import org .scijava .struct .Member ;
53- import org .scijava .types .Types ;
54- import org .scijava .types .Types .TypeVarInfo ;
5545
5646/**
5747 * Default implementation of {@link OpMatcher}. Used for finding Ops which match
@@ -68,121 +58,6 @@ public DefaultOpMatcher(Collection<? extends MatchingRoutine> matchers) {
6858 Collections .sort (this .matchers , Collections .reverseOrder ());
6959 }
7060
71- private OpMatchingException agglomeratedException (
72- List <OpMatchingException > list )
73- {
74- OpMatchingException agglomerated = new OpMatchingException (
75- "No MatchingRoutine was able to produce a match!" );
76- for (int i = 0 ; i < list .size (); i ++) {
77- agglomerated .addSuppressed (list .get (i ));
78- }
79- return agglomerated ;
80- }
81-
82- // -- Helper methods --
83-
84- /**
85- * Performs several checks, whether the specified candidate:</br>
86- * </br>
87- * * {@link #isValid(OpCandidate)}</br>
88- * * {@link #outputsMatch(OpCandidate, HashMap)}</br>
89- * * has a matching number of args</br>
90- * * {@link #missArgs(OpCandidate, Type[])}</br>
91- * </br>
92- * then returns the candidates which fulfill this criteria.
93- *
94- * @param candidates
95- * the candidates to check
96- * @return candidates passing checks
97- */
98- private List <OpCandidate > checkCandidates (final List <OpCandidate > candidates ) {
99- final ArrayList <OpCandidate > validCandidates = new ArrayList <>();
100- for (final OpCandidate candidate : candidates ) {
101- if (!isValid (candidate ))
102- continue ;
103- final Type [] args = candidate .paddedArgs ();
104- if (args == null )
105- continue ;
106- if (missArgs (candidate , args ))
107- continue ;
108- validCandidates .add (candidate );
109- }
110- return validCandidates ;
111- }
112-
113- /**
114- * Checks whether the output types of the candidate are applicable to the
115- * input types of the {@link OpRef}. Sets candidate status code if there are
116- * too many, to few, or not matching types.
117- *
118- * @param candidate
119- * the candidate to check inputs for
120- * @param typeBounds
121- * possibly predetermined type bounds for type variables
122- * @return whether the input types match
123- */
124- private boolean inputsMatch (final OpCandidate candidate , HashMap <TypeVariable <?>, TypeVarInfo > typeBounds ) {
125- if (checkCandidates (Collections .singletonList (candidate )).isEmpty ())
126- return false ;
127- final Type [] refArgTypes = candidate .paddedArgs ();
128- final Type refType = candidate .getRef ().getType ();
129- final Type infoType = candidate .opInfo ().opType ();
130- Type [] candidateArgTypes = OpUtils .inputTypes (candidate );
131- Type implementedInfoType = Types .getExactSuperType (infoType , Types .raw (
132- refType ));
133- if (!(implementedInfoType instanceof ParameterizedType )) {
134- throw new UnsupportedOperationException (
135- "Op type is not a ParameterizedType; we don't know how to deal with these yet." );
136- }
137- Type [] implTypeParams = ((ParameterizedType ) implementedInfoType )
138- .getActualTypeArguments ();
139- candidateArgTypes = candidate .opInfo ().struct ().members ().stream ()//
140- .map (member -> member .isInput () ? member .getType () : null ) //
141- .toArray (Type []::new );
142- for (int i = 0 ; i < implTypeParams .length ; i ++) {
143- if (candidateArgTypes [i ] == null ) implTypeParams [i ] = null ;
144- }
145- candidateArgTypes = Arrays .stream (implTypeParams ) //
146- .filter (t -> t != null ).toArray (Type []::new );
147-
148- if (refArgTypes == null )
149- return true ; // no constraints on output types
150-
151- if (candidateArgTypes .length < refArgTypes .length ) {
152- candidate .setStatus (StatusCode .TOO_FEW_ARGS );
153- return false ;
154- } else if (candidateArgTypes .length > refArgTypes .length ) {
155- candidate .setStatus (StatusCode .TOO_MANY_ARGS );
156- return false ;
157- }
158-
159- int conflictingIndex = Types .isApplicable (refArgTypes , candidateArgTypes , typeBounds );
160- if (conflictingIndex != -1 ) {
161- final Type to = refArgTypes [conflictingIndex ];
162- final Type from = candidateArgTypes [conflictingIndex ];
163- candidate .setStatus (StatusCode .ARG_TYPES_DO_NOT_MATCH , //
164- "request=" + to .getTypeName () + ", actual=" + from .getTypeName ());
165- return false ;
166- }
167- return true ;
168- }
169-
170- /**
171- * Determines if the specified candidate is valid and sets status code if
172- * not.
173- *
174- * @param candidate
175- * the candidate to check
176- * @return whether the candidate is valid
177- */
178- private boolean isValid (final OpCandidate candidate ) {
179- if (candidate .opInfo ().isValid ()) {
180- return true ;
181- }
182- candidate .setStatus (StatusCode .INVALID_STRUCT );
183- return false ;
184- }
185-
18661 @ Override
18762 public OpCandidate match (MatchingConditions conditions , OpEnvironment env ) {
18863 List <OpMatchingException > exceptions = new ArrayList <>(matchers .size ());
@@ -200,69 +75,14 @@ public OpCandidate match(MatchingConditions conditions, OpEnvironment env) {
20075 throw agglomeratedException (exceptions );
20176 }
20277
203- /**
204- * Determines if the candidate has some arguments missing.
205- * <p>
206- * Helper method of {@link #filterMatches(List)}.
207- * </p>
208- */
209- private boolean missArgs (final OpCandidate candidate , final Type [] paddedArgs ) {
210- int i = 0 ;
211- for (final Member <?> member : OpUtils .inputs (candidate )) {
212- if (paddedArgs [i ++] == null && member .isRequired ()) {
213- candidate .setStatus (StatusCode .REQUIRED_ARG_IS_NULL , null , member );
214- return true ;
215- }
216- }
217- return false ;
218- }
219-
220- /**
221- * Checks whether the output type of the candidate matches the output type
222- * of the {@link OpRef}. Sets candidate status code if they are not matching.
223- *
224- * @param candidate
225- * the candidate to check output for
226- * @param typeBounds
227- * possibly predetermined type bounds for type variables
228- * @return whether the output types match
229- */
230- private boolean outputsMatch (final OpCandidate candidate , HashMap <TypeVariable <?>, TypeVarInfo > typeBounds ) {
231- final Type refOutType = candidate .getRef ().getOutType ();
232- if (refOutType == null )
233- return true ; // no constraints on output types
234-
235- if (candidate .opInfo ().output ().isInput ()) return true ;
236- final Type candidateOutType = OpUtils .outputType (candidate );
237- final int conflictingIndex = MatchingUtils .checkGenericOutputsAssignability (new Type [] { candidateOutType },
238- new Type [] { refOutType }, typeBounds );
239- if (conflictingIndex != -1 ) {
240- candidate .setStatus (StatusCode .OUTPUT_TYPES_DO_NOT_MATCH , //
241- "request=" + refOutType .getTypeName () + ", actual=" + candidateOutType .getTypeName ());
242- return false ;
243- }
244- return true ;
245- }
246-
247- /**
248- * Checks whether the arg types of the candidate satisfy the padded arg
249- * types of the candidate. Sets candidate status code if there are too many,
250- * to few,not matching arg types or if a match was found.
251- *
252- * @param candidate
253- * the candidate to check args for
254- * @return whether the arg types are satisfied
255- */
256- @ Override
257- public boolean typesMatch (final OpCandidate candidate ) {
258- HashMap <TypeVariable <?>, TypeVarInfo > typeBounds = new HashMap <>();
259- if (!inputsMatch (candidate , typeBounds )) {
260- return false ;
261- }
262- if (!outputsMatch (candidate , typeBounds )) {
263- return false ;
78+ private OpMatchingException agglomeratedException (
79+ List <OpMatchingException > list )
80+ {
81+ OpMatchingException agglomerated = new OpMatchingException (
82+ "No MatchingRoutine was able to produce a match!" );
83+ for (int i = 0 ; i < list .size (); i ++) {
84+ agglomerated .addSuppressed (list .get (i ));
26485 }
265- candidate .setStatus (StatusCode .MATCH );
266- return true ;
86+ return agglomerated ;
26787 }
26888}
0 commit comments