From d080c0661b1685958e308cf3854442df03ff94b2 Mon Sep 17 00:00:00 2001 From: Jeremy Nimmer Date: Tue, 23 Nov 2021 12:00:35 -0800 Subject: [PATCH] Evict large function definitions from the Helpers.hh header file Signed-off-by: Jeremy Nimmer --- Changelog.md | 3 + include/ignition/math/Helpers.hh | 226 ++---------------------------- src/Helpers.cc | 231 +++++++++++++++++++++++++++++++ 3 files changed, 244 insertions(+), 216 deletions(-) diff --git a/Changelog.md b/Changelog.md index 8d01df91e..04889d290 100644 --- a/Changelog.md +++ b/Changelog.md @@ -27,6 +27,9 @@ 1. Use and narrower includes, not * [Pull request 287](https://github.com/ignitionrobotics/ign-math/pull/287) +1. Evict large function definitions from the Helpers.hh header file. + * [Pull request 288](https://github.com/ignitionrobotics/ign-math/pull/288) + ## Ignition Math 6.x ### Ignition Math 6.x.x diff --git a/include/ignition/math/Helpers.hh b/include/ignition/math/Helpers.hh index 525578685..7eb16c819 100644 --- a/include/ignition/math/Helpers.hh +++ b/include/ignition/math/Helpers.hh @@ -21,11 +21,8 @@ #include #include #include -#include #include #include -#include -#include #include #include #include @@ -687,81 +684,14 @@ namespace ignition /// \brief Convert a std::chrono::steady_clock::time_point to a string /// \param[in] _point The std::chrono::steady_clock::time_point to convert. /// \return A string formatted with the time_point - inline std::string timePointToString( - const std::chrono::steady_clock::time_point &_point) - { - auto duration = _point - secNsecToTimePoint(0, 0); - auto cleanDuration = breakDownDurations( - duration); - std::ostringstream output_string; - output_string << std::setw(2) << std::setfill('0') - << std::get<0>(cleanDuration).count() << " " - << std::setw(2) << std::setfill('0') - << std::get<1>(cleanDuration).count() << ":" - << std::setw(2) << std::setfill('0') - << std::get<2>(cleanDuration).count() << ":" - << std::setfill('0') << std::setw(6) - << std::fixed << std::setprecision(3) - << std::get<3>(cleanDuration).count() + - std::get<4>(cleanDuration).count()/1000.0; - return output_string.str(); - } + std::string IGNITION_MATH_VISIBLE timePointToString( + const std::chrono::steady_clock::time_point &_point); /// \brief Convert a std::chrono::steady_clock::duration to a string /// \param[in] _duration The std::chrono::steady_clock::duration to convert. /// \return A string formatted with the duration - inline std::string durationToString( - const std::chrono::steady_clock::duration &_duration) - { - auto cleanDuration = breakDownDurations( - _duration); - std::ostringstream outputString; - outputString << std::setw(2) << std::setfill('0') - << std::get<0>(cleanDuration).count() << " " - << std::setw(2) << std::setfill('0') - << std::get<1>(cleanDuration).count() << ":" - << std::setw(2) << std::setfill('0') - << std::get<2>(cleanDuration).count() << ":" - << std::setfill('0') << std::setw(6) - << std::fixed << std::setprecision(3) - << std::get<3>(cleanDuration).count() + - std::get<4>(cleanDuration).count()/1000.0; - return outputString.str(); - } - - // The following regex takes a time string in the general format of - // "dd hh:mm:ss.nnn" where n is milliseconds, if just one number is - // provided, it is assumed to be seconds - static const std::regex time_regex( - "^([0-9]+ ){0,1}" // day: - // Any positive integer - - "(?:([1-9]:|[0-1][0-9]:|2[0-3]:){0,1}" // hour: - // 1 - 9: - // 01 - 19: - // 20 - 23: - - "([0-9]:|[0-5][0-9]:)){0,1}" // minute: - // 0 - 9: - // 00 - 59: - - "(?:([0-9]|[0-5][0-9]){0,1}" // second: - // 0 - 9 - // 00 - 59 - - "(\\.[0-9]{1,3}){0,1})$"); // millisecond: - // .0 - .9 - // .00 - .99 - // .000 - 0.999 - + std::string IGNITION_MATH_VISIBLE durationToString( + const std::chrono::steady_clock::duration &_duration); /// \brief Split a std::chrono::steady_clock::duration to a string /// \param[in] _timeString The string to convert in general format @@ -771,82 +701,11 @@ namespace ignition /// \param[out] numberSeconds number of seconds in the string /// \param[out] numberMilliseconds number of milliseconds in the string /// \return True if the regex was able to split the string otherwise False - inline bool splitTimeBasedOnTimeRegex( + bool IGNITION_MATH_VISIBLE splitTimeBasedOnTimeRegex( const std::string &_timeString, uint64_t & numberDays, uint64_t & numberHours, uint64_t & numberMinutes, uint64_t & numberSeconds, - uint64_t & numberMilliseconds) - { - std::smatch matches; - - // `matches` should always be a size of 6 as there are 6 matching - // groups in the regex. - // 1. The whole regex - // 2. The days - // 3. The hours - // 4. The minutes - // 5. The seconds - // 6. The milliseconds - // We can also index them as such below. - // Note that the space will remain in the day match, the colon - // will remain in the hour and minute matches, and the period will - // remain in the millisecond match - if (!std::regex_search(_timeString, matches, time_regex) || - matches.size() != 6) - return false; - - std::string dayString = matches[1]; - std::string hourString = matches[2]; - std::string minuteString = matches[3]; - std::string secondString = matches[4]; - std::string millisecondString = matches[5]; - - // Days are the only unbounded number, so check first to see if stoi - // runs successfully - if (!dayString.empty()) - { - // Erase the space - dayString.erase(dayString.length() - 1); - try - { - numberDays = std::stoi(dayString); - } - catch (const std::out_of_range &) - { - return false; - } - } - - if (!hourString.empty()) - { - // Erase the colon - hourString.erase(hourString.length() - 1); - numberHours = std::stoi(hourString); - } - - if (!minuteString.empty()) - { - // Erase the colon - minuteString.erase(minuteString.length() - 1); - numberMinutes = std::stoi(minuteString); - } - - if (!secondString.empty()) - { - numberSeconds = std::stoi(secondString); - } - - if (!millisecondString.empty()) - { - // Erase the period - millisecondString.erase(0, 1); - - // Multiplier because "4" = 400 ms, "04" = 40 ms, and "004" = 4 ms - numberMilliseconds = std::stoi(millisecondString) * - static_cast(1000 / pow(10, millisecondString.length())); - } - return true; - } + uint64_t & numberMilliseconds); /// \brief Convert a string to a std::chrono::steady_clock::duration /// \param[in] _timeString The string to convert in general format @@ -854,41 +713,8 @@ namespace ignition /// \return A std::chrono::steady_clock::duration containing the /// string's time value. If it isn't possible to convert, the duration will /// be zero. - inline std::chrono::steady_clock::duration stringToDuration( - const std::string &_timeString) - { - using namespace std::chrono_literals; - std::chrono::steady_clock::duration duration{ - std::chrono::steady_clock::duration::zero()}; - - if (_timeString.empty()) - return duration; - - uint64_t numberDays = 0; - uint64_t numberHours = 0; - uint64_t numberMinutes = 0; - uint64_t numberSeconds = 0; - uint64_t numberMilliseconds = 0; - - if (!splitTimeBasedOnTimeRegex(_timeString, numberDays, numberHours, - numberMinutes, numberSeconds, - numberMilliseconds)) - { - return duration; - } - - // TODO(anyone): Replace below day conversion with std::chrono::days. - /// This will exist in C++-20 - duration = std::chrono::steady_clock::duration::zero(); - auto delta = std::chrono::milliseconds(numberMilliseconds) + - std::chrono::seconds(numberSeconds) + - std::chrono::minutes(numberMinutes) + - std::chrono::hours(numberHours) + - std::chrono::hours(24 * numberDays); - duration += delta; - - return duration; - } + std::chrono::steady_clock::duration IGNITION_MATH_VISIBLE stringToDuration( + const std::string &_timeString); /// \brief Convert a string to a std::chrono::steady_clock::time_point /// \param[in] _timeString The string to convert in general format @@ -896,40 +722,8 @@ namespace ignition /// \return A std::chrono::steady_clock::time_point containing the /// string's time value. If it isn't possible to convert, the time will /// be negative 1 second. - inline std::chrono::steady_clock::time_point stringToTimePoint( - const std::string &_timeString) - { - using namespace std::chrono_literals; - std::chrono::steady_clock::time_point timePoint{-1s}; - - if (_timeString.empty()) - return timePoint; - - uint64_t numberDays = 0; - uint64_t numberHours = 0; - uint64_t numberMinutes = 0; - uint64_t numberSeconds = 0; - uint64_t numberMilliseconds = 0; - - if (!splitTimeBasedOnTimeRegex(_timeString, numberDays, numberHours, - numberMinutes, numberSeconds, - numberMilliseconds)) - { - return timePoint; - } - - // TODO(anyone): Replace below day conversion with std::chrono::days. - /// This will exist in C++-20 - timePoint = math::secNsecToTimePoint(0, 0); - auto duration = std::chrono::milliseconds(numberMilliseconds) + - std::chrono::seconds(numberSeconds) + - std::chrono::minutes(numberMinutes) + - std::chrono::hours(numberHours) + - std::chrono::hours(24 * numberDays); - timePoint += duration; - - return timePoint; - } + std::chrono::steady_clock::time_point + IGNITION_MATH_VISIBLE stringToTimePoint(const std::string &_timeString); // Degrade precision on Windows, which cannot handle 'long double' // values properly. See the implementation of Unpair. diff --git a/src/Helpers.cc b/src/Helpers.cc index 85c17962f..56ed58302 100644 --- a/src/Helpers.cc +++ b/src/Helpers.cc @@ -16,12 +16,243 @@ */ #include "ignition/math/Helpers.hh" +#include +#include +#include + namespace ignition { namespace math { inline namespace IGNITION_MATH_VERSION_NAMESPACE { + + ///////////////////////////////////////////// + std::string timePointToString( + const std::chrono::steady_clock::time_point &_point) + { + auto duration = _point - secNsecToTimePoint(0, 0); + auto cleanDuration = breakDownDurations( + duration); + std::ostringstream output_string; + output_string << std::setw(2) << std::setfill('0') + << std::get<0>(cleanDuration).count() << " " + << std::setw(2) << std::setfill('0') + << std::get<1>(cleanDuration).count() << ":" + << std::setw(2) << std::setfill('0') + << std::get<2>(cleanDuration).count() << ":" + << std::setfill('0') << std::setw(6) + << std::fixed << std::setprecision(3) + << std::get<3>(cleanDuration).count() + + std::get<4>(cleanDuration).count()/1000.0; + return output_string.str(); + } + + ///////////////////////////////////////////// + std::string durationToString( + const std::chrono::steady_clock::duration &_duration) + { + auto cleanDuration = breakDownDurations( + _duration); + std::ostringstream outputString; + outputString << std::setw(2) << std::setfill('0') + << std::get<0>(cleanDuration).count() << " " + << std::setw(2) << std::setfill('0') + << std::get<1>(cleanDuration).count() << ":" + << std::setw(2) << std::setfill('0') + << std::get<2>(cleanDuration).count() << ":" + << std::setfill('0') << std::setw(6) + << std::fixed << std::setprecision(3) + << std::get<3>(cleanDuration).count() + + std::get<4>(cleanDuration).count()/1000.0; + return outputString.str(); + } + + // The following regex takes a time string in the general format of + // "dd hh:mm:ss.nnn" where n is milliseconds, if just one number is + // provided, it is assumed to be seconds + static const std::regex time_regex( + "^([0-9]+ ){0,1}" // day: + // Any positive integer + + "(?:([1-9]:|[0-1][0-9]:|2[0-3]:){0,1}" // hour: + // 1 - 9: + // 01 - 19: + // 20 - 23: + + "([0-9]:|[0-5][0-9]:)){0,1}" // minute: + // 0 - 9: + // 00 - 59: + + "(?:([0-9]|[0-5][0-9]){0,1}" // second: + // 0 - 9 + // 00 - 59 + + "(\\.[0-9]{1,3}){0,1})$"); // millisecond: + // .0 - .9 + // .00 - .99 + // .000 - 0.999 + + + ///////////////////////////////////////////// + bool splitTimeBasedOnTimeRegex( + const std::string &_timeString, + uint64_t & numberDays, uint64_t & numberHours, + uint64_t & numberMinutes, uint64_t & numberSeconds, + uint64_t & numberMilliseconds) + { + std::smatch matches; + + // `matches` should always be a size of 6 as there are 6 matching + // groups in the regex. + // 1. The whole regex + // 2. The days + // 3. The hours + // 4. The minutes + // 5. The seconds + // 6. The milliseconds + // We can also index them as such below. + // Note that the space will remain in the day match, the colon + // will remain in the hour and minute matches, and the period will + // remain in the millisecond match + if (!std::regex_search(_timeString, matches, time_regex) || + matches.size() != 6) + return false; + + std::string dayString = matches[1]; + std::string hourString = matches[2]; + std::string minuteString = matches[3]; + std::string secondString = matches[4]; + std::string millisecondString = matches[5]; + + // Days are the only unbounded number, so check first to see if stoi + // runs successfully + if (!dayString.empty()) + { + // Erase the space + dayString.erase(dayString.length() - 1); + try + { + numberDays = std::stoi(dayString); + } + catch (const std::out_of_range &) + { + return false; + } + } + + if (!hourString.empty()) + { + // Erase the colon + hourString.erase(hourString.length() - 1); + numberHours = std::stoi(hourString); + } + + if (!minuteString.empty()) + { + // Erase the colon + minuteString.erase(minuteString.length() - 1); + numberMinutes = std::stoi(minuteString); + } + + if (!secondString.empty()) + { + numberSeconds = std::stoi(secondString); + } + + if (!millisecondString.empty()) + { + // Erase the period + millisecondString.erase(0, 1); + + // Multiplier because "4" = 400 ms, "04" = 40 ms, and "004" = 4 ms + numberMilliseconds = std::stoi(millisecondString) * + static_cast(1000 / pow(10, millisecondString.length())); + } + return true; + } + + ///////////////////////////////////////////// + std::chrono::steady_clock::duration stringToDuration( + const std::string &_timeString) + { + using namespace std::chrono_literals; + std::chrono::steady_clock::duration duration{ + std::chrono::steady_clock::duration::zero()}; + + if (_timeString.empty()) + return duration; + + uint64_t numberDays = 0; + uint64_t numberHours = 0; + uint64_t numberMinutes = 0; + uint64_t numberSeconds = 0; + uint64_t numberMilliseconds = 0; + + if (!splitTimeBasedOnTimeRegex(_timeString, numberDays, numberHours, + numberMinutes, numberSeconds, + numberMilliseconds)) + { + return duration; + } + + // TODO(anyone): Replace below day conversion with std::chrono::days. + /// This will exist in C++-20 + duration = std::chrono::steady_clock::duration::zero(); + auto delta = std::chrono::milliseconds(numberMilliseconds) + + std::chrono::seconds(numberSeconds) + + std::chrono::minutes(numberMinutes) + + std::chrono::hours(numberHours) + + std::chrono::hours(24 * numberDays); + duration += delta; + + return duration; + } + + ///////////////////////////////////////////// + std::chrono::steady_clock::time_point stringToTimePoint( + const std::string &_timeString) + { + using namespace std::chrono_literals; + std::chrono::steady_clock::time_point timePoint{-1s}; + + if (_timeString.empty()) + return timePoint; + + uint64_t numberDays = 0; + uint64_t numberHours = 0; + uint64_t numberMinutes = 0; + uint64_t numberSeconds = 0; + uint64_t numberMilliseconds = 0; + + if (!splitTimeBasedOnTimeRegex(_timeString, numberDays, numberHours, + numberMinutes, numberSeconds, + numberMilliseconds)) + { + return timePoint; + } + + // TODO(anyone): Replace below day conversion with std::chrono::days. + /// This will exist in C++-20 + timePoint = math::secNsecToTimePoint(0, 0); + auto duration = std::chrono::milliseconds(numberMilliseconds) + + std::chrono::seconds(numberSeconds) + + std::chrono::minutes(numberMinutes) + + std::chrono::hours(numberHours) + + std::chrono::hours(24 * numberDays); + timePoint += duration; + + return timePoint; + } + ///////////////////////////////////////////// PairOutput Pair(const PairInput _a, const PairInput _b) {