Project

General

Profile

Statistics
| Branch: | Revision:

root / src / sim / cpar.cc @ a3be1d55

History | View | Annotate | Download (9.77 KB)

1
//=========================================================================
2
//  CPAR.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 "cpar.h"
20
#include "cparimpl.h"
21
#include "cproperties.h"
22
#include "cproperty.h"
23
#include "ccomponent.h"
24
#include "ccomponenttype.h"
25
#include "cmodule.h"
26
#include "csimulation.h"
27
#include "commonutil.h"
28
#include "cenvir.h"
29
#include "cmodelchange.h"
30

    
31
#ifdef WITH_PARSIM
32
#include "ccommbuffer.h"
33
#endif
34

    
35
USING_NAMESPACE
36

    
37

    
38
cPar::~cPar()
39
{
40
    if (p && !p->isShared())
41
        delete p;
42
}
43

    
44
void cPar::init(cComponent *component, cParImpl *newp)
45
{
46
    ASSERT(!p && newp);
47
    ownercomponent = component;
48
    p = newp;
49
}
50

    
51
void cPar::setImpl(cParImpl *newp)
52
{
53
    ASSERT(p && newp);
54
    if (!p->isShared())
55
        delete p;
56
    p = newp;
57
}
58

    
59
void cPar::moveto(cPar& other)
60
{
61
    other.ownercomponent = ownercomponent;
62
    other.p = p;
63
    p = NULL;
64
}
65

    
66
const char *cPar::getName() const
67
{
68
    return p->getName();
69
}
70

    
71
std::string cPar::info() const
72
{
73
    return p->info();
74
}
75

    
76
std::string cPar::detailedInfo() const
77
{
78
    return p->detailedInfo() + " " + getProperties()->info();
79
}
80

    
81
cParImpl *cPar::copyIfShared()
82
{
83
    if (p->isShared()) {
84
        p = p->dup();
85
        p->setIsShared(false);
86
    }
87
    return p;
88
}
89

    
90
cObject *cPar::getOwner() const
91
{
92
    return ownercomponent;
93
}
94

    
95
void cPar::operator=(const cPar& other)
96
{
97
    // this method is not used by the sim kernel, only (rarely) by some
98
    // simulation models to copy parameters
99
    if (other.isExpression())
100
    {
101
        setExpression(other.getExpression()->dup());
102
    }
103
    else
104
    {
105
        switch (getType())
106
        {
107
            case BOOL:   setBoolValue(other.boolValue()); break;
108
            case DOUBLE: setDoubleValue(other.doubleValue()); break;
109
            case LONG:   setLongValue(other.longValue()); break;
110
            case STRING: setStringValue(other.stdstringValue().c_str()); break;
111
            case XML:    setXMLValue(other.xmlValue()); break;
112
            default:     ASSERT(false);
113
        }
114
    }
115
}
116

    
117
cProperties *cPar::getProperties() const
118
{
119
    cComponent *component = check_and_cast<cComponent *>(getOwner());
120
    cComponentType *componentType = component->getComponentType();
121
    cProperties *props = componentType->getParamProperties(getName());
122
    return props;
123
}
124

    
125
const char *cPar::getTypeName(Type t)
126
{
127
    switch (t)
128
    {
129
        case BOOL:   return "bool";
130
        case DOUBLE: return "double";
131
        case LONG:   return "long";
132
        case STRING: return "string";
133
        case XML:    return "xml";
134
        default:     return "???";
135
    }
136
}
137

    
138
// note: the following one-liners should really be inline functions, but
139
// they can't be put into cpar.h because of declaration order.
140

    
141
std::string cPar::str() const
142
{
143
    return p->str();
144
}
145

    
146
cPar::Type cPar::getType() const
147
{
148
    return p->getType();
149
}
150

    
151
bool cPar::isShared() const
152
{
153
    return p->isShared();
154
}
155

    
156
bool cPar::isSet() const
157
{
158
    return p->isSet();
159
}
160

    
161
bool cPar::containsValue() const
162
{
163
    return p->containsValue();
164
}
165

    
166
bool cPar::isNumeric() const
167
{
168
    return p->isNumeric();
169
}
170

    
171
bool cPar::isVolatile() const
172
{
173
    return p->isVolatile();
174
}
175

    
176
bool cPar::isExpression() const
177
{
178
    return p->isExpression();
179
}
180

    
181
#define TRY(x) \
182
    try {x;} catch (std::exception& e) {throw cRuntimeError(ePARAM, getFullName(), e.what());}
