Statistics
| Branch: | Revision:

root / src / envir / valueiterator.cc @ fbe00e73

History | View | Annotate | Download (5.45 KB)

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

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

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

    
18
#include <math.h>
19
#include <locale.h>
20
#include "opp_ctype.h"
21
#include "valueiterator.h"
22
#include "stringutil.h"
23
#include "commonutil.h"
24
#include "stringtokenizer.h"
25
#include "cexception.h"
26

    
27
USING_NAMESPACE
28

    
29

    
30
//FIXME use new StringTokenizer from experimental/inifile, otherwise string literals with commas inside won't work!
31

    
32
ValueIterator::ValueIterator(const char *s)
33
{
34
    pos = itemIndex = k = 0;
35
    if (s)
36
        parse(s);
37
}
38

    
39
ValueIterator::~ValueIterator()
40
{
41
}
42

    
43
void ValueIterator::parse(const char *s)
44
{
45
    items.clear();
46
    StringTokenizer tokenizer(s, ","); //XXX turn on respecting quotes
47
    while (tokenizer.hasMoreTokens())
48
    {
49
        Item item;
50
        item.text = opp_trim(tokenizer.nextToken());
51
        parseAsNumericRegion(item);
52
        // note 1.000001 below: without it, "1..9 step 0.1" would only go up to 8.9,
53
        // because floor(8/0.1) = floor(79.9999999999) = 79 not 80!
54
        item.n = item.isNumeric ? std::max(0, (int)floor((item.to - item.from + 1.000001 * item.step) / item.step)) : 1;
55
        items.push_back(item);
56
    }
57
    restart();
58
}
59

    
60
static const char *PARSEERROR = "Error in numeric range syntax `%s', <number>..<number> or <number>..<number> step <number> expected";
61

    
62
void ValueIterator::parseAsNumericRegion(Item& item)
63
{
64
    setlocale(LC_NUMERIC, "C");
65

    
66
    item.isNumeric = false;
67
    item.from = item.to = item.step = 0;
68

    
69
    const char *s = item.text.c_str();
70
    char *endp;
71

    
72
    double from = strtod(s, &endp);
73
    if (endp==s)
74
        return; // no number here
75
    if (*(endp-1)=='.') endp--; // strtod() ate one of our dots!
76
    s = endp;
77
    while (opp_isspace(*s)) s++;
78
    if (*s!='.' || *(s+1)!='.')
79
        return; // missing ".."
80
    s+= 2;
81
    while (opp_isspace(*s)) s++;
82
    double to = strtod(s, &endp);
83
    if (endp==s)
84
        throw cRuntimeError(PARSEERROR, item.text.c_str()); // missing number after ".."
85
    s = endp;
86
    while (opp_isspace(*s)) s++;
87
    if (!*s) {
88
        item.isNumeric = true;
89
        item.from = from;
90
        item.to = to;
91
        item.step = 1;
92
        return; // OK
93
    }
94
    if (s[0]!='s' || s[1]!='t' || s[2]!='e' || s[3]!='p')
95
        throw cRuntimeError(PARSEERROR, item.text.c_str()); // "step" is supposed to follow, we encountered some garbage instead
96
    s+= 4;
97
    while (opp_isspace(*s)) s++;
98
    double step = strtod(s, &endp);
99
    if (endp==s || step==0)
100
        throw cRuntimeError(PARSEERROR, item.text.c_str()); // no number (or explicit 0) after "step"
101
    s = endp;
102
    while (opp_isspace(*s)) s++;
103
    if (*s)
104
        throw cRuntimeError(PARSEERROR, item.text.c_str()); // trailing garbage after "step <number>"
105

    
106
    // OK
107
    item.isNumeric = true;
108
    item.from = from;
109
    item.to = to;
110
    item.step = step;
111
}
112

    
113
int ValueIterator::length() const
114
{
115
    int n = 0;
116
    for (int i=0; i<(int)items.size(); i++)
117
        n += items[i].n;
118
    return n;
119
}
120

    
121
std::string ValueIterator::get(int index) const
122
{
123
    if (index<0 || index>=length())
124
        throw cRuntimeError("ValueIterator: index %d out of bounds", index);
125

    
126
    int k = 0;
127
    for (int i=0; i<(int)items.size(); i++)
128
    {
129
        const Item& item = items[i];
130
        if (!item.isNumeric)
131
        {
132
            if (k==index)
133
                return item.text;
134
            k++;
135
        }
136
        else if (item.n > 0)
137
        {
138
            if (k <= index && index < k+item.n) {
139
                char buf[32];
140
                sprintf(buf, "%g", item.from + item.step*(index-k));
141
                return buf;
142
            }
143
            k += item.n;
144
        }
145
    }
146
    Assert(false);
147
}
148

    
149
void ValueIterator::restart()
150
{
151
    pos = itemIndex = k = 0;
152
    while (itemIndex < (int)items.size() && items[itemIndex].n == 0)
153
        itemIndex++;
154
}
155

    
156
void ValueIterator::operator++(int)
157
{
158
    if (itemIndex >= (int)items.size())
159
        return;
160
    pos++;
161
    const Item& item = items[itemIndex];
162
    if (k < item.n-1) {
163
        k++;
164
    }
165
    else {
166
        k = 0;
167
        while (++itemIndex < (int)items.size() && items[itemIndex].n == 0);
168
    }
169
}
170

    
171
std::string ValueIterator::get() const
172
{
173
    if (itemIndex >= (int)items.size())
174
        return "";
175
    const Item& item = items[itemIndex];
176
    if (!item.isNumeric) {
177
        return item.text;
178
    }
179
    else {
180
        char buf[32];
181
        sprintf(buf, "%g", item.from + item.step*k);
182
        return buf;
183
    }
184
}
185

    
186
bool ValueIterator::end() const
187
{
188
    return itemIndex >= (int)items.size();
189
}
190

    
191
void ValueIterator::dump() const
192
{
193
    printf("parsed form: ");
194
    for (int i=0; i<(int)items.size(); i++)
195
    {
196
        const Item& item = items[i];
197
        if (i>0) printf(", ");
198
        if (!item.isNumeric)
199
            printf("\"%s\"", item.text.c_str());
200
        else
201
            printf("range(%g..%g step %g)", item.from, item.to, item.step);
202
    }
203
    printf("; enumeration: ");
204
    int n = length();
205
    for (int i=0; i<n; i++)
206
    {
207
        if (i>0) printf(", ");
208
        printf("%s", get(i).c_str());
209
    }
210
    printf(".\n");
211
}
212