X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fdatamodel%2Ffeatures%2FFeatureStore.java;h=1451892985f1f26d63e2c1693e41d8e0c9a66e2c;hb=28e9024f09a78a9625ed4defa2012bf342bec51e;hp=ccd8b66af9774e88b13d58b6720b3f6feb91484a;hpb=8406f2ced29d2c04dbabaf1cde80b1a7fa8ce8ce;p=jalview.git diff --git a/src/jalview/datamodel/features/FeatureStore.java b/src/jalview/datamodel/features/FeatureStore.java index ccd8b66..1451892 100644 --- a/src/jalview/datamodel/features/FeatureStore.java +++ b/src/jalview/datamodel/features/FeatureStore.java @@ -33,6 +33,11 @@ public abstract class FeatureStore implements FeatureStoreI { /** + * track last start for quick insertion of ordered features + */ + protected int lastStart = -1, lastContactStart = -1; + + /** * Answers the 'length' of the feature, counting 0 for non-positional features * and 1 for contact features * @@ -57,38 +62,53 @@ public abstract class FeatureStore implements FeatureStoreI * optimised for the condition that the list is sorted on feature start * position ascending, and will give unreliable results if this does not hold. * - * @param features + * @param list * @param feature * @return */ @Override - public boolean listContains(List features, + public boolean listContains(List list, SequenceFeature feature) { - if (features == null || feature == null) + if (list == null || feature == null) { return false; } + return (getEquivalentFeatureIndex(list, feature) >= 0); + } + + /** + * Binary search for the index (>= 0) of a feature in a list. + * + * @param list + * @param feature + * @return index if found; -1 if not + */ + protected int getEquivalentFeatureIndex(List list, + SequenceFeature feature) + { + /* * locate the first entry in the list which does not precede the feature */ - int pos = findFirstBegin(features, feature.begin); - int len = features.size(); + int begin = feature.begin; + int pos = findFirstBegin(list, begin); + int len = list.size(); while (pos < len) { - SequenceFeature sf = features.get(pos); - if (sf.getBegin() > feature.getBegin()) + SequenceFeature sf = list.get(pos); + if (sf.begin > begin) { - return false; // no match found + return -1; // no match found } if (sf.equals(feature)) { - return true; + return pos; } pos++; } - return false; + return -1; } /** @@ -239,30 +259,55 @@ public abstract class FeatureStore implements FeatureStoreI @Override public boolean addFeature(SequenceFeature feature) { - if (contains(feature)) - { - return false; - } - - /* - * keep a record of feature groups - */ - if (!feature.isNonPositional()) - { - positionalFeatureGroups.add(feature.getFeatureGroup()); - } + // if (contains(feature)) + // { + // return false; + // } + + // /* + // * keep a record of feature groups + // */ + // if (!feature.isNonPositional()) + // { + // positionalFeatureGroups.add(feature.getFeatureGroup()); + // } if (feature.isContactFeature()) { + if (containsContactFeature(feature)) + { + return false; + } + positionalFeatureGroups.add(feature.getFeatureGroup()); + if (feature.begin > lastContactStart) + { + lastContactStart = feature.begin; + } addContactFeature(feature); } else if (feature.isNonPositional()) { + if (containsNonPositional(feature)) + { + return false; + } + addNonPositionalFeature(feature); } else { - addNestedFeature(feature); + // allow for check with + if (checkContainsPositionalFeatureForAdd(feature) + || !addPositionalFeature(feature)) + { + return false; + } + positionalFeatureGroups.add(feature.getFeatureGroup()); + // addPositionalFeature(feature); + if (feature.begin > lastStart) + { + lastStart = feature.begin; + } } /* @@ -315,8 +360,10 @@ public abstract class FeatureStore implements FeatureStoreI /** * Adds one feature to the IntervalStore that can manage nested features * (creating the IntervalStore if necessary) + * + * @return true if added -- allowing for late checking during addition */ - abstract protected void addNestedFeature(SequenceFeature feature); + abstract protected boolean addPositionalFeature(SequenceFeature feature); /** * Adds the feature to the list of non-positional features (with lazy @@ -353,19 +400,50 @@ public abstract class FeatureStore implements FeatureStoreI { if (feature.isNonPositional()) { - return nonPositionalFeatures == null ? false - : nonPositionalFeatures.contains(feature); + return containsNonPositional(feature); + } if (feature.isContactFeature()) { - return contactFeatureStarts != null - && listContains(contactFeatureStarts, feature); + return containsContactFeature(feature); + } - return features == null ? false : containsFeature(feature); + return containsPositionalFeature(feature); + + } + + /** + * A check that can be overridden if the check is being done during the add + * operation itself. + * + * @param feature + * @return + */ + protected boolean checkContainsPositionalFeatureForAdd( + SequenceFeature feature) + { + return containsPositionalFeature(feature); + } + + private boolean containsPositionalFeature(SequenceFeature feature) + { + return features == null || feature.begin > lastStart ? false + : containsFeature(feature); + } + + private boolean containsContactFeature(SequenceFeature feature) + { + return contactFeatureStarts != null && feature.begin <= lastContactStart + && listContains(contactFeatureStarts, feature); } + private boolean containsNonPositional(SequenceFeature feature) + { + return nonPositionalFeatures == null ? false + : nonPositionalFeatures.contains(feature); + } abstract protected boolean containsFeature(SequenceFeature feature); @@ -396,15 +474,12 @@ public abstract class FeatureStore implements FeatureStoreI } } - boolean removedNonPositional = false; - /* * if not found, try non-positional features */ if (!removed && nonPositionalFeatures != null) { - removedNonPositional = nonPositionalFeatures.remove(sf); - removed = removedNonPositional; + removed = nonPositionalFeatures.remove(sf); } /* @@ -412,7 +487,7 @@ public abstract class FeatureStore implements FeatureStoreI */ if (!removed && features != null) { - removed = features.remove(sf); + removed = findAndRemoveNonContactFeature(sf); } if (removed) @@ -423,6 +498,8 @@ public abstract class FeatureStore implements FeatureStoreI return removed; } + abstract protected boolean findAndRemoveNonContactFeature(SequenceFeature sf); + abstract protected void findContactFeatures(long from, long to, List result); @@ -690,8 +767,10 @@ public abstract class FeatureStore implements FeatureStoreI */ if (nonPositionalFeatures != null) { - for (SequenceFeature sf : nonPositionalFeatures) + List list = nonPositionalFeatures; + for (int i = 0, n = list.size(); i < n; i++) { + SequenceFeature sf = list.get(i); nonPositionalFeatureGroups.add(sf.getFeatureGroup()); float score = sf.getScore(); nonPositionalMinScore = min(nonPositionalMinScore, score); @@ -742,8 +821,10 @@ public abstract class FeatureStore implements FeatureStoreI * (Although a simple shift of all values would preserve data integrity!) */ boolean modified = false; - for (SequenceFeature sf : getPositionalFeatures()) + List list = getPositionalFeatures(); + for (int i = 0, n = list.size(); i < n; i++) { + SequenceFeature sf = list.get(i); if (sf.getBegin() >= fromPosition) { modified = true;