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