183

    
184
bool cPar::boolValue() const
185
{
186
    TRY(return p->boolValue(ownercomponent));
187
}
188

    
189
long cPar::longValue() const
190
{
191
    TRY(return p->longValue(ownercomponent));
192
}
193

    
194
double cPar::doubleValue() const
195
{
196
    TRY(return p->doubleValue(ownercomponent));
197
}
198

    
199
const char *cPar::getUnit() const
200
{
201
    return p->getUnit();
202
}
203

    
204
const char *cPar::stringValue() const
205
{
206
    TRY(return p->stringValue(ownercomponent));
207
}
208

    
209
std::string cPar::stdstringValue() const
210
{
211
    TRY(return p->stdstringValue(ownercomponent));
212
}
213

    
214
cXMLElement *cPar::xmlValue() const
215
{
216
    TRY(return p->xmlValue(ownercomponent));
217
}
218

    
219
cExpression *cPar::getExpression() const
220
{
221
    return p->getExpression();
222
}
223

    
224
cPar& cPar::setBoolValue(bool b)
225
{
226
    beforeChange();
227
    copyIfShared();
228
    p->setBoolValue(b);
229
    afterChange();
230
    return *this;
231
}
232

    
233
cPar& cPar::setLongValue(long l)
234
{
235
    beforeChange();
236
    copyIfShared();
237
    p->setLongValue(l);
238
    afterChange();
239
    return *this;
240
}
241

    
242
cPar& cPar::setDoubleValue(double d)
243
{
244
    beforeChange();
245
    copyIfShared();
246
    p->setDoubleValue(d);
247
    afterChange();
248
    return *this;
249
}
250

    
251
cPar& cPar::setStringValue(const char *s)
252
{
253
    beforeChange();
254
    copyIfShared();
255
    p->setStringValue(s);
256
    afterChange();
257
    return *this;
258
}
259

    
260
cPar& cPar::setXMLValue(cXMLElement *node)
261
{
262
    beforeChange();
263
    copyIfShared();
264
    p->setXMLValue(node);
265
    afterChange();
266
    return *this;
267
}
268

    
269
cPar& cPar::setExpression(cExpression *e)
270
{
271
    beforeChange();
272
    copyIfShared();
273
    p->setExpression(e);
274
    afterChange();
275
    return *this;
276
}
277

    
278
void cPar::beforeChange()
279
{
280
    // notify pre-change listeners
281
    if (ownercomponent->hasListeners(PRE_MODEL_CHANGE)) {
282
        cPreParameterChangeNotification tmp;
283
        tmp.par = this;
284
        ownercomponent->emit(PRE_MODEL_CHANGE, &tmp);
285
    }
286
}
287

    
288
void cPar::afterChange()
289
{
290
    ASSERT(ownercomponent);
291
    // call owner's component's handleParameterChange() method,
292
    // i.e. parameter change notification is allowed only on fully initialized components
293
    if (ownercomponent->initialized())
294
    {
295
        cContextSwitcher tmp(ownercomponent);
296
        ownercomponent->handleParameterChange(getFullName());
297
    }
298

    
299
    // notify post-change listeners
300
    if (ownercomponent->hasListeners(POST_MODEL_CHANGE)) {
301
        cPostParameterChangeNotification tmp;
302
        tmp.par = this;
303
        ownercomponent->emit(POST_MODEL_CHANGE, &tmp);
304
    }
305

    
306
}
307

    
308
void cPar::read()
309
{
310
    //TRACE("read() of par=%s", getFullPath().c_str());
311

    
312
    // obtain value if parameter is not set yet
313
    if (!p->isSet())
314
        ev.readParameter(this);
315

    
316
    // convert non-volatile expressions to constant
317
    if (p->isExpression() && !p->isVolatile())
318
        convertToConst();
319

    
320
    // convert CONST subexpressions into constants
321
    if (p->isExpression() && p->containsConstSubexpressions())
322
    {
323
        beforeChange();
324
        copyIfShared();
325
        p->evaluateConstSubexpressions(ownercomponent); //XXX sharing?
326
        afterChange();
327
    }
328
}
329

    
330
void cPar::acceptDefault()
331
{
332
    if (p->isSet())
333
        throw cRuntimeError(this, "acceptDefault(): Parameter is already set");
334
    if (!p->containsValue())
335
        throw cRuntimeError(this, "acceptDefault(): Parameter contains no default value");
336

    
337
    beforeChange();
338

    
339
    // basically we only need to set the isSet flag to true, but only
340
    // for ourselves, without affecting the shared parameter prototype.
341

    
342
    // try to look up the value in the value cache (temporarily setting
343
    // isSet=true so that we can use this object as key)
344
    p->setIsSet(true);
345
    cComponentType *componentType = ownercomponent->getComponentType();
346
    cParImpl *cachedValue = componentType->getSharedParImpl(p);
347
    p->setIsSet(false);
348

    
349
    // use the cached value, or create a value and put it into the cache
350
    if (cachedValue)
351
        setImpl(cachedValue);
352
    else {
353
        copyIfShared();
354
        p->setIsSet(true);
355
        componentType->putSharedParImpl(p);
356
    }
357
    afterChange();
358
}
359

    
360
void cPar::convertToConst()
361
{
362
    beforeChange();
363
    copyIfShared();
364
    try {
365
        p->convertToConst(ownercomponent);
366
    }
367
    catch (std::exception& e) {
368
        throw cRuntimeError(ePARAM, getFullName(), e.what());
369
    }
370

    
371
    // maybe replace it with a shared copy
372
    cComponentType *componentType = ownercomponent->getComponentType();
373
    cParImpl *cachedValue = componentType->getSharedParImpl(p);
374
    if (cachedValue)
375
        setImpl(cachedValue);
376
    else
377
        componentType->putSharedParImpl(p);
378
    afterChange();
379
}
380

    
381
void cPar::parse(const char *text)
382
{
383
    // Implementation note: we are trying to share cParImpl objects for
384
    // values coming from the configuration. This is possible because an
385
    // expression's representation does not contain pointers to concrete
386
    // modules or other parameters. The context is always passed in separately
387
    // when the expression gets evaluated.
388
    //    For sharing parameter values, we use a map stored in cComponentType,
389
    // which we index with "parametername:textualvalue" as key. Per-componentType
390
    // storage ensures that parameters of identical name but different types
391
    // don't cause trouble.
392
    //
393
    // Note: text may not contain "ask" or "default"! This is ensured by
394
    // cParImpl::parse() which throws an error on them.
395
    //
396
    beforeChange();
397
    cComponentType *componentType = ownercomponent->getComponentType();
398
    std::string key = std::string(componentType->getName()) + ":" + getName() + ":" + text;
399
    cParImpl *cachedValue = componentType->getSharedParImpl(key.c_str());
400
    if (cachedValue)
401
    {
402
        // an identical value found in the map -- use it
403
        setImpl(cachedValue);
404
    }
405
    else
406
    {
407
        // not found: clone existing parameter (to preserve name, type, unit etc), then parse text into it
408
        cParImpl *tmp = p->dup();
409
        try {
410
            tmp->parse(text);
411
        }
412
        catch (std::exception& e) {
413
            delete tmp;
414
            throw cRuntimeError("Wrong value `%s' for parameter `%s': %s", text, getFullPath().c_str(), e.what());
415
        }
416

    
417
        // successfully parsed: install it
418
        componentType->putSharedParImpl(key.c_str(), tmp);
419
        setImpl(tmp);
420
    }
421
    afterChange();
422
}
423