Statistics
| Branch: | Revision:

root / src / sim / cmodule.cc @ e1750c09

History | View | Annotate | Download (44.5 KB)

1
//======================================================================
2
//  CMODULE.CC - part of
3
//
4
//                 OMNeT++/OMNEST
5
//              Discrete System Simulation in C++
6
//
7
//  Author: Andras Varga
8
//
9
//======================================================================
10

    
11
/*--------------------------------------------------------------*
12
  Copyright (C) 1992-2008 Andras Varga
13
  Copyright (C) 2006-2008 OpenSim Ltd.
14

15
  This file is distributed WITHOUT ANY WARRANTY. See the file
16
  `license' for details on this and other legal matters.
17
*--------------------------------------------------------------*/
18

    
19
#include <stdio.h>           // sprintf
20
#include <string.h>          // strcpy
21
#include <algorithm>
22
#include "cmodule.h"
23
#include "csimplemodule.h"
24
#include "cgate.h"
25
#include "cmessage.h"
26
#include "csimulation.h"
27
#include "carray.h"
28
#include "ccomponenttype.h"
29
#include "cenvir.h"
30
#include "cexception.h"
31
#include "cchannel.h"
32
#include "cproperties.h"
33
#include "cproperty.h"
34
#include "stringutil.h"
35
#include "simutil.h"
36
#include "cmodelchange.h"
37

    
38
USING_NAMESPACE
39

    
40

    
41
//TODO consider:
42
//  call cGate::clearFullnamePool() between events, and add to doc:
43
//  "lifetime of the string returned by getFullName() is the simulation event"?
44

    
45

    
46
// static members:
47
std::string cModule::lastmodulefullpath;
48
const cModule *cModule::lastmodulefullpathmod = NULL;
49

    
50

    
51
cModule::cModule()
52
{
53
    mod_id = -1;
54
    idx = 0;
55
    vectsize = -1;
56
    fullname = NULL;
57

    
58
    prevp = nextp = firstsubmodp = lastsubmodp = NULL;
59

    
60
    descvSize = 0;
61
    descv = NULL;
62

    
63
    // gates and parameters will be added by cModuleType
64
}
65

    
66
cModule::~cModule()
67
{
68
    // release listeners in the whole subtree first. This mostly eliminates
69
    // the need for explicit unsubscribe() calls in module destructors.
70
    releaseListeners();
71

    
72
    // notify envir while module object still exists (more or less)
73
    EVCB.moduleDeleted(this);
74

    
75
    // delete submodules
76
    for (SubmoduleIterator submod(this); !submod.end(); )
77
    {
78
        if (submod() == (cModule *)simulation.getContextModule())
79
        {
80
            throw cRuntimeError("Cannot delete a compound module from one of its submodules!");
81
            // The reason is that deleteModule() of the currently executing
82
            // module does not return -- for obvious reasons (we would
83
            // execute with an already deallocated stack etc).
84
            // Thus the deletion of the current module would remain unfinished.
85
            // A solution could be to skip deletion of that very module at first,
86
            // and delete it only when everything else is deleted.
87
            // However, this would be clumsy and ugly to implement so
88
            // I'd rather wait until the real need for it emerges... --VA
89
        }
90

    
91
        cModule *mod = submod++;
92
        mod->deleteModule();
93
    }
94

    
95
    // adjust gates that were directed here
96
    for (GateIterator i(this); !i.end(); i++)
97
    {
98
        cGate *gate = i();
99
        if (gate->getNextGate() && gate->getNextGate()->getPreviousGate()==gate)
100
           gate->disconnect();
101
        if (gate->getPreviousGate() && gate->getPreviousGate()->getNextGate()==gate)
102
           gate->getPreviousGate()->disconnect();
103
    }
104

    
105
    // delete all gates
106
    clearGates();
107

    
108
    // deregister ourselves
109
    if (mod_id!=-1)
110
        simulation.deregisterModule(this);
111
    if (getParentModule())
112
        getParentModule()->removeSubmodule(this);
113

    
114
    delete [] fullname;
115
}
116

    
117
void cModule::releaseListeners()
118
{
119
    releaseLocalListeners();
120
    for (ChannelIterator chan(this); !chan.end(); chan++)
121
        chan()->releaseLocalListeners();
122
    for (SubmoduleIterator submod(this); !submod.end(); submod++)
123
        submod()->releaseListeners();
124
}
125

    
126
void cModule::forEachChild(cVisitor *v)
127
{
128
    for (int i=0; i<numparams; i++)
129
        v->visit(&paramv[i]);
130

    
131
    for (GateIterator i(this); !i.end(); i++)
132
        v->visit(i());
133

    
134
    cDefaultList::forEachChild(v);
135
}
136

    
137
void cModule::setId(int n)
138
{
139
    mod_id = n;
140
}
141

    
142
void cModule::setIndex(int i, int n)
143
{
144
    idx = i;
145
    vectsize = n;
146
    updateFullName();
147
}
148

    
149
void cModule::insertSubmodule(cModule *mod)
150
{
151
    // take ownership
152
    take(mod);
153

    
154
    // append at end of submodule list
155
    mod->nextp = NULL;
156
    mod->prevp = lastsubmodp;
157
    if (mod->prevp)
158
        mod->prevp->nextp = mod;
159
    if (!firstsubmodp)
160
        firstsubmodp = mod;
161
    lastsubmodp = mod;
162

    
163
    // update cached signal state
164
    mod->repairSignalFlags();
165

    
166
    // cached module getFullPath() possibly became invalid
167
    lastmodulefullpathmod = NULL;
168
}
169

    
170
void cModule::removeSubmodule(cModule *mod)
171
{
172
    // NOTE: no drop(mod): anyone can take ownership anyway (because we're soft owners)
173
    // and otherwise it'd cause trouble if mod itself is in context (it'd get inserted
174
    // on its own DefaultList)
175

    
176
    // remove from submodule list
177
    if (mod->nextp)
178
         mod->nextp->prevp = mod->prevp;
179
    if (mod->prevp)
180
         mod->prevp->nextp = mod->nextp;
181
    if (firstsubmodp==mod)
182
         firstsubmodp = mod->nextp;
183
    if (lastsubmodp==mod)
184
         lastsubmodp = mod->prevp;
185

    
186
    // this is not strictly needed but makes it cleaner
187
    mod->prevp = mod->nextp = NULL;
188

    
189
    // update cached signal state
190
    mod->repairSignalFlags();
191

    
192
    // cached module getFullPath() possibly became invalid
193
    lastmodulefullpathmod = NULL;
194
}
195

    
196
cModule *cModule::getParentModule() const
197
{
198
    return dynamic_cast<cModule *>(getOwner());
199
}
200

    
201
void cModule::setName(const char *s)
202
{
203
    cOwnedObject::setName(s);
204
    updateFullName();
205
}
206

    
207
void cModule::updateFullName()
208
{
209
    if (fullname)
210
    {
211
        delete [] fullname;
212
        fullname = NULL;
213
    }
214
    if (isVector())
215
    {
216
        fullname = new char[opp_strlen(getName())+10];
217
        strcpy(fullname, getName());
218
        opp_appendindex(fullname, getIndex());
219
    }
220

    
221
    if (lastmodulefullpathmod == this)
222
        lastmodulefullpathmod = NULL;  // invalidate
223
}
224

    
225
const char *cModule::getFullName() const
226
{
227
    // if not in a vector, normal getName() will do
228
    return isVector() ? fullname : getName();
229
}
230

    
231
std::string cModule::getFullPath() const
232
{
233
    if (lastmodulefullpathmod != this)
234
    {
235
        // stop at the toplevel module (don't go up to cSimulation);
236
        // plus, cache the result, expecting more hits from this module
237
        if (getParentModule()==NULL)
238
            lastmodulefullpath = getFullName();
239
        else
240
            lastmodulefullpath = getParentModule()->getFullPath() + "." + getFullName();
241
        lastmodulefullpathmod = this;
242
    }
243
    return lastmodulefullpath;
244
}
245

    
246
bool cModule::isSimple() const
247
{
248
    return dynamic_cast<const cSimpleModule *>(this) != NULL;
249
}
250

    
251
cProperties *cModule::getProperties() const
252
{
253
    cModule *parent = getParentModule();
254
    cComponentType *type = getComponentType();
255
    cProperties *props;
256
    if (parent)
257
        props = parent->getComponentType()->getSubmoduleProperties(getName(), type->getFullName());
258
    else
259
        props = type->getProperties();
260
    return props;
261
}
262

    
263
cGate *cModule::createGateObject(cGate::Type)
264
{
265
    return new cGate();
266
}
267

    
268
cModule::NamePool cModule::namePool;
269

    
270
void cModule::disposeGateObject(cGate *gate, bool checkConnected)
271
{
272
    if (gate)
273
    {
274
        if (checkConnected && (gate->getPreviousGate() || gate->getNextGate()))
275
            throw cRuntimeError(this, "Cannot delete gate `%s', it is still connected", gate->getFullName());
276
        EVCB.gateDeleted(gate);
277
        delete gate;
278
    }
279
}
280

    
281
void cModule::disposeGateDesc(cGate::Desc *desc, bool checkConnected)
282
{
283
    if (!desc->namep)
284
        return;  // already deleted
285

    
286
    // notify pre-change listeners
287
    if (hasListeners(PRE_MODEL_CHANGE)) {
288
        cPreGateDeleteNotification tmp;
289
        tmp.module = this;
290
        tmp.gateName = desc->namep->name.c_str();
291
        emit(PRE_MODEL_CHANGE, &tmp);
292
    }
293

    
294
    // do it
295
    if (!desc->isVector()) {
296
        disposeGateObject(desc->inputgate, checkConnected);
297
        disposeGateObject(desc->outputgate, checkConnected);
298
    }
299
    else {
300
        for (int j=0; j<desc->gateSize(); j++) {
301
            if (desc->inputgatev)
302
                disposeGateObject(desc->inputgatev[j], checkConnected);
303
            if (desc->outputgatev)
304
                disposeGateObject(desc->outputgatev[j], checkConnected);
305
        }
306
        delete [] desc->inputgatev;
307
        delete [] desc->outputgatev;
308
    }
309
    const char *gatename = desc->namep->name.c_str();
310
    cGate::Type gatetype = desc->getType();
311
    desc->namep = NULL; // mark as deleted, but leave shared Name struct in the pool
312

    
313
    // notify post-change listeners
314
    if (hasListeners(POST_MODEL_CHANGE)) {
315
        cPostGateDeleteNotification tmp;
316
        tmp.module = this;
317
        tmp.gateName = gatename;  // points into namePool
318
        tmp.gateType = gatetype;
319
        tmp.isVector = desc->isVector(); // desc still exists, only namep was NULL'd
320
        tmp.vectorSize = desc->gateSize();
321
        emit(POST_MODEL_CHANGE, &tmp);
322
    }
323
}
324

    
325
void cModule::clearGates()
326
{
327
    for (int i=0; i<descvSize; i++)
328
        disposeGateDesc(descv + i, false);
329
    delete [] descv;
330
    descv = NULL;
331
    descvSize = 0;
332
}
333

    
334
void cModule::clearNamePools()
335
{
336
    namePool.clear();
337
    cGate::clearFullnamePool();
338
}
339

    
340
void cModule::adjustGateDesc(cGate *gate, cGate::Desc *newvec)
341
{
342
    if (gate) {
343
        // the "desc" pointer in each gate needs to be updated when descv[] gets reallocated
344
        ASSERT(descv <= gate->desc && gate->desc < descv+descvSize);
345
        gate->desc = newvec + (gate->desc - descv);
346
    }
347
}
348

    
349
cGate::Desc *cModule::addGateDesc(const char *gatename, cGate::Type type, bool isVector)
350
{
351
    // check limits
352
    if (isVector) {
353
        if (descvSize >= MAX_VECTORGATES)
354
            throw cRuntimeError(this, "cannot add gate `%s[]': too many vector gates (limit is %d)", gatename, MAX_VECTORGATES);
355
    }
356
    else {
357
        if (descvSize >= MAX_SCALARGATES)
358
            throw cRuntimeError(this, "cannot add gate `%s': too many scalar gates (limit is %d)", gatename, MAX_SCALARGATES);
359
    }
360

    
361
    // allocate new array
362
    //TODO preallocate a larger descv[] in advance?
363
    cGate::Desc *newv = new cGate::Desc[descvSize+1];
364
    memcpy(newv, descv, descvSize*sizeof(cGate::Desc));
365

    
366
    // adjust desc pointers in already existing gates
367
    for (int i=0; i<descvSize; i++)
368
    {
369
        cGate::Desc *desc = descv + i;
370
        if (desc->namep) {
371
            if (!desc->isVector()) {
372
                adjustGateDesc(desc->inputgate, newv);
373
                adjustGateDesc(desc->outputgate, newv);
374
            }
375
            else {
376
                for (int j=0; j<desc->gateSize(); j++) {
377
                    if (desc->inputgatev)
378
                        adjustGateDesc(desc->inputgatev[j], newv);
379
                    if (desc->outputgatev)
380
                        adjustGateDesc(desc->outputgatev[j], newv);
381
                }
382
            }
383
        }
384
    }
385

    
386
    // install the new array and get its last element
387
    delete [] descv;
388
    descv = newv;
389
    cGate::Desc *newDesc = descv + descvSize++;
390

    
391
    // configure this gatedesc with name and type
392
    cGate::Name key(gatename, type);
393
    NamePool::iterator it = namePool.find(key);
394
    if (it==namePool.end())
395
        it = namePool.insert(key).first;
396
    newDesc->namep = const_cast<cGate::Name*>(&(*it));
397
    newDesc->size = isVector ? 0 : -1;
398
    return newDesc;
399
}
400

    
401
int cModule::findGateDesc(const char *gatename, char& suffix) const
402
{
403
    // determine whether gatename contains "$i"/"$o" suffix
404
    int len = strlen(gatename);
405
    suffix = (len>2 && gatename[len-2]=='$') ? gatename[len-1] : 0;
406
    if (suffix && suffix!='i' && suffix!='o')
407
        return -1;  // invalid suffix ==> no such gate
408

    
409
    // and search accordingly
410
    switch (suffix) {
411
        case '\0':
412
            for (int i=0; i<descvSize; i++) {
413
                const cGate::Desc *desc = descv + i;
414
                if (desc->namep && strcmp(desc->namep->name.c_str(), gatename)==0)
415
                    return i;
416
            }
417
            break;
418
        case 'i':
419
            for (int i=0; i<descvSize; i++) {
420
                const cGate::Desc *desc = descv + i;
421
                if (desc->namep && strcmp(desc->namep->namei.c_str(), gatename)==0)
422
                    return i;
423
            }
424
            break;
425
        case 'o':
426
            for (int i=0; i<descvSize; i++) {
427
                const cGate::Desc *desc = descv + i;
428
                if (desc->namep && strcmp(desc->namep->nameo.c_str(), gatename)==0)
429
                    return i;
430
            }
431
            break;
432
    }
433
    return -1;
434
}
435

    
436
cGate::Desc *cModule::gateDesc(const char *gatename, char& suffix) const
437
{
438
    int descIndex = findGateDesc(gatename, suffix);
439
    if (descIndex<0)
440
        throw cRuntimeError(this, "no such gate or gate vector: `%s'", gatename);
441
    return descv + descIndex;
442
}
443

    
444
#define ENSURE(x)  if (!(x)) throw cRuntimeError(this, eGATEID, id)
445

    
446
cGate *cModule::gate(int id)
447
{
448
    // To make sense of the following code, see comment in cgate.cc,
449
    // titled "Interpretation of gate Ids".
450
    unsigned int h = id & GATEID_HMASK;
451
    if (h==0) {
452
        // scalar gate
453
        unsigned int descIndex = id>>1;
454
        ENSURE(descIndex < (unsigned int) descvSize);
455
        cGate::Desc *desc = descv + descIndex;
456
        ENSURE(desc->namep); // not deleted
457
        ENSURE(!desc->isVector());
458
        ENSURE((id&1)==0 ? desc->getType()!=cGate::OUTPUT : desc->getType()!=cGate::INPUT);
459
        cGate *g = (id&1)==0 ? desc->inputgate : desc->outputgate;
460
        ENSURE((id&1)==(g->pos&1));
461
        return g;
462
    }
463
    else {
464
        // vector gate
465
        unsigned int descIndex = (h>>GATEID_LBITS)-1;
466
        ENSURE(descIndex < (unsigned int) descvSize);
467
        cGate::Desc *desc = descv + descIndex;
468
        ENSURE(desc->namep); // not deleted
469
        ENSURE(desc->isVector());
470
        bool isOutput = id & (1<<(GATEID_LBITS-1));  // L's MSB
471
        ENSURE(isOutput ? desc->getType()!=cGate::INPUT : desc->getType()!=cGate::OUTPUT);
472
        unsigned int index = id & (GATEID_LMASK>>1);
473
        if (index >= (unsigned int)desc->gateSize()) {
474
            // try to issue a useful error message if gate was likely produced as baseId+index
475
            if (index<100000)
476
                throw cRuntimeError(this, "Invalid gate Id %d: size of `%s[]' is only %d, so index %d (deduced from the Id) is out of bounds",
477
                                          id, desc->nameFor(isOutput ? cGate::OUTPUT : cGate::INPUT), desc->gateSize(), index);
478
            else
479
                throw cRuntimeError(this, eGATEID, id); // id probably just plain garbage
480
        }
481
        return isOutput ? desc->outputgatev[index] : desc->inputgatev[index];
482
    }
483
}
484

    
485
#undef ENSURE
486

    
487
cGate *cModule::addGate(const char *gatename, cGate::Type type, bool isVector)
488
{
489
    char suffix;
490
    if (findGateDesc(gatename, suffix)>=0)
491
        throw cRuntimeError(this, "addGate(): Gate `%s' already present", gatename);
492
    if (suffix)
493
        throw cRuntimeError(this, "addGate(): Wrong gate name `%s', must not contain the `$i' or `$o' suffix", gatename);
494

    
495
    // notify pre-change listeners
496
    if (hasListeners(PRE_MODEL_CHANGE)) {
497
        cPreGateAddNotification tmp;
498
        tmp.module = this;
499
        tmp.gateName = gatename;
500
        tmp.gateType = type;
501
        tmp.isVector = isVector;
502
        emit(PRE_MODEL_CHANGE, &tmp);
503
    }
504

    
505
    // create desc for new gate (or gate vector)
506
    cGate::Desc *desc = addGateDesc(gatename, type, isVector);
507
    desc->ownerp = this;
508

    
509
    // if scalar gate, create gate object(s); gate vectors are created with size 0.
510
    cGate *result = NULL;
511
    if (!isVector)
512
    {
513
        cGate *newGate;
514
        if (type!=cGate::OUTPUT)
515
        {
516
            newGate = createGateObject(type);
517
            desc->setInputGate(newGate);
518
            EVCB.gateCreated(newGate);
519
        }
520
        if (type!=cGate::INPUT)
521
        {
522
            newGate = createGateObject(type);
523
            desc->setOutputGate(newGate);
524
            EVCB.gateCreated(newGate);
525
        }
526
        if (type!=cGate::INOUT)
527
            result = newGate;
528
    }
529

    
530
    // notify post-change listeners
531
    if (hasListeners(POST_MODEL_CHANGE)) {
532
        cPostGateAddNotification tmp;
533
        tmp.module = this;
534
        tmp.gateName = gatename;
535
        emit(POST_MODEL_CHANGE, &tmp);
536
    }
537

    
538
    return result;
539
}
540

    
541
static void reallocGatev(cGate **&v, int oldSize, int newSize)
542
{
543
    if (oldSize != newSize) {
544
        cGate **newv = new cGate*[newSize];
545
        memcpy(newv, v, (oldSize<newSize?oldSize:newSize)*sizeof(cGate*));
546
        if (newSize>oldSize)
547
            memset(newv+oldSize, 0, (newSize-oldSize)*sizeof(cGate*));
548
        delete [] v;
549
        v = newv;
550
    }
551
}
552

    
553
void cModule::setGateSize(const char *gatename, int newSize)
554
{
555
    char suffix;
556
    int descIndex = findGateDesc(gatename, suffix);
557
    if (descIndex<0)
558
        throw cRuntimeError(this, "no `%s' or `%s[]' gate", gatename, gatename);
559
    if (suffix)
560
        throw cRuntimeError(this, "setGateSize(): wrong gate name `%s', suffix `$i'/`$o' not accepted here", gatename);
561
    cGate::Desc *desc = descv + descIndex;
562
    if (!desc->isVector())
563
        throw cRuntimeError(this, "setGateSize(): gate `%s' is not a vector gate", gatename);
564
    if (newSize<0)
565
        throw cRuntimeError(this, "setGateSize(): negative vector size (%d) requested for gate %s[]", newSize, gatename);
566
    if (newSize>MAX_VECTORGATESIZE)
567
        throw cRuntimeError(this, "setGateSize(): vector size for gate %s[] too large (%d), limit is %d", gatename, newSize, MAX_VECTORGATESIZE);
568

    
569
    // notify pre-change listeners
570
    if (hasListeners(PRE_MODEL_CHANGE)) {
571
        cPreGateVectorResizeNotification tmp;
572
        tmp.module = this;
573
        tmp.gateName = gatename;
574
        tmp.newSize = newSize;
575
        emit(PRE_MODEL_CHANGE, &tmp);
576
    }
577

    
578
    int oldSize = desc->size;
579
    cGate::Type type = desc->getType();
580

    
581
    // we need to allocate more (to have good gate++ performance) but we
582
    // don't want to store the capacity -- so we'll always calculate the
583
    // capacity from the current size (by rounding it up to the nearest
584
    // multiple of 2, 4, 16, 64).
585
    int oldCapacity = cGate::Desc::capacityFor(oldSize);
586
    int newCapacity = cGate::Desc::capacityFor(newSize);
587

    
588
    // shrink?
589
    if (newSize < oldSize)
590
    {
591
        // remove excess gates
592
        for (int i=oldSize-1; i>=newSize; i--)
593
        {
594
            // check & notify
595
            if (type!=cGate::OUTPUT) {
596
                cGate *gate = desc->inputgatev[i];
597
                if (gate->getPreviousGate() || gate->getNextGate())
598
                    throw cRuntimeError(this,"setGateSize(): Cannot shrink gate vector %s[] to size %d, gate %s still connected", gatename, newSize, gate->getFullPath().c_str());
599
                EVCB.gateDeleted(gate);
600
            }
601
            if (type!=cGate::INPUT) {
602
                cGate *gate = desc->outputgatev[i];
603
                if (gate->getPreviousGate() || gate->getNextGate())
604
                    throw cRuntimeError(this,"setGateSize(): Cannot shrink gate vector %s[] to size %d, gate %s still connected", gatename, newSize, gate->getFullPath().c_str());
605
                EVCB.gateDeleted(gate);
606
            }
607

    
608
            // actually delete
609
            desc->size = i;
610
            if (type!=cGate::OUTPUT) {
611
                delete desc->inputgatev[i];
612
                desc->inputgatev[i] = NULL;
613
            }
614
            if (type!=cGate::INPUT) {
615
                delete desc->outputgatev[i];
616
                desc->outputgatev[i] = NULL;
617
            }
618
        }
619

    
620
        // shrink container
621
        if (type!=cGate::OUTPUT)
622
            reallocGatev(desc->inputgatev, oldCapacity, newCapacity);
623
        if (type!=cGate::INPUT)
624
            reallocGatev(desc->outputgatev, oldCapacity, newCapacity);
625
        desc->size = newSize;
626
    }
627

    
628
    // expand?
629
    if (newSize > oldSize)
630
    {
631
        // expand container (slots newSize..newCapacity will stay unused NULL for now)
632
        if (type!=cGate::OUTPUT)
633
            reallocGatev(desc->inputgatev, oldCapacity, newCapacity);
634
        if (type!=cGate::INPUT)
635
            reallocGatev(desc->outputgatev, oldCapacity, newCapacity);
636

    
637
        // set new size beforehand, because EVCB.gateCreate() calls getId()
638
        // which assumes that gate->index < gateSize.
639
        desc->size = newSize;
640

    
641
        // and create the additional gates
642
        for (int i=oldSize; i<newSize; i++)
643
        {
644
            if (type!=cGate::OUTPUT) {
645
                cGate *newGate = createGateObject(type);
646
                desc->setInputGate(newGate, i);
647
                EVCB.gateCreated(newGate);
648
            }
649
            if (type!=cGate::INPUT) {
650
                cGate *newGate = createGateObject(type);
651
                desc->setOutputGate(newGate, i);
652
                EVCB.gateCreated(newGate);
653
            }
654
        }
655
    }
656

    
657
    // notify post-change listeners
658
    if (hasListeners(POST_MODEL_CHANGE)) {
659
        cPostGateVectorResizeNotification tmp;
660
        tmp.module = this;
661
        tmp.gateName = gatename;
662
        tmp.oldSize = oldSize;
663
        emit(POST_MODEL_CHANGE, &tmp);
664
    }
665

    
666
}
667

    
668
int cModule::gateSize(const char *gatename) const
669
{
670
    char dummy;
671
    const cGate::Desc *desc = gateDesc(gatename, dummy);
672
    return desc->gateSize();
673
}
674

    
675
int cModule::gateBaseId(const char *gatename) const
676
{
677
    char suffix;
678
    int descIndex = findGateDesc(gatename, suffix);
679
    if (descIndex<0)
680
        throw cRuntimeError(this, "gateBaseId(): no such gate or gate vector: `%s'", gatename);
681
    const cGate::Desc *desc = descv+descIndex;
682
    if (desc->getType()==cGate::INOUT && !suffix)
683
        throw cRuntimeError(this, "gateBaseId(): inout gate `%s' cannot be referenced without $i/$o suffix", gatename);
684
    bool isInput = (suffix=='i' || desc->getType()==cGate::INPUT);
685

    
686
    // To make sense of the following code, see comment in cgate.cc,
687
    // titled "Interpretation of gate Ids".
688
    int id;
689
    if (!desc->isVector())
690
        id = (descIndex<<1) | (isInput?0:1);
691
    else
692
        id = ((descIndex+1)<<GATEID_LBITS) | ((isInput?0:1)<<(GATEID_LBITS-1));
693
    return id;
694
}
695

    
696
cGate *cModule::gate(const char *gatename, int index)
697
{
698
    char suffix;
699
    const cGate::Desc *desc = gateDesc(gatename, suffix);
700
    if (desc->getType()==cGate::INOUT && !suffix)
701
        throw cRuntimeError(this, "Inout gate `%s' cannot be referenced without $i/$o suffix", gatename);
702
    bool isInput = (suffix=='i' || desc->getType()==cGate::INPUT);
703

    
704
    if (!desc->isVector())
705
    {
706
        // gate is scalar
707
        if (index!=-1)
708
            throw cRuntimeError(this, "Scalar gate `%s' referenced with index", gatename);
709
        return isInput ? desc->inputgate : desc->outputgate;
710
    }
711
    else
712
    {
713
        // gate is vector
714
        if (index<0)
715
            throw cRuntimeError(this, "%s when accessing vector gate `%s'", (index==-1?"No gate index specified":"Negative gate index specified"), gatename);
716
        if (index>=desc->size)
717
            throw cRuntimeError(this, "Gate index %d out of range when accessing vector gate `%s[]' with size %d", index, gatename, desc->size);
718
        return isInput ? desc->inputgatev[index] : desc->outputgatev[index];
719
    }
720
}
721

    
722
int cModule::findGate(const char *gatename, int index) const
723
{
724
    char suffix;
725
    int descIndex = findGateDesc(gatename, suffix);
726
    if (descIndex<0)
727
        return -1;  // no such gate name
728
    const cGate::Desc *desc = descv + descIndex;
729
    if (desc->getType()==cGate::INOUT && !suffix)
730
        return -1;  // inout gate cannot be referenced without "$i" or "$o" suffix
731
    bool isInput = (suffix=='i' || desc->getType()==cGate::INPUT);
732

    
733
    if (!desc->isVector())
734
    {
735
        // gate is scalar
736
        if (index!=-1)
737
            return -1;  // wrong: scalar gate referenced with index
738
        return isInput ? desc->inputgate->getId() : desc->outputgate->getId();
739
    }
740
    else
741
    {
742
        // gate is vector
743
        if (index<0 || index>=desc->size)
744
            return -1;  // index not specified (-1) or out of range
745
        return isInput ? desc->inputgatev[index]->getId() : desc->outputgatev[index]->getId();
746
    }
747
}
748

    
749
cGate *cModule::gateHalf(const char *gatename, cGate::Type type, int index)
750
{
751
    char dummy;
752
    const cGate::Desc *desc = gateDesc(gatename, dummy);
753
    const char *nameWithSuffix = (type==cGate::INPUT) ? desc->namep->namei.c_str() : desc->namep->nameo.c_str();
754
    return gate(nameWithSuffix, index);
755
}
756

    
757
bool cModule::hasGate(const char *gatename, int index) const
758
{
759
    char suffix;
760
    int descIndex = findGateDesc(gatename, suffix);
761
    if (descIndex<0)
762
        return false;
763
    const cGate::Desc *desc = descv + descIndex;
764
    return index==-1 ? true : (index>=0 && index<desc->size);
765
}
766

    
767
void cModule::deleteGate(const char *gatename)
768
{
769
    char suffix;
770
    cGate::Desc *desc = gateDesc(gatename, suffix);
771
    if (suffix)
772
        throw cRuntimeError(this, "Cannot delete one half of an inout gate: `%s'", gatename);
773
    disposeGateDesc(desc, true);
774
}
775

    
776
std::vector<const char *> cModule::getGateNames() const
777
{
778
    std::vector<const char *> result;
779
    for (int i=0; i<descvSize; i++)
780
        if (descv[i].namep)
781
            result.push_back(descv[i].namep->name.c_str());
782
    return result;
783
}
784

    
785
cGate::Type cModule::gateType(const char *gatename) const
786
{
787
    char suffix;
788
    const cGate::Desc *desc = gateDesc(gatename, suffix);
789
    if (suffix)
790
        return suffix=='i' ? cGate::INPUT : cGate::OUTPUT;
791
    else
792
        return desc->namep->type;
793
}
794

    
795
bool cModule::isGateVector(const char *gatename) const
796
{
797
    char dummy;
798
    const cGate::Desc *desc = gateDesc(gatename, dummy);
799
    return desc->isVector();
800
}
801

    
802
//XXX test code:
803
//    bool operator()(cGate *a, cGate *b) {
804
//        printf("   comparing %s, %s ==> ", (a?a->getFullName():NULL), (b?b->getFullName():NULL) );
805
//        bool x = (a && a->isConnectedInside()) > (b && b->isConnectedInside());
806
//        printf("%d > %d : ", (a && a->isConnectedInside()), (b && b->isConnectedInside()));
807
//        printf("%d\n", x);
808
//        return x;
809
//    }
810

    
811
struct less_gateConnectedInside {
812
    bool operator()(cGate *a, cGate *b) {return (a && a->isConnectedInside()) > (b && b->isConnectedInside());}
813
};
814

    
815
struct less_gateConnectedOutside {
816
    bool operator()(cGate *a, cGate *b) {return (a && a->isConnectedOutside()) > (b && b->isConnectedOutside());}
817
};
818

    
819
struct less_gatePairConnectedInside {
820
    cGate **otherv;
821
    less_gatePairConnectedInside(cGate **otherv) {this->otherv = otherv;}
822
    bool operator()(cGate *a, cGate *b) {
823
        return (a && a->isConnectedInside()) > (b && b->isConnectedInside()) &&
824
               (a && otherv[a->getIndex()]->isConnectedInside()) > (b && otherv[b->getIndex()]->isConnectedInside());
825
    }
826
};
827

    
828
struct less_gatePairConnectedOutside {
829
    cGate **otherv;
830
    less_gatePairConnectedOutside(cGate **otherv) {this->otherv = otherv;}
831
    bool operator()(cGate *a, cGate *b) {
832
        return (a && a->isConnectedOutside()) > (b && b->isConnectedOutside()) &&
833
               (a && otherv[a->getIndex()]->isConnectedOutside()) > (b && otherv[b->getIndex()]->isConnectedOutside());
834
    }
835
};
836

    
837

    
838
cGate *cModule::getOrCreateFirstUnconnectedGate(const char *gatename, char suffix,
839
                                                bool inside, bool expand)
