Clover icon

Coverage Report

  1. Project Clover database Thu Aug 13 2020 12:04:21 BST
  2. Package jalview.datamodel

File SearchResults.java

 

Coverage histogram

../../img/srcFileCovDistChart9.png
12% of files have more coverage

Code metrics

36
88
19
2
351
226
45
0.51
4.63
9.5
2.37

Classes

Class Line # Actions
SearchResults 34 65 32
0.87587.5%
SearchResults.Match 43 23 13
0.897435989.7%
 

Contributing tests

This file is covered by 79 tests. .

Source view

1    /*
2    * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3    * Copyright (C) $$Year-Rel$$ The Jalview Authors
4    *
5    * This file is part of Jalview.
6    *
7    * Jalview is free software: you can redistribute it and/or
8    * modify it under the terms of the GNU General Public License
9    * as published by the Free Software Foundation, either version 3
10    * of the License, or (at your option) any later version.
11    *
12    * Jalview is distributed in the hope that it will be useful, but
13    * WITHOUT ANY WARRANTY; without even the implied warranty
14    * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15    * PURPOSE. See the GNU General Public License for more details.
16    *
17    * You should have received a copy of the GNU General Public License
18    * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19    * The Jalview Authors are detailed in the 'AUTHORS' file.
20    */
21    package jalview.datamodel;
22   
23    import java.util.ArrayList;
24    import java.util.BitSet;
25    import java.util.List;
26   
27    /**
28    * Holds a list of search result matches, where each match is a contiguous
29    * stretch of a single sequence.
30    *
31    * @author gmcarstairs amwaterhouse
32    *
33    */
 
