Skip to content

Commit

Permalink
Evict large function definitions from the Helpers.hh header file
Browse files Browse the repository at this point in the history
Signed-off-by: Jeremy Nimmer <[email protected]>
  • Loading branch information
jwnimmer-tri committed Nov 23, 2021
1 parent 12f5f7f commit a4d03b4
Show file tree
Hide file tree
Showing 3 changed files with 244 additions and 216 deletions.
3 changes: 3 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
1. Prevent -0 with out stream operator
* [Pull request 206](https://github.com/ignitionrobotics/ign-math/pull/206)

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
Expand Down
226 changes: 10 additions & 216 deletions include/ignition/math/Helpers.hh
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,8 @@
#include <chrono>
#include <cmath>
#include <cstdint>
#include <iomanip>
#include <iostream>
#include <limits>
#include <regex>
#include <sstream>
#include <string>
#include <tuple>
#include <utility>
Expand Down Expand Up @@ -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<days,
std::chrono::hours,
std::chrono::minutes,
std::chrono::seconds,
std::chrono::milliseconds>(
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<days,
std::chrono::hours,
std::chrono::minutes,
std::chrono::seconds,
std::chrono::milliseconds>(
_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
Expand All @@ -771,165 +701,29 @@ 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<uint64_t>(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
/// "dd hh:mm:ss.nnn" where n is millisecond value
/// \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
/// "dd hh:mm:ss.nnn" where n is millisecond value
/// \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.
Expand Down
Loading

0 comments on commit a4d03b4

Please sign in to comment.