Project

General

Profile

Statistics
| Branch: | Revision:

root / src / sim / cmodule.cc @ 18befb2d

History | View | Annotate | Download (44.8 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
#include "eventtype.h"
38

    
39
USING_NAMESPACE
40

    
41

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

    
46

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

    
51

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

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

    
61
    descvSize = 0;
62
    descv = NULL;
63

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

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

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

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

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

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

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

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

    
115
    delete [] fullname;
116
}
117

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
269
cModule::NamePool cModule::namePool;
270

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
486
#undef ENSURE
487

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

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

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

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

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

    
539
    return result;
540
}
541

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

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

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

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

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

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

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

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

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

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

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

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

    
667
}
668

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
838

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1088
    setFlag(FL_BUILDINSIDE_CALLED, true);
1089

    
1090
    return 0;
1091
}
1092

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

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

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

    
1126
        delete this;
1127

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1220
    return moreStages;
1221
}
1222

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

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

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

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

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

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

    
1271
    return moreStages;
1272
}
1273

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

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

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

    
1299
//----
1300

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

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

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

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

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

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

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

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

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

    
1382
//----
1383

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

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

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

    
1407
EventType* cModule::getEventType(cMessage* msg)
1408
{
1409
        // Event type exists?
1410
        for(knownEventTypes_t::iterator it=knownEventTypes.begin();it!=knownEventTypes.end();++it)
1411
        {
1412
                if(*it==*msg)
1413
                {
1414
                        return &(*it);
1415
                }
1416
        }
1417

    
1418
        // If event type does not exist, create it:
1419
        knownEventTypes.emplace_back(msg);
1420
        return &knownEventTypes.back();
1421
}
1422