1
2 /* Web Polygraph http://www.web-polygraph.org/
3 * Copyright 2003-2011 The Measurement Factory
4 * Licensed under the Apache License, Version 2.0 */
5
6 #include "base/polygraph.h"
7
8 #include "xstd/h/sstream.h"
9
10 #include "xstd/gadgets.h"
11 #include "base/StringRangeBlocks.h"
12 #include "base/StringRange.h"
13
14
15 StringArrayBlock::TypeAnchor StringRange::TheTypeAnchor;
16
17
StringRange()18 StringRange::StringRange(): StringArrayBlock(&TheTypeAnchor), theCurrentBase(10) {
19 }
20
StringRange(const StringRange & r)21 StringRange::StringRange(const StringRange &r): StringArrayBlock(&TheTypeAnchor), theCurrentBase(r.theCurrentBase) {
22 append(r);
23 }
24
~StringRange()25 StringRange::~StringRange() {
26 reset();
27 }
28
clone() const29 StringArrayBlock *StringRange::clone() const {
30 return new StringRange(*this);
31 }
32
reset()33 void StringRange::reset() {
34 while(theBlocks.count()) delete theBlocks.pop();
35 // the current base is currenlty not reset
36 }
37
operator =(const StringRange & r)38 StringRange &StringRange::operator =(const StringRange &r) {
39 reset();
40 append(r);
41 return *this;
42 }
43
currentBase(int aBase)44 void StringRange::currentBase(int aBase) {
45 Should(aBase == 10 || aBase == 16);
46 theCurrentBase = aBase;
47 }
48
currentBase() const49 int StringRange::currentBase() const {
50 Should(theCurrentBase == 10 || theCurrentBase == 16);
51 return theCurrentBase;
52 }
53
append(const StringRange & r)54 void StringRange::append(const StringRange &r) {
55 if (theBlocks.count())
56 Should(theCurrentBase == r.theCurrentBase);
57 else
58 theCurrentBase = r.theCurrentBase;
59 theBlocks.stretch(theBlocks.count() + r.theBlocks.count());
60 for (int i = 0; i < r.theBlocks.count(); ++i)
61 theBlocks.append(r.theBlocks[i]->clone());
62 }
63
count() const64 int StringRange::count() const {
65 int cnt = theBlocks.count() ? 1 : 0;
66 for (int i = 0; i < theBlocks.count(); ++i)
67 cnt *= theBlocks[i]->count();
68 return cnt;
69 }
70
find(const Area & member,int & idx) const71 bool StringRange::find(const Area &member, int &idx) const {
72 int pos = 0;
73 int cnt = 1;
74 int tailPos = member.size();
75 for (int i = theBlocks.count()-1; i >= 0; --i) {
76 int blockPos = -1;
77 if (!theBlocks[i]->findTail(member.head(tailPos), tailPos, blockPos))
78 return false;
79 pos += blockPos*cnt;
80 cnt *= theBlocks[i]->count();
81 }
82 idx = pos;
83 return true;
84 }
85
iterPos() const86 int StringRange::iterPos() const {
87 int pos = 0;
88 int cnt = 1;
89 for (int i = theBlocks.count()-1; i >= 0; --i) {
90 pos += theBlocks[i]->pos()*cnt;
91 cnt *= theBlocks[i]->count();
92 }
93 return pos;
94 }
95
iterate(Iter iter) const96 void StringRange::iterate(Iter iter) const {
97 startIter();
98 do {
99 String str;
100 currentIter(str);
101 iter(str);
102 } while (nextIter());
103 }
104
toStr() const105 String StringRange::toStr() const {
106 ostringstream buf;
107 print(buf);
108 return Stream2String(buf);
109 }
110
toStrs(Array<String * > & strs) const111 void StringRange::toStrs(Array<String*> &strs) const {
112 startIter();
113 do {
114 String str;
115 currentIter(str);
116 strs.append(new String(str));
117 } while (nextIter());
118 }
119
strAt(int idx,String & str) const120 void StringRange::strAt(int idx, String &str) const {
121 startIter();
122 skipIter(idx);
123 currentIter(str);
124 }
125
item(int idx) const126 String StringRange::item(int idx) const {
127 String s;
128 strAt(idx, s);
129 return s;
130 }
131
startIter() const132 void StringRange::startIter() const {
133 for (int i = 0; i < theBlocks.count(); ++i)
134 theBlocks[i]->start();
135 }
136
skipIter(int count) const137 void StringRange::skipIter(int count) const {
138 count -= iterPos();
139 Assert(count >= 0);
140 int right = 1;
141 int check = 0;
142 for (int i = theBlocks.count()-1; count > check && i >= 0; --i) {
143 StringRangeBlock &b = *theBlocks[i];
144 const int pos = (count/right) % b.count();
145 b.pos(pos);
146 check += pos*right;
147 right *= b.count();
148 }
149 Assert(count == check);
150 }
151
nextIter() const152 bool StringRange::nextIter() const {
153 return nextIter(theBlocks.count()-1);
154 }
155
nextIter(int level) const156 bool StringRange::nextIter(int level) const {
157 if (level < 0)
158 return false;
159
160 StringRangeBlock &b = *theBlocks[level];
161 // delegate to next level if overflow
162 if (b.atLast()) {
163 b.start();
164 return nextIter(level-1);
165 }
166
167 b.next();
168 return true;
169 }
170
currentIter(String & str) const171 void StringRange::currentIter(String &str) const {
172 ostringstream buf;
173 for (int i = 0; i < theBlocks.count(); ++i) {
174 theBlocks[i]->printCur(buf);
175 }
176 str = Stream2String(buf);
177 }
178
addRangePoint(const String & point)179 void StringRange::addRangePoint(const String &point) {
180 theBlocks.append(new StringRangePoint(point));
181 }
182
addRangeInterval(int start,int stop,bool isolated)183 void StringRange::addRangeInterval(int start, int stop, bool isolated) {
184 theBlocks.append(new StringRangeInterval(start, stop, isolated, theCurrentBase));
185 }
186
canMergeSameType(const StringArrayBlock & b) const187 bool StringRange::canMergeSameType(const StringArrayBlock &b) const {
188 const StringRange &r = (const StringRange &)b;
189
190 if (!theBlocks.count()) // brand new object
191 return true;
192
193 if (theBlocks.count() != r.theBlocks.count())
194 return false;
195
196 int diffCount = 0;
197 for (int i = 0; diffCount <= 1 && i < theBlocks.count(); ++i) {
198 const StringRangeBlock &b1 = *theBlocks[i];
199 const StringRangeBlock &b2 = *r.theBlocks[i];
200 diffCount += b1.diffCount(b2);
201 }
202 // can merge ranges that differ by one block only because
203 // the range notation cannot express other resulting sets
204 return diffCount == 1;
205 }
206
mergeSameType(const StringArrayBlock & b)207 void StringRange::mergeSameType(const StringArrayBlock &b) {
208 const StringRange &r = (const StringRange &)b;
209 if (theBlocks.count()) {
210 Assert(theBlocks.count() == r.theBlocks.count());
211 for (int i = 0; i < theBlocks.count(); ++i)
212 theBlocks[i]->merge(*r.theBlocks[i]);
213 } else {
214 // brand new object
215 append(r);
216 }
217
218 }
219
intervalCount() const220 int StringRange::intervalCount() const {
221 int count = 0;
222 for (int i = 0; i < theBlocks.count(); ++i) {
223 if (theBlocks[i]->count() > 1)
224 count++;
225 }
226 return count;
227 }
228
print(ostream & os) const229 ostream &StringRange::print(ostream &os) const {
230 for (int i = 0; i < theBlocks.count(); ++i)
231 theBlocks[i]->print(os);
232 return os;
233 }
234
235