• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.databinding.tool.expr;
18 
19 import org.antlr.v4.runtime.misc.Nullable;
20 
21 import android.databinding.tool.processing.ErrorMessages;
22 import android.databinding.tool.processing.Scope;
23 import android.databinding.tool.processing.scopes.LocationScopeProvider;
24 import android.databinding.tool.reflection.ModelAnalyzer;
25 import android.databinding.tool.reflection.ModelClass;
26 import android.databinding.tool.store.Location;
27 import android.databinding.tool.util.L;
28 import android.databinding.tool.util.Preconditions;
29 import android.databinding.tool.writer.KCode;
30 import android.databinding.tool.writer.LayoutBinderWriterKt;
31 
32 import java.util.ArrayList;
33 import java.util.BitSet;
34 import java.util.Collections;
35 import java.util.List;
36 import java.util.Map;
37 
38 abstract public class Expr implements VersionProvider, LocationScopeProvider {
39 
40     public static final int NO_ID = -1;
41     protected List<Expr> mChildren = new ArrayList<Expr>();
42 
43     // any expression that refers to this. Useful if this expr is duplicate and being replaced
44     private List<Expr> mParents = new ArrayList<Expr>();
45 
46     private Boolean mIsDynamic;
47 
48     private ModelClass mResolvedType;
49 
50     private String mUniqueKey;
51 
52     private List<Dependency> mDependencies;
53 
54     private List<Dependency> mDependants = new ArrayList<Dependency>();
55 
56     private int mId = NO_ID;
57 
58     private int mRequirementId = NO_ID;
59 
60     private int mVersion = 0;
61 
62     // means this expression can directly be invalidated by the user
63     private boolean mCanBeInvalidated = false;
64 
65     @Nullable
66     private List<Location> mLocations = new ArrayList<Location>();
67 
68     /**
69      * This set denotes the times when this expression is invalid.
70      * If it is an Identifier expression, it is its index
71      * If it is a composite expression, it is the union of invalid flags of its descendants
72      */
73     private BitSet mInvalidFlags;
74 
75     /**
76      * Set when this expression is registered to a model
77      */
78     private ExprModel mModel;
79 
80     /**
81      * This set denotes the times when this expression must be read.
82      *
83      * It is the union of invalidation flags of all of its non-conditional dependants.
84      */
85     BitSet mShouldReadFlags;
86 
87     BitSet mReadSoFar = new BitSet();// i've read this variable for these flags
88 
89     /**
90      * calculated on initialization, assuming all conditionals are true
91      */
92     BitSet mShouldReadWithConditionals;
93 
94     private boolean mIsBindingExpression;
95 
96     /**
97      * Used by generators when this expression is resolved.
98      */
99     private boolean mRead;
100     private boolean mIsUsed = false;
101     private boolean mIsTwoWay = false;
102 
Expr(Iterable<Expr> children)103     Expr(Iterable<Expr> children) {
104         for (Expr expr : children) {
105             mChildren.add(expr);
106         }
107         addParents();
108     }
109 
Expr(Expr... children)110     Expr(Expr... children) {
111         Collections.addAll(mChildren, children);
112         addParents();
113     }
114 
getId()115     public int getId() {
116         Preconditions.check(mId != NO_ID, "if getId is called on an expression, it should have"
117                 + " an id: %s", this);
118         return mId;
119     }
120 
setId(int id)121     public void setId(int id) {
122         Preconditions.check(mId == NO_ID, "ID is already set on %s", this);
123         mId = id;
124     }
125 
addLocation(Location location)126     public void addLocation(Location location) {
127         mLocations.add(location);
128     }
129 
getLocations()130     public List<Location> getLocations() {
131         return mLocations;
132     }
133 
getModel()134     public ExprModel getModel() {
135         return mModel;
136     }
137 
getInvalidFlags()138     public BitSet getInvalidFlags() {
139         if (mInvalidFlags == null) {
140             mInvalidFlags = resolveInvalidFlags();
141         }
142         return mInvalidFlags;
143     }
144 
resolveInvalidFlags()145     private BitSet resolveInvalidFlags() {
146         BitSet bitSet = (BitSet) mModel.getInvalidateAnyBitSet().clone();
147         if (mCanBeInvalidated) {
148             bitSet.set(getId(), true);
149         }
150         for (Dependency dependency : getDependencies()) {
151             // TODO optional optimization: do not invalidate for conditional flags
152             bitSet.or(dependency.getOther().getInvalidFlags());
153         }
154         return bitSet;
155     }
156 
setBindingExpression(boolean isBindingExpression)157     public void setBindingExpression(boolean isBindingExpression) {
158         mIsBindingExpression = isBindingExpression;
159     }
160 
isBindingExpression()161     public boolean isBindingExpression() {
162         return mIsBindingExpression;
163     }
164 
canBeEvaluatedToAVariable()165     public boolean canBeEvaluatedToAVariable() {
166         return true; // anything except arg expr can be evaluated to a variable
167     }
168 
isObservable()169     public boolean isObservable() {
170         return getResolvedType().isObservable();
171     }
172 
resolveListeners(ModelClass valueType, Expr parent)173     public Expr resolveListeners(ModelClass valueType, Expr parent) {
174         for (int i = mChildren.size() - 1; i >= 0; i--) {
175             Expr child = mChildren.get(i);
176             child.resolveListeners(valueType, this);
177         }
178         resetResolvedType();
179         return this;
180     }
181 
resolveTwoWayExpressions(Expr parent)182     public Expr resolveTwoWayExpressions(Expr parent) {
183         for (int i = mChildren.size() - 1; i >= 0; i--) {
184             final Expr child = mChildren.get(i);
185             child.resolveTwoWayExpressions(this);
186         }
187         return this;
188     }
189 
resetResolvedType()190     protected void resetResolvedType() {
191         mResolvedType = null;
192     }
193 
getShouldReadFlags()194     public BitSet getShouldReadFlags() {
195         if (mShouldReadFlags == null) {
196             getShouldReadFlagsWithConditionals();
197             mShouldReadFlags = resolveShouldReadFlags();
198         }
199         return mShouldReadFlags;
200     }
201 
getShouldReadFlagsWithConditionals()202     public BitSet getShouldReadFlagsWithConditionals() {
203         if (mShouldReadWithConditionals == null) {
204             mShouldReadWithConditionals = resolveShouldReadWithConditionals();
205         }
206         return mShouldReadWithConditionals;
207     }
208 
setModel(ExprModel model)209     public void setModel(ExprModel model) {
210         mModel = model;
211     }
212 
setTwoWay(boolean isTwoWay)213     public void setTwoWay(boolean isTwoWay) {
214         mIsTwoWay = isTwoWay;
215     }
216 
isTwoWay()217     public boolean isTwoWay() {
218         return mIsTwoWay;
219     }
220 
addTwoWay(String uniqueKey)221     protected String addTwoWay(String uniqueKey) {
222         if (mIsTwoWay) {
223             return "twoWay(" + uniqueKey + ")";
224         } else {
225             return "oneWay(" + uniqueKey + ")";
226         }
227     }
228 
resolveShouldReadWithConditionals()229     private BitSet resolveShouldReadWithConditionals() {
230         // ensure we have invalid flags
231         BitSet bitSet = new BitSet();
232         // if i'm invalid, that DOES NOT mean i should be read :/.
233         if (mIsBindingExpression) {
234             bitSet.or(getInvalidFlags());
235         }
236 
237         for (Dependency dependency : getDependants()) {
238             if (dependency.getCondition() == null) {
239                 bitSet.or(dependency.getDependant().getShouldReadFlagsWithConditionals());
240             } else {
241                 bitSet.set(dependency.getDependant()
242                         .getRequirementFlagIndex(dependency.getExpectedOutput()));
243             }
244         }
245         return bitSet;
246     }
247 
resolveShouldReadFlags()248     private BitSet resolveShouldReadFlags() {
249         // ensure we have invalid flags
250         BitSet bitSet = new BitSet();
251         if (isRead()) {
252             return bitSet;
253         }
254         if (mIsBindingExpression) {
255             bitSet.or(getInvalidFlags());
256         }
257         for (Dependency dependency : getDependants()) {
258             final boolean isUnreadElevated = isUnreadElevated(dependency);
259             if (dependency.isConditional()) {
260                 continue; // will be resolved later when conditional is elevated
261             }
262             if (isUnreadElevated) {
263                 bitSet.set(dependency.getDependant()
264                         .getRequirementFlagIndex(dependency.getExpectedOutput()));
265             } else {
266                 bitSet.or(dependency.getDependant().getShouldReadFlags());
267             }
268         }
269         bitSet.and(mShouldReadWithConditionals);
270         bitSet.andNot(mReadSoFar);
271         return bitSet;
272     }
273 
isUnreadElevated(Dependency input)274     private static boolean isUnreadElevated(Dependency input) {
275         return input.isElevated() && !input.getDependant().isRead();
276     }
addParents()277     private void addParents() {
278         for (Expr expr : mChildren) {
279             expr.mParents.add(this);
280         }
281     }
282 
onSwappedWith(Expr existing)283     public void onSwappedWith(Expr existing) {
284         for (Expr child : mChildren) {
285             child.onParentSwapped(this, existing);
286         }
287     }
288 
onParentSwapped(Expr oldParent, Expr newParent)289     private void onParentSwapped(Expr oldParent, Expr newParent) {
290         Preconditions.check(mParents.remove(oldParent), "trying to remove non-existent parent %s"
291                 + " from %s", oldParent, mParents);
292         mParents.add(newParent);
293     }
294 
getChildren()295     public List<Expr> getChildren() {
296         return mChildren;
297     }
298 
getParents()299     public List<Expr> getParents() {
300         return mParents;
301     }
302 
303     /**
304      * Whether the result of this expression can change or not.
305      *
306      * For example, 3 + 5 can not change vs 3 + x may change.
307      *
308      * Default implementations checks children and returns true if any of them returns true
309      *
310      * @return True if the result of this expression may change due to variables
311      */
isDynamic()312     public boolean isDynamic() {
313         if (mIsDynamic == null) {
314             mIsDynamic = isAnyChildDynamic();
315         }
316         return mIsDynamic;
317     }
318 
isAnyChildDynamic()319     private boolean isAnyChildDynamic() {
320         for (Expr expr : mChildren) {
321             if (expr.isDynamic()) {
322                 return true;
323             }
324         }
325         return false;
326     }
327 
getResolvedType()328     public ModelClass getResolvedType() {
329         if (mResolvedType == null) {
330             // TODO not get instance
331             try {
332                 Scope.enter(this);
333                 mResolvedType = resolveType(ModelAnalyzer.getInstance());
334                 if (mResolvedType == null) {
335                     L.e(ErrorMessages.CANNOT_RESOLVE_TYPE, this);
336                 }
337             } finally {
338                 Scope.exit();
339             }
340         }
341         return mResolvedType;
342     }
343 
resolveType(ModelAnalyzer modelAnalyzer)344     abstract protected ModelClass resolveType(ModelAnalyzer modelAnalyzer);
345 
constructDependencies()346     abstract protected List<Dependency> constructDependencies();
347 
348     /**
349      * Creates a dependency for each dynamic child. Should work for any expression besides
350      * conditionals.
351      */
constructDynamicChildrenDependencies()352     protected List<Dependency> constructDynamicChildrenDependencies() {
353         List<Dependency> dependencies = new ArrayList<Dependency>();
354         for (Expr node : mChildren) {
355             if (!node.isDynamic()) {
356                 continue;
357             }
358             dependencies.add(new Dependency(this, node));
359         }
360         return dependencies;
361     }
362 
getDependencies()363     public final List<Dependency> getDependencies() {
364         if (mDependencies == null) {
365             mDependencies = constructDependencies();
366         }
367         return mDependencies;
368     }
369 
addDependant(Dependency dependency)370     void addDependant(Dependency dependency) {
371         mDependants.add(dependency);
372     }
373 
getDependants()374     public List<Dependency> getDependants() {
375         return mDependants;
376     }
377 
378     protected static final String KEY_JOIN = "~";
379 
380     /**
381      * Returns a unique string key that can identify this expression.
382      *
383      * It must take into account any dependencies
384      *
385      * @return A unique identifier for this expression
386      */
getUniqueKey()387     public final String getUniqueKey() {
388         if (mUniqueKey == null) {
389             mUniqueKey = computeUniqueKey();
390             Preconditions.checkNotNull(mUniqueKey,
391                     "if there are no children, you must override computeUniqueKey");
392             Preconditions.check(!mUniqueKey.trim().equals(""),
393                     "if there are no children, you must override computeUniqueKey");
394         }
395         return mUniqueKey;
396     }
397 
computeUniqueKey()398     protected String computeUniqueKey() {
399         return computeChildrenKey();
400     }
401 
computeChildrenKey()402     protected final String computeChildrenKey() {
403         return join(mChildren);
404     }
405 
enableDirectInvalidation()406     public void enableDirectInvalidation() {
407         mCanBeInvalidated = true;
408     }
409 
canBeInvalidated()410     public boolean canBeInvalidated() {
411         return mCanBeInvalidated;
412     }
413 
trimShouldReadFlags(BitSet bitSet)414     public void trimShouldReadFlags(BitSet bitSet) {
415         mShouldReadFlags.andNot(bitSet);
416     }
417 
isConditional()418     public boolean isConditional() {
419         return false;
420     }
421 
getRequirementId()422     public int getRequirementId() {
423         return mRequirementId;
424     }
425 
setRequirementId(int requirementId)426     public void setRequirementId(int requirementId) {
427         mRequirementId = requirementId;
428     }
429 
430     /**
431      * This is called w/ a dependency of mine.
432      * Base method should thr
433      */
getRequirementFlagIndex(boolean expectedOutput)434     public int getRequirementFlagIndex(boolean expectedOutput) {
435         Preconditions.check(mRequirementId != NO_ID, "If this is an expression w/ conditional"
436                 + " dependencies, it must be assigned a requirement ID. %s", this);
437         return expectedOutput ? mRequirementId + 1 : mRequirementId;
438     }
439 
hasId()440     public boolean hasId() {
441         return mId != NO_ID;
442     }
443 
markFlagsAsRead(BitSet flags)444     public void markFlagsAsRead(BitSet flags) {
445         mReadSoFar.or(flags);
446     }
447 
isRead()448     public boolean isRead() {
449         return mRead;
450     }
451 
considerElevatingConditionals(Expr justRead)452     public boolean considerElevatingConditionals(Expr justRead) {
453         boolean elevated = false;
454         for (Dependency dependency : mDependencies) {
455             if (dependency.isConditional() && dependency.getCondition() == justRead) {
456                 dependency.elevate();
457                 elevated = true;
458             }
459         }
460         return elevated;
461     }
462 
invalidateReadFlags()463     public void invalidateReadFlags() {
464         mShouldReadFlags = null;
465         mVersion ++;
466     }
467 
468     @Override
getVersion()469     public int getVersion() {
470         return mVersion;
471     }
472 
hasNestedCannotRead()473     public boolean hasNestedCannotRead() {
474         if (isRead()) {
475             return false;
476         }
477         if (getShouldReadFlags().isEmpty()) {
478             return true;
479         }
480         for (Dependency dependency : getDependencies()) {
481             if (hasNestedCannotRead(dependency)) {
482                 return true;
483             }
484         }
485         return false;
486     }
487 
hasNestedCannotRead(Dependency input)488     private static boolean hasNestedCannotRead(Dependency input) {
489         return input.isConditional() || input.getOther().hasNestedCannotRead();
490     }
491 
markAsReadIfDone()492     public boolean markAsReadIfDone() {
493         if (mRead) {
494             return false;
495         }
496         // TODO avoid clone, we can calculate this iteratively
497         BitSet clone = (BitSet) mShouldReadWithConditionals.clone();
498 
499         clone.andNot(mReadSoFar);
500         mRead = clone.isEmpty();
501 
502         if (!mRead && !mReadSoFar.isEmpty()) {
503             // check if remaining dependencies can be satisfied w/ existing values
504             // for predicate flags, this expr may already be calculated to get the predicate
505             // to detect them, traverse them later on, see which flags should be calculated to calculate
506             // them. If any of them is completely covered w/ our non-conditional flags, no reason
507             // to add them to the list since we'll already be calculated due to our non-conditional
508             // flags
509             boolean allCovered = true;
510             for (int i = clone.nextSetBit(0); i != -1; i = clone.nextSetBit(i + 1)) {
511                 final Expr expr = mModel.findFlagExpression(i);
512                 if (expr == null) {
513                     continue;
514                 }
515                 if (!expr.isConditional()) {
516                     allCovered = false;
517                     break;
518                 }
519                 final BitSet readForConditional = (BitSet) expr.findConditionalFlags().clone();
520 
521                 // FIXME: this does not do full traversal so misses some cases
522                 // to calculate that conditional, i should've read /readForConditional/ flags
523                 // if my read-so-far bits cover that; that means i would've already
524                 // read myself
525                 readForConditional.andNot(mReadSoFar);
526                 if (!readForConditional.isEmpty()) {
527                     allCovered = false;
528                     break;
529                 }
530             }
531             mRead = allCovered;
532         }
533         if (mRead) {
534             mShouldReadFlags = null; // if we've been marked as read, clear should read flags
535         }
536         return mRead;
537     }
538 
539     BitSet mConditionalFlags;
540 
findConditionalFlags()541     private BitSet findConditionalFlags() {
542         Preconditions.check(isConditional(), "should not call this on a non-conditional expr");
543         if (mConditionalFlags == null) {
544             mConditionalFlags = new BitSet();
545             resolveConditionalFlags(mConditionalFlags);
546         }
547         return mConditionalFlags;
548     }
549 
resolveConditionalFlags(BitSet flags)550     private void resolveConditionalFlags(BitSet flags) {
551         flags.or(getPredicateInvalidFlags());
552         // if i have only 1 dependency which is conditional, traverse it as well
553         if (getDependants().size() == 1) {
554             final Dependency dependency = getDependants().get(0);
555             if (dependency.getCondition() != null) {
556                 flags.or(dependency.getDependant().findConditionalFlags());
557                 flags.set(dependency.getDependant()
558                         .getRequirementFlagIndex(dependency.getExpectedOutput()));
559             }
560         }
561     }
562 
563 
564     @Override
toString()565     public String toString() {
566         return getUniqueKey();
567     }
568 
getReadSoFar()569     public BitSet getReadSoFar() {
570         return mReadSoFar;
571     }
572 
573     private Node mCalculationPaths = null;
574 
575     /**
576      * All flag paths that will result in calculation of this expression.
577      */
getAllCalculationPaths()578     protected Node getAllCalculationPaths() {
579         if (mCalculationPaths == null) {
580             Node node = new Node();
581             if (isConditional()) {
582                 node.mBitSet.or(getPredicateInvalidFlags());
583             } else {
584                 node.mBitSet.or(getInvalidFlags());
585             }
586             for (Dependency dependency : getDependants()) {
587                 final Expr dependant = dependency.getDependant();
588                 if (dependency.getCondition() != null) {
589                     Node cond = new Node();
590                     cond.setConditionFlag(
591                             dependant.getRequirementFlagIndex(dependency.getExpectedOutput()));
592                     cond.mParents.add(dependant.getAllCalculationPaths());
593                     node.mParents.add(cond);
594                 } else {
595                     node.mParents.add(dependant.getAllCalculationPaths());
596                 }
597             }
598             mCalculationPaths = node;
599         }
600         return mCalculationPaths;
601     }
602 
getDefaultValue()603     public String getDefaultValue() {
604         return ModelAnalyzer.getInstance().getDefaultValue(getResolvedType().toJavaCode());
605     }
606 
getPredicateInvalidFlags()607     protected BitSet getPredicateInvalidFlags() {
608         throw new IllegalStateException(
609                 "must override getPredicateInvalidFlags in " + getClass().getSimpleName());
610     }
611 
612     /**
613      * Used by code generation
614      */
shouldReadNow(final List<Expr> justRead)615     public boolean shouldReadNow(final List<Expr> justRead) {
616         if (getShouldReadFlags().isEmpty()) {
617             return false;
618         }
619         for (Dependency input : getDependencies()) {
620             boolean dependencyReady = input.getOther().isRead() || (justRead != null &&
621                     justRead.contains(input.getOther()));
622             if(!dependencyReady) {
623                 return false;
624             }
625         }
626         return true;
627     }
628 
isEqualityCheck()629     public boolean isEqualityCheck() {
630         return false;
631     }
632 
setIsUsed(boolean isUsed)633     public void setIsUsed(boolean isUsed) {
634         mIsUsed = isUsed;
635         for (Expr child : getChildren()) {
636             child.setIsUsed(isUsed);
637         }
638     }
639 
isUsed()640     public boolean isUsed() {
641         return mIsUsed;
642     }
643 
updateExpr(ModelAnalyzer modelAnalyzer)644     public void updateExpr(ModelAnalyzer modelAnalyzer) {
645         final Map<String, Expr> exprMap = mModel.getExprMap();
646         for (int i = mParents.size() - 1; i >= 0; i--) {
647             final Expr parent = mParents.get(i);
648             if (exprMap.get(parent.getUniqueKey()) != parent) {
649                 mParents.remove(i);
650             }
651         }
652         for (Expr child : mChildren) {
653             child.updateExpr(modelAnalyzer);
654         }
655     }
656 
join(String... items)657     protected static String join(String... items) {
658         StringBuilder result = new StringBuilder();
659         for (int i = 0; i < items.length; i ++) {
660             if (i > 0) {
661                 result.append(KEY_JOIN);
662             }
663             result.append(items[i]);
664         }
665         return result.toString();
666     }
667 
join(List<Expr> items)668     protected static String join(List<Expr> items) {
669         StringBuilder result = new StringBuilder();
670         for (int i = 0; i < items.size(); i ++) {
671             if (i > 0) {
672                 result.append(KEY_JOIN);
673             }
674             result.append(items.get(i).getUniqueKey());
675         }
676         return result.toString();
677     }
678 
asPackage()679     protected String asPackage() {
680         return null;
681     }
682 
683     @Override
provideScopeLocation()684     public List<Location> provideScopeLocation() {
685         return mLocations;
686     }
687 
toCode()688     public KCode toCode() {
689         return toCode(false);
690     }
691 
toCode(boolean expand)692     protected KCode toCode(boolean expand) {
693         if (!expand && isDynamic()) {
694             return new KCode(LayoutBinderWriterKt.getExecutePendingLocalName(this));
695         }
696         return generateCode(expand);
697     }
698 
toFullCode()699     public KCode toFullCode() {
700         return generateCode(false);
701     }
702 
generateCode(boolean expand)703     protected abstract KCode generateCode(boolean expand);
704 
toInverseCode(KCode value)705     public KCode toInverseCode(KCode value) {
706         throw new IllegalStateException("expression does not support two-way binding");
707     }
708 
assertIsInvertible()709     public void assertIsInvertible() {
710         final String errorMessage = getInvertibleError();
711         if (errorMessage != null) {
712             L.e(ErrorMessages.EXPRESSION_NOT_INVERTIBLE, toFullCode().generate(),
713                     errorMessage);
714         }
715     }
716 
717     /**
718      * @return The reason the expression wasn't invertible or null if it was invertible.
719      */
getInvertibleError()720     protected abstract String getInvertibleError();
721 
722     /**
723      * This expression is the predicate for 1 or more ternary expressions.
724      */
hasConditionalDependant()725     public boolean hasConditionalDependant() {
726         for (Dependency dependency : getDependants()) {
727             Expr dependant = dependency.getDependant();
728             if (dependant.isConditional() && dependant instanceof TernaryExpr) {
729                 TernaryExpr ternary = (TernaryExpr) dependant;
730                 return ternary.getPred() == this;
731             }
732         }
733         return false;
734     }
735 
736     static class Node {
737 
738         BitSet mBitSet = new BitSet();
739         List<Node> mParents = new ArrayList<Node>();
740         int mConditionFlag = -1;
741 
areAllPathsSatisfied(BitSet readSoFar)742         public boolean areAllPathsSatisfied(BitSet readSoFar) {
743             if (mConditionFlag != -1) {
744                 return readSoFar.get(mConditionFlag)
745                         || mParents.get(0).areAllPathsSatisfied(readSoFar);
746             } else {
747                 final BitSet myBitsClone = (BitSet) mBitSet.clone();
748                 myBitsClone.andNot(readSoFar);
749                 if (!myBitsClone.isEmpty()) {
750                     // read so far does not cover all of my invalidation. The only way I could be
751                     // covered is that I only have 1 conditional dependent which is covered by this.
752                     if (mParents.size() == 1 && mParents.get(0).mConditionFlag != -1) {
753                         return mParents.get(0).areAllPathsSatisfied(readSoFar);
754                     }
755                     return false;
756                 }
757                 if (mParents.isEmpty()) {
758                     return true;
759                 }
760                 for (Node parent : mParents) {
761                     if (!parent.areAllPathsSatisfied(readSoFar)) {
762                         return false;
763                     }
764                 }
765                 return true;
766             }
767         }
768 
setConditionFlag(int requirementFlagIndex)769         public void setConditionFlag(int requirementFlagIndex) {
770             mConditionFlag = requirementFlagIndex;
771         }
772     }
773 }
774