Commit c7727f10 authored by Cédric Traizet's avatar Cédric Traizet
Browse files

PERF: use std::chrono and Howard Hinnant's date library instead of boost date...

PERF: use std::chrono and Howard Hinnant's date library instead of boost date time to manage time in OTB
parent 8ea7df65
Pipeline #9093 failed with stages
in 19 minutes and 57 seconds
......@@ -23,12 +23,9 @@
#include "OTBMetadataExport.h"
// Use nanosecond precision in boost dates and durations
#define BOOST_DATE_TIME_POSIX_TIME_STD_CONFIG
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/config.hpp>
#include <cmath>
#include <boost/operators.hpp>
#include <chrono>
namespace otb
{
......@@ -37,6 +34,17 @@ namespace MetaData
namespace details
{
using InternalDurationType = std::chrono::nanoseconds;
using InternalTimePointType = std::chrono::time_point<std::chrono::system_clock, InternalDurationType>;
// the number of second's fractions per tick of InternalDurationType
constexpr double internalPeriod = static_cast<double>(InternalDurationType::period::num) / InternalDurationType::period::den;
// Standard format used when parsing dates
const std::string timePointFormat = "%Y-%m-%dT%H:%M:%S";
// Add some operators not defined in boost
// division by a scalar and ratio
template <typename T, typename R> struct dividable
{
......@@ -48,11 +56,10 @@ template <typename T, typename R> struct dividable
}
friend scalar_type operator/(T const& lhs, T const& rhs)
{
return ratio_(lhs, rhs);
return Ratio(lhs, rhs);
}
};
template <typename U, typename V> struct substractable_asym
{
friend U operator-(V const& lhs, V const& rhs)
......@@ -74,19 +81,28 @@ template <typename T> struct streamable
};
} // namespace details
class Duration;
/** \class TimePoint
*
* \brief Represents a point in Time
*
* \ingroup OTBMetadata
*/
class OTBMetadata_EXPORT TimePoint : private details::streamable<TimePoint>,
private details::substractable_asym<Duration, TimePoint>,
private boost::equality_comparable<TimePoint>,
private boost::less_than_comparable<TimePoint>
{
public:
//friend class Duration;
TimePoint() = default;
using InternalTimePointType = details::InternalTimePointType;
std::ostream & Display(std::ostream & os) const { return os << m_Time; }
std::istream & Read (std::istream & is) { return is >> m_Time; }
TimePoint(): m_Time(InternalTimePointType::min()) {}
TimePoint(InternalTimePointType const& t): m_Time(t) {}
std::ostream & Display(std::ostream & os, const std::string & format = details::timePointFormat) const;
std::istream & Read (std::istream & is, const std::string & format = details::timePointFormat);
template <typename U, typename V> static U diff(V const& lhs, V const& rhs)
{
......@@ -104,15 +120,20 @@ public:
return lhs.m_Time == rhs.m_Time;
}
friend TimePoint& operator+=(TimePoint & u, Duration const& v);
friend TimePoint& operator-=(TimePoint & u, Duration const& v);
public:
boost::posix_time::ptime m_Time;
};
using TimeType = TimePoint;
private:
InternalTimePointType m_Time;
double ratio_(Duration const& lhs, Duration const& rhs);
};
/** \class Duration
*
* \brief Represents a duration
*
* \ingroup OTBMetadata
*/
class OTBMetadata_EXPORT Duration : private details::streamable<Duration>,
private boost::addable<Duration>,
private boost::subtractable<Duration>,
......@@ -120,38 +141,39 @@ class OTBMetadata_EXPORT Duration : private details::streamable<Duration>,
private details::dividable<Duration, double>,
private boost::equality_comparable<Duration>,
private boost::less_than_comparable<Duration>,
private boost::addable<TimeType, Duration>,
private boost::subtractable<TimeType, Duration>
private boost::addable<TimePoint, Duration>,
private boost::subtractable<TimePoint, Duration>
{
public:
using InternalDurationType = boost::posix_time::time_duration;
using InternalDurationType = details::InternalDurationType;
Duration() = default;
Duration(InternalDurationType const& d): m_Duration(d) {}
static Duration Seconds(double d)
static Duration Seconds(double s)
{
return Duration(boost::posix_time::nanoseconds(static_cast<long long>(std::round(d * 1e9))));
return Duration(InternalDurationType(static_cast<InternalDurationType::rep>(std::round(s / details::internalPeriod))));
}
static Duration Nanoseconds(double d)
static Duration Miliseconds(double ms)
{
return Duration(boost::posix_time::nanoseconds(static_cast<long long>(std::round(d))));
return Duration(InternalDurationType(static_cast<InternalDurationType::rep>(std::round(ms / details::internalPeriod * 1e-3))));
}
Duration(double d): m_Duration(boost::posix_time::nanoseconds(static_cast<long long>(std::round(d)))) {}
double TotalNanoseconds() const
static Duration Microseconds(double us)
{
return m_Duration.total_nanoseconds();
return Duration(InternalDurationType(static_cast<InternalDurationType::rep>(std::round(us / details::internalPeriod * 1e-6))));
}
double TotalSeconds() const
static Duration Nanoseconds(double ns)
{
return m_Duration.total_nanoseconds() * 1e-9;
return Duration(InternalDurationType(static_cast<InternalDurationType::rep>(std::round(ns / details::internalPeriod * 1e-9))));
}
double TotalSeconds() const;
InternalDurationType::rep NumberOfTicks() const;
friend Duration& operator+=(Duration & u, Duration const& v)
{
u.m_Duration += v.m_Duration;
......@@ -166,16 +188,15 @@ public:
friend Duration& operator*=(Duration & u, double v)
{
u.m_Duration = boost::posix_time::nanoseconds(static_cast<long long>(std::round(
u.m_Duration.total_nanoseconds() * v)));
// note: don't use std::chrono::duration::operator* cause it multiplies the input by an integer value.
u.m_Duration = InternalDurationType(static_cast<InternalDurationType::rep>(std::round(u.m_Duration.count() * v)));
return u;
}
friend Duration& operator/=(Duration & u, double v)
{
u.m_Duration = boost::posix_time::nanoseconds(static_cast<long long>(std::round(
u.m_Duration.total_nanoseconds() / v)));
// note: don't use std::chrono::duration::operator/ cause it divides the input by an integer value.
u.m_Duration = InternalDurationType(static_cast<InternalDurationType::rep>(std::round(u.m_Duration.count() / v)));
return u;
}
......@@ -189,39 +210,37 @@ public:
return lhs.m_Duration == rhs.m_Duration;
}
friend TimeType& operator+=(TimeType & u, Duration const& v)
friend TimePoint& operator+=(TimePoint & u, Duration const& v)
{
u.m_Time += v.m_Duration;
return u;
}
friend TimeType& operator-=(TimeType & u, Duration const& v)
friend TimePoint& operator-=(TimePoint & u, Duration const& v)
{
u.m_Time -= v.m_Duration;
return u;
}
std::ostream & Display(std::ostream & os) const { return os << m_Duration; }
std::istream & Read (std::istream & is) { return is >> m_Duration; }
std::ostream & Display(std::ostream & os) const;
std::istream & Read (std::istream & is);
OTBMetadata_EXPORT friend Duration Abs(Duration d);
friend Duration Abs(Duration d);
private:
InternalDurationType m_Duration;
};
OTBMetadata_EXPORT Duration Abs(Duration d);
OTBMetadata_EXPORT double Ratio(const Duration & lhs, const Duration & rhs);
OTBMetadata_EXPORT TimePoint ReadFormattedDate(const std::string & dateStr, const std::string & format = details::timePointFormat);
// TODO: remove these typedefs and methods to make the API cleaner. There are defined here to ease the integration of this version of otbDateTime
using TimeType = TimePoint;
using DurationType = Duration;
OTBMetadata_EXPORT DurationType seconds(double);
OTBMetadata_EXPORT TimeType ReadFormattedDate(const std::string & dateStr, const std::string & format = "%Y-%m-%dT%H:%M:%S%F");
}
}
} // namespace otb
} // namespace MetaData
#endif
#endif // otbDateTime_h
......@@ -31,6 +31,7 @@ ENABLE_SHARED
OTBCommon
OTBGdalAdapters
OTBTinyXML
OTBDate
TEST_DEPENDS
OTBTestKernel
......
......@@ -19,41 +19,72 @@
*/
#include "otbDateTime.h"
#include "otbStringUtilities.h"
#include "date.h"
namespace otb
{
namespace MetaData
{
double ratio_(Duration const& lhs, Duration const& rhs)
TimePoint ReadFormattedDate(const std::string & dateStr, const std::string & format)
{
return (lhs.TotalNanoseconds() / rhs.TotalNanoseconds());
std::istringstream is(dateStr);
TimePoint tp;
tp.Read(is, format.c_str());
return tp;
}
TimeType ReadFormattedDate(const std::string & dateStr, const std::string & format)
std::ostream & TimePoint::Display(std::ostream & os, const std::string& format) const
{
MetaData::TimeType outputDate;
std::stringstream ss;
auto facet = new boost::posix_time::time_input_facet(format);
ss.imbue(std::locale(std::locale(), facet));
ss << dateStr;
ss >> outputDate;
return outputDate;
date::to_stream(os, format.c_str(), m_Time);
return os;
}
DurationType seconds(double input)
std::istream & TimePoint::Read(std::istream & is, const std::string & format)
{
//return boost::posix_time::precise_duration(input * 1e9);
return DurationType::Seconds(input);
date::from_stream(is, format.c_str(), m_Time);
return is;
}
double Duration::TotalSeconds() const
{
return m_Duration.count() * details::internalPeriod;
}
Duration::InternalDurationType::rep Duration::NumberOfTicks() const
{
return m_Duration.count();
}
std::ostream & Duration::Display(std::ostream & os) const
{
return os << m_Duration.count() * details::internalPeriod;
}
std::istream & Duration::Read(std::istream & is)
{
double s;
is >> s;
m_Duration = InternalDurationType(static_cast<long long>(std::round(s * 1e9)));
return is;
}
Duration Abs(Duration d)
{
if(d.m_Duration.is_negative())
d.m_Duration = d.m_Duration.invert_sign();
if(d.m_Duration.count() < 0)
d.m_Duration = -d.m_Duration;
return d;
}
double Ratio(const Duration & lhs, const Duration & rhs)
{
return static_cast<double>(lhs.NumberOfTicks()) / rhs.NumberOfTicks();
}
DurationType seconds(double input)
{
return DurationType::Seconds(input);
}
} // namespace otb
} // namespace MetaData
\ No newline at end of file
......@@ -25,6 +25,7 @@
#include "otbMacro.h"
#include <regex>
#include <iomanip>
namespace
{
......
......@@ -49,7 +49,7 @@ BOOST_AUTO_TEST_CASE(Duration)
// Getter tests
BOOST_TEST(otb::MetaData::Duration::Nanoseconds(10).TotalSeconds() == 10e-9);
BOOST_TEST(otb::MetaData::Duration::Nanoseconds(10).TotalNanoseconds() == 10);
BOOST_TEST(otb::MetaData::Duration::Nanoseconds(10).NumberOfTicks() == 10);
}
BOOST_AUTO_TEST_CASE(TimePoint)
......
#
# Copyright (C) 2005-2020 Centre National d'Etudes Spatiales (CNES)
#
# This file is part of Orfeo Toolbox
#
# https://www.orfeo-toolbox.org/
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
project(OTBDate)
otb_module_impl()
This diff is collapsed.
#
# Copyright (C) 2005-2020 Centre National d'Etudes Spatiales (CNES)
#
# This file is part of Orfeo Toolbox
#
# https://www.orfeo-toolbox.org/
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
set(DOCUMENTATION "This module imports the date.h header from Howard Hinnant's date library")
otb_module(OTBDate
DEPENDS
TEST_DEPENDS
DESCRIPTION
"${DOCUMENTATION}"
)
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment