3 //============================================================================
7 // Implementation of the CdlTransaction class
9 //============================================================================
10 //####COPYRIGHTBEGIN####
12 // ----------------------------------------------------------------------------
13 // Copyright (C) 1999, 2000, 2001, 2002 Red Hat, Inc.
15 // This file is part of the eCos host tools.
17 // This program is free software; you can redistribute it and/or modify it
18 // under the terms of the GNU General Public License as published by the Free
19 // Software Foundation; either version 2 of the License, or (at your option)
22 // This program is distributed in the hope that it will be useful, but WITHOUT
23 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
24 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
27 // You should have received a copy of the GNU General Public License along with
28 // this program; if not, write to the Free Software Foundation, Inc.,
29 // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
31 // ----------------------------------------------------------------------------
33 //####COPYRIGHTEND####
34 //============================================================================
35 //#####DESCRIPTIONBEGIN####
42 //####DESCRIPTIONEND####
43 //============================================================================
48 // ----------------------------------------------------------------------------
49 #include "cdlconfig.h"
51 // Get the infrastructure types, assertions, tracing and similar
53 #include <cyg/infra/cyg_ass.h>
54 #include <cyg/infra/cyg_trac.h>
56 // <cdlcore.hxx> defines everything implemented in this module.
57 // It implicitly supplies <string>, <vector> and <map> because
58 // the class definitions rely on these headers.
59 #include <cdlcore.hxx>
63 //{{{ CdlTransactionCallback class
65 // ----------------------------------------------------------------------------
66 // The callback class is very straightforward. The hard work is done in
67 // the transaction class.
69 CdlTransactionCallback::CdlTransactionCallback(CdlTransaction transact_arg)
71 CYG_REPORT_FUNCNAME("CdlTransactionCallback:: constructor");
72 CYG_REPORT_FUNCARG2XV(this, transact_arg);
73 CYG_PRECONDITION_CLASSC(transact_arg);
75 // The vectors etc. will take care of themselves.
76 transact = transact_arg;
77 cdltransactioncallback_cookie = CdlTransactionCallback_Magic;
79 CYG_POSTCONDITION_THISC();
83 CdlTransactionCallback::~CdlTransactionCallback()
85 CYG_REPORT_FUNCNAME("CdlTransactionCallback:: destructor");
86 CYG_REPORT_FUNCARG1XV(this);
87 CYG_PRECONDITION_THISC();
89 cdltransactioncallback_cookie = CdlTransactionCallback_Invalid;
91 value_changes.clear();
92 active_changes.clear();
93 legal_values_changes.clear();
94 value_source_changes.clear();
95 new_conflicts.clear();
96 new_structural_conflicts.clear();
97 nodes_with_resolved_conflicts.clear();
98 nodes_with_resolved_structural_conflicts.clear();
104 CdlTransactionCallback::set_callback_fn(void (*fn)(const CdlTransactionCallback&))
106 CYG_REPORT_FUNCNAME("CdlTransactionCallback::set_callback_fn");
107 CYG_REPORT_FUNCARG1XV(fn);
109 CdlTransactionBody::set_callback_fn(fn);
114 void (*CdlTransactionCallback::get_callback_fn())(const CdlTransactionCallback&)
116 CYG_REPORT_FUNCNAMETYPE("CdlTransactionCallback::get_callback_fn", "result %p");
118 void (*result)(const CdlTransactionCallback&) = CdlTransactionBody::get_callback_fn();
120 CYG_REPORT_RETVAL(result);
125 CdlTransactionCallback::get_transaction() const
127 CYG_REPORT_FUNCNAMETYPE("CdlTransactionCallback::get_transaction", "result %p");
128 CYG_PRECONDITION_THISC();
130 CdlTransaction result = transact;
131 CYG_POSTCONDITION_CLASSC(result);
133 CYG_REPORT_RETVAL(result);
138 CdlTransactionCallback::get_toplevel() const
140 CYG_REPORT_FUNCNAMETYPE("CdlTransactionCallback::get_toplevel", "result %p");
141 CYG_PRECONDITION_THISC();
143 CdlToplevel result = transact->get_toplevel();
144 CYG_POSTCONDITION_CLASSC(result);
146 CYG_REPORT_RETVAL(result);
151 CdlTransactionCallback::check_this(cyg_assert_class_zeal zeal) const
153 if (CdlTransactionCallback_Magic != cdltransactioncallback_cookie) {
160 //{{{ CdlTransaction statics
162 // ----------------------------------------------------------------------------
163 void (*CdlTransactionBody::callback_fn)(const CdlTransactionCallback&) = 0;
164 CdlInferenceCallback CdlTransactionBody::inference_callback = 0;
165 bool CdlTransactionBody::inference_enabled = true;
166 int CdlTransactionBody::inference_recursion_limit = 3;
167 CdlValueSource CdlTransactionBody::inference_override = CdlValueSource_Inferred;
168 CYGDBG_DEFINE_MEMLEAK_COUNTER(CdlTransactionBody);
171 //{{{ Transaction creation and destruction
173 // ----------------------------------------------------------------------------
175 CdlTransactionBody::make(CdlToplevel toplevel)
177 CYG_REPORT_FUNCNAMETYPE("CdlTransaction::make", "result %p");
178 CYG_REPORT_FUNCARG1XV(toplevel);
179 CYG_PRECONDITION_CLASSC(toplevel);
180 CYG_PRECONDITIONC(0 == toplevel->transaction);
182 CdlTransaction result = new CdlTransactionBody(toplevel, 0, 0);
183 toplevel->transaction = result;
185 CYG_REPORT_RETVAL(result);
190 CdlTransactionBody::make(CdlConflict conflict)
192 CYG_REPORT_FUNCNAMETYPE("CdlTransaction::make (sub-transaction)", "result %p");
193 CYG_REPORT_FUNCARG2XV(this, conflict);
194 CYG_PRECONDITION_THISC();
195 CYG_PRECONDITION_ZERO_OR_CLASSC(conflict);
197 CdlTransaction result = new CdlTransactionBody(0, this, conflict);
199 CYG_REPORT_RETVAL(result);
203 CdlTransactionBody::CdlTransactionBody(CdlToplevel toplevel_arg, CdlTransaction parent_arg, CdlConflict conflict_arg)
205 CYG_REPORT_FUNCNAME("CdlTransaction:: constructor");
206 CYG_REPORT_FUNCARG4XV(this, toplevel_arg, parent_arg, conflict_arg);
207 CYG_PRECONDITION_ZERO_OR_CLASSC(toplevel_arg);
208 CYG_PRECONDITION_ZERO_OR_CLASSC(parent_arg);
209 CYG_PRECONDITION_ZERO_OR_CLASSC(conflict_arg);
210 CYG_PRECONDITIONC( ((0 == toplevel_arg) && (0 != parent_arg)) || ((0 == parent_arg) && (0 != toplevel_arg)));
212 // The containers will take care of themselves, as will all_changes
213 toplevel = toplevel_arg;
215 conflict = conflict_arg;
217 cdltransactionbody_cookie = CdlTransactionBody_Magic;
218 CYGDBG_MEMLEAK_CONSTRUCTOR();
220 CYG_POSTCONDITION_THISC();
224 // ----------------------------------------------------------------------------
225 CdlTransactionBody::~CdlTransactionBody()
227 CYG_REPORT_FUNCNAME("CdlTransaction:: destructor");
228 CYG_REPORT_FUNCARG1XV(this);
229 CYG_PRECONDITION_THISC();
231 // The transaction must have been either committed or cancelled.
232 // This means that various of the STL containers should be empty
233 CYG_ASSERTC(0 == commit_cancel_ops.size());
234 CYG_ASSERTC(0 == changes.size());
235 CYG_ASSERTC(0 == deleted_conflicts.size());
236 CYG_ASSERTC(0 == deleted_structural_conflicts.size());
237 CYG_ASSERTC(0 == new_conflicts.size());
238 CYG_ASSERTC(0 == new_structural_conflicts.size());
239 CYG_ASSERTC(0 == resolved_conflicts.size());
240 CYG_ASSERTC(0 == global_conflicts_with_solutions.size());
241 CYG_ASSERTC(0 == activated.size());
242 CYG_ASSERTC(0 == deactivated.size());
243 CYG_ASSERTC(0 == legal_values_changes.size());
244 CYG_ASSERTC(0 == value_changes.size());
245 CYG_ASSERTC(0 == active_changes.size());
247 // If this was a toplevel transaction, the toplevel knows
248 // about the transaction.
250 CYG_ASSERTC(toplevel->transaction == this);
251 toplevel->transaction = 0;
253 cdltransactionbody_cookie = CdlTransactionBody_Invalid;
259 CYGDBG_MEMLEAK_DESTRUCTOR();
267 // ----------------------------------------------------------------------------
270 CdlTransactionBody::check_this(cyg_assert_class_zeal zeal) const
272 if (CdlTransactionBody_Magic != cdltransactionbody_cookie) {
275 CYGDBG_MEMLEAK_CHECKTHIS();
277 //zeal = cyg_extreme;
279 case cyg_system_test:
282 std::map<CdlValuable,CdlValue>::const_iterator map_i;
283 for (map_i = changes.begin(); map_i != changes.end(); map_i++) {
284 if (!map_i->first->check_this(cyg_quick) || !map_i->second.check_this(cyg_quick)) {
289 std::list<CdlConflict>::const_iterator conf_i;
290 for (conf_i = new_conflicts.begin(); conf_i != new_conflicts.end(); conf_i++) {
291 if (!(*conf_i)->check_this(cyg_quick)) {
295 for (conf_i = new_structural_conflicts.begin(); conf_i != new_structural_conflicts.end(); conf_i++) {
296 if (!(*conf_i)->check_this(cyg_quick)) {
301 std::vector<CdlConflict>::const_iterator conf_i2;
302 for (conf_i2 = deleted_conflicts.begin(); conf_i2 != deleted_conflicts.end(); conf_i2++) {
303 if (!(*conf_i2)->check_this(cyg_quick)) {
307 for (conf_i2 = resolved_conflicts.begin(); conf_i2 != resolved_conflicts.end(); conf_i2++) {
308 if (!(*conf_i2)->check_this(cyg_quick)) {
312 for (conf_i2 = deleted_structural_conflicts.begin(); conf_i2 != deleted_structural_conflicts.end(); conf_i2++) {
313 if (!(*conf_i2)->check_this(cyg_quick)) {
317 for (conf_i = global_conflicts_with_solutions.begin(); conf_i != global_conflicts_with_solutions.end(); conf_i++) {
318 if (!(*conf_i)->check_this(cyg_quick)) {
321 if (0 != (*conf_i)->transaction) {
326 // Nodes cannot have been both activated and deactivated in one transaction
327 std::set<CdlNode>::const_iterator node_i;
328 for (node_i = activated.begin(); node_i != activated.end(); node_i++) {
329 if (!(*node_i)->check_this(cyg_quick)) {
332 if (deactivated.end() != deactivated.find(*node_i)) {
336 for (node_i = deactivated.begin(); node_i != deactivated.end(); node_i++) {
337 if (!(*node_i)->check_this(cyg_quick)) {
340 if (activated.end() != activated.find(*node_i)) {
344 std::set<CdlValuable>::const_iterator val_i;
345 for (val_i = legal_values_changes.begin(); val_i != legal_values_changes.end(); val_i++) {
346 if (!(*val_i)->check_this(cyg_quick)) {
351 std::deque<CdlValuable>::const_iterator val_i2;
352 for (val_i2 = value_changes.begin(); val_i2 != value_changes.end(); val_i2++) {
353 if (!(*val_i2)->check_this(cyg_quick)) {
358 std::deque<CdlNode>::const_iterator active_i;
359 for (active_i = active_changes.begin(); active_i != active_changes.end(); active_i++) {
360 if (!(*active_i)->check_this(cyg_quick)) {
366 if ((0 != toplevel) && !toplevel->check_this(cyg_quick)) {
369 if ((0 != parent) && !parent->check_this(cyg_quick)) {
372 if ((0 != conflict) && !conflict->check_this(cyg_quick)) {
378 if ((0 == toplevel) && (0 == parent)) {
381 if (this == parent) {
395 // ----------------------------------------------------------------------------
397 CdlTransactionBody::get_toplevel() const
399 CYG_REPORT_FUNCNAMETYPE("CdlTransaction::get_toplevel", "result %p");
400 CYG_REPORT_FUNCARG1XV(this);
401 CYG_PRECONDITION_THISC();
403 CdlToplevel result = toplevel;
405 CYG_REPORT_RETVAL(result);
410 CdlTransactionBody::get_parent() const
412 CYG_REPORT_FUNCNAMETYPE("CdlTransaction::get_parent", "result %p");
413 CYG_REPORT_FUNCARG1XV(this);
414 CYG_PRECONDITION_THISC();
416 CdlTransaction result = parent;
418 CYG_REPORT_RETVAL(result);
423 CdlTransactionBody::get_conflict() const
425 CYG_REPORT_FUNCNAMETYPE("CdlTransaction::get_conflict", "result %p");
426 CYG_REPORT_FUNCARG1XV(this);
427 CYG_PRECONDITION_THISC();
429 CdlConflict result = conflict;
431 CYG_REPORT_RETVAL(result);
436 // ----------------------------------------------------------------------------
437 void (*CdlTransactionBody::get_callback_fn())(const CdlTransactionCallback&)
439 CYG_REPORT_FUNCNAMETYPE("CdlTransaction::get_callback_fn", "result %p");
441 void (*result)(const CdlTransactionCallback&) = callback_fn;
443 CYG_REPORT_RETVAL(result);
448 CdlTransactionBody::set_callback_fn(void (*fn)(const CdlTransactionCallback&))
450 CYG_REPORT_FUNCNAME("CdlTransaction::set_callback_fn");
451 CYG_REPORT_FUNCARG1XV(fn);
459 CdlTransactionBody::get_inference_callback_fn()
461 CYG_REPORT_FUNCNAMETYPE("CdlTransaction::get_inference_callback_fn", "result %p");
463 CdlInferenceCallback result = inference_callback;
465 CYG_REPORT_RETVAL(result);
470 CdlTransactionBody::set_inference_callback_fn(CdlInferenceCallback fn)
472 CYG_REPORT_FUNCNAME("CdlTransaction::set_inference_callback");
473 CYG_REPORT_FUNCARG1XV(fn);
475 inference_callback = fn;
481 CdlTransactionBody::enable_automatic_inference()
483 CYG_REPORT_FUNCNAME("CdlTransaction::enable_automatic_inference");
485 inference_enabled = true;
491 CdlTransactionBody::disable_automatic_inference()
493 CYG_REPORT_FUNCNAME("CdlTransaction::disable_automatic_inference");
495 inference_enabled = false;
501 CdlTransactionBody::is_automatic_inference_enabled()
503 CYG_REPORT_FUNCNAMETYPE("CdlTransaction::is_automatic_inference_enabled", "result %d");
505 bool result = inference_enabled;
507 CYG_REPORT_RETVAL(result);
512 CdlTransactionBody::set_inference_recursion_limit(int limit)
514 CYG_REPORT_FUNCNAME("CdlTransaction::set_inference_recursion_limit");
515 CYG_REPORT_FUNCARG1XV(limit);
516 CYG_PRECONDITIONC(0 < limit);
517 CYG_PRECONDITIONC(limit < 16); // arbitrary number
519 inference_recursion_limit = limit;
525 CdlTransactionBody::get_inference_recursion_limit()
527 CYG_REPORT_FUNCNAMETYPE("CdlTransaction::get_inference_recursion_limit", "result %d");
529 int result = inference_recursion_limit;
531 CYG_REPORT_RETVAL(result);
536 CdlTransactionBody::set_inference_override(CdlValueSource source)
538 CYG_REPORT_FUNCNAME("CdlTransaction::set_inference_override");
539 CYG_REPORT_FUNCARG1XV(source);
540 CYG_PRECONDITIONC((CdlValueSource_Invalid == source) || Cdl::is_valid_value_source(source));
542 inference_override = source;
548 CdlTransactionBody::get_inference_override()
550 CYG_REPORT_FUNCNAMETYPE("CdlTransaction::get_inference_override", "result %d");
552 CdlValueSource result = inference_override;
554 CYG_REPORT_RETVAL((int) result);
559 //{{{ Value access and updates
561 // ----------------------------------------------------------------------------
563 CdlTransactionBody::get_whole_value(CdlConstValuable valuable_arg) const
565 CYG_REPORT_FUNCNAMETYPE("CdlTransaction::get_whole_value", "result %p");
566 CYG_REPORT_FUNCARG2XV(this, valuable_arg);
567 CYG_PRECONDITION_THISC();
568 CYG_PRECONDITION_CLASSC(valuable_arg);
570 // Unfortunately I need a valuable rather than a const-valuable when
571 // accessing the STL containers.
572 CdlValuable valuable = const_cast<CdlValuable>(valuable_arg);
574 // If we are trying to find a solution, keep track of all valuables
575 // that were accessed.
576 const CdlValue* result = 0;
578 conflict->solution_references.insert(valuable);
581 std::map<CdlValuable,CdlValue>::const_iterator val_i;
582 val_i = changes.find(valuable);
583 if (val_i != changes.end()) {
584 result = &(val_i->second);
585 } else if (0 != parent) {
586 result = &(parent->get_whole_value(valuable));
588 result = &(valuable->get_whole_value());
591 CYG_REPORT_RETVAL(result);
596 CdlTransactionBody::set_whole_value(CdlValuable valuable, const CdlValue& old_value, const CdlValue& new_value)
598 CYG_REPORT_FUNCNAME("CdlTransaction::set_whole_value");
599 CYG_REPORT_FUNCARG3XV(this, valuable, &new_value);
600 CYG_PRECONDITION_THISC();
601 CYG_PRECONDITION_CLASSC(valuable);
602 CYG_PRECONDITION_CLASSOC(old_value);
603 CYG_PRECONDITION_CLASSOC(new_value);
604 CYG_PRECONDITIONC(&old_value != &new_value);
606 CdlValueFlavor flavor = old_value.get_flavor();
607 CYG_ASSERTC(flavor == new_value.get_flavor());
608 CYG_ASSERTC(CdlValueFlavor_None != flavor);
610 bool value_changed = false;
611 bool bool_changed = false;
613 if ((CdlValueFlavor_Bool == flavor) || (CdlValueFlavor_BoolData == flavor)) {
614 if (old_value.is_enabled() != new_value.is_enabled()) {
615 value_changed = true;
619 if (!value_changed && ((CdlValueFlavor_BoolData == flavor) || (CdlValueFlavor_Data == flavor))) {
620 if (old_value.get_simple_value() != new_value.get_simple_value()) {
621 value_changed = true;
625 std::deque<CdlValuable>::const_iterator change_i;
626 change_i = std::find(value_changes.begin(), value_changes.end(), valuable);
627 if (change_i == value_changes.end()) {
628 value_changes.push_back(valuable);
632 // Actually do the update. This may modify old_value, so has to be
634 changes[valuable] = new_value;
636 // If there was a change to the boolean part of the value and the valuable
637 // implements an interface, the interface value needs to be recalculated.
638 if (bool_changed && valuable->has_property(CdlPropertyId_Implements)) {
639 std::vector<CdlInterface> interfaces;
640 std::vector<CdlInterface>::const_iterator interface_i;
641 valuable->get_implemented_interfaces(interfaces);
642 for (interface_i = interfaces.begin(); interface_i != interfaces.end(); interface_i++) {
643 (*interface_i)->recalculate(this);
650 const std::map<CdlValuable, CdlValue>&
651 CdlTransactionBody::get_changes() const
653 CYG_REPORT_FUNCNAME("CdlTransaction::get_changes");
654 CYG_REPORT_FUNCARG1XV(this);
655 CYG_PRECONDITION_THISC();
662 //{{{ Active access and updates
664 // ----------------------------------------------------------------------------
665 // Nodes can become active or inactive during transactions, and this affects
666 // propagation and expression evaluation
669 CdlTransactionBody::is_active(CdlNode node) const
671 CYG_REPORT_FUNCNAMETYPE("CdlTransaction::is_active", "result %d");
672 CYG_REPORT_FUNCARG2XV(this, node);
673 CYG_PRECONDITION_THISC();
674 CYG_PRECONDITION_CLASSC(node);
677 if (activated.end() != activated.find(node)) {
679 } else if (deactivated.end() != deactivated.find(node)) {
681 } else if (0 != parent) {
682 result = parent->is_active(node);
684 result = node->is_active();
687 CYG_REPORT_RETVAL(result);
692 CdlTransactionBody::set_active(CdlNode node, bool state)
694 CYG_REPORT_FUNCNAME("CdlTransaction::set_active");
695 CYG_REPORT_FUNCARG3XV(this, node, state);
696 CYG_PRECONDITION_THISC();
697 CYG_PRECONDITION_CLASSC(node);
700 activated.insert(node);
701 std::set<CdlNode>::iterator node_i = deactivated.find(node);
702 if (deactivated.end() != node_i) {
703 deactivated.erase(node_i);
706 deactivated.insert(node);
707 std::set<CdlNode>::iterator node_i = activated.find(node);
708 if (activated.end() != node_i) {
709 activated.erase(node_i);
712 active_changes.push_back(node);
714 CdlValuable valuable = dynamic_cast<CdlValuable>(node);
715 if ((0 != valuable) && valuable->has_property(CdlPropertyId_Implements)) {
716 std::vector<CdlInterface> interfaces;
717 std::vector<CdlInterface>::const_iterator interface_i;
718 valuable->get_implemented_interfaces(interfaces);
719 for (interface_i = interfaces.begin(); interface_i != interfaces.end(); interface_i++) {
720 (*interface_i)->recalculate(this);
728 //{{{ Conflict access and updates
730 //{{{ get_conflict() etc.
732 // ----------------------------------------------------------------------------
734 CdlTransactionBody::has_conflict(CdlNode node, bool (*pFn)(CdlConflict))
736 CYG_REPORT_FUNCNAMETYPE("CdlTransaction::has_conflict", "result %d");
737 CYG_REPORT_FUNCARG3XV(this, node, pFn);
738 CYG_PRECONDITION_THISC();
739 CYG_PRECONDITION_CLASSC(node);
741 // Because it is necessary to check whether or not any given
742 // conflict has been cleared in the current transaction or any
743 // parent transaction, recursion into the parent is not
746 std::list<CdlConflict>::const_iterator conf_i;
747 CdlTransaction current_transaction = this;
748 CdlToplevel toplevel = this->toplevel;
750 CYG_LOOP_INVARIANT_CLASSC(current_transaction);
752 for (conf_i = current_transaction->new_conflicts.begin();
753 conf_i != current_transaction->new_conflicts.end();
756 if ((node == (*conf_i)->get_node()) &&
757 !(this->has_conflict_been_cleared(*conf_i)) && (*pFn)(*conf_i)) {
763 toplevel = current_transaction->toplevel;
764 current_transaction = current_transaction->parent;
765 } while (!result && (0 != current_transaction));
768 CYG_ASSERT_CLASSC(toplevel);
769 for (conf_i = toplevel->conflicts.begin(); conf_i != toplevel->conflicts.end(); conf_i++) {
770 if ((node == (*conf_i)->get_node()) && !(this->has_conflict_been_cleared(*conf_i)) && (*pFn)(*conf_i)) {
777 CYG_REPORT_RETVAL(result);
782 CdlTransactionBody::get_conflict(CdlNode node, bool (*pFn)(CdlConflict))
784 CYG_REPORT_FUNCNAMETYPE("CdlTransaction::get_conflict", "result %p");
785 CYG_REPORT_FUNCARG3XV(this, node, pFn);
786 CYG_PRECONDITION_THISC();
787 CYG_PRECONDITION_CLASSC(node);
789 CdlConflict result = 0;
790 std::list<CdlConflict>::const_iterator conf_i;
791 CdlTransaction current_transaction = this;
792 CdlToplevel toplevel = this->toplevel;
794 CYG_LOOP_INVARIANT_CLASSC(current_transaction);
796 for (conf_i = current_transaction->new_conflicts.begin();
797 conf_i != current_transaction->new_conflicts.end();
800 if ((node == (*conf_i)->get_node()) &&
801 !(this->has_conflict_been_cleared(*conf_i)) && (*pFn)(*conf_i)) {
807 toplevel = current_transaction->toplevel;
808 current_transaction = current_transaction->parent;
809 } while ((0 == result) && (0 != current_transaction));
812 CYG_ASSERT_CLASSC(toplevel);
813 for (conf_i = toplevel->conflicts.begin(); conf_i != toplevel->conflicts.end(); conf_i++) {
814 if ((node == (*conf_i)->get_node()) && !(this->has_conflict_been_cleared(*conf_i)) && (*pFn)(*conf_i)) {
821 CYG_REPORT_RETVAL(result);
826 CdlTransactionBody::get_conflicts(CdlNode node, bool (*pFn)(CdlConflict), std::vector<CdlConflict>& result)
828 CYG_REPORT_FUNCNAME("CdlTransaction::get_conflicts");
829 CYG_REPORT_FUNCARG3XV(this, node, pFn);
830 CYG_PRECONDITION_THISC();
831 CYG_PRECONDITION_CLASSC(node);
833 std::list<CdlConflict>::const_iterator conf_i;
834 CdlTransaction current_transaction = this;
835 CdlToplevel toplevel = this->toplevel;
837 CYG_LOOP_INVARIANT_CLASSC(current_transaction);
839 for (conf_i = current_transaction->new_conflicts.begin();
840 conf_i != current_transaction->new_conflicts.end();
843 if ((node == (*conf_i)->get_node()) &&
844 !(this->has_conflict_been_cleared(*conf_i)) && (*pFn)(*conf_i)) {
845 result.push_back(*conf_i);
849 toplevel = current_transaction->toplevel;
850 current_transaction = current_transaction->parent;
851 } while (0 != current_transaction);
853 CYG_ASSERT_CLASSC(toplevel);
854 for (conf_i = toplevel->conflicts.begin(); conf_i != toplevel->conflicts.end(); conf_i++) {
855 if ((node == (*conf_i)->get_node()) && !(this->has_conflict_been_cleared(*conf_i)) && (*pFn)(*conf_i)) {
856 result.push_back(*conf_i);
864 CdlTransactionBody::has_conflict(CdlNode node, CdlProperty prop, bool (*pFn)(CdlConflict))
866 CYG_REPORT_FUNCNAMETYPE("CdlTransaction::has_conflict", "result %d");
867 CYG_REPORT_FUNCARG4XV(this, node, prop, pFn);
868 CYG_PRECONDITION_THISC();
869 CYG_PRECONDITION_CLASSC(node);
870 CYG_PRECONDITION_CLASSC(prop);
873 std::list<CdlConflict>::const_iterator conf_i;
874 CdlTransaction current_transaction = this;
875 CdlToplevel toplevel = this->toplevel;
877 CYG_LOOP_INVARIANT_CLASSC(current_transaction);
879 for (conf_i = current_transaction->new_conflicts.begin();
880 conf_i != current_transaction->new_conflicts.end();
883 if ((node == (*conf_i)->get_node()) && (prop == (*conf_i)->get_property()) &&
884 !(this->has_conflict_been_cleared(*conf_i)) && (*pFn)(*conf_i)) {
891 toplevel = current_transaction->toplevel;
892 current_transaction = current_transaction->parent;
893 } while (!result && (0 != current_transaction));
896 CYG_ASSERT_CLASSC(toplevel);
897 for (conf_i = toplevel->conflicts.begin(); conf_i != toplevel->conflicts.end(); conf_i++) {
898 if ((node == (*conf_i)->get_node()) && (prop == (*conf_i)->get_property()) &&
899 !(this->has_conflict_been_cleared(*conf_i)) && (*pFn)(*conf_i)) {
907 CYG_REPORT_RETVAL(result);
912 CdlTransactionBody::get_conflict(CdlNode node, CdlProperty prop, bool (*pFn)(CdlConflict))
914 CYG_REPORT_FUNCNAMETYPE("CdlTransaction::get_conflict", "result %p");
915 CYG_REPORT_FUNCARG4XV(this, node, prop, pFn);
916 CYG_PRECONDITION_THISC();
917 CYG_PRECONDITION_CLASSC(node);
918 CYG_PRECONDITION_CLASSC(prop);
920 CdlConflict result = 0;
921 std::list<CdlConflict>::const_iterator conf_i;
922 CdlTransaction current_transaction = this;
923 CdlToplevel toplevel = this->toplevel;
925 CYG_LOOP_INVARIANT_CLASSC(current_transaction);
927 for (conf_i = current_transaction->new_conflicts.begin();
928 conf_i != current_transaction->new_conflicts.end();
931 if ((node == (*conf_i)->get_node()) && (prop == (*conf_i)->get_property()) &&
932 !(this->has_conflict_been_cleared(*conf_i)) && (*pFn)(*conf_i)) {
938 toplevel = current_transaction->toplevel;
939 current_transaction = current_transaction->parent;
940 } while ((0 == result) && (0 != current_transaction));
943 CYG_ASSERT_CLASSC(toplevel);
944 for (conf_i = toplevel->conflicts.begin(); conf_i != toplevel->conflicts.end(); conf_i++) {
945 if ((node == (*conf_i)->get_node()) && (prop == (*conf_i)->get_property()) &&
946 !(this->has_conflict_been_cleared(*conf_i)) && (*pFn)(*conf_i)) {
954 CYG_REPORT_RETVAL(result);
959 CdlTransactionBody::get_conflicts(CdlNode node, CdlProperty prop, bool (*pFn)(CdlConflict), std::vector<CdlConflict>& result)
961 CYG_REPORT_FUNCNAME("CdlTransaction::get_conflict");
962 CYG_REPORT_FUNCARG4XV(this, node, prop, pFn);
963 CYG_PRECONDITION_THISC();
964 CYG_PRECONDITION_CLASSC(node);
965 CYG_PRECONDITION_CLASSC(prop);
967 std::list<CdlConflict>::const_iterator conf_i;
968 CdlTransaction current_transaction = this;
969 CdlToplevel toplevel = this->toplevel;
971 CYG_LOOP_INVARIANT_CLASSC(current_transaction);
973 for (conf_i = current_transaction->new_conflicts.begin();
974 conf_i != current_transaction->new_conflicts.end();
977 if ((node == (*conf_i)->get_node()) && (prop == (*conf_i)->get_property()) &&
978 !(this->has_conflict_been_cleared(*conf_i)) && (*pFn)(*conf_i)) {
979 result.push_back(*conf_i);
983 toplevel = current_transaction->toplevel;
984 current_transaction = current_transaction->parent;
985 } while (0 != current_transaction);
987 CYG_ASSERT_CLASSC(toplevel);
988 for (conf_i = toplevel->conflicts.begin(); conf_i != toplevel->conflicts.end(); conf_i++) {
989 if ((node == (*conf_i)->get_node()) && (prop == (*conf_i)->get_property()) &&
990 !(this->has_conflict_been_cleared(*conf_i)) && (*pFn)(*conf_i)) {
992 result.push_back(*conf_i);
1000 //{{{ get_structural_conflict() etc
1002 // ----------------------------------------------------------------------------
1004 CdlTransactionBody::has_structural_conflict(CdlNode node, bool (*pFn)(CdlConflict))
1006 CYG_REPORT_FUNCNAMETYPE("CdlTransaction::has_structural_conflict", "result %d");
1007 CYG_REPORT_FUNCARG3XV(this, node, pFn);
1008 CYG_PRECONDITION_THISC();
1009 CYG_PRECONDITION_CLASSC(node);
1011 // Because it is necessary to check whether or not any given
1012 // conflict has been cleared in the current transaction or any
1013 // parent transaction, recursion into the parent is not
1015 bool result = false;
1016 std::list<CdlConflict>::const_iterator conf_i;
1017 CdlTransaction current_transaction = this;
1018 CdlToplevel toplevel = this->toplevel;
1020 CYG_LOOP_INVARIANT_CLASSC(current_transaction);
1022 for (conf_i = current_transaction->new_structural_conflicts.begin();
1023 conf_i != current_transaction->new_structural_conflicts.end();
1026 if ((node == (*conf_i)->get_node()) &&
1027 !(this->has_conflict_been_cleared(*conf_i)) && (*pFn)(*conf_i)) {
1033 toplevel = current_transaction->toplevel;
1034 current_transaction = current_transaction->parent;
1035 } while (!result && (0 != current_transaction));
1038 CYG_ASSERT_CLASSC(toplevel);
1039 for (conf_i = toplevel->structural_conflicts.begin(); conf_i != toplevel->structural_conflicts.end(); conf_i++) {
1040 if ((node == (*conf_i)->get_node()) && !(this->has_conflict_been_cleared(*conf_i)) && (*pFn)(*conf_i)) {
1047 CYG_REPORT_RETVAL(result);
1052 CdlTransactionBody::get_structural_conflict(CdlNode node, bool (*pFn)(CdlConflict))
1054 CYG_REPORT_FUNCNAMETYPE("CdlTransaction::get_structural_conflict", "result %p");
1055 CYG_REPORT_FUNCARG3XV(this, node, pFn);
1056 CYG_PRECONDITION_THISC();
1057 CYG_PRECONDITION_CLASSC(node);
1059 CdlConflict result = 0;
1060 std::list<CdlConflict>::const_iterator conf_i;
1061 CdlTransaction current_transaction = this;
1062 CdlToplevel toplevel = this->toplevel;
1064 CYG_LOOP_INVARIANT_CLASSC(current_transaction);
1066 for (conf_i = current_transaction->new_structural_conflicts.begin();
1067 conf_i != current_transaction->new_structural_conflicts.end();
1070 if ((node == (*conf_i)->get_node()) &&
1071 !(this->has_conflict_been_cleared(*conf_i)) && (*pFn)(*conf_i)) {
1077 toplevel = current_transaction->toplevel;
1078 current_transaction = current_transaction->parent;
1079 } while ((0 == result) && (0 != current_transaction));
1082 CYG_ASSERT_CLASSC(toplevel);
1083 for (conf_i = toplevel->structural_conflicts.begin(); conf_i != toplevel->structural_conflicts.end(); conf_i++) {
1084 if ((node == (*conf_i)->get_node()) && !(this->has_conflict_been_cleared(*conf_i)) && (*pFn)(*conf_i)) {
1091 CYG_REPORT_RETVAL(result);
1096 CdlTransactionBody::get_structural_conflicts(CdlNode node, bool (*pFn)(CdlConflict), std::vector<CdlConflict>& result)
1098 CYG_REPORT_FUNCNAME("CdlTransaction::get_structural_conflicts");
1099 CYG_REPORT_FUNCARG3XV(this, node, pFn);
1100 CYG_PRECONDITION_THISC();
1101 CYG_PRECONDITION_CLASSC(node);
1103 std::list<CdlConflict>::const_iterator conf_i;
1104 CdlTransaction current_transaction = this;
1105 CdlToplevel toplevel = this->toplevel;
1107 CYG_LOOP_INVARIANT_CLASSC(current_transaction);
1109 for (conf_i = current_transaction->new_structural_conflicts.begin();
1110 conf_i != current_transaction->new_structural_conflicts.end();
1113 if ((node == (*conf_i)->get_node()) &&
1114 !(this->has_conflict_been_cleared(*conf_i)) && (*pFn)(*conf_i)) {
1115 result.push_back(*conf_i);
1119 toplevel = current_transaction->toplevel;
1120 current_transaction = current_transaction->parent;
1121 } while (0 != current_transaction);
1123 CYG_ASSERT_CLASSC(toplevel);
1124 for (conf_i = toplevel->structural_conflicts.begin(); conf_i != toplevel->structural_conflicts.end(); conf_i++) {
1125 if ((node == (*conf_i)->get_node()) && !(this->has_conflict_been_cleared(*conf_i)) && (*pFn)(*conf_i)) {
1126 result.push_back(*conf_i);
1130 CYG_REPORT_RETURN();
1134 CdlTransactionBody::has_structural_conflict(CdlNode node, CdlProperty prop, bool (*pFn)(CdlConflict))
1136 CYG_REPORT_FUNCNAMETYPE("CdlTransaction::has_structural_conflict", "result %d");
1137 CYG_REPORT_FUNCARG4XV(this, node, prop, pFn);
1138 CYG_PRECONDITION_THISC();
1139 CYG_PRECONDITION_CLASSC(node);
1140 CYG_PRECONDITION_CLASSC(prop);
1142 bool result = false;
1143 std::list<CdlConflict>::const_iterator conf_i;
1144 CdlTransaction current_transaction = this;
1145 CdlToplevel toplevel = this->toplevel;
1147 CYG_LOOP_INVARIANT_CLASSC(current_transaction);
1149 for (conf_i = current_transaction->new_structural_conflicts.begin();
1150 conf_i != current_transaction->new_structural_conflicts.end();
1153 if ((node == (*conf_i)->get_node()) && (prop == (*conf_i)->get_property()) &&
1154 !(this->has_conflict_been_cleared(*conf_i)) && (*pFn)(*conf_i)) {
1161 toplevel = current_transaction->toplevel;
1162 current_transaction = current_transaction->parent;
1163 } while (!result && (0 != current_transaction));
1166 CYG_ASSERT_CLASSC(toplevel);
1167 for (conf_i = toplevel->structural_conflicts.begin(); conf_i != toplevel->structural_conflicts.end(); conf_i++) {
1168 if ((node == (*conf_i)->get_node()) && (prop == (*conf_i)->get_property()) &&
1169 !(this->has_conflict_been_cleared(*conf_i)) && (*pFn)(*conf_i)) {
1177 CYG_REPORT_RETVAL(result);
1182 CdlTransactionBody::get_structural_conflict(CdlNode node, CdlProperty prop, bool (*pFn)(CdlConflict))
1184 CYG_REPORT_FUNCNAMETYPE("CdlTransaction::get_structural_conflict", "result %p");
1185 CYG_REPORT_FUNCARG4XV(this, node, prop, pFn);
1186 CYG_PRECONDITION_THISC();
1187 CYG_PRECONDITION_CLASSC(node);
1188 CYG_PRECONDITION_CLASSC(prop);
1190 CdlConflict result = 0;
1191 std::list<CdlConflict>::const_iterator conf_i;
1192 CdlTransaction current_transaction = this;
1193 CdlToplevel toplevel = this->toplevel;
1195 CYG_LOOP_INVARIANT_CLASSC(current_transaction);
1197 for (conf_i = current_transaction->new_structural_conflicts.begin();
1198 conf_i != current_transaction->new_structural_conflicts.end();
1201 if ((node == (*conf_i)->get_node()) && (prop == (*conf_i)->get_property()) &&
1202 !(this->has_conflict_been_cleared(*conf_i)) && (*pFn)(*conf_i)) {
1208 toplevel = current_transaction->toplevel;
1209 current_transaction = current_transaction->parent;
1210 } while ((0 == result) && (0 != current_transaction));
1213 CYG_ASSERT_CLASSC(toplevel);
1214 for (conf_i = toplevel->structural_conflicts.begin(); conf_i != toplevel->structural_conflicts.end(); conf_i++) {
1215 if ((node == (*conf_i)->get_node()) && (prop == (*conf_i)->get_property()) &&
1216 !(this->has_conflict_been_cleared(*conf_i)) && (*pFn)(*conf_i)) {
1224 CYG_REPORT_RETVAL(result);
1229 CdlTransactionBody::get_structural_conflicts(CdlNode node, CdlProperty prop, bool (*pFn)(CdlConflict),
1230 std::vector<CdlConflict>& result)
1232 CYG_REPORT_FUNCNAME("CdlTransaction::get_structural_conflict");
1233 CYG_REPORT_FUNCARG4XV(this, node, prop, pFn);
1234 CYG_PRECONDITION_THISC();
1235 CYG_PRECONDITION_CLASSC(node);
1236 CYG_PRECONDITION_CLASSC(prop);
1238 std::list<CdlConflict>::const_iterator conf_i;
1239 CdlTransaction current_transaction = this;
1240 CdlToplevel toplevel = this->toplevel;
1242 CYG_LOOP_INVARIANT_CLASSC(current_transaction);
1244 for (conf_i = current_transaction->new_structural_conflicts.begin();
1245 conf_i != current_transaction->new_structural_conflicts.end();
1248 if ((node == (*conf_i)->get_node()) && (prop == (*conf_i)->get_property()) &&
1249 !(this->has_conflict_been_cleared(*conf_i)) && (*pFn)(*conf_i)) {
1250 result.push_back(*conf_i);
1254 toplevel = current_transaction->toplevel;
1255 current_transaction = current_transaction->parent;
1256 } while (0 != current_transaction);
1258 CYG_ASSERT_CLASSC(toplevel);
1259 for (conf_i = toplevel->structural_conflicts.begin(); conf_i != toplevel->structural_conflicts.end(); conf_i++) {
1260 if ((node == (*conf_i)->get_node()) && (prop == (*conf_i)->get_property()) &&
1261 !(this->has_conflict_been_cleared(*conf_i)) && (*pFn)(*conf_i)) {
1263 result.push_back(*conf_i);
1267 CYG_REPORT_RETURN();
1271 //{{{ clear_conflicts()
1273 // ----------------------------------------------------------------------------
1274 // Clearing a conflict. This can only happen in the context of a
1277 CdlTransactionBody::clear_conflicts(CdlNode node, bool (*pFn)(CdlConflict))
1279 CYG_REPORT_FUNCNAME("CdlTransaction::clear_conflicts");
1280 CYG_REPORT_FUNCARG3XV(this, node, pFn);
1281 CYG_PRECONDITION_THISC();
1282 CYG_PRECONDITION_CLASSC(node);
1284 // Recursing into the parent is the wrong thing to do here, it
1285 // would result in the conflict being cleared in the parent rather
1286 // than in the current transaction.
1287 std::list<CdlConflict>::iterator conf_i;
1288 CdlTransaction current_transaction = this;
1289 CdlToplevel toplevel = this->toplevel;
1291 CYG_LOOP_INVARIANT_CLASSC(current_transaction);
1293 for (conf_i = current_transaction->new_conflicts.begin(); conf_i != current_transaction->new_conflicts.end(); ) {
1294 CdlConflict conflict = *conf_i++;
1295 if ((node == conflict->get_node()) && !(this->has_conflict_been_cleared(conflict)) && (*pFn)(conflict)) {
1296 this->clear_conflict(conflict);
1299 toplevel = current_transaction->toplevel;
1300 current_transaction = current_transaction->parent;
1301 } while (0 != current_transaction);
1303 CYG_ASSERT_CLASSC(toplevel);
1304 for (conf_i = toplevel->conflicts.begin(); conf_i != toplevel->conflicts.end(); ) {
1305 CdlConflict conflict = *conf_i++;
1306 if ((node == conflict->get_node()) && !(this->has_conflict_been_cleared(conflict)) && (*pFn)(conflict)) {
1307 this->clear_conflict(conflict);
1311 CYG_REPORT_RETURN();
1315 CdlTransactionBody::clear_conflicts(CdlNode node, CdlProperty prop, bool (*pFn)(CdlConflict))
1317 CYG_REPORT_FUNCNAME("CdlTransaction::clear_conflicts");
1318 CYG_REPORT_FUNCARG4XV(this, node, prop, pFn);
1319 CYG_PRECONDITION_THISC();
1320 CYG_PRECONDITION_CLASSC(node);
1322 std::list<CdlConflict>::iterator conf_i;
1323 CdlTransaction current_transaction = this;
1324 CdlToplevel toplevel = this->toplevel;
1326 CYG_LOOP_INVARIANT_CLASSC(current_transaction);
1328 for (conf_i = current_transaction->new_conflicts.begin(); conf_i != current_transaction->new_conflicts.end(); ) {
1329 CdlConflict conflict = *conf_i++;
1330 if ((node == conflict->get_node()) && (prop == conflict->get_property()) &&
1331 !(this->has_conflict_been_cleared(conflict)) && (*pFn)(conflict)) {
1332 this->clear_conflict(conflict);
1335 toplevel = current_transaction->toplevel;
1336 current_transaction = current_transaction->parent;
1337 } while (0 != current_transaction);
1339 CYG_ASSERT_CLASSC(toplevel);
1340 for (conf_i = toplevel->conflicts.begin(); conf_i != toplevel->conflicts.end(); ) {
1341 CdlConflict conflict = *conf_i++;
1342 if ((node == conflict->get_node()) && (prop == conflict->get_property()) &&
1343 !(this->has_conflict_been_cleared(conflict)) && (*pFn)(conflict)) {
1344 this->clear_conflict(conflict);
1348 CYG_REPORT_RETURN();
1352 CdlTransactionBody::clear_structural_conflicts(CdlNode node, bool (*pFn)(CdlConflict))
1354 CYG_REPORT_FUNCNAME("CdlTransaction::clear_structural_conflicts");
1355 CYG_REPORT_FUNCARG3XV(this, node, pFn);
1356 CYG_PRECONDITION_THISC();
1357 CYG_PRECONDITION_CLASSC(node);
1359 std::list<CdlConflict>::iterator conf_i;
1360 CdlTransaction current_transaction = this;
1361 CdlToplevel toplevel = this->toplevel;
1363 CYG_LOOP_INVARIANT_CLASSC(current_transaction);
1365 for (conf_i = current_transaction->new_structural_conflicts.begin();
1366 conf_i != current_transaction->new_structural_conflicts.end();
1369 CdlConflict conflict = *conf_i++;
1370 if ((node == conflict->get_node()) && !(this->has_conflict_been_cleared(conflict)) && (*pFn)(conflict)) {
1371 this->clear_conflict(conflict);
1374 toplevel = current_transaction->toplevel;
1375 current_transaction = current_transaction->parent;
1376 } while (0 != current_transaction);
1378 CYG_ASSERT_CLASSC(toplevel);
1379 for (conf_i = toplevel->structural_conflicts.begin(); conf_i != toplevel->structural_conflicts.end(); ) {
1380 CdlConflict conflict = *conf_i++;
1381 if ((node == conflict->get_node()) && !(this->has_conflict_been_cleared(conflict)) && (*pFn)(conflict)) {
1382 this->clear_conflict(conflict);
1386 CYG_REPORT_RETURN();
1390 CdlTransactionBody::clear_structural_conflicts(CdlNode node, CdlProperty prop, bool (*pFn)(CdlConflict))
1392 CYG_REPORT_FUNCNAME("CdlTransaction::clear_structural_conflicts");
1393 CYG_REPORT_FUNCARG4XV(this, node, prop, pFn);
1394 CYG_PRECONDITION_THISC();
1395 CYG_PRECONDITION_CLASSC(node);
1397 std::list<CdlConflict>::iterator conf_i;
1398 CdlTransaction current_transaction = this;
1399 CdlToplevel toplevel = this->toplevel;
1401 CYG_LOOP_INVARIANT_CLASSC(current_transaction);
1403 for (conf_i = current_transaction->new_structural_conflicts.begin();
1404 conf_i != current_transaction->new_structural_conflicts.end();
1407 CdlConflict conflict = *conf_i++;
1408 if ((node == conflict->get_node()) && (prop == conflict->get_property()) &&
1409 !(this->has_conflict_been_cleared(conflict)) && (*pFn)(conflict)) {
1411 this->clear_conflict(conflict);
1414 toplevel = current_transaction->toplevel;
1415 current_transaction = current_transaction->parent;
1416 } while (0 != current_transaction);
1418 CYG_ASSERT_CLASSC(toplevel);
1419 for (conf_i = toplevel->structural_conflicts.begin(); conf_i != toplevel->structural_conflicts.end(); ) {
1420 CdlConflict conflict = *conf_i++;
1421 if ((node == conflict->get_node()) && (prop == conflict->get_property()) &&
1422 !(this->has_conflict_been_cleared(conflict)) && (*pFn)(conflict)) {
1423 this->clear_conflict(conflict);
1427 CYG_REPORT_RETURN();
1431 //{{{ clear_conflict()
1433 // ----------------------------------------------------------------------------
1435 CdlTransactionBody::clear_conflict(CdlConflict conflict)
1437 CYG_REPORT_FUNCNAME("CdlTransaction::clear_conflict");
1438 CYG_REPORT_FUNCARG2XV(this, conflict);
1439 CYG_PRECONDITION_THISC();
1440 CYG_PRECONDITION_CLASSC(conflict);
1442 // If this conflict was created during the transaction, it should
1443 // be on the new_conflicts or new_structural_conflicts container
1444 if (this == conflict->transaction) {
1445 // The conflict should be on one of the two new_conflicts deques.
1446 if (conflict->structural) {
1447 std::list<CdlConflict>::iterator conf_i = std::find(new_structural_conflicts.begin(),
1448 new_structural_conflicts.end(), conflict);
1449 CYG_ASSERTC(conf_i != new_structural_conflicts.end());
1450 new_structural_conflicts.erase(conf_i);
1452 std::list<CdlConflict>::iterator conf_i = std::find(new_conflicts.begin(), new_conflicts.end(), conflict);
1453 CYG_ASSERTC(conf_i != new_conflicts.end());
1454 new_conflicts.erase(conf_i);
1459 if (conflict->structural) {
1460 deleted_structural_conflicts.push_back(conflict);
1462 deleted_conflicts.push_back(conflict);
1466 CYG_REPORT_RETURN();
1469 // ----------------------------------------------------------------------------
1471 CdlTransactionBody::has_conflict_been_cleared(CdlConflict conf)
1473 CYG_REPORT_FUNCNAMETYPE("CdlTransaction::has_conflict_been_cleared", "result %d");
1474 CYG_REPORT_FUNCARG2XV(this, conf);
1475 CYG_PRECONDITION_THISC();
1476 CYG_PRECONDITION_CLASSC(conf);
1478 bool result = false;
1479 CdlTransaction current_transaction = this;
1481 if (conf->structural) {
1482 if (std::find(current_transaction->deleted_structural_conflicts.begin(),
1483 current_transaction->deleted_structural_conflicts.end(), conf) !=
1484 current_transaction->deleted_structural_conflicts.end()) {
1489 if (std::find(current_transaction->deleted_conflicts.begin(), current_transaction->deleted_conflicts.end(),
1490 conf) != current_transaction->deleted_conflicts.end()) {
1495 current_transaction = current_transaction->parent;
1496 } while (!result && (0 != current_transaction));
1498 CYG_REPORT_RETVAL(result);
1503 //{{{ per-transaction data
1505 // ----------------------------------------------------------------------------
1506 // Accessing the per-transaction conflict data.
1508 const std::list<CdlConflict>&
1509 CdlTransactionBody::get_new_conflicts() const
1511 CYG_REPORT_FUNCNAME("CdlTransaction::get_new_conflicts");
1512 CYG_REPORT_FUNCARG1XV(this);
1513 CYG_PRECONDITION_THISC();
1515 CYG_REPORT_RETURN();
1516 return new_conflicts;
1519 const std::list<CdlConflict>&
1520 CdlTransactionBody::get_new_structural_conflicts() const
1522 CYG_REPORT_FUNCNAME("CdlTransaction::get_new_structural_conflicts");
1523 CYG_REPORT_FUNCARG1XV(this);
1524 CYG_PRECONDITION_THISC();
1526 CYG_REPORT_RETURN();
1527 return new_structural_conflicts;
1530 const std::vector<CdlConflict>&
1531 CdlTransactionBody::get_deleted_conflicts() const
1533 CYG_REPORT_FUNCNAME("CdlTransaction::get_deleted_conflicts");
1534 CYG_REPORT_FUNCARG1XV(this);
1535 CYG_PRECONDITION_THISC();
1537 CYG_REPORT_RETURN();
1538 return deleted_conflicts;
1541 const std::vector<CdlConflict>&
1542 CdlTransactionBody::get_deleted_structural_conflicts() const
1544 CYG_REPORT_FUNCNAME("CdlTransaction::get_deleted_structural_conflicts");
1545 CYG_REPORT_FUNCARG1XV(this);
1546 CYG_PRECONDITION_THISC();
1548 CYG_REPORT_RETURN();
1549 return deleted_structural_conflicts;
1552 const std::vector<CdlConflict>&
1553 CdlTransactionBody::get_resolved_conflicts() const
1555 CYG_REPORT_FUNCNAME("CdlTransaction::get_resolved_conflicts");
1556 CYG_REPORT_FUNCARG1XV(this);
1557 CYG_PRECONDITION_THISC();
1559 CYG_REPORT_RETURN();
1560 return resolved_conflicts;
1563 const std::list<CdlConflict>&
1564 CdlTransactionBody::get_global_conflicts_with_solutions() const
1566 CYG_REPORT_FUNCNAME("CdlTransaction::get_global_conflicts_with_solutions");
1567 CYG_REPORT_FUNCARG1XV(this);
1568 CYG_PRECONDITION_THISC();
1570 CYG_REPORT_RETURN();
1571 return global_conflicts_with_solutions;
1577 //{{{ Commit/cancel operations
1579 // ----------------------------------------------------------------------------
1581 CdlTransactionBody::add_commit_cancel_op(CdlTransactionCommitCancelOp* op)
1583 CYG_REPORT_FUNCNAME("CdlTransaction::add_commit_cancel_op");
1584 CYG_REPORT_FUNCARG2XV(this, op);
1585 CYG_PRECONDITION_THISC();
1586 CYG_PRECONDITIONC(0 != op);
1588 commit_cancel_ops.push_back(op);
1590 CYG_REPORT_RETURN();
1594 CdlTransactionBody::cancel_last_commit_cancel_op()
1596 CYG_REPORT_FUNCNAME("CdlTransaction::cancel_last_commit_cancel_op");
1597 CYG_REPORT_FUNCARG1XV(this);
1598 CYG_PRECONDITION_THISC();
1600 CdlTransactionCommitCancelOp* op = *(commit_cancel_ops.rbegin());
1601 commit_cancel_ops.pop_back();
1605 CYG_REPORT_RETURN();
1608 CdlTransactionCommitCancelOp*
1609 CdlTransactionBody::get_last_commit_cancel_op() const
1611 CYG_REPORT_FUNCNAMETYPE("CdlTransaction::get_last_commit_cancel_op", "result %p");
1612 CYG_REPORT_FUNCARG1XV(this);
1613 CYG_PRECONDITION_THISC();
1615 CdlTransactionCommitCancelOp* op = *(commit_cancel_ops.rbegin());
1617 CYG_REPORT_RETVAL(op);
1621 const std::vector<CdlTransactionCommitCancelOp*>&
1622 CdlTransactionBody::get_commit_cancel_ops() const
1624 CYG_REPORT_FUNCNAME("CdlTransaction::get_commit_cancel_ops");
1625 CYG_REPORT_FUNCARG1XV(this);
1626 CYG_PRECONDITION_THISC();
1628 CYG_REPORT_RETURN();
1629 return commit_cancel_ops;
1635 // ----------------------------------------------------------------------------
1636 // Propagation should happen whenever one or more changes have been applied,
1637 // so that the impact of these changes on other parts of the configuration
1638 // can be fully assessed. The transaction keeps track of all the changes
1639 // to date and invokes appropriate node and property update handlers.
1642 CdlTransactionBody::propagate()
1644 CYG_REPORT_FUNCNAME("CdlTransaction::propagate");
1645 CYG_REPORT_FUNCARG1XV(this);
1646 CYG_INVARIANT_THISC(CdlTransactionBody);
1648 // Now it is time to worry about value and active changes.
1649 // Propagation may result in new entries, so only the
1650 // front item of one of the vectors is modified.
1651 while ((0 < value_changes.size()) || (0 < active_changes.size())) {
1653 if (0 != value_changes.size()) {
1655 CdlValuable valuable = value_changes.front();
1656 value_changes.pop_front();
1658 // A value change may invalidate one or more solutions.
1659 // This happens during propagation rather than at the time
1660 // that the value is actually changed, so that multiple
1661 // solutions can be applied in one go.
1662 std::list<CdlConflict>::iterator conf_i, conf_j;
1663 for (conf_i = new_conflicts.begin(); conf_i != new_conflicts.end(); conf_i++) {
1664 CYG_LOOP_INVARIANT_CLASSC(*conf_i);
1665 (*conf_i)->update_solution_validity(valuable);
1667 for (conf_i = global_conflicts_with_solutions.begin();
1668 conf_i != global_conflicts_with_solutions.end();
1671 CYG_LOOP_INVARIANT_CLASSC(*conf_i);
1674 (*conf_j)->update_solution_validity(valuable);
1675 if (!(*conf_j)->has_known_solution()) {
1676 global_conflicts_with_solutions.erase(conf_j);
1680 // If the valuable is no longer loaded then there is
1681 // no need to worry about propagation
1682 if (0 != valuable->get_toplevel()) {
1684 // Inform the valuable itself about the update, so that
1685 // e.g. the value can be checked against legal_values
1686 valuable->update(this, CdlUpdate_ValueChange);
1688 std::vector<CdlReferrer>& referrers = valuable->referrers;
1689 std::vector<CdlReferrer>::iterator ref_i;
1690 for (ref_i = referrers.begin(); ref_i != referrers.end(); ref_i++) {
1691 ref_i->update(this, valuable, CdlUpdate_ValueChange);
1697 CdlNode node = active_changes.front();
1698 active_changes.pop_front();
1700 if (0 != node->get_toplevel()) {
1701 node->update(this, CdlUpdate_ActiveChange);
1703 std::vector<CdlReferrer>& referrers = node->referrers;
1704 std::vector<CdlReferrer>::iterator ref_i;
1705 for (ref_i = referrers.begin(); ref_i != referrers.end(); ref_i++) {
1706 ref_i->update(this, node, CdlUpdate_ActiveChange);
1712 CYG_REPORT_RETURN();
1715 // ----------------------------------------------------------------------------
1717 CdlTransactionBody::is_propagation_required() const
1719 CYG_REPORT_FUNCNAMETYPE("CdlTransaction::is_propagation_required", "result %d");
1720 CYG_REPORT_FUNCARG1XV(this);
1721 CYG_PRECONDITION_THISC();
1723 bool result = false;
1725 if ((0 != value_changes.size()) || (0 != active_changes.size())) {
1729 CYG_REPORT_RETVAL(result);
1734 // ----------------------------------------------------------------------------
1736 CdlTransactionBody::add_legal_values_change(CdlValuable valuable)
1738 CYG_REPORT_FUNCNAME("CdlTransaction::add_legal_values_change");
1739 CYG_REPORT_FUNCARG2XV(this, valuable);
1740 CYG_PRECONDITION_THISC();
1741 CYG_PRECONDITION_CLASSC(valuable);
1743 legal_values_changes.insert(valuable);
1745 CYG_REPORT_RETURN();
1748 const std::set<CdlValuable>&
1749 CdlTransactionBody::get_legal_values_changes() const
1751 CYG_REPORT_FUNCNAME("CdlTransaction::get_legal_values_changes");
1752 CYG_REPORT_FUNCARG1XV(this);
1753 CYG_PRECONDITION_THISC();
1755 CYG_REPORT_RETURN();
1756 return legal_values_changes;
1762 // ----------------------------------------------------------------------------
1763 // Cancellation is straightforward, essentially it just involves clearing
1764 // out all of the STL containers. The transaction object can then be-used,
1765 // so fields like parent and toplevel must not change.
1767 CdlTransactionBody::cancel()
1769 CYG_REPORT_FUNCNAME("CdlTransaction::cancel");
1770 CYG_REPORT_FUNCARG1XV(this);
1771 CYG_INVARIANT_THISC(CdlTransactionBody);
1773 // First take care of the cancel ops, if any, in case a cancel op
1774 // depends on some of the other transaction state.
1775 std::vector<CdlTransactionCommitCancelOp*>::reverse_iterator cancel_i;
1776 for (cancel_i = commit_cancel_ops.rbegin(); cancel_i != commit_cancel_ops.rend(); cancel_i++) {
1777 (*cancel_i)->cancel(this);
1781 commit_cancel_ops.clear();
1783 this->changes.clear();
1784 std::list<CdlConflict>::iterator conf_i;
1785 for (conf_i = this->new_conflicts.begin(); conf_i != this->new_conflicts.end(); conf_i++) {
1786 CYG_LOOP_INVARIANT_CLASSC(*conf_i);
1789 this->new_conflicts.clear();
1790 for (conf_i = this->new_structural_conflicts.begin(); conf_i != this->new_structural_conflicts.end(); conf_i++) {
1791 CYG_LOOP_INVARIANT_CLASSC(*conf_i);
1794 this->new_structural_conflicts.clear();
1796 this->deleted_structural_conflicts.clear();
1797 this->deleted_conflicts.clear();
1799 // Any conflicts created and resolved during this transaction will
1800 // still be present in resolved_conflicts. Some global conflicts
1801 // may be there as well.
1802 std::vector<CdlConflict>::iterator conf_i2;
1803 for (conf_i2 = this->resolved_conflicts.begin(); conf_i2 != this->resolved_conflicts.end(); conf_i2++) {
1804 if (this == (*conf_i2)->transaction) {
1808 this->resolved_conflicts.clear();
1810 // Any global conflicts which have been updated with a solution need
1811 // to have that solution cleared. Currently no attempt is made to
1812 // keep solutions valid for global conflicts.
1813 for (conf_i = this->global_conflicts_with_solutions.begin();
1814 conf_i != this->global_conflicts_with_solutions.end();
1817 CYG_LOOP_INVARIANT_CLASSC(*conf_i);
1818 (*conf_i)->clear_solution();
1820 this->global_conflicts_with_solutions.clear();
1822 this->activated.clear();
1823 this->deactivated.clear();
1824 this->legal_values_changes.clear();
1825 this->value_changes.clear();
1826 this->active_changes.clear();
1828 CYG_REPORT_RETURN();
1834 // ----------------------------------------------------------------------------
1835 // The commit operation. There are two main branches for this code. The
1836 // first branch deals with sub-transactions, and basically involves
1837 // transferring changes from the sub-transaction to the parent. It is
1838 // assumed that the sub-transaction has been fully propagated, so
1839 // data can just be transferred from the child to the parent.
1841 // The second branch involves committing changes from a transaction to
1842 // the toplevel, invoking the transaction callback if necessary.
1845 CdlTransactionBody::commit()
1847 CYG_REPORT_FUNCNAME("CdlTransaction::commit");
1848 CYG_REPORT_FUNCARG1XV(this);
1849 CYG_INVARIANT_THISC(CdlTransactionBody);
1851 std::map<CdlValuable, CdlValue>::iterator map_i;
1852 std::list<CdlConflict>::iterator conf_i, conf_j;
1853 std::vector<CdlConflict>::const_iterator conf_i2, conf_j2;
1854 std::set<CdlNode>::iterator set_i, set_j, set_k;
1855 std::set<CdlValuable>::iterator set_i2, set_j2;
1858 // Any conflicts that were solved by the inference engine further
1859 // down are still resolved.
1860 // Great care has to be taken with conflict ownership. The following
1861 // cases have to be considered.
1862 // 1) the resolved conflict is global, its transaction is zero, this
1863 // conflict must only be destroyed if the toplevel transaction
1864 // is committed - at which time time the conflict should appear
1865 // on the deleted_conflicts lists.
1866 // 2) the conflict belongs to a higher level transaction, we have
1867 // recursed a certain amount trying to resolve it e.g. to explore
1868 // OR branches of the tree. Again the resolved conflict can only
1869 // be destroyed when the appropriate higher-level commit happens,
1870 // and should appear on the deleted conflicts list.
1871 // 3) the conflict was created and resolved further down the tree.
1872 // We are keeping it around for informational purposes only.
1873 // Associating it with this transaction allows the code to
1874 // distinguish this case from (1) and (2).
1875 for (conf_i2 = resolved_conflicts.begin(); conf_i2 != resolved_conflicts.end(); conf_i2++) {
1876 CdlConflict conf = *conf_i2;
1877 CYG_LOOP_INVARIANT_CLASSC(conf);
1878 CYG_LOOP_INVARIANTC(parent->resolved_conflicts.end() == \
1879 std::find(parent->resolved_conflicts.begin(), \
1880 parent->resolved_conflicts.end(), conf));
1881 parent->resolved_conflicts.push_back(conf);
1882 parent->dirty = true;
1883 if (this == conf->transaction) {
1884 conf->transaction = parent;
1887 resolved_conflicts.clear();
1889 // Any global conflicts for which solutions were found in the
1890 // sub-transaction still have solutions in the parent.
1891 for (conf_i = global_conflicts_with_solutions.begin(); conf_i != global_conflicts_with_solutions.end(); conf_i++) {
1893 CdlConflict conf = *conf_i;
1894 CYG_LOOP_INVARIANT_CLASSC(conf);
1896 // It is not clear that this search is actually useful, especially
1897 // given that the solution is currently stored with the conflict
1898 // rather than with the transaction.
1899 conf_j = std::find(parent->global_conflicts_with_solutions.begin(),
1900 parent->global_conflicts_with_solutions.end(),
1902 if (conf_j == parent->global_conflicts_with_solutions.end()) {
1903 parent->global_conflicts_with_solutions.push_back(conf);
1904 parent->dirty = true;
1907 global_conflicts_with_solutions.clear();
1909 // Now take care of deleted conflicts.
1910 for (conf_i2 = deleted_conflicts.begin(); conf_i2 != deleted_conflicts.end(); conf_i2++) {
1911 CdlConflict conf = *conf_i2;
1912 CYG_LOOP_INVARIANT_CLASSC(conf);
1913 // Possibilities to consider:
1914 // 1) the conflict may have been local to the parent transaction,
1915 // in which case it can be deleted.
1916 // 2) the conflict may have been created in a higher-level
1917 // transaction, in which case it has to be moved to the
1918 // parent's deleted_conflicts vector.
1919 // 3) the conflict may also have been global, again it needs
1920 // to be propagated into the parent's deleted_conflicts vector.
1922 // But that is not the whole story. If this sub-transaction was
1923 // created specifically to resolve the conflict then the latter
1924 // should appear on the resolved vector and not be destroyed
1925 // immediately. This is true for both global and per-transaction
1928 // For global conflicts it is also necessary to worry about
1929 // the global_conflicts_with_solutions list, that has to be
1930 // kept in synch with the rest of the world.
1931 conf_i = std::find(parent->new_conflicts.begin(), parent->new_conflicts.end(), conf);
1932 bool can_delete = false;
1933 if (conf_i != parent->new_conflicts.end()) {
1934 parent->new_conflicts.erase(conf_i);
1937 parent->deleted_conflicts.push_back(conf);
1939 if (0 == conf->transaction) {
1940 conf_j = std::find(parent->global_conflicts_with_solutions.begin(),
1941 parent->global_conflicts_with_solutions.end(),
1943 if (conf_j != parent->global_conflicts_with_solutions.end()) {
1944 parent->global_conflicts_with_solutions.erase(conf_j);
1947 if (conf == this->conflict) {
1948 // The conflict may have been fortuitously resolved lower down,
1949 // in which case it will have appeared in this->resolved_conflicts()
1950 // and copied already.
1951 conf_j2 = std::find(parent->resolved_conflicts.begin(), parent->resolved_conflicts.end(), conf);
1952 if (conf_j2 == parent->resolved_conflicts.end()) {
1953 parent->resolved_conflicts.push_back(conf);
1954 parent->dirty = true;
1956 } else if (can_delete) {
1960 // Unnecessary, but let's keep things clean.
1961 deleted_conflicts.clear();
1963 // Deleted structural conflicts. For now the inference engine can do nothing with
1964 // these so they are a bit simpler.
1965 for (conf_i2 = deleted_structural_conflicts.begin(); conf_i2 != deleted_structural_conflicts.end(); conf_i2++) {
1967 CdlConflict conf = *conf_i2;
1968 CYG_LOOP_INVARIANT_CLASSC(conf);
1969 conf_i = std::find(parent->new_structural_conflicts.begin(), parent->new_structural_conflicts.end(), conf);
1970 if (conf_i != parent->new_structural_conflicts.end()) {
1971 parent->new_structural_conflicts.erase(conf_i);
1974 parent->deleted_structural_conflicts.push_back(conf);
1977 deleted_structural_conflicts.clear();
1979 // All value changes need to be propagated from the child to the parent.
1980 // Also, these value changes may invalidate existing solutions.
1981 for (map_i = changes.begin(); map_i != changes.end(); map_i++) {
1982 CYG_LOOP_INVARIANT_CLASSC(map_i->first);
1983 CYG_LOOP_INVARIANT_CLASSOC(map_i->second);
1984 parent->changes[map_i->first] = map_i->second;
1985 for (conf_i = parent->new_conflicts.begin(); conf_i != parent->new_conflicts.end(); conf_i++) {
1986 CYG_LOOP_INVARIANT_CLASSC(*conf_i);
1987 (*conf_i)->update_solution_validity(map_i->first);
1989 for (conf_i = parent->global_conflicts_with_solutions.begin();
1990 conf_i != parent->global_conflicts_with_solutions.end();
1994 CYG_LOOP_INVARIANT_CLASSC(*conf_j);
1996 (*conf_j)->update_solution_validity(map_i->first);
1997 if (!(*conf_j)->has_known_solution()) {
1998 parent->global_conflicts_with_solutions.erase(conf_j);
2004 // Continue propagating the conflicts.New conflicts can just
2006 for (conf_i = new_conflicts.begin(); conf_i != new_conflicts.end(); conf_i++) {
2007 CYG_LOOP_INVARIANT_CLASSC(*conf_i);
2008 parent->new_conflicts.push_back(*conf_i);
2009 parent->dirty = true;
2010 (*conf_i)->transaction = parent;
2012 for (conf_i = new_structural_conflicts.begin(); conf_i != new_structural_conflicts.end(); conf_i++) {
2013 CYG_LOOP_INVARIANT_CLASSC(*conf_i);
2014 parent->new_structural_conflicts.push_back(*conf_i);
2015 parent->dirty = true;
2016 (*conf_i)->transaction = parent;
2018 // The cancel operation at the end will delete new conflicts, so the
2019 // containers had better be cleared here.
2020 new_conflicts.clear();
2021 new_structural_conflicts.clear();
2024 // Also keep track of nodes that have become active or inactive.
2025 set_j = parent->activated.begin();
2026 for (set_i = activated.begin(); set_i != activated.end(); set_i++) {
2027 set_j = parent->activated.insert(set_j, *set_i);
2028 set_k = parent->deactivated.find(*set_i);
2029 if (set_k != parent->deactivated.end()) {
2030 parent->deactivated.erase(set_k);
2034 set_j = parent->deactivated.begin();
2035 for (set_i = deactivated.begin(); set_i != deactivated.end(); set_i++) {
2036 set_j = parent->deactivated.insert(set_j, *set_i);
2037 set_k = parent->activated.find(*set_i);
2038 if (set_k != parent->activated.end()) {
2039 parent->activated.erase(set_k);
2043 deactivated.clear();
2045 // Keep track of other property changes.
2046 set_j2 = parent->legal_values_changes.begin();
2047 for (set_i2 = legal_values_changes.begin(); set_i2 != legal_values_changes.end(); set_i2++) {
2048 set_j2 = parent->legal_values_changes.insert(set_j2, *set_i2);
2050 legal_values_changes.clear();
2052 // Any pending commit/cancel ops needs to be transferred to the parent
2053 parent->commit_cancel_ops.insert(parent->commit_cancel_ops.end(),
2054 this->commit_cancel_ops.begin(), this->commit_cancel_ops.end());
2055 this->commit_cancel_ops.clear();
2059 CYG_ASSERT_CLASSC(toplevel);
2061 // If there is a registered callback function, it is necessary to fill
2062 // in the remaining fields of the all_changes callback structure. This
2063 // should happen before any conflicts get deleted. The actual callback
2064 // is invoked at the end, once all the changes have been moved to
2066 CdlTransactionCallback all_changes(this);
2067 if (0 != callback_fn) {
2069 for (map_i = changes.begin(); map_i != changes.end(); map_i++) {
2070 if (0 == map_i->first->get_toplevel()) {
2073 CdlValueFlavor flavor = map_i->second.get_flavor();
2074 const CdlValue& old_value = map_i->first->get_whole_value();
2075 CYG_LOOP_INVARIANTC(flavor == old_value.get_flavor());
2076 bool value_changed = false;
2078 if (old_value.get_source() != map_i->second.get_source()) {
2079 all_changes.value_source_changes.push_back(map_i->first);
2081 if ((CdlValueFlavor_Bool == flavor) || (CdlValueFlavor_BoolData == flavor)) {
2082 if (old_value.is_enabled() != map_i->second.is_enabled()) {
2083 value_changed = true;
2086 if (!value_changed && ((CdlValueFlavor_BoolData == flavor) || (CdlValueFlavor_Data == flavor))) {
2087 if (old_value.get_simple_value() != map_i->second.get_simple_value()) {
2088 value_changed = true;
2091 if (value_changed) {
2092 all_changes.value_changes.push_back(map_i->first);
2095 for (conf_i = new_conflicts.begin(); conf_i != new_conflicts.end(); conf_i++) {
2096 all_changes.new_conflicts.push_back(*conf_i);
2098 for (conf_i = new_structural_conflicts.begin(); conf_i != new_structural_conflicts.end(); conf_i++) {
2099 all_changes.new_structural_conflicts.push_back(*conf_i);
2101 for (conf_i2 = deleted_conflicts.begin(); conf_i2 != deleted_conflicts.end(); conf_i2++) {
2102 CdlNode node = (*conf_i2)->get_node();
2103 CYG_LOOP_INVARIANT_CLASSC(node);
2105 all_changes.nodes_with_resolved_conflicts.push_back(node);
2107 for (conf_i2 = deleted_structural_conflicts.begin(); conf_i2 != deleted_structural_conflicts.end(); conf_i2++) {
2108 CdlNode node = (*conf_i2)->get_node();
2109 CYG_LOOP_INVARIANT_CLASSC(node);
2111 all_changes.nodes_with_resolved_structural_conflicts.push_back(node);
2113 for (set_i = activated.begin(); set_i != activated.end(); set_i++) {
2114 if (0 != (*set_i)->get_toplevel()) {
2115 all_changes.active_changes.push_back(*set_i);
2118 for (set_i = deactivated.begin(); set_i != deactivated.end(); set_i++) {
2119 if (0 != (*set_i)->get_toplevel()) {
2120 all_changes.active_changes.push_back(*set_i);
2123 for (set_i2 = legal_values_changes.begin(); set_i2 != legal_values_changes.end(); set_i2++) {
2124 if (0 != (*set_i)->get_toplevel()) {
2125 all_changes.legal_values_changes.push_back(*set_i2);
2128 legal_values_changes.clear();
2131 // All new values need to be installed in the appropriate valuable.
2132 for (map_i = changes.begin(); map_i != changes.end(); map_i++) {
2133 CYG_LOOP_INVARIANT_CLASSC(map_i->first);
2134 CYG_LOOP_INVARIANT_CLASSOC(map_i->second);
2135 map_i->first->value = map_i->second;
2139 // Sort out the conflicts. New conflicts can just be added, although
2140 // care has to be taken to clear state - currently no attempt is
2141 // made to check solution validity for global conflicts.
2142 for (conf_i = new_conflicts.begin(); conf_i != new_conflicts.end(); conf_i++) {
2143 CYG_LOOP_INVARIANT_CLASSC(*conf_i);
2144 toplevel->conflicts.push_back(*conf_i);
2145 (*conf_i)->transaction = 0;
2146 (*conf_i)->clear_solution();
2148 new_conflicts.clear();
2149 for (conf_i = new_structural_conflicts.begin(); conf_i != new_structural_conflicts.end(); conf_i++) {
2150 CYG_LOOP_INVARIANT_CLASSC(*conf_i);
2151 toplevel->structural_conflicts.push_back(*conf_i);
2152 (*conf_i)->transaction = 0;
2153 (*conf_i)->clear_solution();
2155 new_structural_conflicts.clear();
2157 // Resolved conflicts can be either global or per-transaction
2158 // ones. If the former then the conflict will also be present
2159 // in deleted_conflicts and will get deleted shortly.
2160 for (conf_i2 = resolved_conflicts.begin(); conf_i2 != resolved_conflicts.end(); conf_i2++) {
2161 CYG_LOOP_INVARIANT_CLASSC(*conf_i2);
2162 if (0 != (*conf_i2)->transaction) {
2166 resolved_conflicts.clear();
2168 // Now process conflicts that have gone away. These must actually
2170 for (conf_i2 = deleted_conflicts.begin(); conf_i2 != deleted_conflicts.end(); conf_i2++) {
2171 CYG_LOOP_INVARIANT_CLASSC(*conf_i2);
2172 std::list<CdlConflict>::iterator tmp;
2173 tmp = std::find(toplevel->conflicts.begin(), toplevel->conflicts.end(), *conf_i2);
2174 CYG_LOOP_INVARIANTC(tmp != toplevel->conflicts.end());
2175 toplevel->conflicts.erase(tmp);
2178 deleted_conflicts.clear();
2179 for (conf_i2 = deleted_structural_conflicts.begin(); conf_i2 != deleted_structural_conflicts.end(); conf_i2++) {
2180 CYG_LOOP_INVARIANT_CLASSC(*conf_i2);
2181 std::list<CdlConflict>::iterator tmp;
2182 tmp = std::find(toplevel->structural_conflicts.begin(), toplevel->structural_conflicts.end(), *conf_i2);
2183 CYG_LOOP_INVARIANTC(tmp != toplevel->structural_conflicts.end());
2184 toplevel->structural_conflicts.erase(tmp);
2187 deleted_structural_conflicts.clear();
2189 // Any global conflicts with solutions need to have their solutions cleared,
2190 // since currently no attempt is made to preserve their accuracy.
2191 for (conf_i = global_conflicts_with_solutions.begin(); conf_i != global_conflicts_with_solutions.end(); conf_i++) {
2192 CYG_LOOP_INVARIANT_CLASSC(*conf_i);
2193 (*conf_i)->clear_solution();
2195 global_conflicts_with_solutions.clear();
2197 for (set_i = activated.begin(); set_i != activated.end(); set_i++) {
2198 (*set_i)->active = true;
2200 for (set_i = deactivated.begin(); set_i != deactivated.end(); set_i++) {
2201 (*set_i)->active = false;
2204 deactivated.clear();
2206 // Invoke all pending commit operations
2207 std::vector<CdlTransactionCommitCancelOp*>::iterator commit_i;
2208 for (commit_i = commit_cancel_ops.begin(); commit_i != commit_cancel_ops.end(); commit_i++) {
2209 (*commit_i)->commit(this);
2213 commit_cancel_ops.clear();
2215 // Finally take care of the callback.
2216 if (0 != callback_fn) {
2217 (*callback_fn)(all_changes);
2221 CYG_REPORT_RETURN();
2225 //{{{ Solution support
2227 // ----------------------------------------------------------------------------
2228 // Saving a solution basically involves remembering what changes took place
2229 // in the corresponding sub-transaction. There is no need to worry about
2230 // other data in the sub-transaction such as conflicts, because there
2231 // are no actual value changes.
2234 CdlTransactionBody::save_solution()
2236 CYG_REPORT_FUNCNAME("CdlTransaction::save_solution");
2237 CYG_REPORT_FUNCARG1XV(this);
2238 CYG_PRECONDITION_THISC();
2239 // Solutions should only be applicable to sub-transactions immediately
2240 // below the main transaction, since that is the only level at which
2241 // inference callbacks occur
2242 CYG_PRECONDITIONC((0 != parent) && (0 == parent->parent));
2244 CYG_PRECONDITION_CLASSC(conflict);
2245 CYG_PRECONDITIONC(0 == conflict->solution.size());
2247 std::map<CdlValuable, CdlValue>::const_iterator map_i;
2248 for (map_i = changes.begin(); map_i != changes.end(); map_i++) {
2249 // If the valuable was calculated or is otherwise non-modifiable,
2250 // there is no point in storing it with the solution since the
2251 // information is unlikely to be of interest to the user.
2252 CdlValuable valuable = map_i->first;
2253 if (valuable->is_modifiable()) {
2254 conflict->solution.push_back(*map_i);
2258 // save_solution() should operate like commit() or cancel(), i.e.
2259 // it leaves an empty sub-transaction. This sub-transaction cannot
2260 // actually be re-used at present because it still references a
2261 // conflict for which a solution is now already in place, but that
2262 // may get cleaned up in future.
2264 CYG_REPORT_RETURN();
2267 // ----------------------------------------------------------------------------
2268 // Can a solution be applied without e.g. overwriting a user value with
2269 // an inferred value. There is a setting inference_override which controls
2270 // this. Making a previously enabled option inactive also requires
2271 // user confirmation, thus preventing the inference engine from disabling
2272 // entire components.
2274 CdlTransactionBody::user_confirmation_required() const
2276 CYG_REPORT_FUNCNAMETYPE("CdlTransaction::user_confirmation_required", "result %d");
2277 CYG_REPORT_FUNCARG1XV(this);
2278 CYG_PRECONDITION_THISC();
2279 CYG_PRECONDITION_CLASSC(this->parent);
2281 bool result = false;
2283 std::map<CdlValuable, CdlValue>::const_iterator val_i;
2284 for (val_i = changes.begin(); val_i != changes.end(); val_i++) {
2285 const CdlValue& old_value = parent->get_whole_value(val_i->first);
2286 if (old_value.get_source() > CdlTransactionBody::inference_override) {
2291 std::set<CdlNode>::const_iterator val_j;
2292 for (val_j = deactivated.begin(); val_j != deactivated.end(); val_j++) {
2293 CdlValuable valuable = dynamic_cast<CdlValuable>(*val_j);
2294 if (0 != valuable) {
2295 const CdlValue& old_value = parent->get_whole_value(valuable);
2296 if ((old_value.get_source() > CdlTransactionBody::inference_override) && old_value.is_enabled()) {
2303 CYG_REPORT_RETVAL(result);
2307 // ----------------------------------------------------------------------------
2308 // The inference engine is considering modifying a particular valuable. If
2309 // the user has explicitly changed this valuable during the transaction then
2310 // it would be inappropriate to suggest changing it again.
2312 CdlTransactionBody::changed_by_user(CdlValuable valuable) const
2314 CYG_REPORT_FUNCNAMETYPE("CdlTransaction::changed_by_user", "result %d");
2315 CYG_REPORT_FUNCARG2XV(this, valuable);
2316 CYG_PRECONDITION_THISC();
2317 CYG_PRECONDITION_CLASSC(valuable);
2319 bool result = false;
2320 std::map<CdlValuable, CdlValue>::const_iterator change_i = changes.find(valuable);
2321 if (change_i != changes.end()) {
2322 CdlValueSource source = change_i->second.get_source();
2323 if (CdlValueSource_User == source) {
2327 if (!result && (0 != parent)) {
2328 result = parent->changed_by_user(valuable);
2331 CYG_REPORT_RETVAL(result);
2335 // ----------------------------------------------------------------------------
2336 // A variant which takes into account the hierarchy: disabling a container
2337 // when a sub-node has just been changed by the user is also a no-no.
2339 CdlTransactionBody::subnode_changed_by_user(CdlContainer container) const
2341 CYG_REPORT_FUNCNAMETYPE("CdlTransaction::subnode_changed_by_user", "result %d");
2342 CYG_REPORT_FUNCARG2XV(this, container);
2343 CYG_PRECONDITION_THISC();
2344 CYG_PRECONDITION_CLASSC(container);
2346 bool result = false;
2348 const std::vector<CdlNode>& contents = container->get_contents();
2349 std::vector<CdlNode>::const_iterator node_i;
2350 for (node_i = contents.begin(); node_i != contents.end(); node_i++) {
2351 CdlValuable valuable = dynamic_cast<CdlValuable>(*node_i);
2352 if ((0 != valuable) && this->changed_by_user(valuable)) {
2356 CdlContainer container = dynamic_cast<CdlContainer>(*node_i);
2357 if ((0 != container) && this->subnode_changed_by_user(container)) {
2363 CYG_REPORT_RETVAL(result);
2367 // ----------------------------------------------------------------------------
2368 // Is one solution preferable to another? This code assumes that
2369 // user_confirmation_required() and changed_by_user() have already
2370 // been considered, so the only issue at stake here is the changes
2373 // For now a simple metric of the number of changes is used. A more
2374 // intelligent approach would take into account how much of the
2375 // hierarchy is affected, e.g. how many other items would end
2376 // up being disabled. Arguably the calling code should be able to
2377 // supply an additional weighting.
2380 CdlTransactionBody::is_preferable_to(CdlTransaction other) const
2382 CYG_REPORT_FUNCNAMETYPE("CdlTransactionBody::preferable_to", "result %d");
2383 CYG_REPORT_FUNCARG2XV(this, other);
2384 CYG_PRECONDITION_THISC();
2385 CYG_PRECONDITION_CLASSC(other);
2386 CYG_PRECONDITIONC(this != other);
2388 bool result = false;
2389 unsigned int this_changes = this->changes.size() + this->activated.size() + this->deactivated.size();
2390 unsigned int other_changes = other->changes.size() + other->activated.size() + other->deactivated.size();
2392 if (this_changes <= other_changes) {
2396 CYG_REPORT_RETVAL(result);
2400 // ----------------------------------------------------------------------------
2401 // Applying solutions. Multiple solutions can be applied in one go. If there
2402 // is any overlap, tough. Propagation needs to happen after solutions are
2406 CdlTransactionBody::apply_solution(CdlConflict conflict)
2408 CYG_REPORT_FUNCNAME("CdlTransaction::apply_solution");
2409 CYG_REPORT_FUNCARG2XV(this, conflict);
2410 CYG_PRECONDITION_THISC();
2411 CYG_PRECONDITION_CLASSC(conflict);
2413 // The solution can be for either a per-transaction conflict
2414 // or a global one. There are two lists to search.
2415 std::list<CdlConflict>::const_iterator conf_i;
2416 conf_i = std::find(this->new_conflicts.begin(), this->new_conflicts.end(), conflict);
2417 if (conf_i == this->new_conflicts.end()) {
2418 conf_i = std::find(this->global_conflicts_with_solutions.begin(),
2419 this->global_conflicts_with_solutions.end(),
2421 CYG_ASSERTC(conf_i != this->global_conflicts_with_solutions.end());
2424 std::vector<std::pair<CdlValuable, CdlValue> >::const_iterator val_i;
2425 for (val_i = conflict->solution.begin(); val_i != conflict->solution.end(); val_i++) {
2426 CdlValuable valuable = val_i->first;
2427 CYG_LOOP_INVARIANT_CLASSC(valuable);
2429 const CdlValue& old_value = this->get_whole_value(valuable);
2430 this->set_whole_value(valuable, old_value, val_i->second);
2433 CYG_REPORT_RETURN();
2437 CdlTransactionBody::apply_solutions(const std::vector<CdlConflict>& solutions)
2439 CYG_REPORT_FUNCNAME("CdlTransaction::apply_solutions");
2440 CYG_REPORT_FUNCARG1XV(this);
2441 CYG_PRECONDITION_THISC();
2443 std::vector<CdlConflict>::const_iterator conf_i;
2444 for (conf_i = solutions.begin(); conf_i != solutions.end(); conf_i++) {
2446 std::list<CdlConflict>::const_iterator conf_j;
2447 conf_j = std::find(this->new_conflicts.begin(), this->new_conflicts.end(), conflict);
2448 if (conf_j == this->new_conflicts.end()) {
2449 conf_j = std::find(this->global_conflicts_with_solutions.begin(),
2450 this->global_conflicts_with_solutions.end(),
2452 CYG_ASSERTC(conf_j != this->global_conflicts_with_solutions.end());
2455 std::vector<std::pair<CdlValuable, CdlValue> >::const_iterator val_i;
2456 for (val_i = conflict->solution.begin(); val_i != conflict->solution.end(); val_i++) {
2457 CdlValuable valuable = val_i->first;
2458 CYG_LOOP_INVARIANT_CLASSC(valuable);
2459 const CdlValue& old_value = this->get_whole_value(valuable);
2460 this->set_whole_value(valuable, old_value, val_i->second);
2464 CYG_REPORT_RETURN();
2468 CdlTransactionBody::apply_all_solutions()
2470 CYG_REPORT_FUNCNAME("CdlTransaction::apply_all_solutions");
2471 CYG_REPORT_FUNCARG1XV(this);
2472 CYG_PRECONDITION_THISC();
2474 std::list<CdlConflict>::const_iterator conf_i;
2475 for (conf_i = this->new_conflicts.begin(); conf_i != this->new_conflicts.end(); conf_i++) {
2476 if ((*conf_i)->has_known_solution()) {
2478 std::vector<std::pair<CdlValuable, CdlValue> >::const_iterator val_i;
2479 for (val_i = conflict->solution.begin(); val_i != conflict->solution.end(); val_i++) {
2480 CdlValuable valuable = val_i->first;
2481 CYG_LOOP_INVARIANT_CLASSC(valuable);
2482 const CdlValue& old_value = this->get_whole_value(valuable);
2483 this->set_whole_value(valuable, old_value, val_i->second);
2487 for (conf_i = this->global_conflicts_with_solutions.begin();
2488 conf_i != this->global_conflicts_with_solutions.end();
2491 CYG_ASSERTC((*conf_i)->has_known_solution());
2493 std::vector<std::pair<CdlValuable, CdlValue> >::const_iterator val_i;
2494 for (val_i = conflict->solution.begin(); val_i != conflict->solution.end(); val_i++) {
2495 CdlValuable valuable = val_i->first;
2496 CYG_LOOP_INVARIANT_CLASSC(valuable);
2497 const CdlValue& old_value = this->get_whole_value(valuable);
2498 this->set_whole_value(valuable, old_value, val_i->second);
2502 CYG_REPORT_RETURN();
2508 // ----------------------------------------------------------------------------
2509 //{{{ resolve() - all per-transaction conflicts
2512 CdlTransactionBody::resolve(int level)
2514 CYG_REPORT_FUNCNAME("CdlTransaction::resolve");
2515 CYG_REPORT_FUNCARG2XV(this, level);
2516 CYG_PRECONDITION_THISC();
2519 // Resolving one conflict may affect others, so iterating down the list
2520 // is not safe. Instead we need to loop as long as there are conflicts
2521 // to be considered.
2522 std::list<CdlConflict>::iterator conf_i;
2523 for (conf_i = new_conflicts.begin(); conf_i != new_conflicts.end(); conf_i++) {
2524 CYG_LOOP_INVARIANT_CLASSC(*conf_i);
2526 // Is there any point in attempt to resolve this conflict?
2527 if ((*conf_i)->has_known_solution() ||
2528 (*conf_i)->has_no_solution() ||
2529 !(*conf_i)->resolution_implemented()) {
2532 this->resolve(*conf_i, level);
2535 if (conf_i == new_conflicts.end()) {
2540 CYG_REPORT_RETURN();
2544 //{{{ resolve() - vector
2546 // ----------------------------------------------------------------------------
2548 CdlTransactionBody::resolve(const std::vector<CdlConflict>& conflicts, int level)
2550 CYG_REPORT_FUNCNAME("CdlTransaction::resolve");
2551 CYG_REPORT_FUNCARG2XV(this, level);
2552 CYG_PRECONDITION_THISC();
2554 std::vector<CdlConflict>::const_iterator conf_i;
2555 for (conf_i = conflicts.begin(); conf_i != conflicts.end(); conf_i++) {
2556 CYG_LOOP_INVARIANT_CLASSC(*conf_i);
2558 // Is there any point in attempt to resolve this conflict?
2559 if (!(*conf_i)->has_known_solution() &&
2560 !(*conf_i)->has_no_solution() &&
2561 (*conf_i)->resolution_implemented()) {
2562 this->resolve(*conf_i, level);
2566 CYG_REPORT_RETURN();
2570 //{{{ resolve() - single conflict
2572 // ----------------------------------------------------------------------------
2573 // There is a conflict that may have a solution. The resolution
2574 // attempt needs to happen in the context of a sub-transaction
2576 // The conflict may have been created during this transaction,
2577 // or it may be a global conflict left over from a previous
2578 // transaction. This can be detected using the conflict's
2579 // transaction field. The commit() code, amongst others, needs
2580 // to handle global and per-transaction conflicts differently.
2583 CdlTransactionBody::resolve(CdlConflict conflict, int level)
2585 CYG_REPORT_FUNCNAME("CdlTransaction::resolve");
2586 CYG_REPORT_FUNCARG3XV(this, conflict, level);
2587 CYG_PRECONDITION_THISC();
2588 CYG_PRECONDITION_CLASSC(conflict);
2589 CYG_PRECONDITIONC(0 == conflict->solution.size());
2590 CYG_PRECONDITIONC((0 <= level) && (level <= inference_recursion_limit));
2592 CdlTransaction sub_transaction = this->make(conflict);
2593 CYG_PRECONDITION_CLASSC(sub_transaction);
2594 if (!conflict->inner_resolve(sub_transaction, level)) {
2595 CYG_ASSERTC(0 == sub_transaction->changes.size());
2596 sub_transaction->cancel();
2597 delete sub_transaction;
2598 conflict->no_solution = true;
2599 CYG_REPORT_RETURN();
2602 // Is the inference engine lying? The conflict should be resolved
2603 // in the sub-transaction.
2604 if (conflict->is_structural()) {
2605 if (std::find(sub_transaction->deleted_structural_conflicts.begin(),
2606 sub_transaction->deleted_structural_conflicts.end(),
2607 conflict) == sub_transaction->deleted_structural_conflicts.end()) {
2609 CYG_FAIL("The inference engine has proved too optimistic.");
2610 sub_transaction->cancel();
2611 delete sub_transaction;
2612 conflict->no_solution = true;
2613 CYG_REPORT_RETURN();
2617 if (std::find(sub_transaction->deleted_conflicts.begin(), sub_transaction->deleted_conflicts.end(), conflict)
2618 == sub_transaction->deleted_conflicts.end()) {
2620 CYG_FAIL("The inference engine has proved too optimistic.");
2621 sub_transaction->cancel();
2622 delete sub_transaction;
2623 conflict->no_solution = true;
2624 CYG_REPORT_RETURN();
2629 // Even if there is a solution it cannot always be applied
2630 // automatically because that would affect existing user
2631 // values. Instead the solution needs to be saved so that
2632 // the user can inspect it later. This should only happen
2633 // at level 0. If we have recursed into the inference
2634 // engine then we should only worry about this right at
2635 // the end, not at every stage (although internally the
2636 // inference code may worry about this when choosing
2637 // between alternatives).
2638 if ((0 == level) && sub_transaction->user_confirmation_required()) {
2639 sub_transaction->save_solution();
2640 sub_transaction->cancel();
2641 delete sub_transaction;
2644 if (0 == conflict->transaction) {
2645 // This is a global conflict, not a per-transaction one.
2646 // There is a separate list of these conflicts.
2647 std::list<CdlConflict>::const_iterator conf_i;
2648 conf_i = std::find(this->global_conflicts_with_solutions.begin(),
2649 this->global_conflicts_with_solutions.end(),
2651 if (conf_i == this->global_conflicts_with_solutions.end()) {
2652 this->global_conflicts_with_solutions.push_back(conflict);
2657 // This sub-transaction is safe, it can be applied
2658 // immediately. The commit code detects that the
2659 // solution being committed is for a particular
2660 // resolved conflict and will take care of moving that
2661 // conflict to the resolved list.
2662 conflict->solution_references.clear(); // No point in preserving this information
2663 conflict->no_solution = false; // Redundant
2664 std::map<CdlValuable, CdlValue>::const_iterator soln_i;
2665 for (soln_i = sub_transaction->changes.begin(); soln_i != sub_transaction->changes.end(); soln_i++) {
2666 conflict->solution.push_back(*soln_i);
2668 sub_transaction->commit();
2669 delete sub_transaction;
2672 CYG_REPORT_RETURN();
2676 //{{{ resolve_recursion()
2678 // ----------------------------------------------------------------------------
2679 // resolve_recursion()
2681 // The inference engine has tried one or more changes in the context of
2682 // a sub-transaction. It is now necessary to check whether these changes
2683 // are beneficial, i.e. whether or not any new problems are introduced
2684 // that cannot be resolved.
2686 CdlTransactionBody::resolve_recursion(int level)
2688 CYG_REPORT_FUNCNAMETYPE("CdlTransaction::resolve_recursion", "result %d");
2689 CYG_REPORT_FUNCARG2XV(this, level);
2690 CYG_PRECONDITION_THISC();
2692 bool result = false;
2694 if (0 == new_conflicts.size()) {
2696 CYG_REPORT_RETVAL(result);
2699 if (level >= inference_recursion_limit) {
2701 CYG_REPORT_RETVAL(result);
2705 // There are new conflicts, but it may be possible to resolve them
2706 // by a recursive invocation of the inference engine.
2707 bool solutions_possible = false;
2709 this->resolve(level + 1);
2710 std::list<CdlConflict>::const_iterator conf_i;
2711 solutions_possible = false;
2712 for (conf_i = this->new_conflicts.begin(); conf_i != this->new_conflicts.end(); conf_i++) {
2713 if (!(*conf_i)->has_no_solution()) {
2714 solutions_possible = true;
2717 } while(solutions_possible);
2719 result = (0 == new_conflicts.size());
2720 CYG_REPORT_RETVAL(result);
2729 // ----------------------------------------------------------------------------
2730 // The majority of transactions involve the same set of steps. First one
2731 // or more values are modified. Then there has to be propagation, inference,
2732 // an inference callback, ... There may be a number of iterations. It is
2733 // convenient to have a single transaction body function which takes care
2736 // If automatic inference is disabled then life is pretty simple, there
2737 // should be one propagate() operation followed by a commit.
2739 // If automatic inference is enabled but there is no inference callback
2740 // then we need a loop consisting of propagation and inference, while
2741 // progress is made. Progress can be detected by value changes.
2743 // If there is an inference callback then life gets pretty complicated.
2744 // The problem is figuring out exactly when the inference callback
2745 // should be invoked:
2747 // 1) any new conflicts should certainly result in a callback, to give
2748 // the user a chance to cancel the changes.
2749 // 2) any new solutions that have been applied automatically need to
2750 // be shown to the user, again so that it is possible to cancel
2752 // 3) any existing conflicts with a new solution, albeit one that cannot
2753 // be applied automatically, should result in a callback. This is
2754 // somewhat problematical since the new solution may in fact be
2755 // identical to a previous one that the user has already decided
2756 // against committing.
2758 // It is not easy to keep track of when new conflicts or solutions get
2759 // added to a transaction. Simply counting the entries in the
2760 // appropriate STL containers is insufficient, as conflicts come and
2761 // go. Instead it is necessary to have a "dirty" flag. Unfortunately
2762 // this too is not fool-proof: a new conflict may have been created,
2763 // resulting in the dirty flag being set, and then the conflict may
2764 // have disappeared.
2767 CdlTransactionBody::body()
2769 CYG_REPORT_FUNCNAME("CdlTransaction::body");
2770 CYG_REPORT_FUNCARG1XV(this);
2771 CYG_PRECONDITION_THISC();
2773 // The Body() member function can only be applied to a toplevel
2774 // transaction, it does not really make sense to apply it to
2775 // a sub-transaction (at least, not yet);
2776 CYG_PRECONDITIONC((0 == parent) && (0 != toplevel));
2778 if (!inference_enabled) {
2781 CYG_REPORT_RETURN();
2785 if (0 == inference_callback) {
2786 bool progress = false;
2790 CYG_LOOP_INVARIANTC(0 == value_changes.size());
2792 if (0 != value_changes.size()) {
2798 CYG_REPORT_RETURN();
2802 bool cancel = false;
2804 unsigned int resolved_size = 0;
2805 unsigned int globals_with_solutions_size = 0;
2808 bool progress = false;
2812 CYG_LOOP_INVARIANTC(0 == value_changes.size());
2814 if (0 != value_changes.size()) {
2819 // Sanity check: if there are no conflicts and no new entries in
2820 // the resolved vector, then stop here. The user has already seen
2821 // and taken care of everything of interest.
2822 if ((0 == new_conflicts.size()) &&
2823 (resolved_size == resolved_conflicts.size()) &&
2824 (globals_with_solutions_size == global_conflicts_with_solutions.size())) {
2829 // Also, if no conflicts have been added, no new solutions
2830 // have been identified, and no new solutions have been applied,
2831 // then there is no point in asking for user feedback.
2837 // Clear state before invoking the callback. If the user does not
2838 // change anything else then we should get out of the loop next
2840 this->dirty = false;
2841 resolved_size = resolved_conflicts.size();
2842 globals_with_solutions_size = global_conflicts_with_solutions.size();
2844 // Invoke the callback. If the result is cancel, do so. Otherwise
2845 // we need to spin while things are changing.
2846 if (CdlInferenceCallbackResult_Cancel == (*inference_callback)(this)) {
2857 CYG_REPORT_RETURN();