840
{
841
    // look up gate
842
    char suffix1;
843
    cGate::Desc *desc = const_cast<cGate::Desc *>(gateDesc(gatename, suffix1));
844
    if (!desc->isVector())
845
        throw cRuntimeError(this,"getOrCreateFirstUnconnectedGate(): gate `%s' is not a vector gate", gatename);
846
    if (suffix1 && suffix)
847
        throw cRuntimeError(this,"getOrCreateFirstUnconnectedGate(): gate `%s' AND suffix `%c' given", gatename, suffix);
848
    suffix = suffix | suffix1;
849

    
850
    // determine whether input or output gates to check
851
    bool inputSide;
852
    if (!suffix)
853
    {
854
        if (desc->getType()==cGate::INOUT)
855
            throw cRuntimeError(this,"getOrCreateFirstUnconnectedGate(): inout gate specified but no suffix");
856
        inputSide = desc->getType()==cGate::INPUT;
857
    }
858
    else
859
    {
860
        if (suffix!='i' && suffix!='o')
861
            throw cRuntimeError(this,"getOrCreateFirstUnconnectedGate(): wrong gate name suffix `%c'", suffix);
862
        inputSide = suffix=='i';
863
    }
864

    
865
    // gate array we'll be looking at
866
    cGate **gatev = inputSide ? desc->inputgatev : desc->outputgatev;
867
    int oldSize = desc->size;
868

    
869
    // since gates get connected from the beginning of the vector, we can do
870
    // binary search for the first unconnected gate. In the (rare) case when
871
    // gates are not connected in order (i.e. some high gate indices get
872
    // connected before lower ones), binary search may not be able to find the
873
    // "holes" (unconnected gates) and we expand the gate unnecessarily.
874
    // Note: NULL is used as a synonym for "any unconnected gate" (see less_* struct).
875
    cGate **it = inside ?
876
        std::lower_bound(gatev, gatev+oldSize, (cGate *)NULL, less_gateConnectedInside()) :
877
        std::lower_bound(gatev, gatev+oldSize, (cGate *)NULL, less_gateConnectedOutside());
878
    if (it != gatev+oldSize)
879
        return *it;
880

    
881
    // no unconnected gate: expand gate vector
882
    if (expand)
883
    {
884
        setGateSize(desc->namep->name.c_str(), oldSize+1);   //FIXME spare extra name lookup!!!
885
        return inputSide ? desc->inputgatev[oldSize] : desc->outputgatev[oldSize];
886
    }
887
    else
888
    {
889
        // gate is not allowed to expand, so let's try harder to find an unconnected gate
890
        // (in case the binary search missed it)
891
        for (int i=0; i<oldSize; i++)
892
            if (inside ? !gatev[i]->isConnectedInside() : !gatev[i]->isConnectedOutside())
893
                return gatev[i];
894
        return NULL; // sorry
895
    }
896
}
897

    
898
void cModule::getOrCreateFirstUnconnectedGatePair(const char *gatename,
899
                                                  bool inside, bool expand,
900
                                                  cGate *&gatein, cGate *&gateout)
