From 491d89f117681b5276dd20f07e875d0207e9c2a7 Mon Sep 17 00:00:00 2001 From: peri4 Date: Sun, 5 May 2024 00:17:52 +0300 Subject: [PATCH] version 3.19.0 PIMathVectorT subvector methods PISystemTime::isNull() PISystemTime::Frequency::isNull() PISystemTime::toString() PISystemTime::fromString() PIVariant can handle strings with PISystemTime PIDateTime::toSystemTime() now returns null time from invalid strings --- CMakeLists.txt | 4 +- libs/main/literals/piliterals_time.h | 45 ++++++++++++++ libs/main/math/pimathvector.h | 49 +++++++++++++++ libs/main/types/pidatetime.cpp | 5 ++ libs/main/types/pidatetime.h | 2 +- libs/main/types/pisystemtime.cpp | 89 ++++++++++++++++++++++++++++ libs/main/types/pisystemtime.h | 16 +++++ libs/main/types/pivariant.cpp | 30 ++++++++-- libs/main/types/pivariant.h | 1 + 9 files changed, 234 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 292a9a87..4fb32476 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,8 +2,8 @@ cmake_minimum_required(VERSION 3.0) cmake_policy(SET CMP0017 NEW) # need include() with .cmake project(PIP) set(PIP_MAJOR 3) -set(PIP_MINOR 18) -set(PIP_REVISION 1) +set(PIP_MINOR 19) +set(PIP_REVISION 0) set(PIP_SUFFIX ) set(PIP_COMPANY SHS) set(PIP_DOMAIN org.SHS) diff --git a/libs/main/literals/piliterals_time.h b/libs/main/literals/piliterals_time.h index a1e5ca0b..d679883a 100644 --- a/libs/main/literals/piliterals_time.h +++ b/libs/main/literals/piliterals_time.h @@ -29,6 +29,51 @@ #include "pisystemtime.h" +//! \~\brief +//! \~english PISystemTime from days +//! \~russian PISystemTime из дней +inline PISystemTime operator""_d(long double v) { + return PISystemTime::fromSeconds(v * 60. * 60. * 24.); +} + +//! \~\brief +//! \~english PISystemTime from days +//! \~russian PISystemTime из дней +inline PISystemTime operator""_d(unsigned long long v) { + return PISystemTime::fromSeconds(v * 60. * 60. * 24.); +} + + +//! \~\brief +//! \~english PISystemTime from hours +//! \~russian PISystemTime из часов +inline PISystemTime operator""_h(long double v) { + return PISystemTime::fromSeconds(v * 60. * 60.); +} + +//! \~\brief +//! \~english PISystemTime from hours +//! \~russian PISystemTime из часов +inline PISystemTime operator""_h(unsigned long long v) { + return PISystemTime::fromSeconds(v * 60. * 60.); +} + + +//! \~\brief +//! \~english PISystemTime from minutes +//! \~russian PISystemTime из минут +inline PISystemTime operator""_m(long double v) { + return PISystemTime::fromSeconds(v * 60.); +} + +//! \~\brief +//! \~english PISystemTime from minutes +//! \~russian PISystemTime из минут +inline PISystemTime operator""_m(unsigned long long v) { + return PISystemTime::fromSeconds(v * 60.); +} + + //! \~\brief //! \~english PISystemTime from seconds //! \~russian PISystemTime из секунд diff --git a/libs/main/math/pimathvector.h b/libs/main/math/pimathvector.h index 6dbcbc90..4f8195ff 100644 --- a/libs/main/math/pimathvector.h +++ b/libs/main/math/pimathvector.h @@ -127,6 +127,8 @@ public: Type & operator[](uint index) { return c[index]; } const Type & operator[](uint index) const { return c[index]; } Type at(uint index) const { return c[index]; } + inline Type & element(uint index) { return c[index]; } + inline const Type & element(uint index) const { return c[index]; } _CVector & operator=(const Type & v) { PIMV_FOR c[i] = v; @@ -225,6 +227,53 @@ public: return tv; } + //! \~english + //! \brief Returns this vector with another element type. + //! \~russian + //! \brief Возвращает этот вектор с другим типом элементов. + template + PIMathVectorT toType() const { + PIMathVectorT ret; + PIMV_FOR ret[i] = element(i); + return ret; + } + + //! \~english + //! \brief Returns the subvector with size SubSize. Elements takes from coordinates "offset". + //! \details + //! \~russian + //! \brief Возвращает подвектор с размерами SubSize. Элементы берутся с координат "offset". + //! \details Координаты могут быть отрицательными. Возвращаемый подвектор может быть любого размера. Если исходные элементы выходят + //! за границы исходного подвектора, то в подвекторе будут нули. + template + PIMathVectorT subvector(int offset = 0) const { + PIMathVectorT ret; + for (int i = 0; i < (int)SubSize; ++i) { + int si = i + offset; + if (si < 0 || si >= (int)Size) continue; + ret[i] = element(si); + } + return ret; + } + + //! \~english + //! \brief Set the subvector "v" in coordinates "index". + //! \details + //! \~russian + //! \brief Устанавливает подвектор "v" в координаты "index". + //! \details Присваивает значения из вектора "v" в область текущиего вектора, ограниченную + //! размерами "v", самого вектор и границами, исходя из координат установки. Координаты могут быть отрицательными. + //! Вектор "v" может быть любого размера. Возвращает ссылку на этот вектор. + template + PIMathVectorT & setSubvector(int index, const PIMathVectorT & v) { + for (int i = 0; i < (int)SubSize; ++i) { + int si = i + index; + if (si < 0 || si >= (int)Size) continue; + element(si) = v[i]; + } + return *this; + } + static _CVector cross(const _CVector & v1, const _CVector & v2) { return v1.cross(v2); } static _CVector dot(const _CVector & v1, const _CVector & v2) { return v1.dot(v2); } static _CVector mul(const _CVector & v1, const _CVector & v2) { return v1.mul(v2); } diff --git a/libs/main/types/pidatetime.cpp b/libs/main/types/pidatetime.cpp index edcbe11b..879323b8 100644 --- a/libs/main/types/pidatetime.cpp +++ b/libs/main/types/pidatetime.cpp @@ -364,6 +364,11 @@ PIDateTime PIDateTime::fromString(PIString string, PIString format) { } +PISystemTime PIDateTime::toSystemTime() const { + return PISystemTime(piMaxi(0, int(toSecondSinceEpoch())), milliseconds * 1000000); +} + + PIDateTime PIDateTime::fromSecondSinceEpoch(const time_t sec) { tm * pt = localtime(&sec); PIDateTime dt; diff --git a/libs/main/types/pidatetime.h b/libs/main/types/pidatetime.h index 8e192104..72faf29c 100644 --- a/libs/main/types/pidatetime.h +++ b/libs/main/types/pidatetime.h @@ -256,7 +256,7 @@ public: //! \~english Returns time as %PISystemTime //! \~russian Возвращает время как %PISystemTime - PISystemTime toSystemTime() const { return PISystemTime(int(toSecondSinceEpoch()), milliseconds * 1000000); } + PISystemTime toSystemTime() const; //! \~english Returns date part //! \~russian Возвращает дату diff --git a/libs/main/types/pisystemtime.cpp b/libs/main/types/pisystemtime.cpp index f41a4e2c..abf8c258 100644 --- a/libs/main/types/pisystemtime.cpp +++ b/libs/main/types/pisystemtime.cpp @@ -20,6 +20,8 @@ #include "pisystemtime.h" #include "piincludes_p.h" +#include "piiostream.h" +#include "piliterals_time.h" #include "pitime.h" #include @@ -115,6 +117,41 @@ void PISystemTime::toTimespec(void * ts) { } +PIString PISystemTime::toString() const { + static const PISystemTime is_abs_thr = 3650._d; // 10 years + if ((*this) >= is_abs_thr) return PIDateTime::fromSystemTime((*this)).toString("yyyy-MM-dd hh:mm:ss.zzz"); + auto extract = [](int & secs, int part) { + int p = secs / part; + secs -= p * part; + return p; + }; + int s = seconds; + int d = extract(s, 60 * 60 * 24); + int h = extract(s, 60 * 60); + int m = extract(s, 60); + int ns = nanoseconds; + int ms = extract(ns, 1000000); + int us = extract(ns, 1000); + + PIString ret; + PIIOTextStream ts(&ret, PIIODevice::WriteOnly); + auto print = [&ts, &ret](int part, const char * name) { + if (part > 0) { + if (ret.isNotEmpty()) ts << ' '; + ts << part << ' ' << name; + } + }; + print(d, "d"); + print(h, "h"); + print(m, "m"); + print(s, "s"); + print(ms, "ms"); + print(us, "us"); + print(ns, "ns"); + return ret; +} + + PISystemTime PISystemTime::abs() const { if (seconds < 0) return PISystemTime(piAbsl(seconds) - 1, 1000000000l - piAbsl(nanoseconds)); @@ -123,6 +160,58 @@ PISystemTime PISystemTime::abs() const { } +PISystemTime PISystemTime::fromString(PIString s) { + if (s.findAny("-:") >= 0) { + return PIDateTime::fromString(s, "y-M-d h:m:s.z").toSystemTime(); + } + // clang-format off + static const PIMap times({ + {"d", 1_d}, {"day", 1_d}, {"days", 1_d}, + {"h", 1_h}, {"hour", 1_h}, {"hours", 1_h}, + {"m", 1_m}, {"min", 1_m}, {"mins", 1_m}, {"minute", 1_m}, {"minutes", 1_m}, + {"s", 1_s}, {"sec", 1_s}, {"secs", 1_s}, {"second", 1_s}, {"seconds", 1_s}, + {"ms", 1_ms}, {"msec", 1_ms}, {"msecs", 1_ms}, {"millisecond", 1_ms}, {"milliseconds", 1_ms}, {"milli", 1_ms}, {"millis", 1_ms}, + {"us", 1_us}, {"usec", 1_us}, {"usecs", 1_us}, {"microsecond", 1_us}, {"microseconds", 1_us}, {"micro", 1_us}, {"micros", 1_us}, + {"ns", 1_ns}, {"nsec", 1_ns}, {"nsecs", 1_ns}, {"nanosecond", 1_ns}, {"nanoseconds", 1_ns}, {"nano", 1_ns}, {"nanos", 1_ns} + }); + static const PIMap freqs({ + {"hz", 1_Hz}, + {"khz", 1_KHz}, + {"mhz", 1_MHz}, + {"ghz", 1_GHz} + }); + static const PIString num_syms = PIStringAscii("0123456789.eE+-"); + // clang-format on + s = s.toLowerCase(); + PISystemTime sum_t; + PISystemTime::Frequency sum_f; + auto extract = [&sum_t, &sum_f](PIString & str) { + PIString vn, pn; + str.trim(); + bool found = false; + for (int i = 0; i < str.size_s(); ++i) + if (!num_syms.contains(str[i])) { + vn = str.takeLeft(i); + found = true; + break; + } + if (!found) return false; + pn = str.takeWord(); + if (pn.isEmpty()) return false; + if (times.contains(pn)) + sum_t += times.value(pn) * vn.toDouble(); + else if (freqs.contains(pn)) + sum_f += freqs.value(pn) * vn.toDouble(); + return true; + }; + while (extract(s)) + ; + if (!sum_t.isNull() && !sum_f.isNull()) piCout << "[PISystemTime] fromString() warning: ambiguous string, time and frequency!"; + if (sum_t.isNull() && !sum_f.isNull()) sum_t = sum_f.toSystemTime(); + return sum_t; +} + + PISystemTime PISystemTime::current(bool precise_but_not_system) { #ifdef WINDOWS if (precise_but_not_system) { diff --git a/libs/main/types/pisystemtime.h b/libs/main/types/pisystemtime.h index 4f622e65..a427b2ef 100644 --- a/libs/main/types/pisystemtime.h +++ b/libs/main/types/pisystemtime.h @@ -67,6 +67,10 @@ public: //! \~russian Создает нулевую частоту Frequency() {} + //! \~english Returns if frequency is null + //! \~russian Возвращает нулевая ли частота + bool isNull() const { return value_hz == 0.; } + //! \~english Returns frequency as hertz //! \~russian Возвращает частоту в герцах double toHertz() const { return value_hz; } @@ -186,6 +190,10 @@ public: }; + //! \~english Returns if time is null + //! \~russian Возвращает нулевое ли время + bool isNull() const { return (seconds == 0) && (nanoseconds == 0); } + //! \~english Returns time value in seconds //! \~russian Возвращает значение времени в секундах double toSeconds() const { return double(seconds) + nanoseconds / 1.e+9; } @@ -240,6 +248,10 @@ public: //! \~russian На *nix системах присваивает время к timespec структуре void toTimespec(void * ts); + //! \~english Returns "yyyy-MM-dd hh:mm:ss.zzz" for absolute time and " ..." for relative + //! \~russian Возвращает "yyyy-MM-dd hh:mm:ss.zzz" для абсолютного времени и " ..." для относительного + PIString toString() const; + //! \~english Returns copy of this time with absolutely values of s and ns //! \~russian Возвращает копию времени с модулем значения PISystemTime abs() const; @@ -370,6 +382,10 @@ public: return PISystemTime(s, int((v / 1000000000. - s) * 1000000000.)); } + //! \~english Contructs time from string "s" ("yyyy-MM-dd hh:mm:ss.zzz" or free form) + //! \~russian Создает время из строки "s" ("yyyy-MM-dd hh:mm:ss.zzz", либо произвольная форма) + static PISystemTime fromString(PIString s); + //! \~english Returns current system time //! \~russian Возвращает текущее системное время static PISystemTime current(bool precise_but_not_system = false); diff --git a/libs/main/types/pivariant.cpp b/libs/main/types/pivariant.cpp index 667c5214..0130c82f 100644 --- a/libs/main/types/pivariant.cpp +++ b/libs/main/types/pivariant.cpp @@ -137,6 +137,9 @@ void PIVariant::setValueFromString(const PIString & v) { case PIVariant::pivDateTime: { setValue(PIDateTime::fromString(v)); } break; + case PIVariant::pivSystemTime: { + setValue(PISystemTime::fromString(v)); + } break; case PIVariant::pivString: { setValue(v); } break; @@ -1262,10 +1265,14 @@ PIDateTime PIVariant::toDateTime() const { //! \~\details //! \~english //! In case of SystemTime type returns system time. \n +//! In case of String type returns \a PISystemTime::fromString(). \n +//! In case of DateTime type returns \a PIDateTime::toSystemTime(). \n //! In case of other types returns \a PISystemTime::fromSeconds() from \a toDouble(). //! //! \~russian //! Для типа SystemTime возвращает системное время. \n +//! Для типа String возвращает \a PISystemTime::fromString(). \n +//! Для типа DateTime возвращает \a PIDateTime::toSystemTime(). \n //! Для остальных типов возвращает \a PISystemTime::fromSeconds() от \a toDouble(). //! PISystemTime PIVariant::toSystemTime() const { @@ -1275,6 +1282,16 @@ PISystemTime PIVariant::toSystemTime() const { ba >> r; return r; } + if (_type == PIVariant::pivString) { + PIString r; + ba >> r; + return PISystemTime::fromString(r); + } + if (_type == PIVariant::pivDateTime) { + PIDateTime r; + ba >> r; + return r.toSystemTime(); + } if (_type == PIVariant::pivCustom) { return getAsValue(*this); } @@ -1293,8 +1310,8 @@ PISystemTime PIVariant::toSystemTime() const { //! 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 -//! In case of NetworkAddress types returns "i.i.i.i:p" +//! In case of SystemTime types returns \a PISystemTime::toString(). \n +//! In case of NetworkAddress types returns "i.i.i.i:p". \n //! ("(PISystemTime::seconds s, PISystemTime::nanoseconds ns)"). \n //! In case of other types returns \b "". //! @@ -1304,8 +1321,8 @@ PISystemTime PIVariant::toSystemTime() const { //! Для типа StringList возвращает объединенную строку ("(" + PIStringList::join("; ") + ")"). \n //! Для типов BitArray или ByteArray возвращает количество бит/байт. \n //! Для типов Time, Date или DateTime возвращает toString(). \n -//! Для типов SystemTime возвращает секунды и наносекунды в формате "(s, ns)". -//! Для типов NetworkAddress возвращает "i.i.i.i:p" +//! Для типов SystemTime возвращает \a PISystemTime::toString(). \n +//! Для типов NetworkAddress возвращает "i.i.i.i:p". \n //! Для остальных типов возвращает \b "". //! PIString PIVariant::toString() const { @@ -1386,6 +1403,11 @@ PIString PIVariant::toString() const { ba >> r; return r.toString(); } + case PIVariant::pivSystemTime: { + PISystemTime r; + ba >> r; + return r.toString(); + } case PIVariant::pivString: { PIString r; ba >> r; diff --git a/libs/main/types/pivariant.h b/libs/main/types/pivariant.h index 55635283..dc22952a 100644 --- a/libs/main/types/pivariant.h +++ b/libs/main/types/pivariant.h @@ -999,6 +999,7 @@ 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 PISystemTime PIVariant::value() const {return toSystemTime();} template<> inline PIString PIVariant::value() const {return toString();} template<> inline PIStringList PIVariant::value() const {return toStringList();} template<> inline PIBitArray PIVariant::value() const {return toBitArray();}