Skip to content

Commit

Permalink
<chrono>: [time.duration.io] output (#1341)
Browse files Browse the repository at this point in the history
Co-authored-by: mnatsuhara <[email protected]>
Co-authored-by: Stephan T. Lavavej <[email protected]>
  • Loading branch information
3 people authored Nov 6, 2020
1 parent 26bbe2a commit 6458199
Show file tree
Hide file tree
Showing 5 changed files with 214 additions and 1 deletion.
83 changes: 83 additions & 0 deletions stl/inc/chrono
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#if _STL_COMPILER_PREPROCESSOR
#include <limits>
#include <ratio>
#include <sstream>
#include <time.h>
#include <utility>
#include <xtimec.h>
Expand Down Expand Up @@ -617,6 +618,88 @@ namespace chrono {
};

using high_resolution_clock = steady_clock;

#if _HAS_CXX20
// [time.duration.io]

#define _IF_PERIOD_RETURN_SUFFIX_ELSE(_TYPE, _SUFFIX) \
if constexpr (is_same_v<_Period, _TYPE>) { \
if constexpr (is_same_v<_CharT, char>) { \
return _SUFFIX; \
} else { \
return L##_SUFFIX; \
} \
} else

template <class _CharT, class _Period>
_NODISCARD constexpr const _CharT* _Get_literal_unit_suffix() {
_IF_PERIOD_RETURN_SUFFIX_ELSE(atto, "as")
_IF_PERIOD_RETURN_SUFFIX_ELSE(femto, "fs")
_IF_PERIOD_RETURN_SUFFIX_ELSE(pico, "ps")
_IF_PERIOD_RETURN_SUFFIX_ELSE(nano, "ns")
_IF_PERIOD_RETURN_SUFFIX_ELSE(micro, "us")
_IF_PERIOD_RETURN_SUFFIX_ELSE(milli, "ms")
_IF_PERIOD_RETURN_SUFFIX_ELSE(centi, "cs")
_IF_PERIOD_RETURN_SUFFIX_ELSE(deci, "ds")
_IF_PERIOD_RETURN_SUFFIX_ELSE(seconds::period, "s")
_IF_PERIOD_RETURN_SUFFIX_ELSE(deca, "das")
_IF_PERIOD_RETURN_SUFFIX_ELSE(hecto, "hs")
_IF_PERIOD_RETURN_SUFFIX_ELSE(kilo, "ks")
_IF_PERIOD_RETURN_SUFFIX_ELSE(mega, "Ms")
_IF_PERIOD_RETURN_SUFFIX_ELSE(giga, "Gs")
_IF_PERIOD_RETURN_SUFFIX_ELSE(tera, "Ts")
_IF_PERIOD_RETURN_SUFFIX_ELSE(peta, "Ps")
_IF_PERIOD_RETURN_SUFFIX_ELSE(exa, "Es")
_IF_PERIOD_RETURN_SUFFIX_ELSE(minutes::period, "min")
_IF_PERIOD_RETURN_SUFFIX_ELSE(hours::period, "h")
_IF_PERIOD_RETURN_SUFFIX_ELSE(ratio<86400>, "d")

{
return nullptr;
}
}

#undef _IF_PERIOD_RETURN_SUFFIX_ELSE

template <class _CharT>
_NODISCARD _CharT* _Get_general_unit_suffix(_CharT* _Rnext, const intmax_t _Num, const intmax_t _Den) {
// Returns the head pointer of the string, built in reverse.
_STL_INTERNAL_CHECK(_Num > 0 && _Den > 0);
*--_Rnext = '\0';
*--_Rnext = 's';
*--_Rnext = ']';
if (_Den != 1) {
_Rnext = _UIntegral_to_buff(_Rnext, static_cast<uintmax_t>(_Den));
*--_Rnext = '/';
}

_Rnext = _UIntegral_to_buff(_Rnext, static_cast<uintmax_t>(_Num));
*--_Rnext = '[';
return _Rnext;
}

template <class _CharT, class _Traits, class _Rep, class _Period>
basic_ostream<_CharT, _Traits>& operator<<(
basic_ostream<_CharT, _Traits>& _Os, const duration<_Rep, _Period>& _Dur) {
basic_ostringstream<_CharT, _Traits> _Sstr;
_Sstr.flags(_Os.flags());
_Sstr.imbue(_Os.getloc());
_Sstr.precision(_Os.precision());
_Sstr << _Dur.count();

constexpr auto _Suffix = _Get_literal_unit_suffix<_CharT, _Period>();
if constexpr (_Suffix == nullptr) {
_CharT _Buffer[2 * (numeric_limits<intmax_t>::digits10 + 1) + 5] = {}; // 2 numbers + "[/]s\0"
const _CharT* const _Begin =
_Get_general_unit_suffix<_CharT>(_STD end(_Buffer), _Period::num, _Period::den);
_Sstr << _Begin;
} else {
_Sstr << _Suffix;
}

return _Os << _Sstr.str();
}
#endif // _HAS_CXX20
} // namespace chrono

