aboutsummaryrefslogtreecommitdiffstats
path: root/src/core/logic/RBAConstraintInfo.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/logic/RBAConstraintInfo.cpp')
-rw-r--r--src/core/logic/RBAConstraintInfo.cpp695
1 files changed, 695 insertions, 0 deletions
diff --git a/src/core/logic/RBAConstraintInfo.cpp b/src/core/logic/RBAConstraintInfo.cpp
new file mode 100644
index 0000000..b208c5f
--- /dev/null
+++ b/src/core/logic/RBAConstraintInfo.cpp
@@ -0,0 +1,695 @@
+/**
+ * Copyright (c) 2019 DENSO CORPORATION.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/// ConstraintInfo class
+
+#include <algorithm>
+#include "RBAAllocatable.hpp"
+#include "RBAConstraintInfo.hpp"
+#include "RBAExpression.hpp"
+#include "RBAModelElementType.hpp"
+
+namespace rba
+{
+
+void RBAConstraintInfo::setExpression(const RBAExpression* const expression)
+{
+ expression_ = expression;
+}
+
+const RBAExpression*
+RBAConstraintInfo::getExpression() const
+{
+ return expression_;
+}
+
+void RBAConstraintInfo::addOperandAllocatable(const RBAAllocatable* const operandAllocatable)
+{
+ static_cast<void>(operandAllocatable_.insert(operandAllocatable));
+}
+
+void RBAConstraintInfo::setResult(const RBAExecuteResult result)
+{
+ result_ = result;
+}
+
+RBAConstraintInfo*
+RBAConstraintInfo::getChild(const std::uint32_t index) const
+{
+ const std::size_t requiredSize {static_cast<std::size_t>(index + 1U)};
+ if (children_.size() < requiredSize) {
+ children_.resize(requiredSize, std::make_unique<RBAConstraintInfo>());
+ }
+ // Use "[]" instead of "at" because it doesn't access out of range
+ return children_[static_cast<std::size_t>(index)].get();
+}
+
+void RBAConstraintInfo::setChild(const std::shared_ptr<RBAConstraintInfo> info)
+{
+ // This function is used in "let" expressions, which generate a new
+ // "ConstraintInfo" on each evaluation.
+ // Therefore, in the case of "add", "children" will be added for each arbitration,
+ // so use "set" to set "children" for each arbitration.
+ children_ = { info };
+}
+
+void RBAConstraintInfo::addTrueAllocatable(const RBAAllocatable* const allocatable)
+{
+ static_cast<void>(trueAllocatables_.insert(allocatable));
+}
+
+void RBAConstraintInfo::addFalseAllocatable(const RBAAllocatable* const allocatable)
+{
+ static_cast<void>(falseAllocatables_.insert(allocatable));
+}
+
+void RBAConstraintInfo::addTrueAllocatableFromOperand()
+{
+ for (const auto& c : children_) {
+ for (const auto& a : c->operandAllocatable_) {
+ static_cast<void>(trueAllocatables_.insert(a));
+ }
+ }
+}
+
+void RBAConstraintInfo::addFalseAllocatableFromOperand()
+{
+ for (const auto& c : children_) {
+ for (const auto& a : c->operandAllocatable_) {
+ static_cast<void>(falseAllocatables_.insert(a));
+ }
+ }
+}
+
+void RBAConstraintInfo::clearFalseAllocatable()
+{
+ falseAllocatables_.clear();
+}
+
+/// TCheck whether to invert True/False
+/// @return
+bool RBAConstraintInfo::isRevert() const
+{
+ if ((expression_ != nullptr)
+ && expression_->isModelElementType(RBAModelElementType::NotOperator)) {
+ return true;
+ }
+ return false;
+}
+
+bool RBAConstraintInfo::isSizeOperator() const
+{
+ if ((expression_ != nullptr)
+ && (expression_->isModelElementType(RBAModelElementType::SizeOperator))) {
+ return true;
+ }
+ return false;
+}
+
+const bool RBAConstraintInfo::isImplies() const
+{
+ if ((expression_ != nullptr)
+ && (expression_->isModelElementType(RBAModelElementType::ImpliesOperator)
+ || expression_->isModelElementType(RBAModelElementType::IfStatement))) {
+ return true;
+ }
+ return false;
+}
+
+void RBAConstraintInfo::clear()
+{
+ for (const std::shared_ptr<RBAConstraintInfo>& child : children_) {
+ // @Deviation (MEM05-CPP,Rule-7_5_4,A7-5-2)
+ // [Contents that deviate from the rules]
+ // recursively calling clear()
+ //  [Reason that there is no problem if the rule is deviated]
+ // ConstraintInfo is created for each node in the Constraint expression
+ // tree. The Constraint expression tree is determined by the constraint
+ // expressions written in the model file, and its depth is finite.
+ // Therefore, stack overflow does not occur and there is no problem
+ child->clear();
+ }
+ result_ = RBAExecuteResult::SKIP;
+ exceptionBeforeArbitrate_ = false;
+ trueAllocatables_.clear();
+ falseAllocatables_.clear();
+ operandAllocatable_.clear();
+}
+
+bool RBAConstraintInfo::isExceptionBeforeArbitrate() const
+{
+ return exceptionBeforeArbitrate_;
+}
+
+void RBAConstraintInfo::setExceptionBeforeArbitrate(
+ const bool exceptionBeforeArbitrate)
+{
+ exceptionBeforeArbitrate_ = exceptionBeforeArbitrate;
+}
+
+bool RBAConstraintInfo::needsReRearbitrationFor(
+ const RBAAllocatable* const allocatable) const
+{
+ bool result {false};
+ if (children_.empty() == false) {
+ switch (expression_->getModelElementType()) {
+ case RBAModelElementType::ImpliesOperator:
+ if (children_.front()->isExceptionBeforeArbitrate()) {
+ result = children_.back()->needsReRearbitrationFor(allocatable);
+ }
+ break;
+ case RBAModelElementType::IfStatement:
+ if (children_.front()->isExceptionBeforeArbitrate()) {
+ // @Deviation (MEM05-CPP,Rule-7_5_4,A7-5-2)
+ // [Contents that deviate from the rules]
+ // Function '::rba::RBAConstraintInfo::needsReRearbitrationFor=(_,
+ // p={c::rba::RBAAllocatable})' is recursive.
+ //  [Reason that there is no problem if the rule is deviated]
+ // Recursive call is required as a feature
+ result = children_.back()->needsReRearbitrationFor(allocatable);
+ }
+ break;
+ default:
+ for (const auto& child : children_) {
+ result = (result || child->needsReRearbitrationFor(allocatable));
+ }
+ result =
+ (result || (trueAllocatables_.find(allocatable) != trueAllocatables_.end())
+ || (falseAllocatables_.find(allocatable) != falseAllocatables_.end()));
+ break;
+ }
+ }
+ return result;
+}
+
+bool RBAConstraintInfo::needsRearbitrationFor(const RBAAllocatable* const allocatable,
+ bool isImplies) const
+{
+ bool result {false}; // 再調停要否
+ if (children_.empty() == false) {
+ // When the syntax of the constraint expression is
+ // - ImpliesOperator
+ // - IfStatement
+ // - other than the above
+ switch (expression_->getModelElementType()) {
+ case RBAModelElementType::ImpliesOperator:
+ // If the left side of the implication is true and
+ // the left side contains an Allocatable during arbitration,
+ // re-arbitration is required.
+ //
+ // If the left side of the implication is true and
+ // the left side contains an allocatable state reference expression,
+ // re-arbitration is NOT required.
+ if (children_.front()->isTrue()) {
+ if (children_.front()->contains(allocatable)) {
+ result = true;
+ } else {
+ if (children_.front()->contains(nullptr)) {
+ isImplies = true;
+ }
+ result = (result || children_.back()->needsRearbitrationFor(allocatable,
+ isImplies));
+ }
+ }
+ break;
+ case RBAModelElementType::IfStatement:
+ // If the IF condition includes Allocatble in arbitration,
+ // re-arbitration is required.
+ // If the IF condition includes an Allocatable state reference
+ // expression, re-arbitration is NOT required.
+ // If the IF condition does not include an allocatable state reference
+ // expression, search the child syntax.
+ if (children_.front()->contains(allocatable)) {
+ result = true;
+ } else {
+ if (children_.front()->contains(nullptr)) {
+ isImplies = true;
+ }
+ result = (result || children_.back()->needsRearbitrationFor(allocatable,
+ isImplies));
+ }
+ break;
+ default:
+ for (const auto& child : children_) {
+ // @Deviation (MEM05-CPP,Rule-7_5_4,A7-5-2)
+ // [Contents that deviate from the rules]
+ // Function '::rba::RBAConstraintInfo::needsRearbitrationFor=(_,
+ // p={c::rba::RBAAllocatable},_o)' is recursive.
+ //  [Reason that there is no problem if the rule is deviated]
+ // Recursive call is required as a feature
+ result = (result || child->needsRearbitrationFor(allocatable, isImplies));
+ }
+ // The Constraint expression does not include IF or implication,
+ // or
+ // the Allocatable state reference expression is not included in the
+ // left side of the IF condition of the parent syntax or
+ // the implication of the parent syntax,
+ // or
+ // "Allocable" during arbitration is included in the left side of
+ // the IF condition of the parent syntax or the implication of the
+ // parent syntax,
+ //
+ // re-arbitration is required.
+ if (!isImplies && contains(allocatable)) {
+ result = true;
+ }
+ break;
+ }
+ }
+ return result;
+}
+
+/// @brief Collect "Allocatable" whose right side is false.
+/// @details
+/// - Do not collect if an exception has occurred
+/// - When expression_ is nullptr or When expression_ is implication
+/// - If the left side is satisfied and there is a condition on the left
+/// side that is affected by the allocatable state, collect the
+/// allocatable that caused the right side to be false.
+/// - If the left side is satisfied and there is NO condition affected by
+/// the allocatable state on the left side, this function is called on
+/// the right side. (To correspond to implication or IF nest)
+/// - When expression_ is IF
+/// - If there is a condition on the left side that is affected by the
+/// "Allocatable" state, collect the "Allocatable that caused the
+/// right side to be false.
+/// - If there is no condition affected by the allocatable state on the left
+/// side, call this function for the right side.
+/// (To correspond to the implication or nest of IF)
+/// - When expression_ is negative
+/// - Call this function with "isNot" inverted for the left side.
+/// (To deal with implications or IFs present in children.)
+/// - When expression_ is above
+/// - Call this function for the child ConstraintInfo.
+/// (To deal with implications or IFs present in children.)
+/// @param[in] allocatable "Allcatable" during arbitration
+/// @param[out] targets "Allocatable" for re-arbitration
+/// @param[in] isNot Inversion state of right and wrong by negation operator.
+void RBAConstraintInfo::collectRearbitrationTargetFor(
+ const RBAAllocatable* const allocatable, std::set<const RBAAllocatable*>& targets,
+ const bool isNot) const
+{
+ if (isExceptionBeforeArbitrate()) {
+ return;
+ }
+ if (children_.empty() == false) {
+ switch (expression_->getModelElementType()) {
+ case RBAModelElementType::ImpliesOperator:
+ if (children_.front()->isTrue()) {
+ if (isNot) {
+ children_.back()->collectTrueAllocatables(targets);
+ } else {
+ children_.back()->collectFalseAllocatables(targets);
+ }
+ } else if (!children_.front()->isFalse()) {
+ children_.back()->collectRearbitrationTargetFor(allocatable, targets,
+ isNot);
+ } else {
+ }
+ break;
+ case RBAModelElementType::IfStatement:
+ if (isNot) {
+ children_.back()->collectTrueAllocatables(targets);
+ } else {
+ children_.back()->collectFalseAllocatables(targets);
+ }
+ break;
+ case RBAModelElementType::NotOperator:
+ // @Deviation (MEM05-CPP,Rule-7_5_4,A7-5-2)
+ // [Contents that deviate from the rules]
+ // Function '::rba::RBAConstraintInfo::collectRearbitrationTargetFor=(_,p={c::rba::RBAAllocatable},
+ // &{c::std::set<p={c::rba::RBAAllocatable},{c::std::less<p={c::rba::RBAAllocatable}>},
+ // {c::std::allocator<p={c::rba::RBAAllocatable}>}>},_o)' is recursive.
+ //  [Reason that there is no problem if the rule is deviated]
+ // Recursive call is required as a feature
+ children_.front()->collectRearbitrationTargetFor(allocatable, targets,
+ !isNot);
+ break;
+ default:
+ for (const auto& child : children_) {
+ child->collectRearbitrationTargetFor(allocatable, targets, isNot);
+ }
+ break;
+ }
+ }
+}
+
+void RBAConstraintInfo::collectTrueAllocatables(
+ std::set<const RBAAllocatable*>& allocatables) const
+{
+ if (isExceptionBeforeArbitrate() || isFalse()) {
+ return;
+ }
+ if (isRevert()) {
+ for (const auto& child : children_) {
+ child->collectFalseAllocatables(allocatables);
+ }
+ allocatables.insert(falseAllocatables_.begin(), falseAllocatables_.end());
+ } else if (isImplies()) {
+ children_.back()->collectTrueAllocatables(allocatables);
+ } else if (isSizeOperator()) {
+ // Since the size operator evaluates the number of sets,
+ // the Allocatable that combines FalseAllocatable and TrueAllocatable
+ // becomes TrueAllocatables.
+ children_.back()->collectTrueAllocatables(allocatables);
+ children_.back()->collectFalseAllocatables(allocatables);
+ } else {
+ for (const auto& child : children_) {
+ // @Deviation (MEM05-CPP,Rule-7_5_4,A7-5-2)
+ // [Contents that deviate from the rules]
+ // Function '::rba::RBAConstraintInfo::collectTrueAllocatables=(_,
+ // &{c::std::set<p={c::rba::RBAAllocatable},
+ // {c::std::less<p={c::rba::RBAAllocatable}>},
+ // {c::std::allocator<p={c::rba::RBAAllocatable}>}>})' is recursive.
+ //  [Reason that there is no problem if the rule is deviated]
+ // Recursive call is required as a feature
+ child->collectTrueAllocatables(allocatables);
+ }
+ allocatables.insert(trueAllocatables_.begin(), trueAllocatables_.end());
+ }
+ return;
+}
+
+void RBAConstraintInfo::collectFalseAllocatables(
+ std::set<const RBAAllocatable*>& allocatables) const
+{
+ if (isExceptionBeforeArbitrate() || isTrue()) {
+ return;
+ }
+ if (isRevert()) {
+ for (const auto& child : children_) {
+ child->collectTrueAllocatables(allocatables);
+ }
+ allocatables.insert(trueAllocatables_.begin(), trueAllocatables_.end());
+ } else if (isImplies()) {
+ children_.back()->collectFalseAllocatables(allocatables);
+ } else if (isSizeOperator()) {
+ // The size operator evaluates the number of sets, so "Allocatable",
+ // which is a combination of "FalseAllocatable" and "TrueAllocatable",
+ // becomes "FalseAllocatables".
+ children_.back()->collectTrueAllocatables(allocatables);
+ children_.back()->collectFalseAllocatables(allocatables);
+ } else {
+ for (const auto& child : children_) {
+ // @Deviation (MEM05-CPP,Rule-7_5_4,A7-5-2)
+ // [Contents that deviate from the rules]
+ // Function '::rba::RBAConstraintInfo::collectFalseAllocatables=(_,
+ // &{c::std::set<p={c::rba::RBAAllocatable},
+ // {c::std::less<p={c::rba::RBAAllocatable}>},
+ // {c::std::allocator<p={c::rba::RBAAllocatable}>}>})'
+ // is recursive.
+ //  [Reason that there is no problem if the rule is deviated]
+ // Recursive call is required as a feature
+ child->collectFalseAllocatables(allocatables);
+ }
+ allocatables.insert(falseAllocatables_.begin(), falseAllocatables_.end());
+ }
+ return;
+}
+
+bool RBAConstraintInfo::contains(const RBAAllocatable* const allocatable) const
+{
+ if (allocatable != nullptr) {
+ if (trueAllocatables_.find(allocatable) != trueAllocatables_.end()) {
+ return true;
+ }
+ if (falseAllocatables_.find(allocatable) != falseAllocatables_.end()) {
+ return true;
+ }
+ } else {
+ if (!trueAllocatables_.empty() || !falseAllocatables_.empty()) {
+ return true;
+ }
+ }
+ for (const auto& child : children_) {
+ // @Deviation (MEM05-CPP,Rule-7_5_4,A7-5-2)
+ // [Contents that deviate from the rules]
+ // Function '::rba::RBAConstraintInfo::contains=(_,
+ // p={c::rba::RBAAllocatable})'
+ // is recursive.
+ //  [Reason that there is no problem if the rule is deviated]
+ // Recursive call is required as a feature
+ if (child->contains(allocatable)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool RBAConstraintInfo::isTrue() const
+{
+ return (result_ == RBAExecuteResult::TRUE);
+}
+
+bool RBAConstraintInfo::isFalse() const
+{
+ return (result_ == RBAExecuteResult::FALSE);
+}
+
+void RBAConstraintInfo::collectAffectedAllocatables(
+ const bool isRevert, std::set<const RBAAllocatable*>& affectAllocatables,
+ const bool collecting,
+ const bool forObject)
+{
+ // Collect the allocatable that caused the constraint expression to be False.
+ // It is implemented by recursively calling ConstraintInfo of the tree
+ // structure created at the time of "Constraint" expression evaluation.
+ // with this function.
+ // Collect True because the success or failure of ConstraintInfo below
+ // "negative" is reversed.
+ switch (getExpression()->getModelElementType()) {
+ case RBAModelElementType::NotOperator:
+ // ConstraintInfo below negative negates success or failure,
+ // so invert isRevert and call child Info.
+ children_[0U]->collectAffectedAllocatables(!isRevert, affectAllocatables,
+ collecting, forObject);
+ break;
+ case RBAModelElementType::SizeOperator:
+ // Since the size operator evaluates the number of sets,
+ // "Allocatable" which is a combination of "FalseAllocatable" and
+ // "TrueAllocatable" becomes "affectAllocatables".
+ children_[0U]->collectAffectedAllocatables(false, affectAllocatables,
+ true, true);
+ break;
+ case RBAModelElementType::OrOperator:
+ case RBAModelElementType::ExistsOperator:
+ // the same processing is performed, because "Exists {A,B}{x|x.isXXX}"
+ // is equivalent to "A.isXXX OR B.isXXX"
+ if (!isRevert) {
+ // Processing when "Info" of "OR" in which evaluation result that is not
+ // qualified by an odd number of negative is "Skip" or evaluation reslt
+ // that is not qualified by an odd number of negative is "False".
+ if (!isTrue()) {
+ // Collect the Allocatable of child Info whose
+ // whose evaluation result is False.
+ // When "A.isXXX OR B.isXXX", if the evaluation result of A is True,
+ // the evaluation result of OR will be True even if the evaluation
+ // result of B is False. Therefore, A affects B.
+ // Conversely, B also affects A.
+ // Therefore, set "collecting" to True and
+ // search "child Info" for allocatable.
+ for (auto& i : children_) {
+ i->collectAffectedAllocatables(isRevert, affectAllocatables, true,
+ forObject); // Collct when "OR"
+ }
+ }
+ } else {
+ // Processing when "Info" of "OR" in which evaluation result that is not
+ // qualified by an odd number of negative is "Skip" or evaluation reslt
+ // that is not qualified by an odd number of negative is "False".
+ // "!(A.isXXX OR B.isXXX)" can be decomposed into
+ // "!A.isXXX AND !B.isXXX", so if "NOT", perform the same processing
+ // as "AND".
+ if (!isFalse()) {
+ for (auto& i : children_) {
+ i->collectAffectedAllocatables(isRevert, affectAllocatables,
+ collecting, forObject);
+ }
+ }
+ }
+ break;
+ case RBAModelElementType::AndOperator:
+ case RBAModelElementType::ForAllOperator:
+ //"For-All {A,B}{x|x.isXXX}" is equivalent to "A.isXXX AND B.isXXX",
+ // so the same processing is performed
+ if (isRevert) {
+ // Processing when "Info" of "AND" in which evaluation result that
+ // is not qualified by an odd number of "negative" is "Skip" or
+ // evaluation reslt that is not qualified by an odd number of negative
+ // is "True".
+ //
+ // "!(A.isXXX AND B.isXXX)" can be decomposed into
+ // "!A.isXXX OR !B.isXXX", so if "NOT", perform the same processing
+ // as "OR".
+ if (!isFalse()) {
+ for (auto& i : children_) {
+ // @Deviation (MEM05-CPP,Rule-7_5_4,A7-5-2)
+ // [Contents that deviate from the rules]
+ // Function '::rba::RBAConstraintInfo::collectAffectedAllocatables(_,_o,&{c::std::set<p={c::rba::RBAAllocatable},
+ // {c::std::less<p={c::rba::RBAAllocatable}>},{c::std::allocator<p={c::rba::RBAAllocatable}>}>},_o)' is recursive.
+ //  [Reason that there is no problem if the rule is deviated]
+ // Recursive call is required as a feature
+ i->collectAffectedAllocatables(isRevert, affectAllocatables, true,
+ forObject);
+ }
+ }
+ } else {
+ // Processing when "Info" of "AND" in which evaluation result that
+ // is not qualified by an odd number of "negative" is "Skip" or
+ // evaluation reslt that is not qualified by an odd number of negative
+ // is "True".
+ //
+ // When "A.isXXX AND B.isXXX", the evaluation result of "AND" does not
+ // become True unless the evaluation result of B becomes True,
+ // regardless of the evaluation result of A. Therefore, A does not
+ // affect B, and B does not affect A.
+ // Therefore, "collecting" is as it is, and the "child Info" is
+ // searched for an allocable influence.
+ if (!isTrue()) {
+ for (auto& i : children_) {
+ i->collectAffectedAllocatables(isRevert, affectAllocatables,
+ collecting, forObject);
+ }
+ }
+ }
+ break;
+ case RBAModelElementType::MaxOperator:
+ case RBAModelElementType::MinOperator:
+ {
+ // When the <set> expression is "IF(A.isDisplayed) THEN {B,C} ELSE {D,E}",
+ // scan the left side to extract A as the area of influence
+ children_[0U]->collectAffectedAllocatables(false, affectAllocatables,
+ collecting,forObject);
+ // All the operands that are "x" in the lambda expression affect
+ // each other, so it is necessary to extract them as the affected Area.
+ for (std::uint8_t i { 1U }; i < children_.size(); ++i) {
+ children_[i]->collectAffectedAllocatables(isRevert, affectAllocatables,
+ true, true);
+ }
+ break;
+ }
+ // "A -> B" is the same as "!A OR B".
+ case RBAModelElementType::ImpliesOperator:
+ if (!isRevert) {
+ if (!isTrue()) {
+ // "A.isXXX -> B.isXXX" can be decomposed into "!A.isXXX OR B.isXXX",
+ // so the same process as OR is performed
+ // For the above reason, the acquisition target on the left side
+ // inverts isRevert.
+ children_[0U]->collectAffectedAllocatables(!isRevert,
+ affectAllocatables, true,
+ forObject);
+ children_[1U]->collectAffectedAllocatables(isRevert,
+ affectAllocatables, true,
+ forObject);
+ }
+ } else {
+ if (!isFalse()) {
+ // "!(A.isXXX -> B.isXXX)" can be decomposed into "A.isXXX OR !B.isXXX"
+ // For the above reason, the acquisition target on the left side
+ // inverts isRevert.
+ children_[0U]->collectAffectedAllocatables(!isRevert,
+ affectAllocatables,
+ collecting, forObject);
+ children_[1U]->collectAffectedAllocatables(isRevert,
+ affectAllocatables,
+ collecting, forObject);
+ }
+ }
+ break;
+ case RBAModelElementType::IfStatement:
+ // "IF(A) THEN B ELSE C" is the same as "!A OR B" if A is True,
+ // and the same as "A OR C" if A is False
+ if (children_[0U]->isTrue()) {
+ if (!isRevert) {
+ if (!isTrue()) {
+ // "IF(A.isXXX) THEN B.isXXX ELSE C.isXXX" can be decomposed into
+ // "(!A.isXXX OR B.isXXX)" when A is True.
+ // For the above reason, the acquisition target on the left side
+ // inverts isRevert.
+ children_[0U]->collectAffectedAllocatables(!isRevert,
+ affectAllocatables, true,
+ forObject);
+ children_[1U]->collectAffectedAllocatables(isRevert,
+ affectAllocatables, true,
+ forObject);
+ }
+ } else {
+ if (!isFalse()) {
+ // "!(IF(A.isXXX) THEN B.isXXX ELSE C.isXXX)" can be decomposed into
+ // "(!A.isXXX OR !B.isXXX)" when A is True.
+ // For the above reason, the acquisition target on the left side
+ // inverts isRevert.
+ children_[0U]->collectAffectedAllocatables(isRevert,
+ affectAllocatables, true,
+ forObject);
+ children_[1U]->collectAffectedAllocatables(isRevert,
+ affectAllocatables, true,
+ forObject);
+ }
+ }
+ } else {
+ if (!isRevert) {
+ if (!isTrue()) {
+ // "IF(A.isXXX) THEN B.isXXX ELSE C.isXXX" can be decomposed into
+ // "(A.isXXX OR C.isXXX)" when A is False.
+ children_[0U]->collectAffectedAllocatables(isRevert,
+ affectAllocatables, true,
+ forObject);
+ children_[1U]->collectAffectedAllocatables(isRevert,
+ affectAllocatables, true,
+ forObject);
+ }
+ } else {
+ if (!isFalse()) {
+ // "!(IF(A.isXXX) THEN B.isXXX ELSE C.isXXX)" can be decomposed into
+ // "(A.isXXX OR !C.isXXX)" when A is False.
+ children_[0U]->collectAffectedAllocatables(!isRevert,
+ affectAllocatables, true,
+ forObject);
+ children_[1U]->collectAffectedAllocatables(isRevert,
+ affectAllocatables, true,
+ forObject);
+ }
+ }
+ }
+ break;
+ default: // Collect Allocatable
+ if (collecting) {
+ if (isRevert) {
+ affectAllocatables.insert(trueAllocatables_.begin(),
+ trueAllocatables_.end());
+ } else {
+ affectAllocatables.insert(falseAllocatables_.begin(),
+ falseAllocatables_.end());
+ }
+ if (forObject) {
+ for (const auto& a : operandAllocatable_) {
+ affectAllocatables.insert(a);
+ }
+ }
+ }
+ for (auto& i : children_) {
+ i->collectAffectedAllocatables(isRevert, affectAllocatables, collecting,
+ forObject);
+ }
+ break;
+ }
+ return;
+}
+
+}
+