Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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>

Comment thread
MattStephanson marked this conversation as resolved.
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));
Comment thread
StephanTLavavej marked this conversation as resolved.

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");
Comment thread
StephanTLavavej marked this conversation as resolved.

#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>;
Comment thread
StephanTLavavej marked this conversation as resolved.
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;
}