901
{
902
    // look up gate
903
    char suffix;
904
    cGate::Desc *desc = const_cast<cGate::Desc *>(gateDesc(gatename, suffix));
905
    if (!desc->isVector())
906
        throw cRuntimeError(this,"getOrCreateFirstUnconnectedGatePair(): gate `%s' is not a vector gate", gatename);
907
    if (suffix)
908
        throw cRuntimeError(this,"getOrCreateFirstUnconnectedGatePair(): inout gate expected, without `$i'/`$o' suffix");
909

    
910
    // the gate arrays we'll work with
911
    int oldSize = desc->size;
912
    cGate **inputgatev = desc->inputgatev;
913
    cGate **outputgatev = desc->outputgatev;
914

    
915
    // binary search for the first unconnected gate -- see explanation in method above
916
    cGate **it = inside ?
917
        std::lower_bound(inputgatev, inputgatev+oldSize, (cGate *)NULL, less_gatePairConnectedInside(outputgatev)) :
918
        std::lower_bound(inputgatev, inputgatev+oldSize, (cGate *)NULL, less_gatePairConnectedOutside(outputgatev));
919
    if (it != inputgatev+oldSize) {
920
        gatein = *it;
921
        gateout = outputgatev[gatein->getIndex()];
922
        return;
923
    }
924

    
925
    // no unconnected gate: expand gate vector
926
    if (expand)
927
    {
928
        setGateSize(desc->namep->name.c_str(), oldSize+1); //FIXME spare extra name lookup!!!
929
        gatein = desc->inputgatev[oldSize];
930
        gateout = desc->outputgatev[oldSize];
931
        return;
932
    }
933
    else
934
    {
935
        // gate is not allowed to expand, so let's try harder to find an unconnected gate
936
        // (in case the binary search missed it)
937
        for (int i=0; i<oldSize; i++)
938
            if (inside ? !inputgatev[i]->isConnectedInside() : !inputgatev[i]->isConnectedOutside())
939
                if (inside ? !outputgatev[i]->isConnectedInside() : !outputgatev[i]->isConnectedOutside())
940
                    {gatein = inputgatev[i]; gateout = outputgatev[i]; return;}
941
        gatein = gateout = NULL; // sorry
942
    }
943
}
944

    
945
int cModule::gateCount() const
946
{
947
    int n = 0;
948
    for (int i=0; i<descvSize; i++)
949
    {
950
        cGate::Desc *desc = descv + i;
951
        if (desc->namep) {
952
            if (!desc->isVector())
953
                n += (desc->getType()==cGate::INOUT) ? 2 : 1;
954
            else
955
                n += (desc->getType()==cGate::INOUT) ? 2*desc->size : desc->size;
956
        }
957
    }
958
    return n;
959
}
960

    
961
cGate *cModule::gateByOrdinal(int k) const
962
{
963
    GateIterator it(this);
964
    it += k;
965
    return it.end() ? NULL : it();
966
}
967

    
968
bool cModule::checkInternalConnections() const
969
{
970
    // Note: This routine only checks if all gates are connected or not.
971
    // It does NOT check where and how they are connected!
972
    // To allow a gate go unconnected, annotate it with @loose or @directIn.
973

    
974
    // check this compound module if its inside is connected ok
975
    // Note: checking of the inner side of compound module gates
976
    // cannot be turned off with @loose
977
    for (GateIterator i(this); !i.end(); i++)
978
    {
979
       cGate *g = i();
980
       if (g->size()!=0 && !g->isConnectedInside())
981
            throw cRuntimeError(this,"Gate `%s' is not connected to a submodule (or internally to another gate of the same module)", g->getFullPath().c_str());
982
    }
983

    
984
    // check submodules
985
    for (SubmoduleIterator submod(this); !submod.end(); submod++)
986
    {
987
        cModule *m = submod();
988
        for (GateIterator i(m); !i.end(); i++)
989
        {
990
            cGate *g = i();
991
            if (g->size()!=0 && !g->isConnectedOutside() &&
992
                g->getProperties()->getAsBool("loose")==false &&
993
                g->getProperties()->getAsBool("directIn")==false)
994
                throw cRuntimeError(this,"Gate `%s' is not connected to sibling or parent module", g->getFullPath().c_str());
995
        }
996
    }
997
    return true;
998
}
999

    
1000
int cModule::findSubmodule(const char *submodname, int idx)
1001
{
1002
    for (SubmoduleIterator i(this); !i.end(); i++)
1003
        if (i()->isName(submodname) &&
1004
            ((idx==-1 && !i()->isVector()) || i()->getIndex()==idx)
1005
           )
1006
            return i()->getId();
1007
    return -1;
1008
}
1009

    
1010
cModule *cModule::getSubmodule(const char *submodname, int idx)
1011
{
1012
    for (SubmoduleIterator i(this); !i.end(); i++)
1013
        if (i()->isName(submodname) &&
1014
            ((idx==-1 && !i()->isVector()) || i()->getIndex()==idx)
1015
           )
1016
            return i();
1017
    return NULL;
1018
}
1019

    
1020
cModule *cModule::getModuleByRelativePath(const char *path)
1021
{
1022
    // start tokenizing the path
1023
    opp_string pathbuf(path);
1024
    char *s = strtok(pathbuf.buffer(),".");
1025

    
1026
    // search starts from this module
1027
    cModule *modp = this;
1028

    
1029
    // match components of the path
1030
    do {
1031
        char *b;
1032
        if ((b=strchr(s,'['))==NULL)
1033
            modp = modp->getSubmodule(s);  // no index given
1034
        else
1035
        {
1036
            if (s[strlen(s)-1]!=']')
1037
                throw cRuntimeError(this,"getModuleByRelativePath(): syntax error in path `%s'", path);
1038
            *b='\0';
1039
            modp = modp->getSubmodule(s,atoi(b+1));
1040
        }
1041
    } while ((s=strtok(NULL,"."))!=NULL && modp!=NULL);
1042

    
1043
    return modp;  // NULL if not found
1044
}
1045

    
1046
cPar& cModule::getAncestorPar(const char *name)
1047
{
1048
    // search parameter in parent modules
1049
    cModule *pmod = this;
1050
    int k;
1051
    while (pmod && (k=pmod->findPar(name))<0)
1052
        pmod = pmod->getParentModule();
1053
    if (!pmod)
1054
        throw cRuntimeError(this,"has no ancestor parameter called `%s'",name);
1055
    return pmod->par(k);
1056
}
1057

    
1058
void cModule::finalizeParameters()
1059
{
1060
    // temporarily switch context
1061
    cContextSwitcher tmp(this);
1062
    cContextTypeSwitcher tmp2(CTX_BUILD);
1063

    
1064
    cComponent::finalizeParameters(); // this will read input parameters
1065

    
1066
    // set up gate vectors (their sizes may depend on the parameter settings)
1067
    getModuleType()->setupGateVectors(this);
1068
}
1069

    
1070
int cModule::buildInside()
1071
{
1072
    if (buildInsideCalled())
1073
        throw cRuntimeError(this, "buildInside() already called for this module");
1074

    
1075
    // call finalizeParameters() if user has forgotten to do it;
1076
    // this is needed to make dynamic module creation more robust
1077
    if (!parametersFinalized())
1078
        finalizeParameters();
1079

    
1080
    // temporarily switch context
1081
    cContextSwitcher tmp(this);
1082
    cContextTypeSwitcher tmp2(CTX_BUILD);
1083

    
1084
    // call doBuildInside() in this context
1085
    doBuildInside();
1086

    
1087
    setFlag(FL_BUILDINSIDE_CALLED, true);
1088

    
1089
    return 0;
1090
}
1091

    
1092
void cModule::deleteModule()
1093
{
1094
    // check this module doesn't contain the executing module somehow
1095
    for (cModule *mod = simulation.getContextModule(); mod; mod = mod->getParentModule())
1096
        if (mod==this)
1097
            throw cRuntimeError(this, "it is not supported to delete a module that contains "
1098
                                      "the currently executing simple module");
1099

    
1100
    // notify pre-change listeners
1101
    if (hasListeners(PRE_MODEL_CHANGE)) {
1102
        cPreModuleDeleteNotification tmp;
1103
        tmp.module = this;
1104
        emit(PRE_MODEL_CHANGE, &tmp);
1105
    }
1106

    
1107
    cModule *parent = getParentModule();
1108
    if (!parent || !parent->hasListeners(POST_MODEL_CHANGE))
1109
    {
1110
        // no listeners, just do it
1111
        delete this;
1112
    }
1113
    else {
1114
        // need to fill in notification data before deleting the module
1115
        cPostModuleDeleteNotification tmp;
1116
        tmp.module = this;
1117
        tmp.moduleId = getId();
1118
        tmp.moduleType = getModuleType();
1119
        std::string tmpname = getName();
1120
        tmp.moduleName = tmpname.c_str();
1121
        tmp.parentModule = getParentModule();
1122
        tmp.vectorSize = getVectorSize();
1123
        tmp.index = getIndex();
1124

    
1125
        delete this;
1126

    
1127
        parent->emit(POST_MODEL_CHANGE, &tmp);
1128
    }
1129
}
1130

    
1131
void cModule::changeParentTo(cModule *mod)
1132
{
1133
    if (!mod)
1134
        throw cRuntimeError(this, "changeParentTo(): got NULL pointer");
1135

    
1136
    // gates must be unconnected to avoid connections breaking module hierarchy rules
1137
    cGate *g;
1138
    for (GateIterator i(this); !i.end(); i++)
1139
        if (g=i(), g->isConnectedOutside())
1140
            throw cRuntimeError(this, "changeParentTo(): gates of the module must not be "
1141
                                      "connected (%s is connected now)", g->getFullName());
1142

    
1143
    // cannot insert module under one of its own submodules
1144
    for (cModule *m = mod; m; m = m->getParentModule())
1145
        if (m==this)
1146
            throw cRuntimeError(this, "changeParentTo(): cannot move module under one of its own submodules");
1147

    
1148
    // notify pre-change listeners
1149
    if (hasListeners(PRE_MODEL_CHANGE)) {
1150
        cPreModuleReparentNotification tmp;
1151
        tmp.module = this;
1152
        tmp.newParentModule = mod;
1153
        mod->emit(PRE_MODEL_CHANGE, &tmp);
1154
    }
1155

    
1156
    // do it
1157
    cModule *oldparent = getParentModule();
1158
    oldparent->removeSubmodule(this);
1159
    mod->insertSubmodule(this);
1160

    
1161
    // notify environment
1162
    EVCB.moduleReparented(this,oldparent);
1163

    
1164
    // notify post-change listeners
1165
    if (hasListeners(POST_MODEL_CHANGE)) {
1166
        cPostModuleReparentNotification tmp;
1167
        tmp.module = this;
1168
        tmp.oldParentModule = oldparent;
1169
        mod->emit(POST_MODEL_CHANGE, &tmp);
1170
    }
1171
}
1172

    
1173
void cModule::callInitialize()
1174
{
1175
    // Perform stage==0 for channels, then stage==0 for submodules, then
1176
    // stage==1 for channels, stage==1 for modules, etc.
1177
    //
1178
    // Rationale: modules sometimes want to send messages already in stage==0,
1179
    // and channels must be ready for that at that time, i.e. passed at least
1180
    // stage==0.
1181
    //
1182
    cContextTypeSwitcher tmp(CTX_INITIALIZE);
1183
    int stage = 0;
1184
    bool moreChannelStages = true, moreModuleStages = true;
1185
    while (moreChannelStages || moreModuleStages)
1186
    {
1187
        if (moreChannelStages)
1188
            moreChannelStages = initializeChannels(stage);
1189
        if (moreModuleStages)
1190
            moreModuleStages = initializeModules(stage);
1191
        ++stage;
1192
    }
1193
}
1194

    
1195
bool cModule::callInitialize(int stage)
1196
{
1197
    cContextTypeSwitcher tmp(CTX_INITIALIZE);
1198
    bool moreChannelStages = initializeChannels(stage);
1199
    bool moreModuleStages = initializeModules(stage);
1200
    return moreChannelStages || moreModuleStages;
1201
}
1202

    
1203
bool cModule::initializeChannels(int stage)
1204
{
1205
    if (simulation.getContextType()!=CTX_INITIALIZE)
1206
        throw cRuntimeError("internal function initializeChannels() may only be called via callInitialize()");
1207

    
1208
    // initialize channels directly under this module
1209
    bool moreStages = false;
1210
    for (ChannelIterator chan(this); !chan.end(); chan++)
1211
        if (chan()->initializeChannel(stage))
1212
            moreStages = true;
1213

    
1214
    // then recursively initialize channels within our submodules too
1215
    for (SubmoduleIterator submod(this); !submod.end(); submod++)
1216
        if (submod()->initializeChannels(stage))
1217
            moreStages = true;
1218

    
1219
    return moreStages;
1220
}
1221

    
1222
bool cModule::initializeModules(int stage)
1223
{
1224
    if (simulation.getContextType()!=CTX_INITIALIZE)
1225
        throw cRuntimeError("internal function initializeModules() may only be called via callInitialize()");
1226

    
1227
    if (stage==0)
1228
    {
1229
        if (initialized())
1230
            throw cRuntimeError(this, "initialize() already called for this module");
1231

    
1232
        // call buildInside() if user has forgotten to do it; this is needed
1233
        // to make dynamic module creation more robust
1234
        if (!buildInsideCalled())
1235
            buildInside();
1236
    }
1237

    
1238
    // first call initialize(stage) for this module...
1239
    int numStages = numInitStages();
1240
    if (stage < numStages)
1241
    {
1242
        // switch context for the duration of the call
1243
        Enter_Method_Silent("initialize(%d)", stage);
1244
        ev.componentInitBegin(this, stage);
1245
        try {
1246
            initialize(stage);
1247
        } catch (cException&) {
1248
            throw;
1249
        } catch (std::exception& e) {
1250
            throw cRuntimeError("%s: %s", opp_typename(typeid(e)), e.what());
1251
        }
1252
    }
1253

    
1254
    // then recursively initialize submodules
1255
    bool moreStages = stage < numStages-1;
1256
    for (SubmoduleIterator submod(this); !submod.end(); submod++)
1257
        if (submod()->initializeModules(stage))
1258
            moreStages = true;
1259

    
1260
    // as a last step, call handleParameterChange() to notify the component about
1261
    // parameter changes that occured during initialization phase
1262
    if (!moreStages)
1263
    {
1264
        // a module is initialized when all init stages have been completed
1265
        // (both its own and on all its submodules)
1266
        setFlag(FL_INITIALIZED, true);
1267
        handleParameterChange(NULL);
1268
    }
1269

    
1270
    return moreStages;
1271
}
1272

    
1273
void cModule::callFinish()
1274
{
1275
    // This is the interface for calling finish().
1276

    
1277
    // first call it for submodules and channels...
1278
    for (ChannelIterator chan(this); !chan.end(); chan++)
1279
        chan()->callFinish();
1280
    for (SubmoduleIterator submod(this); !submod.end(); submod++)
1281
        submod()->callFinish();
1282

    
1283
    // ...then for this module, in our context: save parameters, then finish()
1284
    cContextSwitcher tmp(this);
1285
    cContextTypeSwitcher tmp2(CTX_FINISH);
1286
    try {
1287
        recordParametersAsScalars();
1288
        //Enter_Method_Silent("finish()");
1289
        finish();
1290
        fireFinish();
1291
    } catch (cException&) {
1292
        throw;
1293
    } catch (std::exception& e) {
1294
        throw cRuntimeError("%s: %s", opp_typename(typeid(e)), e.what());
1295
    }
1296
}
1297

    
1298
//----
1299

    
1300
void cModule::GateIterator::init(const cModule *module)
1301
{
1302
    this->module = module;
1303
    descIndex = 0;
1304
    isOutput = false;
1305
    index = 0;
1306

    
1307
    while (!end() && current()==NULL)
1308
        advance();
1309
}
1310

    
1311
void cModule::GateIterator::advance()
1312
{
1313
    cGate::Desc *desc = module->descv + descIndex;
1314

    
1315
    if (desc->namep) {
1316
        if (isOutput==false && desc->getType()==cGate::OUTPUT) {
1317
            isOutput = true;
1318
            return;
1319
        }
1320

    
1321
        if (desc->isVector()) {
1322
            if (index < desc->size-1) {
1323
                index++;
1324
                return;
1325
            }
1326
            index = 0;
1327
        }
1328
        if (isOutput==false && desc->getType()!=cGate::INPUT) {
1329
            isOutput = true;
1330
            return;
1331
        }
1332
    }
1333
    if (descIndex < module->descvSize) {
1334
        descIndex++;
1335
        isOutput = false;
1336
        index = 0;
1337
    }
1338
}
1339

    
1340
bool cModule::GateIterator::end() const
1341
{
1342
    return descIndex >= module->descvSize;
1343
}
1344

    
1345
cGate *cModule::GateIterator::current() const
1346
{
1347
    if (descIndex >= module->descvSize)
1348
        return NULL;
1349
    cGate::Desc *desc = module->descv + descIndex;
1350
    if (!desc->namep)
1351
        return NULL; // deleted gate
1352
    if (isOutput==false && desc->getType()==cGate::OUTPUT)
1353
        return NULL; // isOutput still incorrect
1354
    if (!desc->isVector())
1355
        return isOutput ? desc->outputgate : desc->inputgate;
1356
    else if (desc->size==0)
1357
        return NULL;
1358
    else
1359
        return isOutput ? desc->outputgatev[index] : desc->inputgatev[index];
1360
}
1361

    
1362
cGate *cModule::GateIterator::operator++(int)
1363
{
1364
    if (end())
1365
        return NULL;
1366
    cGate *gate = NULL;
1367
    do {
1368
        advance();
1369
    } while (!end() && (gate=current())==NULL);
1370
    return gate;
1371
}
1372

    
1373
cGate *cModule::GateIterator::operator+=(int k)
1374
{
1375
    //FIXME this is the primitive solution. We could do better, like skip gate vectors at once, etc
1376
    for (int i=0; i<k; i++)
1377
        (*this)++;
1378
    return (*this)();
1379
}
1380

    
1381
//----
1382

    
1383
void cModule::ChannelIterator::init(const cModule *parentmodule)
1384
{
1385
    // loop through the gates of parentmodule and its submodules
1386
    // to fill in the channels[] vector
1387
    bool parent = false;
1388
    channels.clear();
1389
    for (SubmoduleIterator it(parentmodule); !parent; it++)
1390
    {
1391
        const cModule *mod = !it.end() ? it() : (parent=true,parentmodule);
1392

    
1393
        for (GateIterator i(mod); !i.end(); i++)
1394
        {
1395
            const cGate *gate = i();
1396
            cGate::Type wantedGateType = parent ? cGate::INPUT : cGate::OUTPUT;
1397
            if (gate && gate->getChannel() && gate->getType()==wantedGateType)
1398
                channels.push_back(gate->getChannel());
1399
        }
1400
    }
1401

    
1402
    // reset iterator position too
1403
    k = 0;
1404
}
1405

    
1406