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