OpenCores
URL https://opencores.org/ocsvn/openrisc_2011-10-31/openrisc_2011-10-31/trunk

Subversion Repositories openrisc_2011-10-31

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [tools/] [src/] [libcdl/] [transact.cxx] - Blame information for rev 637

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 26 unneback
//{{{  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
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.