/* PIP - Platform Independent Primitives Variant type Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "pivariant.h" /** \class PIVariant * \brief Variant type * \details * \section PIVariant_sec0 Synopsis * This class provides general type that can contains all standard types, some * PIP types or custom type. In case of standard types this class also provides * convertions between them. * * \section PIVariant_sec1 Usage * %PIVariant useful if you want pass many variables with different types in * single array, e.g.: * \code{cpp} * PIVector array; * array << PIVariant(10) << PIVariant(1.61) << PIVariant(true) << PIVariant("0xFF"); * piCout << array; * piForeachC (PIVariant & i, array) * piCout << i.toInt(); * \endcode * Result: * \code{cpp} * {PIVariant(Int, 10), PIVariant(Double, 1,61), PIVariant(Bool, true), PIVariant(String, 0xFF)} * 10 * 1 * 1 * 255 * \endcode * */ PIVariant::PIVariant() { type_ = PIVariant::Invalid; memset(_vraw, 0, __PIVARIANT_UNION_SIZE__); } PIVariant & PIVariant::operator =(const PIVariant & v) { type_ = v.type_; memcpy(_vraw, v._vraw, __PIVARIANT_UNION_SIZE__); _vbytearray = v._vbytearray; _vbitarray = v._vbitarray; _vstring = v._vstring; _vstringlist = v._vstringlist; _vcustom = v._vcustom; return *this; } bool PIVariant::operator ==(const PIVariant & v) const { if (type_ != v.type_) return false; switch (type_) { case PIVariant::Bool: case PIVariant::Char: case PIVariant::UChar: case PIVariant::Short: case PIVariant::UShort: case PIVariant::Int: case PIVariant::UInt: case PIVariant::Long: case PIVariant::ULong: return _vint == v._vint; case PIVariant::LLong: case PIVariant::ULLong: return _vllong == v._vllong; case PIVariant::Float: return _vfloat == v._vfloat; case PIVariant::Double: return _vdouble == v._vdouble; case PIVariant::LDouble: return _vldouble == v._vldouble; case PIVariant::Complexd: return _vcomplexd == _vvcomplexd(v); case PIVariant::Complexld: return _vcomplexld == _vvcomplexld(v); case PIVariant::BitArray: return _vbitarray == v._vbitarray; case PIVariant::ByteArray: return _vbytearray == v._vbytearray; case PIVariant::String: return _vstring == v._vstring; case PIVariant::StringList: return _vstringlist == v._vstringlist; case PIVariant::Time: return _vtime == _vvtime(v); case PIVariant::Date: return _vdate == _vvdate(v); case PIVariant::DateTime: return _vdatetime == _vvdatetime(v); case PIVariant::SystemTime: return _vsystime == _vvsystime(v); default: break; }; return false; } PIVariant::Type PIVariant::typeFromName(const PIString & tname) { PIString s = tname.trimmed().toLowerCase().replaceAll(" ", ""); if (s == "bool" || s == "boolean") return PIVariant::Bool; if (s == "char" || s == "sbyte") return PIVariant::Char; if (s == "short" || s == "shortint" || s == "signedshort" || s == "signedshortint" || s == "sword") return PIVariant::Short; if (s == "int" || s == "signed" || s == "signedint") return PIVariant::Int; if (s == "long" || s == "longint" || s == "signedlong" || s == "signedlongint" || s == "sdword") return PIVariant::Long; if (s == "llong" || s == "longlong" || s == "longlongint" || s == "signedlonglong" || s == "signedlonglongint" || s == "sqword") return PIVariant::LLong; if (s == "uchar" || s == "byte") return PIVariant::UChar; if (s == "ushort" || s == "unsignedshort" || s == "unsignedshortint" || s == "word") return PIVariant::UShort; if (s == "uint" || s == "unsigned" || s == "unsignedint") return PIVariant::UInt; if (s == "ulong" || s == "unsignedlong" || s == "unsignedlongint" || s == "dword") return PIVariant::ULong; if (s == "ullong" || s == "unsignedlonglong" || s == "unsignedlonglongint" || s == "qword") return PIVariant::ULLong; if (s == "float") return PIVariant::Float; if (s == "double" || s == "real") return PIVariant::Double; if (s == "ldouble" || s == "longdouble") return PIVariant::LDouble; if (s == "complexd" || s == "complex") return PIVariant::Complexd; if (s == "complexld" || s == "complex" || s == "complex") return PIVariant::Complexld; if (s == "pibitarray" || s == "bitarray") return PIVariant::BitArray; if (s == "pibytearray" || s == "bytearray" || s == "vector" || s == "pivector" || s == "vector" || s == "pivector" || s == "vector" || s == "pivector") return PIVariant::ByteArray; if (s == "pistring" || s == "string") return PIVariant::String; if (s == "pistringlist" || s == "vector" || s == "vector" || s == "pivector" || s == "pivector") return PIVariant::StringList; if (s == "pitime" || s == "time") return PIVariant::Time; if (s == "pidate" || s == "date") return PIVariant::Date; if (s == "pidatetime" || s == "datetime") return PIVariant::DateTime; if (s == "pisystemtime" || s == "systemtime") return PIVariant::SystemTime; return PIVariant::Invalid; } PIString PIVariant::typeName(PIVariant::Type type) { switch (type) { case PIVariant::Bool: return "Bool"; case PIVariant::Char: return "Char"; case PIVariant::UChar: return "UChar"; case PIVariant::Short: return "Short"; case PIVariant::UShort: return "UShort"; case PIVariant::Int: return "Int"; case PIVariant::UInt: return "UInt"; case PIVariant::Long: return "Long"; case PIVariant::ULong: return "ULong"; case PIVariant::LLong: return "LLong"; case PIVariant::ULLong: return "ULLong"; case PIVariant::Float: return "Float"; case PIVariant::Double: return "Double"; case PIVariant::LDouble: return "LDouble"; case PIVariant::Complexd: return "Complexd"; case PIVariant::Complexld: return "Complexld"; case PIVariant::BitArray: return "BitArray"; case PIVariant::ByteArray: return "ByteArray"; case PIVariant::String: return "String"; case PIVariant::StringList: return "StringList"; case PIVariant::Time: return "Time"; case PIVariant::Date: return "Date"; case PIVariant::DateTime: return "DateTime"; case PIVariant::SystemTime: return "SystemTime"; case PIVariant::Custom: return "Custom"; default: break; } return "Invalid"; } /** \brief Returns variant content as boolean * \details In case of numeric types returns \b true if value != 0. \n * In case of String type returns \a PIString::toBool(). \n * In case of StringList type returns \b false if string list is empty, * otherwise returns \a PIString::toBool() of first string. \n * In case of other types returns \b false. */ bool PIVariant::toBool() const { switch (type_) { case PIVariant::Bool: case PIVariant::Char: case PIVariant::UChar: case PIVariant::Short: case PIVariant::UShort: case PIVariant::Int: case PIVariant::UInt: case PIVariant::Long: case PIVariant::ULong: return _vint != 0; case PIVariant::LLong: case PIVariant::ULLong: return _vllong != 0; case PIVariant::Float: return _vfloat != 0; case PIVariant::Double: return _vdouble != 0; case PIVariant::LDouble: return _vldouble != 0; case PIVariant::Complexd: return _vcomplexd.real() != 0; case PIVariant::Complexld: return _vcomplexld.real() != 0; case PIVariant::String: return _vstring.toBool(); case PIVariant::StringList: if (_vstringlist.isEmpty()) return false; return _vstringlist.front().toBool(); default: break; } return false; } /** \brief Returns variant content as int * \details In case of numeric types returns integer value. \n * In case of String type returns \a PIString::toInt(). \n * In case of StringList type returns \b 0 if string list is empty, * otherwise returns \a PIString::toInt() of first string. \n * In case of other types returns \b 0. */ int PIVariant::toInt() const { switch (type_) { case PIVariant::Bool: case PIVariant::Char: case PIVariant::UChar: case PIVariant::Short: case PIVariant::UShort: case PIVariant::Int: case PIVariant::UInt: case PIVariant::Long: case PIVariant::ULong: return _vint; case PIVariant::LLong: case PIVariant::ULLong: return _vllong; case PIVariant::Float: return _vfloat; case PIVariant::Double: return _vdouble; case PIVariant::LDouble: return _vldouble; case PIVariant::Complexd: return _vcomplexd.real(); case PIVariant::Complexld: return _vcomplexld.real(); case PIVariant::String: return _vstring.toInt(); case PIVariant::StringList: if (_vstringlist.isEmpty()) return 0; return _vstringlist.front().toInt(); default: break; } return 0; } /** \brief Returns variant content as long long * \details In case of numeric types returns integer value. \n * In case of String type returns \a PIString::toLLong(). \n * In case of StringList type returns \b 0L if string list is empty, * otherwise returns \a PIString::toLLong() of first string. \n * In case of other types returns \b 0L. */ llong PIVariant::toLLong() const { switch (type_) { case PIVariant::Bool: case PIVariant::Char: case PIVariant::UChar: case PIVariant::Short: case PIVariant::UShort: case PIVariant::Int: case PIVariant::UInt: case PIVariant::Long: case PIVariant::ULong: return _vint; case PIVariant::LLong: case PIVariant::ULLong: return _vllong; case PIVariant::Float: return _vfloat; case PIVariant::Double: return _vdouble; case PIVariant::LDouble: return _vldouble; case PIVariant::Complexd: return _vcomplexd.real(); case PIVariant::Complexld: return _vcomplexld.real(); case PIVariant::String: return _vstring.toLLong(); case PIVariant::StringList: if (_vstringlist.isEmpty()) return 0L; return _vstringlist.front().toLLong(); default: break; } return 0L; } /** \brief Returns variant content as float * \details In case of numeric types returns float value. \n * In case of String type returns \a PIString::toFloat(). \n * In case of StringList type returns \b 0.f if string list is empty, * otherwise returns \a PIString::toFloat() of first string. \n * In case of other types returns \b 0.f. */ float PIVariant::toFloat() const { switch (type_) { case PIVariant::Bool: case PIVariant::Char: case PIVariant::UChar: case PIVariant::Short: case PIVariant::UShort: case PIVariant::Int: case PIVariant::UInt: case PIVariant::Long: case PIVariant::ULong: return _vint; case PIVariant::LLong: case PIVariant::ULLong: return _vllong; case PIVariant::Float: return _vfloat; case PIVariant::Double: return _vdouble; case PIVariant::LDouble: return _vldouble; case PIVariant::Complexd: return _vcomplexd.real(); case PIVariant::Complexld: return _vcomplexld.real(); case PIVariant::String: return _vstring.toFloat(); case PIVariant::StringList: if (_vstringlist.isEmpty()) return 0.f; return _vstringlist.front().toFloat(); default: break; } return 0.f; } /** \brief Returns variant content as double * \details In case of numeric types returns double value. \n * In case of String type returns \a PIString::toDouble(). \n * In case of StringList type returns \b 0. if string list is empty, * otherwise returns \a PIString::toDouble() of first string. \n * In case of other types returns \b 0.. */ double PIVariant::toDouble() const { switch (type_) { case PIVariant::Bool: case PIVariant::Char: case PIVariant::UChar: case PIVariant::Short: case PIVariant::UShort: case PIVariant::Int: case PIVariant::UInt: case PIVariant::Long: case PIVariant::ULong: return _vint; case PIVariant::LLong: case PIVariant::ULLong: return _vllong; case PIVariant::Float: return _vfloat; case PIVariant::Double: return _vdouble; case PIVariant::LDouble: return _vldouble; case PIVariant::Complexd: return _vcomplexd.real(); case PIVariant::Complexld: return _vcomplexld.real(); case PIVariant::String: return _vstring.toDouble(); case PIVariant::StringList: if (_vstringlist.isEmpty()) return 0.; return _vstringlist.front().toDouble(); default: break; } return 0.; } /** \brief Returns variant content as long double * \details In case of numeric types returns long double value. \n * In case of String type returns \a PIString::toLDouble(). \n * In case of StringList type returns \b 0. if string list is empty, * otherwise returns \a PIString::toLDouble() of first string. \n * In case of other types returns \b 0.. */ ldouble PIVariant::toLDouble() const { switch (type_) { case PIVariant::Bool: case PIVariant::Char: case PIVariant::UChar: case PIVariant::Short: case PIVariant::UShort: case PIVariant::Int: case PIVariant::UInt: case PIVariant::Long: case PIVariant::ULong: return _vint; case PIVariant::LLong: case PIVariant::ULLong: return _vllong; case PIVariant::Float: return _vfloat; case PIVariant::Double: return _vdouble; case PIVariant::LDouble: return _vldouble; case PIVariant::Complexd: return _vcomplexd.real(); case PIVariant::Complexld: return _vcomplexld.real(); case PIVariant::String: return _vstring.toLDouble(); case PIVariant::StringList: if (_vstringlist.isEmpty()) return 0.; return _vstringlist.front().toLDouble(); default: break; } return 0.; } /** \brief Returns variant content as complex * \details In case of numeric types returns complex value. \n * In case of String type returns \a PIString::toDouble(). \n * In case of StringList type returns \b 0. if string list is empty, * otherwise returns \a PIString::toDouble() of first string. \n * In case of other types returns \b 0.. */ complexd PIVariant::toComplexd() const { switch (type_) { case PIVariant::Bool: case PIVariant::Char: case PIVariant::UChar: case PIVariant::Short: case PIVariant::UShort: case PIVariant::Int: case PIVariant::UInt: case PIVariant::Long: case PIVariant::ULong: return _vint; case PIVariant::LLong: case PIVariant::ULLong: return _vllong; case PIVariant::Float: return _vfloat; case PIVariant::Double: return _vdouble; case PIVariant::LDouble: return _vldouble; case PIVariant::Complexd: return _vcomplexd.real(); case PIVariant::Complexld: return _vcomplexld.real(); case PIVariant::String: return _vstring.toDouble(); case PIVariant::StringList: if (_vstringlist.isEmpty()) return complexd_0; return _vstringlist.front().toDouble(); default: break; } return complexd_0; } /** \brief Returns variant content as long complex * \details In case of numeric types returns long complex value. \n * In case of String type returns \a PIString::toLDouble(). \n * In case of StringList type returns \b 0. if string list is empty, * otherwise returns \a PIString::toLDouble() of first string. \n * In case of other types returns \b 0.. */ complexld PIVariant::toComplexld() const { switch (type_) { case PIVariant::Bool: case PIVariant::Char: case PIVariant::UChar: case PIVariant::Short: case PIVariant::UShort: case PIVariant::Int: case PIVariant::UInt: case PIVariant::Long: case PIVariant::ULong: return _vint; case PIVariant::LLong: case PIVariant::ULLong: return _vllong; case PIVariant::Float: return _vfloat; case PIVariant::Double: return _vdouble; case PIVariant::LDouble: return _vldouble; case PIVariant::Complexd: return _vcomplexd.real(); case PIVariant::Complexld: return _vcomplexld.real(); case PIVariant::String: return _vstring.toLDouble(); case PIVariant::StringList: if (_vstringlist.isEmpty()) return complexld_0; return _vstringlist.front().toLDouble(); default: break; } return complexld_0; } /** \brief Returns variant content as time * \details In case of Time type returns time value. \n * In case of DateTime type returns time part of value. \n * In case of other types returns \a PITime(). */ PITime PIVariant::toTime() const { if (type_ == PIVariant::Time) return _vtime; if (type_ == PIVariant::DateTime) return _vtime; return PITime(); } /** \brief Returns variant content as date * \details In case of Date type returns date value. \n * In case of DateTime type returns date part of value. \n * In case of other types returns \a PIDate(). */ PIDate PIVariant::toDate() const { if (type_ == PIVariant::Date) return _vdate; if (type_ == PIVariant::DateTime) return *((PIDate*)(&(_vdatetime.day))); return PIDate(); } /** \brief Returns variant content as date and time * \details In case of Time type returns time value with null date. \n * In case of Date type returns date value with null time. \n * In case of DateTime type returns date and time. \n * In case of other types returns \a PIDateTime(). */ PIDateTime PIVariant::toDateTime() const { if (type_ == PIVariant::DateTime) return _vdatetime; if (type_ == PIVariant::Time) return PIDateTime(_vtime); if (type_ == PIVariant::Date) return PIDateTime(_vdate); return PIDateTime(); } /** \brief Returns variant content as system time * \details In case of SystemTime type returns system time. \n * In case of other types returns \a PISystemTime::fromSeconds() from * double value of variant content. */ PISystemTime PIVariant::toSystemTime() const { if (type_ == PIVariant::SystemTime) return _vsystime; return PISystemTime::fromSeconds(toDouble()); } /** \brief Returns variant content as string * \details In case of numeric types returns \a PIString::fromNumber(). \n * In case of String type returns string value. \n * In case of StringList type returns joined string ("(" + PIStringList::join("; ") + ")"). \n * In case of BitArray or ByteArray types returns number of bits/bytes. \n * In case of Time, Date or DateTime types returns toString() of this values. \n * In case of SystemTime types returns second and nanoseconds of time * ("(PISystemTime::seconds s, PISystemTime::nanoseconds ns)"). \n * In case of other types returns \b "". */ PIString PIVariant::toString() const { switch (type_) { case PIVariant::Bool: return _vint == 0 ? "false" : "true"; case PIVariant::Char: case PIVariant::UChar: case PIVariant::Short: case PIVariant::UShort: case PIVariant::Int: case PIVariant::UInt: case PIVariant::Long: case PIVariant::ULong: return PIString::fromNumber(_vint); case PIVariant::LLong: case PIVariant::ULLong: return PIString::fromNumber(_vllong); case PIVariant::Float: return PIString::fromNumber(_vfloat); case PIVariant::Double: return PIString::fromNumber(_vdouble); case PIVariant::LDouble: return PIString::fromNumber(_vldouble); case PIVariant::Complexd: return "(" + PIString::fromNumber(_vcomplexd.real()) + "; " + PIString::fromNumber(_vcomplexd.imag()) + ")"; case PIVariant::Complexld: return "(" + PIString::fromNumber(_vcomplexld.real()) + "; " + PIString::fromNumber(_vcomplexld.imag()) + ")"; case PIVariant::BitArray: return PIString::fromNumber(_vbitarray.bitSize()) + " bits"; case PIVariant::ByteArray: return _vbytearray.toString(); case PIVariant::String: return _vstring; case PIVariant::StringList: return "(" + _vstringlist.join("; ") + ")"; case PIVariant::Time: return _vtime.toString(); case PIVariant::Date: return _vdate.toString(); case PIVariant::DateTime: return _vdatetime.toString(); case PIVariant::SystemTime: return "(" + PIString::fromNumber(_vsystime.seconds) + " s, " + PIString::fromNumber(_vsystime.nanoseconds) + " ns)"; default: break; } return ""; } /** \brief Returns variant content as strings list * \details In case of StringList type returns strings list value. \n * In case of other types returns \a PIStringList with one string value of variant content. */ PIStringList PIVariant::toStringList() const { if (type_ == PIVariant::StringList) return _vstringlist; return PIStringList(toString()); } /** \brief Returns variant content as bit array * \details In case of BitArray type returns bit array value. \n * In case of other types returns \a PIBitArray from \a toLLong() value. */ PIBitArray PIVariant::toBitArray() const { if (type_ == PIVariant::BitArray) return _vbitarray; return PIBitArray(ullong(toLLong())); } /** \brief Returns variant content as byte array * \details In case of ByteArray type returns byte array value. \n * In case of other types returns empty \a PIByteArray. */ PIByteArray PIVariant::toByteArray() const { if (type_ == PIVariant::ByteArray) return _vbytearray; return PIByteArray(); }