{
/**
+ * 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
*
* 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<SequenceFeature> features,
+ public boolean listContains(List<SequenceFeature> 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<SequenceFeature> 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;
}
/**
@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;
+ }
}
/*
/**
* 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
{
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);
}
}
- boolean removedNonPositional = false;
-
/*
* if not found, try non-positional features
*/
if (!removed && nonPositionalFeatures != null)
{
- removedNonPositional = nonPositionalFeatures.remove(sf);
- removed = removedNonPositional;
+ removed = nonPositionalFeatures.remove(sf);
}
/*
*/
if (!removed && features != null)
{
- removed = features.remove(sf);
+ removed = findAndRemoveNonContactFeature(sf);
}
if (removed)
return removed;
}
+ abstract protected boolean findAndRemoveNonContactFeature(SequenceFeature sf);
+
abstract protected void findContactFeatures(long from, long to,
List<SequenceFeature> result);
*/
if (nonPositionalFeatures != null)
{
- for (SequenceFeature sf : nonPositionalFeatures)
+ List<SequenceFeature> 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);
* (Although a simple shift of all values would preserve data integrity!)
*/
boolean modified = false;
- for (SequenceFeature sf : getPositionalFeatures())
+ List<SequenceFeature> list = getPositionalFeatures();
+ for (int i = 0, n = list.size(); i < n; i++)
{
+ SequenceFeature sf = list.get(i);
if (sf.getBegin() >= fromPosition)
{
modified = true;