File indexing completed on 2025-01-12 06:47:31
0001 // 0002 // C++ Implementation: cValue, cValueList 0003 // 0004 /* 0005 Copyright 2005-2011 Tomas Mecir <kmuddy@kmuddy.com> 0006 0007 This program is free software; you can redistribute it and/or 0008 modify it under the terms of the GNU General Public License as 0009 published by the Free Software Foundation; either version 2 of 0010 the License, or (at your option) any later version. 0011 0012 This program is distributed in the hope that it will be useful, 0013 but WITHOUT ANY WARRANTY; without even the implied warranty of 0014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0015 GNU General Public License for more details. 0016 0017 You should have received a copy of the GNU General Public License 0018 along with this program. If not, see <http://www.gnu.org/licenses/>. 0019 */ 0020 0021 #include "cvalue.h" 0022 0023 #include <QStringList> 0024 #include <QXmlStreamReader> 0025 #include <QXmlStreamWriter> 0026 0027 #include <map> 0028 #include <set> 0029 0030 using namespace std; 0031 0032 class cValueData { 0033 private: 0034 cValueData (); 0035 ~cValueData (); 0036 /** copy the value */ 0037 void copyTo (cValueData *data); 0038 /** clear data */ 0039 void clear (); 0040 0041 enum ValueType { ValueNone, ValueString, ValueInt, ValueDouble, ValueArray, ValueList, ValueMarker }; 0042 0043 /** return type of currently held value */ 0044 ValueType valueType () const { return valType; }; 0045 bool isEmpty() const { return (valType==ValueNone); }; 0046 bool isString() const { return (valType==ValueString); }; 0047 bool isInteger() const { return (valType==ValueInt); }; 0048 bool isDouble() const { return (valType==ValueDouble); }; 0049 bool isArray() const { return (valType==ValueArray); }; 0050 bool isList() const { return (valType==ValueList); }; 0051 bool isMarker() const { return (valType==ValueMarker); }; 0052 0053 QString asString () const; 0054 int asInteger () const; 0055 double asDouble () const; 0056 0057 QString listJoin (const QString &sep) const; 0058 0059 int usage; 0060 ValueType valType; 0061 union { 0062 int int_val; 0063 double dbl_val; 0064 }; 0065 // these cannot be in the union: 0066 map<int, QString> array_val; 0067 set<QString> list_val; 0068 QString str_val; 0069 0070 /** no implementation here - we don't want to create copies */ 0071 cValueData (const cValueData &val); 0072 /** no implementation here - we don't want to create copies */ 0073 cValueData &operator= (const cValueData &val); 0074 0075 friend class cValue; 0076 }; 0077 0078 cValueData::cValueData () 0079 { 0080 usage = 1; 0081 valType = ValueNone; 0082 } 0083 0084 cValueData::~cValueData () 0085 { 0086 clear (); 0087 } 0088 0089 void cValueData::clear () 0090 { 0091 valType = ValueNone; 0092 str_val = QString(); 0093 list_val.clear (); 0094 array_val.clear (); 0095 } 0096 0097 0098 void cValueData::copyTo (cValueData *data) 0099 { 0100 if (data == this) return; 0101 0102 data->clear (); 0103 data->valType = valType; 0104 switch (valType) { 0105 case ValueNone: 0106 case ValueMarker: 0107 break; 0108 case ValueString: 0109 data->str_val = str_val; 0110 break; 0111 case ValueInt: 0112 data->int_val = int_val; 0113 break; 0114 case ValueDouble: 0115 data->dbl_val = dbl_val; 0116 break; 0117 case ValueArray: 0118 data->array_val = array_val; 0119 break; 0120 case ValueList: 0121 data->list_val = list_val; 0122 break; 0123 }; 0124 } 0125 0126 QString cValueData::asString () const 0127 { 0128 QString ret = QString(); 0129 map<int, QString>::const_iterator ita; 0130 set<QString>::const_iterator itl; 0131 switch (valType) { 0132 case ValueNone: 0133 case ValueMarker: 0134 ret = QString(); 0135 break; 0136 case ValueString: 0137 ret = str_val; 0138 break; 0139 case ValueInt: 0140 ret.setNum (int_val); 0141 break; 0142 case ValueDouble: 0143 ret.setNum (dbl_val); 0144 break; 0145 case ValueArray: 0146 case ValueList: 0147 ret = listJoin ("|"); 0148 break; 0149 } 0150 return ret; 0151 } 0152 0153 int cValueData::asInteger () const 0154 { 0155 bool ok = false; 0156 int ret = 0; 0157 switch (valType) { 0158 case ValueNone: 0159 case ValueMarker: 0160 ret = 0; 0161 break; 0162 case ValueString: 0163 ret = str_val.toInt (&ok); 0164 if (!ok) ret = 0; 0165 break; 0166 case ValueInt: 0167 ret = int_val; 0168 break; 0169 case ValueDouble: 0170 ret = (int) dbl_val; //should auto-trim digits after decimal separator 0171 break; 0172 case ValueArray: 0173 ret = array_val.size(); 0174 break; 0175 case ValueList: 0176 ret = list_val.size(); 0177 break; 0178 } 0179 return ret; 0180 } 0181 0182 double cValueData::asDouble () const 0183 { 0184 double ret = 0.0; 0185 bool ok; 0186 switch (valType) { 0187 case ValueNone: 0188 case ValueMarker: 0189 ret = 0.0; 0190 break; 0191 case ValueString: 0192 ret = str_val.toDouble (&ok); 0193 if (!ok) ret = 0.0; 0194 break; 0195 case ValueInt: 0196 ret = (double) int_val; 0197 break; 0198 case ValueDouble: 0199 ret = dbl_val; 0200 break; 0201 case ValueArray: 0202 ret = array_val.size(); 0203 break; 0204 case ValueList: 0205 ret = list_val.size(); 0206 break; 0207 } 0208 return ret; 0209 } 0210 0211 QString cValueData::listJoin (const QString &sep) const 0212 { 0213 QString ret; 0214 map<int, QString>::const_iterator ita; 0215 set<QString>::const_iterator itl; 0216 if (valType == ValueArray) { 0217 ita = array_val.begin(); 0218 if (ita == array_val.end()) // empty array ? 0219 return ret;; 0220 ret = ita->second; 0221 ++ita; 0222 for (; ita != array_val.end(); ++ita) ret += sep + ita->second; 0223 } 0224 if (valType == ValueList) { 0225 itl = list_val.begin(); 0226 if (itl == list_val.end()) // empty list ? 0227 return ret; 0228 ret = (*itl); 0229 ++itl; 0230 for (; itl != list_val.end(); ++itl) ret += sep + (*itl); 0231 } 0232 return ret; 0233 } 0234 0235 0236 // ********************************* 0237 // cValue implementation starts here 0238 // ********************************* 0239 0240 cValue cValue::_empty; 0241 0242 cValue::cValue () 0243 { 0244 d = nullptr; 0245 } 0246 0247 cValue::cValue (const cValue &val) 0248 { 0249 d = val.d; 0250 if (d) d->usage++; 0251 } 0252 0253 cValue::cValue (const QString &val) 0254 { 0255 d = nullptr; 0256 setValue (val); 0257 } 0258 0259 cValue::cValue (int val) 0260 { 0261 d = nullptr; 0262 setValue (val); 0263 } 0264 0265 cValue::cValue (double val) 0266 { 0267 d = nullptr; 0268 setValue (val); 0269 } 0270 0271 cValue::cValue (bool val) 0272 { 0273 d = nullptr; 0274 setValue (val ? 1 : 0); 0275 } 0276 0277 cValue::~cValue () 0278 { 0279 // detach from value, deleting it if needed 0280 detachValue (); 0281 } 0282 0283 QString cValue::load (QXmlStreamReader *reader) 0284 { 0285 reader->readNext (); 0286 if (!reader->isStartElement ()) return QString(); // something is wrong 0287 if (reader->name() != "variable") return QString(); // likewise 0288 0289 int type = reader->attributes().value ("type").toString().toInt(); 0290 if (type < 0) type = 0; 0291 if (type > 4) type = 0; 0292 QString name = reader->attributes().value ("name").toString(); 0293 QString value = reader->attributes().value ("value").toString(); 0294 switch (type) { 0295 case 0: // string 0296 setValue (value); 0297 break; 0298 case 1: // integer 0299 setValue (value.toInt()); 0300 break; 0301 case 2: // double 0302 setValue (value.toDouble()); 0303 break; 0304 case 3: // array 0305 while (!reader->atEnd()) { 0306 reader->readNext (); 0307 // are we at the end of this section ? 0308 if (reader->isEndElement() && (reader->name() == "value")) break; 0309 0310 if (!reader->isStartElement()) continue; 0311 if (reader->name() != "element") continue; 0312 int index = reader->attributes().value ("index").toString().toInt(); 0313 QString v = reader->attributes().value ("value").toString(); 0314 setItem (index, v); 0315 reader->readNext(); // read the end element 0316 } 0317 break; 0318 case 4: // list 0319 while (!reader->atEnd()) { 0320 reader->readNext (); 0321 // are we at the end of this section ? 0322 if (reader->isEndElement() && (reader->name() == "value")) break; 0323 0324 if (!reader->isStartElement()) continue; 0325 if (reader->name() != "element") continue; 0326 0327 QString v = reader->attributes().value ("value").toString(); 0328 addToList (v); 0329 reader->readNext(); // read the end element 0330 } 0331 break; 0332 } 0333 if (type <= 2) reader->readNext(); // for types other than list/array, we must read the closing element 0334 0335 return name; 0336 } 0337 0338 void cValue::save (QXmlStreamWriter *writer, const QString &name) 0339 { 0340 writer->writeStartElement ("variable"); 0341 if (!name.isEmpty()) writer->writeAttribute ("name", name); 0342 0343 int type = 0; 0344 if (d) switch (d->valType) { 0345 case cValueData::ValueNone: type = 0; break; 0346 // markers are only used in function evaluation, no need to save them 0347 case cValueData::ValueMarker: type = 0; break; 0348 case cValueData::ValueString: type = 0; break; 0349 case cValueData::ValueInt: type = 1; break; 0350 case cValueData::ValueDouble: type = 2; break; 0351 case cValueData::ValueArray: type = 3; break; 0352 case cValueData::ValueList: type = 4; break; 0353 default: type = 0; break; // should never happen 0354 }; 0355 writer->writeAttribute ("type", QString::number (type)); 0356 map<int, QString>::iterator it1; 0357 set<QString>::iterator it2; 0358 switch (type) { 0359 case 0: { // string 0360 writer->writeAttribute ("value", asString()); 0361 } break; 0362 case 1: { // integer 0363 writer->writeAttribute ("value", QString::number (asInteger())); 0364 } break; 0365 case 2: { // double 0366 writer->writeAttribute ("value", QString::number (asDouble(), 'g', 15)); 0367 } break; 0368 case 3: { // array 0369 for (it1 = d->array_val.begin(); it1 != d->array_val.end(); ++it1) { 0370 writer->writeStartElement ("element"); 0371 writer->writeAttribute ("index", QString::number (it1->first)); 0372 writer->writeAttribute ("value", it1->second); 0373 writer->writeEndElement (); 0374 } 0375 } break; 0376 case 4: { // list 0377 for (it2 = d->list_val.begin(); it2 != d->list_val.end(); ++it2) { 0378 writer->writeStartElement ("element"); 0379 writer->writeAttribute ("value", *it2); 0380 writer->writeEndElement (); 0381 } 0382 } break; 0383 } 0384 writer->writeEndElement (); 0385 } 0386 0387 cValue &cValue::operator= (const cValue &a) 0388 { 0389 // handle the a=a; type of assignments correctly 0390 if (a.d == d) return *this; 0391 0392 detachValue (); 0393 d = a.d; 0394 if (d) d->usage++; 0395 return *this; 0396 } 0397 0398 void cValue::setValue (const cValue &val) 0399 { 0400 operator= (val); 0401 } 0402 0403 void cValue::setValue () 0404 { 0405 detachValue (); 0406 d = nullptr; 0407 } 0408 0409 void cValue::setValue (const QString &val) 0410 { 0411 // first of all, try to convert the string to a number ... 0412 bool ok = false; 0413 double value = val.toDouble (&ok); 0414 if (ok) { 0415 // success - set the value as a number 0416 setValue (value); 0417 return; 0418 } 0419 detachValue (); 0420 d = new cValueData; 0421 d->valType = cValueData::ValueString; 0422 d->str_val = val; 0423 } 0424 0425 void cValue::setValue (int val) 0426 { 0427 detachValue (); 0428 d = new cValueData; 0429 d->valType = cValueData::ValueInt; 0430 d->int_val = val; 0431 } 0432 0433 void cValue::setValue (double val) 0434 { 0435 detachValue (); 0436 d = new cValueData; 0437 d->valType = cValueData::ValueDouble; 0438 d->dbl_val = val; 0439 } 0440 0441 void cValue::setAsMarker () 0442 { 0443 detachValue (); 0444 d = new cValueData; 0445 d->valType = cValueData::ValueMarker; 0446 } 0447 0448 bool cValue::isEmpty() const 0449 { 0450 if (d) return d->isEmpty(); 0451 return true; 0452 } 0453 0454 bool cValue::isString() const 0455 { 0456 if (d) return d->isString(); 0457 return false; 0458 } 0459 0460 bool cValue::isInteger() const 0461 { 0462 if (d) return d->isInteger(); 0463 return false; 0464 } 0465 0466 bool cValue::isDouble() const 0467 { 0468 if (d) return d->isDouble(); 0469 return false; 0470 } 0471 0472 bool cValue::isArray() const 0473 { 0474 if (d) return d->isArray(); 0475 return false; 0476 } 0477 0478 bool cValue::isList() const 0479 { 0480 if (d) return d->isList(); 0481 return false; 0482 } 0483 0484 bool cValue::isMarker() const 0485 { 0486 if (d) return d->isMarker(); 0487 return false; 0488 } 0489 0490 cValue cValue::operator[] (int index) const 0491 { 0492 return item (index); 0493 } 0494 0495 void cValue::setItem (int index, const QString &value) 0496 { 0497 if (!isArray()) { 0498 detachValue (); // not an array - get rid of the old value 0499 d = new cValueData; 0500 d->valType = cValueData::ValueArray; 0501 } else 0502 removeItem (index); 0503 d->array_val[index] = value; 0504 } 0505 0506 void cValue::removeItem (int index) 0507 { 0508 if (!isArray()) return; 0509 if (d->array_val.count (index) != 0) 0510 d->array_val.erase (index); 0511 } 0512 0513 void cValue::addToList (const QString &item) 0514 { 0515 if (!isList()) { 0516 detachValue (); // not a list - get rid of the old value 0517 d = new cValueData; 0518 d->valType = cValueData::ValueList; 0519 } 0520 d->list_val.insert (item); 0521 } 0522 0523 void cValue::removeFromList (const QString &item) 0524 { 0525 if (!isList()) return; 0526 d->list_val.erase (item); 0527 } 0528 0529 bool cValue::listContains (const QString &item) 0530 { 0531 if (!isList()) return false; 0532 return (d->list_val.count(item) != 0); 0533 } 0534 0535 0536 QString cValue::asString () const 0537 { 0538 if (d) return d->asString (); 0539 return QString(); 0540 } 0541 0542 int cValue::asInteger () const 0543 { 0544 if (d) return d->asInteger (); 0545 return 0; 0546 } 0547 0548 double cValue::asDouble () const 0549 { 0550 if (d) return d->asDouble (); 0551 return 0.0; 0552 } 0553 0554 QString cValue::item (int index) const 0555 { 0556 if (!isArray()) return QString(); 0557 if (d->array_val.count (index) != 0) 0558 return d->array_val[index]; 0559 return QString(); 0560 } 0561 0562 bool cValue::contains (const QString &item) const 0563 { 0564 if (!isList()) return false; 0565 return (d->list_val.count (item) != 0); 0566 } 0567 0568 int cValue::size () const 0569 { 0570 if (isArray ()) 0571 return d->array_val.size(); 0572 if (isList ()) 0573 return d->list_val.size(); 0574 if (isEmpty ()) 0575 return 0; 0576 return 1; 0577 } 0578 0579 QString cValue::listJoin (const QString &sep) const 0580 { 0581 if ((!isList()) && (!isArray())) return QString(); 0582 return d->listJoin (sep); 0583 } 0584 0585 cValue cValue::toList (const QString &sep) const 0586 { 0587 QStringList list = asString().split (sep); 0588 QStringList::iterator it; 0589 cValue val; 0590 for (it = list.begin(); it != list.end(); ++it) 0591 val.addToList (*it); 0592 return val; 0593 } 0594 0595 void cValue::detachValue () 0596 { 0597 if (!d) return; 0598 if (d->usage > 0) d->usage--; 0599 if (d->usage == 0) delete d; 0600 d = nullptr; 0601 } 0602 0603 void cValue::unique () 0604 { 0605 if (!d) return; 0606 if (d->usage <= 1) return; 0607 cValueData *vd = new cValueData; 0608 d->copyTo (vd); 0609 detachValue (); 0610 d = vd; 0611 } 0612 0613 cValue operator+ (const cValue &a, const cValue &b) 0614 { 0615 if (a.isInteger() && b.isInteger()) 0616 return cValue (a.asInteger() + b.asInteger()); 0617 return cValue (a.asDouble() + b.asDouble()); 0618 } 0619 0620 cValue operator- (const cValue &a, const cValue &b) 0621 { 0622 if (a.isInteger() && b.isInteger()) 0623 return cValue (a.asInteger() - b.asInteger()); 0624 return cValue (a.asDouble() - b.asDouble()); 0625 } 0626 0627 cValue operator* (const cValue &a, const cValue &b) 0628 { 0629 return cValue (a.asDouble() * b.asDouble()); 0630 } 0631 0632 cValue operator/ (const cValue &a, const cValue &b) 0633 { 0634 double bb = b.asDouble (); 0635 if (bb != 0) 0636 return cValue (a.asDouble() / bb); 0637 return cValue (0); 0638 } 0639