blob: 8b9789391f34c20711e6792b79f56bd9d8fd77c8 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#pragma once
#ifndef GEODE_INTERNAL_CHRONO_DURATION_H_
#define GEODE_INTERNAL_CHRONO_DURATION_H_
#include <chrono>
#include <iosfwd>
#include <ratio>
#include <stdexcept>
#include <string>
#include <type_traits>
namespace apache {
namespace geode {
namespace internal {
namespace chrono {
namespace duration {
template <class Period>
struct _suffix {
static constexpr char const* value = "<<unknown units>>";
};
template <>
struct _suffix<std::ratio<3600>> {
static constexpr char const* value = "h";
};
template <>
struct _suffix<std::ratio<60>> {
static constexpr char const* value = "min";
};
template <>
struct _suffix<std::ratio<1>> {
static constexpr char const* value = "s";
};
template <>
struct _suffix<std::milli> {
static constexpr char const* value = "ms";
};
template <>
struct _suffix<std::micro> {
static constexpr char const* value = "us";
};
template <>
struct _suffix<std::nano> {
static constexpr char const* value = "ns";
};
template <class T>
struct _is_duration : std::false_type {};
template <class Rep, class Period>
struct _is_duration<std::chrono::duration<Rep, Period>> : std::true_type {};
template <class Rep, class Period>
struct _is_duration<const std::chrono::duration<Rep, Period>> : std::true_type {
};
template <class Rep, class Period>
struct _is_duration<volatile std::chrono::duration<Rep, Period>>
: std::true_type {};
template <class Rep, class Period>
struct _is_duration<const volatile std::chrono::duration<Rep, Period>>
: std::true_type {};
/**
* Converts std::chrono:duration from given unit to other where other duration
* is no less than the given duration.
*
* For internal use only.
*/
template <class ToDuration, class Rep, class Period>
inline
typename std::enable_if<_is_duration<ToDuration>::value, ToDuration>::type
_ceil(const std::chrono::duration<Rep, Period>& duration) {
ToDuration other = std::chrono::duration_cast<ToDuration>(duration);
if (other < duration) {
return other + ToDuration{1};
}
return other;
}
/**
* Parses std::string into std::chrono::duration expecting same format as that
* of C++14 std::chrono::duration literals.
*
* @returns std::chrono::duration for given input string where the resulting
* std::chrono::duration will not be less than the parsed duration if the
* units of std::chrono::duration are less the units of the given string.
*
* @tparam ToDuration std::chrono::duration type to parse into.
*/
template <class ToDuration = std::chrono::nanoseconds>
inline
typename std::enable_if<_is_duration<ToDuration>::value, ToDuration>::type
from_string(const std::string& string) {
const auto& begin = string.begin();
auto end = string.end();
if (begin != end--) {
if ('s' == *end) {
if (begin != end--) {
if ('m' == *end) {
return _ceil<ToDuration>(std::chrono::milliseconds(
std::stoll(string.substr(0, std::distance(begin, end)))));
} else if ('u' == *end) {
return _ceil<ToDuration>(std::chrono::microseconds(
std::stoll(string.substr(0, std::distance(begin, end)))));
} else if ('n' == *end) {
return _ceil<ToDuration>(std::chrono::nanoseconds(
std::stoll(string.substr(0, std::distance(begin, end)))));
}
}
return _ceil<ToDuration>(std::chrono::seconds(
std::stoll(string.substr(0, std::distance(begin, ++end)))));
} else if ('h' == *end) {
return std::chrono::hours(
std::stoll(string.substr(0, std::distance(begin, end))));
} else if ('n' == *end && begin != end-- && 'i' == *end && begin != end-- &&
'm' == *end) {
return _ceil<ToDuration>(std::chrono::minutes(
std::stoll(string.substr(0, std::distance(begin, end)))));
}
}
throw std::invalid_argument("Not a valid duration parsing '" + string + "'.");
}
template <class Rep, class Period>
inline std::string to_string(
const std::chrono::duration<Rep, Period>& duration) {
return std::to_string(duration.count()) + _suffix<Period>::value;
}
} // namespace duration
} // namespace chrono
} // namespace internal
} // namespace geode
} // namespace apache
#endif /* GEODE_INTERNAL_CHRONO_DURATION_H_ */