version 1.22.0

source tree changed
detached PIConsole and PIScreen* in "pip_console" library
This commit is contained in:
2020-06-28 00:18:24 +03:00
parent 5de62b1c83
commit 42925122cb
231 changed files with 22981 additions and 22948 deletions

557
lib/main/core/pibase.h Normal file
View File

@@ -0,0 +1,557 @@
/*! \file pibase.h
* \brief Base types and functions
*
* This file implements first layer above the system and
* declares some basic useful functions
*/
/*
PIP - Platform Independent Primitives
Base types and functions
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PIBASE_H
#define PIBASE_H
#include "piversion.h"
#include "piplatform.h"
#include "pip_export.h"
#include "pip_defs.h"
#include "string.h"
//! Meta-information section for any entity.
//! Parsing by \a pip_cmg and can be accessed by \a PICodeInfo.
//! Contains sequence of key=value pairs, e.g.
//! PIMETA(id=12345,tag="my string")
#define PIMETA(...)
#ifdef DOXYGEN
//! Major value of PIP version
# define PIP_VERSION_MAJOR
//! Minor value of PIP version
# define PIP_VERSION_MINOR
//! Revision value of PIP version
# define PIP_VERSION_REVISION
//! Suffix of PIP version
# define PIP_VERSION_SUFFIX
//! Version of PIP in hex - 0x##(Major)##(Minor)##(Revision)
# define PIP_VERSION
//! Macro is defined when compile-time debug is enabled
# define PIP_DEBUG
//! Macro is defined when host is any Windows
# define WINDOWS
//! Macro is defined when host is QNX or Blackberry
# define QNX
//! Macro is defined when host is Blackberry
# define BLACKBERRY
//! Macro is defined when host is FreeBSD
# define FREE_BSD
//! Macro is defined when host is Mac OS
# define MAC_OS
//! Macro is defined when host is Android
# define ANDROID
//! Macro is defined when host is any Linux
# define LINUX
//! Macro is defined when compiler is GCC or MinGW
# define CC_GCC
//! Macro is defined when PIP is decided that host is support language
# define HAS_LOCALE
//! Macro is defined when compiler is Visual Studio
# define CC_VC
//! Macro is defined when compiler is unknown
# define CC_OTHER
//! Macro is defined when PIP can use "rt" library for "PITimer::ThreadRT" timers implementation
# define PIP_TIMER_RT
#endif
#ifdef PIP_CXX11_SUPPORT
# include <functional>
#endif
#include <cstddef>
#ifdef WINDOWS
# ifdef CC_VC
# define SHUT_RDWR 2
# pragma comment(lib, "Ws2_32.lib")
# pragma comment(lib, "Iphlpapi.lib")
# pragma comment(lib, "Psapi.lib")
# ifdef ARCH_BITS_32
# define _X86_
# else
# define _IA64_
# endif
# else
# define SHUT_RDWR SD_BOTH
# endif
typedef int socklen_t;
extern long long __pi_perf_freq;
#endif
#ifdef ANDROID
///# define tcdrain(fd) ioctl(fd, TCSBRK, 1)
//inline int wctomb(char * c, wchar_t w) {*c = ((char * )&w)[0]; return 1;}
//inline int mbtowc(wchar_t * w, const char * c, size_t) {*w = ((wchar_t * )&c)[0]; return 1;}
#endif
#ifdef MAC_OS
# define environ (*_NSGetEnviron())
typedef long time_t;
#endif
#ifdef LINUX
# define environ __environ
#endif
#ifdef FREE_BSD
extern char ** environ;
#endif
#ifdef CC_GCC
# undef DEPRECATED
# define DEPRECATED __attribute__((deprecated))
# if CC_GCC_VERSION > 0x025F // > 2.95
# ifdef LINUX
# define HAS_LOCALE
# endif
# ifdef MAC_OS
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
# pragma GCC diagnostic ignored "-Wundefined-bool-conversion"
# pragma GCC diagnostic ignored "-Wc++11-extensions"
# endif
# endif
# ifdef ANDROID
# pragma GCC diagnostic ignored "-Wunused-parameter"
# pragma GCC diagnostic ignored "-Wextra"
# pragma GCC diagnostic ignored "-Wc++11-extensions"
# pragma GCC diagnostic ignored "-Wundefined-bool-conversion"
//# pragma GCC diagnostic ignored "-Wliteral-suffix"
# endif
#endif
#ifdef CC_VC
# undef DEPRECATED
# define DEPRECATED
# pragma warning(disable: 4018)
# pragma warning(disable: 4061)
# pragma warning(disable: 4100)
# pragma warning(disable: 4239)
# pragma warning(disable: 4242)
# pragma warning(disable: 4244)
# pragma warning(disable: 4251)
# pragma warning(disable: 4365)
# pragma warning(disable: 4512)
# pragma warning(disable: 4668)
# pragma warning(disable: 4710)
# pragma warning(disable: 4800)
# pragma warning(disable: 4820)
# pragma warning(disable: 4986)
# pragma warning(disable: 4996)
# ifdef ARCH_BITS_32
typedef long ssize_t;
# else
typedef long long ssize_t;
# endif
#endif
#ifdef CC_OTHER
# undef DEPRECATED
# define DEPRECATED
#endif
// Private data macros
#define PRIVATE_DECLARATION \
struct __Private__; \
friend struct __Private__; \
struct __PrivateInitializer__ { \
__PrivateInitializer__(); \
__PrivateInitializer__(const __PrivateInitializer__ & o); \
~__PrivateInitializer__(); \
__PrivateInitializer__ & operator =(const __PrivateInitializer__ & o); \
__Private__ * p; \
}; \
__PrivateInitializer__ __privateinitializer__;
#define PRIVATE_DEFINITION_START(c) \
struct c::__Private__ {
#define PRIVATE_DEFINITION_END(c) \
}; \
c::__PrivateInitializer__::__PrivateInitializer__() {p = new c::__Private__();} \
c::__PrivateInitializer__::__PrivateInitializer__(const c::__PrivateInitializer__ & ) {/*if (p) delete p;*/ p = new c::__Private__();} \
c::__PrivateInitializer__::~__PrivateInitializer__() {delete p; p = 0;} \
c::__PrivateInitializer__ & c::__PrivateInitializer__::operator =(const c::__PrivateInitializer__ & ) {if (p) delete p; p = new c::__Private__(); return *this;}
#define PRIVATE (__privateinitializer__.p)
#define PRIVATEWB __privateinitializer__.p
#define NO_COPY_CLASS(name) \
explicit name(const name & ); \
void operator =(const name & );
#ifdef FREERTOS
# define PIP_MIN_MSLEEP 10.
#else
# define PIP_MIN_MSLEEP 1.
#endif
//! Macro used for infinite loop
#define FOREVER for (;;)
//! Macro used for infinite wait
#define FOREVER_WAIT FOREVER msleep(PIP_MIN_MSLEEP);
//! Macro used for infinite wait
#define WAIT_FOREVER FOREVER msleep(PIP_MIN_MSLEEP);
//! global variable enabling output to piCout, default is true
extern PIP_EXPORT bool piDebug;
//! global variable that set minimum real update interval
//! for function PIInit::mountInfo(), default is 10000 ms
extern PIP_EXPORT double piMountInfoRefreshIntervalMs;
typedef unsigned char uchar;
typedef unsigned short ushort;
typedef unsigned int uint;
typedef unsigned long ulong;
typedef unsigned long long ullong;
typedef long long llong;
typedef long double ldouble;
/*! \brief Templated function for swap two values
* \details Example:\n \snippet piincludes.cpp swap */
template<typename T> inline void piSwap(T & f, T & s) {T t = f; f = s; s = t;}
/*! \brief Templated function for swap two values without "="
* \details Example:\n \snippet piincludes.cpp swapBinary */
template<typename T> inline void piSwapBinary(T & f, T & s) {
if ((size_t*)&f == (size_t*)&s) return;
size_t j = (sizeof(T) / sizeof(size_t)), bs = j * sizeof(size_t), bf = sizeof(T);
size_t i = 0;
for (i = 0; i < j; ++i) {
((size_t*)(&f))[i] ^= ((size_t*)(&s))[i];
((size_t*)(&s))[i] ^= ((size_t*)(&f))[i];
((size_t*)(&f))[i] ^= ((size_t*)(&s))[i];
}
for (i = bs; i < bf; ++i) {
((uchar*)(&f))[i] ^= ((uchar*)(&s))[i];
((uchar*)(&s))[i] ^= ((uchar*)(&f))[i];
((uchar*)(&f))[i] ^= ((uchar*)(&s))[i];
}
}
template<> inline void piSwapBinary(const void *& f, const void *& s) {
if ((size_t*)f == (size_t*)s) return;
size_t j = (sizeof(void *) / sizeof(size_t)), bs = j * sizeof(size_t), bf = sizeof(void *);
size_t i = 0;
void * pf = const_cast<void*>(f), * ps = const_cast<void*>(s);
for (i = 0; i < j; ++i) {
((size_t*)(&pf))[i] ^= ((size_t*)(&ps))[i];
((size_t*)(&ps))[i] ^= ((size_t*)(&pf))[i];
((size_t*)(&pf))[i] ^= ((size_t*)(&ps))[i];
}
for (i = bs; i < bf; ++i) {
((uchar*)(&pf))[i] ^= ((uchar*)(&ps))[i];
((uchar*)(&ps))[i] ^= ((uchar*)(&pf))[i];
((uchar*)(&pf))[i] ^= ((uchar*)(&ps))[i];
}
}
/*! \brief Function for compare two values without "=" by raw content
* \details Example:\n \snippet piincludes.cpp compareBinary */
inline bool piCompareBinary(const void * f, const void * s, size_t size) {
for (size_t i = 0; i < size; ++i)
if (((const uchar*)f)[i] != ((const uchar*)s)[i])
return false;
return true;
}
/*! \brief Templated function return round of float falue
* \details Round is the nearest integer value \n
* There are some macros:
* - \c piRoundf for "float"
* - \c piRoundd for "double"
*
* Example:
* \snippet piincludes.cpp round */
template<typename T> inline int piRound(const T & v) {return int(v >= T(0.) ? v + T(0.5) : v - T(0.5));}
/*! \brief Templated function return floor of float falue
* \details Floor is the largest integer that is not greater than value \n
* There are some macros:
* - \c piFloorf for "float"
* - \c piFloord for "double"
*
* Example:
* \snippet piincludes.cpp floor */
template<typename T> inline int piFloor(const T & v) {return v < T(0) ? int(v) - 1 : int(v);}
/*! \brief Templated function return ceil of float falue
* \details Ceil is the smallest integer that is not less than value \n
* There are some macros:
* - \c piCeilf for "float"
* - \c piCeild for "double"
*
* Example:
* \snippet piincludes.cpp ceil */
template<typename T> inline int piCeil(const T & v) {return v < T(0) ? int(v) : int(v) + 1;}
/*! \brief Templated function return absolute of numeric falue
* \details Absolute is the positive or equal 0 value \n
* There are some macros:
* - \c piAbss for "short"
* - \c piAbsi for "int"
* - \c piAbsl for "long"
* - \c piAbsll for "llong"
* - \c piAbsf for "float"
* - \c piAbsd for "double"
*
* Example:
* \snippet piincludes.cpp abs */
template<typename T> inline T piAbs(const T & v) {return (v >= T(0) ? v : -v);}
/*! \brief Templated function return minimum of two values
* \details There are some macros:
* - \c piMins for "short"
* - \c piMini for "int"
* - \c piMinl for "long"
* - \c piMinll for "llong"
* - \c piMinf for "float"
* - \c piMind for "double"
*
* Example:
* \snippet piincludes.cpp min2 */
template<typename T> inline T piMin(const T & f, const T & s) {return ((f > s) ? s : f);}
/*! \brief Templated function return minimum of tree values
* \details There are some macros:
* - \c piMins for "short"
* - \c piMini for "int"
* - \c piMinl for "long"
* - \c piMinll for "llong"
* - \c piMinf for "float"
* - \c piMind for "double"
*
* Example:
* \snippet piincludes.cpp min3 */
template<typename T> inline T piMin(const T & f, const T & s, const T & t) {return ((f < s && f < t) ? f : ((s < t) ? s : t));}
/*! \brief Templated function return maximum of two values
* \details There are some macros:
* - \c piMaxs for "short"
* - \c piMaxi for "int"
* - \c piMaxl for "long"
* - \c piMaxll for "llong"
* - \c piMaxf for "float"
* - \c piMaxd for "double"
*
* Example:
* \snippet piincludes.cpp max2 */
template<typename T> inline T piMax(const T & f, const T & s) {return ((f < s) ? s : f);}
/*! \brief Templated function return maximum of tree values
* \details There are some macros:
* - \c piMaxs for "short"
* - \c piMaxi for "int"
* - \c piMaxl for "long"
* - \c piMaxll for "llong"
* - \c piMaxf for "float"
* - \c piMaxd for "double"
*
* Example:
* \snippet piincludes.cpp max3 */
template<typename T> inline T piMax(const T & f, const T & s, const T & t) {return ((f > s && f > t) ? f : ((s > t) ? s : t));}
/*! \brief Templated function return clamped value
* \details Clamped is the not greater than "max" and not lesser than "min" value \n
* There are some macros:
* - \c piClamps for "short"
* - \c piClampi for "int"
* - \c piClampl for "long"
* - \c piClampll for "llong"
* - \c piClampf for "float"
* - \c piClampd for "double"
*
* Example:
* \snippet piincludes.cpp clamp */
template<typename T> inline T piClamp(const T & v, const T & min, const T & max) {return (v > max ? max : (v < min ? min : v));}
/// Function inverse byte order in memory block
inline void piLetobe(void * data, int size) {
for (int i = 0; i < size / 2; i++)
piSwap<uchar>(((uchar*)data)[size - i - 1], ((uchar*)data)[i]);
}
/// \brief Templated function that inverse byte order of value "v"
template<typename T> inline void piLetobe(T * v) {piLetobe(v, sizeof(T));}
/*! \brief Templated function that returns "v" with inversed byte order
* \details This function used to convert values between little and big endian \n
* There are some macros:
* - \c piLetobes for "ushort"
* - \c piLetobei for "uint"
* - \c piLetobel for "ulong"
* - \c piLetobell for "ullong"
*
* Example:
* \snippet piincludes.cpp letobe */
template<typename T> inline T piLetobe(const T & v) {T tv(v); piLetobe(&tv, sizeof(T)); return tv;}
// specialization
template<> inline ushort piLetobe(const ushort & v) {return (v << 8) | (v >> 8);}
template<> inline uint piLetobe(const uint & v) {return (v >> 24) | ((v >> 8) & 0xFF00) | ((v << 8) & 0xFF0000) | ((v << 24) & 0xFF000000);}
template<> inline float piLetobe(const float & v) {
union _pletobe_f {
_pletobe_f(const float &f_) {f = f_;}
float f;
uint v;
};
_pletobe_f a(v);
a.v = (a.v >> 24) | ((a.v >> 8) & 0xFF00) | ((a.v << 8) & 0xFF0000) | ((a.v << 24) & 0xFF000000);
return a.f;
}
DEPRECATED inline ushort letobe_s(const ushort & v) {return (v << 8) | (v >> 8);}
DEPRECATED inline uint letobe_i(const uint & v) {return (v >> 24) | ((v >> 8) & 0xFF00) | ((v << 8) & 0xFF0000) | ((v << 24) & 0xFF000000);}
#ifdef DOXYGEN
/// \deprecated \brief Use \a piLetobe() instead of this function
ushort letobe_s(ushort v) {return (v << 8) | (v >> 8);}
/// \deprecated \brief Use \a piLetobe() instead of this function
uint letobe_i(uint v) {return (v >> 24) | ((v >> 8) & 0xFF00) | ((v << 8) & 0xFF0000) | ((v << 24) & 0xFF000000);}
#endif
/// \brief Generic hash function, impements murmur3/32 algorithm
inline uint piHashData(const uchar * data, uint len, uint seed = 0) {
if (!data || len <= 0) return 0u;
uint h = seed;
if (len > 3) {
uint i = len >> 2;
do {
uint k;
memcpy(&k, data, sizeof(uint));
data += sizeof(uint);
k *= 0xcc9e2d51;
k = (k << 15) | (k >> 17);
k *= 0x1b873593;
h ^= k;
h = (h << 13) | (h >> 19);
h = h * 5 + 0xe6546b64;
} while (--i);
}
if (len & 3) {
uint i = len & 3;
uint k = 0;
do {
k <<= 8;
k |= data[i - 1];
} while (--i);
k *= 0xcc9e2d51;
k = (k << 15) | (k >> 17);
k *= 0x1b873593;
h ^= k;
}
h ^= len;
h ^= h >> 16;
h *= 0x85ebca6b;
h ^= h >> 13;
h *= 0xc2b2ae35;
h ^= h >> 16;
return h;
}
template<typename T> inline uint piHash(const T & v) {
return 0;
}
template<> inline uint piHash(const char & v) {return (uint)v;}
template<> inline uint piHash(const uchar & v) {return (uint)v;}
template<> inline uint piHash(const short & v) {return (uint)v;}
template<> inline uint piHash(const ushort & v) {return (uint)v;}
template<> inline uint piHash(const int & v) {return (uint)v;}
template<> inline uint piHash(const uint & v) {return (uint)v;}
template<> inline uint piHash(const llong & v) {return piHashData((const uchar *)&v, sizeof(v));}
template<> inline uint piHash(const ullong & v) {return piHashData((const uchar *)&v, sizeof(v));}
template<> inline uint piHash(const float & v) {return (uint)v;}
template<> inline uint piHash(const double & v) {return piHashData((const uchar *)&v, sizeof(v));}
template<> inline uint piHash(const ldouble & v) {return piHashData((const uchar *)&v, sizeof(v));}
#define piRoundf piRound<float>
#define piRoundd piRound<double>
#define piFloorf piFloor<float>
#define piFloord piFloor<double>
#define piCeilf piCeil<float>
#define piCeild piCeil<double>
#define piAbss piAbs<short>
#define piAbsi piAbs<int>
#define piAbsl piAbs<long>
#define piAbsll piAbs<llong>
#define piAbsf piAbs<float>
#define piAbsd piAbs<double>
#define piMins piMin<short>
#define piMini piMin<int>
#define piMinl piMin<long>
#define piMinll piMin<llong>
#define piMinf piMin<float>
#define piMind piMin<double>
#define piMaxs piMax<short>
#define piMaxi piMax<int>
#define piMaxl piMax<long>
#define piMaxll piMax<llong>
#define piMaxf piMax<float>
#define piMaxd piMax<double>
#define piClamps piClamp<short>
#define piClampi piClamp<int>
#define piClampl piClamp<long>
#define piClampll piClamp<llong>
#define piClampf piClamp<float>
#define piClampd piClamp<double>
#define piLetobes piLetobe<ushort>
#define piLetobei piLetobe<uint>
#define piLetobel piLetobe<ulong>
#define piLetobell piLetobe<ullong>
#define piLetobef piLetobe<float>
#endif // PIBASE_H

View File

@@ -0,0 +1,44 @@
/*
PIP - Platform Independent Primitives
Bit array
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "pibitarray.h"
#include "picout.h"
PICout operator <<(PICout s, const PIBitArray & ba) {
s.space();
s.setControl(0, true);
for (uint i = 0; i < ba.bitSize(); ++i) {
s << int(ba[i]);
if (i % 8 == 7) s << ' ';
}
s.restoreControl();
return s;
}
#ifdef PIP_STD_IOSTREAM
std::ostream &operator <<(std::ostream & s, const PIBitArray & ba) {
for (uint i = 0; i < ba.bitSize(); ++i) {
s << ba[i];
if (i % 8 == 7) s << ' ';
}
return s;
}
#endif

112
lib/main/core/pibitarray.h Normal file
View File

@@ -0,0 +1,112 @@
/*! \file pibitarray.h
* \brief Bit array
*/
/*
PIP - Platform Independent Primitives
Bit array
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PIBITARRAY_H
#define PIBITARRAY_H
#include "pivector.h"
class PIP_EXPORT PIBitArray {
friend PIByteArray & operator <<(PIByteArray & s, const PIBitArray & v);
friend PIByteArray & operator >>(PIByteArray & s, PIBitArray & v);
public:
PIBitArray(const int & size = 0) {resize(size);}
PIBitArray(uchar val) {resize(sizeof(val) * 8); data_[0] = val;}
PIBitArray(ushort val) {resize(sizeof(val) * 8); memcpy(data(), &val, sizeof(val));}
PIBitArray(uint val) {resize(sizeof(val) * 8); memcpy(data(), &val, sizeof(val));}
PIBitArray(ulong val) {resize(sizeof(val) * 8); memcpy(data(), &val, sizeof(val));}
PIBitArray(ullong val) {resize(sizeof(val) * 8); memcpy(data(), &val, sizeof(val));}
PIBitArray(const uchar * bytes, uint size) {resize(size * 8); memcpy(data(), bytes, size);}
uint bitSize() const {return size_;}
uint byteSize() const {return bytesInBits(size_);}
PIBitArray & resize(const uint & size) {size_ = size; data_.resize(bytesInBits(size_)); return *this;}
PIBitArray & clearBit(const uint & index) {data_[index / 8] &= ~(1 << (index % 8)); return *this;}
PIBitArray & setBit(const uint & index) {data_[index / 8] |= (1 << (index % 8)); return *this;}
PIBitArray & writeBit(const uint & index, const bool & value) {if (value) setBit(index); else clearBit(index); return *this;}
PIBitArray & writeBit(const uint & index, const uchar & value) {return writeBit(index, value > 0);}
PIBitArray & push_back(const bool & value) {resize(size_ + 1); writeBit(size_ - 1, value); return *this;}
PIBitArray & push_back(const uchar & value) {return push_back(value > 0);}
PIBitArray & insert(const uint & index, const bool & value) {
resize(size_ + 1);
uint fi = byteSize() - 1, si = index / 8, ti = index % 8;
uchar c = data_[si];
for (uint i = fi; i > si; --i) {
data_[i] <<= 1;
if ((0x80 & data_[i - 1]) == 0x80) data_[i] |= 1;
else data_[i] &= 0xFE;}
data_[si] &= (0xFF >> (7 - ti));
data_[si] |= ((c << 1) & (0xFF << (ti)));
if (value) data_[si] |= (1 << ti);
else data_[si] &= ~(1 << ti);
return *this;}
PIBitArray & insert(const uint & index, const uchar & value) {return insert(index, value > 0);}
PIBitArray & push_front(const bool & value) {return insert(0, value);}
PIBitArray & push_front(const uchar & value) {return push_front(value > 0);}
PIBitArray & pop_back() {return resize(size_ - 1);}
PIBitArray & pop_front() {
if (size_ == 0) return *this;
uint fi = byteSize() - 1;
for (uint i = 0; i < fi; ++i) {
data_[i] >>= 1;
if ((1 & data_[i + 1]) == 1) data_[i] |= 0x80;
else data_[i] &= 0x7F;}
data_[fi] >>= 1;
resize(size_ - 1);
return *this;}
PIBitArray & append(const PIBitArray & ba) {for (uint i = 0; i < ba.bitSize(); ++i) push_back(ba[i]); return *this;}
uchar * data() {return data_.data();}
uchar toUChar() {if (size_ == 0) return 0; return data_[0];}
ushort toUShort() {ushort t = 0; memcpy(&t, data(), piMin<uint>(byteSize(), sizeof(t))); return t;}
uint toUInt() {uint t = 0; memcpy(&t, data(), piMin<uint>(byteSize(), sizeof(t))); return t;}
ulong toULong() {ulong t = 0; memcpy(&t, data(), piMin<uint>(byteSize(), sizeof(t))); return t;}
ullong toULLong() {ullong t = 0; memcpy(&t, data(), piMin<uint>(byteSize(), sizeof(t))); return t;}
bool at(const uint & index) const {return (1 & (data_[index / 8] >> (index % 8))) == 1 ? true : false;}
bool operator [](const uint & index) const {return at(index);}
void operator +=(const PIBitArray & ba) {append(ba);}
bool operator ==(const PIBitArray & ba) const {if (bitSize() != ba.bitSize()) return false; for (uint i = 0; i < bitSize(); ++i) if (at(i) != ba[i]) return false; return true;}
bool operator !=(const PIBitArray & ba) const {return !(*this == ba);}
void operator =(const uchar & val) {resize(sizeof(val) * 8); data_[0] = val;}
void operator =(const ushort & val) {resize(sizeof(val) * 8); memcpy(data(), &val, sizeof(val));}
void operator =(const uint & val) {resize(sizeof(val) * 8); memcpy(data(), &val, sizeof(val));}
void operator =(const ulong & val) {resize(sizeof(val) * 8); memcpy(data(), &val, sizeof(val));}
void operator =(const ullong & val) {resize(sizeof(val) * 8); memcpy(data(), &val, sizeof(val));}
private:
static uint bytesInBits(const uint & bits) {return (bits + 7) / 8;}
PIVector<uchar> data_;
uint size_;
};
#ifdef PIP_STD_IOSTREAM
//std::ostream & operator <<(std::ostream & s, const PIBitArray & ba);
#endif
PICout operator <<(PICout s, const PIBitArray & ba);
#endif // PIBITARRAY_H

View File

@@ -0,0 +1,403 @@
/*
PIP - Platform Independent Primitives
Byte array
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "pibytearray.h"
#include "pistringlist.h"
#include <iostream>
/*! \class PIByteArray
* \brief Byte array
* \details This class based on PIDeque<uchar> and provide some handle function
* to manipulate it.
*
* \section PIByteArray_sec0 Usage
* %PIByteArray can be used to store custom data and manipulate it. There are many
* stream operators to store/restore common types to byte array. Store operators
* places data at the end of array, restore operators takes data from the beginning
* of array.
* In addition there are Base 64 convertions and checksums:
* * plain 8-bit
* * plain 32-bit
*
* One of the major usage of %PIByteArray is stream functions. You can form binary
* packet from many types (also dynamic types, e.g. PIVector) with one line:
* \snippet pibytearray.cpp 0
*
* Or you can descibe stream operator of your own type and store/restore vectors of
* your type:
* \snippet pibytearray.cpp 1
*
* For store/restore custom data blocks there is PIByteArray::RawData class. Stream
* operators of this class simply store/restore data block to/from byte array.
* \snippet pibytearray.cpp 2
*
* \section PIByteArray_sec1 Attention
* Stream operator of %PIByteArray store byte array as vector, not simply append
* content of byte array. This operators useful to transmit custom data as %PIByteArray
* packed into parent byte array, e.g. to form packet from %PIByteArray.
* To append one byte array to another use funtion \a append().
* \snippet pibytearray.cpp 3
*
*
*/
static const uchar base64Table[64] = {
0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50,
0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
0x59, 0x5a, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76,
0x77, 0x78, 0x79, 0x7a, 0x30, 0x31, 0x32, 0x33,
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2b, 0x2f};
static const uchar base64InvTable[256] = {
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x3E, 0x0, 0x0, 0x0, 0x3F,
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B,
0x3C, 0x3D, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6,
0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE,
0xF, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
0x17, 0x18, 0x19, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20,
0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30,
0x31, 0x32, 0x33, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
struct base64HelpStruct {
base64HelpStruct() {v = 0;}
inline void setBytes(const uchar * r, int size = 3) {
v = 0;
switch (size) {
case 3: v |= r[2];
case 2: v |= r[1] << 8;
case 1: v |= r[0] << 16;
}
}
inline void getBytes(uchar * r) {
r[0] = (v >> 16) & 0xFF;
r[1] = (v >> 8) & 0xFF;
r[2] = v & 0xFF;
}
inline void setAscii(const uchar * r, int size = 4) {
v = 0;
switch (size) {
case 4: v |= (base64InvTable[r[3]] & 0x3F);
case 3: v |= (base64InvTable[r[2]] & 0x3F) << 6;
case 2: v |= (base64InvTable[r[1]] & 0x3F) << 12;
case 1: v |= (base64InvTable[r[0]] & 0x3F) << 18;
}
}
inline void getAscii(uchar * r) {
r[0] = base64Table[(v >> 18) & 0x3F];
r[1] = base64Table[(v >> 12) & 0x3F];
r[2] = base64Table[(v >> 6) & 0x3F];
r[3] = base64Table[ v & 0x3F];
}
uint v;
};
PIByteArray &PIByteArray::convertToBase64() {
return *this = toBase64();
}
PIByteArray &PIByteArray::convertFromBase64() {
return *this = fromBase64(*this);
}
PIByteArray PIByteArray::toBase64() const {
if (isEmpty()) return PIByteArray();
base64HelpStruct hs;
PIByteArray ret;
int sz = (size_s() / 3) * 3, ri = -1;
uchar t[4];
ret.resize(((size_s() - 1) / 3 + 1) * 4);
for (int i = 0; i < sz; i += 3) {
hs.setBytes(data(i));
hs.getAscii(t);
ret[++ri] = (t[0]);
ret[++ri] = (t[1]);
ret[++ri] = (t[2]);
ret[++ri] = (t[3]);
}
int der = size_s() % 3;
switch (der) {
case 1:
hs.setBytes(data(sz), 1);
hs.getAscii(t);
ret[++ri] = (t[0]);
ret[++ri] = (t[1]);
ret[++ri] = ('=');
ret[++ri] = ('=');
break;
case 2:
hs.setBytes(data(sz), 2);
hs.getAscii(t);
ret[++ri] = (t[0]);
ret[++ri] = (t[1]);
ret[++ri] = (t[2]);
ret[++ri] = ('=');
break;
default: break;
}
return ret;
}
PIByteArray PIByteArray::fromBase64(const PIByteArray & base64) {
if (base64.isEmpty()) return PIByteArray();
base64HelpStruct hs;
PIByteArray ret;
int sz = base64.size_s(), ind = -1;
uchar t[4];
ret.resize(sz / 4 * 3);
for (int i = 0; i < sz; i += 4) {
hs.setAscii(base64.data(i));
hs.getBytes(t);
ret[++ind] = (t[0]);
ret[++ind] = (t[1]);
ret[++ind] = (t[2]);
}
if (base64.back() == '=') ret.pop_back();
if (sz > 1) if (base64[sz - 2] == '=') ret.pop_back();
return ret;
}
PIByteArray PIByteArray::fromBase64(const PIString & base64) {
return fromBase64(base64.toByteArray());
}
PIByteArray & PIByteArray::compressRLE(uchar threshold) {
PIByteArray t;
uchar fb, clen, mlen = 255 - threshold;
for (uint i = 0; i < size();) {
fb = at(i);
clen = 1;
while (at(++i) == fb) {
++clen;
if (clen == mlen)
break;
}
if (clen > 1) {
t.push_back(threshold + clen);
t.push_back(fb);
continue;
}
if (fb >= threshold) {
t.push_back(threshold + 1);
t.push_back(fb);
} else
t.push_back(fb);
}
*this = t;
return *this;
}
PIByteArray & PIByteArray::decompressRLE(uchar threshold) {
PIByteArray t;
uchar fb, clen;
for (uint i = 0; i < size(); ++i) {
fb = at(i);
if (fb >= threshold) {
clen = fb - threshold;
fb = at(++i);
for (uint j = 0; j < clen; ++j)
t.push_back(fb);
continue;
} else
t.push_back(fb);
}
*this = t;
return *this;
}
uchar PIByteArray::checksumPlain8() const {
uchar c = 0;
int sz = size_s();
for (int i = 0; i < sz; ++i)
c += at(i);
c = ~(c + 1);
return c;
}
uint PIByteArray::checksumPlain32() const {
uint c = 0;
int sz = size_s();
for (int i = 0; i < sz; ++i)
c += at(i) * (i + 1);
c = ~(c + 1);
return c;
}
uint PIByteArray::hash() const {
return piHashData(data(), size_s());
}
PIString PIByteArray::toString(int base) const {
PIString ret;
int sz = size_s();
for (int i = 0; i < sz; ++i) {
if (i > 0) ret += " ";
if (base == 2) ret += "b";
if (base == 8) ret += "0";
if (base == 16) ret += "0x";
ret += PIString::fromNumber(at(i), base);
}
return ret;
}
PIString PIByteArray::toHex() const {
PIByteArray hex(size() * 2);
uchar *hexData = hex.data();
const uchar *d = data();
for (int i = 0; i < size_s(); ++i) {
int j = (d[i] >> 4) & 0xf;
if (j <= 9) hexData[i*2] = (j + '0');
else hexData[i*2] = (j + 'a' - 10);
j = d[i] & 0xf;
if (j <= 9) hexData[i*2+1] = (j + '0');
else hexData[i*2+1] = (j + 'a' - 10);
}
return PIString(hex);
}
PIByteArray PIByteArray::fromUserInput(PIString str) {
PIByteArray ret;
if (str.trim().isEmpty()) return ret;
str.replaceAll("\n", " ").replaceAll("\t", " ").replaceAll(" ", " ");
PIStringList bl(str.split(" "));
bool ok(false);
piForeachC (PIString & b, bl) {
int bv = b.toInt(-1, &ok);
if (ok) ret << uchar(bv);
}
return ret;
}
PIByteArray PIByteArray::fromHex(PIString str) {
PIByteArray hexEncoded = str.toByteArray();
PIByteArray res((hexEncoded.size() + 1)/ 2);
uchar *result = res.data() + res.size();
bool odd_digit = true;
for (int i = hexEncoded.size() - 1; i >= 0; --i) {
int ch = hexEncoded.at(i);
int tmp;
if (ch >= '0' && ch <= '9') tmp = ch - '0';
else if (ch >= 'a' && ch <= 'f') tmp = ch - 'a' + 10;
else if (ch >= 'A' && ch <= 'F') tmp = ch - 'A' + 10;
else continue;
if (odd_digit) {
--result;
*result = tmp;
odd_digit = false;
} else {
*result |= tmp << 4;
odd_digit = true;
}
}
res.remove(0, result - res.data());
return res;
}
PICout operator <<(PICout s, const PIByteArray & ba) {
s.space();
s.setControl(0, true);
s << "{";
for (uint i = 0; i < ba.size(); ++i) {
s << ba[i];
if (i < ba.size() - 1) s << ", ";
}
s << "}";
s.restoreControl();
return s;
}
#ifdef PIP_STD_IOSTREAM
std::ostream &operator <<(std::ostream & s, const PIByteArray & ba) {
s << "{";
for (uint i = 0; i < ba.size(); ++i) {
s << ba[i];
if (i < ba.size() - 1) s << ", ";
}
s << "}";
return s;
}
#endif
PIByteArray & operator >>(PIByteArray & s, PIByteArray & v) {
if (s.size_s() < 4) {
s.clear();
v.clear();
return s;
}
assert(s.size_s() >= 4);
int sz = 0;
s >> sz;
if (sz > s.size_s()) {
piCout << "[PIByteArray] Warning: operator >> wants too much data, discard!" << sz << s.size_s();
s.clear();
v.clear();
return s;
}
v.resize(sz);
if (sz > 0) {
memcpy(v.data(), s.data(), v.size());
s.remove(0, v.size());
}
return s;
}

321
lib/main/core/pibytearray.h Normal file
View File

@@ -0,0 +1,321 @@
/*! \file pibytearray.h
* \brief Byte array
*/
/*
PIP - Platform Independent Primitives
Byte array
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PIBYTEARRAY_H
#define PIBYTEARRAY_H
#include "pichar.h"
#include "pibitarray.h"
#include "pimap.h"
#include "pivector2d.h"
__PICONTAINERS_SIMPLE_TYPE__(PIChar)
#define __PIBYTEARRAY_SIMPLE_TYPE__(T) \
template<> \
inline PIByteArray & operator <<(PIByteArray & s, const PIVector<T> & v) {s << int(v.size_s()); int os = s.size_s(); s.enlarge(v.size_s()*sizeof(T)); memcpy(s.data(os), v.data(), v.size_s()*sizeof(T)); return s;} \
template<> \
inline PIByteArray & operator >>(PIByteArray & s, PIVector<T> & v) {assert(s.size_s() >= 4); int sz; s >> sz; v._resizeRaw(sz); if (sz > 0) memcpy(v.data(), s.data(), sz*sizeof(T)); s.remove(0, sz*sizeof(T)); return s;} \
template<> \
inline PIByteArray & operator <<(PIByteArray & s, const PIDeque<T> & v) {s << int(v.size_s()); int os = s.size_s(); s.enlarge(v.size_s()*sizeof(T)); memcpy(s.data(os), v.data(), v.size_s()*sizeof(T)); return s;} \
template<> \
inline PIByteArray & operator >>(PIByteArray & s, PIDeque<T> & v) {assert(s.size_s() >= 4); int sz; s >> sz; v._resizeRaw(sz); if (sz > 0) memcpy(v.data(), s.data(), sz*sizeof(T)); s.remove(0, sz*sizeof(T)); return s;} \
template<> \
inline PIByteArray & operator <<(PIByteArray & s, const PIVector2D<T> & v) {s << int(v.rows()) << int(v.cols()); int os = s.size_s(); s.enlarge(v.size_s()*sizeof(T)); memcpy(s.data(os), v.data(), v.size_s()*sizeof(T)); return s;} \
template<> \
inline PIByteArray & operator >>(PIByteArray & s, PIVector2D<T> & v) {assert(s.size_s() >= 8); int r, c; s >> r >> c; v._resizeRaw(r, c); int sz = r*c; if (sz > 0) memcpy(v.data(), s.data(), sz*sizeof(T)); s.remove(0, sz*sizeof(T)); return s;}
class PIString;
class PIByteArray;
class PIP_EXPORT PIByteArray: public PIDeque<uchar>
{
public:
//! Constructs an empty byte array
PIByteArray() {;}
//! Constructs 0-filled byte array with size "size"
PIByteArray(const uint size) {resize(size);}
//! Constructs byte array from data "data" and size "size"
PIByteArray(const void * data, const uint size): PIDeque<uchar>((const uchar*)data, size_t(size)) {}
//! Constructs byte array with size "size" filled by "t"
PIByteArray(const uint size, uchar t): PIDeque<uchar>(size, t) {}
//! Help struct to store/restore custom blocks of data to/from PIByteArray
struct RawData {
friend PIByteArray & operator <<(PIByteArray & s, const PIByteArray::RawData & v);
friend PIByteArray & operator >>(PIByteArray & s, PIByteArray::RawData v);
public:
//! Constructs data block
RawData(void * data = 0, int size = 0) {d = data; s = size;}
RawData(const RawData & o) {d = o.d; s = o.s;}
//! Constructs data block
RawData(const void * data, const int size) {d = const_cast<void * >(data); s = size;}
RawData & operator =(const RawData & o) {d = o.d; s = o.s; return *this;}
private:
void * d;
int s;
};
//! Return resized byte array
PIByteArray resized(uint new_size) const {PIByteArray ret(new_size); memcpy(ret.data(), data(), new_size); return ret;}
//! Convert data to Base 64 and return this byte array
PIByteArray & convertToBase64();
//! Convert data from Base 64 and return this byte array
PIByteArray & convertFromBase64();
//! Return converted to Base 64 data
PIByteArray toBase64() const;
//! Return converted from Base 64 data
PIByteArray & compressRLE(uchar threshold = 192);
PIByteArray & decompressRLE(uchar threshold = 192);
PIByteArray compressedRLE(uchar threshold = 192) {PIByteArray ba(*this); ba.compressRLE(threshold); return ba;}
PIByteArray decompressedRLE(uchar threshold = 192) {PIByteArray ba(*this); ba.decompressRLE(threshold); return ba;}
PIString toString(int base = 16) const;
PIString toHex() const;
//! Add to the end data "data" with size "size"
PIByteArray & append(const void * data_, int size_) {uint ps = size(); enlarge(size_); memcpy(data(ps), data_, size_); return *this;}
//! Add to the end byte array "data"
PIByteArray & append(const PIByteArray & data_) {uint ps = size(); enlarge(data_.size_s()); memcpy(data(ps), data_.data(), data_.size()); return *this;}
//! Add to the end "t"
PIByteArray & append(uchar t) {push_back(t); return *this;}
//! Returns plain 8-bit checksum
uchar checksumPlain8() const;
//! Returns plain 32-bit checksum
uint checksumPlain32() const;
//! Returns hash
uint hash() const;
void operator =(const PIDeque<uchar> & d) {resize(d.size()); memcpy(data(), d.data(), d.size());}
static PIByteArray fromUserInput(PIString str);
static PIByteArray fromHex(PIString str);
static PIByteArray fromBase64(const PIByteArray & base64);
static PIByteArray fromBase64(const PIString & base64);
};
inline bool operator <(const PIByteArray & v0, const PIByteArray & v1) {if (v0.size() == v1.size()) {for (uint i = 0; i < v0.size(); ++i) if (v0[i] != v1[i]) return v0[i] < v1[i]; return false;} return v0.size() < v1.size();}
#ifdef PIP_STD_IOSTREAM
//! \relatesalso PIByteArray \brief Output to std::ostream operator
inline std::ostream & operator <<(std::ostream & s, const PIByteArray & ba);
#endif
//! \relatesalso PIByteArray \brief Output to PICout operator
PICout operator <<(PICout s, const PIByteArray & ba);
#define PBA_OPERATOR_TO int os = s.size_s(); s.enlarge(sizeof(v)); memcpy(s.data(os), &v, sizeof(v));
//! \relatesalso PIByteArray \brief Store operator
inline PIByteArray & operator <<(PIByteArray & s, bool v) {s.push_back(v); return s;}
//! \relatesalso PIByteArray \brief Store operator
inline PIByteArray & operator <<(PIByteArray & s, char v) {s.push_back(v); return s;}
//! \relatesalso PIByteArray \brief Store operator
inline PIByteArray & operator <<(PIByteArray & s, uchar v) {s.push_back(v); return s;}
//! \relatesalso PIByteArray \brief Store operator
inline PIByteArray & operator <<(PIByteArray & s, const short v) {PBA_OPERATOR_TO return s;}
//! \relatesalso PIByteArray \brief Store operator
inline PIByteArray & operator <<(PIByteArray & s, const int v) {PBA_OPERATOR_TO return s;}
//! \relatesalso PIByteArray \brief Store operator
inline PIByteArray & operator <<(PIByteArray & s, const long & v) {PBA_OPERATOR_TO return s;}
//! \relatesalso PIByteArray \brief Store operator
inline PIByteArray & operator <<(PIByteArray & s, const llong & v) {PBA_OPERATOR_TO return s;}
//! \relatesalso PIByteArray \brief Store operator
inline PIByteArray & operator <<(PIByteArray & s, const ushort v) {PBA_OPERATOR_TO return s;}
//! \relatesalso PIByteArray \brief Store operator
inline PIByteArray & operator <<(PIByteArray & s, const uint v) {PBA_OPERATOR_TO return s;}
//! \relatesalso PIByteArray \brief Store operator
inline PIByteArray & operator <<(PIByteArray & s, const ulong & v) {PBA_OPERATOR_TO return s;}
//! \relatesalso PIByteArray \brief Store operator
inline PIByteArray & operator <<(PIByteArray & s, const ullong & v) {PBA_OPERATOR_TO return s;}
//! \relatesalso PIByteArray \brief Store operator
inline PIByteArray & operator <<(PIByteArray & s, const float v) {PBA_OPERATOR_TO return s;}
//! \relatesalso PIByteArray \brief Store operator
inline PIByteArray & operator <<(PIByteArray & s, const double & v) {PBA_OPERATOR_TO return s;}
//! \relatesalso PIByteArray \brief Store operator
inline PIByteArray & operator <<(PIByteArray & s, const ldouble & v) {PBA_OPERATOR_TO return s;}
//! \relatesalso PIByteArray \brief Store operator
template<typename T> inline PIByteArray & operator <<(PIByteArray & s, const PIFlags<T> & v) {PBA_OPERATOR_TO return s;}
//! \relatesalso PIByteArray \brief Store operator, see \ref PIByteArray_sec1 for details
inline PIByteArray & operator <<(PIByteArray & s, const PIByteArray & v) {s << int(v.size_s()); int os = s.size_s(); s.enlarge(v.size_s()); if (v.size_s() > 0) memcpy(s.data(os), v.data(), v.size()); return s;}
//! \relatesalso PIByteArray \brief Store operator, see \ref PIByteArray_sec1 for details
inline PIByteArray & operator <<(PIByteArray & s, const PIByteArray::RawData & v) {int os = s.size_s(); s.enlarge(v.s); if (v.s > 0) memcpy(s.data(os), v.d, v.s); return s;}
#undef PBA_OPERATOR_TO
#define PBA_OPERATOR_FROM memcpy((void*)(&v), s.data(), sizeof(v)); s.remove(0, sizeof(v));
//! \relatesalso PIByteArray \brief Restore operator
inline PIByteArray & operator >>(PIByteArray & s, bool & v) {assert(s.size() >= 1u); v = s.take_front(); return s;}
//! \relatesalso PIByteArray \brief Restore operator
inline PIByteArray & operator >>(PIByteArray & s, char & v) {assert(s.size() >= 1u); v = s.take_front(); return s;}
//! \relatesalso PIByteArray \brief Restore operator
inline PIByteArray & operator >>(PIByteArray & s, uchar & v) {assert(s.size() >= 1u); v = s.take_front(); return s;}
//! \relatesalso PIByteArray \brief Restore operator
inline PIByteArray & operator >>(PIByteArray & s, short & v) {assert(s.size() >= sizeof(v)); PBA_OPERATOR_FROM return s;}
//! \relatesalso PIByteArray \brief Restore operator
inline PIByteArray & operator >>(PIByteArray & s, int & v) {assert(s.size() >= sizeof(v)); PBA_OPERATOR_FROM return s;}
//! \relatesalso PIByteArray \brief Restore operator
inline PIByteArray & operator >>(PIByteArray & s, long & v) {assert(s.size() >= sizeof(v)); PBA_OPERATOR_FROM return s;}
//! \relatesalso PIByteArray \brief Restore operator
inline PIByteArray & operator >>(PIByteArray & s, llong & v) {assert(s.size() >= sizeof(v)); PBA_OPERATOR_FROM return s;}
//! \relatesalso PIByteArray \brief Restore operator
inline PIByteArray & operator >>(PIByteArray & s, ushort & v) {assert(s.size() >= sizeof(v)); PBA_OPERATOR_FROM return s;}
//! \relatesalso PIByteArray \brief Restore operator
inline PIByteArray & operator >>(PIByteArray & s, uint & v) {assert(s.size() >= sizeof(v)); PBA_OPERATOR_FROM return s;}
//! \relatesalso PIByteArray \brief Restore operator
inline PIByteArray & operator >>(PIByteArray & s, ulong & v) {assert(s.size() >= sizeof(v)); PBA_OPERATOR_FROM return s;}
//! \relatesalso PIByteArray \brief Restore operator
inline PIByteArray & operator >>(PIByteArray & s, ullong & v) {assert(s.size() >= sizeof(v)); PBA_OPERATOR_FROM return s;}
//! \relatesalso PIByteArray \brief Restore operator
inline PIByteArray & operator >>(PIByteArray & s, float & v) {assert(s.size() >= sizeof(v)); PBA_OPERATOR_FROM return s;}
//! \relatesalso PIByteArray \brief Restore operator
inline PIByteArray & operator >>(PIByteArray & s, double & v) {assert(s.size() >= sizeof(v)); PBA_OPERATOR_FROM return s;}
//! \relatesalso PIByteArray \brief Restore operator
inline PIByteArray & operator >>(PIByteArray & s, ldouble & v) {assert(s.size() >= sizeof(v)); PBA_OPERATOR_FROM return s;}
//! \relatesalso PIByteArray \brief Restore operator
template<typename T> inline PIByteArray & operator >>(PIByteArray & s, PIFlags<T> & v) {PBA_OPERATOR_FROM return s;}
//! \relatesalso PIByteArray \brief Restore operator, see \ref PIByteArray_sec1 for details
PIByteArray & operator >>(PIByteArray & s, PIByteArray & v);
//! \relatesalso PIByteArray \brief Restore operator, see \ref PIByteArray_sec1 for details
inline PIByteArray & operator >>(PIByteArray & s, PIByteArray::RawData v) {assert(s.size_s() >= v.s); if (v.s > 0) memcpy((void*)(v.d), s.data(), v.s); s.remove(0, v.s); return s;}
#undef PBA_OPERATOR_FROM
template<typename Type0, typename Type1> inline PIByteArray & operator <<(PIByteArray & s, const PIPair<Type0, Type1> & v);
//! \relatesalso PIByteArray \brief Store operator
template<typename T> inline PIByteArray & operator <<(PIByteArray & s, const PIVector<T> & v);
//! \relatesalso PIByteArray \brief Store operator
template<typename T> inline PIByteArray & operator <<(PIByteArray & s, const PIDeque<T> & v);
//! \relatesalso PIByteArray \brief Store operator
template <typename Key, typename T> inline PIByteArray & operator <<(PIByteArray & s, const PIMap<Key, T> & v);
//! Write operator to \c PIByteArray
inline PIByteArray & operator <<(PIByteArray & s, const PIChar & v) {s << v.ch; return s;}
//! \relatesalso PIByteArray \brief Restore operator
template<typename Type0, typename Type1> inline PIByteArray & operator >>(PIByteArray & s, PIPair<Type0, Type1> & v);
//! \relatesalso PIByteArray \brief Restore operator
template<typename T> inline PIByteArray & operator >>(PIByteArray & s, PIVector<T> & v);
//! \relatesalso PIByteArray \brief Restore operator
template<typename T> inline PIByteArray & operator >>(PIByteArray & s, PIDeque<T> & v);
//! \relatesalso PIByteArray \brief Restore operator
template <typename Key, typename T> inline PIByteArray & operator >>(PIByteArray & s, PIMap<Key, T> & v);
//! Read operator from \c PIByteArray
inline PIByteArray & operator >>(PIByteArray & s, PIChar & v) {s >> v.ch; return s;}
//! \relatesalso PIByteArray \brief Store operator
inline PIByteArray & operator <<(PIByteArray & s, const PIBitArray & v) {s << v.size_ << v.data_; return s;}
template<typename Type0, typename Type1>
inline PIByteArray & operator <<(PIByteArray & s, const PIPair<Type0, Type1> & v) {s << v.first << v.second; return s;}
template<typename T>
inline PIByteArray & operator <<(PIByteArray & s, const PIVector<T> & v) {s << int(v.size_s()); for (uint i = 0; i < v.size(); ++i) s << v[i]; return s;}
template<typename T>
inline PIByteArray & operator <<(PIByteArray & s, const PIDeque<T> & v) {s << int(v.size_s()); for (uint i = 0; i < v.size(); ++i) s << v[i]; return s;}
template <typename Key, typename T>
inline PIByteArray & operator <<(PIByteArray & s, const PIMap<Key, T> & v) {
s << int(v.pim_index.size_s());
for (uint i = 0; i < v.size(); ++i)
s << int(v.pim_index[i].index) << v.pim_index[i].key;
s << v.pim_content;
return s;
}
template<typename T>
inline PIByteArray & operator <<(PIByteArray & s, const PIVector2D<T> & v) {s << int(v.rows()) << int(v.cols()) << v.toPlainVector(); return s;}
//! \relatesalso PIByteArray \brief Restore operator
inline PIByteArray & operator >>(PIByteArray & s, PIBitArray & v) {assert(s.size_s() >= 8); s >> v.size_ >> v.data_; return s;}
template<typename Type0, typename Type1>
inline PIByteArray & operator >>(PIByteArray & s, PIPair<Type0, Type1> & v) {s >> v.first >> v.second; return s;}
template<typename T>
inline PIByteArray & operator >>(PIByteArray & s, PIVector<T> & v) {assert(s.size_s() >= 4); int sz; s >> sz; v.resize(sz); for (int i = 0; i < sz; ++i) s >> v[i]; return s;}
template<typename T>
inline PIByteArray & operator >>(PIByteArray & s, PIDeque<T> & v) {assert(s.size_s() >= 4); int sz; s >> sz; v.resize(sz); for (int i = 0; i < sz; ++i) s >> v[i]; return s;}
template <typename Key, typename T>
inline PIByteArray & operator >>(PIByteArray & s, PIMap<Key, T> & v) {
assert(s.size_s() >= 4);
int sz; s >> sz; v.pim_index.resize(sz);
int ind = 0;
for (int i = 0; i < sz; ++i) {
s >> ind >> v.pim_index[i].key;
v.pim_index[i].index = ind;
}
s >> v.pim_content;
if (v.pim_content.size_s() != v.pim_index.size_s()) {
piCout << "Warning: loaded invalid PIMap, clear";
v.clear();
}
return s;
}
template<typename T>
inline PIByteArray & operator >>(PIByteArray & s, PIVector2D<T> & v) {assert(s.size_s() >= 8); int r,c; PIVector<T> tmp; s >> r >> c >> tmp; v = PIVector2D<T>(r, c, tmp); return s;}
template<typename T>
inline PIByteArray & operator <<(PIByteArray & s, const T & ) {piCout << "[PIByteArray] Warning: using undeclared operator <<!"; return s;}
template<typename T>
inline PIByteArray & operator >>(PIByteArray & s, T & ) {piCout << "[PIByteArray] Warning: using undeclared operator >>!"; return s;}
//! \relatesalso PIByteArray \brief Byte arrays compare operator
inline bool operator ==(PIByteArray & f, PIByteArray & s) {if (f.size_s() != s.size_s()) return false; for (int i = 0; i < f.size_s(); ++i) if (f[i] != s[i]) return false; return true;}
//! \relatesalso PIByteArray \brief Byte arrays compare operator
inline bool operator !=(PIByteArray & f, PIByteArray & s) {if (f.size_s() != s.size_s()) return true; for (int i = 0; i < f.size_s(); ++i) if (f[i] != s[i]) return true; return false;}
__PIBYTEARRAY_SIMPLE_TYPE__(bool)
__PIBYTEARRAY_SIMPLE_TYPE__(char)
__PIBYTEARRAY_SIMPLE_TYPE__(short)
__PIBYTEARRAY_SIMPLE_TYPE__(ushort)
__PIBYTEARRAY_SIMPLE_TYPE__(int)
__PIBYTEARRAY_SIMPLE_TYPE__(uint)
__PIBYTEARRAY_SIMPLE_TYPE__(long)
__PIBYTEARRAY_SIMPLE_TYPE__(ulong)
__PIBYTEARRAY_SIMPLE_TYPE__(llong)
__PIBYTEARRAY_SIMPLE_TYPE__(ullong)
__PIBYTEARRAY_SIMPLE_TYPE__(float)
__PIBYTEARRAY_SIMPLE_TYPE__(double)
__PIBYTEARRAY_SIMPLE_TYPE__(ldouble)
__PIBYTEARRAY_SIMPLE_TYPE__(PIChar)
template<> inline uint piHash(const PIByteArray & ba) {return ba.hash();}
#endif // PIBYTEARRAY_H

393
lib/main/core/pichar.cpp Normal file
View File

@@ -0,0 +1,393 @@
/*! \file pichar.h
* \brief Unicode char
*/
/*
PIP - Platform Independent Primitives
Unicode char
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "piincludes_p.h"
#include "pibytearray.h"
#ifdef PIP_ICU
# define U_NOEXCEPT
# include "unicode/ucnv.h"
# include "unicode/ustring.h"
#endif
#ifdef WINDOWS
# include <stringapiset.h>
# include <winnls.h>
#endif
char * __syslocname__ = 0;
char * __sysoemname__ = 0;
char * __utf8name__ = 0;
#ifdef BLACKBERRY
# include <ctype.h>
#endif
#include <wchar.h>
#ifdef ANDROID
# if __ANDROID_API__ < 21
# define wctomb(s, wc) wcrtomb(s, wc, NULL)
# define mbtowc(pwc, s, n) mbrtowc(pwc, s, n, NULL)
# endif
#endif
/*! \class PIChar
* \brief Unicode char
* \details This class is wrapper around \c "uint".
* There are many contructors and information functions
*/
ushort charFromCodepage(const char * c, int size, const char * codepage, int * taken = 0) {
if (!c || size <= 0) return 0;
if (uchar(c[0]) < 0x80) return c[0];
int ret;
#ifdef PIP_ICU
UErrorCode e((UErrorCode)0);
UConverter * cc = ucnv_open(codepage, &e);
if (cc) {
UChar uc(0);
e = (UErrorCode)0;
ret = ucnv_toUChars(cc, &uc, 1, c, size, &e);
//printf("PIChar %d -> %d\n", c[0], uc);
if (taken) *taken = ret;
ucnv_close(cc);
return ushort(uc);
}
#else
# ifdef WINDOWS
wchar_t buffer;
ret = MultiByteToWideChar((uint)(uintptr_t)codepage, MB_ERR_INVALID_CHARS, c, size, &buffer, 1);
if (ret <= 0) return 0;
if (taken) *taken = ret;
return buffer;
# else
wchar_t wc(0);
mbtowc(0, 0, 0); // reset mbtowc
ret = mbtowc(&wc, c, size);
//printf("mbtowc = %d\n", ret);
if (ret < 1) return 0;
return ushort(int(wc));
# endif
#endif
return ushort(c[0]);
}
int charCompare(const PIChar & f, const PIChar & s) {
if (f.isAscii() && s.isAscii())
return strncmp(f.toCharPtr(), s.toCharPtr(), 1);
return
#ifdef PIP_ICU
u_strCompare((const UChar*)f.toWCharPtr(), 1, (const UChar*)s.toWCharPtr(), 1, FALSE);
#else
# ifdef WINDOWS
CompareStringW(LOCALE_USER_DEFAULT, 0, (PCNZWCH)f.toWCharPtr(), 1, (PCNZWCH)s.toWCharPtr(), 1) - 2;
# else
wcsncmp((const wchar_t *)f.toWCharPtr(), (const wchar_t *)s.toWCharPtr(), 1);
# endif
#endif
}
bool winIsCharType(const ushort * ch, int type) {
#ifdef WINDOWS
WORD attr = 0;
if (GetStringTypeW(CT_CTYPE1, (LPCWCH)ch, 1, &attr) == 0) return false;
return ((attr & type) == type);
#endif
return false;
}
PIChar::PIChar(const char * c, int * bytes) {
ch = charFromCodepage(c, 4, __syslocname__, bytes);
}
PIChar PIChar::fromConsole(char c) {
PIChar ret;
ret.ch = charFromCodepage(&c, 1, __sysoemname__);
return ret;
}
PIChar PIChar::fromSystem(char c) {
PIChar ret;
ret.ch = charFromCodepage(&c, 1, __syslocname__);
return ret;
}
PIChar PIChar::fromUTF8(const char * c) {
PIChar ret;
int l = 0;
while (c[l] != '\0') ++l;
ret.ch = charFromCodepage(c, l, __utf8name__);
return ret;
}
bool PIChar::operator ==(const PIChar & o) const {
return ch == o.ch;
}
bool PIChar::operator >(const PIChar & o) const {
return charCompare(*this, o) > 0;
}
bool PIChar::operator <(const PIChar & o) const {
return charCompare(*this, o) < 0;
}
bool PIChar::operator >=(const PIChar & o) const {
return charCompare(*this, o) >= 0;
}
bool PIChar::operator <=(const PIChar & o) const {
return charCompare(*this, o) <= 0;
}
bool PIChar::isDigit() const {
if (isAscii()) return isdigit(ch) != 0;
#ifdef WINDOWS
return winIsCharType(&ch, C1_DIGIT);
#else
return iswdigit(ch) != 0;
#endif
}
bool PIChar::isHex() const {
if (isAscii()) return isxdigit(ch) != 0;
#ifdef WINDOWS
return winIsCharType(&ch, C1_XDIGIT);
#else
return iswxdigit(ch) != 0;
#endif
}
bool PIChar::isGraphical() const {
if (isAscii()) return isgraph(ch) != 0;
#ifdef WINDOWS
return !winIsCharType(&ch, C1_CNTRL);
#else
return iswgraph(ch) != 0;
#endif
}
bool PIChar::isControl() const {
if (isAscii()) return iscntrl(ch) != 0;
#ifdef WINDOWS
return winIsCharType(&ch, C1_CNTRL);
#else
return iswcntrl(ch) != 0;
#endif
}
bool PIChar::isLower() const {
if (isAscii()) return islower(ch) != 0;
#ifdef WINDOWS
return winIsCharType(&ch, C1_LOWER);
#else
return iswlower(ch) != 0;
#endif
}
bool PIChar::isUpper() const {
if (isAscii()) return isupper(ch) != 0;
#ifdef WINDOWS
return winIsCharType(&ch, C1_UPPER);
#else
return iswupper(ch) != 0;
#endif
}
bool PIChar::isPrint() const {
if (isAscii()) return isprint(ch) != 0;
#ifdef WINDOWS
return !winIsCharType(&ch, C1_CNTRL);
#else
return iswprint(ch) != 0;
#endif
}
bool PIChar::isSpace() const {
if (isAscii()) return isspace(ch) != 0;
#ifdef WINDOWS
return winIsCharType(&ch, C1_SPACE);
#else
return iswspace(ch) != 0;
#endif
}
bool PIChar::isAlpha() const {
if (isAscii()) return isalpha(ch) != 0;
#ifdef WINDOWS
return winIsCharType(&ch, C1_ALPHA);
#else
return iswalpha(ch) != 0;
#endif
}
bool PIChar::isAscii() const {
return isascii(ch) != 0;
}
const wchar_t * PIChar::toWCharPtr() const {
return reinterpret_cast<const wchar_t * >(&ch);
}
const char * PIChar::toCharPtr() const {
return reinterpret_cast<const char * >(&ch);
}
wchar_t PIChar::toWChar() const {
return wchar_t(ch);
}
char PIChar::toConsole1Byte() const {
if (ch < 0x80) return ch;
#ifdef PIP_ICU
UErrorCode e((UErrorCode)0);
UConverter * cc = ucnv_open(__sysoemname__, &e);
if (cc) {
char uc[8];
e = (UErrorCode)0;
ucnv_fromUChars(cc, uc, 8, (const UChar*)(&ch), 1, &e);
ucnv_close(cc);
return uc[0];
}
#endif
#ifdef WINDOWS
char ret[4] = {0,0,0,0};
WideCharToMultiByte(CP_OEMCP, 0, (LPCWCH)&ch, 1, ret, 4, NULL, NULL);
return ret[0];
#endif
return toAscii();
}
char PIChar::toSystem() const {
if (ch < 0x80) return ch;
#ifdef PIP_ICU
UErrorCode e((UErrorCode)0);
UConverter * cc = ucnv_open(__syslocname__, &e);
if (cc) {
char uc[8];
e = (UErrorCode)0;
ucnv_fromUChars(cc, uc, 8, (const UChar*)(&ch), 1, &e);
ucnv_close(cc);
return uc[0];
}
#endif
#ifdef WINDOWS
char ret[4] = {0,0,0,0};
WideCharToMultiByte(CP_ACP, 0, (LPCWCH)&ch, 1, ret, 4, NULL, NULL);
return ret[0];
#endif
return toAscii();
}
PIChar PIChar::toUpper() const {
if (isAscii()) return PIChar(toupper(ch));
#ifdef PIP_ICU
UChar c(0);
UErrorCode e((UErrorCode)0);
u_strToUpper(&c, 1, (const UChar*)(&ch), 1, 0, &e);
return PIChar(c);
#else
# ifdef WINDOWS
ushort wc = 0;
if (LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE, (LPCWSTR)&ch, 1, (LPWSTR)&wc, 1) == 1)
return PIChar(wc);
# endif
#endif
return PIChar(towupper(ch));
}
PIChar PIChar::toLower() const {
if (isAscii()) return PIChar(tolower(ch));
#ifdef PIP_ICU
UChar c(0);
UErrorCode e((UErrorCode)0);
u_strToLower(&c, 1, (const UChar*)(&ch), 1, 0, &e);
return PIChar(c);
#else
# ifdef WINDOWS
ushort wc = 0;
if (LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE, (LPCWSTR)&ch, 1, (LPWSTR)&wc, 1) == 1)
return PIChar(wc);
# endif
#endif
return PIChar(towlower(ch));
}
PICout operator <<(PICout s, const PIChar & v) {
s.space();
s.setControl(0, true);
if (v.isAscii()) s << char(v.ch);
else {
#ifdef PIP_ICU
UErrorCode e((UErrorCode)0);
UConverter * cc = ucnv_open(__syslocname__, &e);
if (cc) {
char uc[8];
memset(uc, 0, 8);
e = (UErrorCode)0;
ucnv_fromUChars(cc, uc, 8, (const UChar*)(&v.ch), 1, &e);
ucnv_close(cc);
s << uc;
} else
#endif
#ifdef WINDOWS
s << v.toSystem();
#else
{
char tc[8];
wctomb(0, 0);
int sz = wctomb(tc, v.ch);
for (int b = 0; b < sz; ++b)
s << tc[b];
}
#endif
}
s.restoreControl();
return s;
}

187
lib/main/core/pichar.h Normal file
View File

@@ -0,0 +1,187 @@
/*! \file pichar.h
* \brief Unicode char
*/
/*
PIP - Platform Independent Primitives
Unicode char
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PICHAR_H
#define PICHAR_H
#include "piincludes.h"
extern char * __syslocname__;
extern char * __sysoemname__;
extern char * __utf8name__;
class PIP_EXPORT PIChar
{
friend class PIString;
friend PIByteArray & operator <<(PIByteArray & s, const PIChar & v);
friend PIByteArray & operator >>(PIByteArray & s, PIChar & v);
friend PICout operator <<(PICout s, const PIChar & v);
public:
//! Contructs ascii symbol
PIChar(const char c) {ch = c; ch &= 0xFF;}
//! Contructs 2-bytes symbol
PIChar(const short c) {ch = c;}
//! Contructs 4-bytes symbol
PIChar(const int c) {ch = c;}
//! Contructs ascii symbol
PIChar(const uchar c) {ch = c; ch &= 0xFF;}
//! Contructs 2-bytes symbol
PIChar(const ushort c) {ch = c;}
//! Default constructor. Contructs 4-bytes symbol
PIChar(const uint c = 0) {ch = c;}
//! Contructs symbol from no more than 4 bytes of string
PIChar(const char * c, int * bytes = 0);
//! Copy operator
PIChar & operator =(const char v) {ch = v; return *this;}
//! Compare operator
bool operator ==(const PIChar & o) const;
//! Compare operator
bool operator !=(const PIChar & o) const {return !(o == *this);}
//! Compare operator
bool operator >(const PIChar & o) const;
//! Compare operator
bool operator <(const PIChar & o) const;
//! Compare operator
bool operator >=(const PIChar & o) const;
//! Compare operator
bool operator <=(const PIChar & o) const;
//! Return \b true if symbol is digit ('0' to '9')
bool isDigit() const;
//! Return \b true if symbol is HEX digit ('0' to '9', 'a' to 'f', 'A' to 'F')
bool isHex() const;
//! Return \b true if symbol is drawable (without space)
bool isGraphical() const;
//! Return \b true if symbol is control byte (< 32 or 127)
bool isControl() const;
//! Return \b true if symbol is in lower case
bool isLower() const;
//! Return \b true if symbol is in upper case
bool isUpper() const;
//! Return \b true if symbol is printable (with space)
bool isPrint() const;
//! Return \b true if symbol is space or tab
bool isSpace() const;
//! Return \b true if symbol is alphabetical letter
bool isAlpha() const;
//! Return \b true if symbol is ascii (< 128)
bool isAscii() const;
const wchar_t * toWCharPtr() const;
//! Return as <tt>"char * "</tt> string
const char * toCharPtr() const;
wchar_t toWChar() const;
char toAscii() const {return ch % 256;}
char toConsole1Byte() const;
char toSystem() const;
ushort unicode16Code() const {return ch;}
//! Return symbol in upper case
PIChar toUpper() const;
//! Return symbol in lower case
PIChar toLower() const;
static PIChar fromConsole(char c);
static PIChar fromSystem(char c);
static PIChar fromUTF8(const char * c);
private:
ushort ch;
};
//! Output operator to \a PICout
PICout operator <<(PICout s, const PIChar & v);
//! Compare operator
inline bool operator ==(const char v, const PIChar & c) {return (PIChar(v) == c);}
//! Compare operator
inline bool operator >(const char v, const PIChar & c) {return (PIChar(v) > c);}
//! Compare operator
inline bool operator <(const char v, const PIChar & c) {return (PIChar(v) < c);}
//! Compare operator
inline bool operator >=(const char v, const PIChar & c) {return (PIChar(v) >= c);}
//! Compare operator
inline bool operator <=(const char v, const PIChar & c) {return (PIChar(v) <= c);}
//! Compare operator
inline bool operator ==(const char * v, const PIChar & c) {return (PIChar(v) == c);}
//! Compare operator
inline bool operator >(const char * v, const PIChar & c) {return (PIChar(v) > c);}
//! Compare operator
inline bool operator <(const char * v, const PIChar & c) {return (PIChar(v) < c);}
//! Compare operator
inline bool operator >=(const char * v, const PIChar & c) {return (PIChar(v) >= c);}
//! Compare operator
inline bool operator <=(const char * v, const PIChar & c) {return (PIChar(v) <= c);}
//! Compare operator
inline bool operator ==(const int v, const PIChar & c) {return (PIChar(v) == c);}
//! Compare operator
inline bool operator >(const int v, const PIChar & c) {return (PIChar(v) > c);}
//! Compare operator
inline bool operator <(const int v, const PIChar & c) {return (PIChar(v) < c);}
//! Compare operator
inline bool operator >=(const int v, const PIChar & c) {return (PIChar(v) >= c);}
//! Compare operator
inline bool operator <=(const int v, const PIChar & c) {return (PIChar(v) <= c);}
#endif // PICHAR_H

View File

@@ -0,0 +1,148 @@
/*
PIP - Platform Independent Primitives
Binary markup serializator
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "pichunkstream.h"
/*! \class PIChunkStream
* \brief Class for binary serialization
*
* \section PIChunkStream_sec0 Synopsis
* This class provides very handly mechanism to store and restore values to and from
* \a PIByteArray. The main advantage of using this class is that your binary data
* become independent from order and collection of your values.
*
* \section PIChunkStream_sec1 Mechanism
* %PIChunkStream works with items called "chunk". Chunk is an ID and any value that
* can be stored and restored to \a PIByteArray with stream operators << and >>.
* You can place chunks to stream and read chunks from stream.
*
* To construct %PIChunkStream for writing data use any constructor. Empty constructor
* creates internal empty buffer that can be accessed by function \a data().
* Non-empty constructor works with given byte array.
*
* To read chunks from byte array use function \a read() that returns ID of
* next chunk. Then you can get value of this chunk with function \a getData(),
* but you should definitely know type of this value. You can read from byte array
* while \a atEnd() if false.
*
* \section PIChunkStream_ex0 Example
* Prepare your structs to work with %PIChunkStream
* \snippet pichunkstream.cpp struct
* Writing to %PIChunkStream
* \snippet pichunkstream.cpp write
* Reading from %PIChunkStream
* \snippet pichunkstream.cpp read
*/
void PIChunkStream::setSource(const PIByteArray & data) {
data_ = const_cast<PIByteArray*>(&data);
_init();
}
void PIChunkStream::setSource(PIByteArray * data) {
data_ = (data ? data : &tmp_data);
_init();
}
int PIChunkStream::read() {
switch (version_) {
case Version_1:
(*data_) >> last_id >> last_data;
break;
case Version_2:
last_id = readVInt(*data_);
last_data.resize(readVInt(*data_));
//piCout << last_id << last_data.size();
(*data_) >> PIByteArray::RawData(last_data.data(), last_data.size_s());
break;
default: break;
}
return last_id;
}
void PIChunkStream::readAll() {
data_map.clear();
while (!atEnd()) {
read();
data_map[last_id] = last_data;
}
}
PIChunkStream::~PIChunkStream() {
}
void PIChunkStream::_init() {
last_id = -1;
last_data.clear();
if (!data_->isEmpty()) {
uchar v = data_->at(0);
if ((v & 0x80) == 0x80) {
v &= 0x7f;
switch (v) {
case 2: version_ = (uchar)Version_2; data_->pop_front(); break;
default: version_ = Version_1; break;
}
} else
version_ = Version_1;
}
}
uint PIChunkStream::readVInt(PIByteArray & s) {
if (s.isEmpty()) return 0;
uchar bytes[4]; s >> bytes[0];
uchar abc = 0;
for (abc = 0; abc < 3; ++abc) {
uchar mask = (0x80 >> abc);
if ((bytes[0] & mask) == mask) {
bytes[0] &= (mask - 1);
s >> bytes[abc + 1];
} else break;
}
uint ret = 0;
for (int i = 0; i <= abc; ++i) {
ret += (bytes[i] << (8 * ((int)abc - i)));
}
return ret;
}
void PIChunkStream::writeVInt(PIByteArray & s, uint val) {
if (val > 0xfffffff) return;
if (val <= 0x7f) {
s << uchar(val);
return;
}
if (val <= 0x3fff) {
s << uchar((val >> 8) | 0x80) << uchar(val & 0xff);
return;
}
if (val <= 0x1fffff) {
s << uchar((val >> 16) | 0xc0) << uchar((val >> 8) & 0xff) << uchar(val & 0xff);
return;
}
s << uchar((val >> 24) | 0xe0) << uchar((val >> 16) & 0xff) << uchar((val >> 8) & 0xff) << uchar(val & 0xff);
}

View File

@@ -0,0 +1,137 @@
/*! \file pichunkstream.h
* \brief Binary markup serializator
*/
/*
PIP - Platform Independent Primitives
Binary markup serializator
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PICHUNKSTREAM_H
#define PICHUNKSTREAM_H
#include "pibytearray.h"
class PIP_EXPORT PIChunkStream
{
public:
//! Version of data packing. Read-access %PIChunkStream automatic detect version, but write-access
//! %PIChunkStream by default write in new version, be careful!
enum Version {
Version_1 /*! First, old version */,
Version_2 /*! Second, more optimized version */ = 2,
};
//! Contructs stream for read from "data"
PIChunkStream(const PIByteArray & data): version_(Version_2) {setSource(data);}
//! Contructs stream for read or write to/from "data", or empty stream for write
PIChunkStream(PIByteArray * data = 0, Version v = Version_2): version_(v) {setSource(data);}
//! Contructs empty stream for write with version \"v\"
PIChunkStream(Version v): version_(v) {setSource(0);}
~PIChunkStream();
template <typename T>
struct Chunk {
Chunk(int i, const T & d): id(i), data(d) {}
int id;
T data;
};
//! Returns chunk with ID "id" and value "data" for write to stream
template <typename T> static Chunk<T> chunk(int id, const T & data) {return Chunk<T>(id, data);}
//! Add data to this chunk strean with ID "id" and value "data"
template <typename T> PIChunkStream & add(int id, const T & data) {*this << Chunk<T>(id, data); return *this;}
void setSource(const PIByteArray & data);
void setSource(PIByteArray * data);
//! Returns internal buffer with written data
PIByteArray data() const {return tmp_data;}
//! Returns if there is end of stream
bool atEnd() const {return data_->size_s() <= 1;}
//! Returns stream version
Version version() const {return (Version)version_;}
//! Read one chunk from stream and returns its ID
int read();
//! Read all chunks from stream
void readAll();
//! Returns last readed chunk ID
int getID() {return last_id;}
//! Returns value of last readed chunk
template <typename T>
T getData() const {T ret; PIByteArray s(last_data); s >> ret; return ret;}
//! Place value of last readed chunk into \"v\"
template <typename T>
void get(T & v) const {v = getData<T>();}
//! Place value of chunk with id \"id\" into \"v\". You should call \a readAll() before using this function!
template <typename T>
const PIChunkStream & get(int id, T & v) const {
PIByteArray ba = data_map.value(id);
if (!ba.isEmpty())
ba >> v;
return *this;
}
private:
void _init();
static uint readVInt(PIByteArray & s);
static void writeVInt(PIByteArray & s, uint val);
int last_id;
uchar version_;
PIByteArray * data_, last_data, tmp_data;
PIMap<int, PIByteArray> data_map;
template <typename T> friend PIChunkStream & operator <<(PIChunkStream & s, const PIChunkStream::Chunk<T> & c);
};
template <typename T>
PIChunkStream & operator <<(PIChunkStream & s, const PIChunkStream::Chunk<T> & c) {
PIByteArray ba;
ba << c.data;
switch (s.version_) {
case PIChunkStream::Version_1:
(*(s.data_)) << c.id << ba;
break;
case PIChunkStream::Version_2:
if (s.data_->isEmpty())
(*(s.data_)) << uchar(uchar(s.version_) | 0x80);
PIChunkStream::writeVInt(*(s.data_), c.id);
PIChunkStream::writeVInt(*(s.data_), ba.size());
s.data_->append(ba);
break;
default: break;
}
return s;
}
#endif // PICHUNKSTREAM_H

101
lib/main/core/picli.cpp Normal file
View File

@@ -0,0 +1,101 @@
/*
PIP - Platform Independent Primitives
Command-Line Parser
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "picli.h"
#include "pisysteminfo.h"
/*! \class PICLI
* \brief Command-line arguments parser
*
* \section PICLI_sec0 Synopsis
* This class provide handy parsing of command-line arguments. First you should add
* arguments to PICLI with function \a addArgument(). Then you can check if there
* is some argument in application command-line with function \a hasArgument();
* \section PICLI_sec1 Example
* \snippet picli.cpp main
*/
PICLI::PICLI(int argc, char * argv[]) {
setName("CLI");
needParse = true;
_prefix_short = "-";
_prefix_full = "--";
_count_opt = 0;
_count_mand = 0;
for (int i = 0; i < argc; ++i)
_args_raw << argv[i];
if (argc > 0)
PISystemInfo::instance()->execCommand = argv[0];
}
void PICLI::parse() {
if (!needParse) return;
PIString cra, full;
Argument * last = 0;
for (int i = 1; i < _args_raw.size_s(); ++i) {
cra = _args_raw[i];
if (cra.left(2) == _prefix_full) {
last = 0;
full = cra.right(cra.length() - 2);
piForeach (Argument & a, _args) {
if (a.full_key == full) {
a.found = true;
last = &a;
break;
}
}
} else {
if (cra.left(1) == _prefix_short) {
last = 0;
for (int j = 1; j < cra.length(); ++j) {
bool found = false;
piForeach (Argument & a, _args) {
if ((a.short_key != '\0') && (a.short_key == cra[j])) {
a.found = true;
last = &a;
found = true;
break;
}
}
if (!found) break;
}
} else {
if (last == 0 ? true : !last->has_value) {
if (_args_mand.size_s() < _count_mand) {
_args_mand << cra;
continue;
}
if (_args_opt.size_s() < _count_opt || _count_opt < 0) {
_args_opt << cra;
continue;
}
piCoutObj << "[PICli] Arguments overflow, \"" << cra << "\" ignored";
}
if (last == 0 ? false : last->has_value) {
last->value = cra;
last = 0;
}
}
}
}
needParse = false;
}

101
lib/main/core/picli.h Normal file
View File

@@ -0,0 +1,101 @@
/*! \file picli.h
* \brief Command-Line parser
*/
/*
PIP - Platform Independent Primitives
Command-Line Parser
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PICLI_H
#define PICLI_H
#include "piobject.h"
class PIP_EXPORT PICLI: public PIObject
{
PIOBJECT_SUBCLASS(PICLI, PIObject)
public:
//! Constructor
PICLI(int argc, char * argv[]);
//! Add argument with name "name", short key = name first letter, full key = name
void addArgument(const PIString & name, bool value = false) {_args << Argument(name, name[0], name, value); needParse = true;}
//! Add argument with name "name", short key = "shortKey", full key = name
void addArgument(const PIString & name, const PIChar & shortKey, bool value = false) {_args << Argument(name, shortKey, name, value); needParse = true;}
//! Add argument with name "name", short key = "shortKey", full key = name
void addArgument(const PIString & name, const char * shortKey, bool value = false) {_args << Argument(name, PIChar(shortKey), name, value); needParse = true;}
//! Add argument with name "name", short key = "shortKey", full key = "fullKey"
void addArgument(const PIString & name, const PIChar & shortKey, const PIString & fullKey, bool value = false) {_args << Argument(name, shortKey, fullKey, value); needParse = true;}
//! Add argument with name "name", short key = "shortKey", full key = "fullKey"
void addArgument(const PIString & name, const char * shortKey, const PIString & fullKey, bool value = false) {_args << Argument(name, PIChar(shortKey), fullKey, value); needParse = true;}
//! Returns unparsed command-line argument by index "index". Index 0 is program execute command.
PIString rawArgument(int index) {parse(); return _args_raw[index];}
PIString mandatoryArgument(int index) {parse(); return _args_mand[index];}
PIString optionalArgument(int index) {parse(); return _args_opt[index];}
//! Returns unparsed command-line arguments
const PIStringList & rawArguments() {parse(); return _args_raw;}
const PIStringList & mandatoryArguments() {parse(); return _args_mand;}
const PIStringList & optionalArguments() {parse(); return _args_opt;}
//! Returns program execute command without arguments
PIString programCommand() {parse(); return _args_raw.size() > 0 ? _args_raw.front() : PIString();}
bool hasArgument(const PIString & name) {parse(); piForeach (Argument & i, _args) if (i.name == name && i.found) return true; return false;}
PIString argumentValue(const PIString & name) {parse(); piForeach (Argument &i, _args) if (i.name == name && i.found) return i.value; return PIString();}
PIString argumentShortKey(const PIString & name) {piForeach (Argument &i, _args) if (i.name == name) return i.short_key; return PIString();}
PIString argumentFullKey(const PIString & name) {piForeach (Argument &i, _args) if (i.name == name) return i.full_key; return PIString();}
const PIString & shortKeyPrefix() const {return _prefix_short;}
const PIString & fullKeyPrefix() const {return _prefix_full;}
int mandatoryArgumentsCount() const {return _count_mand;}
int optionalArgumentsCount() const {return _count_opt;}
void setShortKeyPrefix(const PIString & prefix) {_prefix_short = prefix; needParse = true;}
void setFullKeyPrefix(const PIString & prefix) {_prefix_full = prefix; needParse = true;}
void setMandatoryArgumentsCount(const int count) {_count_mand = count; needParse = true;}
void setOptionalArgumentsCount(const int count) {_count_opt = count; needParse = true;}
private:
struct Argument {
Argument() {has_value = found = false;}
Argument(const PIString & n, const PIChar & s, const PIString & f, bool v) {name = n; short_key = s; full_key = f; has_value = v; found = false;}
PIString name;
PIChar short_key;
PIString full_key;
PIString value;
bool has_value, found;
};
void parse();
PIString _prefix_short, _prefix_full;
PIStringList _args_raw, _args_mand, _args_opt;
PISet<PIString> keys_full, keys_short;
PIVector<Argument> _args;
int _count_mand, _count_opt;
bool needParse;
};
#endif // PICLI_H

View File

@@ -0,0 +1,84 @@
/*
PIP - Platform Independent Primitives
Peer - named I/O ethernet node, forming self-organized peering network
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "picollection.h"
/** \class PICollection
* \brief Interface to discover element groups
* \details
* \section PICollection_sec0 Synopsis
* This class has only static functions so no need to create instance of the
* %PICollection. This class provide macros to add some classes or existing
* objects to global collection and access to them from any place of the code.
* \snippet picollection.cpp main
* */
PIStringList PICollection::groups() {
PIStringList sl;
PIVector<PICollection::Group> & cg(_groups());
piForeachC (Group & g, cg)
sl << g.name;
return sl;
}
PIVector<const PIObject * > PICollection::groupElements(const PIString & group) {
PIVector<PICollection::Group> & cg(_groups());
piForeachC (Group & g, cg)
if (g.name == group)
return g.elements;
return PIVector<const PIObject * >();
}
bool PICollection::addToGroup(const PIString & group, const PIObject * element) {
//piCout << "add to" << group << element;
PIString n = PIStringAscii(element->className());
PIVector<PICollection::Group> & cg(_groups());
piForeach (Group & g, cg)
if (g.name == group) {
for (int i = 0; i < g.elements.size_s(); ++i)
if (PIString(g.elements[i]->className()) == n)
return false;
g.elements << element;
//piCout << "new group" << group << ", ok";
return true;
}
_groups() << Group(group);
_groups().back().elements << element;
//piCout << "new group" << group << ", ok";
return true;
}
PIVector<PICollection::Group> & PICollection::_groups() {
static PIVector<PICollection::Group> ret;
return ret;
}
PICollection::CollectionAdder::CollectionAdder(const PIString & group, const PIObject * element, const PIString & name, bool own) {
if (!element) return;
const_cast<PIObject * >(element)->setName(name);
bool added = PICollection::addToGroup(group, element);
if (!added && own)
delete element;
}

View File

@@ -0,0 +1,83 @@
/*! \file picollection.h
* \brief Custom elements collection
*/
/*
PIP - Platform Independent Primitives
Peer - named I/O ethernet node, forming self-organized peering network
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PICOLLECTION_H
#define PICOLLECTION_H
#include "piobject.h"
#ifdef DOXYGEN
/** \brief Add existing element "object" in group with name "group"
* \relatesalso PICollection
* \details If there is no group with name "group" it will be created.
* Only one element of the class "object" can be in group "group". If
* this is already exists nothing be happens. \n "object" should to
* be pointer to object based on PIObject. */
# define ADD_TO_COLLECTION(group, object)
/** \brief Add new element of class "class" in group with name "group"
* \relatesalso PICollection
* \details If there is no group with name "group" it will be created.
* Only one element of the class "class" can be in group "group". If
* this is already exists nothing be happens. \n "class" should to
* be name of the any class based on PIObject. */
# define ADD_NEW_TO_COLLECTION(group, class)
#else
# define ADD_TO_COLLECTION(group, object) static PICollection::CollectionAdder __##group##_##__LINE__##_##adder##__(#group, object, false);
# define ADD_TO_COLLECTION_WITH_NAME(group, object, name) static PICollection::CollectionAdder __##group##_##__LINE__##_##adder##__(#group, object, #name, false);
# define ADD_NEW_TO_COLLECTION(group, class) static PICollection::CollectionAdder __##group##_##class##_##adder##__(#group, new class(), true);
# define ADD_NEW_TO_COLLECTION_WITH_NAME(group, class, name) static PICollection::CollectionAdder __##group##_##class##_##adder##__(#group, new class(), #name, true);
#endif
class PIP_EXPORT PICollection
{
friend class __PICollectionInitializer;
public:
PICollection() {;}
//! \brief Returns all existing groups by their names
static PIStringList groups();
//! \brief Returns all elements of group "group"
static PIVector<const PIObject * > groupElements(const PIString & group);
static bool addToGroup(const PIString & group, const PIObject * element);
class CollectionAdder {
public:
CollectionAdder(const PIString & group, const PIObject * element, const PIString & name = PIString(), bool own = false);
};
protected:
struct Group {
Group(const PIString & name_ = PIString()) {name = name_;}
PIString name;
PIVector<const PIObject * > elements;
};
static PIVector<Group> & _groups();
};
#endif // PICOLLECTION_H

View File

@@ -0,0 +1,30 @@
/*
PIP - Platform Independent Primitives
Module includes
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PICOREMODULE_H
#define PICOREMODULE_H
#include "picollection.h"
#include "piobject.h"
#include "pitime.h"
#include "picli.h"
#include "pichunkstream.h"
#include "pipropertystorage.h"
#endif // PICOREMODULE_H

548
lib/main/core/picout.cpp Normal file
View File

@@ -0,0 +1,548 @@
/*
PIP - Platform Independent Primitives
Universal output to console class
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "piincludes_p.h"
#include "picout.h"
#include "piconsole.h"
#include "pibytearray.h"
#include "pistack.h"
#include "pistring_std.h"
#ifdef WINDOWS
# include <windows.h>
# include <wincon.h>
# define COMMON_LVB_UNDERSCORE 0x8000
#endif
/*! \class PICout
* \brief Class for formatted output similar std::cout
*
* \section PICout_sec0 Synopsis
* This class provide many stream operators for output with some features.
* Output to PICout is thread-sequential, i.e. doesn`t mixed from parallel
* threads.
*
* \section PICout_sec1 Features
* - insertion spaces between entries
* - insertion new line at the end of output
* - strings are quoted
* - custom output operator can be easily written
*
* \section PICout_ex0 Usage
* \snippet picout.cpp 0
*
* \section PICout_ex1 Writing your own output operator
* \snippet picout.cpp own
*/
/*! \class PICout::Notifier
* \brief Class for emit notifications of PICout
*
* \section PICout_sec0 Synopsis
* This class used as PICout events emitter. When
* PICout constructs with external PIString* buffer
* and some id, last copy of this PICout on delete
* emit event "finished()" on object Notifier::object().
* Sample:
* \snippet picout.cpp notifier
*/
class NotifierObject: public PIObject {
PIOBJECT(NotifierObject)
public:
NotifierObject() {}
EVENT2(finished, int, id, PIString*, buffer)
};
PICout::Notifier::Notifier() {
o = new NotifierObject();
}
PICout::Notifier * PICout::Notifier::instance() {
static PICout::Notifier * ret = new PICout::Notifier();
return ret;
}
PIObject * PICout::Notifier::object() {
return instance()->o;
}
using namespace PICoutManipulators;
PIMutex & PICout::__mutex__() {static PIMutex * ret = new PIMutex(); return *ret;}
PIString & PICout::__string__() {static PIString * ret = new PIString(); return *ret;}
PICout::OutputDevices PICout::devs = PICout::StdOut;
PRIVATE_DEFINITION_START(PICout)
PIStack<PICoutControls> cos_;
#ifdef WINDOWS
static void * hOut;
static WORD dattr;
static DWORD smode;
#endif
PRIVATE_DEFINITION_END(PICout)
#ifdef WINDOWS
void * PICout::__Private__::hOut = 0;
WORD PICout::__Private__::dattr = 0;
DWORD PICout::__Private__::smode = 0;
#endif
PICout::PICout(PIFlags<PICoutControl> controls): fo_(true), cc_(false), fc_(false), act_(true), cnb_(10), co_(controls) {
init();
}
PICout::PICout(PICoutControl control): fo_(true), cc_(false), fc_(false), act_(true), cnb_(10), co_(control) {
init();
}
PICout::PICout(bool active): fo_(true), cc_(false), fc_(false), act_(active), cnb_(10), co_(PICoutManipulators::DefaultControls) {
if (act_)
init();
}
PICout::PICout(PIString * buffer, int id, PIFlags<PICoutManipulators::PICoutControl> controls): fo_(true), cc_(false),
fc_(false), act_(true), cnb_(10), co_(controls) {
init();
buffer_ = buffer;
id_ = id;
}
PICout::PICout(const PICout & other): fo_(other.fo_), cc_(true), fc_(false), act_(other.act_), cnb_(other.cnb_), attr_(other.attr_),
id_(other.id_), buffer_(other.buffer_), co_(other.co_) {
}
PICout::~PICout() {
if (!act_) return;
if (fc_) applyFormat(PICoutManipulators::Default);
if (cc_) return;
newLine();
if ((co_ & NoLock) != NoLock)
PICout::__mutex__().unlock();
if (buffer_)
((NotifierObject*)Notifier::object())->finished(id_, buffer_);
}
PICout PICout::operator <<(const PICoutAction v) {
if (!act_) return *this;
#ifdef WINDOWS
CONSOLE_SCREEN_BUFFER_INFO sbi;
COORD coord;
CONSOLE_CURSOR_INFO curinfo;
#endif
switch (v) {
case PICoutManipulators::Flush:
if (!buffer_ && isOutputDeviceActive(StdOut))
std::cout << std::flush;
break;
case PICoutManipulators::Backspace:
if (isOutputDeviceActive(StdOut)) {
#ifdef WINDOWS
GetConsoleScreenBufferInfo(__Private__::hOut, &sbi);
coord = sbi.dwCursorPosition;
coord.X = piMax<int>(0, int(coord.X) - 1);
SetConsoleCursorPosition(__Private__::hOut, coord);
printf(" ");
SetConsoleCursorPosition(__Private__::hOut, coord);
#else
printf("\e[1D \e[1D");
#endif
}
break;
case PICoutManipulators::ShowCursor:
if (isOutputDeviceActive(StdOut)) {
#ifdef WINDOWS
GetConsoleCursorInfo(__Private__::hOut, &curinfo);
curinfo.bVisible = true;
SetConsoleCursorInfo(__Private__::hOut, &curinfo);
#else
printf("\e[?25h");
#endif
}
break;
case PICoutManipulators::HideCursor:
if (isOutputDeviceActive(StdOut)) {
#ifdef WINDOWS
GetConsoleCursorInfo(__Private__::hOut, &curinfo);
curinfo.bVisible = false;
SetConsoleCursorInfo(__Private__::hOut, &curinfo);
#else
printf("\e[?25l");
#endif
}
break;
case PICoutManipulators::ClearLine:
if (isOutputDeviceActive(StdOut)) {
#ifdef WINDOWS
GetConsoleScreenBufferInfo(__Private__::hOut, &sbi);
coord = sbi.dwCursorPosition;
int dx = coord.X;
coord.X = 0;
SetConsoleCursorPosition(__Private__::hOut, coord);
if (dx > 0) {
char * line = new char[dx + 1];
memset(line, ' ', dx);
line[dx] = 0;
printf("%s", line);
delete[] line;
}
SetConsoleCursorPosition(__Private__::hOut, coord);
#else
printf("\e[0G\e[K");
#endif
}
break;
case PICoutManipulators::ClearScreen:
if (isOutputDeviceActive(StdOut)) {
#ifdef WINDOWS
/// TODO : wondows ClearScreen !!!
#else
printf("\e[H\e[J");
#endif
}
break;
case PICoutManipulators::SaveContol: saveControl(); break;
case PICoutManipulators::RestoreControl: restoreControl(); break;
default: break;
};
return *this;
}
#define PICOUTTOTARGET(v) { \
if (buffer_) {\
(*buffer_) << (v);\
} else {\
if (PICout::isOutputDeviceActive(PICout::StdOut)) std::cout << (v);\
if (PICout::isOutputDeviceActive(PICout::Buffer)) PICout::__string__() << (v);\
}\
}
#define PICOUTTOTARGETS(v) { \
if (buffer_) {\
(*buffer_) << (v);\
} else {\
if (PICout::isOutputDeviceActive(PICout::StdOut)) std::cout << (v).dataConsole();\
if (PICout::isOutputDeviceActive(PICout::Buffer)) PICout::__string__() << (v);\
}\
}
#define PINUMERICCOUT if (cnb_ == 10) PICOUTTOTARGET(v) else PICOUTTOTARGETS(PIString::fromNumber(v, cnb_))
PICout PICout::operator <<(const char * v) {if (!act_) return *this; if (v[0] == '\0') return *this; space(); quote(); PICOUTTOTARGET(v) quote(); return *this;}
PICout PICout::operator <<(const bool v) {if (!act_) return *this; space(); if (v) PICOUTTOTARGET("true") else PICOUTTOTARGET("false") return *this;}
PICout PICout::operator <<(const char v) {if (!act_) return *this; space(); PICOUTTOTARGET(v) return *this;}
PICout PICout::operator <<(const uchar v) {if (!act_) return *this; space(); if (cnb_ == 10) PICOUTTOTARGET(ushort(v)) else PICOUTTOTARGETS(PIString::fromNumber(v, cnb_)) return *this;}
PICout PICout::operator <<(const short int v) {if (!act_) return *this; space(); PINUMERICCOUT return *this;}
PICout PICout::operator <<(const ushort v) {if (!act_) return *this; space(); PINUMERICCOUT return *this;}
PICout PICout::operator <<(const int v) {if (!act_) return *this; space(); PINUMERICCOUT return *this;}
PICout PICout::operator <<(const uint v) {if (!act_) return *this; space(); PINUMERICCOUT return *this;}
PICout PICout::operator <<(const long v) {if (!act_) return *this; space(); PINUMERICCOUT return *this;}
PICout PICout::operator <<(const ulong v) {if (!act_) return *this; space(); PINUMERICCOUT return *this;}
PICout PICout::operator <<(const llong v) {if (!act_) return *this; space(); PINUMERICCOUT return *this;}
PICout PICout::operator <<(const ullong v) {if (!act_) return *this; space(); PINUMERICCOUT return *this;}
PICout PICout::operator <<(const float v) {if (!act_) return *this; space(); PICOUTTOTARGET(v) return *this;}
PICout PICout::operator <<(const double v) {if (!act_) return *this; space(); PICOUTTOTARGET(v) return *this;}
PICout PICout::operator <<(const void * v) {if (!act_) return *this; space(); PICOUTTOTARGET("0x") PICOUTTOTARGETS(PIString::fromNumber(ullong(v), 16)) return *this;}
PICout PICout::operator <<(const PIObject * v) {
if (!act_) return *this;
space();
if (v == 0) PICOUTTOTARGET("PIObject*(0x0)")
else {
PICOUTTOTARGET(v->className())
PICOUTTOTARGET("*(0x")
PICOUTTOTARGETS(PIString::fromNumber(ullong(v), 16))
PICOUTTOTARGET(", \"")
PICOUTTOTARGET(v->name())
PICOUTTOTARGET("\")")
}
return *this;
}
PICout PICout::operator <<(const PICoutSpecialChar v) {
if (!act_) return *this;
switch (v) {
case Null:
if (buffer_) {
(*buffer_) << PIChar(0);
} else {
if (isOutputDeviceActive(StdOut)) std::cout << char(0);
if (isOutputDeviceActive(Buffer)) PICout::__string__() << PIChar(0);
}
break;
case NewLine:
if (buffer_) {
(*buffer_) << "\n";
} else {
if (isOutputDeviceActive(StdOut)) std::cout << '\n';
if (isOutputDeviceActive(Buffer)) PICout::__string__() << "\n";
}
fo_ = true;
break;
case Tab:
if (buffer_) {
(*buffer_) << "\t";
} else {
if (isOutputDeviceActive(StdOut)) std::cout << '\t';
if (isOutputDeviceActive(Buffer)) PICout::__string__() << "\t";
}
break;
case Esc:
#ifdef CC_VC
if (buffer_) {
(*buffer_) << PIChar(27);
} else {
if (isOutputDeviceActive(StdOut)) std::cout << char(27);
if (isOutputDeviceActive(Buffer)) PICout::__string__() << PIChar(27);
}
#else
if (buffer_) {
(*buffer_) << "\e";
} else {
if (isOutputDeviceActive(StdOut)) std::cout << '\e';
if (isOutputDeviceActive(Buffer)) PICout::__string__() << "\e";
}
#endif
break;
case Quote:
if (buffer_) {
(*buffer_) << "\"";
} else {
if (isOutputDeviceActive(StdOut)) std::cout << '"';
if (isOutputDeviceActive(Buffer)) PICout::__string__() << "\"";
}
break;
};
return *this;
}
PICout & PICout::saveControl() {
if (!act_) return *this;
PRIVATE->cos_.push(co_);
return *this;
}
PICout & PICout::restoreControl() {
if (!act_) return *this;
if (!PRIVATE->cos_.isEmpty()) {
co_ = PRIVATE->cos_.top();
PRIVATE->cos_.pop();
}
return *this;
}
#undef PICOUTTOTARGET
#undef PINUMERICCOUT
PICout & PICout::space() {
if (!act_) return *this;
if (!fo_ && co_[AddSpaces]) {
if (buffer_) {
(*buffer_) << " ";
} else {
if (isOutputDeviceActive(StdOut)) std::cout << ' ';
if (isOutputDeviceActive(Buffer)) PICout::__string__() << " ";
}
}
fo_ = false;
return *this;
}
PICout & PICout::quote() {
if (!act_) return *this;
if (co_[AddQuotes]) {
if (buffer_) {
(*buffer_) << "\"";
} else {
if (isOutputDeviceActive(StdOut)) std::cout << '"';
if (isOutputDeviceActive(Buffer)) PICout::__string__() << "\"";
}
}
fo_ = false;
return *this;
}
PICout & PICout::newLine() {
if (!act_) return *this;
if (co_[AddNewLine]) {
if (buffer_) {
(*buffer_) << "\n";
} else {
if (isOutputDeviceActive(StdOut)) std::cout << std::endl;
if (isOutputDeviceActive(Buffer)) PICout::__string__() << "\n";
}
}
fo_ = false;
return *this;
}
void PICout::init() {
#ifdef WINDOWS
if (__Private__::hOut == 0) {
__Private__::hOut = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO sbi;
GetConsoleScreenBufferInfo(__Private__::hOut, &sbi);
__Private__::dattr = sbi.wAttributes;
}
attr_ = __Private__::dattr;
#endif
buffer_ = 0;
id_ = 0;
if ((co_ & NoLock) != NoLock)
PICout::__mutex__().lock();
}
void PICout::applyFormat(PICoutFormat f) {
if (!act_) return;
if (buffer_ || !isOutputDeviceActive(StdOut)) return;
fc_ = true;
#ifdef WINDOWS
static int mask_fore = ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
static int mask_back = ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE);
switch (f) {
case Bin: case Oct: case Dec: case Hex: break;
case PICoutManipulators::Bold: attr_ |= FOREGROUND_INTENSITY; break;
case PICoutManipulators::Underline: attr_ |= COMMON_LVB_UNDERSCORE; break;
case PICoutManipulators::Black: attr_ = (attr_ & mask_fore); break;
case PICoutManipulators::Red: attr_ = (attr_ & mask_fore) | FOREGROUND_RED; break;
case PICoutManipulators::Green: attr_ = (attr_ & mask_fore) | FOREGROUND_GREEN; break;
case PICoutManipulators::Blue: attr_ = (attr_ & mask_fore) | FOREGROUND_BLUE; break;
case PICoutManipulators::Yellow: attr_ = (attr_ & mask_fore) | FOREGROUND_RED | FOREGROUND_GREEN; break;
case PICoutManipulators::Magenta: attr_ = (attr_ & mask_fore) | FOREGROUND_RED | FOREGROUND_BLUE; break;
case PICoutManipulators::Cyan: attr_ = (attr_ & mask_fore) | FOREGROUND_GREEN | FOREGROUND_BLUE; break;
case PICoutManipulators::White: attr_ = (attr_ & mask_fore) | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; break;
case PICoutManipulators::BackBlack: attr_ = (attr_ & mask_back); break;
case PICoutManipulators::BackRed: attr_ = (attr_ & mask_back) | BACKGROUND_RED; break;
case PICoutManipulators::BackGreen: attr_ = (attr_ & mask_back) | BACKGROUND_GREEN; break;
case PICoutManipulators::BackBlue: attr_ = (attr_ & mask_back) | BACKGROUND_BLUE; break;
case PICoutManipulators::BackYellow: attr_ = (attr_ & mask_back) | BACKGROUND_RED | BACKGROUND_GREEN; break;
case PICoutManipulators::BackMagenta: attr_ = (attr_ & mask_back) | BACKGROUND_RED | BACKGROUND_BLUE; break;
case PICoutManipulators::BackCyan: attr_ = (attr_ & mask_back) | BACKGROUND_GREEN | BACKGROUND_BLUE; break;
case PICoutManipulators::BackWhite: attr_ = (attr_ & mask_back) | BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE; break;
case PICoutManipulators::Default: attr_ = __Private__::dattr; break;
default: break;
}
SetConsoleTextAttribute(__Private__::hOut, attr_);
#else
switch (f) {
case Bin: case Oct: case Dec: case Hex: break;
case PICoutManipulators::Bold: printf("\e[1m"); break;
case PICoutManipulators::Faint: printf("\e[2m"); break;
case PICoutManipulators::Italic: printf("\e[3m"); break;
case PICoutManipulators::Underline: printf("\e[4m"); break;
case PICoutManipulators::Blink: printf("\e[5m"); break;
case PICoutManipulators::Black: printf("\e[30m"); break;
case PICoutManipulators::Red: printf("\e[31m"); break;
case PICoutManipulators::Green: printf("\e[32m"); break;
case PICoutManipulators::Blue: printf("\e[34m"); break;
case PICoutManipulators::Yellow: printf("\e[33m"); break;
case PICoutManipulators::Magenta: printf("\e[35m"); break;
case PICoutManipulators::Cyan: printf("\e[36m"); break;
case PICoutManipulators::White: printf("\e[37m"); break;
case PICoutManipulators::BackBlack: printf("\e[40m"); break;
case PICoutManipulators::BackRed: printf("\e[41m"); break;
case PICoutManipulators::BackGreen: printf("\e[42m"); break;
case PICoutManipulators::BackBlue: printf("\e[44m"); break;
case PICoutManipulators::BackYellow: printf("\e[43m"); break;
case PICoutManipulators::BackMagenta: printf("\e[45m"); break;
case PICoutManipulators::BackCyan: printf("\e[46m"); break;
case PICoutManipulators::BackWhite: printf("\e[47m"); break;
case PICoutManipulators::Default: printf("\e[0m"); break;
default: break;
}
#endif
}
bool PICout::setBufferActive(bool on, bool clear) {
PIMutexLocker ml(PICout::__mutex__());
bool ret = isBufferActive();
if (clear) PICout::__string__().clear();
setOutputDevice(Buffer, on);
return ret;
}
bool PICout::isBufferActive() {
return isOutputDeviceActive(Buffer);
}
PIString PICout::buffer(bool clear) {
PIMutexLocker ml(PICout::__mutex__());
PIString ret = PICout::__string__();
if (clear) PICout::__string__().clear();
return ret;
}
void PICout::clearBuffer() {
PIMutexLocker ml(PICout::__mutex__());
PICout::__string__().clear();
}
bool PICout::setOutputDevice(PICout::OutputDevice d, bool on) {
bool ret = devs[d];
devs.setFlag(d, on);
return ret;
}
void PICout::setOutputDevices(PICout::OutputDevices d) {
devs = d;
}
bool PICout::isOutputDeviceActive(PICout::OutputDevice d) {
return devs[d];
}

301
lib/main/core/picout.h Normal file
View File

@@ -0,0 +1,301 @@
/*! \file picout.h
* \brief Universal output to console class
*/
/*
PIP - Platform Independent Primitives
Universal output to console class
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PICOUT_H
#define PICOUT_H
#include "piincludes.h"
#ifdef DOXYGEN
//! \brief Macro used for conditional (piDebug) output to PICout
# define piCout
//! \relatesalso PIObject \brief Macro used for conditional (piDebug and PIObject::debug()) output to PICout for subclasses of PIObject
# define piCoutObj
#else
# define piCout PICout(piDebug)
# define piCoutObj PICout(piDebug && debug()) << (PIStringAscii("[") + className() + PIStringAscii(" \"") + name() + PIStringAscii("\"]"))
#endif
class PIObject;
//! \brief Namespace contains enums controlled PICout
namespace PICoutManipulators {
//! \brief Enum contains special characters
enum PIP_EXPORT PICoutSpecialChar {
Null /*! Null-character, '\\0' */,
NewLine /*! New line character, '\\n' */,
Tab /*! Tab character, '\\t' */,
Esc /*! Escape character, '\\e' */,
Quote /*! Quote character, '"' */
};
//! \brief Enum contains immediate action
enum PIP_EXPORT PICoutAction {
Flush /*! Flush the output */,
Backspace /*! Remove last symbol */,
ShowCursor /*! Show cursor */,
HideCursor /*! Hide cursor */,
ClearLine /*! Clear current line */,
ClearScreen /*! Clear the screen */,
SaveContol /*! Save control flags, equivalent to \a saveControl() */,
RestoreControl /*! Restore control flags, equivalent to \a restoreControl() */
};
//! \brief Enum contains control of PICout
enum PIP_EXPORT PICoutControl {
AddNone /*! No controls */ = 0x0,
AddSpaces /*! Spaces will be appear after each output */ = 0x1,
AddNewLine /*! New line will be appear after all output */ = 0x2,
AddQuotes /*! Each string will be quoted */ = 0x4,
DefaultControls /*! Default controls */ = AddSpaces | AddNewLine,
AddAll /*! All controls */ = 0xFF,
NoLock /*! Don`t use mutex for output */ = 0x100,
};
//! \brief Enum contains output format
enum PIP_EXPORT PICoutFormat {
Bin /*! Binary representation of integers */ = 0x01,
Oct /*! Octal representation of integers */ = 0x02,
Dec /*! Decimal representation of integers */ = 0x04,
Hex /*! Hexadecimal representation of integers */ = 0x08,
Bold /*! Bold */ = 0x10,
Faint /*! */ = 0x20,
Italic /*! */ = 0x40,
Underline /*! Underline */ = 0x80,
Blink /*! Blink */ = 0x100,
Black /*! Black font */ = 0x400,
Red /*! Red font */ = 0x800,
Green /*! Green font */ = 0x1000,
Blue /*! Blue font */ = 0x2000,
Yellow /*! Yellow font */ = 0x4000,
Magenta /*! Magenta font */ = 0x8000,
Cyan /*! Cyan font */ = 0x10000,
White /*! White font */ = 0x20000,
BackBlack /*! Black background */ = 0x40000,
BackRed /*! Red background */ = 0x80000,
BackGreen /*! Green background */ = 0x100000,
BackBlue /*! Blue background */ = 0x200000,
BackYellow /*! Yellow background */ = 0x400000,
BackMagenta /*! Magenta background */ = 0x800000,
BackCyan /*! Cyan background */ = 0x1000000,
BackWhite /*! White background */ = 0x2000000,
Default /*! Default format */ = 0x4000000
};
typedef PIFlags<PICoutControl> PICoutControls;
}
class PIP_EXPORT PICout {
public:
//! Default constructor with default features (AddSpaces and AddNewLine)
PICout(PIFlags<PICoutManipulators::PICoutControl> controls = PICoutManipulators::DefaultControls);
PICout(PICoutManipulators::PICoutControl control = PICoutManipulators::DefaultControls);
//! Construct with default features (AddSpaces and AddNewLine), but if \"active\" is false does nothing
PICout(bool active);
//! Construct with external buffer and id "id". See \a Notifier for details
PICout(PIString * buffer, int id = 0, PIFlags<PICoutManipulators::PICoutControl> controls = PICoutManipulators::AddSpaces | PICoutManipulators::AddNewLine);
PICout(const PICout & other);
~PICout();
class Notifier {
public:
static Notifier * instance();
static PIObject * object();
private:
Notifier();
PIObject * o;
};
//! \brief Enum contains output devices of PICout
enum OutputDevice {
NoDevices /** PICout is disabled */ = 0x0,
StdOut /** Standard console output */ = 0x1,
Buffer /** Internal buffer */ = 0x2,
AllDevices /** All */ = 0xFFFF,
};
typedef PIFlags<OutputDevice> OutputDevices;
//! Output operator for strings with <tt>"const char * "</tt> type
PICout operator <<(const char * v);
//! Output operator for strings with <tt>"std::string"</tt> type
//PICout operator <<(const std::string & v);
//! Output operator for boolean values
PICout operator <<(const bool v);
//! Output operator for <tt>"char"</tt> values
PICout operator <<(const char v);
//! Output operator for <tt>"unsigned char"</tt> values
PICout operator <<(const uchar v);
//! Output operator for <tt>"short"</tt> values
PICout operator <<(const short v);
//! Output operator for <tt>"unsigned short"</tt> values
PICout operator <<(const ushort v);
//! Output operator for <tt>"int"</tt> values
PICout operator <<(const int v);
//! Output operator for <tt>"unsigned int"</tt> values
PICout operator <<(const uint v);
//! Output operator for <tt>"long"</tt> values
PICout operator <<(const long v);
//! Output operator for <tt>"unsigned long"</tt> values
PICout operator <<(const ulong v);
//! Output operator for <tt>"long long"</tt> values
PICout operator <<(const llong v);
//! Output operator for <tt>"unsigned long long"</tt> values
PICout operator <<(const ullong v);
//! Output operator for <tt>"float"</tt> values
PICout operator <<(const float v);
//! Output operator for <tt>"double"</tt> values
PICout operator <<(const double v);
//! Output operator for pointers
PICout operator <<(const void * v);
//! Output operator for PIObject and ancestors
PICout operator <<(const PIObject * v);
//! Output operator for \a PICoutSpecialChar values
PICout operator <<(const PICoutManipulators::PICoutSpecialChar v);
//! Output operator for \a PIFlags<PICoutFormat> values
PICout operator <<(const PIFlags<PICoutManipulators::PICoutFormat> & v) {
if (v[PICoutManipulators::Bin]) cnb_ = 2;
if (v[PICoutManipulators::Oct]) cnb_ = 8;
if (v[PICoutManipulators::Dec]) cnb_ = 10;
if (v[PICoutManipulators::Hex]) cnb_ = 16;
if (v[PICoutManipulators::Bold]) applyFormat(PICoutManipulators::Bold);
if (v[PICoutManipulators::Faint]) applyFormat(PICoutManipulators::Faint);
if (v[PICoutManipulators::Italic]) applyFormat(PICoutManipulators::Italic);
if (v[PICoutManipulators::Underline]) applyFormat(PICoutManipulators::Underline);
if (v[PICoutManipulators::Blink]) applyFormat(PICoutManipulators::Blink);
if (v[PICoutManipulators::Black]) applyFormat(PICoutManipulators::Black);
if (v[PICoutManipulators::Red]) applyFormat(PICoutManipulators::Red);
if (v[PICoutManipulators::Green]) applyFormat(PICoutManipulators::Green);
if (v[PICoutManipulators::Blue]) applyFormat(PICoutManipulators::Blue);
if (v[PICoutManipulators::Yellow]) applyFormat(PICoutManipulators::Yellow);
if (v[PICoutManipulators::Magenta]) applyFormat(PICoutManipulators::Magenta);
if (v[PICoutManipulators::Cyan]) applyFormat(PICoutManipulators::Cyan);
if (v[PICoutManipulators::White]) applyFormat(PICoutManipulators::White);
if (v[PICoutManipulators::BackBlack]) applyFormat(PICoutManipulators::BackBlack);
if (v[PICoutManipulators::BackRed]) applyFormat(PICoutManipulators::BackRed);
if (v[PICoutManipulators::BackGreen]) applyFormat(PICoutManipulators::BackGreen);
if (v[PICoutManipulators::BackBlue]) applyFormat(PICoutManipulators::BackBlue);
if (v[PICoutManipulators::BackYellow]) applyFormat(PICoutManipulators::BackYellow);
if (v[PICoutManipulators::BackMagenta]) applyFormat(PICoutManipulators::BackMagenta);
if (v[PICoutManipulators::BackCyan]) applyFormat(PICoutManipulators::BackCyan);
if (v[PICoutManipulators::BackWhite]) applyFormat(PICoutManipulators::BackWhite);
if (v[PICoutManipulators::Default]) applyFormat(PICoutManipulators::Default);
return *this;
}
//! Output operator for \a PICoutFormat values
PICout operator <<(const PICoutManipulators::PICoutFormat v) {
switch (v) {
case PICoutManipulators::Bin: cnb_ = 2; break;
case PICoutManipulators::Oct: cnb_ = 8; break;
case PICoutManipulators::Dec: cnb_ = 10; break;
case PICoutManipulators::Hex: cnb_ = 16; break;
default: applyFormat(v);
};
return *this;
}
//! Do some action
PICout operator <<(const PICoutManipulators::PICoutAction v);
//! Set control flag "c" is "on" state
PICout & setControl(PICoutManipulators::PICoutControl c, bool on = true) {co_.setFlag(c, on); return *this;}
//! Set control flags "c" and if "save" exec \a saveControl()
PICout & setControl(PICoutManipulators::PICoutControls c, bool save = false) {if (save) saveControl(); co_ = c; return *this;}
//! Save control flags to internal stack \sa \a restoreControl()
PICout & saveControl();
//! Restore control flags from internal stack \sa \a saveControl()
PICout & restoreControl();
/*! \brief Conditional put space character to output
* \details If it is not a first output and control \a AddSpaces is set
* space character is put \sa \a quote(), \a newLine() */
PICout & space();
/*! \brief Conditional put quote character to output
* \details If control \a AddQuotes is set
* quote character is put \sa \a space(), \a newLine() */
PICout & quote();
/*! \brief Conditional put new line character to output
* \details If control \a AddNewLine is set
* new line character is put \sa \a space(), \a quote() */
PICout & newLine();
static bool setBufferActive(bool on, bool clear = false);
static bool isBufferActive();
static PIString buffer(bool clear = false);
static void clearBuffer();
static bool setOutputDevice(OutputDevice d, bool on = true);
static void setOutputDevices(OutputDevices d);
static bool isOutputDeviceActive(OutputDevice d);
static PIMutex & __mutex__();
static PIString & __string__();
private:
void init();
void applyFormat(PICoutManipulators::PICoutFormat f);
static OutputDevices devs;
PRIVATE_DECLARATION
bool fo_, cc_, fc_, act_;
int cnb_, attr_, id_;
PIString * buffer_;
PICoutManipulators::PICoutControls co_;
};
#endif // PICOUT_H

137
lib/main/core/piflags.h Normal file
View File

@@ -0,0 +1,137 @@
/*! \file piflags.h
* \brief General flags class
*/
/*
PIP - Platform Independent Primitives
General flags class
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PIFLAGS_H
#define PIFLAGS_H
#include "pip_export.h"
/*! \brief This class used as container for bit flags
* \details PIFlags is wrapper around \c "int". There are many
* bit-wise operators, native conversion to int and function
* to test flag. \n Example:
* \snippet piincludes.cpp flags
*/
template<typename Enum>
class PIP_EXPORT PIFlags {
public:
//! Constructor with flags = 0
PIFlags(): flags(0) {;}
//! Constructor with flags = Enum "e"
PIFlags(Enum e): flags(e) {;}
//! Constructor with flags = PIFlags "f"
PIFlags(const PIFlags & f): flags(f.flags) {;}
//! Constructor with flags = int "i"
PIFlags(const int i): flags(i) {;}
//! Set flags "f" to value "on"
PIFlags & setFlag(const PIFlags & f, bool on = true) {if (on) flags |= f.flags; else flags &= ~f.flags; return *this;}
//! Set flag "e" to value "on"
PIFlags & setFlag(const Enum & e, bool on = true) {if (on) flags |= e; else flags &= ~e; return *this;}
//! Set flag "i" to value "on"
PIFlags & setFlag(const int & i, bool on = true) {if (on) flags |= i; else flags &= ~i; return *this;}
//! copy operator
void operator =(const PIFlags & f) {flags = f.flags;}
//! copy operator
void operator =(const Enum & e) {flags = e;}
//! copy operator
void operator =(const int & i) {flags = i;}
//! compare operator
bool operator ==(const PIFlags & f) {return flags == f.flags;}
//! compare operator
bool operator ==(const Enum & e) {return flags == e;}
//! compare operator
bool operator ==(const int i) {return flags == i;}
//! compare operator
bool operator !=(const PIFlags & f) {return flags != f.flags;}
//! compare operator
bool operator !=(const Enum & e) {return flags != e;}
//! compare operator
bool operator !=(const int i) {return flags != i;}
//! compare operator
bool operator >(const PIFlags & f) {return flags > f.flags;}
//! compare operator
bool operator >(const Enum & e) {return flags > e;}
//! compare operator
bool operator >(const int i) {return flags > i;}
//! compare operator
bool operator <(const PIFlags & f) {return flags < f.flags;}
//! compare operator
bool operator <(const Enum & e) {return flags < e;}
//! compare operator
bool operator <(const int i) {return flags < i;}
//! compare operator
bool operator >=(const PIFlags & f) {return flags >= f.flags;}
//! compare operator
bool operator >=(const Enum & e) {return flags >= e;}
//! compare operator
bool operator >=(const int i) {return flags >= i;}
//! compare operator
bool operator <=(const PIFlags & f) {return flags <= f.flags;}
//! compare operator
bool operator <=(const Enum & e) {return flags <= e;}
//! compare operator
bool operator <=(const int i) {return flags <= i;}
//! Bit-wise AND operator
void operator &=(const PIFlags & f) {flags &= f.flags;}
//! Bit-wise AND operator
void operator &=(const Enum & e) {flags &= e;}
//! Bit-wise AND operator
void operator &=(const int i) {flags &= i;}
//! Bit-wise OR operator
void operator |=(const PIFlags & f) {flags |= f.flags;}
//! Bit-wise OR operator
void operator |=(const Enum & e) {flags |= e;}
//! Bit-wise OR operator
void operator |=(const int i) {flags |= i;}
//! Bit-wise XOR operator
void operator ^=(const PIFlags & f) {flags ^= f.flags;}
//! Bit-wise XOR operator
void operator ^=(const Enum & e) {flags ^= e;}
//! Bit-wise XOR operator
void operator ^=(const int i) {flags ^= i;}
//! Bit-wise AND operator
PIFlags operator &(PIFlags f) const {PIFlags tf(flags & f.flags); return tf;}
//! Bit-wise AND operator
PIFlags operator &(Enum e) const {PIFlags tf(flags & e); return tf;}
//! Bit-wise AND operator
PIFlags operator &(int i) const {PIFlags tf(flags & i); return tf;}
//! Bit-wise OR operator
PIFlags operator |(PIFlags f) const {PIFlags tf(flags | f.flags); return tf;}
//! Bit-wise OR operator
PIFlags operator |(Enum e) const {PIFlags tf(flags | e); return tf;}
//! Bit-wise OR operator
PIFlags operator |(int i) const {PIFlags tf(flags | i); return tf;}
//! Bit-wise XOR operator
PIFlags operator ^(PIFlags f) const {PIFlags tf(flags ^ f.flags); return tf;}
//! Bit-wise XOR operator
PIFlags operator ^(Enum e) const {PIFlags tf(flags ^ e); return tf;}
//! Bit-wise XOR operator
PIFlags operator ^(int i) const {PIFlags tf(flags ^ i); return tf;}
//! Test flag operator
bool operator [](Enum e) const {return (flags & e) == e;}
//! Implicity conversion to \c int
operator int() const {return flags;}
private:
int flags;
};
#endif // PIFLAGS_H

View File

@@ -0,0 +1,266 @@
/*
PIP - Platform Independent Primitives
Global includes
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "piincludes.h"
#include "piincludes_p.h"
#include "piconsole.h"
#include "pitime.h"
#ifndef QNX
# include <clocale>
#else
# include <locale.h>
#endif
#ifdef MAC_OS
//# include <mach/mach_traps.h>
//# include <mach/mach.h>
# include <mach/clock.h>
//# include <crt_externs.h>
#endif
#include <errno.h>
bool piDebug = true;
double piMountInfoRefreshIntervalMs = 10000.;
lconv * currentLocale =
#ifdef ANDROID
0;
#else
std::localeconv();
#endif
#ifdef MAC_OS
clock_serv_t __pi_mac_clock;
#endif
#ifdef WINDOWS
FILETIME __pi_ftjan1970;
long long __pi_perf_freq = -1;
PINtQueryTimerResolution getTimerResolutionAddr = 0;
PINtSetTimerResolution setTimerResolutionAddr = 0;
#endif
void errorClear() {
#ifdef WINDOWS
SetLastError(0);
#else
errno = 0;
#endif
}
PIString errorString() {
#ifdef WINDOWS
char * msg;
int err = GetLastError();
FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&msg, 0, NULL);
return "code " + PIString::fromNumber(err) + " - " + PIString(msg);
#else
int e = errno;
return PIString("code ") + PIString::fromNumber(e) + " - " + PIString(strerror(e));
#endif
}
PIString PIPVersion() {
static PIString ret = PIStringAscii(PIP_VERSION_NAME);
return ret;
}
/*! \class PICout
* \brief Class for formatted output similar std::cout
*
* \section PICout_sec0 Synopsis
* This class provide many stream operators for output with some features.
* Output to PICout is thread-sequential, i.e. doesn`t mixed from parallel
* threads.
*
* \section PICout_sec1 Features
* - insertion spaces between entries
* - insertion new line at the end of output
* - strings are quoted
* - custom output operator can be easily written
*
* \section PICout_ex0 Usage
* \snippet picout.cpp 0
*
* \section PICout_ex1 Writing your own output operator
* \snippet picout.cpp own
*/
/*! \mainpage What is PIP
* PIP - Platform-Independent Primitives - is crossplatform library for C++ developers.
* It is wrap around STL and pure C++. This library can help developers write non-GUI
* projects much more quickly, efficiently and customizable than on pure C++.
* Library contains many classes, some of them are pure abstract, some classes
* can be used as they are, some classes should be inherited to new classes.
* PIP provide classes:
* * direct output to console (\a PICout)
* * containers (\a PIVector, \a PIList, \a PIMap, \a PIStack)
* * byte array (\a PIByteArray)
* * string (\a PIString, \a PIStringList)
* * base object (events and handlers) (\a PIObject)
* * multithreading
* * thread (\a PIThread)
* * executor (\a PIThreadPoolExecutor)
* * blocking dequeue (\a PIBlockingDequeue)
* * timer (\a PITimer)
* * console (information output) (\a PIConsole)
* * stand-alone
* * server
* * client
* * I/O devices
* * base class (\a PIIODevice)
* * file (\a PIFile)
* * serial port (\a PISerial)
* * ethernet (\a PIEthernet)
* * USB (\a PIUSB)
* * packets extractor (\a PIPacketExtractor)
* * binary log (\a PIBinaryLog)
* * complex I/O point (\a PIConnection)
* * connection quality diagnotic (\a PIDiagnostics)
* * command-line arguments parser (\a PICLI)
* * math evaluator (\a PIEvaluator)
* * peering net node (\a PIPeer)
* * process (\a PIProcess)
* * state machine (\a PIStateMachine)
* \n \n Basic using of PIP described at page \ref using_basic */
/*! \page using_basic Getting started
* Many novice programmers are solved many common task with system integrity: output to console,
* keyboard buttons press detecting, working with serial ports, ethernet or files, and many other.
* These tasks can solve this library, and code, based only on PIP will be compile and work
* similar on many systems: Windows, any Linux, Red Hat, FreeBSD, MacOS X and QNX.
* Typical application on PIP looks like this: \n
\code{.cpp}
#include <pip.h>
// declare key press handler
void key_event(char key, void * );
PIConsole console(false, key_event); // don`t start now, key handler is "key_event"
// some vars
int i = 2, j = 3;
// implicit key press handler
void key_event(char key, void * ) {
switch (key) {
case '-':
i--;
break;
case '+':
i++;
break;
case '(':
j--;
break;
case ')':
j++;
break;
};
};
class MainClass: public PITimer {
PIOBJECT(MainClass)
public:
MainClass() {}
protected:
void tick(void * data, int delimiter) {
piCout << "timer tick";
// timer tick
}
};
MainClass main_class;
int main(int argc, char * argv[]) {
// enabling auto-detection of exit button press, by default 'Q' (shift+q)
console.enableExitCapture();
// if we want to parse command-line arguments
PICLI cli(argc, argv);
cli.addArgument("console"); // "-c" or "--console"
cli.addArgument("debug"); // "-d" or "--debug"
// enabling or disabling global debug flag
piDebug = cli.hasArgument("debug");
// configure console
console.addTab("first tab", '1');
console.addString("PIP console", 1, PIConsole::Bold);
console.addVariable("int var (i)", &i, 1);
console.addVariable("int green var (j)", &j, 1, PIConsole::Green);
console.addString("'-' - i--", 2);
console.addString("'+' - i++", 2);
console.addString("'(' - j--", 2);
console.addString("')' - j++", 2);
console.addTab("second tab", '2');
console.addString("col 1", 1);
console.addString("col 2", 2);
console.addString("col 3", 3);
console.setTab("first tab");
// start output to console if "console" argument exists
if (cli.hasArgument("console"))
console.start();
// start main class, e.g. 40 Hz
main_class.start(25.);
// wait for 'Q' press, independently if console is started or not
console.waitForFinish();
return 0;
};
\endcode
* This code demonstrates simple interactive configurable program, which can be started with console
* display or not, and with debug or not. \b MainClass is central class that also can be inherited from
* \a PIThread and reimplement \a run() function.
* \n Many PIP classes has events and event handlers, which can be connected one to another.
* Details you can see at \a PIObject reference page (\ref PIObject_sec0).
* \n To configure your program from file use \a PIConfig.
* \n If you want more information see \ref using_advanced */
/*! \page using_advanced Advanced using
* Sorry, creativity crysis xD
*/
void piqsort(void * base, size_t num, size_t size, int (*compar)(const void *, const void *)) {
qsort(base, num, size, compar);
}
void randomize() {
srand(PISystemTime::current(true).nanoseconds);
}
int randomi() {
return rand();
}

View File

@@ -0,0 +1,56 @@
/*
PIP - Platform Independent Primitives
Minimal PIP includes
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PIINCLUDES_H
#define PIINCLUDES_H
#include "pibase.h"
#include "piflags.h"
#include <sys/types.h>
#ifdef PIP_STD_IOSTREAM
# include <iostream>
#endif
class PIObject;
class PIMutex;
class PIString;
class PIByteArray;
class PIInit;
class PIChar;
class PICout;
struct lconv;
extern lconv * currentLocale;
/*! \fn errorString()
* \brief Return readable error description in format "code <number> - <description>" */
PIP_EXPORT PIString errorString();
PIP_EXPORT void errorClear();
PIP_EXPORT void piqsort(void* base, size_t num, size_t size, int (*compar)(const void*,const void*));
PIP_EXPORT void randomize();
PIP_EXPORT int randomi();
/// Return readable version of PIP
PIP_EXPORT PIString PIPVersion();
#endif // PIINCLUDES_H

View File

@@ -0,0 +1,45 @@
/*
PIP - Platform Independent Primitives
Private PIP includes
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PIINCLUDES_P_H
#define PIINCLUDES_P_H
#include "picout.h"
#ifdef WINDOWS
# include <stdarg.h>
# include <windef.h>
# include <winbase.h>
typedef LONG(NTAPI*PINtQueryTimerResolution)(PULONG, PULONG, PULONG);
typedef LONG(NTAPI*PINtSetTimerResolution)(ULONG, BOOLEAN, PULONG);
#endif
#ifdef CC_GCC
# include <unistd.h>
#endif
#include <string.h>
#include <cstring>
#include <string>
#include <stdlib.h>
#include <cstdlib>
#include <stdio.h>
#include <cstdio>
#include <iostream>
#endif // PIINCLUDES_P_H

417
lib/main/core/piinit.cpp Normal file
View File

@@ -0,0 +1,417 @@
/*
PIP - Platform Independent Primitives
Initialization
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "piincludes_p.h"
#include "piinit.h"
#include "pitime.h"
#include "pisignals.h"
#include "piobject.h"
#include "pisysteminfo.h"
#include "piresourcesstorage.h"
#include "pidir.h"
#ifndef FREERTOS
# include "piprocess.h"
#endif
#ifdef ESP_PLATFORM
# include "esp_system.h"
#endif
#ifdef WINDOWS
# include <winsock2.h>
extern FILETIME __pi_ftjan1970;
extern PINtQueryTimerResolution getTimerResolutionAddr;
extern PINtSetTimerResolution setTimerResolutionAddr;
void __PISetTimerResolution() {
if (setTimerResolutionAddr == NULL || getTimerResolutionAddr == NULL)
return;
ULONG _max(0), _min(0), _cur(0);
//printf("getTimerResolution ...\n");
LONG q = getTimerResolutionAddr(&_max, &_min, &_cur);
//printf("getTimerResolution %d %lu %lu %lu\n", q, _min, _max, _cur);
if (q == 0)
setTimerResolutionAddr(_min, TRUE, &_cur);
//printf("setTimerResolution %lu\n", cur);
}
#else
# include <pwd.h>
# ifndef FREERTOS
# include <sys/utsname.h>
# endif
# include <pthread.h>
# ifdef BLACKBERRY
# include <signal.h>
# else
# include <csignal>
# endif
#endif
#ifdef MAC_OS
# include <mach/mach_traps.h>
# include <mach/mach.h>
# include <mach/clock.h>
extern clock_serv_t __pi_mac_clock;
#endif
#ifdef PIP_ICU
# define U_NOEXCEPT
# include <unicode/uclean.h>
# include <unicode/ucnv.h>
#endif
#ifdef HAS_LOCALE
static locale_t currentLocale_t = 0;
#endif
PRIVATE_DEFINITION_START(PIInit)
#ifdef WINDOWS
HMODULE ntlib;
ULONG prev_res;
#endif
bool delete_locs;
PRIVATE_DEFINITION_END(PIInit)
#ifndef FREERTOS
void __sighandler__(PISignals::Signal s) {
//piCout << Hex << int(s);
if (s == PISignals::StopTTYInput || s == PISignals::StopTTYOutput)
piMSleep(10);
if (s == PISignals::UserDefined1)
dumpApplicationToFile(PIDir::home().path() + PIDir::separator + PIStringAscii("_PIP_DUMP_") + PIString::fromNumber(PIProcess::currentPID()));
}
#endif
#ifdef ANDROID
void android_thread_exit_handler(int sig) {
pthread_exit(0);
}
#endif
PIInit::PIInit() {
file_charset = 0;
PISystemInfo * sinfo = PISystemInfo::instance();
sinfo->execDateTime = PIDateTime::current();
setFileCharset("UTF-8");
#ifndef FREERTOS
#ifndef ANDROID
PISignals::setSlot(__sighandler__);
PISignals::grabSignals(PISignals::UserDefined1);
# ifndef WINDOWS
PISignals::grabSignals(PISignals::StopTTYInput | PISignals::StopTTYOutput);
sigset_t ss;
sigemptyset(&ss);
sigaddset(&ss, SIGALRM);
sigprocmask(SIG_BLOCK, &ss, 0);
pthread_sigmask(SIG_BLOCK, &ss, 0);
signal(SIGPIPE, SIG_IGN);
PIStringList ifpathes;
ifpathes << PIStringAscii("/bin/ifconfig") << PIStringAscii("/sbin/ifconfig")
<< PIStringAscii("/usr/bin/ifconfig") << PIStringAscii("/usr/sbin/ifconfig");
piForeachC (PIString & i, ifpathes) {
if (fileExists(i)) {
sinfo->ifconfigPath = i;
piBreak;
}
}
# else
// OS version
DWORD dwVersion = GetVersion();
DWORD dwMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
DWORD dwMinorVersion = (DWORD)(HIBYTE(LOWORD(dwVersion)));
sinfo->OS_version = PIString::fromNumber(dwMajorVersion) + "." + PIString::fromNumber(dwMinorVersion);
// WinSock inint
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
// Timers init
SYSTEMTIME jan1970 = {1970, 1, 4, 1, 0, 0, 0, 0};
SystemTimeToFileTime(&jan1970, &__pi_ftjan1970);
LARGE_INTEGER pf;
pf.QuadPart = -1;
if (QueryPerformanceFrequency(&pf) != 0) __pi_perf_freq = pf.QuadPart;
if (__pi_perf_freq == 0) __pi_perf_freq = -1;
// Sleep precision init
PRIVATE->ntlib = LoadLibrary("ntdll.dll");
if (PRIVATE->ntlib) {
getTimerResolutionAddr = (PINtQueryTimerResolution)GetProcAddress(PRIVATE->ntlib, "NtQueryTimerResolution");
setTimerResolutionAddr = (PINtSetTimerResolution)GetProcAddress(PRIVATE->ntlib, "NtSetTimerResolution");
__PISetTimerResolution();
}
# endif
# ifdef HAS_LOCALE
//cout << "has locale" << endl;
if (currentLocale_t != 0) {
freelocale(currentLocale_t);
currentLocale_t = 0;
}
currentLocale_t = newlocale(LC_ALL, setlocale(LC_ALL, ""), 0);
# else
setlocale(LC_ALL, "");
setlocale(LC_NUMERIC, "C");
# endif
#else
struct sigaction actions;
memset(&actions, 0, sizeof(actions));
sigemptyset(&actions.sa_mask);
actions.sa_flags = 0;
actions.sa_handler = android_thread_exit_handler;
sigaction(SIGTERM, &actions, 0);
#endif
PRIVATE->delete_locs = false;
__syslocname__ = __sysoemname__ = 0;
__utf8name__ = const_cast<char*>("UTF-8");
#ifdef PIP_ICU
UErrorCode e((UErrorCode)0);
u_init(&e);
# ifdef WINDOWS
PRIVATE->delete_locs = true;
CPINFOEX cpinfo;
int l = 0;
GetCPInfoEx(CP_OEMCP, 0, &cpinfo);
for (l = 0; l < MAX_PATH; ++l)
if (cpinfo.CodePageName[l] == '\0' || cpinfo.CodePageName[l] == ' ')
break;
__sysoemname__ = new char[256];
memset(__sysoemname__, 0, 256);
memcpy(__sysoemname__, "ibm-", 4);
memcpy(&(__sysoemname__[4]), cpinfo.CodePageName, l);
# else
/*PIString en(getenv("LANG"));
if (!en.isEmpty())
en = en.mid(en.find(".") + 1);
PIByteArray enba = en.toByteArray();
memcpy(__syslocname__, enba.data(), enba.size_s());*/
# endif
//piCout << __syslocname__;
//piCout << __sysoemname__;
#else
# ifdef WINDOWS
__syslocname__ = (char *)CP_ACP;
__sysoemname__ = (char *)CP_OEMCP;
__utf8name__ = (char *)CP_UTF8;
# endif
#endif
#ifdef MAC_OS
host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &__pi_mac_clock);
#endif
char cbuff[1024];
memset(cbuff, 0, 1024);
if (gethostname(cbuff, 1023) == 0)
sinfo->hostname = cbuff;
#ifdef WINDOWS
SYSTEM_INFO sysinfo;
GetSystemInfo(&sysinfo);
sinfo->processorsCount = sysinfo.dwNumberOfProcessors;
switch (sysinfo.wProcessorArchitecture) {
case PROCESSOR_ARCHITECTURE_AMD64: sinfo->architecture = PIStringAscii("x86_64"); break;
case PROCESSOR_ARCHITECTURE_ARM: sinfo->architecture = PIStringAscii("arm"); break;
case PROCESSOR_ARCHITECTURE_IA64: sinfo->architecture = PIStringAscii("Intel Itanium-based"); break;
case PROCESSOR_ARCHITECTURE_INTEL: sinfo->architecture = PIStringAscii("x86"); break;
case PROCESSOR_ARCHITECTURE_UNKNOWN:
default: sinfo->architecture = PIStringAscii("unknown"); break;
}
int argc_(0);
wchar_t ** argv_ = CommandLineToArgvW(GetCommandLineW(), &argc_);
if (argc_ > 0 && argv_ != 0)
sinfo->execCommand = argv_[0];
LocalFree(argv_);
memset(cbuff, 0, 1024);
ulong unlen = 1023;
if (GetUserName(cbuff, &unlen) != 0)
sinfo->user = cbuff;
#else
sinfo->processorsCount = piMaxi(1, int(sysconf(_SC_NPROCESSORS_ONLN)));
passwd * ps = getpwuid(getuid());
if (ps)
sinfo->user = ps->pw_name;
else {
memset(cbuff, 0, 1024);
char * l = getlogin();
if (l)
sinfo->user = l;
}
struct utsname uns;
if (uname(&uns) == 0) {
sinfo->OS_version = uns.release;
sinfo->architecture = uns.machine;
}
# endif
#endif
#ifdef ESP_PLATFORM
esp_chip_info_t chip_info;
esp_chip_info(&chip_info);
sinfo->processorsCount = chip_info.cores;
sinfo->architecture = "Xtensa LX6";
//printf("silicon revision %d, ", chip_info.revision);
sinfo->OS_version = esp_get_idf_version();
#endif
sinfo->OS_name =
#ifdef WINDOWS
PIStringAscii("Windows");
#elif defined(QNX)
PIStringAscii("QNX");
#elif defined(MAC_OS)
PIStringAscii("MacOS");
#elif defined(ANDROID)
PIStringAscii("Android");
#elif defined(FREE_BSD)
PIStringAscii("FreeBSD");
#elif defined(FREERTOS)
PIStringAscii("FreeRTOS");
#else
uns.sysname;
#endif
}
PIInit::~PIInit() {
if (file_charset) delete file_charset;
file_charset = 0;
PIResourcesStorage::instance()->clear();
#ifdef WINDOWS
WSACleanup();
if (PRIVATE->ntlib) FreeLibrary(PRIVATE->ntlib);
PRIVATE->ntlib = 0;
#endif
#ifdef MAC_OS
mach_port_deallocate(mach_task_self(), __pi_mac_clock);
#endif
if (PRIVATE->delete_locs) {
if (__syslocname__) delete __syslocname__;
if (__sysoemname__) delete __sysoemname__;
}
#ifdef PIP_ICU
u_cleanup();
#endif
}
bool PIInit::isBuildOptionEnabled(PIInit::BuildOption o) {
switch (o) {
case ICU: return
#ifdef PIP_ICU
true;
#else
false;
#endif
case USB: return
#ifdef PIP_USB
true;
#else
false;
#endif
case Crypt: return
#ifdef PIP_CRYPT
true;
#else
false;
#endif
case Introspection: return
#ifdef PIP_INTROSPECTION
true;
#else
false;
#endif
case FFTW: return
#ifdef PIP_FFTW
true;
#else
false;
#endif
case Compress: return
#ifdef PIP_COMPRESS
true;
#else
false;
#endif
case OpenCL: return
#ifdef PIP_OPENCL
true;
#else
false;
#endif
case Cloud: return
#ifdef PIP_CLOUD
true;
#else
false;
#endif
default: return false;
}
return false;
}
PIStringList PIInit::buildOptions() {
PIStringList ret;
if (isBuildOptionEnabled(ICU)) ret << "ICU";
if (isBuildOptionEnabled(USB)) ret << "USB";
if (isBuildOptionEnabled(Crypt)) ret << "Crypt";
if (isBuildOptionEnabled(Introspection)) ret << "Introspection";
if (isBuildOptionEnabled(FFTW)) ret << "FFTW";
if (isBuildOptionEnabled(Compress)) ret << "Compress";
if (isBuildOptionEnabled(OpenCL)) ret << "OpenCL";
if (isBuildOptionEnabled(Cloud)) ret << "Cloud";
return ret;
}
void PIInit::setFileCharset(const char *charset) {
if (file_charset) delete file_charset;
file_charset = 0;
if (charset) {
file_charset = new char[1024];
memset(file_charset, 0, 1024);
strcpy(file_charset, charset);
}
}
bool PIInit::fileExists(const PIString & p) {
FILE * f = fopen(p.data(), "r");
if (f == 0)
return false;
fclose(f);
return true;
}
int __PIInit_Initializer__::count_(0);
PIInit * __PIInit_Initializer__::__instance__(0);
__PIInit_Initializer__::__PIInit_Initializer__() {
count_++;
if (count_ > 1) return;
//piCout << "create PIInit";
__instance__ = new PIInit();
}
__PIInit_Initializer__::~__PIInit_Initializer__() {
count_--;
if (count_ > 0) return;
//piCout << "delete PIInit";
if (__instance__ != 0) {
delete __instance__;
__instance__ = 0;
}
}

73
lib/main/core/piinit.h Normal file
View File

@@ -0,0 +1,73 @@
/*! \file piinit.h
* \brief Initialization
*/
/*
PIP - Platform Independent Primitives
Initialization
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PIINIT_H
#define PIINIT_H
#include "piincludes.h"
class PIFile;
class PIStringList;
class PIP_EXPORT __PIInit_Initializer__ {
public:
__PIInit_Initializer__();
~__PIInit_Initializer__();
static int count_;
static PIInit * __instance__;
};
class PIP_EXPORT PIInit {
friend class __PIInit_Initializer__;
friend class PIFile;
public:
~PIInit();
//! \brief Build options which PIP library was built
enum BuildOption {
ICU /*! Unicode support */ = 0x01,
USB /*! USB support */ = 0x02,
Crypt /*! Crypt support */ = 0x08,
Introspection /*! Introspection */ = 0x010,
FFTW /*! FFTW3 support */ = 0x40,
Compress /*! Zlib compression support */ = 0x80,
OpenCL /*! OpenCL support */ = 0x100,
Cloud /*! Cloud transport support */ = 0x200,
};
static PIInit * instance() {return __PIInit_Initializer__::__instance__;}
static bool isBuildOptionEnabled(BuildOption o);
static PIStringList buildOptions();
private:
explicit PIInit();
void setFileCharset(const char *charset);
bool fileExists(const PIString & p);
PRIVATE_DECLARATION
char * file_charset;
};
static __PIInit_Initializer__ __piinit_initializer__;
#endif // PIINIT_H

676
lib/main/core/piobject.cpp Normal file
View File

@@ -0,0 +1,676 @@
/*
PIP - Platform Independent Primitives
Object, base class of some PIP classes, provide EVENT -> EVENT_HANDLER mechanism
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "piobject.h"
#include "pisysteminfo.h"
#ifndef FREERTOS
# include "pifile.h"
#endif
/** \class PIObject
* \brief This is base class for any classes which use events -> handlers mechanism.
* \details
* \section PIObject_sec0 Events and Event handlers
* %PIObject provide notification mechanism similar Qt but implemented
* on language capabilities without any special preprocessors or compilers.
* Any class inherits PIObject should use macro \a PIOBJECT() immediate
* after declaration to proper compile.
*
* Event is a some abstract event that can be raised at any time.
* Event is a function but declared with special macro \a EVENT().
* To raise event simply execute event function.
*
* Event handler is a function but declared with special macro
* \a EVENT_HANDLER(). You can use event handlers as ordinary functions.
*
* Main goal of this mechanism is perform abstract connections between
* various objects. This functionality provide macro \a CONNECT() which
* connect some event of first object to some event handler or event of
* second object. Each event can be connected any times to any event handlers.
*
* \image html events_handlers.png
*
* Example: \snippet piobject.cpp main
* Result:
\code{.cpp}
handler B: 2 , 0.5
handler A: event to handler
handler A: event to event
\endcode
*/
PIString PIObject::__MetaFunc::arguments() const {
return types.join(",");
}
PIString PIObject::__MetaFunc::fullFormat() const {
PIString ret = type_ret + " " + scope + "::" + func_name +"(";
for (int i = 0; i < types.size_s(); ++i) {
if (i > 0) ret += ", ";
ret += types[i] + " " + names[i];
}
ret += ")";
return ret;
}
PIObject::PIObject(const PIString & name): _signature_(__PIOBJECT_SIGNATURE__), emitter_(0), thread_safe_(false), proc_event_queue(false) {
setName(name);
setDebug(true);
mutexObjects().lock();
objects() << this;
mutexObjects().unlock();
//piCout << "new" << this;
}
PIObject::~PIObject() {
//piCout << "delete" << this;
mutexObjects().lock();
objects().removeAll(this);
mutexObjects().unlock();
piDisconnect(this);
}
PIMap<PIString, PIVariant> PIObject::properties() const {
PIMap<PIString, PIVariant> ret;
piForeachC (PropertyHash p, properties_)
ret[p.second.first] = p.second.second;
return ret;
}
bool PIObject::execute(const PIString & method, const PIVector<PIVariant> & vl) {
if (method.isEmpty()) return false;
if (!isPIObject()) {
piCout << "Error: \"execute(" << method << ")\":" << (void*)this << "is not PIObject!";
return false;
}
int ac = 0;
__MetaFunc func;
bool ok = findSuitableMethodV(method, vl.size_s(), ac, func);
if (!ok)
return false;
callAddrV(func.addrV, toThis(), ac, vl);
return true;
}
bool PIObject::executeQueued(PIObject * performer, const PIString & method, const PIVector<PIVariant> & vl) {
if (!isPIObject()) {
piCout << "Error: \"executeQueued(" << method << ")\": this(" << (void*)this << ") is not PIObject!";
return false;
}
if (!performer->isPIObject()) {
piCout << "Error: \"executeQueued(" << method << ")\": performer(" << (void*)performer << ") is not PIObject!";
return false;
}
int ac = 0;
__MetaFunc func;
bool ok = findSuitableMethodV(method, vl.size_s(), ac, func);
if (!ok)
return false;
performer->postQueuedEvent(__QueuedEvent(func.addrV, toThis(), this, performer, vl));
performer->proc_event_queue = true;
return true;
}
void PIObject::piConnect(const PIString & src, const PIString & sig, void * dest, void * ev_h) {
PIObject * o = findByName(src);
if (o == 0) {
piCout << "[PIObject] Can`t find object with name \"" << src << "\"!";
return;
}
PIMutexLocker _ml(o->mutex_connect);
PIMutexLocker _mld(((PIObject*)dest)->mutex_connect, ((PIObject*)dest) != o);
o->connections << __Connection(ev_h, 0, sig, (PIObject*)dest, dest);
((PIObject*)dest)->connectors << o;
}
void PIObject::piConnect(PIObject * src, const PIString & sig, const PIString & dest, void * ev_h) {
PIObject * o = findByName(dest);
if (o == 0) {
piCout << "[PIObject] Can`t find object with name \"" << dest << "\"!";
return;
}
PIMutexLocker _ml(src->mutex_connect);
PIMutexLocker _mld(o->mutex_connect, src != o);
src->connections << __Connection(ev_h, 0, sig, o, o);
((PIObject*)o)->connectors << src;
}
void PIObject::piConnect(const PIString & src, const PIString & sig, const PIString & dest, void * ev_h) {
PIObject * s = findByName(src);
if (s == 0) {
piCout << "[PIObject] Can`t find object with name \"" << src << "\"!";
return;
}
PIObject * d = findByName(dest);
if (d == 0) {
piCout << "[PIObject] Can`t find object with name \"" << dest << "\"!";
return;
}
PIMutexLocker _ml(s->mutex_connect);
PIMutexLocker _mld(d->mutex_connect, s != d);
s->connections << __Connection(ev_h, 0, sig, d, d);
d->connectors << s;
}
PIStringList PIObject::scopeList() const {
PIMutexLocker ml(__meta_mutex());
return __meta_data()[classNameID()].scope_list;
}
PIStringList PIObject::methodsEH() const {
PIMutexLocker ml(__meta_mutex());
PIStringList ret;
__MetaData & ehd(__meta_data()[classNameID()]);
piForeachC (__EHPair & eh, ehd.eh_func)
ret << eh.second.fullFormat();
return ret;
}
bool PIObject::isMethodEHContains(const PIString & name) const {
PIMutexLocker ml(__meta_mutex());
__MetaData & ehd(__meta_data()[classNameID()]);
piForeachC (__EHPair & eh, ehd.eh_func)
if (eh.second.func_name == name)
return true;
return false;
}
PIString PIObject::methodEHArguments(const PIString & name) const {
PIMutexLocker ml(__meta_mutex());
__MetaData & ehd(__meta_data()[classNameID()]);
piForeachC (__EHPair & eh, ehd.eh_func)
if (eh.second.func_name == name)
return eh.second.arguments();
return PIString();
}
PIString PIObject::methodEHFullFormat(const PIString & name) const {
PIMutexLocker ml(__meta_mutex());
__MetaData & ehd(__meta_data()[classNameID()]);
piForeachC (__EHPair & eh, ehd.eh_func)
if (eh.second.func_name == name)
return eh.second.fullFormat();
return PIString();
}
PIString PIObject::methodEHFromAddr(const void * addr) const {
return methodEH(addr).func_name;
}
PIVector<PIObject::__MetaFunc> PIObject::findEH(const PIString & name) const {
PIVector<__MetaFunc> ret;
__MetaData & ehd(__meta_data()[classNameID()]);
piForeachC (__EHPair & eh, ehd.eh_func)
if (eh.second.func_name == name)
ret << eh.second;
return ret;
}
PIObject::__MetaFunc PIObject::methodEH(const void * addr) const {
PIMutexLocker ml(__meta_mutex());
return __meta_data()[classNameID()].eh_func.value(addr);
}
void PIObject::piConnect(PIObject * src, const PIString & sig, PIObject * dest_o, void * dest, void * ev_h, void * e_h, int args, const char * loc) {
//piCout << "piConnect ...";
//piCout << "piConnect" << src << (void*)(dest) << sig;
//piCout << "piConnect" << src->className() << "->" << ((PIObject*)dest)->className();
PIMutexLocker _ml(src->mutex_connect);
PIMutexLocker _mld(dest_o->mutex_connect, src != dest_o);
src->connections << __Connection(ev_h, e_h, sig, dest_o, dest, args);
//piCout << "piConnect" << ((PIObject*)dest) << sig << ((PIObject*)dest)->connectors.size_s() << "...";
//piCout << "addConnector" << dest_o << src;
dest_o->connectors << src;
//piCout << "piConnect" << ((PIObject*)dest) << sig << ((PIObject*)dest)->connectors.size_s();
//piCout << "piConnect ok";
}
bool PIObject::piConnectU(PIObject * src, const PIString & sig, PIObject * dest_o, void * dest, const PIString & hname, const char * loc, PIObject * performer) {
if (src == 0 || dest_o == 0 || dest == 0) return false;
if (!src->isPIObject()) {
piCout << "[piConnectU] \"" << sig << "\" -> \"" << hname << "\" error: source object is not PIObject! (" << loc << ")";
return false;
}
if (!dest_o->isPIObject()) {
piCout << "[piConnectU] \"" << sig << "\" -> \"" << hname << "\" error: destination object is not PIObject! (" << loc << ")";
return false;
}
PIMutexLocker ml(__meta_mutex());
PIMutexLocker mls(src->mutex_connect);
PIMutexLocker mld(dest_o->mutex_connect, src != dest_o);
PIVector<__MetaFunc> m_src = src->findEH(sig), m_dest = dest_o->findEH(hname);
if (m_src.isEmpty()) {
piCout << "[piConnectU] Error: can`t find event \"" << sig << "\" in class \"" << src->className() << "\"! (" << loc << ")";
return false;
}
if (m_dest.isEmpty()) {
piCout << "[piConnectU] Error: can`t find handler \"" << hname << "\" in class \"" << dest_o->className() << "\"! (" << loc << ")";
return false;
}
void * addr_src(0), * addr_dest(0);
int args(0);
bool que = (performer != 0);
piForeachC (__MetaFunc & fs, m_src) {
if (addr_src != 0) break;
piForeachC (__MetaFunc & fd, m_dest) {
if (addr_src != 0) break;
if (fs.arguments().startsWith(fd.arguments()) || fd.arguments().isEmpty()) {
addr_src = fs.addr;
addr_dest = que ? fd.addrV : fd.addr;
args = fd.names.size_s();
}
}
}
if (addr_src == 0) {
piCout << "[piConnectU] Error: can`t find suitable pair of event \"" << sig << "\" in class \"" << src->className()
<< "\" and handler \"" << hname << "\" in class \"" << dest_o->className() << "\"! (" << loc << ")";
return false;
}
src->connections << PIObject::__Connection(addr_dest, addr_src, sig, dest_o, dest, args, performer);
if (que) performer->proc_event_queue = true;
dest_o->connectors << src;
//piCout << cc << cq << _ol.size();//"connect" << src << "->" << dest_o << ", dest.connectors.size() =" << dest_o->connectors.size();
return true;
}
#ifdef PIP_CXX11_SUPPORT
bool PIObject::piConnectLS(PIObject * src, const PIString & sig, std::function<void()> * f, const char * loc) {
if (src == 0) {
delete f;
return false;
}
if (!src->isPIObject()) {
piCout << "[piConnectLS] \"" << sig << "\" -> [lambda] error: source object is not PIObject! (" << loc << ")";
delete f;
return false;
}
PIMutexLocker ml(__meta_mutex());
PIMutexLocker mls(src->mutex_connect);
//piCout << "locked";
PIVector<__MetaFunc> m_src = src->findEH(sig);
if (m_src.isEmpty()) {
piCout << "[piConnectLS] Error: can`t find event \"" << sig << "\" in class \"" << src->className() << "\"! (" << loc << ")";
delete f;
return false;
}
if (m_src.size() != 1) {
piCout << "[piConnectLS] Error: can`t connect overloaded event \"" << sig << "\" in class \"" << src->className() << "\"! (" << loc << ")";
delete f;
return false;
}
PIObject::__Connection conn(0, m_src[0].addr, sig);
//piCout << "found";
conn.functor = f;
src->connections << conn;
//piCout << "finished";
return true;
}
#endif
void PIObject::piDisconnect(PIObject * src, const PIString & sig, PIObject * dest, void * ev_h) {
PIMutexLocker _ml(src->mutex_connect);
PIMutexLocker _mld(dest->mutex_connect, src != dest);
for (int i = 0; i < src->connections.size_s(); ++i) {
__Connection & cc(src->connections[i]);
if (cc.event == sig && cc.dest_o == dest && cc.slot == ev_h) {
src->connections[i].destroy();
src->connections.remove(i);
i--;
}
}
dest->updateConnectors();
}
void PIObject::piDisconnect(PIObject * src, const PIString & sig, PIObject * dest) {
PIMutexLocker _ml(src->mutex_connect);
PIMutexLocker _mld(dest->mutex_connect, src != dest);
for (int i = 0; i < src->connections.size_s(); ++i) {
__Connection & cc(src->connections[i]);
if (cc.event == sig && cc.dest_o == dest) {
src->connections[i].destroy();
src->connections.remove(i);
i--;
}
}
dest->updateConnectors();
}
void PIObject::piDisconnect(PIObject * src, const PIString & sig) {
PIMutexLocker _ml(src->mutex_connect);
for (int i = 0; i < src->connections.size_s(); ++i) {
__Connection & cc(src->connections[i]);
if (cc.event == sig) {
PIObject * dest = cc.dest_o;
if (!dest) {
src->connections[i].destroy();
src->connections.remove(i);
i--;
#if !defined(ANDROID) && !defined(MAC_OS) && !defined(FREERTOS)
PIMutexLocker _mld(dest->mutex_connect, src != dest);
#endif
dest->updateConnectors();
}
}
}
}
void PIObject::piDisconnect(PIObject * src) {
src->deleted();
PIMutexLocker _ml(src->mutex_connect);
PIVector<PIObject * > cv = src->connectors.toVector();
piForeach (PIObject * o, cv) {
//piCout << "disconnect"<< src->className()<< o->className();
if (!o || (o == src)) continue;
if (!o->isPIObject()) continue;
#if !defined(ANDROID) && !defined(MAC_OS) && !defined(FREERTOS)
PIMutexLocker _mld(o->mutex_connect, src != o);
#endif
PIVector<__Connection> & oc(o->connections);
for (int i = 0; i < oc.size_s(); ++i) {
if (oc[i].functor) continue;
//piCout << " check" << (void*)(oc[i].dest_o) << "==" << (void*)(src);
if (oc[i].dest_o == src) {
oc[i].destroy();
oc.remove(i);
--i;
}
}
}
piForeachC (PIObject::__Connection & c, src->connections) {
if (c.functor) continue;
if (!c.dest_o) continue;
if (!c.dest_o->isPIObject()) continue;
c.dest_o->connectors.remove(src);
}
for (int i = 0; i < src->connections.size_s(); ++i)
src->connections[i].destroy();
src->connections.clear();
}
void PIObject::updateConnectors() {
//piCout << "*** updateConnectors" << this;
connectors.clear();
PIMutexLocker _ml(mutexObjects());
piForeach (PIObject * o, objects()) {
if (o == this) continue;
PIVector<__Connection> & oc(o->connections);
piForeach (__Connection & c, oc)
if (c.dest == this)
connectors << o;
}
}
void PIObject::postQueuedEvent(const PIObject::__QueuedEvent & e) {
mutex_queue.lock();
events_queue << e;
mutex_queue.unlock();
}
void * PIObject::toThis() const {
//piCout << ptrOffset() << (void*)this << (void*)((char*)this - ptrOffset());
return (void*)((char*)this - ptrOffset());
}
PIMutex & PIObject::__meta_mutex() {
static PIMutex ret;
return ret;
}
PIMap<uint, PIObject::__MetaData> & PIObject::__meta_data() {
static PIMap<uint, PIObject::__MetaData> ret;
return ret;
}
void PIObject::callQueuedEvents() {
mutex_queue.lock();
PIVector<__QueuedEvent> qe = events_queue;
events_queue.clear();
mutex_queue.unlock();
piForeachC (__QueuedEvent & e, qe) {
if (e.dest_o->thread_safe_) e.dest_o->mutex_.lock();
e.dest_o->emitter_ = e.src;
callAddrV(e.slot, e.dest, e.values.size_s(), e.values);
e.dest_o->emitter_ = 0;
if (e.dest_o->thread_safe_) e.dest_o->mutex_.unlock();
}
}
bool PIObject::findSuitableMethodV(const PIString & method, int args, int & ret_args, PIObject::__MetaFunc & ret) {
PIVector<__MetaFunc> ml = findEH(method);
if (ml.isEmpty()) {
piCoutObj << "Error: no such method \"" << method << "\"!";
return false;
}
int mfi = -1, ac = -1, mac = -1;
for (int i = 0; i < ml.size_s(); ++i) {
__MetaFunc & m(ml[i]);
int j = m.names.size_s();
if (mac < 0 || mac > j) mac = j;
if ((j <= args) && (ac < j)) {
ac = j;
mfi = i;
}
}
if (mfi < 0) {
piCoutObj << "Error: no such suitable method \"" << method << "\", need at least" << mac << "arguments!";
return false;
}
ret_args = ac;
ret = ml[mfi];
return true;
}
PIVector<PIObject * > & PIObject::objects() {
static PIVector<PIObject * > * ret = new PIVector<PIObject * >();
return *ret;
}
PIMutex & PIObject::mutexObjects() {
static PIMutex ret;
return ret;
}
void PIObject::callAddrV(void * slot, void * obj, int args, const PIVector<PIVariant> & vl) {
args = piMini(args, vl.size_s());
switch (args) {
case 0: ((void(*)(void *))slot)(obj); break;
case 1: ((void(*)(void * , const PIVariant & ))slot)(obj, vl[0]); break;
case 2: ((void(*)(void * , const PIVariant & , const PIVariant & ))slot)(obj, vl[0], vl[1]); break;
case 3: ((void(*)(void * , const PIVariant & , const PIVariant & , const PIVariant & ))slot)(obj, vl[0], vl[1], vl[2]); break;
case 4: ((void(*)(void * , const PIVariant & , const PIVariant & , const PIVariant & , const PIVariant & ))slot)(obj, vl[0], vl[1], vl[2], vl[3]); break;
default: break;
}
}
PIString PIObject::simplifyType(const char * a) {
PIString ret = PIStringAscii(a).trim();
int white = -1;
for (int i = 0; i < ret.size_s(); ++i) {
bool iw = ret[i] == ' ' || ret[i] == '\t' || ret[i] == '\r' || ret[i] == '\n';
//piCout << i << iw << white;
if (white < 0) {
if (iw) {
white = i;
continue;
}
} else {
if (!iw) {
ret.replace(white, i - white, " ");
i = white;
white = -1;
//piCout << i;
}
}
}
ret.replaceAll(" &", "&");
ret.replaceAll(" *", "*");
if (ret.startsWith("const ") && ret.endsWith("&"))
ret.cutLeft(6).cutRight(1).trim();
return ret;
}
bool PIObject::isPIObject(const PIObject * o) {
if (!o) return false;
return o->_signature_ == __PIOBJECT_SIGNATURE__;
}
void PIObject::dump(const PIString & line_prefix) const {
//printf("dump %s \"%s\"\n", className(), name().data());
PICout(PICoutManipulators::AddNewLine) << line_prefix << "class " << className() << " (" << (const void*)this << ", \"" << name() << "\") {";
PICout(PICoutManipulators::AddNewLine) << line_prefix << " scope: " << scopeList().join(" -> ");
PICout(PICoutManipulators::AddNewLine) << line_prefix << " properties {";
PICout(PICoutManipulators::AddNewLine) << line_prefix << " count: " << properties_.size_s();
//printf("dump %d properties\n", properties_.size());
piForeachC (PropertyHash p, properties_)
if (p.first != PIString("name").hash())
PICout(PICoutManipulators::AddNewLine) << line_prefix << " " << p.second.first << ": " << p.second.second;
//printf("dump %d properties ok\n", properties_.size());
PICout(PICoutManipulators::AddNewLine) << line_prefix << " }";
PICout(PICoutManipulators::AddNewLine) << line_prefix << " methods {";
__MetaData & ehd(__meta_data()[classNameID()]);
PICout(PICoutManipulators::AddNewLine) << line_prefix << " count: " << ehd.eh_func.size_s();
//printf("dump %d methods\n", ehd.eh_func.size());
piForeachC (__EHPair & eh, ehd.eh_func) {
PICout(PICoutManipulators::AddNewLine) << line_prefix << " " << eh.second.fullFormat();
}
//printf("dump %d methods ok\n", ehd.eh_func.size());
PICout(PICoutManipulators::AddNewLine) << line_prefix << " }";
PICout(PICoutManipulators::AddNewLine) << line_prefix << " connections {";
PICout(PICoutManipulators::AddNewLine) << line_prefix << " count: " << connections.size_s();
//printf("dump %d connections\n",connections.size());
piForeachC (__Connection & c, connections) {
PIObject * dst = c.dest_o;
__MetaFunc ef = methodEH(c.signal);
PIString src(c.event);
if (!ef.func_name.isEmpty())
src = ef.func_name + "(" + ef.arguments() + ")";
if (dst) {
__MetaFunc hf = dst->methodEH(c.slot);
if (hf.func_name.isEmpty()) hf.func_name = "[BROKEN]";
else hf.func_name += "(" + hf.arguments() + ")";
PICout(PICoutManipulators::AddNewLine) << line_prefix << " " << src << " -> " << dst->className() << " (" << c.dest << ", \"" << dst->name() << "\")::" << hf.func_name;
} else {
PICout(PICoutManipulators::AddNewLine) << line_prefix << " " << src << " -> " << "[lambda]";
}
}
//printf("dump %d connections ok\n",connections.size());
PICout(PICoutManipulators::AddNewLine) << line_prefix << " }";
PICout(PICoutManipulators::AddNewLine) << line_prefix << "}";
}
void dumpApplication() {
PIMutexLocker _ml(PIObject::mutexObjects());
//printf("dump application ...\n");
PIDateTime cd = PIDateTime::current();
PISystemInfo * pi = PISystemInfo::instance();
PICout(PICoutManipulators::AddNewLine) << "application {";
PICout(PICoutManipulators::AddNewLine) << " PIP version: " << PIPVersion();
PICout(PICoutManipulators::AddNewLine) << " OS name: \"" << pi->OS_name << "\"";
PICout(PICoutManipulators::AddNewLine) << " OS version: \"" << pi->OS_version << "\"";
PICout(PICoutManipulators::AddNewLine) << " processors: " << pi->processorsCount;
PICout(PICoutManipulators::AddNewLine) << " architecture: \"" << pi->architecture << "\"";
PICout(PICoutManipulators::AddNewLine) << " hostname: \"" << pi->hostname << "\"";
PICout(PICoutManipulators::AddNewLine) << " username: \"" << pi->user << "\"";
PICout(PICoutManipulators::AddNewLine) << " exec command: \"" << pi->execCommand << "\"";
PICout(PICoutManipulators::AddNewLine) << " started: " << pi->execDateTime.toString();
PICout(PICoutManipulators::AddNewLine) << " uptime: " << PITime::fromSystemTime(cd.toSystemTime() - pi->execDateTime.toSystemTime()).toString();
PICout(PICoutManipulators::AddNewLine) << " PIObjects {";
PICout(PICoutManipulators::AddNewLine) << " count: " << PIObject::objects().size_s();
piForeachC (PIObject * o, PIObject::objects())
o->dump(" ");
PICout(PICoutManipulators::AddNewLine) << " }";
PICout(PICoutManipulators::AddNewLine) << "}";
//printf("dump application done\n");
}
#ifndef FREERTOS
bool dumpApplicationToFile(const PIString & path) {
PIFile f(path + "_tmp");
f.setName("__S__DumpFile");
f.clear();
if (!f.open(PIIODevice::WriteOnly)) return false;
bool ba = PICout::isBufferActive();
PICout::setBufferActive(true, true);
dumpApplication();
f << PICout::buffer();
f.close();
PICout::setBufferActive(ba, true);
PIFile::rename(path + "_tmp", path);
return true;
}
#endif
void PIObject::__MetaData::addScope(const PIString & s, uint shash) {
if (!scope_id.contains(shash)) {
scope_list << s;
scope_id << shash;
}
}
void PIObject::__Connection::destroy() {
#ifdef PIP_CXX11_SUPPORT
if (functor) delete functor;
functor = nullptr;
#endif
}

955
lib/main/core/piobject.h Normal file
View File

@@ -0,0 +1,955 @@
/*! \file piobject.h
* \brief Base object
*
* This file declare PIObject class and associated macros
*/
/*
PIP - Platform Independent Primitives
Object, base class of some PIP classes, provide EVENT -> EVENT_HANDLER mechanism
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PIOBJECT_H
#define PIOBJECT_H
#include "piinit.h"
#include "pivariant.h"
#include "pimutex.h"
#include "piset.h"
#include "piqueue.h"
#ifdef DOXYGEN
/// \relatesalso PIObject \brief you should use this macro after class declaration to use EVENT and EVENT_HANDLER and correct piCoutObj output
#define PIOBJECT(name)
/// \relatesalso PIObject \brief you should use this macro after class declaration to use EVENT and EVENT_HANDLER of parent class, and \a scopeList()
#define PIOBJECT_SUBCLASS(name, parent)
/// \relatesalso PIObject \brief declare event handler \"event\" with name \"name\" and return type \"ret\", ret name()
#define EVENT_HANDLER0(ret, name) ret name()
/// \relatesalso PIObject \brief declare event handler \"event\" with name \"name\" and return type \"ret\", ret name(type0 var0)
#define EVENT_HANDLER1(ret, name, type0, var0) ret name(type0 var0)
/// \relatesalso PIObject \brief declare event handler \"event\" with name \"name\" and return type \"ret\", ret name(type0 var0, type1 var1)
#define EVENT_HANDLER2(ret, name, type0, var0, type1, var1) ret name(type0 var0, type1 var1)
/// \relatesalso PIObject \brief declare event handler \"event\" with name \"name\" and return type \"ret\", ret name(type0 var0, type1 var1, type2 var2)
#define EVENT_HANDLER3(ret, name, type0, var0, type1, var1, type2, var2) ret name(type0 var0, type1 var1, type2 var2)
/// \relatesalso PIObject \brief declare event handler \"event\" with name \"name\" and return type \"ret\", ret name(type0 var0, type1 var1, type2 var2, type3 var3)
#define EVENT_HANDLER4(ret, name, type0, var0, type1, var1, type2, var2, type3, var3) ret name(type0 var0, type1 var1, type2 var2, type3 var3)
/// \relatesalso PIObject \brief EVENT_HANDLER is synonym of EVENT_HANDLER0
#define EVENT_HANDLER EVENT_HANDLER0
/// \relatesalso PIObject \brief declare virtual event handler \"event\" with name \"name\" and return type \"ret\", virtual ret name()
#define EVENT_VHANDLER0(ret, name) virtual ret name()
/// \relatesalso PIObject \brief declare virtual event handler \"event\" with name \"name\" and return type \"ret\", virtual ret name(type0 var0)
#define EVENT_VHANDLER1(ret, name, type0, var0) virtual ret name(type0 var0)
/// \relatesalso PIObject \brief declare virtual event handler \"event\" with name \"name\" and return type \"ret\", virtual ret name(type0 var0, type1 var1)
#define EVENT_VHANDLER2(ret, name, type0, var0, type1, var1) virtual ret name(type0 var0, type1 var1)
/// \relatesalso PIObject \brief declare virtual event handler \"event\" with name \"name\" and return type \"ret\", virtual ret name(type0 var0, type1 var1, type2 var2)
#define EVENT_VHANDLER3(ret, name, type0, var0, type1, var1, type2, var2) virtual ret name(type0 var0, type1 var1, type2 var2)
/// \relatesalso PIObject \brief declare virtual event handler \"event\" with name \"name\" and return type \"ret\", virtual ret name(type0 var0, type1 var1, type2 var2, type3 var3)
#define EVENT_VHANDLER4(ret, name, type0, var0, type1, var1, type2, var2, type3, var3) virtual ret name(type0 var0, type1 var1, type2 var2, type3 var3)
/// \relatesalso PIObject \brief EVENT_VHANDLER is synonym of EVENT_VHANDLER0
#define EVENT_VHANDLER EVENT_VHANDLER0
/// \relatesalso PIObject \brief declare event \"event\" with name \"name\", void name();
#define EVENT0(name) void name();
/// \relatesalso PIObject \brief declare event \"event\" with name \"name\", void name(type0 var0);
#define EVENT1(name, type0, var0) void name(type0 var0);
/// \relatesalso PIObject \brief declare event \"event\" with name \"name\", void name(type0 var0, type1 var1);
#define EVENT2(name, type0, var0, type1, var1) void name(type0 var0, type1 var1);
/// \relatesalso PIObject \brief declare event \"event\" with name \"name\", void name(type0 var0, type1 var1, type2 var2);
#define EVENT3(name, type0, var0, type1, var1, type2, var2) void name(type0 var0, type1 var1, type2 var2);
/// \relatesalso PIObject \brief declare event \"event\" with name \"name\", void name(type0 var0, type1 var1, type2 var2, type3 var3);
#define EVENT4(name, type0, var0, type1, var1, type2, var2, type3, var3) void name(type0 var0, type1 var1, type2 var2, type3 var3);
/// \relatesalso PIObject \brief EVENT is synonym of EVENT0
#define EVENT EVENT0
#define RAISE_EVENT0(src, event)
#define RAISE_EVENT1(src, event, v0)
#define RAISE_EVENT2(src, event, v0, v1)
#define RAISE_EVENT3(src, event, v0, v1, v2)
#define RAISE_EVENT4(src, event, v0, v1, v2, v3)
#define RAISE_EVENT RAISE_EVENT0
/// \relatesalso PIObject \brief connect event \"event\" from object \"src\" to event handler \"handler\". \"Event\" and \"handler\" must has equal argument lists.
#define CONNECTU(src, event, dest, handler)
/// \relatesalso PIObject \brief connect event \"event\" from object \"src\" to event handler \"handler\".
/// Event handler will be executed by \"performer\". \"Event\" and \"handler\" must has equal argument lists.
#define CONNECTU_QUEUED(src, event, dest, handler, performer)
/// \relatesalso PIObject \brief connect event \"event\" from object \"src\" to lambda-expression \"functor\". \"Event\" and \"functor\" must has equal argument lists.
#define CONNECTL(src, event, functor)
/// \relatesalso PIObject \brief connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" with check of event and handler exists
#define CONNECT0(ret, src, event, dest, handler)
/// \relatesalso PIObject \brief connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" with check of event and handler exists
#define CONNECT1(ret, type0, src, event, dest, handler)
/// \relatesalso PIObject \brief connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" with check of event and handler exists
#define CONNECT2(ret, type0, type1, src, event, dest, handler)
/// \relatesalso PIObject \brief connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" with check of event and handler exists
#define CONNECT3(ret, type0, type1, type2, src, event, dest, handler)
/// \relatesalso PIObject \brief connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" with check of event and handler exists
#define CONNECT4(ret, type0, type1, type2, type3, src, event, dest, handler)
/// \relatesalso PIObject \brief CONNECT is synonym of CONNECT0
#define CONNECT CONNECT0
/// \relatesalso PIObject \brief connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" without check of event exists
#define WEAK_CONNECT0(ret, src, event, dest, handler)
/// \relatesalso PIObject \brief connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" without check of event exists
#define WEAK_CONNECT1(ret, type0, src, event, dest, handler)
/// \relatesalso PIObject \brief connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" without check of event exists
#define WEAK_CONNECT2(ret, type0, type1, src, event, dest, handler)
/// \relatesalso PIObject \brief connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" without check of event exists
#define WEAK_CONNECT3(ret, type0, type1, type2, src, event, dest, handler)
/// \relatesalso PIObject \brief connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" without check of event exists
#define WEAK_CONNECT4(ret, type0, type1, type2, type3, src, event, dest, handler)
/// \relatesalso PIObject \brief WEAK_CONNECT is synonym of WEAK_CONNECT0
#define WEAK_CONNECT WEAK_CONNECT0
/// \relatesalso PIObject \brief piDisconnect event \"event\" from object \"src\" from event handler \"handler\" with return type \"ret\" from object \"dest\"
#define DISCONNECT0(ret, src, event, dest, handler)
/// \relatesalso PIObject \brief piDisconnect event \"event\" from object \"src\" from event handler \"handler\" with return type \"ret\" from object \"dest\"
#define DISCONNECT1(ret, type0, src, event, dest, handler)
/// \relatesalso PIObject \brief piDisconnect event \"event\" from object \"src\" from event handler \"handler\" with return type \"ret\" from object \"dest\"
#define DISCONNECT2(ret, type0, type1, src, event, dest, handler)
/// \relatesalso PIObject \brief piDisconnect event \"event\" from object \"src\" from event handler \"handler\" with return type \"ret\" from object \"dest\"
#define DISCONNECT3(ret, type0, type1, type2, src, event, dest, handler)
/// \relatesalso PIObject \brief piDisconnect event \"event\" from object \"src\" from event handler \"handler\" with return type \"ret\" from object \"dest\"
#define DISCONNECT4(ret, type0, type1, type2, type3, src, event, dest, handler)
/// \relatesalso PIObject \brief DISCONNECT is synonym of DISCONNECT0
#define DISCONNECT DISCONNECT0
/// \relatesalso PIObject \brief Returns pointer to events handler \"handler\"
#define HANDLER(handler)
#define PIOBJECT(name)
#define PIOBJECT_SUBCLASS(name)
#else
#define _PI_STR(x) #x
#define _PI_SSTR(x) _PI_STR(x)
#define LOCATION __FILE__ ":" _PI_SSTR(__LINE__)
#ifdef CC_GCC
# define __PTYPE(t) typename __PIVariantTypeInfo__<t>::PureType
#else
# define __PTYPE(t) __PIVariantTypeInfo__<t>::PureType
#endif
#define __VVALUE(t, v) v.value< __PTYPE(t) >()
//printf("base_init %s id=%d (%d) pid=%d (%d) ...\n", #name, id, eh.eh_func.size(), pid, ehp.eh_func.size());
//printf("base_init %s id=%d (%d) pid=%d (%d) ok\n", #name, id, eh.eh_func.size(), pid, ehp.eh_func.size());
//printf("parent_init %s::%s id=%d (%d) pid=%d (%d) ...\n", __classNameS().dataAscii(), #name, id, eh.eh_func.size(), pid, ehp.eh_func.size());
//printf("parent_init %s::%s id=%d (%d) pid=%d (%d) ok\n", __classNameS().dataAscii(), #name, id, eh.eh_func.size(), pid, ehp.eh_func.size());
#define PIOBJECT(name) \
protected: \
typedef name __PIObject__; \
public: \
static const PIString __classNameS() {static PIString ret = PIStringAscii(#name); return ret;} \
static uint __classNameIDS() {static uint ret = PIStringAscii(#name).hash(); return ret;} \
virtual const char * className() const {return #name;} \
virtual uint classNameID() const {static uint ret = PIStringAscii(#name).hash(); return ret;} \
private: \
virtual int ptrOffset() const {name * o = (name*)100; return int(llong((PIObject*)o) - llong(o));} \
class __BaseInitializer__ { \
public: \
__BaseInitializer__() { \
uint pid = PIObject::__classNameIDS(); \
if (pid == 0) return; \
uint id = __classNameIDS(); \
PIMutexLocker ml(__meta_mutex()); \
if (__meta_data().contains(id)) return; \
__meta_data()[pid]; \
__meta_data()[id]; \
__MetaData & ehp(__meta_data()[pid]); \
__MetaData & eh(__meta_data()[id]); \
eh.eh_set << ehp.eh_set; \
eh.eh_func << ehp.eh_func; \
eh.addScope(__classNameS(), id); \
} \
}; \
__BaseInitializer__ __base_init__;
#define PIOBJECT_PARENT(name) \
class __ParentInitializer__ { \
public: \
__ParentInitializer__() { \
uint pid = name::__classNameIDS(); \
if (pid == 0) return; \
uint id = __classNameIDS(); \
PIMutexLocker ml(__meta_mutex()); \
__MetaData & eh(__meta_data()[id]); \
if (eh.scope_id.contains(pid)) return; \
__MetaData ehp(__meta_data().value(pid)); \
eh.eh_set << ehp.eh_set; \
eh.eh_func << ehp.eh_func; \
eh.scope_id = ehp.scope_id; \
eh.scope_list = ehp.scope_list; \
eh.addScope(__classNameS(), id); \
} \
}; \
__ParentInitializer__ __parent_init__; \
public: \
virtual const char * parentClassName() const {return #name;} \
typedef name __Parent__; \
private:
#define PIOBJECT_SUBCLASS(name, parent) PIOBJECT(name) PIOBJECT_PARENT(parent)
#define EH_INIT0(ret, name) \
class __##name##0_Initializer__ { \
public: \
__##name##0_Initializer__() { \
PIMutexLocker ml(__meta_mutex()); \
__MetaData & eh(__meta_data()[__classNameIDS()]); \
void * fp = (void*)(ret(*)(void*))__stat_eh_##name##__; \
void * fpV = fp; \
if (eh.eh_set[fp]) return; \
eh.eh_set << fp; \
__MetaFunc & f(eh.eh_func[fp]); \
f.scope = __classNameS(); \
f.func_name = PIStringAscii(#name); \
f.addr = fp; \
f.addrV = fpV; \
f.type_ret = PIStringAscii(#ret); \
} \
}; \
__##name##0_Initializer__ __##name##0_init__; \
#define EH_INIT1(ret, name, a0, n0) \
class __##name##1##n0##_Initializer__ { \
public: \
__##name##1##n0##_Initializer__() { \
PIMutexLocker ml(__meta_mutex()); \
__MetaData & eh(__meta_data()[__classNameIDS()]); \
void * fp = (void*)(ret(*)(void*, a0))__stat_eh_##name##__; \
void * fpV = (void*)(ret(*)(void*, const PIVariant &))__stat_eh_v_##name##__; \
if (eh.eh_set[fp]) return; \
eh.eh_set << fp; \
__MetaFunc & f(eh.eh_func[fp]); \
f.scope = __classNameS(); \
f.func_name = PIStringAscii(#name); \
f.addr = fp; \
f.addrV = fpV; \
f.type_ret = PIStringAscii(#ret); \
f.types << PIObject::simplifyType(#a0); \
f.names << PIStringAscii(#n0); \
} \
}; \
__##name##1##n0##_Initializer__ __##name##1##n0##_init__; \
#define EH_INIT2(ret, name, a0, n0, a1, n1) \
class __##name##2##n0##n1##_Initializer__ { \
public: \
__##name##2##n0##n1##_Initializer__() { \
PIMutexLocker ml(__meta_mutex()); \
__MetaData & eh(__meta_data()[__classNameIDS()]); \
void * fp = (void*)(ret(*)(void*, a0, a1))__stat_eh_##name##__; \
void * fpV = (void*)(ret(*)(void*, const PIVariant &, const PIVariant &))__stat_eh_v_##name##__; \
if (eh.eh_set[fp]) return; \
eh.eh_set << fp; \
__MetaFunc & f(eh.eh_func[fp]); \
f.scope = __classNameS(); \
f.func_name = PIStringAscii(#name); \
f.addr = fp; \
f.addrV = fpV; \
f.type_ret = PIStringAscii(#ret); \
f.types << PIObject::simplifyType(#a0) << PIObject::simplifyType(#a1); \
f.names << PIStringAscii(#n0) << PIStringAscii(#n1); \
} \
}; \
__##name##2##n0##n1##_Initializer__ __##name##2##n0##n1##_init__; \
#define EH_INIT3(ret, name, a0, n0, a1, n1, a2, n2) \
class __##name##3##n0##n1##n2##_Initializer__ { \
public: \
__##name##3##n0##n1##n2##_Initializer__() { \
PIMutexLocker ml(__meta_mutex()); \
__MetaData & eh(__meta_data()[__classNameIDS()]); \
void * fp = (void*)(ret(*)(void*, a0, a1, a2))__stat_eh_##name##__; \
void * fpV = (void*)(ret(*)(void*, const PIVariant &, const PIVariant &, const PIVariant &))__stat_eh_v_##name##__; \
if (eh.eh_set[fp]) return; \
eh.eh_set << fp; \
__MetaFunc & f(eh.eh_func[fp]); \
f.scope = __classNameS(); \
f.func_name = PIStringAscii(#name); \
f.addr = fp; \
f.addrV = fpV; \
f.type_ret = PIStringAscii(#ret); \
f.types << PIObject::simplifyType(#a0) << PIObject::simplifyType(#a1) << PIObject::simplifyType(#a2); \
f.names << PIStringAscii(#n0) << PIStringAscii(#n1) << PIStringAscii(#n2); \
} \
}; \
__##name##3##n0##n1##n2##_Initializer__ __##name##3##n0##n1##n2##_init__; \
#define EH_INIT4(ret, name, a0, n0, a1, n1, a2, n2, a3, n3) \
class __##name##4##n0##n1##n2##n3##_Initializer__ { \
public: \
__##name##4##n0##n1##n2##n3##_Initializer__() { \
PIMutexLocker ml(__meta_mutex()); \
__MetaData & eh(__meta_data()[__classNameIDS()]); \
void * fp = (void*)(ret(*)(void*, a0, a1, a2, a3))__stat_eh_##name##__; \
void * fpV = (void*)(ret(*)(void*, const PIVariant &, const PIVariant &, const PIVariant &, const PIVariant &))__stat_eh_v_##name##__; \
if (eh.eh_set[fp]) return; \
eh.eh_set << fp; \
__MetaFunc & f(eh.eh_func[fp]); \
f.scope = __classNameS(); \
f.func_name = PIStringAscii(#name); \
f.addr = fp; \
f.addrV = fpV; \
f.type_ret = PIStringAscii(#ret); \
f.types << PIObject::simplifyType(#a0) << PIObject::simplifyType(#a1) << PIObject::simplifyType(#a2) << PIObject::simplifyType(#a3); \
f.names << PIStringAscii(#n0) << PIStringAscii(#n1) << PIStringAscii(#n2) << PIStringAscii(#n3); \
} \
}; \
__##name##4##n0##n1##n2##n3##_Initializer__ __##name##4##n0##n1##n2##n3##_init__; \
#define EVENT_HANDLER0(ret, name) \
EH_INIT0(ret, name) \
static ret __stat_eh_##name##__(void * __o__) {return ((__PIObject__*)__o__)->name();} \
ret name()
#define EVENT_HANDLER1(ret, name, a0, n0) \
EH_INIT1(ret, name, a0, n0) \
static ret __stat_eh_##name##__(void * __o__, a0 n0) {return ((__PIObject__*)__o__)->name(n0);} \
static ret __stat_eh_v_##name##__(void * __o__, const PIVariant & v0) { \
__PTYPE(a0) tv0 = __VVALUE(a0, v0); \
return ((__PIObject__*)__o__)->name(tv0);} \
ret name(a0 n0)
#define EVENT_HANDLER2(ret, name, a0, n0, a1, n1) \
EH_INIT2(ret, name, a0, n0, a1, n1) \
static ret __stat_eh_##name##__(void * __o__, a0 n0, a1 n1) {return ((__PIObject__*)__o__)->name(n0, n1);} \
static ret __stat_eh_v_##name##__(void * __o__, const PIVariant & v0, const PIVariant & v1) { \
__PTYPE(a0) tv0 = __VVALUE(a0, v0); \
__PTYPE(a1) tv1 = __VVALUE(a1, v1); \
return ((__PIObject__*)__o__)->name(tv0, tv1);} \
ret name(a0 n0, a1 n1)
#define EVENT_HANDLER3(ret, name, a0, n0, a1, n1, a2, n2) \
EH_INIT3(ret, name, a0, n0, a1, n1, a2, n2) \
static ret __stat_eh_##name##__(void * __o__, a0 n0, a1 n1, a2 n2) {return ((__PIObject__*)__o__)->name(n0, n1, n2);} \
static ret __stat_eh_v_##name##__(void * __o__, const PIVariant & v0, const PIVariant & v1, const PIVariant & v2) { \
__PTYPE(a0) tv0 = __VVALUE(a0, v0); \
__PTYPE(a1) tv1 = __VVALUE(a1, v1); \
__PTYPE(a2) tv2 = __VVALUE(a2, v2); \
return ((__PIObject__*)__o__)->name(tv0, tv1, tv2);} \
ret name(a0 n0, a1 n1, a2 n2)
#define EVENT_HANDLER4(ret, name, a0, n0, a1, n1, a2, n2, a3, n3) \
EH_INIT4(ret, name, a0, n0, a1, n1, a2, n2, a3, n3) \
static ret __stat_eh_##name##__(void * __o__, a0 n0, a1 n1, a2 n2, a3 n3) {return ((__PIObject__*)__o__)->name(n0, n1, n2, n3);} \
static ret __stat_eh_v_##name##__(void * __o__, const PIVariant & v0, const PIVariant & v1, const PIVariant & v2, const PIVariant & v3) { \
__PTYPE(a0) tv0 = __VVALUE(a0, v0); \
__PTYPE(a1) tv1 = __VVALUE(a1, v1); \
__PTYPE(a2) tv2 = __VVALUE(a2, v2); \
__PTYPE(a3) tv3 = __VVALUE(a3, v3); \
return ((__PIObject__*)__o__)->name(tv0, tv1, tv2, tv3);} \
ret name(a0 n0, a1 n1, a2 n2, a3 n3)
#define EVENT_HANDLER EVENT_HANDLER0
#define EVENT_VHANDLER0(ret, name) \
EH_INIT0(ret, name) \
static ret __stat_eh_##name##__(void * __o__) {return ((__PIObject__*)__o__)->name();} \
virtual ret name()
#define EVENT_VHANDLER1(ret, name, a0, n0) \
EH_INIT1(ret, name, a0, n0) \
static ret __stat_eh_##name##__(void * __o__, a0 n0) {return ((__PIObject__*)__o__)->name(n0);} \
static ret __stat_eh_v_##name##__(void * __o__, const PIVariant & v0) {return ((__PIObject__*)__o__)->name(__VVALUE(a0, v0));} \
virtual ret name(a0 n0)
#define EVENT_VHANDLER2(ret, name, a0, n0, a1, n1) \
EH_INIT2(ret, name, a0, n0, a1, n1) \
static ret __stat_eh_##name##__(void * __o__, a0 n0, a1 n1) {return ((__PIObject__*)__o__)->name(n0, n1);} \
static ret __stat_eh_v_##name##__(void * __o__, const PIVariant & v0, const PIVariant & v1) {return ((__PIObject__*)__o__)->name(__VVALUE(a0, v0), __VVALUE(a1, v1));} \
virtual ret name(a0 n0, a1 n1)
#define EVENT_VHANDLER3(ret, name, a0, n0, a1, n1, a2, n2) \
EH_INIT3(ret, name, a0, n0, a1, n1, a2, n2) \
static ret __stat_eh_##name##__(void * __o__, a0 n0, a1 n1, a2 n2) {return ((__PIObject__*)__o__)->name(n0, n1, n2);} \
static ret __stat_eh_v_##name##__(void * __o__, const PIVariant & v0, const PIVariant & v1, const PIVariant & v2) {return ((__PIObject__*)__o__)->name(__VVALUE(a0, v0), __VVALUE(a1, v1), __VVALUE(a2, v2));} \
virtual ret name(a0 n0, a1 n1, a2 n2)
#define EVENT_VHANDLER4(ret, name, a0, n0, a1, n1, a2, n2, a3, n3) \
EH_INIT4(ret, name, a0, n0, a1, n1, a2, n2, a3, n3) \
static ret __stat_eh_##name##__(void * __o__, a0 n0, a1 n1, a2 n2, a3 n3) {return ((__PIObject__*)__o__)->name(n0, n1, n2, n3);} \
static ret __stat_eh_v_##name##__(void * __o__, const PIVariant & v0, const PIVariant & v1, const PIVariant & v2, const PIVariant & v3) {return ((__PIObject__*)__o__)->name(__VVALUE(a0, v0), __VVALUE(a1, v1), __VVALUE(a2, v2), __VVALUE(a3, v3));} \
virtual ret name(a0 n0, a1 n1, a2 n2, a3 n3)
#define EVENT_VHANDLER EVENT_VHANDLER0
#define EVENT0(name) EVENT_HANDLER0(void, name) {static uint eid = PIStringAscii(#name).hash(); PIObject::raiseEvent(this, eid);}
#define EVENT1(name, a0, n0) EVENT_HANDLER1(void, name, a0, n0) {static uint eid = PIStringAscii(#name).hash(); PIObject::raiseEvent(this, eid, n0);}
#define EVENT2(name, a0, n0, a1, n1) EVENT_HANDLER2(void, name, a0, n0, a1, n1) {static uint eid = PIStringAscii(#name).hash(); PIObject::raiseEvent(this, eid, n0, n1);}
#define EVENT3(name, a0, n0, a1, n1, a2, n2) EVENT_HANDLER3(void, name, a0, n0, a1, n1, a2, n2) {static uint eid = PIStringAscii(#name).hash(); PIObject::raiseEvent(this, eid, n0, n1, n2);}
#define EVENT4(name, a0, n0, a1, n1, a2, n2, a3, n3) EVENT_HANDLER4(void, name, a0, n0, a1, n1, a2, n2, a3, n3) {static uint eid = PIStringAscii(#name).hash(); PIObject::raiseEvent(this, eid, n0, n1, n2, n3);}
#define EVENT EVENT0
#define RAISE_EVENT0(src, event) (src)->event();
#define RAISE_EVENT1(src, event, v0) (src)->event(v0);
#define RAISE_EVENT2(src, event, v0, v1) (src)->event(v0, v1);
#define RAISE_EVENT3(src, event, v0, v1, v2) (src)->event(v0, v1, v2);
#define RAISE_EVENT4(src, event, v0, v1, v2, v3) (src)->event(v0, v1, v2, v3);
#define RAISE_EVENT RAISE_EVENT0
#define CONNECTU(src, event, dest, handler) PIObject::piConnectU(src, PIStringAscii(#event), dest, dest, PIStringAscii(#handler), LOCATION);
#define CONNECTU_QUEUED(src, event, dest, handler, performer) PIObject::piConnectU(src, PIStringAscii(#event), dest, dest, PIStringAscii(#handler), LOCATION, performer);
#ifdef PIP_CXX11_SUPPORT
# define CONNECTL(src, event, functor) PIObject::piConnectLS(src, PIStringAscii(#event), PIObject::__newFunctor(&(src)->__stat_eh_##event##__, functor), LOCATION);
#endif
#define CONNECT0(ret, src, event, dest, handler) PIObject::piConnect(src, PIStringAscii(#event), dest, dest, (void*)(ret(*)(void*))(&(dest)->__stat_eh_##handler##__), (void*)(void(*)(void*))(&(src)->__stat_eh_##event##__), 0, LOCATION);
#define CONNECT1(ret, a0, src, event, dest, handler) PIObject::piConnect(src, PIStringAscii(#event), dest, dest, (void*)(ret(*)(void*, a0))(&(dest)->__stat_eh_##handler##__), (void*)(void(*)(void*, a0))(&(src)->__stat_eh_##event##__), 1, LOCATION);
#define CONNECT2(ret, a0, a1, src, event, dest, handler) PIObject::piConnect(src, PIStringAscii(#event), dest, dest, (void*)(ret(*)(void*, a0, a1))(&(dest)->__stat_eh_##handler##__), (void*)(void(*)(void*, a0, a1))(&(src)->__stat_eh_##event##__), 2, LOCATION);
#define CONNECT3(ret, a0, a1, a2, src, event, dest, handler) PIObject::piConnect(src, PIStringAscii(#event), dest, dest, (void*)(ret(*)(void*, a0, a1, a2))(&(dest)->__stat_eh_##handler##__), (void*)(void(*)(void*, a0, a1, a2))(&(src)->__stat_eh_##event##__), 3, LOCATION);
#define CONNECT4(ret, a0, a1, a2, a3, src, event, dest, handler) PIObject::piConnect(src, PIStringAscii(#event), dest, dest, (void*)(ret(*)(void*, a0, a1, a2, a3))(&(dest)->__stat_eh_##handler##__), (void*)(void(*)(void*, a0, a1, a2, a3))(&(src)->__stat_eh_##event##__), 4, LOCATION);
#define CONNECT CONNECT0
#define WEAK_CONNECT0(ret, src, event, dest, handler) PIObject::piConnect(src, PIStringAscii(#event), dest, dest, (void*)(ret(*)(void*))(&(dest)->__stat_eh_##handler##__), 0, 0, LOCATION);
#define WEAK_CONNECT1(ret, a0, src, event, dest, handler) PIObject::piConnect(src, PIStringAscii(#event), dest, dest, (void*)(ret(*)(void*, a0))(&(dest)->__stat_eh_##handler##__), 0, 1, LOCATION);
#define WEAK_CONNECT2(ret, a0, a1, src, event, dest, handler) PIObject::piConnect(src, PIStringAscii(#event), dest, dest, (void*)(ret(*)(void*, a0, a1))(&(dest)->__stat_eh_##handler##__), 0, 2, LOCATION);
#define WEAK_CONNECT3(ret, a0, a1, a2, src, event, dest, handler) PIObject::piConnect(src, PIStringAscii(#event), dest, dest, (void*)(ret(*)(void*, a0, a1, a2))(&(dest)->__stat_eh_##handler##__), 0, 3, LOCATION);
#define WEAK_CONNECT4(ret, a0, a1, a2, a3, src, event, dest, handler) PIObject::piConnect(src, PIStringAscii(#event), dest, dest, (void*)(ret(*)(void*, a0, a1, a2, a3))(&(dest)->__stat_eh_##handler##__), 0, 4, LOCATION);
#define WEAK_CONNECT WEAK_CONNECT0
#define DISCONNECT0(ret, src, event, dest, handler) PIObject::piDisconnect(src, PIStringAscii(#event), dest, (void*)(ret(*)(void*))(&(dest)->__stat_eh_##handler##__));
#define DISCONNECT1(ret, a0, src, event, dest, handler) PIObject::piDisconnect(src, PIStringAscii(#event), dest, (void*)(ret(*)(void*, a0))(&(dest)->__stat_eh_##handler##__));
#define DISCONNECT2(ret, a0, a1, src, event, dest, handler) PIObject::piDisconnect(src, PIStringAscii(#event), dest, (void*)(ret(*)(void*, a0, a1))(&(dest)->__stat_eh_##handler##__));
#define DISCONNECT3(ret, a0, a1, a2, src, event, dest, handler) PIObject::piDisconnect(src, PIStringAscii(#event), dest, (void*)(ret(*)(void*, a0, a1, a2))(&(dest)->__stat_eh_##handler##__));
#define DISCONNECT4(ret, a0, a1, a2, a3, src, event, dest, handler) PIObject::piDisconnect(src, PIStringAscii(#event), dest, (void*)(ret(*)(void*, a0, a1, a2, a3))(&(dest)->__stat_eh_##handler##__));
#define DISCONNECT DISCONNECT0
#define HANDLER(handler) __stat_eh_##handler##__
#define __PIOBJECT_SIGNATURE__ 0xabcdbadc
#endif
typedef void (*Handler)(void * );
class PIP_EXPORT PIObject {
friend class PIObjectManager;
friend void dumpApplication();
typedef PIObject __PIObject__;
typedef void __Parent__;
friend class PIIntrospection;
public:
//! Contructs PIObject with name "name"
explicit PIObject(const PIString & name = PIString());
virtual ~PIObject();
private:
explicit PIObject(const PIObject & );
void operator =(const PIObject & );
uint _signature_;
public:
//! Returns object name
PIString name() const {return property(PIStringAscii("name")).toString();}
//! Returns object class name
virtual const char * className() const {return "PIObject";}
virtual uint classNameID() const {static uint ret = PIStringAscii("PIObject").hash(); return ret;}
static const PIString __classNameS() {return PIStringAscii("PIObject");}
static uint __classNameIDS() {static uint ret = PIStringAscii("PIObject").hash(); return ret;}
//! Returns parent object class name
virtual const char * parentClassName() const {return "";}
//! Return if debug of this object is active
bool debug() const {return property(PIStringAscii("debug")).toBool();}
//! Set object name
void setName(const PIString & name) {setProperty(PIStringAscii("name"), name);}
void setName(const char * name) {setName(PIStringAscii(name));}
//! Set object debug active
void setDebug(bool debug) {setProperty(PIStringAscii("debug"), debug);}
//! Returns properties of the object
PIMap<PIString, PIVariant> properties() const;
//! Returns properties count of the object
int propertiesCount() const {return properties_.size_s();}
//! Returns property with name "name"
PIVariant property(const PIString & name) const {return properties_.value(name.hash(), Property(PIString(), PIVariant())).second;}
PIVariant property(const char * name) const {return property(PIStringAscii(name));}
//! Set property with name "name" to "value". If there is no such property in object it will be added
void setProperty(const PIString & name, const PIVariant & value) {properties_[name.hash()] = Property(name, value); propertyChanged(name);}
void setProperty(const char * name, const PIVariant & value) {setProperty(PIStringAscii(name), value);}
//! Returns if property with name "name" exists
bool isPropertyExists(const PIString & name) const {return properties_.contains(name.hash());}
bool isPropertyExists(const char * name) const {return isPropertyExists(PIStringAscii(name));}
void setThreadSafe(bool yes) {thread_safe_ = yes;}
bool isThreadSafe() const {return thread_safe_;}
bool execute(const PIString & method, const PIVector<PIVariant> & vl);
bool execute(const PIString & method) {return execute(method, PIVector<PIVariant>());}
bool execute(const PIString & method, const PIVariant & v0) {return execute(method, PIVector<PIVariant>() << v0);}
bool execute(const PIString & method, const PIVariant & v0, const PIVariant & v1) {return execute(method, PIVector<PIVariant>() << v0 << v1);}
bool execute(const PIString & method, const PIVariant & v0, const PIVariant & v1, const PIVariant & v2) {return execute(method, PIVector<PIVariant>() << v0 << v1 << v2);}
bool execute(const PIString & method, const PIVariant & v0, const PIVariant & v1, const PIVariant & v2, const PIVariant & v3) {return execute(method, PIVector<PIVariant>() << v0 << v1 << v2 << v3);}
bool executeQueued(PIObject * performer, const PIString & method, const PIVector<PIVariant> & vl);
bool executeQueued(PIObject * performer, const PIString & method) {return executeQueued(performer, method, PIVector<PIVariant>());}
bool executeQueued(PIObject * performer, const PIString & method, const PIVariant & v0) {return executeQueued(performer, method, PIVector<PIVariant>() << v0);}
bool executeQueued(PIObject * performer, const PIString & method, const PIVariant & v0, const PIVariant & v1) {return executeQueued(performer, method, PIVector<PIVariant>() << v0 << v1);}
bool executeQueued(PIObject * performer, const PIString & method, const PIVariant & v0, const PIVariant & v1, const PIVariant & v2) {return executeQueued(performer, method, PIVector<PIVariant>() << v0 << v1 << v2);}
bool executeQueued(PIObject * performer, const PIString & method, const PIVariant & v0, const PIVariant & v1, const PIVariant & v2, const PIVariant & v3) {return executeQueued(performer, method, PIVector<PIVariant>() << v0 << v1 << v2 << v3);}
static bool execute(PIObject * o, const PIString & method, const PIVector<PIVariant> & vl) {return o->execute(method, vl);}
static bool execute(PIObject * o, const PIString & method) {return execute(o, method, PIVector<PIVariant>());}
static bool execute(PIObject * o, const PIString & method, const PIVariant & v0) {return execute(o, method, PIVector<PIVariant>() << v0);}
static bool execute(PIObject * o, const PIString & method, const PIVariant & v0, const PIVariant & v1) {return execute(o, method, PIVector<PIVariant>() << v0 << v1);}
static bool execute(PIObject * o, const PIString & method, const PIVariant & v0, const PIVariant & v1, const PIVariant & v2) {return execute(o, method, PIVector<PIVariant>() << v0 << v1 << v2);}
static bool execute(PIObject * o, const PIString & method, const PIVariant & v0, const PIVariant & v1, const PIVariant & v2, const PIVariant & v3) {return execute(o, method, PIVector<PIVariant>() << v0 << v1 << v2 << v3);}
static bool executeQueued(PIObject * o, PIObject * performer, const PIString & method, const PIVector<PIVariant> & vl) {return o->executeQueued(performer, method, vl);}
static bool executeQueued(PIObject * o, PIObject * performer, const PIString & method) {return executeQueued(o, performer, method, PIVector<PIVariant>());}
static bool executeQueued(PIObject * o, PIObject * performer, const PIString & method, const PIVariant & v0) {return executeQueued(o, performer, method, PIVector<PIVariant>() << v0);}
static bool executeQueued(PIObject * o, PIObject * performer, const PIString & method, const PIVariant & v0, const PIVariant & v1) {return executeQueued(o, performer, method, PIVector<PIVariant>() << v0 << v1);}
static bool executeQueued(PIObject * o, PIObject * performer, const PIString & method, const PIVariant & v0, const PIVariant & v1, const PIVariant & v2) {return executeQueued(o, performer, method, PIVector<PIVariant>() << v0 << v1 << v2);}
static bool executeQueued(PIObject * o, PIObject * performer, const PIString & method, const PIVariant & v0, const PIVariant & v1, const PIVariant & v2, const PIVariant & v3) {return executeQueued(o, performer, method, PIVector<PIVariant>() << v0 << v1 << v2 << v3);}
void dump(const PIString & line_prefix = PIString()) const;
PIStringList scopeList() const;
PIStringList methodsEH() const;
bool isMethodEHContains(const PIString & name) const;
PIString methodEHArguments(const PIString & name) const;
PIString methodEHFullFormat(const PIString & name) const;
PIString methodEHFromAddr(const void * addr) const;
// / Direct connect
static void piConnect(PIObject * src, const PIString & sig, PIObject * dest_o, void * dest, void * ev_h, void * e_h, int args, const char * loc);
static bool piConnectU(PIObject * src, const PIString & sig, PIObject * dest_o, void * dest, const PIString & hname, const char * loc, PIObject * performer = 0);
#ifdef PIP_CXX11_SUPPORT
static bool piConnectLS(PIObject * src, const PIString & sig, std::function<void()> * f, const char * loc);
template <typename INPUT, typename... TYPES>
static std::function<void()> * __newFunctor(void(*stat_handler)(void*,TYPES...), INPUT functor) {
return (std::function<void()>*)(new std::function<void(TYPES...)>(functor));
}
#endif
// / Through names and mixed
static void piConnect(const PIString & src, const PIString & sig, void * dest, void * ev_h);
static void piConnect(PIObject * src, const PIString & sig, const PIString & dest, void * ev_h);
static void piConnect(const PIString & src, const PIString & sig, const PIString & dest, void * ev_h);
static void piDisconnect(PIObject * src, const PIString & sig, PIObject * dest, void * ev_h);
static void piDisconnect(PIObject * src, const PIString & sig, PIObject * dest);
//! Disconnect object "src" from all connections with event name "sig"
static void piDisconnect(PIObject * src, const PIString & sig);
//! Disconnect object "src" from all connections, i.e. all connections where object "src" is emitter
static void piDisconnect(PIObject * src);
// / Raise events
static void raiseEvent(PIObject * sender, const uint eventID) {
for (int j = 0; j < sender->connections.size_s(); ++j) {
__Connection i(sender->connections[j]);
if (i.eventID != eventID) continue;
#ifdef PIP_CXX11_SUPPORT
if (i.functor) {
(*(i.functor))();
} else {
#endif
if (i.performer) {
i.performer->postQueuedEvent(__QueuedEvent(i.slot, i.dest, i.dest_o, sender));
} else {
bool ts = sender->thread_safe_;
if (ts) i.dest_o->mutex_.lock();
i.dest_o->emitter_ = sender;
((void( *)(void * ))i.slot)(i.dest);
if (i.dest_o->isPIObject()) {
i.dest_o->emitter_ = 0;
if (ts) i.dest_o->mutex_.unlock();
}
}
#ifdef PIP_CXX11_SUPPORT
}
#endif
if (!sender->isPIObject()) break;
}
}
template <typename T0>
static void raiseEvent(PIObject * sender, const uint eventID, const T0 & v0 = T0()) {
for (int j = 0; j < sender->connections.size_s(); ++j) {
__Connection i(sender->connections[j]);
if (i.eventID != eventID) continue;
#ifdef PIP_CXX11_SUPPORT
if (i.functor) {
(*((std::function<void(T0)>*)i.functor))(v0);
} else {
#endif
if (i.performer) {
PIVector<PIVariant> vl;
if (i.args_count > 0) vl << PIVariant::fromValue(v0);
i.performer->postQueuedEvent(__QueuedEvent(i.slot, i.dest, i.dest_o, sender, vl));
} else {
bool ts = sender->thread_safe_;
if (ts) i.dest_o->mutex_.lock();
i.dest_o->emitter_ = sender;
if (i.args_count == 0) ((void(*)(void *))i.slot)(i.dest);
else ((void(*)(void * , T0))i.slot)(i.dest, v0);
if (i.dest_o->isPIObject()) {
i.dest_o->emitter_ = 0;
if (ts) i.dest_o->mutex_.unlock();
}
}
#ifdef PIP_CXX11_SUPPORT
}
#endif
if (!sender->isPIObject()) break;
}
}
template <typename T0, typename T1>
static void raiseEvent(PIObject * sender, const uint eventID, const T0 & v0 = T0(), const T1 & v1 = T1()) {
for (int j = 0; j < sender->connections.size_s(); ++j) {
__Connection i(sender->connections[j]);
if (i.eventID != eventID) continue;
#ifdef PIP_CXX11_SUPPORT
if (i.functor) {
(*((std::function<void(T0, T1)>*)i.functor))(v0, v1);
} else {
#endif
if (i.performer) {
PIVector<PIVariant> vl;
if (i.args_count > 0) vl << PIVariant::fromValue(v0);
if (i.args_count > 1) vl << PIVariant::fromValue(v1);
i.performer->postQueuedEvent(__QueuedEvent(i.slot, i.dest, i.dest_o, sender, vl));
} else {
bool ts = sender->thread_safe_;
if (ts) i.dest_o->mutex_.lock();
i.dest_o->emitter_ = sender;
switch (i.args_count) {
case 0: ((void(*)(void *))i.slot)(i.dest); break;
case 1: ((void(*)(void * , T0))i.slot)(i.dest, v0); break;
default: ((void(*)(void * , T0, T1))i.slot)(i.dest, v0, v1); break;
}
if (i.dest_o->isPIObject()) {
i.dest_o->emitter_ = 0;
if (ts) i.dest_o->mutex_.unlock();
}
}
#ifdef PIP_CXX11_SUPPORT
}
#endif
if (!sender->isPIObject()) break;
}
}
template <typename T0, typename T1, typename T2>
static void raiseEvent(PIObject * sender, const uint eventID, const T0 & v0 = T0(), const T1 & v1 = T1(), const T2 & v2 = T2()) {
for (int j = 0; j < sender->connections.size_s(); ++j) {
__Connection i(sender->connections[j]);
if (i.eventID != eventID) continue;
#ifdef PIP_CXX11_SUPPORT
if (i.functor) {
(*((std::function<void(T0, T1, T2)>*)i.functor))(v0, v1, v2);
} else {
#endif
if (i.performer) {
PIVector<PIVariant> vl;
if (i.args_count > 0) vl << PIVariant::fromValue(v0);
if (i.args_count > 1) vl << PIVariant::fromValue(v1);
if (i.args_count > 2) vl << PIVariant::fromValue(v2);
i.performer->postQueuedEvent(__QueuedEvent(i.slot, i.dest, i.dest_o, sender, vl));
} else {
bool ts = sender->thread_safe_;
if (ts) i.dest_o->mutex_.lock();
i.dest_o->emitter_ = sender;
switch (i.args_count) {
case 0: ((void(*)(void *))i.slot)(i.dest); break;
case 1: ((void(*)(void * , T0))i.slot)(i.dest, v0); break;
case 2: ((void(*)(void * , T0, T1))i.slot)(i.dest, v0, v1); break;
default: ((void(*)(void * , T0, T1, T2))i.slot)(i.dest, v0, v1, v2); break;
}
if (i.dest_o->isPIObject()) {
i.dest_o->emitter_ = 0;
if (ts) i.dest_o->mutex_.unlock();
}
}
#ifdef PIP_CXX11_SUPPORT
}
#endif
if (!sender->isPIObject()) break;
}
}
template <typename T0, typename T1, typename T2, typename T3>
static void raiseEvent(PIObject * sender, const uint eventID, const T0 & v0 = T0(), const T1 & v1 = T1(), const T2 & v2 = T2(), const T3 & v3 = T3()) {
for (int j = 0; j < sender->connections.size_s(); ++j) {
__Connection i(sender->connections[j]);
if (i.eventID != eventID) continue;
#ifdef PIP_CXX11_SUPPORT
if (i.functor) {
(*((std::function<void(T0, T1, T2, T3)>*)i.functor))(v0, v1, v2, v3);
} else {
#endif
if (i.performer) {
PIVector<PIVariant> vl;
if (i.args_count > 0) vl << PIVariant::fromValue(v0);
if (i.args_count > 1) vl << PIVariant::fromValue(v1);
if (i.args_count > 2) vl << PIVariant::fromValue(v2);
if (i.args_count > 3) vl << PIVariant::fromValue(v3);
i.performer->postQueuedEvent(__QueuedEvent(i.slot, i.dest, i.dest_o, sender, vl));
} else {
bool ts = sender->thread_safe_;
if (ts) i.dest_o->mutex_.lock();
i.dest_o->emitter_ = sender;
switch (i.args_count) {
case 0: ((void(*)(void *))i.slot)(i.dest); break;
case 1: ((void(*)(void * , T0))i.slot)(i.dest, v0); break;
case 2: ((void(*)(void * , T0, T1))i.slot)(i.dest, v0, v1); break;
case 3: ((void(*)(void * , T0, T1, T2))i.slot)(i.dest, v0, v1, v2); break;
default: ((void(*)(void * , T0, T1, T2, T3))i.slot)(i.dest, v0, v1, v2, v3); break;
}
if (i.dest_o->isPIObject()) {
i.dest_o->emitter_ = 0;
if (ts) i.dest_o->mutex_.unlock();
}
}
#ifdef PIP_CXX11_SUPPORT
}
#endif
if (!sender->isPIObject()) break;
}
}
//! Returns PIObject* with name "name" or 0, if there is no object found
static PIObject * findByName(const PIString & name) {
PIMutexLocker _ml(mutexObjects());
piForeach (PIObject * i, PIObject::objects()) {
if (i->name() != name) continue;
return i;
}
return 0;
}
bool isPIObject() const {return isPIObject(this);}
template<typename T>
bool isTypeOf() const {
if (!isPIObject()) return false;
return scopeList().contains(T::__classNameS());
}
template<typename T>
T * cast() const {
if (!isTypeOf<T>()) return (T*)0;
return (T*)this;
}
static bool isPIObject(const PIObject * o);
static bool isPIObject(const void * o) {return isPIObject((PIObject*)o);}
template<typename T>
static bool isTypeOf(const PIObject * o) {return o->isTypeOf<T>();}
template<typename T>
static bool isTypeOf(const void * o) {return isTypeOf<T>((PIObject*)o);}
static PIString simplifyType(const char * a);
struct __MetaFunc {
__MetaFunc(): addr(0), addrV(0) {;}
bool isNull() const {return addr == 0;}
PIString arguments() const;
PIString fullFormat() const;
void * addr;
void * addrV;
PIString func_name;
PIString type_ret;
PIString scope;
PIStringList types;
PIStringList names;
};
struct __MetaData {
__MetaData() {scope_list << PIStringAscii("PIObject"); scope_id << PIStringAscii("PIObject").hash();}
void addScope(const PIString & s, uint shash);
PIStringList scope_list;
PISet<uint> scope_id;
PISet<const void * > eh_set;
PIMap<const void * , __MetaFunc> eh_func;
};
typedef PIPair<const void * , __MetaFunc> __EHPair;
static PIMutex & __meta_mutex();
static PIMap<uint, __MetaData> & __meta_data(); // [hash(classname)]=__MetaData
//! \brief Execute all posted events from CONNECTU_QUEUED connections
void callQueuedEvents();
//! \brief Check if any CONNECTU_QUEUED connections to this object and execute them.
//! \details This function is more optimized than \a callQueuedEvents() for objects that doesn`t
//! appears as \"performer\" target at CONNECTU_QUEUED
bool maybeCallQueuedEvents() {if (proc_event_queue) callQueuedEvents(); return proc_event_queue;}
protected:
//! Returns PIObject* which has raised an event. This value is correct only in definition of some event handler
PIObject * emitter() const {return emitter_;}
//! Virtual function executes after property with name "name" has been changed
virtual void propertyChanged(const PIString & name) {}
EVENT(deleted)
//! \events
//! \{
/** \fn void deleted()
* \brief Raise before object delete
* \note This event raised from destructor, so use only emitter() value,
* don`t try to cast deleted object to some subclass! */
//! \}
private:
struct __Connection {
__Connection(void * sl = 0, void * si = 0, const PIString & e = PIString(), PIObject * d_o = 0, void * d = 0, int ac = 0, PIObject * p = 0) {
slot = sl;
signal = si;
event = e;
eventID = e.hash();
dest_o = d_o;
dest = d;
args_count = ac;
performer = p;
#ifdef PIP_CXX11_SUPPORT
functor = 0;
#endif
}
void destroy();
void * slot;
void * signal;
#ifdef PIP_CXX11_SUPPORT
std::function<void()> * functor;
#endif
PIString event;
uint eventID;
PIObject * dest_o;
PIObject * performer;
void * dest;
int args_count;
};
struct __QueuedEvent {
__QueuedEvent(void * sl = 0, void * d = 0, PIObject * d_o = 0, PIObject * s = 0, const PIVector<PIVariant> & v = PIVector<PIVariant>()) {
slot = sl;
dest = d;
dest_o = d_o;
src = s;
values = v;
}
void * slot;
void * dest;
PIObject * dest_o;
PIObject * src;
PIVector<PIVariant> values;
};
typedef PIPair<PIString, PIVariant> Property;
typedef PIPair<uint, PIPair<PIString, PIVariant> > PropertyHash;
bool findSuitableMethodV(const PIString & method, int args, int & ret_args, __MetaFunc & ret);
PIVector<__MetaFunc> findEH(const PIString & name) const;
__MetaFunc methodEH(const void * addr) const;
void updateConnectors();
void postQueuedEvent(const __QueuedEvent & e);
void * toThis() const;
virtual int ptrOffset() const {return 0;}
static PIVector<PIObject * > & objects();
static PIMutex & mutexObjects();
static void callAddrV(void * slot, void * obj, int args, const PIVector<PIVariant> & vl);
PIVector<__Connection> connections;
PIMap<uint, PIPair<PIString, PIVariant> > properties_;
PISet<PIObject * > connectors;
PIVector<__QueuedEvent> events_queue;
PIMutex mutex_, mutex_connect, mutex_queue;
PIObject * emitter_;
bool thread_safe_, proc_event_queue;
};
void dumpApplication();
bool dumpApplicationToFile(const PIString & path);
#endif // PIOBJECT_H

View File

@@ -0,0 +1,133 @@
/*
PIP - Platform Independent Primitives
Storage of properties for GUI usage
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "pipropertystorage.h"
bool PIPropertyStorage::isPropertyExists(const PIString & _name) const {
for (uint i = 0; i < props.size(); ++i)
if (props[i].name == _name)
return true;
return false;
}
void PIPropertyStorage::addProperty(const PIPropertyStorage::Property & p) {
for (uint i = 0; i < props.size(); ++i)
if (props[i].name == p.name) {
props[i] = p;
return;
}
props << p;
}
void PIPropertyStorage::removeProperty(const PIString & _name) {
for (uint i = 0; i < props.size(); ++i)
if (props[i].name == _name) {
props.remove(i);
return;
}
}
void PIPropertyStorage::removePropertiesByFlag(int flag) {
for (int i = 0; i < props.size_s(); ++i)
if ((props[i].flags & flag) == flag) {
props.remove(i);
--i;
}
}
void PIPropertyStorage::updateProperties(const PIVector<PIPropertyStorage::Property> & properties_, int flag_ignore) {
PIMap<PIString, PIVariant> values;
piForeachC(Property & p, props)
if (((p.flags & flag_ignore) != flag_ignore) || (flag_ignore == 0))
values[p.name] = p.value;
props = properties_;
for (uint i = 0; i < props.size(); ++i) {
Property & p(props[i]);
if (values.contains(p.name)) {
PIVariant pv = values[p.name];
if (pv.type() == p.value.type())
p.value = pv;
}
}
}
PIPropertyStorage::Property PIPropertyStorage::propertyByName(const PIString & name) const {
piForeachC(Property & p, props)
if (p.name == name)
return p;
return Property();
}
PIVariant PIPropertyStorage::propertyValueByName(const PIString & name) const {
piForeachC(Property & p, props)
if (p.name == name)
return p.value;
return PIVariant();
}
void PIPropertyStorage::setPropertyValue(const PIString & name, const PIVariant & value) {
for (uint i = 0; i < props.size(); ++i)
if (props[i].name == name) {
props[i].value = value;
return;
}
}
void PIPropertyStorage::setPropertyComment(const PIString & name, const PIString & comment) {
for (uint i = 0; i < props.size(); ++i)
if (props[i].name == name) {
props[i].comment = comment;
return;
}
}
void PIPropertyStorage::setPropertyFlags(const PIString & name, int flags) {
for (uint i = 0; i < props.size(); ++i)
if (props[i].name == name) {
props[i].flags = flags;
return;
}
}
PIPropertyStorage::Property & PIPropertyStorage::operator[](const PIString & name) {
piForeach (Property & p, props)
if (p.name == name)
return p;
addProperty(name, "");
return props.back();
}
const PIPropertyStorage::Property PIPropertyStorage::operator[](const PIString & name) const {
piForeachC (Property & p, props)
if (p.name == name)
return p;
return Property();
}

View File

@@ -0,0 +1,172 @@
/*! \file pipropertystorage.h
* \brief Storage of properties for GUI usage
*
* This file declare PIPropertyStorage
*/
/*
PIP - Platform Independent Primitives
Storage of properties for GUI usage
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PIPROPERTYSTORAGE_H
#define PIPROPERTYSTORAGE_H
#include "pivariant.h"
/**
* @brief Key-value storage, based on PIVector with PIPropertyStorage::Property elements. Each element in vector
* contains unique name and you can identify property by name with propertyValueByName(), propertyByName().
* You can add property using addProperty(const Property&), addProperty(const PIString&, const PIVariant&, const PIString&, int).
*/
class PIPropertyStorage {
public:
PIPropertyStorage() {}
/**
* @brief PIPropertyStorage element.
*/
struct Property {
Property(const PIString & n = PIString(), const PIString & c = PIString(), const PIVariant & v = PIVariant(), int f = 0):
name(n), comment(c), value(v), flags(f) {}
bool toBool() const {return value.toBool();}
int toInt() const {return value.toInt();}
float toFloat() const {return value.toFloat();}
double toDouble() const {return value.toDouble();}
PIString toString() const {return value.toString();}
/*! Uniqueue id of property */
PIString name;
/*! Optional description of property */
PIString comment;
/*! Custom value of property */
PIVariant value;
/*! Abstract flags which may be used for user needs */
int flags;
};
PIPropertyStorage(const PIVector<Property> & pl) {props = pl;}
typedef PIVector<Property>::const_iterator const_iterator;
typedef PIVector<Property>::iterator iterator;
typedef Property value_type;
iterator begin() {return props.begin();}
const_iterator begin() const {return props.begin();}
iterator end() {return props.end();}
const_iterator end() const {return props.end();}
int length() const {return props.length();}
int size() const {return props.size();}
bool isEmpty() const {return props.isEmpty();}
Property & front() {return props.front();}
const Property & front() const {return props.front();}
Property & back() {return props.back();}
const Property & back() const {return props.back();}
void removeAt(int i) {props.remove(i);}
void clear() {props.clear();}
PIPropertyStorage copy() const {return PIPropertyStorage(*this);}
int propertiesCount() const {return props.size();}
PIVector<Property> & properties() {return props;}
const PIVector<Property> & properties() const {return props;}
const PIPropertyStorage & propertyStorage() const {return *this;}
bool isPropertyExists(const PIString & _name) const;
void clearProperties() {props.clear();}
/**
* @brief Add property if name isn't present in storage, otherwrise update existing property with same name.
*
* @param p to copy in storage
*/
void addProperty(const Property & p);
/**
* @brief First of all construct Property with method params. After then add property if name isn't present
* in storage, otherwrise update existing property with same name.
*/
void addProperty(const PIString & _name, const PIVariant & _def_value, const PIString & _comment = PIString(), int _flags = 0) {addProperty(Property(_name, _comment, _def_value, _flags));}
void removeProperty(const PIString & _name);
void removePropertiesByFlag(int flag);
void updateProperties(const PIVector<Property> & properties_, int flag_ignore = 0);
/**
* @brief Search property by name and return it.
*
* @param name of property
* @return property value or default constructed Property
*/
Property propertyByName(const PIString & name) const;
/**
* @brief Search property by name and return property value.
*
* @param name of property
* @return property value or invalid PIVariant if name unknown
*/
PIVariant propertyValueByName(const PIString & name) const;
/**
* @brief Set value of property with specific name if name is present in storage.
*
* @param name of property to set value
* @param value to set
*/
void setPropertyValue(const PIString & name, const PIVariant & value);
/**
* @brief Set comment of property with specific name if name is present in storage.
*
* @param name of property to set comment
* @param comment to set
*/
void setPropertyComment(const PIString & name, const PIString & comment);
/**
* @brief Set flags of property with specific name if name is present in storage.
*
* @param name of property to set flags
* @param flags to set
*/
void setPropertyFlags(const PIString & name, int flags);
PIPropertyStorage & operator <<(const PIPropertyStorage::Property & p) {props << p; return *this;}
PIPropertyStorage & operator <<(const PIVector<Property> & p) {props << p; return *this;}
PIPropertyStorage & operator <<(const PIPropertyStorage & p) {props << p.props; return *this;}
Property & operator[](int i) {return props[i];}
const Property & operator[](int i) const {return props[i];}
Property & operator[](const PIString & name);
const Property operator[](const PIString & name) const;
static Property parsePropertyLine(PIString l);
protected:
PIVector<Property> props;
};
inline PIByteArray & operator <<(PIByteArray & s, const PIPropertyStorage::Property & v) {s << v.name << v.value << v.comment << v.flags; return s;}
inline PIByteArray & operator >>(PIByteArray & s, PIPropertyStorage::Property & v) {s >> v.name >> v.value >> v.comment >> v.flags; return s;}
inline PIByteArray & operator <<(PIByteArray & s, const PIPropertyStorage & v) {s << v.properties(); return s;}
inline PIByteArray & operator >>(PIByteArray & s, PIPropertyStorage & v) {s >> v.properties(); return s;}
#endif // PIPROPERTYSTORAGE_H

1225
lib/main/core/pistring.cpp Normal file
View File

@@ -0,0 +1,1225 @@
/*
PIP - Platform Independent Primitives
String
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "piincludes_p.h"
#include "pistring.h"
#include "pistringlist.h"
#ifdef PIP_ICU
# define U_NOEXCEPT
# include "unicode/ucnv.h"
#endif
#ifdef WINDOWS
# include <stringapiset.h>
#endif
#include <wchar.h>
#ifdef ANDROID
# if __ANDROID_API__ < 21
# define wctomb(s, wc) wcrtomb(s, wc, NULL)
# define mbtowc(pwc, s, n) mbrtowc(pwc, s, n, NULL)
# endif
#endif
/*! \class PIString
* \brief String class
* \details PIP use this class for use string information.
*
* \section PIString_sec0 Synopsis
* This class based on \a PIVector to store information.
* String is a sequence of \a PIChar and can contain multibyte
* symbols. Therefore real memory size of string is symbols count * 4.
* String can be constucted from many types of data and can be converted
* to many types. There are man operators and handly functions to use
* string as you wish.
*
* \section PIString_sec1 To/from data convertions
* Most common constructor is \a PIString(const char * str), where "str"
* is null-terminated string, e.g. \c "string". This is 7 chars with last char = 0.
* Also you can constructs \a PIString from single \a PIChar, \a PIByteArray,
* other \a PIString or sequency of the same characters with custom length.\n \n
* This class has implicit conversions to <tt>const char * </tt> and
* \c std::string. Also there are functions to make same convertions:
* * \a data() - to <tt>const char * </tt>,
* * \a stdString() - to \c std::string,
* * \a toByteArray() - to \a PIByteArray.
*
* \section PIString_sec2 Numeric operations
* You can get symbolic representation of any numeric value with function
* \a setNumber(any integer value, int base = 10, bool * ok = 0). Default
* arguments are set for decimal base system, but you can choose any system
* from 2 to 40. There are the same static functions \a fromNumber(), that
* returns \a PIString. \n
* Also there is function \a setReadableSize() which is set human-readable
* size in bytes, Kb, Mb, Gb or Pb. Static analog is \a readableSize().
*
*/
/*! \fn int versionCompare(const PIString & v0, const PIString & v1, int components = 6)
* \relatesalso PIString
* \brief Compare two version strings in free notation and returns 0, -1 or 1
* \details This function parse version to number codes and labels. Then it
* compare no more than "components" codes. If there is no difference, compare
* labels. Each label has corresponding integer value, so
* "prealpha" < "alpha" < "prebeta" < "beta" < "rcN" < "" < "rN".
* Example:
* \code
* piCout << versionCompare("1.0.0_rc2-999", "1.0.1_rc2-999"); // -1
* piCout << versionCompare("1.0.0", "0.9.2"); // 1
* piCout << versionCompare("1.0.0_r1", "1.0.0"); // 1
* piCout << versionCompare("1.0.0_r1", "1.0.0", 3); // 0
* piCout << versionCompare("1.0.0_r1", "1.0.0", 3); // 0
* piCout << versionCompare(".2-alpha", "0.2_alpha"); // 0
* piCout << versionCompare("1_prebeta", "1.0_alpha"); // 1
* \endcode
* \return
* * 0 - equal
* * 1 - v0 > v1
* * -1 - v0 < v1
*
*
* \fn PIString versionNormalize(const PIString & v)
* \relatesalso PIString
* \brief Converts version string in free notation to classic view
* \details Parse version as described in \a versionCompare() and
* returns classic view of codes and labels: major.minor.revision[-build][_label].
* Example:
* \code
* piCout << versionNormalize(""); // 0.0.0
* piCout << versionNormalize("1"); // 1.0.0
* piCout << versionNormalize("1.2"); // 1.2.0
* piCout << versionNormalize("1.2.3"); // 1.2.3
* piCout << versionNormalize("1.2+rc1.99"); // 1.2.99_rc1
* piCout << versionNormalize("1.2-alpha"); // 1.2.0_alpha
* piCout << versionNormalize("1..4_rc2-999"); // 1.0.4-999_rc2
* \endcode
*
*/
const char PIString::toBaseN[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^'};
const int PIString::fromBaseN[] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
-1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, -1,
-1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
const float PIString::ElideLeft = 0.f;
const float PIString::ElideCenter = .5f;
const float PIString::ElideRight = 1.f;
#ifndef CC_VC
# define pisprintf(f, v) char ch[256]; memset(ch, 0, 256); sprintf(ch, f, v);
#else
# define pisprintf(f, v) char ch[256]; memset(ch, 0, 256); sprintf_s(ch, 256, f, v);
#endif
#ifdef ANDROID
//int wctomb(char * c, wchar_t w) {*c = ((char * )&w)[0]; return 1;}
#endif
PIString PIString::itos(const int num) {pisprintf("%d", num); return PIString(ch);}
PIString PIString::ltos(const long num) {pisprintf("%ld", num); return PIString(ch);}
PIString PIString::lltos(const llong num) {pisprintf("%lld", num); return PIString(ch);}
PIString PIString::uitos(const uint num) {pisprintf("%u", num); return PIString(ch);}
PIString PIString::ultos(const ulong num) {pisprintf("%lu", num); return PIString(ch);}
PIString PIString::ulltos(const ullong num) {pisprintf("%llu", num); return PIString(ch);}
PIString PIString::ftos(const float num, char format, int precision) {
char f[8] = "%.";
int wr = sprintf(&(f[2]), "%d", precision);
f[2 + wr] = format;
f[3 + wr] = 0;
pisprintf(f, num);
return PIString(ch);
}
PIString PIString::dtos(const double num, char format, int precision) {
char f[8] = "%.";
int wr = sprintf(&(f[2]), "%d", precision);
f[2 + wr] = format;
f[3 + wr] = 0;
pisprintf(f, num);
return PIString(ch);
}
#undef pisprintf
PIString PIString::fromNumberBaseS(const llong value, int base, bool * ok) {
if (value == 0LL) return PIString("0");
if (base < 2 || base > 40) {if (ok != 0) *ok = false; return PIString();}
if (ok != 0) *ok = true;
if (base == 10) return lltos(value);
PIString ret;
llong v = value < 0 ? -value : value, cn;
int b = base;
while (v >= llong(base)) {
cn = v % b;
v /= b;
//cout << int(cn) << ", " << int(v) << endl;
ret.push_front(PIChar(toBaseN[cn]));
}
if (v > 0) ret.push_front(PIChar(toBaseN[v]));
if (value < 0) ret.push_front('-');
return ret;
}
PIString PIString::fromNumberBaseU(const ullong value, int base, bool * ok) {
if (value == 0ULL) return PIString("0");
if (base < 2 || base > 40) {if (ok != 0) *ok = false; return PIString();}
if (ok != 0) *ok = true;
if (base == 10) return ulltos(value);
PIString ret;
ullong v = value, cn;
int b = base;
while (v >= ullong(base)) {
cn = v % b;
v /= b;
//cout << int(cn) << ", " << int(v) << endl;
ret.push_front(PIChar(toBaseN[cn]));
}
if (v > 0) ret.push_front(PIChar(toBaseN[v]));
return ret;
}
llong PIString::toNumberBase(const PIString & value, int base, bool * ok) {
PIString v = value.trimmed();
if (base < 0) {
int ind = v.find("0x");
if (ind == 0 || ind == 1) {v.remove(ind, 2); base = 16;}
else base = 10;
} else
if (base < 2 || base > 40) {if (ok != 0) *ok = false; return 0;}
if (ok) *ok = true;
PIVector<int> digits;
llong ret = 0, m = 1;
bool neg = false;
int cs;
for (int i = 0; i < v.size_s(); ++i) {
if (v[i] == PIChar('-')) {neg = !neg; continue;}
cs = fromBaseN[int(v[i].toAscii())];
if (cs < 0 || cs >= base) {
if (ok) *ok = false;
break;
}
digits << cs;
}
for (int i = digits.size_s() - 1; i >= 0; --i) {
ret += digits[i] * m;
m *= base;
}
if (neg) ret = -ret;
return ret;
}
void PIString::appendFromChars(const char * c, int s, const char * codepage) {
if (s <= 0) return;
int sz;
#ifdef PIP_ICU
UErrorCode e((UErrorCode)0);
UConverter * cc = ucnv_open(codepage, &e);
if (cc) {
UChar * ucs = new UChar[s];
memset(ucs, 0, s * sizeof(UChar));
e = (UErrorCode)0;
int sz = ucnv_toUChars(cc, ucs, s, c, s, &e);
//printf("appendFromChars %d -> %d\n", s, sz);
//printf("PIString %d -> %d\n", c[0], ucs[0]);
for (int i = 0; i < sz; ++i)
push_back(PIChar(ucs[i]));
delete[] ucs;
ucnv_close(cc);
return;
}
#else
# ifdef WINDOWS
sz = MultiByteToWideChar((uint)(uintptr_t)codepage, MB_ERR_INVALID_CHARS, c, s, 0, 0);
if (sz <= 0) return;
wchar_t * buffer = new wchar_t[sz];
MultiByteToWideChar((uint)(uintptr_t)codepage, MB_ERR_INVALID_CHARS, c, s, buffer, sz);
for (int i = 0; i < sz; ++i)
push_back(PIChar((ushort)buffer[i]));
delete[] buffer;
return;
//printf("request %d\n", sz);
# else
wchar_t wc;
mbtowc(0,0,0); // reset mbtowc
//qDebug() << "FromChars ...";
while (s>0) {
//qDebug() << "0" << s;
sz = mbtowc(&wc, c, s);
//qDebug() << "1" << sz;
if (sz < 1) break;
push_back(PIChar(int(wc)));
c += sz; s -= sz;
//qDebug() << "2" << c;
}
//qDebug() << "FromChars done" << size();
# endif
#endif
}
PIString PIString::fromConsole(const char * s) {
int l = 0;
while (s[l] != '\0') ++l;
PIString ret;
if (l > 0) ret.appendFromChars(s, l, __sysoemname__);
return ret;
}
PIString PIString::fromSystem(const char * s) {
int l = 0;
while (s[l] != '\0') ++l;
PIString ret;
if (l > 0) ret.appendFromChars(s, l, __syslocname__);
return ret;
}
PIString PIString::fromUTF8(const char * s) {
int l = 0;
while (s[l] != '\0') ++l;
PIString ret;
if (l > 0) ret.appendFromChars(s, l, __utf8name__);
return ret;
}
PIString PIString::fromUTF8(const PIByteArray & ba) {
PIString ret;
if (ba.isEmpty()) return ret;
ret.appendFromChars((const char*)ba.data(), ba.size(), __utf8name__);
return ret;
}
PIString PIString::fromAscii(const char * s) {
PIString ret;
int l = 0;
while (s[l] != '\0') {
ret.push_back(PIChar(short(s[l])));
++l;
}
return ret;
}
PIString PIString::fromCodepage(const char * s, const char * c) {
int l = 0;
while (s[l] != '\0') ++l;
PIString ret;
if (l > 0) ret.appendFromChars(s, l
#ifdef PIP_ICU
, c
#else
# ifdef WINDOWS
, __utf8name__
# endif
#endif
);
return ret;
}
PIString PIString::readableSize(llong bytes) {
PIString s;
s.setReadableSize(bytes);
return s;
}
void PIString::buildData(const char * cp) const {
data_.clear();
int sz = 0;
#ifdef PIP_ICU
UErrorCode e((UErrorCode)0);
UConverter * cc = ucnv_open(cp, &e);
if (cc) {
char uc[8];
for (int i = 0; i < size_s(); ++i) {
if (at(i).isAscii())
data_.push_back(uchar(at(i).unicode16Code()));
else {
e = (UErrorCode)0;
sz = ucnv_fromUChars(cc, uc, 8, (const UChar*)(PIDeque<PIChar>::data(i)), 1, &e);
for (int j = 0; j < sz; ++j)
data_.push_back(uc[j]);
}
}
ucnv_close(cc);
data_.push_back('\0');
return;
}
#else
# ifdef WINDOWS
sz = WideCharToMultiByte((uint)(uintptr_t)cp, 0, (LPCWCH)PIDeque<PIChar>::data(), PIDeque<PIChar>::size_s(), 0, 0, NULL, NULL);
//printf("WideCharToMultiByte %d %d\n", (uint)(uintptr_t)cp, sz);
if (sz <= 0) {
//printf("WideCharToMultiByte erro %d\n", GetLastError());
data_.push_back(uchar('\0'));
return;
}
data_.resize(sz);
WideCharToMultiByte((uint)(uintptr_t)cp, 0, (LPCWCH)PIDeque<PIChar>::data(), PIDeque<PIChar>::size_s(), (LPSTR)data_.data(), data_.size_s(), NULL, NULL);
data_.push_back(uchar('\0'));
return;
# else
wchar_t wc;
char tc[8];
wctomb(0, 0);
for (int i = 0; i < size_s(); ++i) {
if (at(i).isAscii()) {
data_.push_back(uchar(at(i).toAscii()));
continue;
}
wc = at(i).toWChar();
sz = wctomb(tc, wc);
for (int b = 0; b < sz; ++b)
data_.push_back(uchar(tc[b]));
}
data_.push_back(uchar('\0'));
# endif
#endif
}
void PIString::trimsubstr(int &st, int &fn) const {
for (int i = 0; i < length(); ++i)
if (at(i) != ' ' && at(i) != '\t' && at(i) != '\n' && at(i) != '\r' && at(i) != char(12) && at(i) != uchar(0))
{st = i; break;}
if (st < 0) return;
for (int i = length() - 1; i >= 0; --i)
if (at(i) != ' ' && at(i) != '\t' && at(i) != '\n' && at(i) != '\r' && at(i) != char(12) && at(i) != uchar(0))
{fn = i; break;}
}
const char * PIString::dataConsole() const {
buildData(__sysoemname__ );
return (const char *)(data_.data());
}
const char * PIString::dataUTF8() const {
buildData(__utf8name__);
return (const char *)(data_.data());
}
const char * PIString::dataAscii() const {
data_.clear();
for (int i = 0; i < size_s(); ++i)
data_.push_back(uchar(at(i).ch));
data_.push_back(uchar('\0'));
return (const char *)data_.data();
}
uint PIString::hash() const {
return piHashData((const uchar*)PIDeque<PIChar>::data(), size() * sizeof(PIChar));
}
PIByteArray PIString::toUTF8() const {
if (isEmpty()) return data_.resized(0);
buildData(__utf8name__);
return data_.resized(data_.size_s() - 1);
}
PIByteArray PIString::toCharset(const char * c) const {
if (isEmpty()) return data_.resized(0);
buildData(
#ifdef PIP_ICU
c
#else
# ifdef WINDOWS
__utf8name__
# endif
#endif
);
return data_.resized(data_.size_s() - 1);
}
PIString & PIString::operator +=(const char * str) {
if (!str) return *this;
int l = 0;
while (str[l] != '\0') ++l;
appendFromChars(str, l, __syslocname__);
return *this;
}
PIString & PIString::operator +=(const wchar_t * str) {
if (!str) return *this;
int i = -1;
while (str[++i])
push_back(PIChar(ushort(str[i])));
return *this;
}
PIString & PIString::operator +=(const PIString & str) {
*((PIDeque<PIChar>*)this) << *((PIDeque<PIChar>*)&str);
return *this;
}
bool PIString::operator ==(const PIString & str) const {
uint l = str.size();
if (size() != l) return false;
for (uint i = 0; i < l; ++i)
if (str[i] != at(i))
return false;
return true;
}
bool PIString::operator !=(const PIString & str) const {
uint l = str.size();
if (size() != l) return true;
for (uint i = 0; i < l; ++i)
if (str[i] != at(i))
return true;
return false;
}
bool PIString::operator <(const PIString & str) const {
uint l = str.size();
if (size() < l) return true;
if (size() > l) return false;
for (uint i = 0; i < l; ++i) {
if (at(i) == str[i]) continue;
if (at(i) < str[i]) return true;
else return false;
}
return false;
}
bool PIString::operator >(const PIString & str) const {
uint l = str.size();
if (size() < l) return false;
if (size() > l) return true;
for (uint i = 0; i < l; ++i) {
if (at(i) == str[i]) continue;
if (at(i) < str[i]) return false;
else return true;
}
return false;
}
PIString PIString::mid(const int start, const int len) const {
//PIString str;
int s = start, l = len;
if (l == 0 || s >= length()) return PIString();
if (s < 0) {
l += s;
s = 0;
}
if (l < 0) {
return PIString(&(at(s)), size_s() - s);
} else {
if (l > length() - s)
l = length() - s;
return PIString(&(at(s)), l);
}
return PIString();
}
PIString & PIString::cutMid(const int start, const int len) {
int s = start, l = len;
if (l == 0) return *this;
if (s < 0) {
l += s;
s = 0;
}
if (l < 0)
remove(s, size() - s);
else {
if (l > length() - s)
l = length() - s;
remove(s, l);
}
return *this;
}
PIString & PIString::trim() {
int st = -1, fn = 0;
trimsubstr(st, fn);
if (st < 0) {
clear();
return *this;
}
if (fn < size_s() - 1) cutRight(size_s() - fn - 1);
if (st > 0) cutLeft(st);
return *this;
}
PIString PIString::trimmed() const {
int st = -1, fn = 0;
trimsubstr(st, fn);
if (st < 0) return PIString();
return mid(st, fn - st + 1);
}
PIString & PIString::replace(int from, int count, const PIString & with) {
if (count < length() - from) remove(from, count);
else remove(from, length() - from);
uint c = with.length();
for (uint i = 0; i < c; ++i) insert(from + i, with[i]);
return *this;
}
PIString & PIString::replace(const PIString & what, const PIString & with, bool * ok) {
//piCout << "replace" << what << with;
if (what.isEmpty()) {
if (ok != 0) *ok = false;
return *this;
}
int s = find(what);
if (s >= 0) replace(s, what.length(), with);
if (ok != 0) *ok = (s >= 0);
return *this;
}
PIString & PIString::replaceAll(const PIString & what, const PIString & with) {
if (what.isEmpty() || what == with) return *this;
bool ok = true;
while (ok) replace(what, with, &ok);
return *this;
}
PIString & PIString::insert(int index, const PIString & str) {
PIDeque<PIChar>::insert(index, *((const PIDeque<PIChar>*)&str));
return *this;
}
PIString & PIString::elide(int size, float pos) {
if (length() <= size) return *this;
if (length() <= 2) {
fill(".");
return *this;
}
pos = piClampf(pos, 0.f, 1.f);
int ns = size - 2;
int ls = piRoundf(ns * pos);
remove(ls, length() - ns);
insert(ls, "..");
return *this;
}
PIStringList PIString::split(const PIString & delim) const {
PIStringList sl;
if (isEmpty() || delim.isEmpty()) return sl;
PIString ts(*this);
int ci = ts.find(delim);
while (ci >= 0) {
sl << ts.left(ci);
ts.cutLeft(ci + delim.length());
ci = ts.find(delim);
}
if (ts.length() > 0) sl << ts;
return sl;
}
int PIString::find(const char str, const int start) const {
for (int i = start; i < length(); ++i)
if (at(i) == str)
return i;
return -1;
}
int PIString::find(const PIString & str, const int start) const {
int l = str.length();
for (int i = start; i < length() - l + 1; ++i)
if (mid(i, l) == str)
return i;
return -1;
}
int PIString::findLast(const char str, const int start) const {
for (int i = length() - 1; i >= start; --i)
if (at(i) == str)
return i;
return -1;
}
int PIString::findLast(const PIString & str, const int start) const {
int l = str.length();
for (int i = length() - l; i >= start; --i)
if (mid(i, l) == str)
return i;
return -1;
}
int PIString::findWord(const PIString & word, const int start) const {
int f = start - 1, tl = length(), wl = word.length();
while ((f = find(word, f + 1)) >= 0) {
bool ok = true;
PIChar c;
if (f > 0) {c = (*this)[f - 1]; if (!(c == ' ' || c == '\t' || c == '\n' || c == '\r')) {ok = false; continue;}}
if (f + wl < tl) {c = (*this)[f + wl]; if (!(c == ' ' || c == '\t' || c == '\n' || c == '\r')) {ok = false; continue;}}
if (ok) return f;
}
return -1;
}
int PIString::findCWord(const PIString & word, const int start) const {
int f = start - 1, tl = length(), wl = word.length();
while ((f = find(word, f + 1)) >= 0) {
bool ok = true;
PIChar c;
if (f > 0) {c = (*this)[f - 1]; if (!(c == ' ' || c == '\t' || c == '\n' || c == '\r' || (c != '_' && !c.isAlpha() && !c.isDigit()))) {ok = false; continue;}}
if (f + wl < tl) {c = (*this)[f + wl]; if (!(c == ' ' || c == '\t' || c == '\n' || c == '\r' || (c != '_' && !c.isAlpha() && !c.isDigit()))) {ok = false; continue;}}
if (ok) return f;
}
return -1;
}
int PIString::findRange(const PIChar & start, const PIChar & end, const PIChar & shield, const int start_index, int * len) const {
if (len) *len = 0;
bool trim_ = (start != ' ' && start != '\t' && start != '\n' && start != '\r'), eq = (start == end);
int sz = size_s(), ls = -1, le = -1, cnt = 0;
for (int i = start_index; i < sz; ++i) {
PIChar c = at(i);
if (c == shield) {++i; continue;}
if (trim_) {
if (c == ' ' || c == '\t' || c == '\n' || c == '\r')
continue;
trim_ = false;
}
if (eq) {
if (c == start) {
if (cnt == 0) ls = i;
else {le = i; cnt = 0; break;}
cnt++;
}
} else {
if (c == start) {
if (cnt == 0) ls = i;
cnt++;
}
if (c == end) {
cnt--;
if (cnt == 0) le = i;
}
}
if (cnt <= 0) break;
}
//piCout << ls << le << cnt;
if (le < ls || ls < 0 || le < 0 || cnt != 0) return -1;
if (len) *len = le - ls - 1;
return ls + 1;
}
int PIString::findAny(const PIString & str, const int start) const {
for (int i = start; i < length(); ++i)
if (str.contains(at(i)))
return i;
return -1;
}
int PIString::findAnyLast(const PIString & str, const int start) const {
for (int i = length() - 1; i >= start; --i)
if (str.contains(at(i)))
return i;
return -1;
}
int PIString::entries(const PIChar & c) const {
int sz = size_s(), ret = 0;
for (int i = 0; i < sz; ++i)
if (at(i) == c) ++ret;
return ret;
}
bool PIString::startsWith(const PIString & str) const {
if (size() < str.size()) return false;
return str == left(str.size());
}
bool PIString::endsWith(const PIString & str) const {
if (size() < str.size()) return false;
return str == right(str.size());
}
bool PIString::toBool() const {
PIString s(*this);
s = s.trimmed().toLowerCase();
if ( atof(s.toNativeDecimalPoints().data()) > 0. || s == "true" || s == "yes" || s == "on" || s == "ok") return true;
return false;
}
PIString PIString::takeSymbol() {
PIString ret;
int sz = size_s(), ss = -1;
for (int i = 0; i < sz; ++i) {
PIChar c = at(i);
if (c == ' ' || c == '\t' || c == '\n' || c == '\r')
continue;
ss = i;
break;
}
if (ss < 0) return ret;
ret = mid(ss, 1);
cutLeft(ss + 1);
return ret;
}
PIString PIString::takeWord() {
int sz = size_s(), ws = -1, we = -1;
for (int i = 0; i < sz; ++i) {
PIChar c = at(i);
if (c == ' ' || c == '\t' || c == '\n' || c == '\r') {
if (we < 0 && ws >= 0) {
we = i;
break;
}
} else {
if (ws < 0) ws = i;
if (we >= 0) break;
}
}
PIString ret = mid(ws, we - ws);
cutLeft(we < 0 ? sz : we);
return ret;
}
PIString PIString::takeCWord() {
PIString ret;
int sz = size_s(), ws = -1, we = -1;
for (int i = 0; i < sz; ++i) {
PIChar c = at(i);
if (c == ' ' || c == '\t' || c == '\n' || c == '\r') {
if (we < 0 && ws >= 0) {
we = i;
break;
}
} else {
if (ws < 0) {
if (c.isAlpha() || c == '_')
ws = i;
else
return ret;
} else {
if (!c.isAlpha() && !c.isDigit() && c != '_') {
we = i;
break;
}
}
if (we >= 0) break;
}
}
ret = mid(ws, we - ws);
cutLeft(we < 0 ? sz : we);
return ret;
}
PIString PIString::takeLine() {
int sz = size_s(), le = -1;
for (int i = 0; i < sz; ++i) {
PIChar c = at(i);
if (c == '\n') {
le = i;
break;
}
}
PIString ret = left(le);
if (!ret.isEmpty())
if (ret.back() == '\r')
ret.cutRight(1);
cutLeft(le < 0 ? sz : le + 1);
return ret;
}
PIString PIString::takeNumber() {
PIString ret;
int sz = size_s(), ls = -1, le = -1, phase = 0;
for (int i = 0; i < sz; ++i) {
if (phase > 7) break;
PIChar c = at(i);
//piCout << "char " << c << "phase" << phase;
switch (phase) {
case 0: // trim
if (c == ' ' || c == '\t' || c == '\n' || c == '\r')
continue;
phase = 7;
case 7: // sign
if (c == '-' || c == '+') {ls = i; phase = 1; break;}
case 1: // search start
if (c >= '0' && c <= '9') {le = i; if (ls < 0) ls = i; phase = 2; break;}
if (c == '.') {le = i; if (ls < 0) ls = i; phase = 3; break;}
phase = 9;
break;
case 2: // integer
if (c == '.') {le = i; phase = 3; break;}
if (c == 'e' || c == 'E') {le = i; phase = 4; break;}
if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') || c == 'x') {le = i; break;}
phase = 6;
break;
case 3: // point
if (c == 'e' || c == 'E') {le = i; phase = 4; break;}
if (c >= '0' && c <= '9') {le = i; break;}
phase = 6;
break;
case 4: // exp
if ((c >= '0' && c <= '9') || c == '-' || c == '+') {le = i; phase = 5; break;}
phase = 6;
break;
case 5: // power
if (c >= '0' && c <= '9') {le = i; break;}
phase = 6;
break;
case 6: // suffix
if (c == 'f' || c == 's' || c == 'u' || c == 'l' || c == 'L') {le = i; break;}
phase = 9;
break;
}
if (phase == 6) {
if (c == 'f' || c == 's' || c == 'u' || c == 'l' || c == 'L') le = i;
else phase = 9;
}
}
//piCout << ls << le;
if (le < ls) return ret;
ret = mid(ls, le - ls + 1);
cutLeft(le + 1);
return ret;
}
PIString PIString::takeRange(const PIChar & start, const PIChar & end, const PIChar & shield) {
PIString ret;
bool trim_ = (start != ' ' && start != '\t' && start != '\n' && start != '\r'), eq = (start == end);
int sz = size_s(), ls = -1, le = -1, cnt = 0;
for (int i = 0; i < sz; ++i) {
PIChar c = at(i);
if (c == shield) {++i; continue;}
if (trim_) {
if (c == ' ' || c == '\t' || c == '\n' || c == '\r')
continue;
trim_ = false;
}
if (eq) {
if (c == start) {
if (cnt == 0) ls = i;
else {le = i; cnt = 0; break;}
cnt++;
}
} else {
if (c == start) {
if (cnt == 0) ls = i;
cnt++;
}
if (c == end) {
cnt--;
if (cnt == 0) le = i;
}
}
if (cnt <= 0) break;
}
//piCout << ls << le << cnt;
if (le < ls || ls < 0 || le < 0 || cnt != 0) return ret;
ret = mid(ls + 1, le - ls - 1);
cutLeft(le + 1);
return ret;
}
PIString PIString::inBrackets(const PIChar &start, const PIChar &end) const {
int slen = length();
int st = -1, bcnt = 0;
PIChar cc;
for (int i = 0; i < slen; i++) {
cc = at(i);
if (cc == start) {
if (bcnt == 0) st = i;
bcnt++;
}
if (cc == end && st >= 0) {
bcnt--;
if (bcnt == 0) return mid(st+1, i-st-1);
}
}
return PIString();
}
PIString PIString::toUpperCase() const {
PIString str(*this);
int l = str.size();
for (int i = 0; i < l; ++i) str[i] = str[i].toUpper();
return str;
}
PIString PIString::toLowerCase() const {
PIString str(*this);
int l = str.size();
for (int i = 0; i < l; ++i) str[i] = str[i].toLower();
return str;
}
PIString PIString::toNativeDecimalPoints() const {
#ifdef HAS_LOCALE
PIString s(*this);
if (currentLocale == 0) return s;
return s.replaceAll(".", currentLocale->decimal_point).replaceAll(",", currentLocale->decimal_point);
#else
return PIString(*this).replaceAll(",", ".");
#endif
}
char PIString::toChar() const {
PIString s(toNativeDecimalPoints());
char v;
sscanf(s.data(), "%c", &v);
return v;
}
float PIString::toFloat() const {
return (float)atof(toNativeDecimalPoints().data());
}
double PIString::toDouble() const {
return atof(toNativeDecimalPoints().data());
}
ldouble PIString::toLDouble() const {
return atof(toNativeDecimalPoints().data());
}
PIString & PIString::setReadableSize(llong bytes) {
clear();
if (bytes < 1024) {*this += (PIString::fromNumber(bytes) + " B"); return *this;}
double fres = bytes / 1024.;
llong res = bytes / 1024;
fres -= res;
if (res < 1024) {*this += (PIString::fromNumber(res) + "." + PIString::fromNumber(llong(fres * 10)).left(1) + " kB"); return *this;}
fres = res / 1024.;
res /= 1024;
fres -= res;
if (res < 1024) {*this += (PIString::fromNumber(res) + "." + PIString::fromNumber(llong(fres * 10)).left(1) + " MB"); return *this;}
fres = res / 1024.;
res /= 1024;
fres -= res;
if (res < 1024) {*this += (PIString::fromNumber(res) + "." + PIString::fromNumber(llong(fres * 10)).left(1) + " GB"); return *this;}
fres = res / 1024.;
res /= 1024;
fres -= res;
if (res < 1024) {*this += (PIString::fromNumber(res) + "." + PIString::fromNumber(llong(fres * 10)).left(1) + " TB"); return *this;}
fres = res / 1024.;
res /= 1024;
fres -= res;
*this += (PIString::fromNumber(res) + "." + PIString::fromNumber(llong(fres * 10)).left(1) + " PB");
return *this;
}
inline char chrUpr(char c) {
if (c >= 'a' && c <= 'z') return c + 'A' - 'a';
return c;
}
inline char chrLwr(char c) {
if (c >= 'A' && c <= 'Z') return c + 'a' - 'A';
return c;
}
const static PIString _versionDelims_ = PIStringAscii("._-+");
void parseVersion(PIString s, PIVector<int> & codes, PIStringList & strs) {
s.trim();
if (s.isEmpty()) {
codes.resize(3, 0);
return;
}
int mccnt = 2 - s.entries('.');
if (mccnt > 0) {
int ind = s.findLast(".") + 1;
while (!_versionDelims_.contains(s[ind])) {
++ind;
if (ind > s.size_s() - 1)
break;
}
for (int i = 0; i < mccnt; ++i)
s.insert(ind, ".0");
}
PIStringList comps;
while (!s.isEmpty()) {
int ind = s.findAny(_versionDelims_);
if (ind >= 0) {
comps << s.takeLeft(ind);
s.cutLeft(1).trim();
} else {
comps << s;
s.clear();
}
}
for (int i = 0; i < comps.size_s(); ++i) {
if (comps[i].isEmpty())
comps[i] = "0";
bool ok = false;
int val = comps[i].toInt(-1, &ok);
if (ok) {
codes << val;
} else {
strs << comps[i];
}
}
//piCout << codes << strs;
}
int versionLabelValue(PIString s) {
int ret = -10000;
if (s.isEmpty()) return 0;
if (s.startsWith("pre")) {
s.cutLeft(3);
ret -= 1;
}
if (s.startsWith("rc")) {
s.cutLeft(2);
ret += s.toInt();
}
if (s.startsWith("r")) {
s.cutLeft(1);
ret += 10000 + s.toInt();
}
if (s == "alpha") ret -= 4;
if (s == "beta" ) ret -= 2;
return ret;
}
int versionCompare(const PIString & v0, const PIString & v1, int components) {
PIStringList strs[2]; PIVector<int> codes[2];
parseVersion(v0.toLowerCase(), codes[0], strs[0]);
parseVersion(v1.toLowerCase(), codes[1], strs[1]);
//piCout << codes[0] << strs[0];
int mc = piMaxi(codes[0].size_s(), codes[1].size_s());
if (codes[0].size_s() < mc) codes[0].resize(mc, 0);
if (codes[1].size_s() < mc) codes[1].resize(mc, 0);
mc = piMaxi(strs[0].size_s(), strs[1].size_s());
if (strs[0].size_s() < mc) strs[0].resize(mc, "");
if (strs[1].size_s() < mc) strs[1].resize(mc, "");
int comps = piMini(components, codes[0].size_s(), codes[1].size_s());
if (comps < 1) return (v0 == v1 ? 0 : (v0 > v1 ? 1 : -1));
for (int c = 0; c < comps; ++c) {
if (codes[0][c] > codes[1][c]) return 1;
if (codes[0][c] < codes[1][c]) return -1;
}
mc = piClampi(mc, 0, components - comps);
for (int c = 0; c < mc; ++c) {
int lv0 = versionLabelValue(strs[0][c]);
int lv1 = versionLabelValue(strs[1][c]);
if (lv0 > lv1) return 1;
if (lv0 < lv1) return -1;
}
return 0;
}
PIString versionNormalize(const PIString & v) {
PIStringList strs; PIVector<int> codes;
parseVersion(v.toLowerCase(), codes, strs);
PIString ret;
for (int i = 0; i < codes.size_s(); ++i) {
if (i > 0) {
if (i < 3) ret += ".";
else ret += "-";
}
ret += PIString::fromNumber(codes[i]);
}
for (int i = 0; i < strs.size_s(); ++i) {
ret += "_";
ret += strs[i];
}
return ret;
}
PICout operator <<(PICout s, const PIString & v) {
s.space();
s.quote();
s.setControl(0, true);
s << v.data();
s.restoreControl();
s.quote();
return s;
}

774
lib/main/core/pistring.h Normal file
View File

@@ -0,0 +1,774 @@
/*! \file pistring.h
* \brief String
*
* This file declare string and string list classes
*/
/*
PIP - Platform Independent Primitives
String
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PISTRING_H
#define PISTRING_H
#include "pibytearray.h"
#define PIStringAscii PIString::fromAscii
class PIStringList;
class PIP_EXPORT PIString: public PIDeque<PIChar>
{
friend PIByteArray & operator >>(PIByteArray & s, PIString & v);
public:
//! Contructs an empty string
PIString(): PIDeque<PIChar>() {}
static const float ElideLeft ;
static const float ElideCenter;
static const float ElideRight ;
PIString & operator +=(const PIChar & c) {push_back(c); return *this;}
PIString & operator +=(const char * str);
PIString & operator +=(const wchar_t * str);
PIString & operator +=(const PIByteArray & ba) {appendFromChars((const char * )ba.data(), ba.size_s(), __utf8name__); return *this;}
PIString & operator +=(const PIString & str);
PIString(const PIString & o): PIDeque<PIChar>() {*this += o;}
//! Contructs string with single symbol "c"
PIString(const PIChar & c): PIDeque<PIChar>() {*this += c;}
PIString(const char c): PIDeque<PIChar>() {*this += PIChar(c);}
/*! \brief Contructs string from c-string "str"
* \details "str" should be null-terminated\n
* Example: \snippet pistring.cpp PIString(char * ) */
PIString(const char * str): PIDeque<PIChar>() {*this += str;}
/*! \brief Contructs string from \c wchar_t c-string "str"
* \details "str" should be null-terminated\n
* Example: \snippet pistring.cpp PIString(wchar_t * ) */
PIString(const wchar_t * str): PIDeque<PIChar>() {*this += str;}
//! Contructs string from byte array "ba"
PIString(const PIByteArray & ba): PIDeque<PIChar>() {*this += ba;}
//! \brief Contructs string from "len" characters of buffer "str"
PIString(const PIChar * str, const int len): PIDeque<PIChar>(str, size_t(len)) {}
/*! \brief Contructs string from "len" characters of buffer "str"
* \details Example: \snippet pistring.cpp PIString(char * , int) */
PIString(const char * str, const int len): PIDeque<PIChar>() {appendFromChars(str, len);}
/*! \brief Contructs string as sequence of characters "c" of buffer with length "len"
* \details Example: \snippet pistring.cpp PIString(int, char) */
PIString(const int len, const char c): PIDeque<PIChar>() {for (int i = 0; i < len; ++i) push_back(c);}
/*! \brief Contructs string as sequence of symbols "c" of buffer with length "len"
* \details Example: \snippet pistring.cpp PIString(int, PIChar) */
PIString(const int len, const PIChar & c): PIDeque<PIChar>() {for (int i = 0; i < len; ++i) push_back(c);}
~PIString() {}
PIString & operator =(const PIString & o) {if (this == &o) return *this; clear(); *this += o; return *this;}
/*! \brief Return c-string representation of string
* \details Converts content of string to c-string and return
* pointer to first char. This buffer is valid until new convertion
* or execution \a data() or \a toByteArray().\n
* Example: \snippet pistring.cpp PIString::char* */
operator const char*() {return data();}
//! Return symbol at index "pos"
PIChar operator [](const int pos) const {return at(pos);}
//! Return reference to symbol at index "pos"
PIChar & operator [](const int pos) {return at(pos);}
//! Compare operator
bool operator ==(const PIString & str) const;
//! Compare operator
bool operator ==(const PIChar c) const {return *this == PIString(c);}
//! Compare operator
bool operator ==(const char * str) const {return *this == PIString(str);}
//! Compare operator
bool operator !=(const PIString & str) const;
//! Compare operator
bool operator !=(const PIChar c) const {return *this != PIString(c);}
//! Compare operator
bool operator !=(const char * str) const {return *this != PIString(str);}
//! Compare operator
bool operator <(const PIString & str) const;
//! Compare operator
bool operator <(const PIChar c) const {return *this < PIString(c);}
//! Compare operator
bool operator <(const char * str) const {return *this < PIString(str);}
//! Compare operator
bool operator >(const PIString & str) const;
//! Compare operator
bool operator >(const PIChar c) const {return *this > PIString(c);}
//! Compare operator
bool operator >(const char * str) const {return *this > PIString(str);}
//! Compare operator
bool operator <=(const PIString & str) const {return !(*this > str);}
//! Compare operator
bool operator <=(const PIChar c) const {return *this <= PIString(c);}
//! Compare operator
bool operator <=(const char * str) const {return *this <= PIString(str);}
//! Compare operator
bool operator >=(const PIString & str) const {return !(*this < str);}
//! Compare operator
bool operator >=(const PIChar c) const {return *this >= PIString(c);}
//! Compare operator
bool operator >=(const char * str) const {return *this >= PIString(str);}
/*! \brief Append string "str" at the end of string
* \details Example: \snippet pistring.cpp PIString::<<(PIString) */
PIString & operator <<(const PIString & str) {*this += str; return *this;}
/*! \brief Append symbol "c" at the end of string
* \details Example: \snippet pistring.cpp PIString::<<(PIChar) */
PIString & operator <<(const PIChar & c) {*this += c; return *this;}
/*! \brief Append c-string "str" at the end of string
* \details Example: \snippet pistring.cpp PIString::<<(char * ) */
PIString & operator <<(const char * str) {*this += str; return *this;}
/*! \brief Append \c wchar_t c-string "str" at the end of string
* \details Example: \snippet pistring.cpp PIString::<<(wchar_t * ) */
PIString & operator <<(const wchar_t * str) {*this += str; return *this;}
/*! \brief Append string representation of "num" at the end of string
* \details Example: \snippet pistring.cpp PIString::<<(int) */
PIString & operator <<(const int & num) {*this += PIString::fromNumber(num); return *this;}
PIString & operator <<(const uint & num) {*this += PIString::fromNumber(num); return *this;}
/*! \brief Append string representation of "num" at the end of string
* \details Example: \snippet pistring.cpp PIString::<<(int) */
PIString & operator <<(const short & num) {*this += PIString::fromNumber(num); return *this;}
PIString & operator <<(const ushort & num) {*this += PIString::fromNumber(num); return *this;}
/*! \brief Append string representation of "num" at the end of string
* \details Example: \snippet pistring.cpp PIString::<<(int) */
PIString & operator <<(const long & num) {*this += PIString::fromNumber(num); return *this;}
PIString & operator <<(const ulong & num) {*this += PIString::fromNumber(num); return *this;}
PIString & operator <<(const llong & num) {*this += PIString::fromNumber(num); return *this;}
PIString & operator <<(const ullong & num) {*this += PIString::fromNumber(num); return *this;}
/*! \brief Append string representation of "num" at the end of string
* \details Example: \snippet pistring.cpp PIString::<<(int) */
PIString & operator <<(const float & num) {*this += PIString::fromNumber(num); return *this;}
/*! \brief Append string representation of "num" at the end of string
* \details Example: \snippet pistring.cpp PIString::<<(int) */
PIString & operator <<(const double & num) {*this += PIString::fromNumber(num); return *this;}
//! \brief Insert string "str" at the begin of string
PIString & prepend(const PIString & str) {insert(0, str); return *this;}
//! \brief Insert string "str" at the end of string
PIString & append(const PIString & str) {*this += str; return *this;}
/*! \brief Return part of string from symbol at index "start" and maximum length "len"
* \details All variants demonstrated in example: \snippet pistring.cpp PIString::mid
* \sa \a left(), \a right() */
PIString mid(const int start, const int len = -1) const;
/*! \brief Return sub-string of string from symbol at index "start" and maximum length "len" */
PIString subString(const int start, const int len = -1) const {return mid(start, len);}
/*! \brief Return part of string from left and maximum length "len"
* \details Example: \snippet pistring.cpp PIString::left
* \sa \a mid(), \a right() */
PIString left(const int len) const {return len <= 0 ? PIString() : mid(0, len);}
/*! \brief Return part of string from right and maximum length "len"
* \details Example: \snippet pistring.cpp PIString::right
* \sa \a mid(), \a left() */
PIString right(const int len) const {return len <= 0 ? PIString() : mid(size() - len, len);}
/*! \brief Remove part of string from symbol as index "start" and maximum length "len"
* and return this string
* \details All variants demonstrated in example: \snippet pistring.cpp PIString::cutMid
* \sa \a cutLeft(), \a cutRight() */
PIString & cutMid(const int start, const int len);
/*! \brief Remove part of string from left and maximum length "len" and return this string
* \details Example: \snippet pistring.cpp PIString::cutLeft
* \sa \a cutMid(), \a cutRight() */
PIString & cutLeft(const int len) {return len <= 0 ? *this : cutMid(0, len);}
/*! \brief Remove part of string from right and maximum length "len" and return this string
* \details Example: \snippet pistring.cpp PIString::cutRight
* \sa \a cutMid(), \a cutLeft() */
PIString & cutRight(const int len) {return len <= 0 ? *this : cutMid(size() - len, len);}
/*! \brief Remove spaces at the start and at the end of string and return this string
* \details Example: \snippet pistring.cpp PIString::trim
* \sa \a trimmed() */
PIString & trim();
/*! \brief Return copy of this string without spaces at the start and at the end
* \details Example: \snippet pistring.cpp PIString::trimmed
* \sa \a trim() */
PIString trimmed() const;
/*! \brief Replace part of string from index "from" and maximum length "len"
* with string "with" and return this string
* \details Example: \snippet pistring.cpp PIString::replace_0
* \sa \a replaced(), \a replaceAll() */
PIString & replace(const int from, const int count, const PIString & with);
/*! \brief Replace part copy of this string from index "from" and maximum length "len"
* with string "with" and return copied string
* \details Example: \snippet pistring.cpp PIString::replaced_0
* \sa \a replace(), \a replaceAll() */
PIString replaced(const int from, const int count, const PIString & with) const {PIString str(*this); str.replace(from, count, with); return str;}
/*! \brief Replace first founded substring "what" with string "with" and return this string
* \details If "ok" is not null, it set to "true" if something was replaced\n
* Example: \snippet pistring.cpp PIString::replace_1
* \sa \a replaced(), \a replaceAll() */
PIString & replace(const PIString & what, const PIString & with, bool * ok = 0);
/*! \brief Replace first founded substring "what" with string "with" and return copied string
* \details If "ok" is not null, it set to "true" if something was replaced\n
* Example: \snippet pistring.cpp PIString::replaced_1
* \sa \a replaced(), \a replaceAll() */
PIString replaced(const PIString & what, const PIString & with, bool * ok = 0) const {PIString str(*this); str.replace(what, with, ok); return str;}
/*! \brief Replace all founded substrings "what" with strings "with" and return this string
* \details Example: \snippet pistring.cpp PIString::replaceAll
* \sa \a replace(), \a replaced() */
PIString & replaceAll(const PIString & what, const PIString & with);
PIString replaceAll(const PIString & what, const PIString & with) const {PIString str(*this); str.replaceAll(what, with); return str;}
/*! \brief Repeat content of string "times" times and return this string
* \details Example: \snippet pistring.cpp PIString::repeat */
PIString & repeat(int times) {PIString ss(*this); times--; piForTimes (times) *this += ss; return *this;}
/*! \brief Returns repeated "times" times string
* \details Example: \snippet pistring.cpp PIString::repeated */
PIString repeated(int times) const {PIString ss(*this); return ss.repeat(times);}
/*! \brief Insert symbol "c" after index "index" and return this string
* \details Example: \snippet pistring.cpp PIString::insert_0 */
PIString & insert(const int index, const PIChar & c) {PIDeque<PIChar>::insert(index, c); return *this;}
/*! \brief Insert symbol "c" after index "index" and return this string
* \details Example: \snippet pistring.cpp PIString::insert_1 */
PIString & insert(const int index, const char & c) {return insert(index, PIChar(c));}
/*! \brief Insert string "str" after index "index" and return this string
* \details Example: \snippet pistring.cpp PIString::insert_2 */
PIString & insert(const int index, const PIString & str);
/*! \brief Insert string "str" after index "index" and return this string
* \details Example: \snippet pistring.cpp PIString::insert_2 */
PIString & insert(const int index, const char * c) {return insert(index, PIString(c));}
/*! \brief Enlarge string to length "len" by addition sequence of symbols
* "c" at the end of string, and return this string
* \details Example: \snippet pistring.cpp PIString::expandRightTo
* \sa \a expandLeftTo() */
PIString & expandRightTo(const int len, const PIChar & c) {if (len > length()) resize(len, c); return *this;}
/*! \brief Enlarge string to length "len" by addition sequence of symbols
* "c" at the beginning of string, and return this string
* \details Example: \snippet pistring.cpp PIString::expandLeftTo
* \sa \a expandRightTo() */
PIString & expandLeftTo(const int len, const PIChar & c) {if (len > length()) insert(0, PIString(len - length(), c)); return *this;}
/*! \brief Add "c" symbols at the beginning and end of the string, and return this string
* \sa \a quoted() */
PIString & quote(PIChar c = PIChar('"')) {insert(0, c); *this += c; return *this;}
/*! \brief Return quoted copy of this string
* \sa \a quote() */
PIString quoted(PIChar c = PIChar('"')) {return PIString(*this).quote(c);}
/*! \brief Reverse string and return this string
* \details Example: \snippet pistring.cpp PIString::reverse
* \sa \a reversed() */
PIString & reverse() {PIString str(*this); clear(); piForeachR (const PIChar & c, str) push_back(c); return *this;}
/*! \brief Reverse copy of this string and return it
* \details Example: \snippet pistring.cpp PIString::reversed
* \sa \a reverse() */
PIString reversed() const {PIString str(*this); str.reverse(); return str;}
/*! \brief Elide string to maximum size \"size\" and return this string
* \sa \a elided() */
PIString & elide(int size, float pos = ElideCenter);
/*! \brief Elide copy of this string to maximum size \"size\" and return it
* \details Example: \snippet pistring.cpp PIString::elided
* \sa \a elide() */
PIString elided(int size, float pos = ElideCenter) const {PIString str(*this); str.elide(size, pos); return str;}
/*! \brief Take a part of string from symbol at index "start" and maximum length "len" and return it
* \details Example: \snippet pistring.cpp PIString::takeMid
* \sa \a takeLeft, \a takeRight() */
PIString takeMid(const int start, const int len = -1) {PIString ret(mid(start, len)); cutMid(start, len); return ret;}
/*! \brief Take a part from the begin of string with maximum length "len" and return it
* \details Example: \snippet pistring.cpp PIString::takeLeft
* \sa \a takeMid(), \a takeRight() */
PIString takeLeft(const int len) {PIString ret(left(len)); cutLeft(len); return ret;}
/*! \brief Take a part from the end of string with maximum length "len" and return it
* \details Example: \snippet pistring.cpp PIString::takeRight
* \sa \a takeMid(), \a takeLeft() */
PIString takeRight(const int len) {PIString ret(right(len)); cutRight(len); return ret;}
/*! \brief Take a symbol from the begin of this string and return it
* \details Example: \snippet pistring.cpp PIString::takeSymbol
* \sa \a takeWord(), \a takeCWord(), \a takeLine(), \a takeNumber(), \a takeRange() */
PIString takeSymbol();
/*! \brief Take a word from the begin of this string and return it
* \details Example: \snippet pistring.cpp PIString::takeWord
* \sa \a takeSymbol(), \a takeCWord(), \a takeLine(), \a takeNumber(), \a takeRange() */
PIString takeWord();
/*! \brief Take a word with letters, numbers and '_' symbols from the
* begin of this string and return it
* \details Example: \snippet pistring.cpp PIString::takeCWord
* \sa \a takeSymbol(), \a takeWord(), \a takeLine(), \a takeNumber(), \a takeRange() */
PIString takeCWord();
/*! \brief Take a line from the begin of this string and return it
* \details Example: \snippet pistring.cpp PIString::takeLine
* \sa \a takeSymbol(), \a takeWord(), \a takeCWord(), \a takeNumber(), \a takeRange() */
PIString takeLine();
/*! \brief Take a number with C-format from the begin of this string and return it
* \details Example: \snippet pistring.cpp PIString::takeNumber
* \sa \a takeSymbol(), \a takeWord(), \a takeCWord(), \a takeLine(), \a takeRange() */
PIString takeNumber();
/*! \brief Take a range between "start" and "end" symbols from the begin of this
* string and return it.
* \details "Shield" symbol prevent analysis of the next symbol.
* Example: \snippet pistring.cpp PIString::takeRange
* \sa \a takeSymbol(), \a takeWord(), \a takeLine(), \a takeNumber() */
PIString takeRange(const PIChar & start, const PIChar & end, const PIChar & shield = '\\');
/*! \brief Return a string in brackets "start" and "end" symbols from the begin of this
* string and return it.
* \details Example: string = "a(b(c)d)e"; inBrackets('(', ')') = "b(c)d"; */
PIString inBrackets(const PIChar & start, const PIChar & end) const;
/*! \brief Return real bytes count of this string
* \details It`s equivalent length of char sequence
* returned by function \a data() - 1, without terminating null-char \n
* Example: \snippet pistring.cpp PIString::lengthAscii
* \sa \a data() */
int lengthAscii() const {buildData(__syslocname__); return data_.size_s() - 1;}
/*! \brief Return \c char * representation of this string in system codepage
* \details This function fill buffer by sequence
* of chars. Minimum length of this buffer is count
* of symbols. Returned \c char * is valid until next
* execution of this function.\n
* Example: \snippet pistring.cpp PIString::data
* \sa \a dataConsole(), \a dataUTF8() */
const char * data() const {buildData(__syslocname__); return (const char *)(data_.data());}
/*! \brief Return \c char * representation of this string in terminal codepage
* \details This function fill buffer by sequence
* of chars. Minimum length of this buffer is count
* of symbols. Returned \c char * is valid until next
* execution of this function.\n
* \sa \a data(), \a dataUTF8() */
const char * dataConsole() const;
/*! \brief Return \c char * representation of this string in UTF-8
* \details This function fill buffer by sequence
* of chars. Minimum length of this buffer is count
* of symbols. Returned \c char * is valid until next
* execution of this function.\n
* \sa \a data(), \a dataConsole() */
const char * dataUTF8() const;
/*! \brief Return \c char * representation of this string in ASCII
* \details This function fill buffer by sequence
* of chars. Minimum length of this buffer is count
* of symbols. Returned \c char * is valid until next
* execution of this function.\n */
const char * dataAscii() const;
//! Returns hash
uint hash() const;
//! \brief Return \a PIByteArray contains \a data() of this string without terminating null-char
PIByteArray toByteArray() const {buildData(__utf8name__); return data_.resized(data_.size_s() - 1);}
//! \brief Return \a PIByteArray contains UTF-8 \a data() of this string without terminating null-char
PIByteArray toUTF8() const;
//! \brief Return \a PIByteArray contains custom charset representation of this string without terminating null-char
PIByteArray toCharset(const char * c) const;
/*! \brief Split string with delimiter "delim" to \a PIStringList and return it
* \details Example: \snippet pistring.cpp PIString::split */
PIStringList split(const PIString & delim) const;
//! \brief Convert each symbol in copyed string to upper case and return it
PIString toUpperCase() const;
//! \brief Convert each symbol in copyed string to lower case and return it
PIString toLowerCase() const;
PIString toNativeDecimalPoints() const;
//! \brief Returns if string contains "str"
bool contains(const char str) const {return contains(PIString(str));}
//! \brief Returns if string contains "str"
bool contains(const PIChar str) const {return contains(PIString(str));}
//! \brief Returns if string contains "str"
bool contains(const char * str) const {return contains(PIString(str));}
//! \brief Returns if string contains "str"
bool contains(const PIString & str) const {return find(str) >= 0;}
//! \brief Search substring "str" from symbol at index "start" and return first occur position
//! \details Example: \snippet pistring.cpp PIString::find
int find(const char str, const int start = 0) const;
//! \brief Search substring "str" from symbol at index "start" and return first occur position
//! \details Example: \snippet pistring.cpp PIString::find
int find(const PIString & str, const int start = 0) const;
//! \brief Search substring "str" from symbol at index "start" and return first occur position
//! \details Example: \snippet pistring.cpp PIString::find
int find(const char * str, const int start = 0) const {return find(PIString(str), start);}
//! \brief Search substring "str" from symbol at index "start" and return last occur position
//! \details Example: \snippet pistring.cpp PIString::findLast
int findLast(const char str, const int start = 0) const;
//! \brief Search substring "str" from symbol at index "start" and return last occur position
//! \details Example: \snippet pistring.cpp PIString::findLast
int findLast(const PIString & str, const int start = 0) const;
//! \brief Search substring "str" from symbol at index "start" and return last occur position
//! \details Example: \snippet pistring.cpp PIString::findLast
int findLast(const char * str, const int start = 0) const {return findLast(PIString(str), start);}
//! \brief Search word "word" from symbol at index "start" and return first occur position.
//! \details Example: \snippet pistring.cpp PIString::findWord
int findWord(const PIString & word, const int start = 0) const;
//! \brief Search C-style word "word" from symbol at index "start" and return first occur position.
//! \details Example: \snippet pistring.cpp PIString::findCWord
int findCWord(const PIString & word, const int start = 0) const;
//! \brief Search range between "start" and "end" symbols at index "start_index" and return first occur position.
//! \details Example: \snippet pistring.cpp PIString::findRange
int findRange(const PIChar & start, const PIChar & end, const PIChar & shield = '\\', const int start_index = 0, int * len = 0) const;
//! \brief Search any symbol of "str" from symbol at index "start" and return first occur position
//! \details Example: \snippet pistring.cpp PIString::findAny
int findAny(const PIString & str, const int start = 0) const;
//! \brief Search any symbol of "str" from symbol at index "start" and return first occur position
//! \details Example: \snippet pistring.cpp PIString::findAny
int findAny(const char * str, const int start = 0) const {return findAny(PIString(str), start);}
//! \brief Search any symbol of "str" from symbol at index "start" and return last occur position
//! \details Example: \snippet pistring.cpp PIString::findAnyLast
int findAnyLast(const PIString & str, const int start = 0) const;
//! \brief Search any symbol of "str" from symbol at index "start" and return last occur position
//! \details Example: \snippet pistring.cpp PIString::findAnyLast
int findAnyLast(const char * str, const int start = 0) const {return findAnyLast(PIString(str), start);}
//! \brief Returns number of occurrences of symbol "c"
int entries(const PIChar & c) const;
//! \brief Returns number of occurrences of symbol "c"
int entries(char c) const {return entries(PIChar(c));}
//! \brief Return if string starts with "str"
bool startsWith(const PIString & str) const;
//! \brief Return if string ends with "str"
bool endsWith(const PIString & str) const;
//! \brief Return symbols length of string
int length() const {return size();}
//! \brief Return \c true if string is empty, i.e. length = 0
bool isEmpty() const {return (size() == 0 || *this == "");}
//! \brief Return \c true if string equal "true", "yes", "on" or positive not null numeric value
bool toBool() const;
//! \brief Return \c char numeric value of string
char toChar() const;
//! \brief Return \c short numeric value of string in base "base"
//! \details Example: \snippet pistring.cpp PIString::toNumber
short toShort(int base = -1, bool * ok = 0) const {return short(toNumberBase(*this, base, ok));}
//! \brief Return \c ushort numeric value of string in base "base"
//! \details Example: \snippet pistring.cpp PIString::toNumber
ushort toUShort(int base = -1, bool * ok = 0) const {return ushort(toNumberBase(*this, base, ok));}
//! \brief Return \c int numeric value of string in base "base"
//! \details Example: \snippet pistring.cpp PIString::toNumber
int toInt(int base = -1, bool * ok = 0) const {return int(toNumberBase(*this, base, ok));}
//! \brief Return \c uint numeric value of string in base "base"
//! \details Example: \snippet pistring.cpp PIString::toNumber
uint toUInt(int base = -1, bool * ok = 0) const {return uint(toNumberBase(*this, base, ok));}
//! \brief Return \c long numeric value of string in base "base"
//! \details Example: \snippet pistring.cpp PIString::toNumber
long toLong(int base = -1, bool * ok = 0) const {return long(toNumberBase(*this, base, ok));}
//! \brief Return \c ulong numeric value of string in base "base"
//! \details Example: \snippet pistring.cpp PIString::toNumber
ulong toULong(int base = -1, bool * ok = 0) const {return ulong(toNumberBase(*this, base, ok));}
//! \brief Return \c llong numeric value of string in base "base"
//! \details Example: \snippet pistring.cpp PIString::toNumber
llong toLLong(int base = -1, bool * ok = 0) const {return toNumberBase(*this, base, ok);}
//! \brief Return \c ullong numeric value of string in base "base"
//! \details Example: \snippet pistring.cpp PIString::toNumber
ullong toULLong(int base = -1, bool * ok = 0) const {return ullong(toNumberBase(*this, base, ok));}
//! \brief Return \c float numeric value of string
//! \details Example: \snippet pistring.cpp PIString::toFloat
float toFloat() const;
//! \brief Return \c double numeric value of string
//! \details Example: \snippet pistring.cpp PIString::toFloat
double toDouble() const;
//! \brief Return \c ldouble numeric value of string
//! \details Example: \snippet pistring.cpp PIString::toFloat
ldouble toLDouble() const;
//! \brief Set string content to numeric representation of "value" in base "base"
//! \details Example: \snippet pistring.cpp PIString::setNumber
PIString & setNumber(const short value, int base = 10, bool * ok = 0) {clear(); *this += PIString::fromNumber(value, base, ok); return *this;}
//! \brief Set string content to numeric representation of "value" in base "base"
//! \details Example: \snippet pistring.cpp PIString::setNumber
PIString & setNumber(const ushort value, int base = 10, bool * ok = 0) {clear(); *this += PIString::fromNumber(value, base, ok); return *this;}
//! \brief Set string content to numeric representation of "value" in base "base"
//! \details Example: \snippet pistring.cpp PIString::setNumber
PIString & setNumber(const int value, int base = 10, bool * ok = 0) {clear(); *this += PIString::fromNumber(value, base, ok); return *this;}
//! \brief Set string content to numeric representation of "value" in base "base"
//! \details Example: \snippet pistring.cpp PIString::setNumber
PIString & setNumber(const uint value, int base = 10, bool * ok = 0) {clear(); *this += PIString::fromNumber(value, base, ok); return *this;}
//! \brief Set string content to numeric representation of "value" in base "base"
//! \details Example: \snippet pistring.cpp PIString::setNumber
PIString & setNumber(const long value, int base = 10, bool * ok = 0) {clear(); *this += PIString::fromNumber(value, base, ok); return *this;}
//! \brief Set string content to numeric representation of "value" in base "base"
//! \details Example: \snippet pistring.cpp PIString::setNumber
PIString & setNumber(const ulong value, int base = 10, bool * ok = 0) {clear(); *this += PIString::fromNumber(value, base, ok); return *this;}
//! \brief Set string content to numeric representation of "value" in base "base"
//! \details Example: \snippet pistring.cpp PIString::setNumber
PIString & setNumber(const llong & value, int base = 10, bool * ok = 0) {clear(); *this += PIString::fromNumber(value, base, ok); return *this;}
//! \brief Set string content to numeric representation of "value" in base "base"
//! \details Example: \snippet pistring.cpp PIString::setNumber
PIString & setNumber(const ullong & value, int base = 10, bool * ok = 0) {clear(); *this += PIString::fromNumber(value, base, ok); return *this;}
//! \brief Set string content to numeric representation of "value"
//! \details Example: \snippet pistring.cpp PIString::setFloat
PIString & setNumber(const float value, char format = 'f', int precision = 8) {clear(); *this += PIString::fromNumber(value, format, precision); return *this;}
//! \brief Set string content to numeric representation of "value"
//! \details Example: \snippet pistring.cpp PIString::setFloat
PIString & setNumber(const double & value, char format = 'f', int precision = 8) {clear(); *this += PIString::fromNumber(value, format, precision); return *this;}
//! \brief Set string content to numeric representation of "value"
//! \details Example: \snippet pistring.cpp PIString::setFloat
PIString & setNumber(const ldouble & value, char format = 'f', int precision = 8) {clear(); *this += PIString::fromNumber(value, format, precision); return *this;}
//! \brief Set string content to human readable size in B/kB/MB/GB/TB
//! \details Example: \snippet pistring.cpp PIString::setReadableSize
PIString & setReadableSize(llong bytes);
//! \brief Return string contains numeric representation of "value" in base "base"
//! \details Example: \snippet pistring.cpp PIString::fromNumber
static PIString fromNumber(const short value, int base = 10, bool * ok = 0) {return fromNumberBaseS(llong(value), base, ok);}
//! \brief Return string contains numeric representation of "value" in base "base"
//! \details Example: \snippet pistring.cpp PIString::fromNumber
static PIString fromNumber(const ushort value, int base = 10, bool * ok = 0) {return fromNumberBaseU(ullong(value), base, ok);}
//! \brief Return string contains numeric representation of "value" in base "base"
//! \details Example: \snippet pistring.cpp PIString::fromNumber
static PIString fromNumber(const int value, int base = 10, bool * ok = 0) {return fromNumberBaseS(llong(value), base, ok);}
//! \brief Return string contains numeric representation of "value" in base "base"
//! \details Example: \snippet pistring.cpp PIString::fromNumber
static PIString fromNumber(const uint value, int base = 10, bool * ok = 0) {return fromNumberBaseU(ullong(value), base, ok);}
//! \brief Return string contains numeric representation of "value" in base "base"
//! \details Example: \snippet pistring.cpp PIString::fromNumber
static PIString fromNumber(const long value, int base = 10, bool * ok = 0) {return fromNumberBaseS(llong(value), base, ok);}
//! \brief Return string contains numeric representation of "value" in base "base"
//! \details Example: \snippet pistring.cpp PIString::fromNumber
static PIString fromNumber(const ulong value, int base = 10, bool * ok = 0) {return fromNumberBaseU(ullong(value), base, ok);}
//! \brief Return string contains numeric representation of "value" in base "base"
//! \details Example: \snippet pistring.cpp PIString::fromNumber
static PIString fromNumber(const llong & value, int base = 10, bool * ok = 0) {return fromNumberBaseS(value, base, ok);}
//! \brief Return string contains numeric representation of "value" in base "base"
//! \details Example: \snippet pistring.cpp PIString::fromNumber
static PIString fromNumber(const ullong & value, int base = 10, bool * ok = 0) {return fromNumberBaseU(value, base, ok);}
//! \brief Return string contains numeric representation of "value"
//! \details Example: \snippet pistring.cpp PIString::fromFloat
static PIString fromNumber(const float value, char format = 'f', int precision = 8) {return ftos(value, format, precision);}
//! \brief Return string contains numeric representation of "value"
//! \details Example: \snippet pistring.cpp PIString::fromFloat
static PIString fromNumber(const double & value, char format = 'f', int precision = 8) {return dtos(value, format, precision);}
//! \brief Return string contains numeric representation of "value"
//! \details Example: \snippet pistring.cpp PIString::fromFloat
static PIString fromNumber(const ldouble & value, char format = 'f', int precision = 8) {return dtos(value, format, precision);}
//! \brief Return "true" or "false"
static PIString fromBool(const bool value) {return PIString(value ? "true" : "false");}
//! \brief Return string constructed from terminal codepage
static PIString fromConsole(const char * s);
//! \brief Return string constructed from system codepage
static PIString fromSystem(const char * s);
//! \brief Return string constructed from UTF-8
static PIString fromUTF8(const char * s);
//! \brief Return string constructed from UTF-8
static PIString fromUTF8(const PIByteArray &ba);
//! \brief Return string constructed from ASCII
static PIString fromAscii(const char * s);
//! \brief Return string constructed from "c" codepage
static PIString fromCodepage(const char * s, const char * c);
//! \brief Return string contains human readable size in B/kB/MB/GB/TB
//! \details Example: \snippet pistring.cpp PIString::readableSize
static PIString readableSize(llong bytes);
PIString & removeAll(char v) {replaceAll(v, ""); return *this;}
PIString & removeAll(const PIString & v) {replaceAll(v, ""); return *this;}
private:
static const char toBaseN[];
static const int fromBaseN[];
static PIString itos(const int num);
static PIString ltos(const long num);
static PIString lltos(const llong num);
static PIString uitos(const uint num);
static PIString ultos(const ulong num);
static PIString ulltos(const ullong num);
static PIString ftos(const float num, char format = 'f', int precision = 8);
static PIString dtos(const double num, char format = 'f', int precision = 8);
static PIString fromNumberBaseS(const llong value, int base = 10, bool * ok = 0);
static PIString fromNumberBaseU(const ullong value, int base = 10, bool * ok = 0);
static llong toNumberBase(const PIString & value, int base = -1, bool * ok = 0);
void appendFromChars(const char * c, int s, const char * cp = __syslocname__);
void buildData(const char * cp = __syslocname__) const;
void trimsubstr(int &st, int &fn) const;
mutable PIByteArray data_;
};
//! \relatesalso PIString \relatesalso PICout \brief Output operator to PICout
PIP_EXPORT PICout operator <<(PICout s, const PIString & v);
//! \relatesalso PIString \relatesalso PIByteArray \brief Output operator to PIByteArray
inline PIByteArray & operator <<(PIByteArray & s, const PIString & v) {s << *(PIDeque<PIChar>*)&v; return s;}
//! \relatesalso PIString \relatesalso PIByteArray \brief Input operator from PIByteArray
inline PIByteArray & operator >>(PIByteArray & s, PIString & v) {v.clear(); s >> *(PIDeque<PIChar>*)&v; return s;}
//! \relatesalso PIString \brief Return concatenated string
inline PIString operator +(const PIString & str, const PIString & f) {PIString s(str); s += f; return s;}
//! \relatesalso PIString \brief Return concatenated string
inline PIString operator +(const PIString & f, const char * str) {PIString s(f); s += str; return s;}
//! \relatesalso PIString \brief Return concatenated string
inline PIString operator +(const char * str, const PIString & f) {return PIString(str) + f;}
inline char chrUpr(char c);
inline char chrLwr(char c);
int versionCompare(const PIString & v0, const PIString & v1, int components = 6);
PIString versionNormalize(const PIString & v);
template<> inline uint piHash(const PIString & s) {return s.hash();}
#endif // PISTRING_H

View File

@@ -0,0 +1,100 @@
/*! \file pistring.h
* \brief String
*
* This file declare std operators and string conversions
*/
/*
PIP - Platform Independent Primitives
STD for PIString
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PISTRING_STD_H
#define PISTRING_STD_H
#include <string>
#ifdef QNX
typedef std::basic_string<wchar_t> wstring;
#endif
#include "pistringlist.h"
inline std::string PIString2StdString(const PIString & v) {
std::string s;
uint wc;
uchar tc;
if (v.size() > 0) {
for (int i = 0; i < v.length(); ++i) {
wc = uint(v.at(i).unicode16Code());
while (tc = wc & 0xFF, tc) {
s.push_back(char(tc));
wc >>= 8;
}
}
}
return s;
}
inline PIString StdString2PIString(const std::string & v) {
return PIString(v.c_str(), v.length());
}
#ifdef HAS_LOCALE
inline std::wstring PIString2StdWString(const PIString & v) {
std::wstring s;
for (int i = 0; i < v.length(); ++i)
s.push_back(v.at(i).toWChar());
return s;
}
inline PIString StdWString2PIString(const std::wstring & v) {
PIString s;
uint l = v.size();
for (uint i = 0; i < l; ++i) s.push_back(v[i]);
return s;
}
#endif
//! \relatesalso PIChar \brief Output operator to \c std::ostream
inline std::ostream & operator <<(std::ostream & s, const PIChar & v) {s << v.toCharPtr(); return s;}
//! \relatesalso PIString \brief Return concatenated string
inline PIString operator +(const PIString & f, const std::string & str) {PIString s(f); s += StdString2PIString(str); return s;}
//! \relatesalso PIString \brief Return concatenated string
inline PIString operator +(const std::string & str, const PIString & f) {return StdString2PIString(str) + f;}
//! \relatesalso PIString \brief Output operator to std::ostream (cout)
inline std::ostream & operator <<(std::ostream & s, const PIString & v) {for (int i = 0; i < v.length(); ++i) s << v[i]; return s;}
//! \relatesalso PIString \brief Input operator from std::istream (cin)
inline std::istream & operator >>(std::istream & s, PIString & v) {std::string ss; s >> ss; v = StdString2PIString(ss); return s;}
//! \relatesalso PIStringList \brief Output operator to std::ostream (cout)
inline std::ostream & operator <<(std::ostream & s, const PIStringList & v) {
s << PIChar("{");
for (uint i = 0; i < v.size(); ++i) {
s << PIChar("\"") << v[i] << PIChar("\"");
if (i < v.size() - 1) s << PIStringAscii(", ");
}
s << PIChar("}");
return s;
}
#endif // PISTRING_STD_H

View File

@@ -0,0 +1,42 @@
/*
PIP - Platform Independent Primitives
Strings array class
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "pistringlist.h"
PIStringList& PIStringList::removeDuplicates() {
PIStringList l;
PIString s;
bool ae;
for (int i = 0; i < size_s(); ++i) {
ae = false;
s = at(i);
for (int j = 0; j < l.size_s(); ++j) {
if (s != l[j]) continue;
ae = true; break;
}
if (!ae) {
l << s;
continue;
}
remove(i);
--i;
}
return *this;
}

View File

@@ -0,0 +1,100 @@
/*! \brief Strings array class
* \details This class is based on \a PIDeque<PIString> and
* expand it functionality. */
/*
PIP - Platform Independent Primitives
Strings array class
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PISTRINGLIST_H
#define PISTRINGLIST_H
#include "pistring.h"
class PIP_EXPORT PIStringList: public PIDeque<PIString>
{
public:
//! Contructs empty strings list
PIStringList() {;}
~PIStringList() {;}
//! Contructs strings list with one string "str"
PIStringList(const PIString & str) {push_back(str);}
//! Contructs empty strings list with strings "s0" and "s1"
PIStringList(const PIString & s0, const PIString & s1) {push_back(s0); push_back(s1);}
//! Contructs empty strings list with strings "s0", "s1" and "s2"
PIStringList(const PIString & s0, const PIString & s1, const PIString & s2) {push_back(s0); push_back(s1); push_back(s2);}
//! Contructs empty strings list with strings "s0", "s1", "s2" and "s3"
PIStringList(const PIString & s0, const PIString & s1, const PIString & s2, const PIString & s3) {push_back(s0); push_back(s1); push_back(s2); push_back(s3);}
PIStringList(const PIStringList & o): PIDeque<PIString>() {resize(o.size()); for (uint i = 0; i < size(); ++i) (*this)[i] = o[i];}
PIStringList(const PIVector<PIString> & o): PIDeque<PIString>() {resize(o.size()); for (uint i = 0; i < size(); ++i) (*this)[i] = o[i];}
PIStringList(const PIDeque<PIString> & o): PIDeque<PIString>() {resize(o.size()); for (uint i = 0; i < size(); ++i) (*this)[i] = o[i];}
//! \brief Join all strings in one with delimiter "delim" and return it
//! \details Example: \snippet pistring.cpp PIStringList::join
PIString join(const PIString & delim) const {PIString s; for (uint i = 0; i < size(); ++i) {s += at(i); if (i < size() - 1) s += delim;} return s;}
//! \brief Remove all strings equal "value" and return this
//! \details Example: \snippet pistring.cpp PIStringList::removeStrings
PIStringList & removeStrings(const PIString & value) {for (uint i = 0; i < size(); ++i) {if (at(i) == value) {remove(i); --i;}} return *this;}
PIStringList & remove(uint num) {PIDeque<PIString>::remove(num); return *this;}
PIStringList & remove(uint num, uint count) {PIDeque<PIString>::remove(num, count); return *this;}
//! \brief Remove duplicated strings and return this
//! \details Example: \snippet pistring.cpp PIStringList::removeDuplicates
PIStringList & removeDuplicates();
//! \brief Trim all strings
//! \details Example: \snippet pistring.cpp PIStringList::trim
PIStringList & trim() {for (uint i = 0; i < size(); ++i) at(i).trim(); return *this;}
//! Return sum of lengths of all strings
uint contentSize() {uint s = 0; for (uint i = 0; i < size(); ++i) s += at(i).size(); return s;}
//! Compare operator
bool operator ==(const PIStringList & o) const {if (size() != o.size()) return false; for (size_t i = 0; i < size(); ++i) if (o[i] != (*this)[i]) return false; return true;}
//! Compare operator
bool operator !=(const PIStringList & o) const {return !(o == (*this));}
PIStringList & operator =(const PIStringList & o) {PIDeque<PIString>::operator=(o); return *this;}
PIStringList & operator <<(const PIString & str) {append(str); return *this;}
PIStringList & operator <<(const PIStringList & sl) {append(sl); return *this;}
};
//! \relatesalso PIStringList \relatesalso PIByteArray \brief Output operator to PIByteArray
inline PIByteArray & operator <<(PIByteArray & s, const PIStringList & v) {s << int(v.size_s()); for (int i = 0; i < v.size_s(); ++i) s << v[i]; return s;}
//! \relatesalso PIStringList \relatesalso PIByteArray \brief Input operator from PIByteArray
inline PIByteArray & operator >>(PIByteArray & s, PIStringList & v) {int sz; s >> sz; v.resize(sz); for (int i = 0; i < sz; ++i) s >> v[i]; return s;}
//! \relatesalso PIStringList \relatesalso PICout \brief Output operator to PICout
inline PICout operator <<(PICout s, const PIStringList & v) {s.space(); s.setControl(0, true); s << "{"; for (uint i = 0; i < v.size(); ++i) {s << "\"" << v[i] << "\""; if (i < v.size() - 1) s << ", ";} s << "}"; s.restoreControl(); return s;}
#endif // PISTRINGLIST_H

474
lib/main/core/pitime.cpp Normal file
View File

@@ -0,0 +1,474 @@
/*
PIP - Platform Independent Primitives
Timer
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "piincludes_p.h"
#include "pitime.h"
#include "pisystemtests.h"
#ifdef WINDOWS
extern FILETIME __pi_ftjan1970;
long long __PIQueryPerformanceCounter() {LARGE_INTEGER li; QueryPerformanceCounter(&li); return li.QuadPart;}
#endif
#ifdef MAC_OS
//# include <mach/mach_traps.h>
//# include <mach/mach.h>
# include <mach/clock.h>
//# include <crt_externs.h>
extern clock_serv_t __pi_mac_clock;
#endif
#ifdef FREERTOS
# include "freertos/FreeRTOS.h"
# include "freertos/task.h"
#endif
/*! \class PISystemTime
* \brief System time
*
* \section PISystemTime_sec0 Synopsis
* This class provide arithmetic functions for POSIX system time.
* This time represents as seconds and nanosecons in integer formats.
* You can take current system time with function \a PISystemTime::current(),
* compare times, sum or subtract two times, convert time to/from
* seconds, milliseconds, microseconds or nanoseconds.
* \section PISystemTime_sec1 Example
* \snippet pitimer.cpp system_time
*/
/*! \class PITimeMeasurer
* \brief Time measurements
*
* \section PITimeMeasurer_sec0 Synopsis
* Function \a reset() set time mark to current
* system time, then functions double elapsed_*() returns time elapsed from this mark.
* These functions can returns nano-, micro-, milli- and seconds with suffixes "n", "u", "m"
* and "s"
*/
void piUSleep(int usecs) {
if (usecs <= 0) return;
#ifdef WINDOWS
//printf("Sleep %d\n", usecs / 1000);
if (usecs > 0) Sleep(usecs / 1000);
//printf("Sleep end");
#else
# ifdef FREERTOS
vTaskDelay(usecs / 1000 / portTICK_PERIOD_MS);
# else
usecs -= PISystemTests::usleep_offset_us;
if (usecs > 0) usleep(usecs);
# endif
#endif
}
bool operator ==(const PITime & t0, const PITime & t1) {
return (t0.hours == t1.hours && t0.minutes == t1.minutes && t0.seconds == t1.seconds);
}
bool operator <(const PITime & t0, const PITime & t1) {
if (t0.hours == t1.hours) {
if (t0.minutes == t1.minutes) {
return t0.seconds < t1.seconds;
} else return t0.minutes < t1.minutes;
} else return t0.hours < t1.hours;
}
bool operator >(const PITime & t0, const PITime & t1) {
if (t0.hours == t1.hours) {
if (t0.minutes == t1.minutes) {
return t0.seconds > t1.seconds;
} else return t0.minutes > t1.minutes;
} else return t0.hours > t1.hours;
}
bool operator ==(const PIDate & t0, const PIDate & t1) {
return (t0.year == t1.year && t0.month == t1.month && t0.day == t1.day);
}
bool operator <(const PIDate & t0, const PIDate & t1) {
if (t0.year == t1.year) {
if (t0.month == t1.month) {
return t0.day < t1.day;
} else return t0.month < t1.month;
} else return t0.year < t1.year;
}
bool operator >(const PIDate & t0, const PIDate & t1) {
if (t0.year == t1.year) {
if (t0.month == t1.month) {
return t0.day > t1.day;
} else return t0.month > t1.month;
} else return t0.year > t1.year;
}
bool operator ==(const PIDateTime & t0, const PIDateTime & t1) {
return (t0.year == t1.year && t0.month == t1.month && t0.day == t1.day &&
t0.hours == t1.hours && t0.minutes == t1.minutes && t0.seconds == t1.seconds);
}
bool operator <(const PIDateTime & t0, const PIDateTime & t1) {
if (t0.year == t1.year) {
if (t0.month == t1.month) {
if (t0.day == t1.day) {
if (t0.hours == t1.hours) {
if (t0.minutes == t1.minutes) {
return t0.seconds < t1.seconds;
} else return t0.minutes < t1.minutes;
} else return t0.hours < t1.hours;
} else return t0.day < t1.day;
} else return t0.month < t1.month;
} else return t0.year < t1.year;
}
bool operator >(const PIDateTime & t0, const PIDateTime & t1) {
if (t0.year == t1.year) {
if (t0.month == t1.month) {
if (t0.day == t1.day) {
if (t0.hours == t1.hours) {
if (t0.minutes == t1.minutes) {
return t0.seconds > t1.seconds;
} else return t0.minutes > t1.minutes;
} else return t0.hours > t1.hours;
} else return t0.day > t1.day;
} else return t0.month > t1.month;
} else return t0.year > t1.year;
}
PISystemTime PITime::toSystemTime() const {
return PISystemTime((hours * 60. + minutes) * 60. + seconds, milliseconds * 1000.);
}
PITime PITime::current() {
time_t rt = ::time(0);
tm * pt = localtime(&rt);
PITime t;
t.seconds = pt->tm_sec;
t.minutes = pt->tm_min;
t.hours = pt->tm_hour;
return t;
}
PITime PITime::fromSystemTime(const PISystemTime & st) {
double s = st.toSeconds();
int v = s;
PITime ret;
ret.milliseconds = (s - v) * 1000;
ret.seconds = v % 60; v = (v - ret.seconds) / 60;
ret.minutes = v % 60; v = (v - ret.minutes) / 60;
ret.hours = v;
return ret;
}
PIDate PIDate::current() {
time_t rt = ::time(0);
tm * pt = localtime(&rt);
PIDate d;
d.day = pt->tm_mday;
d.month = pt->tm_mon + 1;
d.year = pt->tm_year + 1900;
return d;
}
PIDateTime PIDateTime::current() {
time_t rt = ::time(0);
tm * pt = localtime(&rt);
PIDateTime dt;
dt.milliseconds = 0;
dt.seconds = pt->tm_sec;
dt.minutes = pt->tm_min;
dt.hours = pt->tm_hour;
dt.day = pt->tm_mday;
dt.month = pt->tm_mon + 1;
dt.year = pt->tm_year + 1900;
return dt;
}
PISystemTime PISystemTime::abs() const {
if (seconds < 0)
return PISystemTime(piAbsl(seconds) - 1, 1000000000l - piAbsl(nanoseconds));
else
return PISystemTime(piAbsl(seconds), piAbsl(nanoseconds));
}
PISystemTime PISystemTime::current(bool precise_but_not_system) {
#ifdef WINDOWS
if (precise_but_not_system) {
llong qpc(0);
if (__pi_perf_freq > 0) {
qpc = __PIQueryPerformanceCounter();
return PISystemTime::fromSeconds(qpc / double(__pi_perf_freq));
}
return PISystemTime();
} else {
FILETIME ft, sft;
# if (_WIN32_WINNT >= 0x0602)
GetSystemTimePreciseAsFileTime(&ft);
# else
GetSystemTimeAsFileTime(&ft);
# endif
sft.dwHighDateTime = ft.dwHighDateTime - __pi_ftjan1970.dwHighDateTime;
if (ft.dwLowDateTime < __pi_ftjan1970.dwLowDateTime) {
sft.dwLowDateTime = ft.dwLowDateTime + (0xFFFFFFFF - __pi_ftjan1970.dwLowDateTime);
sft.dwHighDateTime--;
} else
sft.dwLowDateTime = ft.dwLowDateTime - __pi_ftjan1970.dwLowDateTime;
ullong lt = ullong(sft.dwHighDateTime) * 0x100000000U + ullong(sft.dwLowDateTime);
return PISystemTime(lt / 10000000U, (lt % 10000000U) * 100U);
}
#else
# ifdef MAC_OS
mach_timespec_t t_cur;
clock_get_time(__pi_mac_clock, &t_cur);
# else
# ifdef FREERTOS
timespec t_cur;
timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 0;
gettimeofday(&tv, NULL);
t_cur.tv_sec = tv.tv_sec;
t_cur.tv_nsec = tv.tv_usec * 1000;
# else
timespec t_cur;
clock_gettime(0, &t_cur);
# endif
# endif
return PISystemTime(t_cur.tv_sec, t_cur.tv_nsec);
#endif
}
PIString PITime::toString(const PIString & format) const {
PIString ts = format;
ts.replace("hh", PIString::fromNumber(hours).expandLeftTo(2, '0'));
ts.replace("h", PIString::fromNumber(hours));
ts.replace("mm", PIString::fromNumber(minutes).expandLeftTo(2, '0'));
ts.replace("m", PIString::fromNumber(minutes));
ts.replace("ss", PIString::fromNumber(seconds).expandLeftTo(2, '0'));
ts.replace("s", PIString::fromNumber(seconds));
ts.replace("zzz", PIString::fromNumber(milliseconds).expandLeftTo(3, '0'));
ts.replace("zz", PIString::fromNumber(milliseconds).expandLeftTo(2, '0'));
ts.replace("z", PIString::fromNumber(milliseconds));
return ts;
}
PIString PIDate::toString(const PIString & format) const {
PIString ts = format;
ts.replace("yyyy", PIString::fromNumber(year).expandLeftTo(4, '0'));
ts.replace("yy", PIString::fromNumber(year).right(2));
ts.replace("y", PIString::fromNumber(year).right(1));
ts.replace("MM", PIString::fromNumber(month).expandLeftTo(2, '0'));
ts.replace("M", PIString::fromNumber(month));
ts.replace("dd", PIString::fromNumber(day).expandLeftTo(2, '0'));
ts.replace("d", PIString::fromNumber(day));
return ts;
}
PIString PIDateTime::toString(const PIString & format) const {
PIString ts = format;
ts.replace("yyyy", PIString::fromNumber(year).expandLeftTo(4, '0'));
ts.replace("yy", PIString::fromNumber(year).right(2));
ts.replace("y", PIString::fromNumber(year).right(1));
ts.replace("MM", PIString::fromNumber(month).expandLeftTo(2, '0'));
ts.replace("M", PIString::fromNumber(month));
ts.replace("dd", PIString::fromNumber(day).expandLeftTo(2, '0'));
ts.replace("d", PIString::fromNumber(day));
ts.replace("hh", PIString::fromNumber(hours).expandLeftTo(2, '0'));
ts.replace("h", PIString::fromNumber(hours));
ts.replace("mm", PIString::fromNumber(minutes).expandLeftTo(2, '0'));
ts.replace("m", PIString::fromNumber(minutes));
ts.replace("ss", PIString::fromNumber(seconds).expandLeftTo(2, '0'));
ts.replace("s", PIString::fromNumber(seconds));
ts.replace("zzz", PIString::fromNumber(milliseconds).expandLeftTo(3, '0'));
ts.replace("zz", PIString::fromNumber(milliseconds).expandLeftTo(2, '0'));
ts.replace("z", PIString::fromNumber(milliseconds));
return ts;
}
time_t PIDateTime::toSecondSinceEpoch() const {
tm pt;
memset(&pt, 0, sizeof(pt));
pt.tm_sec = seconds;
pt.tm_min = minutes;
pt.tm_hour = hours;
pt.tm_mday = day;
pt.tm_mon = month - 1;
#ifdef WINDOWS
pt.tm_year = piMaxi(year - 1900, 70);
#else
pt.tm_year = piMaxi(year - 1900, 0);
#endif
return mktime(&pt);
}
PIDateTime PIDateTime::fromSecondSinceEpoch(const time_t sec) {
tm * pt = localtime(&sec);
PIDateTime dt;
dt.seconds = pt->tm_sec;
dt.minutes = pt->tm_min;
dt.hours = pt->tm_hour;
dt.day = pt->tm_mday;
dt.month = pt->tm_mon + 1;
dt.year = pt->tm_year + 1900;
return dt;
}
PIString time2string(const PITime & time, const PIString & format) {
PIString ts = format;
ts.replace("hh", PIString::fromNumber(time.hours).expandLeftTo(2, '0'));
ts.replace("h", PIString::fromNumber(time.hours));
ts.replace("mm", PIString::fromNumber(time.minutes).expandLeftTo(2, '0'));
ts.replace("m", PIString::fromNumber(time.minutes));
ts.replace("ss", PIString::fromNumber(time.seconds).expandLeftTo(2, '0'));
ts.replace("s", PIString::fromNumber(time.seconds));
return ts;
}
PIString date2string(const PIDate & date, const PIString & format) {
PIString ts = format;
ts.replace("yyyy", PIString::fromNumber(date.year).expandLeftTo(4, '0'));
ts.replace("yy", PIString::fromNumber(date.year).right(2));
ts.replace("y", PIString::fromNumber(date.year).right(1));
ts.replace("MM", PIString::fromNumber(date.month).expandLeftTo(2, '0'));
ts.replace("M", PIString::fromNumber(date.month));
ts.replace("dd", PIString::fromNumber(date.day).expandLeftTo(2, '0'));
ts.replace("d", PIString::fromNumber(date.day));
return ts;
}
PIString datetime2string(const PIDateTime & date, const PIString & format) {
PIString ts = format;
ts.replace("hh", PIString::fromNumber(date.hours).expandLeftTo(2, '0'));
ts.replace("h", PIString::fromNumber(date.hours));
ts.replace("mm", PIString::fromNumber(date.minutes).expandLeftTo(2, '0'));
ts.replace("m", PIString::fromNumber(date.minutes));
ts.replace("ss", PIString::fromNumber(date.seconds).expandLeftTo(2, '0'));
ts.replace("s", PIString::fromNumber(date.seconds));
ts.replace("yyyy", PIString::fromNumber(date.year).expandLeftTo(4, '0'));
ts.replace("yy", PIString::fromNumber(date.year).right(2));
ts.replace("y", PIString::fromNumber(date.year).right(1));
ts.replace("MM", PIString::fromNumber(date.month).expandLeftTo(2, '0'));
ts.replace("M", PIString::fromNumber(date.month));
ts.replace("dd", PIString::fromNumber(date.day).expandLeftTo(2, '0'));
ts.replace("d", PIString::fromNumber(date.day));
return ts;
}
PITimeMeasurer::PITimeMeasurer() {
reset();
}
double PITimeMeasurer::elapsed_n() const {
return (PISystemTime::current(true) - t_st).toNanoseconds() - PISystemTests::time_elapsed_ns;
}
double PITimeMeasurer::elapsed_u() const {
return (PISystemTime::current(true) - t_st).toMicroseconds() - PISystemTests::time_elapsed_ns / 1.E+3;
}
double PITimeMeasurer::elapsed_m() const {
return (PISystemTime::current(true) - t_st).toMilliseconds() - PISystemTests::time_elapsed_ns / 1.E+6;
}
double PITimeMeasurer::elapsed_s() const {
return (PISystemTime::current(true) - t_st).toSeconds() - PISystemTests::time_elapsed_ns / 1.E+9;
}
PISystemTime PITimeMeasurer::elapsed() const {
return (PISystemTime::current(true) - t_st);
}
PICout operator <<(PICout s, const PITime & v) {
s.space();
s.setControl(0, true);
s << "PITime(" << v.hours << ":";
s << PIString::fromNumber(v.minutes).expandLeftTo(2, '0') << ":";
s << PIString::fromNumber(v.seconds).expandLeftTo(2, '0') << ":";
s << PIString::fromNumber(v.milliseconds).expandLeftTo(3, '0') << ")";
s.restoreControl();
return s;
}
PICout operator <<(PICout s, const PIDate & v) {
s.space();
s.setControl(0, true);
s << "PIDate(" << v.day << "-";
s << PIString::fromNumber(v.month).expandLeftTo(2, '0') << "-";
s << v.year << ")";
s.restoreControl();
return s;
}
PICout operator <<(PICout s, const PIDateTime & v) {
s.space();
s.setControl(0, true);
s << "PIDateTime(";
s << v.day << "-";
s << PIString::fromNumber(v.month).expandLeftTo(2, '0') << "-";
s << v.year << " ";
s << v.hours << ":";
s << PIString::fromNumber(v.minutes).expandLeftTo(2, '0') << ":";
s << PIString::fromNumber(v.seconds).expandLeftTo(2, '0') << ":";
s << PIString::fromNumber(v.milliseconds).expandLeftTo(3, '0') << ")";
s.restoreControl();
return s;
}
#ifdef WINDOWS
void msleep(int msecs) {Sleep(msecs);}
#else
# ifdef FREERTOS
void msleep(int msecs) {vTaskDelay(msecs / portTICK_PERIOD_MS);}
# else
void msleep(int msecs) {usleep(msecs * 1000);}
# endif
#endif

333
lib/main/core/pitime.h Normal file
View File

@@ -0,0 +1,333 @@
/*! \file pitime.h
* \brief Time structs
*/
/*
PIP - Platform Independent Primitives
Time structs
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PITIME_H
#define PITIME_H
#include "pistring.h"
#include <ctime>
#ifdef QNX
# include <time.h>
#endif
//! \brief Sleep for "msecs" milliseconds
PIP_EXPORT void msleep(int msecs);
/*! \brief Precise sleep for "usecs" microseconds
* \details This function consider \c "usleep" offset
* on QNX/Linux/Mac, which is calculated with
* \a pip_sys_test program. If there is correct
* offset value in system config, this function
* wait \b exactly "usecs" microseconds. */
PIP_EXPORT void piUSleep(int usecs); // on !Windows consider constant "usleep" offset
/*! \brief Precise sleep for "msecs" milliseconds
* \details This function exec \a piUSleep (msecs * 1000). */
inline void piMSleep(double msecs) {piUSleep(int(msecs * 1000.));} // on !Windows consider constant "usleep" offset
/*! \brief Precise sleep for "secs" seconds
* \details This function exec \a piUSleep (msecs * 1000000). */
inline void piSleep(double secs) {piUSleep(int(secs * 1000000.));} // on !Windows consider constant "usleep" offset
class PIP_EXPORT PISystemTime {
public:
//! Contructs system time with s = ns = 0
PISystemTime() {seconds = nanoseconds = 0;}
//! Contructs system time with s = "s" and ns = "ns"
PISystemTime(int s, int ns) {seconds = s; nanoseconds = ns; checkOverflows();}
//! Contructs system time from another
PISystemTime(const PISystemTime & t) {seconds = t.seconds; nanoseconds = t.nanoseconds;}
//! Returns stored system time value in seconds
double toSeconds() const {return double(seconds) + nanoseconds / 1.e+9;}
//! Returns stored system time value in milliseconds
double toMilliseconds() const {return seconds * 1.e+3 + nanoseconds / 1.e+6;}
//! Returns stored system time value in microseconds
double toMicroseconds() const {return seconds * 1.e+6 + nanoseconds / 1.e+3;}
//! Returns stored system time value in nanoseconds
double toNanoseconds() const {return seconds * 1.e+9 + double(nanoseconds);}
//! Add to stored system time "v" seconds
PISystemTime & addSeconds(double v) {*this += fromSeconds(v); return *this;}
//! Add to stored system time "v" milliseconds
PISystemTime & addMilliseconds(double v) {*this += fromMilliseconds(v); return *this;}
//! Add to stored system time "v" microseconds
PISystemTime & addMicroseconds(double v) {*this += fromMicroseconds(v); return *this;}
//! Add to stored system time "v" nanoseconds
PISystemTime & addNanoseconds(double v) {*this += fromNanoseconds(v); return *this;}
//! Sleep for stored value. \warning Use this function to sleep for difference of system times or constructs system time.
//! If you call this function on system time returned with \a PISystemTime::current() thread will be sleep almost forever.
void sleep() {piUSleep(piFloord(toMicroseconds()));} // wait self value, useful to wait some dT = (t1 - t0)
//! Returns copy of this system time with absolutely values of s and ns
PISystemTime abs() const;
//! Returns sum of this system time with "t"
PISystemTime operator +(const PISystemTime & t) const {PISystemTime tt(*this); tt.seconds += t.seconds; tt.nanoseconds += t.nanoseconds; tt.checkOverflows(); return tt;}
//! Returns difference between this system time and "t"
PISystemTime operator -(const PISystemTime & t) const {PISystemTime tt(*this); tt.seconds -= t.seconds; tt.nanoseconds -= t.nanoseconds; tt.checkOverflows(); return tt;}
//! Returns multiplication between this system time and "t"
PISystemTime operator *(const double & v) const {return fromMilliseconds(toMilliseconds() * v);}
//! Returns division between this system time and "t"
PISystemTime operator /(const double & v) const {return fromMilliseconds(toMilliseconds() / v);}
//! Add to stored value system time "t"
PISystemTime & operator +=(const PISystemTime & t) {seconds += t.seconds; nanoseconds += t.nanoseconds; checkOverflows(); return *this;}
//! Subtract from stored value system time "t"
PISystemTime & operator -=(const PISystemTime & t) {seconds -= t.seconds; nanoseconds -= t.nanoseconds; checkOverflows(); return *this;}
//! Multiply stored value system time by "v"
PISystemTime & operator *=(const double & v) {*this = fromMilliseconds(toMilliseconds() * v); return *this;}
//! Divide stored value system time by "v"
PISystemTime & operator /=(const double & v) {*this = fromMilliseconds(toMilliseconds() / v); return *this;}
//! Compare system times
bool operator ==(const PISystemTime & t) const {return ((seconds == t.seconds) && (nanoseconds == t.nanoseconds));}
//! Compare system times
bool operator !=(const PISystemTime & t) const {return ((seconds != t.seconds) || (nanoseconds != t.nanoseconds));}
//! Compare system times
bool operator >(const PISystemTime & t) const {if (seconds == t.seconds) return nanoseconds > t.nanoseconds; return seconds > t.seconds;}
//! Compare system times
bool operator <(const PISystemTime & t) const {if (seconds == t.seconds) return nanoseconds < t.nanoseconds; return seconds < t.seconds;}
//! Compare system times
bool operator >=(const PISystemTime & t) const {if (seconds == t.seconds) return nanoseconds >= t.nanoseconds; return seconds >= t.seconds;}
//! Compare system times
bool operator <=(const PISystemTime & t) const {if (seconds == t.seconds) return nanoseconds <= t.nanoseconds; return seconds <= t.seconds;}
//! Contructs system time from seconds "v"
static PISystemTime fromSeconds(double v) {int s = piFloord(v); return PISystemTime(s, int((v - s) * 1000000000.));}
//! Contructs system time from milliseconds "v"
static PISystemTime fromMilliseconds(double v) {int s = piFloord(v / 1000.); return PISystemTime(s, int((v / 1000. - s) * 1000000000.));}
//! Contructs system time from microseconds "v"
static PISystemTime fromMicroseconds(double v) {int s = piFloord(v / 1000000.); return PISystemTime(s, int((v / 1000000. - s) * 1000000000.));}
//! Contructs system time from nanoseconds "v"
static PISystemTime fromNanoseconds(double v) {int s = piFloord(v / 1000000000.); return PISystemTime(s, int((v / 1000000000. - s) * 1000000000.));}
//! Returns current system time
static PISystemTime current(bool precise_but_not_system = false);
//! Seconds of stored system time
int seconds;
//! Nanoseconds of stored system time
int nanoseconds;
private:
void checkOverflows() {while (nanoseconds >= 1000000000) {nanoseconds -= 1000000000; seconds++;} while (nanoseconds < 0) {nanoseconds += 1000000000; seconds--;}}
};
//! \relatesalso PICout \relatesalso PICout \brief Output operator to PICout
inline PICout operator <<(PICout s, const PISystemTime & v) {s.space(); s.setControl(0, true); s << "(" << v.seconds << " s, " << v.nanoseconds << " ns)"; s.restoreControl(); return s;}
//! \relatesalso PISystemTime \relatesalso PIByteArray \brief Output operator to PIByteArray
inline PIByteArray & operator <<(PIByteArray & s, const PISystemTime & v) {s << v.seconds << v.nanoseconds; return s;}
//! \relatesalso PISystemTime \relatesalso PIByteArray \brief Input operator from PIByteArray
inline PIByteArray & operator >>(PIByteArray & s, PISystemTime & v) {s >> v.seconds >> v.nanoseconds; return s;}
struct PIP_EXPORT PITime {
PITime(int hours_ = 0, int minutes_ = 0, int seconds_ = 0, int milliseconds_ = 0): hours(hours_), minutes(minutes_), seconds(seconds_), milliseconds(milliseconds_) {;}
int hours;
int minutes;
int seconds;
int milliseconds;
PIString toString(const PIString & format = "h:mm:ss") const;
PISystemTime toSystemTime() const;
static PITime current();
static PITime fromSystemTime(const PISystemTime & st);
};
PIP_EXPORT bool operator ==(const PITime & t0, const PITime & t1);
PIP_EXPORT bool operator <(const PITime & t0, const PITime & t1);
PIP_EXPORT bool operator >(const PITime & t0, const PITime & t1);
inline bool operator !=(const PITime & t0, const PITime & t1) {return !(t0 == t1);}
inline bool operator <=(const PITime & t0, const PITime & t1) {return !(t0 > t1);}
inline bool operator >=(const PITime & t0, const PITime & t1) {return !(t0 < t1);}
inline PIByteArray & operator <<(PIByteArray & s, const PITime & v) {s << v.hours << v.minutes << v.seconds << v.milliseconds; return s;}
inline PIByteArray & operator >>(PIByteArray & s, PITime & v) {s >> v.hours >> v.minutes >> v.seconds >> v.milliseconds; return s;}
//! \relatesalso PICout \relatesalso PICout \brief Output operator to PICout
PIP_EXPORT PICout operator <<(PICout s, const PITime & v);
struct PIP_EXPORT PIDate {
PIDate(int year_ = 0, int month_ = 0, int day_ = 0): year(year_), month(month_), day(day_) {;}
int year;
int month;
int day;
PIString toString(const PIString & format = "d.MM.yyyy") const;
static PIDate current();
};
PIP_EXPORT bool operator ==(const PIDate & t0, const PIDate & t1);
PIP_EXPORT bool operator <(const PIDate & t0, const PIDate & t1);
PIP_EXPORT bool operator >(const PIDate & t0, const PIDate & t1);
inline bool operator !=(const PIDate & t0, const PIDate & t1) {return !(t0 == t1);}
inline bool operator <=(const PIDate & t0, const PIDate & t1) {return !(t0 > t1);}
inline bool operator >=(const PIDate & t0, const PIDate & t1) {return !(t0 < t1);}
inline PIByteArray & operator <<(PIByteArray & s, const PIDate & v) {s << v.year << v.month << v.day; return s;}
inline PIByteArray & operator >>(PIByteArray & s, PIDate & v) {s >> v.year >> v.month >> v.day; return s;}
//! \relatesalso PICout \relatesalso PICout \brief Output operator to PICout
PIP_EXPORT PICout operator <<(PICout s, const PIDate & v);
struct PIP_EXPORT PIDateTime {
PIDateTime() {year = month = day = hours = minutes = seconds = milliseconds = 0;}
PIDateTime(const PITime & time) {year = month = day = 0; hours = time.hours; minutes = time.minutes; seconds = time.seconds; milliseconds = time.milliseconds;}
PIDateTime(const PIDate & date) {year = date.year; month = date.month; day = date.day; hours = minutes = seconds = milliseconds = 0;}
PIDateTime(const PIDate & date, const PITime & time) {year = date.year; month = date.month; day = date.day; hours = time.hours; minutes = time.minutes; seconds = time.seconds; milliseconds = time.milliseconds;}
int year;
int month;
int day;
int hours;
int minutes;
int seconds;
int milliseconds;
PIDateTime normalized() const {return PIDateTime::fromSecondSinceEpoch(toSecondSinceEpoch());}
void normalize() {*this = normalized();}
PIString toString(const PIString & format = "h:mm:ss d.MM.yyyy") const;
time_t toSecondSinceEpoch() const;
PISystemTime toSystemTime() const {return PISystemTime(int(toSecondSinceEpoch()), milliseconds * 1000000);}
PIDate date() const {return PIDate(year, month, day);}
PITime time() const {return PITime(hours, minutes, seconds, milliseconds);}
void setDate(const PIDate & d) {year = d.year; month = d.month; day = d.day;}
void setTime(const PITime & t) {hours = t.hours; minutes = t.minutes; seconds = t.seconds; milliseconds = t.milliseconds;}
void operator +=(const PIDateTime & d1) {year += d1.year; month += d1.month; day += d1.day; hours += d1.hours; minutes += d1.minutes; seconds += d1.seconds; normalize();}
void operator -=(const PIDateTime & d1) {year -= d1.year; month -= d1.month; day -= d1.day; hours -= d1.hours; minutes -= d1.minutes; seconds -= d1.seconds; normalize();}
static PIDateTime fromSecondSinceEpoch(const time_t sec);
static PIDateTime fromSystemTime(const PISystemTime & st) {PIDateTime dt = fromSecondSinceEpoch(st.seconds); dt.milliseconds = piClampi(st.nanoseconds / 1000000, 0, 999); return dt;}
static PIDateTime current();
};
inline PIDateTime operator +(const PIDateTime & d0, const PIDateTime & d1) {PIDateTime td = d0; td += d1; return td.normalized();}
inline PIDateTime operator -(const PIDateTime & d0, const PIDateTime & d1) {PIDateTime td = d0; td -= d1; return td.normalized();}
PIP_EXPORT bool operator ==(const PIDateTime & t0, const PIDateTime & t1);
PIP_EXPORT bool operator <(const PIDateTime & t0, const PIDateTime & t1);
PIP_EXPORT bool operator >(const PIDateTime & t0, const PIDateTime & t1);
inline bool operator !=(const PIDateTime & t0, const PIDateTime & t1) {return !(t0 == t1);}
inline bool operator <=(const PIDateTime & t0, const PIDateTime & t1) {return !(t0 > t1);}
inline bool operator >=(const PIDateTime & t0, const PIDateTime & t1) {return !(t0 < t1);}
inline PIByteArray & operator <<(PIByteArray & s, const PIDateTime & v) {s << v.year << v.month << v.day << v.hours << v.minutes << v.seconds << v.milliseconds; return s;}
inline PIByteArray & operator >>(PIByteArray & s, PIDateTime & v) {s >> v.year >> v.month >> v.day >> v.hours >> v.minutes >> v.seconds >> v.milliseconds; return s;}
//! \relatesalso PICout \relatesalso PICout \brief Output operator to PICout
PIP_EXPORT PICout operator <<(PICout s, const PIDateTime & v);
class PIP_EXPORT PITimeMeasurer {
public:
PITimeMeasurer();
/** \brief Set internal time mark to current system time
* \details This function used for set start time mark. Later
* you can find out elapsed time from this time mark to any
* moment of time with \a elapsed_s(), \a elapsed_m(),
* \a elapsed_u() or \a elapsed_n() functions.
* \sa \a elapsed_s(), \a elapsed_m(), \a elapsed_u(), \a elapsed_n() */
void reset() {t_st = PISystemTime::current(true);}
//! \brief Returns nanoseconds elapsed from last \a reset() execution or from timer measurer creation.
double elapsed_n() const;
//! \brief Returns microseconds elapsed from last \a reset() execution or from timer measurer creation.
double elapsed_u() const;
//! \brief Returns milliseconds elapsed from last \a reset() execution or from timer measurer creation.
double elapsed_m() const;
//! \brief Returns seconds elapsed from last \a reset() execution or from timer measurer creation.
double elapsed_s() const;
//! \brief Returns PISystemTime elapsed from last \a reset() execution or from timer measurer creation.
PISystemTime elapsed() const;
double reset_time_n() const {return t_st.toNanoseconds();}
double reset_time_u() const {return t_st.toMicroseconds();}
double reset_time_m() const {return t_st.toMilliseconds();}
double reset_time_s() const {return t_st.toSeconds();}
//! \brief Returns time mark of last \a reset() execution or timer measurer creation.
PISystemTime reset_time() {return t_st;}
//! \brief Returns nanoseconds representation of current system time.
static double elapsed_system_n() {return PISystemTime::current(true).toNanoseconds();}
//! \brief Returns microseconds representation of current system time.
static double elapsed_system_u() {return PISystemTime::current(true).toMicroseconds();}
//! \brief Returns milliseconds representation of current system time.
static double elapsed_system_m() {return PISystemTime::current(true).toMilliseconds();}
//! \brief Returns seconds representation of current system time.
static double elapsed_system_s() {return PISystemTime::current(true).toSeconds();}
//! \brief Returns time mark of current system time.
static PISystemTime elapsed_system() {return PISystemTime::current(true);}
private:
PISystemTime t_st, t_cur;
};
#endif // PITIME_H

View File

@@ -0,0 +1,87 @@
/*! \file pitime_win.h
* \brief PITime conversions for Windows
*
* This file declare time conversions for Windows
*/
/*
PIP - Platform Independent Primitives
PITime conversions for Windows
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PITIME_WIN_H
#define PITIME_WIN_H
#include "pibase.h"
#ifdef WINDOWS
#include "pitime.h"
#include <windows.h>
inline PISystemTime FILETIME2PISystemTime(const FILETIME &t) {
PISystemTime st;
ullong lt = ullong(t.dwHighDateTime) * 0x100000000U + ullong(t.dwLowDateTime);
st.seconds = lt / 10000000U;
st.nanoseconds = (lt % 10000000U) * 100U;
return st;
}
inline PIDateTime SYSTEMTIME2PIDateTime(const SYSTEMTIME &t) {
PIDateTime dt;
dt.year = t.wYear;
dt.month = t.wMonth;
dt.day = t.wDay;
dt.hours = t.wHour;
dt.minutes = t.wMinute;
dt.seconds = t.wSecond;
dt.milliseconds = t.wMilliseconds;
return dt;
}
inline PIDateTime FILETIME2PIDateTime(const FILETIME &t) {
FILETIME lt;
SYSTEMTIME st;
FileTimeToLocalFileTime(&t, &lt);
FileTimeToSystemTime(&lt, &st);
return SYSTEMTIME2PIDateTime(st);
}
inline SYSTEMTIME PIDateTime2SYSTEMTIME(const PIDateTime &dt) {
SYSTEMTIME st;
st.wYear = dt.year;
st.wMonth = dt.month;
st.wDay = dt.day;
st.wHour = dt.hours;
st.wMinute = dt.minutes;
st.wSecond = dt.seconds;
st.wMilliseconds = dt.milliseconds;
return st;
}
inline FILETIME PIDateTime2FILETIME(const PIDateTime &dt) {
FILETIME lt, ret;
SYSTEMTIME st = PIDateTime2SYSTEMTIME(dt);
SystemTimeToFileTime(&st, &lt);
LocalFileTimeToFileTime(&lt, &ret);
return ret;
}
#endif // WINDOWS
#endif // PITIME_WIN_H

620
lib/main/core/pivariant.cpp Normal file
View File

@@ -0,0 +1,620 @@
/*
PIP - Platform Independent Primitives
Variant type
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#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<PIVariant> 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
* */
#ifdef CUSTOM_PIVARIANT
PIMap<PIString, __PIVariantInfo__ * > * __PIVariantInfoStorage__::map = 0;
#endif
PIVariant::PIVariant() {
_type = PIVariant::pivInvalid;
_info = 0;
}
PIVariant::PIVariant(const PIVariant &v) {
_type = v._type;
_content = v._content;
#ifdef CUSTOM_PIVARIANT
_info = v._info;
#endif
}
void PIVariant::setValueFromString(const PIString & v) {
switch (_type) {
case PIVariant::pivBool: {setValue(v.toBool());} break;
case PIVariant::pivChar: {setValue(v.toChar());} break;
case PIVariant::pivUChar: {setValue((uchar)v.toChar());} break;
case PIVariant::pivShort: {setValue(v.toShort());} break;
case PIVariant::pivUShort: {setValue(v.toUShort());} break;
case PIVariant::pivInt: {setValue(v.toInt());} break;
case PIVariant::pivUInt: {setValue(v.toUInt());} break;
case PIVariant::pivLLong: {setValue(v.toLLong());} break;
case PIVariant::pivULLong: {setValue(v.toULLong());} break;
case PIVariant::pivFloat: {setValue(v.toFloat());} break;
case PIVariant::pivDouble: {setValue(v.toDouble());} break;
case PIVariant::pivLDouble: {setValue(v.toLDouble());} break;
case PIVariant::pivTime: {} break; // TODO
case PIVariant::pivDate: {} break; // TODO
case PIVariant::pivDateTime: {} break; // TODO
case PIVariant::pivString: {setValue(v);} break;
case PIVariant::pivStringList: {setValue(v.split("%|%"));} break;
case PIVariant::pivEnum: {PIVariantTypes::Enum r = toEnum(); r.selectName(v); setValue(r);} break;
case PIVariant::pivFile: {PIVariantTypes::File r = toFile(); r.file = v; setValue(r);} break;
case PIVariant::pivDir: {PIVariantTypes::Dir r = toDir(); r.dir = v; setValue(r);} break;
case PIVariant::pivColor: {setValue(PIVariantTypes::Color(v.mid(1).toUInt(16)));} break;
case PIVariant::pivIODevice: {setValue(PIVariantTypes::IODevice());} break; // TODO
case PIVariant::pivCustom: {} break; // TODO;
default: break;
}
}
PIVariant & PIVariant::operator =(const PIVariant & v) {
_type = v._type;
_content = v._content;
#ifdef CUSTOM_PIVARIANT
_info = v._info;
#endif
return *this;
}
bool PIVariant::operator ==(const PIVariant & v) const {
return (_type == v._type) && (_content == v._content);
}
PIVariant::Type PIVariant::typeFromName(const PIString & tname) {
PIString s = tname.trimmed().toLowerCase().replaceAll(" ", "");
if (s == "bool" || s == "boolean") return PIVariant::pivBool;
if (s == "char" || s == "sbyte") return PIVariant::pivChar;
if (s == "short" || s == "shortint" || s == "signedshort" || s == "signedshortint" || s == "sword") return PIVariant::pivShort;
if (s == "int" || s == "signed" || s == "signedint") return PIVariant::pivInt;
if (s == "long" || s == "longint" || s == "signedlong" || s == "signedlongint" || s == "sdword") return PIVariant::pivInt;
if (s == "llong" || s == "longlong" || s == "longlongint" || s == "signedlonglong" || s == "signedlonglongint" || s == "sqword") return PIVariant::pivLLong;
if (s == "uchar" || s == "byte") return PIVariant::pivUChar;
if (s == "ushort" || s == "unsignedshort" || s == "unsignedshortint" || s == "word") return PIVariant::pivUShort;
if (s == "uint" || s == "unsigned" || s == "unsignedint") return PIVariant::pivUInt;
if (s == "ulong" || s == "unsignedlong" || s == "unsignedlongint" || s == "dword") return PIVariant::pivUInt;
if (s == "ullong" || s == "unsignedlonglong" || s == "unsignedlonglongint" || s == "qword") return PIVariant::pivULLong;
if (s == "float") return PIVariant::pivFloat;
if (s == "double" || s == "real") return PIVariant::pivDouble;
if (s == "ldouble" || s == "longdouble") return PIVariant::pivLDouble;
if (s == "complexd" || s == "complex<double>") return PIVariant::pivComplexd;
if (s == "complexld" || s == "complex<ldouble>" || s == "complex<longdouble>") return PIVariant::pivComplexld;
if (s == "pibitarray" || s == "bitarray") return PIVariant::pivBitArray;
if (s == "pibytearray" || s == "bytearray" || s == "vector<uchar>" || s == "pivector<uchar>" || s == "vector<unsignedchar>" || s == "pivector<unsignedchar>" ||
s == "vector<char>" || s == "pivector<char>") return PIVariant::pivByteArray;
if (s == "pistring" || s == "string") return PIVariant::pivString;
if (s == "pistringlist" || s == "stringlist" || s == "vector<string>" || s == "vector<pistring>" || s == "pivector<string>" || s == "pivector<pistring>") return PIVariant::pivStringList;
if (s == "pitime" || s == "time") return PIVariant::pivTime;
if (s == "pidate" || s == "date") return PIVariant::pivDate;
if (s == "pidatetime" || s == "datetime") return PIVariant::pivDateTime;
if (s == "pisystemtime" || s == "systemtime") return PIVariant::pivSystemTime;
if (s == "enum") return PIVariant::pivEnum;
if (s == "file" || s == "path") return PIVariant::pivFile;
if (s == "dir" || s == "directory") return PIVariant::pivDir;
if (s == "color") return PIVariant::pivColor;
if (s == "point") return PIVariant::pivPoint;
if (s == "rect") return PIVariant::pivRect;
if (s == "vector") return PIVariant::pivMathVector;
if (s == "matrix") return PIVariant::pivMathMatrix;
return PIVariant::pivInvalid;
}
PIString PIVariant::typeName() const {
#ifdef CUSTOM_PIVARIANT
if ((_type == pivCustom) && _info)
return _info->typeName;
#endif
return typeName(_type);
}
PIString PIVariant::typeName(PIVariant::Type type) {
switch (type) {
case PIVariant::pivBool: return "Bool";
case PIVariant::pivChar: return "Char";
case PIVariant::pivUChar: return "UChar";
case PIVariant::pivShort: return "Short";
case PIVariant::pivUShort: return "UShort";
case PIVariant::pivInt: return "Int";
case PIVariant::pivUInt: return "UInt";
case PIVariant::pivLLong: return "LLong";
case PIVariant::pivULLong: return "ULLong";
case PIVariant::pivFloat: return "Float";
case PIVariant::pivDouble: return "Double";
case PIVariant::pivLDouble: return "LDouble";
case PIVariant::pivComplexd: return "Complexd";
case PIVariant::pivComplexld: return "Complexld";
case PIVariant::pivBitArray: return "BitArray";
case PIVariant::pivByteArray: return "ByteArray";
case PIVariant::pivString: return "String";
case PIVariant::pivStringList: return "StringList";
case PIVariant::pivTime: return "Time";
case PIVariant::pivDate: return "Date";
case PIVariant::pivDateTime: return "DateTime";
case PIVariant::pivSystemTime: return "SystemTime";
case PIVariant::pivEnum: return "Enum";
case PIVariant::pivFile: return "File";
case PIVariant::pivDir: return "Dir";
case PIVariant::pivColor: return "Color";
case PIVariant::pivPoint: return "Point";
case PIVariant::pivRect: return "Rect";
case PIVariant::pivMathVector: return "Vector";
case PIVariant::pivMathMatrix: return "Matrix";
case PIVariant::pivCustom: 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 {
PIByteArray ba(_content);
switch (_type) {
case PIVariant::pivBool: {bool r; ba >> r; return r;}
case PIVariant::pivChar: {char r; ba >> r; return r != 0;}
case PIVariant::pivUChar: {uchar r; ba >> r; return r != 0;}
case PIVariant::pivShort: {short r; ba >> r; return r != 0;}
case PIVariant::pivUShort: {ushort r; ba >> r; return r != 0;}
case PIVariant::pivInt: {int r; ba >> r; return r != 0;}
case PIVariant::pivUInt: {uint r; ba >> r; return r != 0;}
case PIVariant::pivLLong: {llong r; ba >> r; return r != 0;}
case PIVariant::pivULLong: {ullong r; ba >> r; return r != 0;}
case PIVariant::pivFloat: {float r; ba >> r; return r > 0.f;}
case PIVariant::pivDouble: {double r; ba >> r; return r > 0.;}
case PIVariant::pivLDouble: {ldouble r; ba >> r; return r > 0.;}
case PIVariant::pivString: {PIString r; ba >> r; return r.toBool();}
case PIVariant::pivStringList: {PIStringList r; ba >> r; if (r.isEmpty()) return false; return r.front().toBool();}
case PIVariant::pivCustom: return getAsValue<bool>(*this);
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 {
PIByteArray ba(_content);
switch (_type) {
case PIVariant::pivBool: {bool r; ba >> r; return r;}
case PIVariant::pivChar: {char r; ba >> r; return r;}
case PIVariant::pivUChar: {uchar r; ba >> r; return r;}
case PIVariant::pivShort: {short r; ba >> r; return r;}
case PIVariant::pivUShort: {ushort r; ba >> r; return r;}
case PIVariant::pivInt: {int r; ba >> r; return r;}
case PIVariant::pivUInt: {uint r; ba >> r; return r;}
case PIVariant::pivLLong: {llong r; ba >> r; return r;}
case PIVariant::pivULLong: {ullong r; ba >> r; return r;}
case PIVariant::pivFloat: {float r; ba >> r; return r;}
case PIVariant::pivDouble: {double r; ba >> r; return r;}
case PIVariant::pivLDouble: {ldouble r; ba >> r; return r;}
case PIVariant::pivString: {PIString r; ba >> r; return r.toInt();}
case PIVariant::pivStringList: {PIStringList r; ba >> r; if (r.isEmpty()) return 0; return r.front().toInt();}
case PIVariant::pivEnum: {PIVariantTypes::Enum r; ba >> r; return r.selectedValue();}
case PIVariant::pivColor: {PIVariantTypes::Color r; ba >> r; return (int)r.rgba;}
case PIVariant::pivCustom: return getAsValue<int>(*this);
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 {
PIByteArray ba(_content);
switch (_type) {
case PIVariant::pivBool: {bool r; ba >> r; return r;}
case PIVariant::pivChar: {char r; ba >> r; return r;}
case PIVariant::pivUChar: {uchar r; ba >> r; return r;}
case PIVariant::pivShort: {short r; ba >> r; return r;}
case PIVariant::pivUShort: {ushort r; ba >> r; return r;}
case PIVariant::pivInt: {int r; ba >> r; return r;}
case PIVariant::pivUInt: {uint r; ba >> r; return r;}
case PIVariant::pivLLong: {llong r; ba >> r; return r;}
case PIVariant::pivULLong: {ullong r; ba >> r; return r;}
case PIVariant::pivFloat: {float r; ba >> r; return r;}
case PIVariant::pivDouble: {double r; ba >> r; return r;}
case PIVariant::pivLDouble: {ldouble r; ba >> r; return r;}
case PIVariant::pivString: {PIString r; ba >> r; return r.toLLong();}
case PIVariant::pivStringList: {PIStringList r; ba >> r; if (r.isEmpty()) return 0L; return r.front().toLLong();}
case PIVariant::pivEnum: {PIVariantTypes::Enum r; ba >> r; return llong(r.selectedValue());}
case PIVariant::pivCustom: return getAsValue<llong>(*this);
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 {
PIByteArray ba(_content);
switch (_type) {
case PIVariant::pivBool: {bool r; ba >> r; return r;}
case PIVariant::pivChar: {char r; ba >> r; return r;}
case PIVariant::pivUChar: {uchar r; ba >> r; return r;}
case PIVariant::pivShort: {short r; ba >> r; return r;}
case PIVariant::pivUShort: {ushort r; ba >> r; return r;}
case PIVariant::pivInt: {int r; ba >> r; return r;}
case PIVariant::pivUInt: {uint r; ba >> r; return r;}
case PIVariant::pivLLong: {llong r; ba >> r; return r;}
case PIVariant::pivULLong: {ullong r; ba >> r; return r;}
case PIVariant::pivFloat: {float r; ba >> r; return r;}
case PIVariant::pivDouble: {double r; ba >> r; return r;}
case PIVariant::pivLDouble: {ldouble r; ba >> r; return r;}
case PIVariant::pivString: {PIString r; ba >> r; return r.toFloat();}
case PIVariant::pivStringList: {PIStringList r; ba >> r; if (r.isEmpty()) return 0.f; return r.front().toFloat();}
case PIVariant::pivEnum: {PIVariantTypes::Enum r; ba >> r; return float(r.selectedValue());}
case PIVariant::pivCustom: return getAsValue<float>(*this);
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 {
PIByteArray ba(_content);
switch (_type) {
case PIVariant::pivBool: {bool r; ba >> r; return r;}
case PIVariant::pivChar: {char r; ba >> r; return r;}
case PIVariant::pivUChar: {uchar r; ba >> r; return r;}
case PIVariant::pivShort: {short r; ba >> r; return r;}
case PIVariant::pivUShort: {ushort r; ba >> r; return r;}
case PIVariant::pivInt: {int r; ba >> r; return r;}
case PIVariant::pivUInt: {uint r; ba >> r; return r;}
case PIVariant::pivLLong: {llong r; ba >> r; return r;}
case PIVariant::pivULLong: {ullong r; ba >> r; return r;}
case PIVariant::pivFloat: {float r; ba >> r; return r;}
case PIVariant::pivDouble: {double r; ba >> r; return r;}
case PIVariant::pivLDouble: {ldouble r; ba >> r; return r;}
case PIVariant::pivString: {PIString r; ba >> r; return r.toDouble();}
case PIVariant::pivStringList: {PIStringList r; ba >> r; if (r.isEmpty()) return 0.; return r.front().toDouble();}
case PIVariant::pivEnum: {PIVariantTypes::Enum r; ba >> r; return double(r.selectedValue());}
case PIVariant::pivCustom: return getAsValue<double>(*this);
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 {
PIByteArray ba(_content);
switch (_type) {
case PIVariant::pivBool: {bool r; ba >> r; return r;}
case PIVariant::pivChar: {char r; ba >> r; return r;}
case PIVariant::pivUChar: {uchar r; ba >> r; return r;}
case PIVariant::pivShort: {short r; ba >> r; return r;}
case PIVariant::pivUShort: {ushort r; ba >> r; return r;}
case PIVariant::pivInt: {int r; ba >> r; return r;}
case PIVariant::pivUInt: {uint r; ba >> r; return r;}
case PIVariant::pivLLong: {llong r; ba >> r; return r;}
case PIVariant::pivULLong: {ullong r; ba >> r; return r;}
case PIVariant::pivFloat: {float r; ba >> r; return r;}
case PIVariant::pivDouble: {double r; ba >> r; return r;}
case PIVariant::pivLDouble: {ldouble r; ba >> r; return r;}
case PIVariant::pivString: {PIString r; ba >> r; return r.toLDouble();}
case PIVariant::pivStringList: {PIStringList r; ba >> r; if (r.isEmpty()) return 0.; return r.front().toLDouble();}
case PIVariant::pivEnum: {PIVariantTypes::Enum r; ba >> r; return ldouble(r.selectedValue());}
case PIVariant::pivCustom: return getAsValue<float>(*this);
default: break;
}
return 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 {
PIByteArray ba(_content);
if (_type == PIVariant::pivTime) {PITime r; ba >> r; return r;}
if (_type == PIVariant::pivDateTime) {PIDateTime r; ba >> r; return r.time();}
if (_type == PIVariant::pivCustom) {return getAsValue<PITime>(*this);}
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 {
PIByteArray ba(_content);
if (_type == PIVariant::pivDate) {PIDate r; ba >> r; return r;}
if (_type == PIVariant::pivDateTime) {PIDateTime r; ba >> r; return r.date();}
if (_type == PIVariant::pivCustom) {return getAsValue<PIDate>(*this);}
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 {
PIByteArray ba(_content);
if (_type == PIVariant::pivTime) {PITime r; ba >> r; return PIDateTime(r);}
if (_type == PIVariant::pivDate) {PIDate r; ba >> r; return PIDateTime(r);}
if (_type == PIVariant::pivDateTime) {PIDateTime r; ba >> r; return r;}
if (_type == PIVariant::pivCustom) {return getAsValue<PIDateTime>(*this);}
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 {
PIByteArray ba(_content);
if (_type == PIVariant::pivSystemTime) {PISystemTime r; ba >> r; return r;}
if (_type == PIVariant::pivCustom) {return getAsValue<PISystemTime>(*this);}
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 {
PIByteArray ba(_content);
switch (_type) {
case PIVariant::pivBool: {bool r; ba >> r; return PIString::fromNumber(r);}
case PIVariant::pivChar: {char r; ba >> r; return PIString::fromNumber(r);}
case PIVariant::pivUChar: {uchar r; ba >> r; return PIString::fromNumber(r);}
case PIVariant::pivShort: {short r; ba >> r; return PIString::fromNumber(r);}
case PIVariant::pivUShort: {ushort r; ba >> r; return PIString::fromNumber(r);}
case PIVariant::pivInt: {int r; ba >> r; return PIString::fromNumber(r);}
case PIVariant::pivUInt: {uint r; ba >> r; return PIString::fromNumber(r);}
case PIVariant::pivLLong: {llong r; ba >> r; return PIString::fromNumber(r);}
case PIVariant::pivULLong: {ullong r; ba >> r; return PIString::fromNumber(r);}
case PIVariant::pivFloat: {float r; ba >> r; return PIString::fromNumber(r);}
case PIVariant::pivDouble: {double r; ba >> r; return PIString::fromNumber(r);}
case PIVariant::pivLDouble: {ldouble r; ba >> r; return PIString::fromNumber(r);}
case PIVariant::pivTime: {PITime r; ba >> r; return r.toString();}
case PIVariant::pivDate: {PIDate r; ba >> r; return r.toString();}
case PIVariant::pivDateTime: {PIDateTime r; ba >> r; return r.toString();}
case PIVariant::pivString: {PIString r; ba >> r; return r;}
case PIVariant::pivStringList: {PIStringList r; ba >> r; if (r.isEmpty()) return PIString(); return r.join(";");}
case PIVariant::pivEnum: {PIVariantTypes::Enum r; ba >> r; return r.selectedName();}
case PIVariant::pivFile: {PIVariantTypes::File r; ba >> r; return r.file;}
case PIVariant::pivDir: {PIVariantTypes::Dir r; ba >> r; return r.dir;}
case PIVariant::pivColor: {PIVariantTypes::Color r; ba >> r; return "#" + PIString::fromNumber(r.rgba, 16);}
case PIVariant::pivIODevice: {PIVariantTypes::IODevice r; ba >> r; return "IODevice";} // TODO
case PIVariant::pivCustom: return getAsValue<PIString>(*this);
default: break;
}
return PIString();
}
/** \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 {
PIByteArray ba(_content);
if (_type == PIVariant::pivStringList) {PIStringList r; ba >> r; return r;}
if (_type == PIVariant::pivEnum) {PIVariantTypes::Enum r; ba >> r; return r.names();}
if (_type == PIVariant::pivCustom) {return getAsValue<PIStringList>(*this);}
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 {
PIByteArray ba(_content);
if (_type == PIVariant::pivBitArray) {PIBitArray r; ba >> r; return r;}
if (_type == PIVariant::pivCustom) {return getAsValue<PIBitArray>(*this);}
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 {
PIByteArray ba(_content);
if (_type == PIVariant::pivByteArray) {PIByteArray r; ba >> r; return r;}
if (_type == PIVariant::pivCustom) {return getAsValue<PIByteArray>(*this);}
return PIByteArray();
}
/** \brief Returns variant content as enum
* \details In case of Enum type returns enum value. \n
* In case of String returns Enum with one member. \n
* In case of StringList returns Enum with corresponding members. \n
* In case of other types returns empty Enum. */
PIVariantTypes::Enum PIVariant::toEnum() const {
PIByteArray ba(_content);
if (_type == PIVariant::pivEnum) {PIVariantTypes::Enum r; ba >> r; return r;}
if (_type == PIVariant::pivString) {PIString v; ba >> v; PIVariantTypes::Enum r; r << v; return r;}
if (_type == PIVariant::pivStringList) {PIStringList v; ba >> v; PIVariantTypes::Enum r; r << v; return r;}
if (_type == PIVariant::pivCustom) {return getAsValue<PIVariantTypes::Enum>(*this);}
return PIVariantTypes::Enum();
}
/** \brief Returns variant content as file
* \details In case of File type returns file value. \n
* In case of String returns File with string value path. \n
* In case of other types returns empty File. */
PIVariantTypes::File PIVariant::toFile() const {
PIByteArray ba(_content);
if (_type == PIVariant::pivFile) {PIVariantTypes::File r; ba >> r; return r;}
if (_type == PIVariant::pivString) {PIString v; ba >> v; PIVariantTypes::File r; r.file = v; return r;}
if (_type == PIVariant::pivCustom) {return getAsValue<PIVariantTypes::File>(*this);}
return PIVariantTypes::File();
}
/** \brief Returns variant content as dir
* \details In case of Dir type returns dir value. \n
* In case of String returns Dir with string value path. \n
* In case of other types returns empty Dir. */
PIVariantTypes::Dir PIVariant::toDir() const {
PIByteArray ba(_content);
if (_type == PIVariant::pivDir) {PIVariantTypes::Dir r; ba >> r; return r;}
if (_type == PIVariant::pivString) {PIString v; ba >> v; PIVariantTypes::Dir r; r.dir = v; return r;}
if (_type == PIVariant::pivCustom) {return getAsValue<PIVariantTypes::Dir>(*this);}
return PIVariantTypes::Dir();
}
/** \brief Returns variant content as color
* \details In case of Color type returns color value. \n
* In case of int returns color with int value. \n
* In case of other types returns empty Color. */
PIVariantTypes::Color PIVariant::toColor() const {
PIByteArray ba(_content);
if (_type == PIVariant::pivColor) {PIVariantTypes::Color r; ba >> r; return r;}
if (_type == PIVariant::pivInt) {int v; ba >> v; return PIVariantTypes::Color(v);}
if (_type == PIVariant::pivCustom) {return getAsValue<PIVariantTypes::Color>(*this);}
return PIVariantTypes::Color();
}
/** \brief Returns variant content as IODevice
* \details In case of IODevice type returns IODevice value. \n
* In case of other types returns empty IODevice. */
PIVariantTypes::IODevice PIVariant::toIODevice() const {
PIByteArray ba(_content);
if (_type == PIVariant::pivIODevice) {PIVariantTypes::IODevice r; ba >> r; return r;}
return PIVariantTypes::IODevice();
}
/** \brief Returns variant content as point
* \details In case of PIPointd type returns point value. \n
* In case of other types returns empty PIPointd. */
PIPointd PIVariant::toPoint() const {
PIByteArray ba(_content);
if (_type == PIVariant::pivPoint) {PIPointd r; ba >> r; return r;}
return PIPointd();
}
/** \brief Returns variant content as rect
* \details In case of PIRectd type returns rect value. \n
* In case of other types returns empty PIRectd. */
PIRectd PIVariant::toRect() const {
PIByteArray ba(_content);
if (_type == PIVariant::pivRect) {PIRectd r; ba >> r; return r;}
return PIRectd();
}
/** \brief Returns variant content as math vector
* \details In case of PIMathVectord type returns rect value. \n
* In case of other types returns empty PIMathVectord. */
PIMathVectord PIVariant::toMathVector() const {
PIByteArray ba(_content);
if (_type == PIVariant::pivMathVector) {PIMathVectord r; ba >> r; return r;}
return PIMathVectord();
}
/** \brief Returns variant content as math matrix
* \details In case of PIMathMatrixd type returns rect value. \n
* In case of other types returns empty PIMathMatrixd. */
PIMathMatrixd PIVariant::toMathMatrix() const {
PIByteArray ba(_content);
if (_type == PIVariant::pivMathMatrix) {PIMathMatrixd r; ba >> r; return r;}
return PIMathMatrixd();
}

787
lib/main/core/pivariant.h Normal file
View File

@@ -0,0 +1,787 @@
/*! \file pivariant.h
* \brief Variant type
*
* This file declares PIVariant
*/
/*
PIP - Platform Independent Primitives
Variant type
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PIVARIANT_H
#define PIVARIANT_H
#include "pivarianttypes.h"
#include "pitime.h"
#include "pigeometry.h"
#include "pimathmatrix.h"
#ifndef QNX
# define CUSTOM_PIVARIANT
#endif
#ifdef CUSTOM_PIVARIANT
template<typename T>
class PIP_EXPORT __PIVariantFunctions__ {
public:
static PIString typeNameHelper() {return PIStringAscii("");}
static bool isSimpleHelper() {return false;}
template<typename C> static PIByteArray castHelper(PIByteArray ba) {return PIByteArray();}
template<typename C> static C castVariant(const T & v) {return C();}
};
struct PIP_EXPORT __PIVariantInfo__ {
__PIVariantInfo__() {
simple = false;
}
typedef PIByteArray(*castHelperFunc)(PIByteArray);
PIMap<PIString, castHelperFunc> cast;
PIString typeName;
bool simple;
};
template<typename T>
struct PIP_EXPORT __PIVariantTypeInfo__ {
typedef T PureType;
typedef const T ConstPureType;
typedef T * PointerType;
typedef const T * ConstPointerType;
typedef T & ReferenceType;
typedef const T & ConstReferenceType;
};
#define __TYPEINFO_SINGLE(PT, T) \
template<> struct __PIVariantTypeInfo__<T> { \
typedef PT PureType; \
typedef const PT ConstPureType; \
typedef PT * PointerType; \
typedef const PT * ConstPointerType; \
typedef PT & ReferenceType; \
typedef const PT & ConstReferenceType; \
};
#define REGISTER_VARIANT_TYPEINFO(T) \
__TYPEINFO_SINGLE(T, T &) \
__TYPEINFO_SINGLE(T, const T) \
__TYPEINFO_SINGLE(T, const T &)
class PIP_EXPORT __PIVariantInfoStorage__ {
public:
__PIVariantInfoStorage__() {if (!map) map = new PIMap<PIString, __PIVariantInfo__ * >();}
static __PIVariantInfoStorage__ * get() {static __PIVariantInfoStorage__ * r = new __PIVariantInfoStorage__(); return r;}
static PIMap<PIString, __PIVariantInfo__ * > * map;
};
#define REGISTER_VARIANT_H(classname) \
template<> inline PIString __PIVariantFunctions__< classname >::typeNameHelper() {static PIString tn = PIStringAscii(#classname); return tn;} \
REGISTER_VARIANT_TYPEINFO(classname)
#define REGISTER_NS_VARIANT_H(ns, classname) \
template<> inline PIString __PIVariantFunctions__< ns::classname >::typeNameHelper() {static PIString tn = PIStringAscii(#ns"::"#classname); return tn;} \
REGISTER_VARIANT_TYPEINFO(ns::classname)
#define REGISTER_VARIANT_CPP(classname) \
template <typename T> \
class PIP_EXPORT __##classname##_PIVariantInitializer__ { \
public: \
__##classname##_PIVariantInitializer__(const PIString & name) { \
if (__PIVariantInfoStorage__::get()->map->contains(name)) \
return; \
__PIVariantInfo__ * vi = new __PIVariantInfo__(); \
vi->typeName = name; \
(*(__PIVariantInfoStorage__::get()->map))[name] = vi; \
} \
};
#define REGISTER_NS_VARIANT_CPP(ns, classname) \
template <typename T> \
class PIP_EXPORT __##ns##classname##_PIVariantInitializer__ { \
public: \
__##ns##classname##_PIVariantInitializer__(const PIString & name) { \
if (__PIVariantInfoStorage__::get()->map->contains(name)) \
return; \
__PIVariantInfo__ * vi = new __PIVariantInfo__(); \
vi->typeName = name; \
(*(__PIVariantInfoStorage__::get()->map))[name] = vi; \
} \
};
#define INIT_VARIANT(classname) \
__##classname##_PIVariantInitializer__< classname > __##classname##_pivariant_initializer__(#classname);
#define INIT_NS_VARIANT(ns, classname) \
__##ns##classname##_PIVariantInitializer__< ns::classname > __##ns##classname##_pivariant_initializer__(#ns"::"#classname);
#define REGISTER_VARIANT(classname) \
REGISTER_VARIANT_H(classname) \
REGISTER_VARIANT_CPP(classname) \
static INIT_VARIANT(classname)
#define REGISTER_NS_VARIANT(ns, classname) \
REGISTER_NS_VARIANT_H(ns, classname) \
REGISTER_NS_VARIANT_CPP(ns, classname) \
static INIT_NS_VARIANT(ns, classname)
#define REGISTER_VARIANT_CAST_H(classname_from, classname_to) \
template<> template<> inline \
classname_to __PIVariantFunctions__<classname_from>::castVariant<classname_to>(const classname_from & v);
#define REGISTER_VARIANT_CAST_CPP(classname_from, classname_to) \
template<> template<> inline \
PIByteArray __PIVariantFunctions__<classname_from>::castHelper<classname_to>(PIByteArray v) { \
classname_from f; v >> f; \
classname_to t = __PIVariantFunctions__<classname_from>::castVariant<classname_to>(f); \
PIByteArray ret; ret << t; \
return ret;} \
template <typename T, typename C> \
class PIP_EXPORT __##classname_from##_##classname_to##_PIVariantCastInitializer__ { \
public: \
__##classname_from##_##classname_to##_PIVariantCastInitializer__(const PIString & name, const PIString & cname) { \
__PIVariantInfo__ * vi(__PIVariantInfoStorage__::get()->map->value(name, 0)); \
if (!vi) { \
piCout << "Warning! Using REGISTER_VARIANT_CAST("#classname_from", "#classname_to") before REGISTER_VARIANT("#classname_from"), ignore."; \
return; \
} \
vi->cast[cname] = __PIVariantFunctions__<classname_from>::castHelper<classname_to>; \
} \
}; \
static __##classname_from##_##classname_to##_PIVariantCastInitializer__< classname_from, classname_to > __##classname_from##_##classname_to##_pivariant_cast_initializer__(#classname_from, #classname_to); \
template<> template<> \
classname_to __PIVariantFunctions__<classname_from>::castVariant<classname_to>(const classname_from & v)
#define REGISTER_VARIANT_CAST(classname_from, classname_to) \
REGISTER_VARIANT_CAST_H(classname_from, classname_to) \
REGISTER_VARIANT_CAST_CPP(classname_from, classname_to)
#define REGISTER_VARIANT_CAST_SIMPLE(classname_from, classname_to) REGISTER_VARIANT_CAST(classname_from, classname_to) {return classname_to(v);}
#define REGISTER_VARIANT_CAST_SIMPLE_H(classname_from, classname_to) REGISTER_VARIANT_CAST_H(classname_from, classname_to)
#define REGISTER_VARIANT_CAST_SIMPLE_CPP(classname_from, classname_to) REGISTER_VARIANT_CAST_CPP(classname_from, classname_to) {return classname_to(v);}
#else
#define REGISTER_VARIANT_TYPEINFO(classname)
#define REGISTER_VARIANT_H(classname)
#define REGISTER_VARIANT_CPP(classname)
#define INIT_VARIANT(classname)
#define REGISTER_VARIANT(classname)
#define REGISTER_NS_VARIANT_H(ns, classname)
#define REGISTER_NS_VARIANT_CPP(ns, classname)
#define INIT_NS_VARIANT(ns, classname)
#define REGISTER_NS_VARIANT(ns, classname)
#define REGISTER_VARIANT_CAST_H(classname_from, classname_to)
#define REGISTER_VARIANT_CAST_CPP(classname_from, classname_to)
#define REGISTER_VARIANT_CAST(classname_from, classname_to)
#define REGISTER_VARIANT_CAST_SIMPLE(classname_from, classname_to)
#define REGISTER_VARIANT_CAST_SIMPLE_H(classname_from, classname_to)
#define REGISTER_VARIANT_CAST_SIMPLE_CPP(classname_from, classname_to)
#endif
class PIP_EXPORT PIVariant {
friend PICout operator <<(PICout s, const PIVariant & v);
friend PIByteArray & operator <<(PIByteArray & s, const PIVariant & v);
friend PIByteArray & operator >>(PIByteArray & s, PIVariant & v);
public:
//! Type of %PIVariant content
enum PIP_EXPORT Type {
pivInvalid /** Invalid type , default type of empty contructor */ = 0 ,
pivBool /** bool */ ,
pivChar /** char */ ,
pivUChar /** uchar */ ,
pivShort /** short */ ,
pivUShort /** ushort */ ,
pivInt /** int */ ,
pivUInt /** uint */ ,
pivLLong /** llong */ ,
pivULLong /** ullong */ ,
pivFloat /** float */ ,
pivDouble /** double */ ,
pivLDouble /** ldouble */ ,
pivComplexd /** complexd */ ,
pivComplexld /** complexld */ ,
pivBitArray /** PIBitArray */ ,
pivByteArray /** PIByteArray */ ,
pivString /** PIString */ ,
pivStringList /** PIStringList */ ,
pivTime /** PITime */ ,
pivDate /** PIDate */ ,
pivDateTime /** PIDateTime */ ,
pivSystemTime /** PISystemTime */ ,
pivEnum /** PIVariantTypes::Enum */ ,
pivFile /** PIVariantTypes::File */ ,
pivDir /** PIVariantTypes::Dir */ ,
pivColor /** PIVariantTypes::Color */ ,
pivPoint /** PIPoint */ ,
pivRect /** PIRect */ ,
pivIODevice /** PIVariantTypes::IODevice */ ,
pivMathVector /** PIMathVectord */ ,
pivMathMatrix /** PIMathMatrixd */ ,
pivCustom /** Custom */ = 0xFF
};
//! Empty constructor, \a type() will be set to \a Invalid
PIVariant();
PIVariant(const PIVariant & v);
//! Constructs variant from string
PIVariant(const char * v) {initType(PIString(v));}
//! Constructs variant from boolean
PIVariant(const bool v) {initType(v);}
//! Constructs variant from char
PIVariant(const char v) {initType(v);}
//! Constructs variant from integer
PIVariant(const uchar v) {initType(v);}
//! Constructs variant from integer
PIVariant(const short v) {initType(v);}
//! Constructs variant from integer
PIVariant(const ushort v) {initType(v);}
//! Constructs variant from integer
PIVariant(const int & v) {initType(v);}
//! Constructs variant from integer
PIVariant(const uint & v) {initType(v);}
//! Constructs variant from integer
PIVariant(const llong & v) {initType(v);}
//! Constructs variant from integer
PIVariant(const ullong & v) {initType(v);}
//! Constructs variant from float
PIVariant(const float & v) {initType(v);}
//! Constructs variant from double
PIVariant(const double & v) {initType(v);}
//! Constructs variant from long double
PIVariant(const ldouble & v) {initType(v);}
//! Constructs variant from bit array
PIVariant(const PIBitArray & v) {initType(v);}
//! Constructs variant from byte array
PIVariant(const PIByteArray & v) {initType(v);}
//! Constructs variant from string
PIVariant(const PIString & v) {initType(v);}
//! Constructs variant from strings list
PIVariant(const PIStringList & v) {initType(v);}
//! Constructs variant from time
PIVariant(const PITime & v) {initType(v);}
//! Constructs variant from date
PIVariant(const PIDate & v) {initType(v);}
//! Constructs variant from date and time
PIVariant(const PIDateTime & v) {initType(v);}
//! Constructs variant from system time
PIVariant(const PISystemTime & v) {initType(v);}
//! Constructs variant from enum
PIVariant(const PIVariantTypes::Enum & v) {initType(v);}
//! Constructs variant from file
PIVariant(const PIVariantTypes::File & v) {initType(v);}
//! Constructs variant from dir
PIVariant(const PIVariantTypes::Dir & v) {initType(v);}
//! Constructs variant from color
PIVariant(const PIVariantTypes::Color & v) {initType(v);}
//! Constructs variant from IODevice
PIVariant(const PIVariantTypes::IODevice & v) {initType(v);}
//! Constructs variant from point
PIVariant(const PIPointd & v) {initType(v);}
//! Constructs variant from rect
PIVariant(const PIRectd & v) {initType(v);}
//! Constructs variant from MathVector
PIVariant(const PIMathVectord & v) {initType(v);}
//! Constructs variant from MathMatrix
PIVariant(const PIMathMatrixd & v) {initType(v);}
//! Set variant content and type to string
void setValue(const char * v) {setValue(PIString(v));}
//! Set variant content and type to boolean
void setValue(const bool v) {initType(v);}
//! Set variant content and type to char
void setValue(const char v) {initType(v);}
//! Set variant content and type to integer
void setValue(const uchar v) {initType(v);}
//! Set variant content and type to integer
void setValue(const short v) {initType(v);}
//! Set variant content and type to integer
void setValue(const ushort v) {initType(v);}
//! Set variant content and type to integer
void setValue(const int & v) {initType(v);}
//! Set variant content and type to integer
void setValue(const uint & v) {initType(v);}
//! Set variant content and type to integer
void setValue(const llong & v) {initType(v);}
//! Set variant content and type to integer
void setValue(const ullong & v) {initType(v);}
//! Set variant content and type to float
void setValue(const float & v) {initType(v);}
//! Set variant content and type to double
void setValue(const double & v) {initType(v);}
//! Set variant content and type to long double
void setValue(const ldouble & v) {initType(v);}
//! Set variant content and type to bit array
void setValue(const PIBitArray & v) {initType(v);}
//! Set variant content and type to byte array
void setValue(const PIByteArray & v) {initType(v);}
//! Set variant content and type to string
void setValue(const PIString & v) {initType(v);}
//! Set variant content and type to strings list
void setValue(const PIStringList & v) {initType(v);}
//! Set variant content and type to time
void setValue(const PITime & v) {initType(v);}
//! Set variant content and type to date
void setValue(const PIDate & v) {initType(v);}
//! Set variant content and type to date and time
void setValue(const PIDateTime & v) {initType(v);}
//! Set variant content and type to system time
void setValue(const PISystemTime & v) {initType(v);}
//! Set variant content and type to enum
void setValue(const PIVariantTypes::Enum & v) {initType(v);}
//! Set variant content and type to file
void setValue(const PIVariantTypes::File & v) {initType(v);}
//! Set variant content and type to dir
void setValue(const PIVariantTypes::Dir & v) {initType(v);}
//! Set variant content and type to color
void setValue(const PIVariantTypes::Color & v) {initType(v);}
//! Set variant content and type to IODevice
void setValue(const PIVariantTypes::IODevice & v) {initType(v);}
//! Set variant content and type to point
void setValue(const PIPointd & v) {initType(v);}
//! Set variant content and type to rect
void setValue(const PIRectd & v) {initType(v);}
//! Set variant content and type to math vector
void setValue(const PIMathVectord & v) {initType(v);}
//! Set variant content and type to math matrix
void setValue(const PIMathMatrixd & v) {initType(v);}
//! Set current value from string without change type
void setValueFromString(const PIString & v);
bool toBool() const;
int toInt() const;
llong toLLong() const;
float toFloat() const;
double toDouble() const;
ldouble toLDouble() const;
PITime toTime() const;
PIDate toDate() const;
PIDateTime toDateTime() const;
PISystemTime toSystemTime() const;
PIString toString() const;
PIStringList toStringList() const;
PIBitArray toBitArray() const;
PIByteArray toByteArray() const;
PIVariantTypes::Enum toEnum() const;
PIVariantTypes::File toFile() const;
PIVariantTypes::Dir toDir() const;
PIVariantTypes::Color toColor() const;
PIVariantTypes::IODevice toIODevice() const;
PIPointd toPoint() const;
PIRectd toRect() const;
PIMathVectord toMathVector() const;
PIMathMatrixd toMathMatrix() const;
/** \brief Returns variant content as custom type
* \details In case of known types this function equivalent \a to<Type> function. \n
* Otherwise returns content as type T. */
template<typename T>
T value() const {return getAsValue<T>(*this);}
//! Assign operator
PIVariant & operator =(const PIVariant & v);
//! Assign operator
PIVariant & operator =(const char * v) {setValue(PIString(v)); return *this;}
//! Assign operator
PIVariant & operator =(const bool v) {setValue(v); return *this;}
//! Assign operator
PIVariant & operator =(const char v) {setValue(v); return *this;}
//! Assign operator
PIVariant & operator =(const uchar v) {setValue(v); return *this;}
//! Assign operator
PIVariant & operator =(const short v) {setValue(v); return *this;}
//! Assign operator
PIVariant & operator =(const ushort v) {setValue(v); return *this;}
//! Assign operator
PIVariant & operator =(const int & v) {setValue(v); return *this;}
//! Assign operator
PIVariant & operator =(const uint & v) {setValue(v); return *this;}
//! Assign operator
PIVariant & operator =(const llong & v) {setValue(v); return *this;}
//! Assign operator
PIVariant & operator =(const ullong & v) {setValue(v); return *this;}
//! Assign operator
PIVariant & operator =(const float & v) {setValue(v); return *this;}
//! Assign operator
PIVariant & operator =(const double & v) {setValue(v); return *this;}
//! Assign operator
PIVariant & operator =(const ldouble & v) {setValue(v); return *this;}
//! Assign operator
PIVariant & operator =(const PIBitArray & v) {setValue(v); return *this;}
//! Assign operator
PIVariant & operator =(const PIByteArray & v) {setValue(v); return *this;}
//! Assign operator
PIVariant & operator =(const PIString & v) {setValue(v); return *this;}
//! Assign operator
PIVariant & operator =(const PIStringList & v) {setValue(v); return *this;}
//! Assign operator
PIVariant & operator =(const PITime & v) {setValue(v); return *this;}
//! Assign operator
PIVariant & operator =(const PIDate & v) {setValue(v); return *this;}
//! Assign operator
PIVariant & operator =(const PIDateTime & v) {setValue(v); return *this;}
//! Assign operator
PIVariant & operator =(const PISystemTime & v) {setValue(v); return *this;}
//! Assign operator
PIVariant & operator =(const PIVariantTypes::Enum & v) {setValue(v); return *this;}
//! Assign operator
PIVariant & operator =(const PIVariantTypes::File & v) {setValue(v); return *this;}
//! Assign operator
PIVariant & operator =(const PIVariantTypes::Dir & v) {setValue(v); return *this;}
//! Assign operator
PIVariant & operator =(const PIVariantTypes::Color & v) {setValue(v); return *this;}
//! Assign operator
PIVariant & operator =(const PIVariantTypes::IODevice & v) {setValue(v); return *this;}
//! Assign operator
PIVariant & operator =(const PIPointd & v) {setValue(v); return *this;}
//! Assign operator
PIVariant & operator =(const PIRectd & v) {setValue(v); return *this;}
//! Assign operator
PIVariant & operator =(const PIMathVectord & v) {setValue(v); return *this;}
//! Assign operator
PIVariant & operator =(const PIMathMatrixd & v) {setValue(v); return *this;}
//! Compare operator
bool operator ==(const PIVariant & v) const;
//! Compare operator
bool operator !=(const PIVariant & v) const {return !(*this == v);}
//! Returns type of variant content
PIVariant::Type type() const {return _type;}
//! Returns type name of variant content
PIString typeName() const;
//! Returns \b true if type is not Invalid
bool isValid() const {return _type != PIVariant::pivInvalid;}
/** \brief Returns new variant from custom type
* \details In case of known types this function equivalent \a PIVariant(T) constructors. \n
* Otherwise returns variant with content \a v and type Custom. */
template <typename T>
static PIVariant fromValue(const T & v) {
PIVariant ret;
ret.initType<T>(v);
return ret;
}
static PIVariant fromValue(const PIByteArray & c, const PIString & type) {
PIVariant ret;
PIVariant::Type t = typeFromName(type);
if (t == pivInvalid) {
#ifdef CUSTOM_PIVARIANT
ret._info = __PIVariantInfoStorage__::get()->map->value(type, 0);
if (ret._info) {
t = pivCustom;
} else
#endif
{
piCout << "Can`t initialize PIVariant from unregistered type \"" << type << "\"!";
return ret;
}
}
ret._type = t;
ret._content = c;
return ret;
}
//! Returns type from name
static PIVariant::Type typeFromName(const PIString & tname);
//! Returns type name
static PIString typeName(PIVariant::Type type);
private:
void destroy() {_content.clear();}
template <typename T> inline static Type getType() {return pivCustom;}
template <typename T> inline void initType(const T & v) {
_content.clear();
_content << v;
_type = getType<T>();
#ifdef CUSTOM_PIVARIANT
if (_type == pivCustom) {
_info = __PIVariantInfoStorage__::get()->map->value(__PIVariantFunctions__<T>::typeNameHelper(), 0);
if (!_info)
piCout << "Can`t initialize PIVariant from unregistered type!";
} else
_info = 0;
#endif
}
template<typename T> inline static T getAsValue(const PIVariant & v) {
#ifdef CUSTOM_PIVARIANT
if (v._content.isEmpty() || !v._info) return T();
PIString cn = __PIVariantFunctions__<T>::typeNameHelper();
//piCout << "gav" << cn;
PIByteArray ba;
if (cn == v._info->typeName) {
ba = v._content;
} else {
__PIVariantInfo__::castHelperFunc cf = v._info->cast.value(cn);
//piCout << "gav cast" << cf;
if (!cf) return T();
ba = cf(v._content);
}
T ret; ba >> ret;
return ret;
#else
return T();
#endif
}
PIByteArray _content;
PIVariant::Type _type;
#ifdef CUSTOM_PIVARIANT
__PIVariantInfo__ * _info;
#endif
};
template<> inline bool PIVariant::value() const {return toBool();}
template<> inline char PIVariant::value() const {return (char)toInt();}
template<> inline uchar PIVariant::value() const {return (uchar)toInt();}
template<> inline short PIVariant::value() const {return (short)toInt();}
template<> inline ushort PIVariant::value() const {return (ushort)toInt();}
template<> inline int PIVariant::value() const {return toInt();}
template<> inline uint PIVariant::value() const {return (uint)toInt();}
template<> inline llong PIVariant::value() const {return toLLong();}
template<> inline ullong PIVariant::value() const {return (ullong)toLLong();}
template<> inline float PIVariant::value() const {return toFloat();}
template<> inline double PIVariant::value() const {return toDouble();}
template<> inline ldouble PIVariant::value() const {return toLDouble();}
template<> inline void* PIVariant::value() const {return (void*)toLLong();}
template<> inline const char* PIVariant::value() const {return toString().data();}
template<> inline PITime PIVariant::value() const {return toTime();}
template<> inline PIDate PIVariant::value() const {return toDate();}
template<> inline PIDateTime PIVariant::value() const {return toDateTime();}
template<> inline PIString PIVariant::value() const {return toString();}
template<> inline PIStringList PIVariant::value() const {return toStringList();}
template<> inline PIBitArray PIVariant::value() const {return toBitArray();}
template<> inline PIByteArray PIVariant::value() const {return toByteArray();}
template<> inline PIVariantTypes::Enum PIVariant::value() const {return toEnum();}
template<> inline PIVariantTypes::File PIVariant::value() const {return toFile();}
template<> inline PIVariantTypes::Dir PIVariant::value() const {return toDir();}
template<> inline PIVariantTypes::Color PIVariant::value() const {return toColor();}
template<> inline PIVariantTypes::IODevice PIVariant::value() const {return toIODevice();}
template<> inline PIPointd PIVariant::value() const {return toPoint();}
template<> inline PIRectd PIVariant::value() const {return toRect();}
template<> inline PIVariant PIVariant::fromValue(const bool & v) {return PIVariant(v);}
template<> inline PIVariant PIVariant::fromValue(const char & v) {return PIVariant(v);}
template<> inline PIVariant PIVariant::fromValue(const uchar & v) {return PIVariant(v);}
template<> inline PIVariant PIVariant::fromValue(const short & v) {return PIVariant(v);}
template<> inline PIVariant PIVariant::fromValue(const ushort & v) {return PIVariant(v);}
template<> inline PIVariant PIVariant::fromValue(const int & v) {return PIVariant(v);}
template<> inline PIVariant PIVariant::fromValue(const uint & v) {return PIVariant(v);}
template<> inline PIVariant PIVariant::fromValue(const llong & v) {return PIVariant(v);}
template<> inline PIVariant PIVariant::fromValue(const ullong & v) {return PIVariant(v);}
template<> inline PIVariant PIVariant::fromValue(const float & v) {return PIVariant(v);}
template<> inline PIVariant PIVariant::fromValue(const double & v) {return PIVariant(v);}
template<> inline PIVariant PIVariant::fromValue(const ldouble & v) {return PIVariant(v);}
template<> inline PIVariant PIVariant::fromValue(const PIBitArray & v) {return PIVariant(v);}
template<> inline PIVariant PIVariant::fromValue(const PIByteArray & v) {return PIVariant(v);}
template<> inline PIVariant PIVariant::fromValue(const PIString & v) {return PIVariant(v);}
template<> inline PIVariant PIVariant::fromValue(const PIStringList & v) {return PIVariant(v);}
template<> inline PIVariant PIVariant::fromValue(const PITime & v) {return PIVariant(v);}
template<> inline PIVariant PIVariant::fromValue(const PIDate & v) {return PIVariant(v);}
template<> inline PIVariant PIVariant::fromValue(const PIDateTime & v) {return PIVariant(v);}
template<> inline PIVariant PIVariant::fromValue(const PISystemTime & v) {return PIVariant(v);}
template<> inline PIVariant PIVariant::fromValue(const PIVariantTypes::Enum & v) {return PIVariant(v);}
template<> inline PIVariant PIVariant::fromValue(const PIVariantTypes::File & v) {return PIVariant(v);}
template<> inline PIVariant PIVariant::fromValue(const PIVariantTypes::Dir & v) {return PIVariant(v);}
template<> inline PIVariant PIVariant::fromValue(const PIVariantTypes::Color & v) {return PIVariant(v);}
template<> inline PIVariant PIVariant::fromValue(const PIVariantTypes::IODevice & v) {return PIVariant(v);}
template<> inline PIVariant PIVariant::fromValue(const PIPointd & v) {return PIVariant(v);}
template<> inline PIVariant PIVariant::fromValue(const PIRectd & v) {return PIVariant(v);}
template<> inline PIVariant PIVariant::fromValue(const PIMathVectord & v) {return PIVariant(v);}
template<> inline PIVariant PIVariant::fromValue(const PIMathMatrixd & v) {return PIVariant(v);}
template<> inline PIVariant::Type PIVariant::getType<bool>() {return PIVariant::pivBool;}
template<> inline PIVariant::Type PIVariant::getType<char>() {return PIVariant::pivChar;}
template<> inline PIVariant::Type PIVariant::getType<uchar>() {return PIVariant::pivUChar;}
template<> inline PIVariant::Type PIVariant::getType<short>() {return PIVariant::pivShort;}
template<> inline PIVariant::Type PIVariant::getType<ushort>() {return PIVariant::pivUShort;}
template<> inline PIVariant::Type PIVariant::getType<int>() {return PIVariant::pivInt;}
template<> inline PIVariant::Type PIVariant::getType<uint>() {return PIVariant::pivUInt;}
template<> inline PIVariant::Type PIVariant::getType<llong>() {return PIVariant::pivLLong;}
template<> inline PIVariant::Type PIVariant::getType<ullong>() {return PIVariant::pivULLong;}
template<> inline PIVariant::Type PIVariant::getType<float>() {return PIVariant::pivFloat;}
template<> inline PIVariant::Type PIVariant::getType<double>() {return PIVariant::pivDouble;}
template<> inline PIVariant::Type PIVariant::getType<ldouble>() {return PIVariant::pivLDouble;}
template<> inline PIVariant::Type PIVariant::getType<PIBitArray>() {return PIVariant::pivBitArray;}
template<> inline PIVariant::Type PIVariant::getType<PIByteArray>() {return PIVariant::pivByteArray;}
template<> inline PIVariant::Type PIVariant::getType<PIString>() {return PIVariant::pivString;}
template<> inline PIVariant::Type PIVariant::getType<PIStringList>() {return PIVariant::pivStringList;}
template<> inline PIVariant::Type PIVariant::getType<PITime>() {return PIVariant::pivTime;}
template<> inline PIVariant::Type PIVariant::getType<PIDate>() {return PIVariant::pivDate;}
template<> inline PIVariant::Type PIVariant::getType<PIDateTime>() {return PIVariant::pivDateTime;}
template<> inline PIVariant::Type PIVariant::getType<PISystemTime>() {return PIVariant::pivSystemTime;}
template<> inline PIVariant::Type PIVariant::getType<PIVariantTypes::Enum>() {return PIVariant::pivEnum;}
template<> inline PIVariant::Type PIVariant::getType<PIVariantTypes::File>() {return PIVariant::pivFile;}
template<> inline PIVariant::Type PIVariant::getType<PIVariantTypes::Dir>() {return PIVariant::pivDir;}
template<> inline PIVariant::Type PIVariant::getType<PIVariantTypes::Color>() {return PIVariant::pivColor;}
template<> inline PIVariant::Type PIVariant::getType<PIVariantTypes::IODevice>() {return PIVariant::pivIODevice;}
template<> inline PIVariant::Type PIVariant::getType<PIPointd>() {return PIVariant::pivPoint;}
template<> inline PIVariant::Type PIVariant::getType<PIRectd>() {return PIVariant::pivRect;}
template<> inline PIVariant::Type PIVariant::getType<PIMathVectord>() {return PIVariant::pivMathVector;}
template<> inline PIVariant::Type PIVariant::getType<PIMathMatrixd>() {return PIVariant::pivMathMatrix;}
REGISTER_VARIANT(bool)
REGISTER_VARIANT(char)
REGISTER_VARIANT(uchar)
REGISTER_VARIANT(short)
REGISTER_VARIANT(ushort)
REGISTER_VARIANT(int)
REGISTER_VARIANT(uint)
REGISTER_VARIANT(llong)
REGISTER_VARIANT(ullong)
REGISTER_VARIANT(float)
REGISTER_VARIANT(double)
REGISTER_VARIANT(ldouble)
REGISTER_VARIANT(PIBitArray)
REGISTER_VARIANT(PIByteArray)
REGISTER_VARIANT(PIString)
REGISTER_VARIANT(PIStringList)
REGISTER_VARIANT(PITime)
REGISTER_VARIANT(PIDate)
REGISTER_VARIANT(PIDateTime)
REGISTER_VARIANT(PISystemTime)
REGISTER_NS_VARIANT(PIVariantTypes, Enum)
REGISTER_NS_VARIANT(PIVariantTypes, File)
REGISTER_NS_VARIANT(PIVariantTypes, Dir)
REGISTER_NS_VARIANT(PIVariantTypes, Color)
REGISTER_NS_VARIANT(PIVariantTypes, IODevice)
REGISTER_VARIANT(PIPointd)
REGISTER_VARIANT(PIRectd)
REGISTER_VARIANT(PIMathVectord)
REGISTER_VARIANT(PIMathMatrixd)
inline PIByteArray & operator <<(PIByteArray & s, const PIVariant & v) {
s << v._content << int(v._type);
if (v._type == PIVariant::pivCustom) {
#ifdef CUSTOM_PIVARIANT
if (v._info) {
s << v._info->typeName;
} else {
s << PIStringAscii("");
}
#else
s << PIStringAscii("");
#endif
}
return s;
}
inline PIByteArray & operator >>(PIByteArray & s, PIVariant & v) {
int t(0);
s >> v._content >> t;
v._type = (PIVariant::Type)t;
if (v._type == PIVariant::pivCustom) {
PIString tn;
s >> tn;
#ifdef CUSTOM_PIVARIANT
PIByteArray vc = v._content;
v = PIVariant::fromValue(vc, tn);
#endif
}
return s;
}
inline PICout operator <<(PICout s, const PIVariant & v) {
s.space(); s.setControl(0, true);
s << "PIVariant(" << v.typeName() << ", " << v.toString() << ")";
s.restoreControl(); return s;
}
#endif // PIVARIANT_H

View File

@@ -0,0 +1,152 @@
/*
PIP - Platform Independent Primitives
Variant types
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "pivarianttypes.h"
#include "pipropertystorage.h"
#include "piiodevice.h"
int PIVariantTypes::Enum::selectedValue() const {
piForeachC (Enumerator & e, enum_list)
if (e.name == selected)
return e.value;
return 0;
}
bool PIVariantTypes::Enum::selectValue(int v) {
piForeachC (Enumerator & e, enum_list)
if (e.value == v) {
selected = e.name;
return true;
}
return false;
}
bool PIVariantTypes::Enum::selectName(const PIString & n) {
piForeachC (Enumerator & e, enum_list)
if (e.name == n) {
selected = e.name;
return true;
}
return false;
}
int PIVariantTypes::Enum::value(const PIString & n) const {
piForeachC (Enumerator & e, enum_list)
if (e.name == n)
return e.value;
return 0;
}
PIString PIVariantTypes::Enum::name(int v) const {
piForeachC (Enumerator & e, enum_list)
if (e.value == v)
return e.name;
return PIString();
}
PIVector<int> PIVariantTypes::Enum::values() const {
PIVector<int> ret;
piForeachC (Enumerator & e, enum_list)
ret << e.value;
return ret;
}
PIStringList PIVariantTypes::Enum::names() const {
PIStringList ret;
piForeachC (Enumerator & e, enum_list)
ret << e.name;
return ret;
}
PIVariantTypes::IODevice::IODevice() {
mode = PIIODevice::ReadWrite;
options = 0;
}
void PIVariantTypes::IODevice::set(const PIPropertyStorage & ps) {
props.clear();
props << ps;
}
PIPropertyStorage PIVariantTypes::IODevice::get() const {
PIPropertyStorage ret;
PIByteArray ba = props;
if (!ba.isEmpty()) ba >> ret;
return ret;
}
PIString PIVariantTypes::IODevice::toPICout() const {
PIString s;
s << "IODevice(" << prefix << ", mode=";
int rwc = 0;
if (mode & 1) {s << "r"; ++rwc;}
if (mode & 2) {s << "w"; ++rwc;}
if (rwc == 1) s << "o";
s << ", flags=";
if (options != 0) {
if (((PIIODevice::DeviceOptions)options)[PIIODevice::BlockingRead])
s << " br";
if (((PIIODevice::DeviceOptions)options)[PIIODevice::BlockingWrite])
s << " bw";
}
PIPropertyStorage ps = get();
piForeachC (PIPropertyStorage::Property & p, ps) {
s << ", " << p.name << "=\"" << p.value.toString() << "\"";
}
s << ")";
return s;
}
PIVariantTypes::Enum & PIVariantTypes::Enum::operator <<(const PIVariantTypes::Enumerator & v) {
enum_list << v;
return *this;
}
PIVariantTypes::Enum & PIVariantTypes::Enum::operator <<(const PIString & v) {
if (enum_list.isEmpty()) {
enum_list << Enumerator(0, v);
} else {
enum_list << Enumerator(enum_list.back().value+1, v);
}
return *this;
}
PIVariantTypes::Enum & PIVariantTypes::Enum::operator <<(const PIStringList & v) {
piForeachC (PIString & s, v)
(*this) << s;
return *this;
}

View File

@@ -0,0 +1,182 @@
/*! \file pivarianttypes.h
* \brief Variant type
*
* This file declares PIVariant
*/
/*
PIP - Platform Independent Primitives
Variant types
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PIVARIANTYPES_H
#define PIVARIANTYPES_H
#include "pistringlist.h"
class PIPropertyStorage;
namespace PIVariantTypes {
/**
* @brief name-value pair
*/
struct PIP_EXPORT Enumerator {
Enumerator(int v = 0, const PIString & n = PIString()): value(v), name(n) {}
int value;
PIString name;
};
/**
* @brief Collection of PIVariantTypes::Enumerator. It's replace classic c-style enum.
* Contains elements with unique name and not uniqueue values.
*/
struct PIP_EXPORT Enum {
Enum(const PIString & n = PIString()): enum_name(n) {}
PIString toString() const {return selected;} // obsolete
/**
* @brief Find selected value.
* @return selected value, otherwrise 0
*/
int selectedValue() const;
/**
* @brief Get selected name
* @return selected name, otherwrise empty PIString
*/
PIString selectedName() const {return selected;}
/**
* @brief Select value if exists in Enum. If Enum contains several PIVariantTypes::Enumerator with same values,
* first PIVariantTypes::Enumerator will selected
* @param v value for selection
* @return true if value exists in Enum, false otherwrise
*/
bool selectValue(int v);
/**
* @brief Select name if exists in enum
* @param n name for selection
* @return true if name exists in Enum, false otherwrise
*/
bool selectName(const PIString & n);
/**
* @brief Find PIVariantTypes::Enumerator with specific name and return it value
* @param n name for search
* @return value of founded PIVariantTypes::Enumerator, 0 otherwrise
*/
int value(const PIString & n) const;
/**
* @brief Find first PIVariantTypes::Enumerator with specific value and return it name
* @param v value for search
* @return name of founded PIVariantTypes::Enumerator, empty string otherwrise
*/
PIString name(int v) const;
/**
* @brief Make vector of Enum values
*/
PIVector<int> values() const;
/**
* @brief Make vector of Enum names
*/
PIStringList names() const;
PIString enum_name;
PIString selected;
PIVector<Enumerator> enum_list;
/**
* @brief Add PIVariantTypes::Enumerator to Enum
*/
Enum & operator <<(const Enumerator & v);
/**
* @brief Add PIVariantTypes::Enumerator element to Enum. Element contains specific name and value more per
* unit then last element. If the is no elements, contains zero value.
* @param v name for new PIVariantTypes::Enumerator element
*/
Enum & operator <<(const PIString & v);
/**
* @brief Add PIVariantTypes::Enumerator element for each name in vector
*/
Enum & operator <<(const PIStringList & v);
};
struct PIP_EXPORT File {
File(const PIString & p = PIString(), const PIString & f = PIString(), bool abs = false): file(p), filter(f), is_abs(abs) {}
PIString toString() const {return file;}
PIString file;
PIString filter;
bool is_abs;
};
struct PIP_EXPORT Dir {
Dir(const PIString & d = PIString(), bool abs = false): dir(d), is_abs(abs) {}
PIString toString() const {return dir;}
PIString dir;
bool is_abs;
};
struct PIP_EXPORT Color {
Color(uint v = 0) {rgba = v;}
uint rgba;
};
struct PIP_EXPORT IODevice {
IODevice();
void set(const PIPropertyStorage & ps);
PIPropertyStorage get() const;
PIString toPICout() const;
PIString prefix;
int mode; // PIIODevice::DeviceMode
int options; // PIIODevice::DeviceOptions
PIByteArray props;
};
}
inline PIByteArray & operator <<(PIByteArray & s, const PIVariantTypes::Enumerator & v) {s << v.value << v.name; return s;}
inline PIByteArray & operator >>(PIByteArray & s, PIVariantTypes::Enumerator & v) {s >> v.value >> v.name; return s;}
inline PICout operator <<(PICout s, const PIVariantTypes::Enumerator & v) {s << v.name << "(" << v.value << ")"; return s;}
inline PIByteArray & operator <<(PIByteArray & s, const PIVariantTypes::Enum & v) {s << v.enum_name << v.selected << v.enum_list; return s;}
inline PIByteArray & operator >>(PIByteArray & s, PIVariantTypes::Enum & v) {s >> v.enum_name >> v.selected >> v.enum_list; return s;}
inline PICout operator <<(PICout s, const PIVariantTypes::Enum & v) {s << "Enum(" << v.selectedValue() << "=" << v.selectedName() << ")"; return s;}
inline PIByteArray & operator <<(PIByteArray & s, const PIVariantTypes::File & v) {s << v.file << v.filter << v.is_abs; return s;}
inline PIByteArray & operator >>(PIByteArray & s, PIVariantTypes::File & v) {s >> v.file >> v.filter >> v.is_abs; return s;}
inline PICout operator <<(PICout s, const PIVariantTypes::File & v) {s << "File(\"" << v.file << "\")"; return s;}
inline PIByteArray & operator <<(PIByteArray & s, const PIVariantTypes::Dir & v) {s << v.dir << v.is_abs; return s;}
inline PIByteArray & operator >>(PIByteArray & s, PIVariantTypes::Dir & v) {s >> v.dir >> v.is_abs; return s;}
inline PICout operator <<(PICout s, const PIVariantTypes::Dir & v) {s << "Dir(\"" << v.dir << "\")"; return s;}
inline PIByteArray & operator <<(PIByteArray & s, const PIVariantTypes::Color & v) {s << v.rgba; return s;}
inline PIByteArray & operator >>(PIByteArray & s, PIVariantTypes::Color & v) {s >> v.rgba; return s;}
inline PICout operator <<(PICout s, const PIVariantTypes::Color & v) {s.saveControl(); s << PICoutManipulators::Hex << "Color(#" << v.rgba << ")"; s.restoreControl(); return s;}
inline PIByteArray & operator <<(PIByteArray & s, const PIVariantTypes::IODevice & v) {s << v.prefix << v.mode << v.options << v.props; return s;}
inline PIByteArray & operator >>(PIByteArray & s, PIVariantTypes::IODevice & v) {s >> v.prefix >> v.mode >> v.options >> v.props; return s;}
inline PICout operator <<(PICout s, const PIVariantTypes::IODevice & v) {s << v.toPICout(); return s;}
#endif // PIVARIANTYPES_H