From d3ec80805c5fa326e9c478ae4062ce13ed1072da Mon Sep 17 00:00:00 2001 From: Dirk Eddelbuettel Date: Mon, 17 Jun 2024 05:54:41 -0500 Subject: [PATCH] Refactor bitfield calculations for increased portability (#124) * nanoduration / nanoduration returns double instead of integer64 * incomplete solution for bitfield removal - NA is not yet handled correctly * handle neg numbers * remove '-mno-ms-bitfields' for Windows compilation * Additional polish for bitfield change * Roll micro version and date, update NEWS --------- Co-authored-by: lsilvest --- ChangeLog | 30 ++++++ DESCRIPTION | 13 +-- inst/NEWS.Rd | 2 + inst/include/nanotime/interval.hpp | 163 ++++++++++++++--------------- inst/include/nanotime/period.hpp | 4 +- man/nanoperiod.Rd | 2 +- src/Makevars | 2 + src/Makevars.ucrt | 3 - src/Makevars.win | 4 +- src/interval.cpp | 83 +++++++-------- src/period.cpp | 17 +-- 11 files changed, 162 insertions(+), 161 deletions(-) delete mode 100644 src/Makevars.ucrt diff --git a/ChangeLog b/ChangeLog index a60e749..7de0408 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,33 @@ +2024-06-16 Dirk Eddelbuettel + + * DESCRIPTION (Version, Date): Roll minor version and date + + * inst/include/nanotime/interval.hpp: Add extra braces + * src/interval.cpp: Updated output stream helper + * src/period.cpp: Idem + + * src/Makevars (CXX_STD): Set C++17 + * src/Makevars.win (CXX_STD): Idem + * src/Makevars.ucrt: Removed + +2024-06-14 Leonardo Silvestri + + * src/Makevars.win: Remove -mno-ms-bitfields + +2024-06-13 Leonardo Silvestri + + * inst/include/nanotime/interval.hpp: NA behavior for bitfield + +2024-06-11 Leonardo Silvestri + + * inst/include/nanotime/interval.hpp: Initial fix for bitfield + * inst/include/nanotime/period.hppL Idem + * src/interval.cpp: Idem + +2024-06-09 Dirk Eddelbuettel + + * README.md: Use tinyverse.netlify.app for dependency badge + 2024-05-24 Leonardo Silvestri * R/nanoduration.R: duration divided by duration returns double diff --git a/DESCRIPTION b/DESCRIPTION index f2002df..4316866 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,8 +1,8 @@ Package: nanotime Type: Package Title: Nanosecond-Resolution Time Support for R -Version: 0.3.7.5 -Date: 2024-04-28 +Version: 0.3.7.6 +Date: 2024-06-16 Author: Dirk Eddelbuettel and Leonardo Silvestri Maintainer: Dirk Eddelbuettel Description: Full 64-bit resolution date and time functionality with @@ -16,10 +16,7 @@ License: GPL (>= 2) URL: https://github.com/eddelbuettel/nanotime, https://eddelbuettel.github.io/nanotime/, https://dirk.eddelbuettel.com/code/nanotime.html BugReports: https://github.com/eddelbuettel/nanotime/issues RoxygenNote: 7.3.1 -Collate: - 'nanotime.R' - 'nanoival.R' - 'nanoduration.R' - 'nanoperiod.R' - 'RcppExports.R' +Collate: 'nanotime.R' 'nanoival.R' 'nanoduration.R' 'nanoperiod.R' 'RcppExports.R' Encoding: UTF-8 +NeedsCompilation: yes +Packaged: 2024-05-25 13:30:56 UTC; edd diff --git a/inst/NEWS.Rd b/inst/NEWS.Rd index 7b85f71..b2b2e95 100644 --- a/inst/NEWS.Rd +++ b/inst/NEWS.Rd @@ -17,6 +17,8 @@ API function \code{Rf_asS4} (Leonardo in \ghpr{121} closing \ghit{120}) \item An \code{nanoduration} / \code{nanoduration} expression now returns a double (Leonardo in \ghpr{122} closing \ghit{117}) + \item Bitfield calculations no longer require an Windows-only compiler + switch (Leonardo in \ghpr{124}) } } diff --git a/inst/include/nanotime/interval.hpp b/inst/include/nanotime/interval.hpp index badfe20..2d2c464 100644 --- a/inst/include/nanotime/interval.hpp +++ b/inst/include/nanotime/interval.hpp @@ -11,83 +11,76 @@ namespace nanotime { struct interval { -#ifdef WORDS_BIGENDIAN - constexpr interval() : s(0), sopen(0), e(0), eopen(0) { } -#else - constexpr interval() : sopen(0), s(0), eopen(0), e(0) { } -#endif + constexpr interval() : s_impl(0), e_impl(0) { } - interval(dtime s_p, dtime e_p, int sopen_p, int eopen_p) -#ifdef WORDS_BIGENDIAN - : s(s_p.time_since_epoch().count()), sopen(sopen_p), - e(e_p.time_since_epoch().count()), eopen(eopen_p) { -#else - : sopen(sopen_p), s(s_p.time_since_epoch().count()), - eopen(eopen_p), e(e_p.time_since_epoch().count()) { -#endif + interval(dtime s_p, dtime e_p, int sopen_p, int eopen_p) : + s_impl(s_p.time_since_epoch().count()), + e_impl(e_p.time_since_epoch().count()) + { + if (sopen_p) { + s_impl |= std::int64_t{1} << 63; + } + if (eopen_p) { + e_impl |= std::int64_t{1} << 63; + } + // if any of the constructor parameters is NA, we construct an NA interval: if (s_p.time_since_epoch() == duration::min() || e_p.time_since_epoch() == duration::min() || sopen_p == NA_INTEGER || eopen_p == NA_INTEGER) { - s = IVAL_NA; - e = IVAL_NA; + s_impl = IVAL_NA; + e_impl = IVAL_NA; } else { if (s_p.time_since_epoch().count() < IVAL_MIN || e_p.time_since_epoch().count() < IVAL_MIN) { - s = IVAL_NA; - e = IVAL_NA; + s_impl= IVAL_NA; + e_impl = IVAL_NA; Rf_warning("NAs produced by time overflow (remember that interval times are coded with 63 bits)"); } if (s_p.time_since_epoch().count() > IVAL_MAX || e_p.time_since_epoch().count() > IVAL_MAX) { - s = IVAL_NA; - e = IVAL_NA; + s_impl = IVAL_NA; + e_impl = IVAL_NA; Rf_warning("NAs produced by time overflow (remember that interval times are coded with 63 bits)"); } - if (s > e) { + if (e() < s()) { std::stringstream ss; - ss << "interval end (" << e << ") smaller than interval start (" << s << ")"; + ss << "interval end (" << e() << ") smaller than interval start (" << s() << ")"; throw std::range_error(ss.str()); } } } - // interval(std::int64_t s_p, std::int64_t e_p, bool sopen_p, bool eopen_p) - // : sopen(sopen_p), s(s_p), eopen(eopen_p), e(e_p) { - // if (s > e) { - // std::stringstream ss; - // ss << "interval end (" << e << ") smaller than interval start (" << s << ")"; - // throw std::range_error(ss.str()); - // } - // } + dtime getStart() const { return dtime(duration(s())); } + dtime getEnd() const { return dtime(duration(e())); } - dtime getStart() const { return dtime(duration(s)); } - dtime getEnd() const { return dtime(duration(e)); } - bool isNA() const { return s == IVAL_NA; } - -#ifdef WORDS_BIGENDIAN - std::int64_t s : 63; - bool sopen : 1; // encode if the interval's start boundary is open (true) or closed (false) - std::int64_t e : 63; - bool eopen : 1; // encode if the interval's end boundary is open (true) or closed (false) -#else - bool sopen : 1; // encode if the interval's start boundary is open (true) or closed (false) - std::int64_t s : 63; - bool eopen : 1; // encode if the interval's end boundary is open (true) or closed (false) - std::int64_t e : 63; -#endif + // below we do some bit gynmastic to use the uppermost bit to store whether the + // interval is opened or closed; bitfields would give us all that for free, + // but we can't rely upon them because of Windows: + bool sopen() const { return (s_impl & (std::int64_t{1} << 63)) != 0; } + bool eopen() const { return (e_impl & (std::int64_t{1} << 63)) != 0; } + static const std::int64_t bit64_compl = ~(std::int64_t{1} << 63); + static const std::int64_t bit63 = std::int64_t{1} << 62; + std::int64_t s() const { return s_impl & (bit64_compl | ((bit63 & s_impl) << 1)); } + std::int64_t e() const { return e_impl & (bit64_compl | ((bit63 & e_impl) << 1)); } + bool isNA() const { return s_impl == IVAL_NA; } + static const std::int64_t IVAL_MAX = 4611686018427387903LL; static const std::int64_t IVAL_MIN = -4611686018427387903LL; - static const std::int64_t IVAL_NA = -4611686018427387904LL; + static const std::int64_t IVAL_NA = -9223372036854775807LL; + + private: + std::int64_t s_impl; // start of ival; last bit encodes if boundary is open (1) or closed (0) + std::int64_t e_impl; // end of ival; last bit encodes if boundary is open (1) or closed (0) }; // operators: inline duration operator-(const interval& i1, const interval& i2) { - return duration(i1.s - i2.s); + return duration(i1.s() - i2.s()); } inline bool operator==(const interval& i1, const interval& i2) { - return i1.s == i2.s && i1.e == i2.e && i1.sopen == i2.sopen && - i1.eopen == i2.eopen; + return i1.s() == i2.s() && i1.e() == i2.e() && i1.sopen() == i2.sopen() && + i1.eopen() == i2.eopen(); } inline bool operator!=(const interval& i1, const interval& i2) { @@ -95,30 +88,30 @@ namespace nanotime { } inline bool operator<=(const interval& i1, const interval& i2) { - if (i1.s < i2.s) return true; - if (i1.s == i2.s) { - if (!i1.sopen && i2.sopen) return true; - if (i1.sopen && !i2.sopen) return false; - // here we know that s1.sopen == s2.sopen - if (i1.e < i2.e) return true; - if (i1.e == i2.e) { - if (i1.eopen == i2.eopen) return true; - if (i1.eopen && !i2.eopen) return true; + if (i1.s() < i2.s()) return true; + if (i1.s() == i2.s()) { + if (!i1.sopen() && i2.sopen()) return true; + if (i1.sopen() && !i2.sopen()) return false; + // here we know that s1.sopen() == s2.sopen() + if (i1.e() < i2.e()) return true; + if (i1.e() == i2.e()) { + if (i1.eopen() == i2.eopen()) return true; + if (i1.eopen() && !i2.eopen()) return true; } } return false; } inline bool operator<(const interval& i1, const interval& i2) { - if (i1.s < i2.s) return true; - if (i1.s == i2.s) { - if (!i1.sopen && i2.sopen) return true; - if (i1.sopen && !i2.sopen) return false; - // here we know that s1.sopen == s2.sopen - if (i1.e < i2.e) return true; - if (i1.e == i2.e) { - if (i1.eopen == i2.eopen) return false; - if (i1.eopen && !i2.eopen) return true; + if (i1.s() < i2.s()) return true; + if (i1.s() == i2.s()) { + if (!i1.sopen() && i2.sopen()) return true; + if (i1.sopen() && !i2.sopen()) return false; + // here we know that s1.sopen() == s2.sopen() + if (i1.e() < i2.e()) return true; + if (i1.e() == i2.e()) { + if (i1.eopen() == i2.eopen()) return false; + if (i1.eopen() && !i2.eopen()) return true; } } return false; @@ -133,30 +126,30 @@ namespace nanotime { } inline bool operator<(const dtime& i1, const interval& i2) { - if (i1.time_since_epoch().count() < i2.s) return true; - if (i1.time_since_epoch().count() == i2.s) return i2.sopen; + if (i1.time_since_epoch().count() < i2.s()) return true; + if (i1.time_since_epoch().count() == i2.s()) return i2.sopen(); return false; } inline bool operator>(const dtime& i1, const interval& i2) { - if (i1.time_since_epoch().count() > i2.e) return true; - if (i1.time_since_epoch().count() == i2.e) return i2.eopen; + if (i1.time_since_epoch().count() > i2.e()) return true; + if (i1.time_since_epoch().count() == i2.e()) return i2.eopen(); return false; } inline interval operator+(const interval& i, const duration d) { // test duration is not > 63-bits, and after that the constructor can test for overflow: - return interval(i.getStart() + d, i.getEnd() + d, i.sopen, i.eopen); + return interval(i.getStart() + d, i.getEnd() + d, i.sopen(), i.eopen()); } inline interval operator-(const interval& i, const duration d) { // test duration is not > 63-bits, and after that the constructor can test for underflow: - return interval(i.getStart() - d, i.getEnd() - d, i.sopen, i.eopen); + return interval(i.getStart() - d, i.getEnd() - d, i.sopen(), i.eopen()); } inline interval operator+(const duration d, const interval& i) { // test duration is not > 63-bits, and after that the constructor can test for overflow: - return interval(i.getStart() + d, i.getEnd() + d, i.sopen, i.eopen); + return interval(i.getStart() + d, i.getEnd() + d, i.sopen(), i.eopen()); } // interval components comparators: @@ -195,10 +188,10 @@ namespace nanotime { // interval comparators: inline bool start_lt(const interval& i1, const interval& i2) { - return start_lt(i1.getStart(), i1.sopen, i2.getStart(), i2.sopen); + return start_lt(i1.getStart(), i1.sopen(), i2.getStart(), i2.sopen()); } inline bool start_gt(const interval& i1, const interval& i2) { - return start_gt(i1.getStart(), i1.sopen, i2.getStart(), i2.sopen); + return start_gt(i1.getStart(), i1.sopen(), i2.getStart(), i2.sopen()); } inline bool start_le(const interval& i1, const interval& i2) { return !start_gt(i1,i2); @@ -207,10 +200,10 @@ namespace nanotime { return !start_lt(i1,i2); } inline bool end_lt(const interval& i1, const interval& i2) { - return end_lt(i1.getEnd(), i1.eopen, i2.getEnd(), i2.eopen); + return end_lt(i1.getEnd(), i1.eopen(), i2.getEnd(), i2.eopen()); } inline bool end_gt(const interval& i1, const interval& i2) { - return end_gt(i1.getEnd(), i1.eopen, i2.getEnd(), i2.eopen); + return end_gt(i1.getEnd(), i1.eopen(), i2.getEnd(), i2.eopen()); } inline bool end_le(const interval& i1, const interval& i2) { return !end_gt(i1,i2); @@ -222,10 +215,10 @@ namespace nanotime { /// True if the end of 'i1' is smaller than the start of 'i2'. This /// tests that 'i1' and 'i2' are disjoint and 'i2' is after 'i1'. inline bool end_lt_start(const interval& i1, const interval& i2) { - return end_lt(i1.getEnd(), i1.eopen, i2.getStart(), i2.sopen); + return end_lt(i1.getEnd(), i1.eopen(), i2.getStart(), i2.sopen()); } inline bool end_gt_start(const interval& i1, const interval& i2) { - return end_gt(i1.getEnd(), i1.eopen, i2.getStart(), i2.sopen); + return end_gt(i1.getEnd(), i1.eopen(), i2.getStart(), i2.sopen()); } /// True if the end of 'i1' is greater or equal than the start of /// 'i2'. This tests that 'i1' and 'i2' "touch" and that 'i2' is @@ -277,10 +270,10 @@ namespace nanotime { // interval comparators: inline bool union_start_lt(const interval& i1, const interval& i2) { - return union_start_lt(i1.getStart(), i1.sopen, i2.getStart(), i2.sopen); + return union_start_lt(i1.getStart(), i1.sopen(), i2.getStart(), i2.sopen()); } inline bool union_start_gt(const interval& i1, const interval& i2) { - return union_start_gt(i1.getStart(), i1.sopen, i2.getStart(), i2.sopen); + return union_start_gt(i1.getStart(), i1.sopen(), i2.getStart(), i2.sopen()); } inline bool union_start_le(const interval& i1, const interval& i2) { return !union_start_gt(i1,i2); @@ -289,10 +282,10 @@ namespace nanotime { return !union_start_lt(i1,i2); } inline bool union_end_lt(const interval& i1, const interval& i2) { - return union_end_lt(i1.getEnd(), i1.eopen, i2.getEnd(), i2.eopen); + return union_end_lt(i1.getEnd(), i1.eopen(), i2.getEnd(), i2.eopen()); } inline bool union_end_gt(const interval& i1, const interval& i2) { - return union_end_gt(i1.getEnd(), i1.eopen, i2.getEnd(), i2.eopen); + return union_end_gt(i1.getEnd(), i1.eopen(), i2.getEnd(), i2.eopen()); } inline bool union_end_le(const interval& i1, const interval& i2) { return !union_end_gt(i1,i2); @@ -304,10 +297,10 @@ namespace nanotime { /// True if the end of 'i1' is smaller than the start of 'i2'. This /// tests that 'i1' and 'i2' are disjoint and 'i2' is after 'i1'. inline bool union_end_lt_start(const interval& i1, const interval& i2) { - return union_end_lt(i1.getEnd(), i1.eopen, i2.getStart(), i2.sopen); + return union_end_lt(i1.getEnd(), i1.eopen(), i2.getStart(), i2.sopen()); } inline bool union_end_gt_start(const interval& i1, const interval& i2) { - return union_end_gt(i1.getEnd(), i1.eopen, i2.getStart(), i2.sopen); + return union_end_gt(i1.getEnd(), i1.eopen(), i2.getStart(), i2.sopen()); } /// True if the end of 'i1' is greater or equal than the start of /// 'i2'. This tests that 'i1' and 'i2' "touch" and that 'i2' is diff --git a/inst/include/nanotime/period.hpp b/inst/include/nanotime/period.hpp index 69f7e39..b6ad14d 100644 --- a/inst/include/nanotime/period.hpp +++ b/inst/include/nanotime/period.hpp @@ -125,8 +125,8 @@ namespace nanotime { inline interval plus (const interval& i, const period& p, const std::string& z) { - return interval(plus(dtime{duration{i.s}}, p, z), - plus(dtime{duration{i.e}}, p, z), i.sopen, i.eopen); + return interval(plus(dtime{duration{i.s()}}, p, z), + plus(dtime{duration{i.e()}}, p, z), i.sopen(), i.eopen()); } inline interval plus (const period& p, const interval& i, const std::string& z) { return plus(i, p, z); diff --git a/man/nanoperiod.Rd b/man/nanoperiod.Rd index 3831037..83900ba 100644 --- a/man/nanoperiod.Rd +++ b/man/nanoperiod.Rd @@ -265,7 +265,7 @@ like this: \code{10m2d/10:12:34.123_453_000}. Adding or subtracting \code{nanoperiod} and \code{nanotime} require a timezone as third argument. For this reason it is not -possible to use the binary operator `\code{+}`. Instead thea +possible to use the binary operator `\code{+}`. Instead the functions `\code{plus}` and `\code{minus}` are defined. These functions attempt to keep the same offset within a day in the specified timezone: this means for instance that adding a day when diff --git a/src/Makevars b/src/Makevars index 49b2112..5765680 100644 --- a/src/Makevars +++ b/src/Makevars @@ -1,3 +1,5 @@ +## Compile as C++17 +CXX_STD = CXX17 ## We need headers from our package, the directory is not automatically included PKG_CXXFLAGS = -I../inst/include diff --git a/src/Makevars.ucrt b/src/Makevars.ucrt deleted file mode 100644 index 6322870..0000000 --- a/src/Makevars.ucrt +++ /dev/null @@ -1,3 +0,0 @@ - -## We need headers from our package, the directory is not automatically included -PKG_CXXFLAGS = -I../inst/include -mno-ms-bitfields -D_POSIX_THREAD_SAFE_FUNCTIONS diff --git a/src/Makevars.win b/src/Makevars.win index f449af1..5765680 100644 --- a/src/Makevars.win +++ b/src/Makevars.win @@ -1,3 +1,5 @@ +## Compile as C++17 +CXX_STD = CXX17 ## We need headers from our package, the directory is not automatically included -PKG_CXXFLAGS = -I../inst/include -mno-ms-bitfields +PKG_CXXFLAGS = -I../inst/include diff --git a/src/interval.cpp b/src/interval.cpp index 8027268..be2f5c2 100644 --- a/src/interval.cpp +++ b/src/interval.cpp @@ -37,28 +37,17 @@ typedef ConstPseudoVector Con // for debug reasons... -// the following code from: https://stackoverflow.com/a/16692519 +// cf https://stackoverflow.com/a/16692519 template std::ostream &operator<<(std::ostream &stream, const std::chrono::time_point &time_point) { - const time_t time = Clock::to_time_t(time_point); -#if __GNUC__ > 4 || \ - ((__GNUC__ == 4) && __GNUC_MINOR__ > 8 && __GNUC_REVISION__ > 1) - // Maybe the put_time will be implemented later? - struct tm tm; - localtime_r(&time, &tm); - return stream << std::put_time(&tm, "%c"); // Print standard date&time -#else - char buffer[26]; - ctime_r(&time, buffer); - buffer[24] = '\0'; // Removes the newline that is added - return stream << buffer; -#endif + // updated with https://stackoverflow.com/a/71442312/23224962 and using C++17 + return stream << std::chrono::duration_cast(time_point.time_since_epoch()).count(); } #if 0 static void print(const interval& i) { - Rcpp::Rcout << (i.sopen ? "-" : "+") << i.s << "->" << i.e << (i.eopen ? "-" : "+") << std::endl; + Rcpp::Rcout << (i.sopen() ? "-" : "+") << i.s() << "->" << i.e() << (i.eopen() ? "-" : "+") << std::endl; } #endif @@ -229,7 +218,7 @@ Rcpp::ComplexVector nanoival_union_impl(const Rcpp::ComplexVector nv1, if (nv1.size() > 0 && nv2.size() > 0) { auto v1_lt_v2 = start_lt(v1[i1], v2[i2]); auto start = v1_lt_v2 ? v1[i1].getStart() : v2[i2].getStart(); - auto sopen = v1_lt_v2 ? v1[i1].sopen : v2[i2].sopen; + auto sopen = v1_lt_v2 ? v1[i1].sopen() : v2[i2].sopen(); for (;;) { if (union_end_ge_start(v1[i1], v2[i2]) && union_end_le(v1[i1], v2[i2])) { @@ -237,7 +226,7 @@ Rcpp::ComplexVector nanoival_union_impl(const Rcpp::ComplexVector nv1, // v2 |------------| |------------| if (i1 >= nv1.size() - 1) { // if equal ends, have to do the union of the eopens: - auto eopen = union_end_le(v2[i2], v1[i1]) ? v1[i1].eopen && v2[i2].eopen : v2[i2].eopen; + auto eopen = union_end_le(v2[i2], v1[i1]) ? v1[i1].eopen() && v2[i2].eopen() : v2[i2].eopen(); // v2 interval done, as there's no more v1 elts to overlap res.push_back(interval(start, v2[i2].getEnd(), sopen, eopen)); ++i1; ++i2; @@ -249,7 +238,7 @@ Rcpp::ComplexVector nanoival_union_impl(const Rcpp::ComplexVector nv1, // v2 |------------| |--------| if (i2 >= nv2.size() - 1) { // if equal ends, have to do the union of the eopens: - auto eopen = union_end_le(v1[i1], v2[i2]) ? v1[i1].eopen && v2[i2].eopen : v1[i1].eopen; + auto eopen = union_end_le(v1[i1], v2[i2]) ? v1[i1].eopen() && v2[i2].eopen() : v1[i1].eopen(); // v1 interval done, as there's no more v2 elts to overlap res.push_back(interval(start, v1[i1].getEnd(), sopen, eopen)); ++i1; ++i2; @@ -257,24 +246,24 @@ Rcpp::ComplexVector nanoival_union_impl(const Rcpp::ComplexVector nv1, } ++i2; } else { - if (v1[i1].getEnd() == v2[i2].getEnd() && v1[i1].eopen && v2[i2].eopen) { + if (v1[i1].getEnd() == v2[i2].getEnd() && v1[i1].eopen() && v2[i2].eopen()) { // special case where the intervals are ends are equal and open: - res.push_back(interval(start, v1[i1].getEnd(), sopen, v1[i1].eopen)); + res.push_back(interval(start, v1[i1].getEnd(), sopen, v1[i1].eopen())); ++i1; ++i2; } else if (union_end_lt(v1[i1], v2[i2])) { // no interval overlap - res.push_back(interval(start, v1[i1].getEnd(), sopen, v1[i1].eopen)); + res.push_back(interval(start, v1[i1].getEnd(), sopen, v1[i1].eopen())); ++i1; } else { // no interval overlap - res.push_back(interval(start, v2[i2].getEnd(), sopen, v2[i2].eopen)); + res.push_back(interval(start, v2[i2].getEnd(), sopen, v2[i2].eopen())); ++i2; } // set the start of the next interval: if (i1 < nv1.size() && i2 < nv2.size()) { auto v1_lt_v2 = start_lt(v1[i1], v2[i2]); start = v1_lt_v2 ? v1[i1].getStart() : v2[i2].getStart(); - sopen = v1_lt_v2 ? v1[i1].sopen : v2[i2].sopen; + sopen = v1_lt_v2 ? v1[i1].sopen() : v2[i2].sopen(); } else { break; } @@ -305,22 +294,22 @@ Rcpp::ComplexVector nanoival_intersect_impl(const Rcpp::ComplexVector nv1, R_xlen_t i1 = 0, i2 = 0; while (i1 < nv1.size() && i2 < nv2.size()) { - if (v1[i1].getEnd() < v2[i2].getStart() || (v1[i1].getEnd() == v2[i2].getStart() && (v1[i1].eopen || v2[i2].sopen))) { + if (v1[i1].getEnd() < v2[i2].getStart() || (v1[i1].getEnd() == v2[i2].getStart() && (v1[i1].eopen() || v2[i2].sopen()))) { ++i1; continue; - } else if (v2[i2].getEnd() < v1[i1].getStart() || (v2[i2].getEnd() == v1[i1].getStart() && (v1[i1].sopen || v2[i2].eopen))) { + } else if (v2[i2].getEnd() < v1[i1].getStart() || (v2[i2].getEnd() == v1[i1].getStart() && (v1[i1].sopen() || v2[i2].eopen()))) { ++i2; continue; } else { auto v1_gt_v2 = start_gt(v1[i1], v2[i2]); auto start = v1_gt_v2 ? v1[i1].getStart() : v2[i2].getStart(); - auto sopen = v1_gt_v2 ? v1[i1].sopen : v2[i2].sopen; + auto sopen = v1_gt_v2 ? v1[i1].sopen() : v2[i2].sopen(); if (end_lt(v1[i1], v2[i2])) { - res.push_back(interval(start, v1[i1].getEnd(), sopen, v1[i1].eopen)); + res.push_back(interval(start, v1[i1].getEnd(), sopen, v1[i1].eopen())); ++i1; } else { - res.push_back(interval(start, v2[i2].getEnd(), sopen, v2[i2].eopen)); + res.push_back(interval(start, v2[i2].getEnd(), sopen, v2[i2].eopen())); ++i2; } } @@ -342,55 +331,55 @@ Rcpp::ComplexVector nanoival_setdiff_impl(const Rcpp::ComplexVector nv1, R_xlen_t i1 = 0, i2 = 0; auto start = v1[i1].getStart(); - auto sopen = v1[i1].sopen; + auto sopen = v1[i1].sopen(); while (i1 < nv1.size() && i2 < nv2.size()) { if (end_lt_start(v1[i1], v2[i2])) { // |-------------| // |------------| - res.push_back(interval(start, v1[i1].getEnd(), sopen, v1[i1].eopen)); + res.push_back(interval(start, v1[i1].getEnd(), sopen, v1[i1].eopen())); if (++i1 >= nv1.size()) break; start = v1[i1].getStart(); - sopen = v1[i1].sopen; - } else if (start_lt(v2[i2].getEnd(), v2[i2].eopen, start, sopen)) { + sopen = v1[i1].sopen(); + } else if (start_lt(v2[i2].getEnd(), v2[i2].eopen(), start, sopen)) { // |------------| // |-------------| ++i2; - } else if (start_lt(start, sopen, v2[i2].getStart(), v2[i2].sopen)) { + } else if (start_lt(start, sopen, v2[i2].getStart(), v2[i2].sopen())) { // |-------------| or |-------------| // |------------| |-------| - res.push_back(interval(start, v2[i2].getStart(), sopen, !v2[i2].sopen)); + res.push_back(interval(start, v2[i2].getStart(), sopen, !v2[i2].sopen())); if (end_gt(v1[i1], v2[i2])) { // |-------------| // |-------| start = v2[i2].getEnd(); - sopen = !v2[i2].eopen; + sopen = !v2[i2].eopen(); ++i2; } else { // |-------------| // |------------| if (++i1 >= nv1.size()) break; start = v1[i1].getStart(); - sopen = v1[i1].sopen; + sopen = v1[i1].sopen(); } - } else if (start_ge(start, sopen, v2[i2].getStart(), v2[i2].sopen) && + } else if (start_ge(start, sopen, v2[i2].getStart(), v2[i2].sopen()) && end_ge(v2[i2], v1[i1])) { // |-------| // |-------------| if (++i1 >= nv1.size()) break; start = v1[i1].getStart(); - sopen = v1[i1].sopen; + sopen = v1[i1].sopen(); } else { // |------------| // |----------| start = v2[i2].getEnd(); - sopen = !v2[i2].eopen; + sopen = !v2[i2].eopen(); ++i2; } } // remaining non-overlapping intervals in v1: if (i1 < nv1.size()) { - res.push_back(interval(start, v1[i1].getEnd(), sopen, v1[i1].eopen)); + res.push_back(interval(start, v1[i1].getEnd(), sopen, v1[i1].eopen())); ++i1; while (i1 < nv1.size()) { res.push_back(v1[i1++]); @@ -592,7 +581,7 @@ static Rcpp::NumericVector setdiff_idx(const T* v1, size_t v1_size, const U* v2, Rcpp::NumericVector nanoival_setdiff_idx_time_interval_impl(const Rcpp::NumericVector nv1, const Rcpp::ComplexVector cv2) { const dtime* v1 = reinterpret_cast(&nv1[0]); - const interval* v2 = reinterpret_cast(&cv2[0]); + const interval* v2 = reinterpret_cast(&cv2[0]); return setdiff_idx(v1, nv1.size(), v2, cv2.size()); } @@ -638,7 +627,7 @@ Rcpp::NumericVector nanoival_get_start_impl(const Rcpp::ComplexVector cv) { res[i] = d; } else { - std::int64_t start = ival.s; + std::int64_t start = ival.s(); double d; memcpy(&d, reinterpret_cast(&start), sizeof(start)); res[i] = d; @@ -663,7 +652,7 @@ Rcpp::NumericVector nanoival_get_end_impl(const Rcpp::ComplexVector cv) { res[i] = d; } else { - std::int64_t end = ival.e; + std::int64_t end = ival.e(); double d; memcpy(&d, reinterpret_cast(&end), sizeof(end)); res[i] = d; @@ -686,7 +675,7 @@ Rcpp::LogicalVector nanoival_get_sopen_impl(const Rcpp::ComplexVector cv) { res[i] = NA_LOGICAL; } else { - res[i] = ival.sopen; + res[i] = ival.sopen(); } } res.names() = cv.names(); @@ -705,7 +694,7 @@ Rcpp::LogicalVector nanoival_get_eopen_impl(const Rcpp::ComplexVector cv) { res[i] = NA_LOGICAL; } else { - res[i] = ival.eopen; + res[i] = ival.eopen(); } } res.names() = cv.names(); @@ -809,10 +798,10 @@ Rcpp::ComplexVector nanoival_make_impl(const Rcpp::CharacterVector nt_v, } -static Rcomplex getNA_ival() { +Rcomplex getNA_ival() { static const auto p = interval(dtime(duration::min()), dtime(duration::min()), // #nocov (seems like the cov tool fails us here!) - true, true); + NA_INTEGER, NA_INTEGER); Rcomplex c; memcpy(&c, &p, sizeof(p)); return c; diff --git a/src/period.cpp b/src/period.cpp index fb79058..7865173 100644 --- a/src/period.cpp +++ b/src/period.cpp @@ -13,23 +13,12 @@ using namespace nanotime; // for debug reasons... -// the following code from: https://stackoverflow.com/a/16692519 +// cf https://stackoverflow.com/a/16692519 template std::ostream &operator<<(std::ostream &stream, const std::chrono::time_point &time_point) { - const time_t time = Clock::to_time_t(time_point); -#if __GNUC__ > 4 || \ - ((__GNUC__ == 4) && __GNUC_MINOR__ > 8 && __GNUC_REVISION__ > 1) - // Maybe the put_time will be implemented later? - struct tm tm; - localtime_r(&time, &tm); - return stream << std::put_time(&tm, "%c"); // Print standard date&time -#else - char buffer[26]; - ctime_r(&time, buffer); - buffer[24] = '\0'; // Removes the newline that is added - return stream << buffer; -#endif + // updated with https://stackoverflow.com/a/71442312/23224962 and using C++17 + return stream << std::chrono::duration_cast(time_point.time_since_epoch()).count(); }