34    public class SearchResults implements SearchResultsI
35    {
36   
37    private List<SearchResultMatchI> matches = new ArrayList<>();
38   
39    /**
40    * One match consists of a sequence reference, start and end positions.
41    * Discontiguous ranges in a sequence require two or more Match objects.
42    */
 
43    public class Match implements SearchResultMatchI
44    {
45    final SequenceI sequence;
46   
47    /**
48    * Start position of match in sequence (base 1)
49    */
50    final int start;
51   
52    /**
53    * End position (inclusive) (base 1)
54    */
55    final int end;
56   
57    /**
58    * create a Match on a range of sequence. Match always holds region in
59    * forwards order, even if given in reverse order (such as from a mapping to
60    * a reverse strand); this avoids trouble for routines that highlight search
61    * results etc
62    *
63    * @param seq
64    * a sequence
65    * @param start
66    * start position of matched range (base 1)
67    * @param end
68    * end of matched range (inclusive, base 1)
69    */
 
70  214 toggle public Match(SequenceI seq, int start, int end)
71    {
72  214 sequence = seq;
73   
74    /*
75    * always hold in forwards order, even if given in reverse order
76    * (such as from a mapping to a reverse strand); this avoids
77    * trouble for routines that highlight search results etc
78    */
79  214 if (start <= end)
80    {
81  213 this.start = start;
82  213 this.end = end;
83    }
84    else
85    {
86    // TODO: JBP could mark match as being specified in reverse direction
87    // for use
88    // by caller ? e.g. visualizing reverse strand highlight
89  1 this.start = end;
90  1 this.end = start;
91    }
92    }
93   
 
94  265 toggle @Override
95    public SequenceI getSequence()
96    {
97  265 return sequence;
98    }
99   
 
100  233 toggle @Override
101    public int getStart()
102    {
103  233 return start;
104    }
105   
 
106  195 toggle @Override
107    public int getEnd()
108    {
109  195 return end;
110    }
111   
112    /**
113    * Returns a representation as "seqid/start-end"
114    */
 
115  7 toggle @Override
116    public String toString()
117    {
118  7 StringBuilder sb = new StringBuilder();
119  7 if (sequence != null)
120    {
121  7 sb.append(sequence.getName()).append("/");
122    }
123  7 sb.append(start).append("-").append(end);
124  7 return sb.toString();
125    }
126   
127    /**
128    * Hashcode is the hashcode of the matched sequence plus a hash of start and
129    * end positions. Match objects that pass the test for equals are guaranteed
130    * to have the same hashcode.
131    */
 
132  8 toggle @Override
133    public int hashCode()
134    {
135  8 int hash = sequence == null ? 0 : sequence.hashCode();
136  8 hash += 31 * start;
137  8 hash += 67 * end;
138  8 return hash;
139    }
140   
141    /**
142    * Two Match objects are equal if they are for the same sequence, start and
143    * end positions
144    */
 
145  81 toggle @Override
146    public boolean equals(Object obj)
147    {
148  81 if (obj == null || !(obj instanceof SearchResultMatchI))
149    {
150  0 return false;
151    }
152  81 SearchResultMatchI m = (SearchResultMatchI) obj;
153  81 return (sequence == m.getSequence() && start == m.getStart()
154    && end == m.getEnd());
155    }
156   
 
157  36 toggle @Override
158    public boolean contains(SequenceI seq, int from, int to)
159    {
160  36 return (sequence == seq && start <= from && end >= to);
161    }
162    }
163   
 
164  210 toggle @Override
165    public SearchResultMatchI addResult(SequenceI seq, int start, int end)
166    {
167  210 Match m = new Match(seq, start, end);
168  210 if (!matches.contains(m))
169    {
170  209 matches.add(m);
171    }
172  210 return m;
173    }
174   
 
175  65 toggle @Override
176    public boolean involvesSequence(SequenceI sequence)
177    {
178  65 final int start = sequence.getStart();
179  65 final int end = sequence.getEnd();
180   
181  65 SequenceI ds = sequence.getDatasetSequence();
182  65 for (SearchResultMatchI m : matches)
183    {
184  68 SequenceI matched = m.getSequence();
185  68 if (matched != null && (matched == sequence || matched == ds)
186    && (m.getEnd() >= start) && (m.getStart() <= end))
187    {
188  14 return true;
189    }
190    }
191  51 return false;
192    }
193   
 
194  48 toggle @Override
195    public int[] getResults(SequenceI sequence, int start, int end)
196    {
197  48 if (matches.isEmpty())
198    {
199  0 return null;
200    }
201   
202  48 int[] result = null;
203  48 int[] tmp = null;
204  48 int resultLength, matchStart = 0, matchEnd = 0;
205  48 boolean mfound;
206  48 Match m;
207  48 for (SearchResultMatchI _m : matches)
208    {
209  64 m = (Match) _m;
210   
211  64 mfound = false;
212  64 if (m.sequence == sequence
213    || m.sequence == sequence.getDatasetSequence())
214    {
215  23 mfound = true;
216  23 matchStart = sequence.findIndex(m.start) - 1;
217  23 matchEnd = m.start == m.end ? matchStart : sequence
218    .findIndex(m.end) - 1;
219    }
220   
221  64 if (mfound)
222    {
223  23 if (matchStart <= end && matchEnd >= start)
224    {
225  23 if (matchStart < start)
226    {
227  1 matchStart = start;
228    }
229   
230  23 if (matchEnd > end)
231    {
232  1 matchEnd = end;
233    }
234   
235  23 if (result == null)
236    {
237  23 result = new int[] { matchStart, matchEnd };
238    }
239    else
240    {
241  0 resultLength = result.length;
242  0 tmp = new int[resultLength + 2];
243  0 System.arraycopy(result, 0, tmp, 0, resultLength);
244  0 result = tmp;
245  0 result[resultLength] = matchStart;
246  0 result[resultLength + 1] = matchEnd;
247    }
248    }
249    else
250    {
251    // debug
252    // System.err.println("Outwith bounds!" + matchStart+">"+end +" or "
253    // + matchEnd+"<"+start);
254    }
255    }
256    }
257  48 return result;
258    }
259   
 
260  8 toggle @Override
261    public int markColumns(SequenceCollectionI sqcol, BitSet bs)
262    {
263  8 int count = 0;
264  8 BitSet mask = new BitSet();
265  8 int startRes = sqcol.getStartRes();
266  8 int endRes = sqcol.getEndRes();
267   
268  8 for (SequenceI s : sqcol.getSequences())
269    {
270  27 int[] cols = getResults(s, startRes, endRes);
271  27 if (cols != null)
272    {
273  24 for (int pair = 0; pair < cols.length; pair += 2)
274    {
275  12 mask.set(cols[pair], cols[pair + 1] + 1);
276    }
277    }
278    }
279    // compute columns that were newly selected
280  8 BitSet original = (BitSet) bs.clone();
281  8 original.and(mask);
282  8 count = mask.cardinality() - original.cardinality();
283    // and mark ranges not already marked
284  8 bs.or(mask);
285  8 return count;
286    }
287   
 
288  29 toggle @Override
289    public int getSize()
290    {
291  29 return matches.size();
292    }
293   
 
294  443 toggle @Override
295    public boolean isEmpty()
296    {
297  443 return matches.isEmpty();
298    }
299   
 
300  254 toggle @Override
301    public List<SearchResultMatchI> getResults()
302    {
303  254 return matches;
304    }
305   
306    /**
307    * Return the results as a list of matches [seq1/from-to, seq2/from-to, ...]
308    *
309    * @return
310    */
 
311  3 toggle @Override
312    public String toString()
313    {
314  3 return matches == null ? "" : matches.toString();
315    }
316   
317    /**
318    * Hashcode is derived from the list of matches. This ensures that when two
319    * SearchResults objects satisfy the test for equals(), then they have the
320    * same hashcode.
321    *
322    * @see Match#hashCode()
323    * @see java.util.AbstractList#hashCode()
324    */
 
325  6 toggle @Override
326    public int hashCode()
327    {
328  6 return matches.hashCode();
329    }
330   
331    /**
332    * Two SearchResults are considered equal if they contain the same matches in
333    * the same order.
334    */
 
335  35 toggle @Override
336    public boolean equals(Object obj)
337    {
338  35 if (obj == null || !(obj instanceof SearchResultsI))
339    {
340  6 return false;
341    }
342  29 SearchResultsI sr = (SearchResultsI) obj;
343  29 return matches.equals(sr.getResults());
344    }
345   
 
346  0 toggle @Override
347    public void addSearchResults(SearchResultsI toAdd)
348    {
349  0 matches.addAll(toAdd.getResults());
350    }
351    }