]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - tools/src/libcdl/transact.cxx
Initial revision
[karo-tx-redboot.git] / tools / src / libcdl / transact.cxx
1 //{{{  Banner                                   
2
3 //============================================================================
4 //
5 //      transaction.cxx
6 //
7 //      Implementation of the CdlTransaction class
8 //
9 //============================================================================
10 //####COPYRIGHTBEGIN####
11 //                                                                          
12 // ----------------------------------------------------------------------------
13 // Copyright (C) 1999, 2000, 2001, 2002 Red Hat, Inc.
14 //
15 // This file is part of the eCos host tools.
16 //
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) 
20 // any later version.
21 // 
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 
25 // more details.
26 // 
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.
30 //
31 // ----------------------------------------------------------------------------
32 //                                                                          
33 //####COPYRIGHTEND####
34 //============================================================================
35 //#####DESCRIPTIONBEGIN####
36 //
37 // Author(s):   bartv
38 // Contact(s):  bartv
39 // Date:        1999/07/16
40 // Version:     0.01
41 //
42 //####DESCRIPTIONEND####
43 //============================================================================
44
45 //}}}
46 //{{{  #include's                               
47
48 // ----------------------------------------------------------------------------
49 #include "cdlconfig.h"
50
51 // Get the infrastructure types, assertions, tracing and similar
52 // facilities.
53 #include <cyg/infra/cyg_ass.h>
54 #include <cyg/infra/cyg_trac.h>
55
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>
60
61 //}}}
62
63 //{{{  CdlTransactionCallback class             
64
65 // ----------------------------------------------------------------------------
66 // The callback class is very straightforward. The hard work is done in
67 // the transaction class.
68
69 CdlTransactionCallback::CdlTransactionCallback(CdlTransaction transact_arg)
70 {
71     CYG_REPORT_FUNCNAME("CdlTransactionCallback:: constructor");
72     CYG_REPORT_FUNCARG2XV(this, transact_arg);
73     CYG_PRECONDITION_CLASSC(transact_arg);
74     
75     // The vectors etc. will take care of themselves.
76     transact = transact_arg;
77     cdltransactioncallback_cookie = CdlTransactionCallback_Magic;
78     
79     CYG_POSTCONDITION_THISC();
80     CYG_REPORT_RETURN();
81 }
82
83 CdlTransactionCallback::~CdlTransactionCallback()
84 {
85     CYG_REPORT_FUNCNAME("CdlTransactionCallback:: destructor");
86     CYG_REPORT_FUNCARG1XV(this);
87     CYG_PRECONDITION_THISC();
88
89     cdltransactioncallback_cookie = CdlTransactionCallback_Invalid;
90     transact = 0;
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();
99     
100     CYG_REPORT_RETURN();
101 }
102
103 void
104 CdlTransactionCallback::set_callback_fn(void (*fn)(const CdlTransactionCallback&))
105 {
106     CYG_REPORT_FUNCNAME("CdlTransactionCallback::set_callback_fn");
107     CYG_REPORT_FUNCARG1XV(fn);
108
109     CdlTransactionBody::set_callback_fn(fn);
110
111     CYG_REPORT_RETURN();
112 }
113
114 void (*CdlTransactionCallback::get_callback_fn())(const CdlTransactionCallback&)
115 {
116     CYG_REPORT_FUNCNAMETYPE("CdlTransactionCallback::get_callback_fn", "result %p");
117
118     void (*result)(const CdlTransactionCallback&) = CdlTransactionBody::get_callback_fn();
119     
120     CYG_REPORT_RETVAL(result);
121     return result;
122 }
123
124 CdlTransaction
125 CdlTransactionCallback::get_transaction() const
126 {
127     CYG_REPORT_FUNCNAMETYPE("CdlTransactionCallback::get_transaction", "result %p");
128     CYG_PRECONDITION_THISC();
129
130     CdlTransaction result = transact;
131     CYG_POSTCONDITION_CLASSC(result);
132
133     CYG_REPORT_RETVAL(result);
134     return result;
135 }
136
137 CdlToplevel
138 CdlTransactionCallback::get_toplevel() const
139 {
140     CYG_REPORT_FUNCNAMETYPE("CdlTransactionCallback::get_toplevel", "result %p");
141     CYG_PRECONDITION_THISC();
142
143     CdlToplevel result = transact->get_toplevel();
144     CYG_POSTCONDITION_CLASSC(result);
145
146     CYG_REPORT_RETVAL(result);
147     return result;
148 }
149
150 bool
151 CdlTransactionCallback::check_this(cyg_assert_class_zeal zeal) const
152 {
153     if (CdlTransactionCallback_Magic != cdltransactioncallback_cookie) {
154         return false;
155     }
156     return true;
157 }
158
159 //}}}
160 //{{{  CdlTransaction statics                   
161
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);
169
170 //}}}
171 //{{{  Transaction creation and destruction     
172
173 // ----------------------------------------------------------------------------
174 CdlTransaction
175 CdlTransactionBody::make(CdlToplevel toplevel)
176 {
177     CYG_REPORT_FUNCNAMETYPE("CdlTransaction::make", "result %p");
178     CYG_REPORT_FUNCARG1XV(toplevel);
179     CYG_PRECONDITION_CLASSC(toplevel);
180     CYG_PRECONDITIONC(0 == toplevel->transaction);
181     
182     CdlTransaction result = new CdlTransactionBody(toplevel, 0, 0);
183     toplevel->transaction = result;
184
185     CYG_REPORT_RETVAL(result);
186     return result;
187 }
188
189 CdlTransaction
190 CdlTransactionBody::make(CdlConflict conflict)
191 {
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);
196
197     CdlTransaction result = new CdlTransactionBody(0, this, conflict);
198
199     CYG_REPORT_RETVAL(result);
200     return result;
201 }
202     
203 CdlTransactionBody::CdlTransactionBody(CdlToplevel toplevel_arg, CdlTransaction parent_arg, CdlConflict conflict_arg)
204 {
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)));
211
212     // The containers will take care of themselves, as will all_changes
213     toplevel    = toplevel_arg;
214     parent      = parent_arg;
215     conflict    = conflict_arg;
216     dirty       = false;
217     cdltransactionbody_cookie   = CdlTransactionBody_Magic;
218     CYGDBG_MEMLEAK_CONSTRUCTOR();
219     
220     CYG_POSTCONDITION_THISC();
221     CYG_REPORT_RETURN();
222 }
223
224 // ----------------------------------------------------------------------------
225 CdlTransactionBody::~CdlTransactionBody()
226 {
227     CYG_REPORT_FUNCNAME("CdlTransaction:: destructor");
228     CYG_REPORT_FUNCARG1XV(this);
229     CYG_PRECONDITION_THISC();
230
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());
246     
247     // If this was a toplevel transaction, the toplevel knows
248     // about the transaction.
249     if (0 != toplevel) {
250         CYG_ASSERTC(toplevel->transaction == this);
251         toplevel->transaction = 0;
252     }
253     cdltransactionbody_cookie   = CdlTransactionBody_Invalid;
254     toplevel    = 0;
255     parent      = 0;
256     conflict    = 0;
257     dirty       = false;
258
259     CYGDBG_MEMLEAK_DESTRUCTOR();
260
261     CYG_REPORT_RETURN();
262 }
263
264 //}}}
265 //{{{  check_this()                             
266
267 // ----------------------------------------------------------------------------
268
269 bool
270 CdlTransactionBody::check_this(cyg_assert_class_zeal zeal) const
271 {
272     if (CdlTransactionBody_Magic != cdltransactionbody_cookie) {
273         return false;
274     }
275     CYGDBG_MEMLEAK_CHECKTHIS();
276
277     //zeal = cyg_extreme;
278     switch(zeal) {
279       case cyg_system_test:
280       case cyg_extreme :
281       {
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)) {
285                   return false;
286               }
287           }
288
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)) {
292                   return false;
293               }
294           }
295           for (conf_i = new_structural_conflicts.begin(); conf_i != new_structural_conflicts.end(); conf_i++) {
296               if (!(*conf_i)->check_this(cyg_quick)) {
297                   return false;
298               }
299           }
300
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)) {
304                   return false;
305               }
306           }
307           for (conf_i2 = resolved_conflicts.begin(); conf_i2 != resolved_conflicts.end(); conf_i2++) {
308               if (!(*conf_i2)->check_this(cyg_quick)) {
309                   return false;
310               }
311           }
312           for (conf_i2 = deleted_structural_conflicts.begin(); conf_i2 != deleted_structural_conflicts.end(); conf_i2++) {
313               if (!(*conf_i2)->check_this(cyg_quick)) {
314                   return false;
315               }
316           }
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)) {
319                   return false;
320               }
321               if (0 != (*conf_i)->transaction) {
322                   return false;
323               }
324           }
325           
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)) {
330                   return false;
331               }
332               if (deactivated.end() != deactivated.find(*node_i)) {
333                   return false;
334               }
335           }
336           for (node_i = deactivated.begin(); node_i != deactivated.end(); node_i++) {
337               if (!(*node_i)->check_this(cyg_quick)) {
338                   return false;
339               }
340               if (activated.end() != activated.find(*node_i)) {
341                   return false;
342               }
343           }
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)) {
347                   return false;
348               }
349           }
350           
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)) {
354                   return false;
355               }
356           }
357           
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)) {
361                   return false;
362               }
363           }
364       }
365       case cyg_thorough:
366           if ((0 != toplevel) && !toplevel->check_this(cyg_quick)) {
367               return false;
368           }
369           if ((0 != parent) && !parent->check_this(cyg_quick)) {
370               return false;
371           }
372           if ((0 != conflict) && !conflict->check_this(cyg_quick)) {
373               return false;
374           }
375               
376       case cyg_quick:
377       case cyg_trivial :
378           if ((0 == toplevel) && (0 == parent)) {
379               return false;
380           }
381           if (this == parent) {
382               return false;
383           }
384           
385       case cyg_none :
386         break;
387     }
388
389     return true;
390 }
391
392 //}}}
393 //{{{  Misc                                     
394
395 // ----------------------------------------------------------------------------
396 CdlToplevel
397 CdlTransactionBody::get_toplevel() const
398 {
399     CYG_REPORT_FUNCNAMETYPE("CdlTransaction::get_toplevel", "result %p");
400     CYG_REPORT_FUNCARG1XV(this);
401     CYG_PRECONDITION_THISC();
402
403     CdlToplevel result = toplevel;
404     
405     CYG_REPORT_RETVAL(result);
406     return result;
407 }
408
409 CdlTransaction
410 CdlTransactionBody::get_parent() const
411 {
412     CYG_REPORT_FUNCNAMETYPE("CdlTransaction::get_parent", "result %p");
413     CYG_REPORT_FUNCARG1XV(this);
414     CYG_PRECONDITION_THISC();
415
416     CdlTransaction result = parent;
417
418     CYG_REPORT_RETVAL(result);
419     return result;
420 }
421
422 CdlConflict
423 CdlTransactionBody::get_conflict() const
424 {
425     CYG_REPORT_FUNCNAMETYPE("CdlTransaction::get_conflict", "result %p");
426     CYG_REPORT_FUNCARG1XV(this);
427     CYG_PRECONDITION_THISC();
428
429     CdlConflict result = conflict;
430
431     CYG_REPORT_RETVAL(result);
432     return result;
433 }
434
435
436 // ----------------------------------------------------------------------------
437 void (*CdlTransactionBody::get_callback_fn())(const CdlTransactionCallback&)
438 {
439     CYG_REPORT_FUNCNAMETYPE("CdlTransaction::get_callback_fn", "result %p");
440
441     void (*result)(const CdlTransactionCallback&) = callback_fn;
442
443     CYG_REPORT_RETVAL(result);
444     return result;
445 }
446
447 void
448 CdlTransactionBody::set_callback_fn(void (*fn)(const CdlTransactionCallback&))
449 {
450     CYG_REPORT_FUNCNAME("CdlTransaction::set_callback_fn");
451     CYG_REPORT_FUNCARG1XV(fn);
452
453     callback_fn = fn;
454
455     CYG_REPORT_RETURN();
456 }
457
458 CdlInferenceCallback
459 CdlTransactionBody::get_inference_callback_fn()
460 {
461     CYG_REPORT_FUNCNAMETYPE("CdlTransaction::get_inference_callback_fn", "result %p");
462
463     CdlInferenceCallback result = inference_callback;
464
465     CYG_REPORT_RETVAL(result);
466     return result;
467 }
468
469 void
470 CdlTransactionBody::set_inference_callback_fn(CdlInferenceCallback fn)
471 {
472     CYG_REPORT_FUNCNAME("CdlTransaction::set_inference_callback");
473     CYG_REPORT_FUNCARG1XV(fn);
474
475     inference_callback = fn;
476
477     CYG_REPORT_RETURN();
478 }
479
480 void
481 CdlTransactionBody::enable_automatic_inference()
482 {
483     CYG_REPORT_FUNCNAME("CdlTransaction::enable_automatic_inference");
484
485     inference_enabled = true;
486     
487     CYG_REPORT_RETURN();
488 }
489
490 void
491 CdlTransactionBody::disable_automatic_inference()
492 {
493     CYG_REPORT_FUNCNAME("CdlTransaction::disable_automatic_inference");
494
495     inference_enabled = false;
496
497     CYG_REPORT_RETURN();
498 }
499
500 bool
501 CdlTransactionBody::is_automatic_inference_enabled()
502 {
503     CYG_REPORT_FUNCNAMETYPE("CdlTransaction::is_automatic_inference_enabled", "result %d");
504
505     bool result = inference_enabled;
506
507     CYG_REPORT_RETVAL(result);
508     return result;
509 }
510
511 void
512 CdlTransactionBody::set_inference_recursion_limit(int limit)
513 {
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
518     
519     inference_recursion_limit = limit;
520
521     CYG_REPORT_RETURN();
522 }
523
524 int
525 CdlTransactionBody::get_inference_recursion_limit()
526 {
527     CYG_REPORT_FUNCNAMETYPE("CdlTransaction::get_inference_recursion_limit", "result %d");
528
529     int result = inference_recursion_limit;
530
531     CYG_REPORT_RETVAL(result);
532     return result;
533 }
534
535 void
536 CdlTransactionBody::set_inference_override(CdlValueSource source)
537 {
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));
541     
542     inference_override = source;
543
544     CYG_REPORT_RETURN();
545 }
546
547 CdlValueSource
548 CdlTransactionBody::get_inference_override()
549 {
550     CYG_REPORT_FUNCNAMETYPE("CdlTransaction::get_inference_override", "result %d");
551
552     CdlValueSource result = inference_override;
553
554     CYG_REPORT_RETVAL((int) result);
555     return result;
556 }
557
558 //}}}
559 //{{{  Value access and updates                 
560
561 // ----------------------------------------------------------------------------
562 const CdlValue&
563 CdlTransactionBody::get_whole_value(CdlConstValuable valuable_arg) const
564 {
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);
569
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);
573
574     // If we are trying to find a solution, keep track of all valuables
575     // that were accessed.
576     const CdlValue* result = 0;
577     if (0 != conflict) {
578         conflict->solution_references.insert(valuable);
579     }
580     
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));
587     } else {
588         result = &(valuable->get_whole_value());
589     }
590         
591     CYG_REPORT_RETVAL(result);
592     return *result;
593 }
594
595 void
596 CdlTransactionBody::set_whole_value(CdlValuable valuable, const CdlValue& old_value, const CdlValue& new_value)
597 {
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);
605
606     CdlValueFlavor flavor = old_value.get_flavor();
607     CYG_ASSERTC(flavor == new_value.get_flavor());
608     CYG_ASSERTC(CdlValueFlavor_None != flavor);
609     
610     bool value_changed = false;
611     bool bool_changed  = false;
612     
613     if ((CdlValueFlavor_Bool == flavor) || (CdlValueFlavor_BoolData == flavor)) {
614         if (old_value.is_enabled() != new_value.is_enabled()) {
615             value_changed = true;
616             bool_changed  = true;
617         }
618     }
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;
622         }
623     }
624     if (value_changed) {
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);
629         }
630     }
631                                                                               
632     // Actually do the update. This may modify old_value, so has to be
633     // left to the end.
634     changes[valuable] = new_value;
635
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);
644         }
645     }
646     
647     CYG_REPORT_RETURN();
648 }
649
650 const std::map<CdlValuable, CdlValue>&
651 CdlTransactionBody::get_changes() const
652 {
653     CYG_REPORT_FUNCNAME("CdlTransaction::get_changes");
654     CYG_REPORT_FUNCARG1XV(this);
655     CYG_PRECONDITION_THISC();
656
657     CYG_REPORT_RETURN();
658     return changes;
659 }
660
661 //}}}
662 //{{{  Active access and updates                
663
664 // ----------------------------------------------------------------------------
665 // Nodes can become active or inactive during transactions, and this affects
666 // propagation and expression evaluation
667
668 bool
669 CdlTransactionBody::is_active(CdlNode node) const
670 {
671     CYG_REPORT_FUNCNAMETYPE("CdlTransaction::is_active", "result %d");
672     CYG_REPORT_FUNCARG2XV(this, node);
673     CYG_PRECONDITION_THISC();
674     CYG_PRECONDITION_CLASSC(node);
675
676     bool result = false;
677     if (activated.end() != activated.find(node)) {
678         result = true;
679     } else if (deactivated.end() != deactivated.find(node)) {
680         result = false;
681     } else if (0 != parent) {
682         result = parent->is_active(node);
683     } else {
684         result = node->is_active();
685     }
686
687     CYG_REPORT_RETVAL(result);
688     return result;
689 }
690
691 void
692 CdlTransactionBody::set_active(CdlNode node, bool state)
693 {
694     CYG_REPORT_FUNCNAME("CdlTransaction::set_active");
695     CYG_REPORT_FUNCARG3XV(this, node, state);
696     CYG_PRECONDITION_THISC();
697     CYG_PRECONDITION_CLASSC(node);
698
699     if (state) {
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);
704         }
705     } else {
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);
710         }
711     }
712     active_changes.push_back(node);
713
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);
721         }
722     }
723         
724     CYG_REPORT_RETURN();
725 }
726
727 //}}}
728 //{{{  Conflict access and updates              
729
730 //{{{  get_conflict() etc.                      
731
732 // ----------------------------------------------------------------------------
733 bool
734 CdlTransactionBody::has_conflict(CdlNode node, bool (*pFn)(CdlConflict))
735 {
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);
740
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
744     // appropriate.
745     bool result = false;
746     std::list<CdlConflict>::const_iterator conf_i;
747     CdlTransaction current_transaction = this;
748     CdlToplevel    toplevel            = this->toplevel;
749     do {
750         CYG_LOOP_INVARIANT_CLASSC(current_transaction);
751         
752         for (conf_i = current_transaction->new_conflicts.begin();
753              conf_i != current_transaction->new_conflicts.end();
754              conf_i++) {
755
756             if ((node == (*conf_i)->get_node()) &&
757                 !(this->has_conflict_been_cleared(*conf_i)) && (*pFn)(*conf_i)) {
758                 result = true;
759                 break;
760             }
761         }
762             
763         toplevel            = current_transaction->toplevel;
764         current_transaction = current_transaction->parent;
765     } while (!result && (0 != current_transaction));
766
767     if (!result) {
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)) {
771                 result = true;
772                 break;
773             }
774         }
775     }
776
777     CYG_REPORT_RETVAL(result);
778     return result;
779 }
780
781 CdlConflict
782 CdlTransactionBody::get_conflict(CdlNode node, bool (*pFn)(CdlConflict))
783 {
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);
788
789     CdlConflict result = 0;
790     std::list<CdlConflict>::const_iterator conf_i;
791     CdlTransaction current_transaction = this;
792     CdlToplevel    toplevel            = this->toplevel;
793     do {
794         CYG_LOOP_INVARIANT_CLASSC(current_transaction);
795         
796         for (conf_i = current_transaction->new_conflicts.begin();
797              conf_i != current_transaction->new_conflicts.end();
798              conf_i++) {
799
800             if ((node == (*conf_i)->get_node()) &&
801                 !(this->has_conflict_been_cleared(*conf_i)) && (*pFn)(*conf_i)) {
802                 result = *conf_i;
803                 break;
804             }
805         }
806             
807         toplevel            = current_transaction->toplevel;
808         current_transaction = current_transaction->parent;
809     } while ((0 == result) && (0 != current_transaction));
810
811     if (0 == result) {
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)) {
815                 result = *conf_i;
816                 break;
817             }
818         }
819     }
820
821     CYG_REPORT_RETVAL(result);
822     return result;
823 }
824
825 void
826 CdlTransactionBody::get_conflicts(CdlNode node, bool (*pFn)(CdlConflict), std::vector<CdlConflict>& result)
827 {
828     CYG_REPORT_FUNCNAME("CdlTransaction::get_conflicts");
829     CYG_REPORT_FUNCARG3XV(this, node, pFn);
830     CYG_PRECONDITION_THISC();
831     CYG_PRECONDITION_CLASSC(node);
832
833     std::list<CdlConflict>::const_iterator conf_i;
834     CdlTransaction current_transaction = this;
835     CdlToplevel    toplevel            = this->toplevel;
836     do {
837         CYG_LOOP_INVARIANT_CLASSC(current_transaction);
838         
839         for (conf_i = current_transaction->new_conflicts.begin();
840              conf_i != current_transaction->new_conflicts.end();
841              conf_i++) {
842
843             if ((node == (*conf_i)->get_node()) &&
844                 !(this->has_conflict_been_cleared(*conf_i)) && (*pFn)(*conf_i)) {
845                 result.push_back(*conf_i);
846             }
847         }
848             
849         toplevel            = current_transaction->toplevel;
850         current_transaction = current_transaction->parent;
851     } while (0 != current_transaction);
852
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);
857         }
858     }
859
860     CYG_REPORT_RETURN();
861 }
862
863 bool
864 CdlTransactionBody::has_conflict(CdlNode node, CdlProperty prop, bool (*pFn)(CdlConflict))
865 {
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);
871     
872     bool result = false;
873     std::list<CdlConflict>::const_iterator conf_i;
874     CdlTransaction current_transaction = this;
875     CdlToplevel    toplevel            = this->toplevel;
876     do {
877         CYG_LOOP_INVARIANT_CLASSC(current_transaction);
878         
879         for (conf_i = current_transaction->new_conflicts.begin();
880              conf_i != current_transaction->new_conflicts.end();
881              conf_i++) {
882
883             if ((node == (*conf_i)->get_node()) && (prop == (*conf_i)->get_property()) &&
884                 !(this->has_conflict_been_cleared(*conf_i)) && (*pFn)(*conf_i)) {
885                 
886                 result = true;
887                 break;
888             }
889         }
890             
891         toplevel            = current_transaction->toplevel;
892         current_transaction = current_transaction->parent;
893     } while (!result && (0 != current_transaction));
894
895     if (!result) {
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)) {
900                 
901                 result = true;
902                 break;
903             }
904         }
905     }
906
907     CYG_REPORT_RETVAL(result);
908     return result;
909 }
910
911 CdlConflict
912 CdlTransactionBody::get_conflict(CdlNode node, CdlProperty prop, bool (*pFn)(CdlConflict))
913 {
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);
919
920     CdlConflict result = 0;
921     std::list<CdlConflict>::const_iterator conf_i;
922     CdlTransaction current_transaction = this;
923     CdlToplevel    toplevel            = this->toplevel;
924     do {
925         CYG_LOOP_INVARIANT_CLASSC(current_transaction);
926         
927         for (conf_i = current_transaction->new_conflicts.begin();
928              conf_i != current_transaction->new_conflicts.end();
929              conf_i++) {
930
931             if ((node == (*conf_i)->get_node()) && (prop == (*conf_i)->get_property()) &&
932                 !(this->has_conflict_been_cleared(*conf_i)) && (*pFn)(*conf_i)) {
933                 result = *conf_i;
934                 break;
935             }
936         }
937             
938         toplevel            = current_transaction->toplevel;
939         current_transaction = current_transaction->parent;
940     } while ((0 == result) && (0 != current_transaction));
941
942     if (0 == result) {
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)) {
947                 
948                 result = *conf_i;
949                 break;
950             }
951         }
952     }
953
954     CYG_REPORT_RETVAL(result);
955     return result;
956 }
957
958 void
959 CdlTransactionBody::get_conflicts(CdlNode node, CdlProperty prop, bool (*pFn)(CdlConflict), std::vector<CdlConflict>& result)
960 {
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);
966
967     std::list<CdlConflict>::const_iterator conf_i;
968     CdlTransaction current_transaction = this;
969     CdlToplevel    toplevel            = this->toplevel;
970     do {
971         CYG_LOOP_INVARIANT_CLASSC(current_transaction);
972         
973         for (conf_i = current_transaction->new_conflicts.begin();
974              conf_i != current_transaction->new_conflicts.end();
975              conf_i++) {
976
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);
980             }
981         }
982             
983         toplevel            = current_transaction->toplevel;
984         current_transaction = current_transaction->parent;
985     } while (0 != current_transaction);
986
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)) {
991             
992             result.push_back(*conf_i);
993         }
994     }
995
996     CYG_REPORT_RETURN();
997 }
998
999 //}}}
1000 //{{{  get_structural_conflict() etc            
1001
1002 // ----------------------------------------------------------------------------
1003 bool
1004 CdlTransactionBody::has_structural_conflict(CdlNode node, bool (*pFn)(CdlConflict))
1005 {
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);
1010
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
1014     // appropriate.
1015     bool result = false;
1016     std::list<CdlConflict>::const_iterator conf_i;
1017     CdlTransaction current_transaction = this;
1018     CdlToplevel    toplevel            = this->toplevel;
1019     do {
1020         CYG_LOOP_INVARIANT_CLASSC(current_transaction);
1021         
1022         for (conf_i = current_transaction->new_structural_conflicts.begin();
1023              conf_i != current_transaction->new_structural_conflicts.end();
1024              conf_i++) {
1025
1026             if ((node == (*conf_i)->get_node()) &&
1027                 !(this->has_conflict_been_cleared(*conf_i)) && (*pFn)(*conf_i)) {
1028                 result = true;
1029                 break;
1030             }
1031         }
1032             
1033         toplevel            = current_transaction->toplevel;
1034         current_transaction = current_transaction->parent;
1035     } while (!result && (0 != current_transaction));
1036
1037     if (!result) {
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)) {
1041                 result = true;
1042                 break;
1043             }
1044         }
1045     }
1046
1047     CYG_REPORT_RETVAL(result);
1048     return result;
1049 }
1050
1051 CdlConflict
1052 CdlTransactionBody::get_structural_conflict(CdlNode node, bool (*pFn)(CdlConflict))
1053 {
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);
1058
1059     CdlConflict result = 0;
1060     std::list<CdlConflict>::const_iterator conf_i;
1061     CdlTransaction current_transaction = this;
1062     CdlToplevel    toplevel            = this->toplevel;
1063     do {
1064         CYG_LOOP_INVARIANT_CLASSC(current_transaction);
1065         
1066         for (conf_i = current_transaction->new_structural_conflicts.begin();
1067              conf_i != current_transaction->new_structural_conflicts.end();
1068              conf_i++) {
1069
1070             if ((node == (*conf_i)->get_node()) &&
1071                 !(this->has_conflict_been_cleared(*conf_i)) && (*pFn)(*conf_i)) {
1072                 result = *conf_i;
1073                 break;
1074             }
1075         }
1076             
1077         toplevel            = current_transaction->toplevel;
1078         current_transaction = current_transaction->parent;
1079     } while ((0 == result) && (0 != current_transaction));
1080
1081     if (0 == result) {
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)) {
1085                 result = *conf_i;
1086                 break;
1087             }
1088         }
1089     }
1090
1091     CYG_REPORT_RETVAL(result);
1092     return result;
1093 }
1094
1095 void
1096 CdlTransactionBody::get_structural_conflicts(CdlNode node, bool (*pFn)(CdlConflict), std::vector<CdlConflict>& result)
1097 {
1098     CYG_REPORT_FUNCNAME("CdlTransaction::get_structural_conflicts");
1099     CYG_REPORT_FUNCARG3XV(this, node, pFn);
1100     CYG_PRECONDITION_THISC();
1101     CYG_PRECONDITION_CLASSC(node);
1102
1103     std::list<CdlConflict>::const_iterator conf_i;
1104     CdlTransaction current_transaction = this;
1105     CdlToplevel    toplevel            = this->toplevel;
1106     do {
1107         CYG_LOOP_INVARIANT_CLASSC(current_transaction);
1108         
1109         for (conf_i = current_transaction->new_structural_conflicts.begin();
1110              conf_i != current_transaction->new_structural_conflicts.end();
1111              conf_i++) {
1112
1113             if ((node == (*conf_i)->get_node()) &&
1114                 !(this->has_conflict_been_cleared(*conf_i)) && (*pFn)(*conf_i)) {
1115                 result.push_back(*conf_i);
1116             }
1117         }
1118             
1119         toplevel            = current_transaction->toplevel;
1120         current_transaction = current_transaction->parent;
1121     } while (0 != current_transaction);
1122
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);
1127         }
1128     }
1129
1130     CYG_REPORT_RETURN();
1131 }
1132
1133 bool
1134 CdlTransactionBody::has_structural_conflict(CdlNode node, CdlProperty prop, bool (*pFn)(CdlConflict))
1135 {
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);
1141
1142     bool result = false;
1143     std::list<CdlConflict>::const_iterator conf_i;
1144     CdlTransaction current_transaction = this;
1145     CdlToplevel    toplevel            = this->toplevel;
1146     do {
1147         CYG_LOOP_INVARIANT_CLASSC(current_transaction);
1148         
1149         for (conf_i = current_transaction->new_structural_conflicts.begin();
1150              conf_i != current_transaction->new_structural_conflicts.end();
1151              conf_i++) {
1152
1153             if ((node == (*conf_i)->get_node()) && (prop == (*conf_i)->get_property()) &&
1154                 !(this->has_conflict_been_cleared(*conf_i)) && (*pFn)(*conf_i)) {
1155                 
1156                 result = true;
1157                 break;
1158             }
1159         }
1160             
1161         toplevel            = current_transaction->toplevel;
1162         current_transaction = current_transaction->parent;
1163     } while (!result && (0 != current_transaction));
1164
1165     if (!result) {
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)) {
1170                 
1171                 result = true;
1172                 break;
1173             }
1174         }
1175     }
1176
1177     CYG_REPORT_RETVAL(result);
1178     return result;
1179 }
1180
1181 CdlConflict
1182 CdlTransactionBody::get_structural_conflict(CdlNode node, CdlProperty prop, bool (*pFn)(CdlConflict))
1183 {
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);
1189
1190     CdlConflict result = 0;
1191     std::list<CdlConflict>::const_iterator conf_i;
1192     CdlTransaction current_transaction = this;
1193     CdlToplevel    toplevel            = this->toplevel;
1194     do {
1195         CYG_LOOP_INVARIANT_CLASSC(current_transaction);
1196         
1197         for (conf_i = current_transaction->new_structural_conflicts.begin();
1198              conf_i != current_transaction->new_structural_conflicts.end();
1199              conf_i++) {
1200
1201             if ((node == (*conf_i)->get_node()) && (prop == (*conf_i)->get_property()) &&
1202                 !(this->has_conflict_been_cleared(*conf_i)) && (*pFn)(*conf_i)) {
1203                 result = *conf_i;
1204                 break;
1205             }
1206         }
1207             
1208         toplevel            = current_transaction->toplevel;
1209         current_transaction = current_transaction->parent;
1210     } while ((0 == result) && (0 != current_transaction));
1211
1212     if (0 == result) {
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)) {
1217                 
1218                 result = *conf_i;
1219                 break;
1220             }
1221         }
1222     }
1223
1224     CYG_REPORT_RETVAL(result);
1225     return result;
1226 }
1227
1228 void
1229 CdlTransactionBody::get_structural_conflicts(CdlNode node, CdlProperty prop, bool (*pFn)(CdlConflict),
1230                                              std::vector<CdlConflict>& result)
1231 {
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);
1237
1238     std::list<CdlConflict>::const_iterator conf_i;
1239     CdlTransaction current_transaction = this;
1240     CdlToplevel    toplevel            = this->toplevel;
1241     do {
1242         CYG_LOOP_INVARIANT_CLASSC(current_transaction);
1243         
1244         for (conf_i = current_transaction->new_structural_conflicts.begin();
1245              conf_i != current_transaction->new_structural_conflicts.end();
1246              conf_i++) {
1247
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);
1251             }
1252         }
1253             
1254         toplevel            = current_transaction->toplevel;
1255         current_transaction = current_transaction->parent;
1256     } while (0 != current_transaction);
1257
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)) {
1262             
1263             result.push_back(*conf_i);
1264         }
1265     }
1266
1267     CYG_REPORT_RETURN();
1268 }
1269
1270 //}}}
1271 //{{{  clear_conflicts()                        
1272
1273 // ----------------------------------------------------------------------------
1274 // Clearing a conflict. This can only happen in the context of a
1275 // transaction.
1276 void
1277 CdlTransactionBody::clear_conflicts(CdlNode node, bool (*pFn)(CdlConflict))
1278 {
1279     CYG_REPORT_FUNCNAME("CdlTransaction::clear_conflicts");
1280     CYG_REPORT_FUNCARG3XV(this, node, pFn);
1281     CYG_PRECONDITION_THISC();
1282     CYG_PRECONDITION_CLASSC(node);
1283
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;
1290     do {
1291         CYG_LOOP_INVARIANT_CLASSC(current_transaction);
1292         
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);
1297             }
1298         }
1299         toplevel = current_transaction->toplevel;
1300         current_transaction = current_transaction->parent;
1301     } while (0 != current_transaction);
1302     
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);
1308         }
1309     }
1310     
1311     CYG_REPORT_RETURN();
1312 }
1313
1314 void
1315 CdlTransactionBody::clear_conflicts(CdlNode node, CdlProperty prop, bool (*pFn)(CdlConflict))
1316 {
1317     CYG_REPORT_FUNCNAME("CdlTransaction::clear_conflicts");
1318     CYG_REPORT_FUNCARG4XV(this, node, prop, pFn);
1319     CYG_PRECONDITION_THISC();
1320     CYG_PRECONDITION_CLASSC(node);
1321
1322     std::list<CdlConflict>::iterator conf_i;
1323     CdlTransaction current_transaction = this;
1324     CdlToplevel    toplevel            = this->toplevel;
1325     do {
1326         CYG_LOOP_INVARIANT_CLASSC(current_transaction);
1327         
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);
1333             }
1334         }
1335         toplevel = current_transaction->toplevel;
1336         current_transaction = current_transaction->parent;
1337     } while (0 != current_transaction);
1338     
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);
1345         }
1346     }
1347     
1348     CYG_REPORT_RETURN();
1349 }
1350
1351 void
1352 CdlTransactionBody::clear_structural_conflicts(CdlNode node, bool (*pFn)(CdlConflict))
1353 {
1354     CYG_REPORT_FUNCNAME("CdlTransaction::clear_structural_conflicts");
1355     CYG_REPORT_FUNCARG3XV(this, node, pFn);
1356     CYG_PRECONDITION_THISC();
1357     CYG_PRECONDITION_CLASSC(node);
1358
1359     std::list<CdlConflict>::iterator conf_i;
1360     CdlTransaction current_transaction = this;
1361     CdlToplevel    toplevel            = this->toplevel;
1362     do {
1363         CYG_LOOP_INVARIANT_CLASSC(current_transaction);
1364         
1365         for (conf_i = current_transaction->new_structural_conflicts.begin();
1366              conf_i != current_transaction->new_structural_conflicts.end();
1367             ) {
1368             
1369             CdlConflict conflict = *conf_i++;
1370             if ((node == conflict->get_node()) && !(this->has_conflict_been_cleared(conflict)) && (*pFn)(conflict)) {
1371                 this->clear_conflict(conflict);
1372             }
1373         }
1374         toplevel = current_transaction->toplevel;
1375         current_transaction = current_transaction->parent;
1376     } while (0 != current_transaction);
1377     
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);
1383         }
1384     }
1385     
1386     CYG_REPORT_RETURN();
1387 }
1388
1389 void
1390 CdlTransactionBody::clear_structural_conflicts(CdlNode node, CdlProperty prop, bool (*pFn)(CdlConflict))
1391 {
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);
1396
1397     std::list<CdlConflict>::iterator conf_i;
1398     CdlTransaction current_transaction = this;
1399     CdlToplevel    toplevel            = this->toplevel;
1400     do {
1401         CYG_LOOP_INVARIANT_CLASSC(current_transaction);
1402         
1403         for (conf_i = current_transaction->new_structural_conflicts.begin();
1404              conf_i != current_transaction->new_structural_conflicts.end();
1405             ) {
1406             
1407             CdlConflict conflict = *conf_i++;
1408             if ((node == conflict->get_node()) && (prop == conflict->get_property()) && 
1409                 !(this->has_conflict_been_cleared(conflict)) && (*pFn)(conflict)) {
1410                 
1411                 this->clear_conflict(conflict);
1412             }
1413         }
1414         toplevel = current_transaction->toplevel;
1415         current_transaction = current_transaction->parent;
1416     } while (0 != current_transaction);
1417     
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);
1424         }
1425     }
1426     
1427     CYG_REPORT_RETURN();
1428 }
1429
1430 //}}}
1431 //{{{  clear_conflict()                         
1432
1433 // ----------------------------------------------------------------------------
1434 void
1435 CdlTransactionBody::clear_conflict(CdlConflict conflict)
1436 {
1437     CYG_REPORT_FUNCNAME("CdlTransaction::clear_conflict");
1438     CYG_REPORT_FUNCARG2XV(this, conflict);
1439     CYG_PRECONDITION_THISC();
1440     CYG_PRECONDITION_CLASSC(conflict);
1441
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);
1451         } else {
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);
1455         }
1456         delete conflict;
1457         
1458     } else {
1459         if (conflict->structural) {
1460             deleted_structural_conflicts.push_back(conflict);
1461         } else {
1462             deleted_conflicts.push_back(conflict);
1463         }
1464     }
1465
1466     CYG_REPORT_RETURN();
1467 }
1468
1469 // ----------------------------------------------------------------------------
1470 bool
1471 CdlTransactionBody::has_conflict_been_cleared(CdlConflict conf)
1472 {
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);
1477     
1478     bool result = false;
1479     CdlTransaction current_transaction = this;
1480     do {
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()) {
1485                 
1486                 result = true;
1487             }
1488         } else {
1489             if (std::find(current_transaction->deleted_conflicts.begin(), current_transaction->deleted_conflicts.end(),
1490                           conf) != current_transaction->deleted_conflicts.end()) {
1491                 result = true;
1492             }
1493         }
1494
1495         current_transaction = current_transaction->parent;
1496     } while (!result && (0 != current_transaction));
1497     
1498     CYG_REPORT_RETVAL(result);
1499     return result;
1500 }
1501
1502 //}}}
1503 //{{{  per-transaction data                     
1504
1505 // ----------------------------------------------------------------------------
1506 // Accessing the per-transaction conflict data.
1507
1508 const std::list<CdlConflict>&
1509 CdlTransactionBody::get_new_conflicts() const
1510 {
1511     CYG_REPORT_FUNCNAME("CdlTransaction::get_new_conflicts");
1512     CYG_REPORT_FUNCARG1XV(this);
1513     CYG_PRECONDITION_THISC();
1514
1515     CYG_REPORT_RETURN();
1516     return new_conflicts;
1517 }
1518
1519 const std::list<CdlConflict>&
1520 CdlTransactionBody::get_new_structural_conflicts() const
1521 {
1522     CYG_REPORT_FUNCNAME("CdlTransaction::get_new_structural_conflicts");
1523     CYG_REPORT_FUNCARG1XV(this);
1524     CYG_PRECONDITION_THISC();
1525
1526     CYG_REPORT_RETURN();
1527     return new_structural_conflicts;
1528 }
1529
1530 const std::vector<CdlConflict>&
1531 CdlTransactionBody::get_deleted_conflicts() const
1532 {
1533     CYG_REPORT_FUNCNAME("CdlTransaction::get_deleted_conflicts");
1534     CYG_REPORT_FUNCARG1XV(this);
1535     CYG_PRECONDITION_THISC();
1536
1537     CYG_REPORT_RETURN();
1538     return deleted_conflicts;
1539 }
1540
1541 const std::vector<CdlConflict>&
1542 CdlTransactionBody::get_deleted_structural_conflicts() const
1543 {
1544     CYG_REPORT_FUNCNAME("CdlTransaction::get_deleted_structural_conflicts");
1545     CYG_REPORT_FUNCARG1XV(this);
1546     CYG_PRECONDITION_THISC();
1547
1548     CYG_REPORT_RETURN();
1549     return deleted_structural_conflicts;
1550 }
1551
1552 const std::vector<CdlConflict>&
1553 CdlTransactionBody::get_resolved_conflicts() const
1554 {
1555     CYG_REPORT_FUNCNAME("CdlTransaction::get_resolved_conflicts");
1556     CYG_REPORT_FUNCARG1XV(this);
1557     CYG_PRECONDITION_THISC();
1558
1559     CYG_REPORT_RETURN();
1560     return resolved_conflicts;
1561 }
1562
1563 const std::list<CdlConflict>&
1564 CdlTransactionBody::get_global_conflicts_with_solutions() const
1565 {
1566     CYG_REPORT_FUNCNAME("CdlTransaction::get_global_conflicts_with_solutions");
1567     CYG_REPORT_FUNCARG1XV(this);
1568     CYG_PRECONDITION_THISC();
1569
1570     CYG_REPORT_RETURN();
1571     return global_conflicts_with_solutions;
1572 }
1573
1574 //}}}
1575
1576 //}}}
1577 //{{{  Commit/cancel operations                 
1578
1579 // ----------------------------------------------------------------------------
1580 void
1581 CdlTransactionBody::add_commit_cancel_op(CdlTransactionCommitCancelOp* op)
1582 {
1583     CYG_REPORT_FUNCNAME("CdlTransaction::add_commit_cancel_op");
1584     CYG_REPORT_FUNCARG2XV(this, op);
1585     CYG_PRECONDITION_THISC();
1586     CYG_PRECONDITIONC(0 != op);
1587
1588     commit_cancel_ops.push_back(op);
1589     
1590     CYG_REPORT_RETURN();
1591 }
1592
1593 void
1594 CdlTransactionBody::cancel_last_commit_cancel_op()
1595 {
1596     CYG_REPORT_FUNCNAME("CdlTransaction::cancel_last_commit_cancel_op");
1597     CYG_REPORT_FUNCARG1XV(this);
1598     CYG_PRECONDITION_THISC();
1599
1600     CdlTransactionCommitCancelOp* op = *(commit_cancel_ops.rbegin());
1601     commit_cancel_ops.pop_back();
1602     op->cancel(this);
1603     delete op;
1604         
1605     CYG_REPORT_RETURN();
1606 }
1607
1608 CdlTransactionCommitCancelOp*
1609 CdlTransactionBody::get_last_commit_cancel_op() const
1610 {
1611     CYG_REPORT_FUNCNAMETYPE("CdlTransaction::get_last_commit_cancel_op", "result %p");
1612     CYG_REPORT_FUNCARG1XV(this);
1613     CYG_PRECONDITION_THISC();
1614
1615     CdlTransactionCommitCancelOp* op = *(commit_cancel_ops.rbegin());
1616     
1617     CYG_REPORT_RETVAL(op);
1618     return op;
1619 }
1620
1621 const std::vector<CdlTransactionCommitCancelOp*>&
1622 CdlTransactionBody::get_commit_cancel_ops() const
1623 {
1624     CYG_REPORT_FUNCNAME("CdlTransaction::get_commit_cancel_ops");
1625     CYG_REPORT_FUNCARG1XV(this);
1626     CYG_PRECONDITION_THISC();
1627
1628     CYG_REPORT_RETURN();
1629     return commit_cancel_ops;
1630 }
1631
1632 //}}}
1633 //{{{  Propagation                              
1634
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.
1640
1641 void
1642 CdlTransactionBody::propagate()
1643 {
1644     CYG_REPORT_FUNCNAME("CdlTransaction::propagate");
1645     CYG_REPORT_FUNCARG1XV(this);
1646     CYG_INVARIANT_THISC(CdlTransactionBody);
1647     
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())) {
1652         
1653         if (0 != value_changes.size()) {
1654             
1655             CdlValuable valuable = value_changes.front();
1656             value_changes.pop_front();
1657             
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);
1666             }
1667             for (conf_i = global_conflicts_with_solutions.begin();
1668                  conf_i != global_conflicts_with_solutions.end();
1669                  ) {
1670                 
1671                 CYG_LOOP_INVARIANT_CLASSC(*conf_i);
1672                 conf_j = conf_i++;
1673
1674                 (*conf_j)->update_solution_validity(valuable);
1675                 if (!(*conf_j)->has_known_solution()) {
1676                     global_conflicts_with_solutions.erase(conf_j);
1677                 }
1678             }
1679
1680             // If the valuable is no longer loaded then there is
1681             // no need to worry about propagation
1682             if (0 != valuable->get_toplevel()) {
1683                 
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);
1687             
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);
1692                 }
1693             }
1694                 
1695         } else {
1696             
1697             CdlNode node = active_changes.front();
1698             active_changes.pop_front();
1699
1700             if (0 != node->get_toplevel()) {
1701                 node->update(this, CdlUpdate_ActiveChange);
1702             
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);
1707                 }
1708             }
1709         }
1710     }
1711
1712     CYG_REPORT_RETURN();
1713 }
1714
1715 // ----------------------------------------------------------------------------
1716 bool
1717 CdlTransactionBody::is_propagation_required() const
1718 {
1719     CYG_REPORT_FUNCNAMETYPE("CdlTransaction::is_propagation_required", "result %d");
1720     CYG_REPORT_FUNCARG1XV(this);
1721     CYG_PRECONDITION_THISC();
1722
1723     bool result = false;
1724
1725     if ((0 != value_changes.size()) || (0 != active_changes.size())) {
1726         result = true;
1727     }
1728     
1729     CYG_REPORT_RETVAL(result);
1730     return result;
1731 }
1732
1733
1734 // ----------------------------------------------------------------------------
1735 void
1736 CdlTransactionBody::add_legal_values_change(CdlValuable valuable)
1737 {
1738     CYG_REPORT_FUNCNAME("CdlTransaction::add_legal_values_change");
1739     CYG_REPORT_FUNCARG2XV(this, valuable);
1740     CYG_PRECONDITION_THISC();
1741     CYG_PRECONDITION_CLASSC(valuable);
1742
1743     legal_values_changes.insert(valuable);
1744     
1745     CYG_REPORT_RETURN();
1746 }
1747
1748 const std::set<CdlValuable>&
1749 CdlTransactionBody::get_legal_values_changes() const
1750 {
1751     CYG_REPORT_FUNCNAME("CdlTransaction::get_legal_values_changes");
1752     CYG_REPORT_FUNCARG1XV(this);
1753     CYG_PRECONDITION_THISC();
1754
1755     CYG_REPORT_RETURN();
1756     return legal_values_changes;
1757 }
1758
1759 //}}}
1760 //{{{  Cancel                                   
1761
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.
1766 void
1767 CdlTransactionBody::cancel()
1768 {
1769     CYG_REPORT_FUNCNAME("CdlTransaction::cancel");
1770     CYG_REPORT_FUNCARG1XV(this);
1771     CYG_INVARIANT_THISC(CdlTransactionBody);
1772
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);
1778         delete *cancel_i;
1779         *cancel_i = 0;
1780     }
1781     commit_cancel_ops.clear();
1782     
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);
1787         delete *conf_i;
1788     }
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);
1792         delete *conf_i;
1793     }
1794     this->new_structural_conflicts.clear();
1795     
1796     this->deleted_structural_conflicts.clear();
1797     this->deleted_conflicts.clear();
1798     
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) {
1805             delete (*conf_i2);
1806         }
1807     }
1808     this->resolved_conflicts.clear();
1809
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();
1815          conf_i++) {
1816
1817         CYG_LOOP_INVARIANT_CLASSC(*conf_i);
1818         (*conf_i)->clear_solution();
1819     }
1820     this->global_conflicts_with_solutions.clear();
1821     
1822     this->activated.clear();
1823     this->deactivated.clear();
1824     this->legal_values_changes.clear();
1825     this->value_changes.clear();
1826     this->active_changes.clear();
1827
1828     CYG_REPORT_RETURN();
1829 }
1830
1831 //}}}
1832 //{{{  Commit                                   
1833
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.
1840 //
1841 // The second branch involves committing changes from a transaction to
1842 // the toplevel, invoking the transaction callback if necessary.
1843
1844 void
1845 CdlTransactionBody::commit()
1846 {
1847     CYG_REPORT_FUNCNAME("CdlTransaction::commit");
1848     CYG_REPORT_FUNCARG1XV(this);
1849     CYG_INVARIANT_THISC(CdlTransactionBody);
1850
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;
1856
1857     if (0 != parent) {
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;
1885             }
1886         }
1887         resolved_conflicts.clear();
1888
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++) {
1892             
1893             CdlConflict conf = *conf_i;
1894             CYG_LOOP_INVARIANT_CLASSC(conf);
1895             
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(),
1901                                 conf);
1902             if (conf_j == parent->global_conflicts_with_solutions.end()) {
1903                 parent->global_conflicts_with_solutions.push_back(conf);
1904                 parent->dirty = true;
1905             }
1906         }
1907         global_conflicts_with_solutions.clear();
1908         
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.
1921             //
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
1926             // conflicts.
1927             //
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);
1935                 can_delete = true;
1936             } else {
1937                 parent->deleted_conflicts.push_back(conf);
1938             }
1939             if (0 == conf->transaction) {
1940                 conf_j = std::find(parent->global_conflicts_with_solutions.begin(),
1941                                    parent->global_conflicts_with_solutions.end(),
1942                                    conf);
1943                 if (conf_j != parent->global_conflicts_with_solutions.end()) {
1944                     parent->global_conflicts_with_solutions.erase(conf_j);
1945                 }
1946             }
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;
1955                 }
1956             } else if (can_delete) {
1957                 delete conf;
1958             }
1959         }
1960         // Unnecessary, but let's keep things clean.
1961         deleted_conflicts.clear();
1962
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++) {
1966             
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);
1972                 delete conf;
1973             } else {
1974                 parent->deleted_structural_conflicts.push_back(conf);
1975             }
1976         }
1977         deleted_structural_conflicts.clear();
1978  
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);
1988             }
1989             for (conf_i = parent->global_conflicts_with_solutions.begin();
1990                  conf_i != parent->global_conflicts_with_solutions.end();
1991                  ) {
1992
1993                 conf_j = conf_i++;
1994                 CYG_LOOP_INVARIANT_CLASSC(*conf_j);
1995
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);
1999                 }
2000             }
2001         }
2002         changes.clear();
2003         
2004         // Continue propagating the conflicts.New conflicts can just
2005         // be added.
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;
2011         }
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;
2017         }
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();
2022
2023         
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);
2031             }
2032         }
2033         
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);
2040             }
2041         }
2042         activated.clear();
2043         deactivated.clear();
2044
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);
2049         }
2050         legal_values_changes.clear();
2051
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();
2056         
2057     } else {
2058         
2059         CYG_ASSERT_CLASSC(toplevel);
2060
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
2065         // the toplevel.
2066         CdlTransactionCallback all_changes(this);
2067         if (0 != callback_fn) {
2068             
2069             for (map_i = changes.begin(); map_i != changes.end(); map_i++) {
2070                 if (0 == map_i->first->get_toplevel()) {
2071                     continue;
2072                 }
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;
2077                 
2078                 if (old_value.get_source() != map_i->second.get_source()) {
2079                     all_changes.value_source_changes.push_back(map_i->first);
2080                 }
2081                 if ((CdlValueFlavor_Bool == flavor) || (CdlValueFlavor_BoolData == flavor)) {
2082                     if (old_value.is_enabled() != map_i->second.is_enabled()) {
2083                         value_changed = true;
2084                     }
2085                 }
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;
2089                     }
2090                 }
2091                 if (value_changed) {
2092                     all_changes.value_changes.push_back(map_i->first);
2093                 }
2094             }
2095             for (conf_i = new_conflicts.begin(); conf_i != new_conflicts.end(); conf_i++) {
2096                 all_changes.new_conflicts.push_back(*conf_i);
2097             }
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);
2100             }
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);
2104
2105                 all_changes.nodes_with_resolved_conflicts.push_back(node);
2106             }
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);
2110
2111                 all_changes.nodes_with_resolved_structural_conflicts.push_back(node);
2112             }
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);
2116                 }
2117             }
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);
2121                 }
2122             }
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);
2126                 }
2127             }
2128             legal_values_changes.clear();
2129         }
2130
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;
2136         }
2137         changes.clear();
2138
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();
2147         }
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();
2154         }
2155         new_structural_conflicts.clear();
2156
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) {
2163                 delete *conf_i2;
2164             }
2165         }
2166         resolved_conflicts.clear();
2167
2168         // Now process conflicts that have gone away. These must actually
2169         // be deleted.
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);
2176             delete *conf_i2;
2177         }
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);
2185             delete *conf_i2;
2186         }
2187         deleted_structural_conflicts.clear();
2188
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();
2194         }
2195         global_conflicts_with_solutions.clear();
2196         
2197         for (set_i = activated.begin(); set_i != activated.end(); set_i++) {
2198             (*set_i)->active = true;
2199         }
2200         for (set_i = deactivated.begin(); set_i != deactivated.end(); set_i++) {
2201             (*set_i)->active = false;
2202         }
2203         activated.clear();
2204         deactivated.clear();
2205
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);
2210             delete *commit_i;
2211             *commit_i = 0;
2212         }
2213         commit_cancel_ops.clear();
2214
2215         // Finally take care of the callback.
2216         if (0 != callback_fn) {
2217             (*callback_fn)(all_changes);
2218         }
2219     }
2220     
2221     CYG_REPORT_RETURN();
2222 }
2223
2224 //}}}
2225 //{{{  Solution support                         
2226
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.
2232
2233 void
2234 CdlTransactionBody::save_solution()
2235 {
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));
2243
2244     CYG_PRECONDITION_CLASSC(conflict);
2245     CYG_PRECONDITIONC(0 == conflict->solution.size());
2246     
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);
2255         }
2256     }
2257     
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.
2263     this->cancel();
2264     CYG_REPORT_RETURN();
2265 }
2266
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.
2273 bool
2274 CdlTransactionBody::user_confirmation_required() const
2275 {
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);
2280
2281     bool result = false;
2282   
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) {
2287             result = true;
2288             break;
2289         }
2290     }
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()) {
2297                 result = true;
2298                 break;
2299             }
2300         }
2301     }
2302   
2303     CYG_REPORT_RETVAL(result);
2304     return result;
2305 }
2306
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.
2311 bool
2312 CdlTransactionBody::changed_by_user(CdlValuable valuable) const
2313 {
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);
2318     
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) {
2324             result = true;
2325         }
2326     }
2327     if (!result && (0 != parent)) {
2328         result = parent->changed_by_user(valuable);
2329     }
2330
2331     CYG_REPORT_RETVAL(result);
2332     return result;
2333 }
2334
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.
2338 bool
2339 CdlTransactionBody::subnode_changed_by_user(CdlContainer container) const
2340 {
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);
2345
2346     bool result = false;
2347
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)) {
2353             result = true;
2354             break;
2355         }
2356         CdlContainer container = dynamic_cast<CdlContainer>(*node_i);
2357         if ((0 != container) && this->subnode_changed_by_user(container)) {
2358             result = true;
2359             break;
2360         }
2361     }
2362     
2363     CYG_REPORT_RETVAL(result);
2364     return result;
2365 }
2366
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
2371 // themselves.
2372 //
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.
2378
2379 bool
2380 CdlTransactionBody::is_preferable_to(CdlTransaction other) const
2381 {
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);
2387
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();
2391         
2392     if (this_changes <= other_changes) {
2393         result = true;
2394     }
2395     
2396     CYG_REPORT_RETVAL(result);
2397     return result;
2398 }
2399
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
2403 // applied.
2404
2405 void
2406 CdlTransactionBody::apply_solution(CdlConflict conflict)
2407 {
2408     CYG_REPORT_FUNCNAME("CdlTransaction::apply_solution");
2409     CYG_REPORT_FUNCARG2XV(this, conflict);
2410     CYG_PRECONDITION_THISC();
2411     CYG_PRECONDITION_CLASSC(conflict);
2412
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(),
2420                            conflict);
2421         CYG_ASSERTC(conf_i != this->global_conflicts_with_solutions.end());
2422     }
2423     
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);
2428
2429         const CdlValue& old_value = this->get_whole_value(valuable);
2430         this->set_whole_value(valuable, old_value, val_i->second);
2431     }
2432
2433     CYG_REPORT_RETURN();
2434 }
2435
2436 void
2437 CdlTransactionBody::apply_solutions(const std::vector<CdlConflict>& solutions)
2438 {
2439     CYG_REPORT_FUNCNAME("CdlTransaction::apply_solutions");
2440     CYG_REPORT_FUNCARG1XV(this);
2441     CYG_PRECONDITION_THISC();
2442
2443     std::vector<CdlConflict>::const_iterator conf_i;
2444     for (conf_i = solutions.begin(); conf_i != solutions.end(); conf_i++) {
2445         
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(),
2451                                conflict);
2452             CYG_ASSERTC(conf_j != this->global_conflicts_with_solutions.end());
2453         }
2454
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);
2461         }
2462     }
2463
2464     CYG_REPORT_RETURN();
2465 }
2466
2467 void
2468 CdlTransactionBody::apply_all_solutions()
2469 {
2470     CYG_REPORT_FUNCNAME("CdlTransaction::apply_all_solutions");
2471     CYG_REPORT_FUNCARG1XV(this);
2472     CYG_PRECONDITION_THISC();
2473
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()) {
2477
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);
2484             }
2485         }
2486     }
2487     for (conf_i = this->global_conflicts_with_solutions.begin();
2488          conf_i != this->global_conflicts_with_solutions.end();
2489          conf_i++) {
2490
2491         CYG_ASSERTC((*conf_i)->has_known_solution());
2492         
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);
2499         }
2500     }
2501
2502     CYG_REPORT_RETURN();
2503 }
2504
2505 //}}}
2506 //{{{  Inference                                
2507
2508 // ----------------------------------------------------------------------------
2509 //{{{  resolve() - all per-transaction conflicts        
2510
2511 void
2512 CdlTransactionBody::resolve(int level)
2513 {
2514     CYG_REPORT_FUNCNAME("CdlTransaction::resolve");
2515     CYG_REPORT_FUNCARG2XV(this, level);
2516     CYG_PRECONDITION_THISC();
2517
2518     while(1) {
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);
2525
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()) {
2530                 continue;
2531             }
2532             this->resolve(*conf_i, level);
2533             break;
2534         }
2535         if (conf_i == new_conflicts.end()) {
2536             break;
2537         }
2538     }
2539     
2540     CYG_REPORT_RETURN();
2541 }
2542
2543 //}}}
2544 //{{{  resolve() - vector                               
2545
2546 // ----------------------------------------------------------------------------
2547 void
2548 CdlTransactionBody::resolve(const std::vector<CdlConflict>& conflicts, int level)
2549 {
2550     CYG_REPORT_FUNCNAME("CdlTransaction::resolve");
2551     CYG_REPORT_FUNCARG2XV(this, level);
2552     CYG_PRECONDITION_THISC();
2553
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);
2557
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);
2563         }
2564     }
2565     
2566     CYG_REPORT_RETURN();
2567 }
2568
2569 //}}}
2570 //{{{  resolve() - single conflict                      
2571
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
2575 //
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.
2581
2582 void
2583 CdlTransactionBody::resolve(CdlConflict conflict, int level)
2584 {
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));
2591
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();
2600         return;
2601     }
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()) {
2608  
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();
2614             return;
2615         }
2616     } else {
2617         if (std::find(sub_transaction->deleted_conflicts.begin(), sub_transaction->deleted_conflicts.end(), conflict)
2618             == sub_transaction->deleted_conflicts.end()) {
2619                     
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();
2625             return;
2626         }
2627     }
2628             
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;
2642         this->dirty = true;
2643
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(),
2650                                conflict);
2651             if (conf_i == this->global_conflicts_with_solutions.end()) {
2652                 this->global_conflicts_with_solutions.push_back(conflict);
2653             }
2654         }
2655     } else {
2656             
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);
2667         }
2668         sub_transaction->commit();
2669         delete sub_transaction;
2670     }
2671
2672     CYG_REPORT_RETURN();
2673 }
2674
2675 //}}}
2676 //{{{  resolve_recursion()                              
2677
2678 // ----------------------------------------------------------------------------
2679 // resolve_recursion()
2680 //
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.
2685 bool
2686 CdlTransactionBody::resolve_recursion(int level)
2687 {
2688     CYG_REPORT_FUNCNAMETYPE("CdlTransaction::resolve_recursion", "result %d");
2689     CYG_REPORT_FUNCARG2XV(this, level);
2690     CYG_PRECONDITION_THISC();
2691
2692     bool result = false;
2693     this->propagate();
2694     if (0 == new_conflicts.size()) {
2695         result = true;
2696         CYG_REPORT_RETVAL(result);
2697         return result;
2698     }
2699     if (level >= inference_recursion_limit) {
2700         result = false;
2701         CYG_REPORT_RETVAL(result);
2702         return result;
2703     }
2704
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;
2708     do {
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;
2715             }
2716         }
2717     } while(solutions_possible);
2718
2719     result = (0 == new_conflicts.size());
2720     CYG_REPORT_RETVAL(result);
2721     return result;
2722 }
2723
2724 //}}}
2725
2726 //}}}
2727 //{{{  Body                                     
2728
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
2734 // of all of that.
2735 //
2736 // If automatic inference is disabled then life is pretty simple, there
2737 // should be one propagate() operation followed by a commit.
2738 //
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.
2742 //
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:
2746 //
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
2751 //    the changes.
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.
2757 //
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.
2765
2766 void
2767 CdlTransactionBody::body()
2768 {
2769     CYG_REPORT_FUNCNAME("CdlTransaction::body");
2770     CYG_REPORT_FUNCARG1XV(this);
2771     CYG_PRECONDITION_THISC();
2772
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));
2777
2778     if (!inference_enabled) {
2779         this->propagate();
2780         this->commit();
2781         CYG_REPORT_RETURN();
2782         return;
2783     }
2784
2785     if (0 == inference_callback) {
2786         bool progress = false;
2787         do {
2788             progress = false;
2789             this->propagate();
2790             CYG_LOOP_INVARIANTC(0 == value_changes.size());
2791             this->resolve();
2792             if (0 != value_changes.size()) {
2793                 progress = true;
2794             }
2795         } while(progress);
2796
2797         this->commit();
2798         CYG_REPORT_RETURN();
2799         return;
2800     }
2801
2802     bool cancel = false;
2803     
2804     unsigned int resolved_size = 0;
2805     unsigned int globals_with_solutions_size = 0;
2806     
2807     do {
2808         bool progress = false;
2809         do {
2810             progress = false;
2811             this->propagate();
2812             CYG_LOOP_INVARIANTC(0 == value_changes.size());
2813             this->resolve();
2814             if (0 != value_changes.size()) {
2815                 progress = true;
2816             }
2817         } while(progress);
2818
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())) {
2825             cancel = false;
2826             break;
2827         }
2828
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.
2832         if (!this->dirty) {
2833             cancel = false;
2834             break;
2835         }
2836         
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
2839         // time around.
2840         this->dirty = false;
2841         resolved_size = resolved_conflicts.size();
2842         globals_with_solutions_size = global_conflicts_with_solutions.size();
2843
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)) {
2847             cancel = true;
2848         }
2849     } while(!cancel);
2850
2851     if (cancel) {
2852         this->cancel();
2853     } else {
2854         this->commit();
2855     }
2856     
2857     CYG_REPORT_RETURN();
2858 }
2859
2860 //}}}
2861