Merge pull request #18 from ToruNiina/threadsafe-localtime

add threadsafe localtime_(s|r)
This commit is contained in:
Toru Niina 2019-02-16 23:28:48 +09:00 committed by GitHub
commit d7b8c3c78f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -14,6 +14,36 @@
namespace toml
{
// To avoid non-threadsafe std::localtime. In C11 (not C++11!), localtime_s is
// provided in the absolutely same purpose, but C++11 is actually not compatible
// with C11. We need to dispatch the function depending on the OS.
namespace detail
{
// TODO: find more sophisticated way to handle this
#if _POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _BSD_SOURCE || _SVID_SOURCE || _POSIX_SOURCE
inline std::tm localtime_s(const std::time_t* src)
{
std::tm dst;
const auto result = ::localtime_r(src, &dst);
if(!result)
{
throw std::runtime_error("localtime_r failed.");
}
return dst;
}
#else
// XXX: On Windows, std::localtime is thread-safe because they uses thread-local
// storage to store the instance of std::tm. On the other platforms, it may not
// be thread-safe.
inline std::tm localtime_s(const std::time_t* src)
{
const auto result = std::localtime(src);
if(!result) {throw std::runtime_error("localtime failed.");}
return *result;
}
#endif
} // detail
enum class month_t : std::int8_t
{
Jan = 0,
@ -50,10 +80,8 @@ struct local_date
explicit local_date(const std::chrono::system_clock::time_point& tp)
{
const auto t = std::chrono::system_clock::to_time_t(tp);
const auto tmp = std::localtime(&t); //XXX: not threadsafe!
assert(tmp); // if std::localtime fails, tmp is nullptr
const std::tm time = *tmp;
const auto t = std::chrono::system_clock::to_time_t(tp);
const auto time = detail::localtime_s(&t);
*this = local_date(time);
}
@ -330,10 +358,8 @@ struct local_datetime
explicit local_datetime(const std::chrono::system_clock::time_point& tp)
{
const auto t = std::chrono::system_clock::to_time_t(tp);
const auto tmp = std::localtime(&t); //XXX: not threadsafe!
assert(tmp); // if std::localtime fails, tmp is nullptr
std::tm time = detail::localtime_s(&t);
std::tm time = *tmp;
this->date = local_date(time);
this->time = local_time(time);
@ -482,10 +508,8 @@ struct offset_datetime
static time_offset get_local_offset()
{
// get current timezone
const auto tmp1 = std::time(nullptr);
const auto tmp2 = std::localtime(&tmp1); // XXX not threadsafe!
assert(tmp2);
std::tm t = *tmp2;
const auto tmp1 = std::time(nullptr);
const auto t = detail::localtime_s(&tmp1);
std::array<char, 6> buf;
const auto result = std::strftime(buf.data(), 6, "%z", &t); // +hhmm\0