From 2d282e35fa18119d6d9396813da2cc4ad29a9d5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Kami=C5=84ski?= Date: Sat, 16 Jun 2018 21:05:57 +0200 Subject: [PATCH] Use string_literal for C++11 when possible --- include/date/date.h | 475 +++++++++-------------- test/date_test/durations_output.pass.cpp | 327 ++++++++++++++++ 2 files changed, 503 insertions(+), 299 deletions(-) create mode 100644 test/date_test/durations_output.pass.cpp diff --git a/include/date/date.h b/include/date/date.h index a69e905..7b455bf 100644 --- a/include/date/date.h +++ b/include/date/date.h @@ -7,6 +7,7 @@ // Copyright (c) 2016 Adrian Colomitchi // Copyright (c) 2017 Florian Dang // Copyright (c) 2017 Paul Thompson +// Copyright (c) 2018 Tomasz Kamiński // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -3005,7 +3006,8 @@ year_month_weekday::ok() const NOEXCEPT return false; if (wdi_.index() <= 4) return true; - auto d2 = wdi_.weekday() - date::weekday(static_cast(y_/m_/1)) + days((wdi_.index()-1)*7 + 1); + auto d2 = wdi_.weekday() - date::weekday(static_cast(y_/m_/1)) + + days((wdi_.index()-1)*7 + 1); return static_cast(d2.count()) <= static_cast((y_/m_/last).day()); } @@ -6220,7 +6222,8 @@ from_stream(std::basic_istream& is, const CharT* fmt, if (modified != CharT{'E'}) #endif { - read(is, ru{trial_wd, 1, width == -1 ? 1u : static_cast(width)}); + read(is, ru{trial_wd, 1, width == -1 ? + 1u : static_cast(width)}); if (!is.fail()) { if (*fmt == 'u') @@ -7754,14 +7757,25 @@ parse(const CharT* format, Parsable& tp, namespace detail { -#if __cplusplus >= 201402 && (!defined(__EDG_VERSION__) || __EDG_VERSION__ > 411) \ - && (!defined(__SUNPRO_CC) || __SUNPRO_CC > 0x5150) +template +class string_literal; + +template +inline +CONSTCD14 +string_literal::type, + N1 + N2 - 1> +operator+(const string_literal& x, const string_literal& y) NOEXCEPT; template class string_literal { CharT p_[N]; + CONSTCD11 string_literal() NOEXCEPT + : p_{} + {} + public: using const_iterator = const CharT*; @@ -7769,12 +7783,26 @@ public: string_literal& operator=(string_literal const&) = delete; template > - CONSTCD14 string_literal(CharT c) NOEXCEPT + class = typename std::enable_if::type> + CONSTCD11 string_literal(CharT c) NOEXCEPT : p_{c} { } + template ::type> + CONSTCD11 string_literal(CharT c1, CharT c2) NOEXCEPT + : p_{c1, c2} + { + } + + template ::type> + CONSTCD11 string_literal(CharT c1, CharT c2, CharT c3) NOEXCEPT + : p_{c1, c2, c3} + { + } + CONSTCD14 string_literal(const CharT(&a)[N]) NOEXCEPT : p_{} { @@ -7782,7 +7810,8 @@ public: p_[i] = a[i]; } - template > + template ::type> CONSTCD14 string_literal(const char(&a)[N]) NOEXCEPT : p_{} { @@ -7790,7 +7819,8 @@ public: p_[i] = a[i]; } - template {}>> + template ::value>::type> CONSTCD14 string_literal(string_literal const& a) NOEXCEPT : p_{} { @@ -7798,26 +7828,13 @@ public: p_[i] = a[i]; } - template > - CONSTCD14 string_literal(const string_literal& x, - const string_literal& y) NOEXCEPT - : p_{} - { - std::size_t i = 0; - for (; i < N1-1; ++i) - p_[i] = x[i]; - for (std::size_t j = 0; j < N2; ++j, ++i) - p_[i] = y[j]; - } + CONSTCD11 const CharT* data() const NOEXCEPT {return p_;} + CONSTCD11 std::size_t size() const NOEXCEPT {return N-1;} - CONSTCD14 const CharT* data() const NOEXCEPT {return p_;} - CONSTCD14 std::size_t size() const NOEXCEPT {return N-1;} + CONSTCD11 const_iterator begin() const NOEXCEPT {return p_;} + CONSTCD11 const_iterator end() const NOEXCEPT {return p_ + N-1;} - CONSTCD14 const_iterator begin() const NOEXCEPT {return p_;} - CONSTCD14 const_iterator end() const NOEXCEPT {return p_ + N-1;} - - CONSTCD14 CharT const& operator[](std::size_t n) const NOEXCEPT + CONSTCD11 CharT const& operator[](std::size_t n) const NOEXCEPT { return p_[n]; } @@ -7829,38 +7846,64 @@ public: { return os << s.p_; } + + template + friend + CONSTCD14 + string_literal::type, + N1 + N2 - 1> + operator+(const string_literal& x, const string_literal& y) NOEXCEPT; }; +template +CONSTCD11 +inline +string_literal +operator+(const string_literal& x, const string_literal& y) NOEXCEPT +{ + return string_literal(x[0], y[0]); +} + +template +CONSTCD11 +inline +string_literal +operator+(const string_literal& x, const string_literal& y) NOEXCEPT +{ + return string_literal(x[0], x[1], y[0]); +} + template CONSTCD14 inline -string_literal, +string_literal::type, N1 + N2 - 1> operator+(const string_literal& x, const string_literal& y) NOEXCEPT { - using CharT = std::conditional_t; - return string_literal{string_literal{x}, - string_literal{y}}; + using CT = typename std::conditional::type; + + string_literal r; + std::size_t i = 0; + for (; i < N1-1; ++i) + r.p_[i] = CT(x.p_[i]); + for (std::size_t j = 0; j < N2; ++j, ++i) + r.p_[i] = CT(y.p_[j]); + + return r; } + template inline std::basic_string -operator+(std::basic_string x, - const string_literal& y) NOEXCEPT +operator+(std::basic_string x, const string_literal& y) { x.append(y.data(), y.size()); return x; } -template -CONSTCD14 -inline -string_literal -msl(const CharT(&a)[N]) NOEXCEPT -{ - return string_literal{a}; -} +#if __cplusplus >= 201402 && (!defined(__EDG_VERSION__) || __EDG_VERSION__ > 411) \ + && (!defined(__SUNPRO_CC) || __SUNPRO_CC > 0x5150) template {} || @@ -7945,198 +7988,6 @@ msl(std::ratio) NOEXCEPT return msl(CharT{'['}) + msl() + msl(CharT{']'}); } -template -CONSTCD14 -inline -auto -msl(std::atto) NOEXCEPT -{ - return msl(CharT{'a'}); -} - -template -CONSTCD14 -inline -auto -msl(std::femto) NOEXCEPT -{ - return msl(CharT{'f'}); -} - -template -CONSTCD14 -inline -auto -msl(std::pico) NOEXCEPT -{ - return msl(CharT{'p'}); -} - -template -CONSTCD14 -inline -auto -msl(std::nano) NOEXCEPT -{ - return msl(CharT{'n'}); -} - -template -CONSTCD14 -inline -std::enable_if_t -< - std::is_same{}, - string_literal -> -msl(std::micro) NOEXCEPT -{ - return string_literal{"\xC2\xB5"}; -} - -template -CONSTCD14 -inline -std::enable_if_t -< - !std::is_same{}, - string_literal -> -msl(std::micro) NOEXCEPT -{ - return string_literal{CharT{static_cast('\xB5')}}; -} - -template -CONSTCD14 -inline -auto -msl(std::milli) NOEXCEPT -{ - return msl(CharT{'m'}); -} - -template -CONSTCD14 -inline -auto -msl(std::centi) NOEXCEPT -{ - return msl(CharT{'c'}); -} - -template -CONSTCD14 -inline -auto -msl(std::deci) NOEXCEPT -{ - return msl(CharT{'d'}); -} - -template -CONSTCD14 -inline -auto -msl(std::deca) NOEXCEPT -{ - return string_literal{"da"}; -} - -template -CONSTCD14 -inline -auto -msl(std::hecto) NOEXCEPT -{ - return msl(CharT{'h'}); -} - -template -CONSTCD14 -inline -auto -msl(std::kilo) NOEXCEPT -{ - return msl(CharT{'k'}); -} - -template -CONSTCD14 -inline -auto -msl(std::mega) NOEXCEPT -{ - return msl(CharT{'M'}); -} - -template -CONSTCD14 -inline -auto -msl(std::giga) NOEXCEPT -{ - return msl(CharT{'G'}); -} - -template -CONSTCD14 -inline -auto -msl(std::tera) NOEXCEPT -{ - return msl(CharT{'T'}); -} - -template -CONSTCD14 -inline -auto -msl(std::peta) NOEXCEPT -{ - return msl(CharT{'P'}); -} - -template -CONSTCD14 -inline -auto -msl(std::exa) NOEXCEPT -{ - return msl(CharT{'E'}); -} - -template -CONSTCD14 -auto -get_units(Period p) -{ - return msl(p) + string_literal{"s"}; -} - -template -CONSTCD14 -auto -get_units(std::ratio<1>) -{ - return string_literal{"s"}; -} - -template -CONSTCD14 -auto -get_units(std::ratio<60>) -{ - return string_literal{"min"}; -} - -template -CONSTCD14 -auto -get_units(std::ratio<3600>) -{ - return string_literal{"h"}; -} #else // __cplusplus < 201402 || (defined(__EDG_VERSION__) && __EDG_VERSION__ <= 411) @@ -8148,6 +7999,7 @@ to_string(std::uint64_t x) } template +inline std::basic_string to_string(std::uint64_t x) { @@ -8182,179 +8034,206 @@ msl(std::ratio) return std::basic_string(1, '[') + to_string(R::num) + CharT{']'}; } +#endif // __cplusplus < 201402 || (defined(__EDG_VERSION__) && __EDG_VERSION__ <= 411) + template +CONSTCD11 inline -std::basic_string -msl(std::atto) +string_literal +msl(std::atto) NOEXCEPT { - return {'a'}; + return string_literal{'a'}; } template +CONSTCD11 inline -std::basic_string -msl(std::femto) +string_literal +msl(std::femto) NOEXCEPT { - return {'f'}; + return string_literal{'f'}; } template +CONSTCD11 inline -std::basic_string -msl(std::pico) +string_literal +msl(std::pico) NOEXCEPT { - return {'p'}; + return string_literal{'p'}; } template +CONSTCD11 inline -std::basic_string -msl(std::nano) +string_literal +msl(std::nano) NOEXCEPT { - return {'n'}; + return string_literal{'n'}; } template +CONSTCD11 inline typename std::enable_if < std::is_same::value, - std::string + string_literal >::type -msl(std::micro) +msl(std::micro) NOEXCEPT { - return "\xC2\xB5"; + return string_literal{'\xC2', '\xB5'}; } template +CONSTCD11 inline typename std::enable_if < !std::is_same::value, - std::basic_string + string_literal >::type -msl(std::micro) +msl(std::micro) NOEXCEPT { - return {CharT(static_cast('\xB5'))}; + return string_literal{CharT{static_cast('\xB5')}}; } template +CONSTCD11 inline -std::basic_string -msl(std::milli) +string_literal +msl(std::milli) NOEXCEPT { - return {'m'}; + return string_literal{'m'}; } template +CONSTCD11 inline -std::basic_string -msl(std::centi) +string_literal +msl(std::centi) NOEXCEPT { - return {'c'}; + return string_literal{'c'}; } template +CONSTCD11 inline -std::basic_string -msl(std::deci) +string_literal +msl(std::deca) NOEXCEPT { - return {'d'}; + return string_literal{'d', 'a'}; } template +CONSTCD11 inline -std::basic_string -msl(std::deca) +string_literal +msl(std::deci) NOEXCEPT { - return {'d', 'a'}; + return string_literal{'d'}; } template +CONSTCD11 inline -std::basic_string -msl(std::hecto) +string_literal +msl(std::hecto) NOEXCEPT { - return {'h'}; + return string_literal{'h'}; } template +CONSTCD11 inline -std::basic_string -msl(std::kilo) +string_literal +msl(std::kilo) NOEXCEPT { - return {'k'}; + return string_literal{'k'}; } template +CONSTCD11 inline -std::basic_string -msl(std::mega) +string_literal +msl(std::mega) NOEXCEPT { - return {'M'}; + return string_literal{'M'}; } template +CONSTCD11 inline -std::basic_string -msl(std::giga) +string_literal +msl(std::giga) NOEXCEPT { - return {'G'}; + return string_literal{'G'}; } template +CONSTCD11 inline -std::basic_string -msl(std::tera) +string_literal +msl(std::tera) NOEXCEPT { - return {'T'}; + return string_literal{'T'}; } template +CONSTCD11 inline -std::basic_string -msl(std::peta) +string_literal +msl(std::peta) NOEXCEPT { - return {'P'}; + return string_literal{'P'}; } template +CONSTCD11 inline -std::basic_string -msl(std::exa) +string_literal +msl(std::exa) NOEXCEPT { - return {'E'}; + return string_literal{'E'}; } template -std::basic_string +CONSTCD11 +inline +auto get_units(Period p) + -> decltype(msl(p) + string_literal{'s'}) { - return msl(p) + CharT{'s'}; + return msl(p) + string_literal{'s'}; } template -std::basic_string +CONSTCD11 +inline +string_literal get_units(std::ratio<1>) { - return {'s'}; + return string_literal{'s'}; } template -std::basic_string -get_units(std::ratio<60>) -{ - return {'m', 'i', 'n'}; -} - -template -std::basic_string +CONSTCD11 +inline +string_literal get_units(std::ratio<3600>) { - return {'h'}; + return string_literal{'h'}; } -#endif // __cplusplus < 201402 || (defined(__EDG_VERSION__) && __EDG_VERSION__ <= 411) + +template +CONSTCD11 +inline +string_literal +get_units(std::ratio<60>) +{ + return string_literal{'m', 'i', 'n'}; +} template > struct make_string; @@ -8424,10 +8303,8 @@ operator<<(std::basic_ostream& os, } // namespace date - #ifdef __GNUC__ # pragma GCC diagnostic pop #endif - #endif // DATE_H diff --git a/test/date_test/durations_output.pass.cpp b/test/date_test/durations_output.pass.cpp new file mode 100644 index 0000000..f4cbac2 --- /dev/null +++ b/test/date_test/durations_output.pass.cpp @@ -0,0 +1,327 @@ +// The MIT License (MIT) +// +// Copyright (c) 2018 Tomasz Kamiński +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + + +#include "date.h" + +#include +#include + +void test_SI() +{ + using namespace std::chrono; + using namespace date; + + std::ostringstream os; + + // atto + { + duration d(13); + os << d; + assert(os.str() == "13as"); + os.str(""); + } + + // femto + { + duration d(13); + os << d; + assert(os.str() == "13fs"); + os.str(""); + } + + // pico + { + duration d(13); + os << d; + assert(os.str() == "13ps"); + os.str(""); + } + + // nano + { + duration d(13); + os << d; + assert(os.str() == "13ns"); + os.str(""); + } + + // mikro + { + duration d(13); + os << d; + assert(os.str() == "13\xC2\xB5s"); + os.str(""); + } + + // milli + { + duration d(13); + os << d; + assert(os.str() == "13ms"); + os.str(""); + } + + // centi + { + duration d(13); + os << d; + assert(os.str() == "13cs"); + os.str(""); + } + + // deci + { + duration d(13); + os << d; + assert(os.str() == "13ds"); + os.str(""); + } + + // seconds + { + duration d(13); + os << d; + assert(os.str() == "13s"); + os.str(""); + } + + // deca + { + duration d(13); + os << d; + assert(os.str() == "13das"); + os.str(""); + } + + // hecto + { + duration d(13); + os << d; + assert(os.str() == "13hs"); + os.str(""); + } + + // kilo + { + duration d(13); + os << d; + assert(os.str() == "13ks"); + os.str(""); + } + + // mega + { + duration d(13); + os << d; + assert(os.str() == "13Ms"); + os.str(""); + } + + // giga + { + duration d(13); + os << d; + assert(os.str() == "13Gs"); + os.str(""); + } + + // tera + { + duration d(13); + os << d; + assert(os.str() == "13Ts"); + os.str(""); + } + + // peta + { + duration d(13); + os << d; + assert(os.str() == "13Ps"); + os.str(""); + } + + // femto + { + duration d(13); + os << d; + assert(os.str() == "13Es"); + os.str(""); + } +} + +void test_calendar() +{ + using namespace std::chrono; + using namespace date; + + std::ostringstream os; + + // minutes + { + minutes d(13); + os << d; + assert(os.str() == "13min"); + os.str(""); + } + + // hours + { + hours d(13); + os << d; + assert(os.str() == "13h"); + os.str(""); + } +} + +void test_integral_scale() +{ + using namespace std::chrono; + using namespace date; + + std::ostringstream os; + + // ratio 123 / 1 + { + duration> d(13); + os << d; + assert(os.str() == "13[123]s"); + os.str(""); + } + + // ratio 100 / 4 = ratio 25 / 1 + { + duration> d(13); + os << d; + assert(os.str() == "13[25]s"); + os.str(""); + } + + // days = ratio 24 * 60 * 60 / 1 = ratio 86400 / 1 + { + days d(13); + os << d; + assert(os.str() == "13[86400]s"); + os.str(""); + } + + // weeks = ratio 7 * 24 * 60 * 60 / 1 = ratio 604800 / 1 + { + weeks d(13); + os << d; + assert(os.str() == "13[604800]s"); + os.str(""); + } + + // years = 146097/400 days = ratio 146097/400 * 24 * 60 * 60 = ratio 31556952 / 1 + { + years d(13); + os << d; + assert(os.str() == "13[31556952]s"); + os.str(""); + } + + // months = 1/12 years = ratio 1/12 * 31556952 = ratio 2629746 / 1 + { + months d(13); + os << d; + assert(os.str() == "13[2629746]s"); + os.str(""); + } +} + +void test_ratio_scale() +{ + using namespace std::chrono; + using namespace date; + + std::ostringstream os; + + // ratio 1 / 2 + { + duration> d(13); + os << d; + assert(os.str() == "13[1/2]s"); + os.str(""); + } + + // ratio 100 / 3 + { + duration> d(13); + os << d; + assert(os.str() == "13[100/3]s"); + os.str(""); + } + + // ratio 100 / 6 = ratio 50 / 3 + { + duration> d(13); + os << d; + assert(os.str() == "13[50/3]s"); + os.str(""); + } +} + +void test_constexpr() +{ + using date::detail::get_units; + + CONSTCD11 auto as = get_units(std::atto{}); + CONSTCD11 auto fs = get_units(std::femto{}); + CONSTCD11 auto ps = get_units(std::pico{}); + CONSTCD11 auto ns = get_units(std::nano{}); + CONSTCD11 auto us = get_units(std::micro{}); + CONSTCD11 auto usw = get_units(std::micro{}); + CONSTCD11 auto ms = get_units(std::milli{}); + CONSTCD11 auto cs = get_units(std::centi{}); + CONSTCD11 auto ds = get_units(std::deci{}); + CONSTCD11 auto s = get_units(std::ratio<1>{}); + CONSTCD11 auto das = get_units(std::deca{}); + CONSTCD11 auto hs = get_units(std::hecto{}); + CONSTCD11 auto ks = get_units(std::kilo{}); + CONSTCD11 auto Ms = get_units(std::mega{}); + CONSTCD11 auto Gs = get_units(std::giga{}); + CONSTCD11 auto Ts = get_units(std::tera{}); + CONSTCD11 auto Ps = get_units(std::peta{}); + CONSTCD11 auto Es = get_units(std::exa{}); + (void)as, (void)fs, (void)ps, (void)ns, (void)usw, (void)us, + (void)ms, (void)cs, (void)ds, (void)s, (void)das, (void)hs, + (void)ks, (void)Ms, (void)Gs, (void)Ts, (void)Ps, (void)Es; + + CONSTCD11 auto min = get_units(std::ratio<60>{}); + CONSTCD11 auto h = get_units(std::ratio<3600>{}); + (void)min, (void)h; + + CONSTCD14 auto integer = get_units(std::ratio<123>{}); + CONSTCD14 auto ratio = get_units(std::ratio<123, 3>{}); + (void)integer, (void)ratio; +} + +int +main() +{ + test_SI(); + test_calendar(); + test_integral_scale(); + test_ratio_scale(); +}