// HELPERS
Expand Down
2 changes: 1 addition & 1 deletion stl/inc/string
Original file line number Diff line number Diff line change
Expand Up @@ -448,7 +448,7 @@ inline long double stold(const wstring& _Str, size_t* _Idx = nullptr) { // conve
return _Ans;
}

// HELPERS FOR to_string AND to_wstring
// HELPERS FOR to_string AND to_wstring AND operator<<(duration)
template <class _Elem, class _UTy>
_Elem* _UIntegral_to_buff(_Elem* _RNext, _UTy _UVal) { // format _UVal into buffer *ending at* _RNext
static_assert(is_unsigned_v<_UTy>, "_UTy must be unsigned");
Expand Down
1 change: 1 addition & 0 deletions tests/std/test.lst
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@ tests\P0220R1_searchers
tests\P0220R1_string_view
tests\P0325R4_to_array
tests\P0339R6_polymorphic_allocator
tests\P0355R7_calendars_and_time_zones_io
tests\P0356R5_bind_front
tests\P0357R3_supporting_incomplete_types_in_reference_wrapper
tests\P0414R2_shared_ptr_for_arrays
Expand Down
4 changes: 4 additions & 0 deletions tests/std/tests/P0355R7_calendars_and_time_zones_io/env.lst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

RUNALL_INCLUDE ..\usual_latest_matrix.lst
125 changes: 125 additions & 0 deletions tests/std/tests/P0355R7_calendars_and_time_zones_io/test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#include <cassert>
#include <chrono>
#include <climits>
#include <locale>
#include <ratio>
#include <sstream>
#include <string>
#include <utility>

using namespace std;
using chrono::duration;

template <class CharT, class Rep, class Period>
bool test_duration_basic_out(const duration<Rep, Period>& d, const CharT* expected) {
basic_ostringstream<CharT> ss;

ss << d;
return ss.str() == expected;
}

#define WIDEN(TYPE, STR) get<const TYPE*>(make_pair(STR, L##STR));

template <class CharT>
bool test_duration_locale_out() {
basic_stringstream<CharT> ss;
const duration<double> d{0.140625};
ss.precision(3);
ss << d;
ss.setf(ios_base::scientific, ios_base::floatfield);
ss << ' ' << d;

basic_string<CharT> expected = WIDEN(CharT, "0.141s 1.406e-01s");

#ifdef _DEBUG
#define DEFAULT_IDL_SETTING 2
#else
#define DEFAULT_IDL_SETTING 0
#endif

#if !defined(_DLL) || _ITERATOR_DEBUG_LEVEL == DEFAULT_IDL_SETTING
// When linking dynamically, user-defined facets are incompatible with non-default _ITERATOR_DEBUG_LEVEL settings.
struct comma : numpunct<CharT> {
CharT do_decimal_point() const {
return ',';
}
};

ss.imbue(locale(ss.getloc(), new comma));
ss << ' ' << d;
expected += WIDEN(CharT, " 1,406e-01s");
#endif // !defined(_DLL) || _ITERATOR_DEBUG_LEVEL == DEFAULT_IDL_SETTING

return ss.str() == expected;
}

#undef WIDEN

void test_duration_output() {
using LongRatio = ratio<INTMAX_MAX - 1, INTMAX_MAX>;
assert(test_duration_basic_out(duration<int, atto>{1}, "1as"));
assert(test_duration_basic_out(duration<int, femto>{2}, "2fs"));
assert(test_duration_basic_out(duration<int, pico>{3}, "3ps"));
assert(test_duration_basic_out(duration<int, nano>{42}, "42ns"));
assert(test_duration_basic_out(duration<int, micro>{42}, "42us"));
assert(test_duration_basic_out(duration<int, milli>{42}, "42ms"));
assert(test_duration_basic_out(duration<int, centi>{42}, "42cs"));
assert(test_duration_basic_out(duration<int, deci>{42}, "42ds"));
assert(test_duration_basic_out(duration<int, ratio<1>>{42}, "42s"));
assert(test_duration_basic_out(duration<int, deca>{42}, "42das"));
assert(test_duration_basic_out(duration<int, hecto>{42}, "42hs"));
assert(test_duration_basic_out(duration<int, kilo>{42}, "42ks"));
assert(test_duration_basic_out(duration<int, mega>{42}, "42Ms"));
assert(test_duration_basic_out(duration<int, giga>{42}, "42Gs"));
assert(test_duration_basic_out(duration<int, tera>{42}, "42Ts"));
assert(test_duration_basic_out(duration<int, peta>{42}, "42Ps"));
assert(test_duration_basic_out(duration<int, exa>{42}, "42Es"));
assert(test_duration_basic_out(duration<int, ratio<60>>{42}, "42min"));
assert(test_duration_basic_out(duration<int, ratio<60 * 60>>{42}, "42h"));
assert(test_duration_basic_out(duration<int, ratio<60 * 60 * 24>>{42}, "42d"));

assert(test_duration_basic_out(duration<int, ratio<2>>{24}, "24[2]s"));
assert(test_duration_basic_out(duration<int, ratio<1, 2>>{24}, "24[1/2]s"));
assert(test_duration_basic_out(duration<int, ratio<22, 7>>{24}, "24[22/7]s"));
assert(test_duration_basic_out(duration<int, LongRatio>{24}, "24[9223372036854775806/9223372036854775807]s"));

assert(test_duration_basic_out(duration<double>{0.140625}, "0.140625s"));
assert(test_duration_locale_out<char>());

assert(test_duration_basic_out(duration<int, atto>{1}, L"1as"));
assert(test_duration_basic_out(duration<int, femto>{2}, L"2fs"));
assert(test_duration_basic_out(duration<int, pico>{3}, L"3ps"));
assert(test_duration_basic_out(duration<int, nano>{42}, L"42ns"));
assert(test_duration_basic_out(duration<int, micro>{42}, L"42us"));
assert(test_duration_basic_out(duration<int, milli>{42}, "42ms"));
assert(test_duration_basic_out(duration<int, centi>{42}, L"42cs"));
assert(test_duration_basic_out(duration<int, deci>{42}, L"42ds"));
assert(test_duration_basic_out(duration<int, ratio<1>>{42}, L"42s"));
assert(test_duration_basic_out(duration<int, deca>{42}, L"42das"));
assert(test_duration_basic_out(duration<int, hecto>{42}, L"42hs"));
assert(test_duration_basic_out(duration<int, kilo>{42}, L"42ks"));
assert(test_duration_basic_out(duration<int, mega>{42}, L"42Ms"));
assert(test_duration_basic_out(duration<int, giga>{42}, L"42Gs"));
assert(test_duration_basic_out(duration<int, tera>{42}, L"42Ts"));
assert(test_duration_basic_out(duration<int, peta>{42}, L"42Ps"));
assert(test_duration_basic_out(duration<int, exa>{42}, L"42Es"));
assert(test_duration_basic_out(duration<int, ratio<60>>{42}, L"42min"));
assert(test_duration_basic_out(duration<int, ratio<60 * 60>>{42}, L"42h"));
assert(test_duration_basic_out(duration<int, ratio<60 * 60 * 24>>{42}, L"42d"));

assert(test_duration_basic_out(duration<int, ratio<2>>{24}, L"24[2]s"));
assert(test_duration_basic_out(duration<int, ratio<1, 2>>{24}, L"24[1/2]s"));
assert(test_duration_basic_out(duration<int, ratio<22, 7>>{24}, L"24[22/7]s"));
assert(test_duration_basic_out(duration<int, LongRatio>{24}, L"24[9223372036854775806/9223372036854775807]s"));

assert(test_duration_basic_out(duration<double>{0.140625}, L"0.140625s"));
assert(test_duration_locale_out<wchar_t>());
}

int main() {
test_duration_output();
return 0;
}

0 comments on commit 6458199

Please sign in to comment.