diff --git a/chrono_io.h b/chrono_io.h new file mode 100644 index 0000000..3182c64 --- /dev/null +++ b/chrono_io.h @@ -0,0 +1,668 @@ +#ifndef CHRONO_IO_H +#define CHRONO_IO_H + +// The MIT License (MIT) +// +// Copyright (c) 2016 Howard Hinnant +// +// 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. +// +// Our apologies. When the previous paragraph was written, lowercase had not yet +// been invented (that woud involve another several millennia of evolution). +// We did not mean to shout. + +#include +#include +#include +#include +#include +#include +#include + +namespace date +{ + +namespace detail +{ + +#if __cplusplus >= 201402 + +template +class string_literal +{ + CharT p_[N]; + +public: + using const_iterator = const CharT*; + + string_literal(string_literal const&) = default; + string_literal& operator=(string_literal const&) = delete; + + template > + constexpr string_literal(CharT c) noexcept + : p_{c} + { + } + + constexpr string_literal(const CharT(&a)[N]) noexcept + : p_{} + { + for (std::size_t i = 0; i < N; ++i) + p_[i] = a[i]; + } + + template > + constexpr string_literal(const char(&a)[N]) noexcept + : p_{} + { + for (std::size_t i = 0; i < N; ++i) + p_[i] = a[i]; + } + + template {}>> + constexpr string_literal(string_literal const& a) noexcept + : p_{} + { + for (std::size_t i = 0; i < N; ++i) + p_[i] = a[i]; + } + + template > + constexpr 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]; + } + + constexpr const CharT* data() const noexcept {return p_;} + constexpr std::size_t size() const noexcept {return N-1;} + + constexpr const_iterator begin() const noexcept {return p_;} + constexpr const_iterator end() const noexcept {return p_ + N-1;} + + constexpr CharT const& operator[](std::size_t n) const noexcept + { + return p_[n]; + } + + template + friend + std::basic_ostream& + operator<<(std::basic_ostream& os, const string_literal& s) + { + return os << s.p_; + } +}; + +template +constexpr +inline +string_literal, + 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}}; +} + +template +constexpr +inline +string_literal +msl(const CharT(&a)[N]) noexcept +{ + return string_literal{a}; +} + +template {} || + std::is_same{} || + std::is_same{} || + std::is_same{}>> +constexpr +inline +string_literal +msl(CharT c) noexcept +{ + return string_literal{c}; +} + +constexpr +std::size_t +to_string_len(std::intmax_t i) +{ + std::size_t r = 0; + do + { + i /= 10; + ++r; + } while (i > 0); + return r; +} + +template +constexpr +inline +std::enable_if_t +< + N < 10, + string_literal +> +msl() noexcept +{ + return msl(char(N % 10 + '0')); +} + +template +constexpr +inline +std::enable_if_t +< + 10 <= N, + string_literal +> +msl() noexcept +{ + return msl() + msl(char(N % 10 + '0')); +} + +template +constexpr +inline +std::enable_if_t +< + std::ratio::type::den != 1, + string_literal::type::num) + + to_string_len(std::ratio::type::den) + 4> +> +msl(std::ratio) noexcept +{ + using R = typename std::ratio::type; + return msl(CharT{'['}) + msl() + msl(CharT{'/'}) + + msl() + msl(CharT{']'}); +} + +template +constexpr +inline +std::enable_if_t +< + std::ratio::type::den == 1, + string_literal::type::num) + 3> +> +msl(std::ratio) noexcept +{ + using R = typename std::ratio::type; + return msl(CharT{'['}) + msl() + msl(CharT{']'}); +} + +template +constexpr +inline +auto +msl(std::atto) noexcept +{ + return msl(CharT{'a'}); +} + +template +constexpr +inline +auto +msl(std::femto) noexcept +{ + return msl(CharT{'f'}); +} + +template +constexpr +inline +auto +msl(std::pico) noexcept +{ + return msl(CharT{'p'}); +} + +template +constexpr +inline +auto +msl(std::nano) noexcept +{ + return msl(CharT{'n'}); +} + +template +constexpr +inline +std::enable_if_t +< + std::is_same{}, + string_literal +> +msl(std::micro) noexcept +{ + return string_literal{"\xC2\xB5"}; +} + +template +constexpr +inline +std::enable_if_t +< + !std::is_same{}, + string_literal +> +msl(std::micro) noexcept +{ + return string_literal{CharT{static_cast('\xB5')}}; +} + +template +constexpr +inline +auto +msl(std::milli) noexcept +{ + return msl(CharT{'m'}); +} + +template +constexpr +inline +auto +msl(std::centi) noexcept +{ + return msl(CharT{'c'}); +} + +template +constexpr +inline +auto +msl(std::deci) noexcept +{ + return msl(CharT{'d'}); +} + +template +constexpr +inline +auto +msl(std::deca) noexcept +{ + return string_literal{"da"}; +} + +template +constexpr +inline +auto +msl(std::hecto) noexcept +{ + return msl(CharT{'h'}); +} + +template +constexpr +inline +auto +msl(std::kilo) noexcept +{ + return msl(CharT{'k'}); +} + +template +constexpr +inline +auto +msl(std::mega) noexcept +{ + return msl(CharT{'M'}); +} + +template +constexpr +inline +auto +msl(std::giga) noexcept +{ + return msl(CharT{'G'}); +} + +template +constexpr +inline +auto +msl(std::tera) noexcept +{ + return msl(CharT{'T'}); +} + +template +constexpr +inline +auto +msl(std::peta) noexcept +{ + return msl(CharT{'P'}); +} + +template +constexpr +inline +auto +msl(std::exa) noexcept +{ + return msl(CharT{'E'}); +} + +template +constexpr +auto +get_units(const std::chrono::duration&) +{ + return msl(Period{}) + string_literal{"s"}; +} + +template +constexpr +auto +get_units(const std::chrono::duration>&) +{ + return string_literal{"s"}; +} + +template +constexpr +auto +get_units(const std::chrono::duration>&) +{ + return string_literal{"min"}; +} + +template +constexpr +auto +get_units(const std::chrono::duration>&) +{ + return string_literal{"h"}; +} + +#else // __cplusplus < 201402 + +inline +std::string +to_string(std::uint64_t x) +{ + return std::to_string(x); +} + +template +std::basic_string +to_string(std::uint64_t x) +{ + auto y = std::to_string(x); + return std::basic_string(y.begin(), y.end()); +} + +template +constexpr +inline +typename std::enable_if +< + std::ratio::type::den != 1, + std::basic_string +>::type +msl(std::ratio) noexcept +{ + using R = typename std::ratio::type; + return std::basic_string(1, '[') + to_string(R::num) + CharT{'/'} + + to_string(R::den) + CharT{']'}; +} + +template +constexpr +inline +typename std::enable_if +< + std::ratio::type::den == 1, + std::basic_string +>::type +msl(std::ratio) noexcept +{ + using R = typename std::ratio::type; + return std::basic_string(1, '[') + to_string(R::num) + CharT{']'}; +} + +template +constexpr +inline +std::basic_string +msl(std::atto) noexcept +{ + return {1, 'a'}; +} + +template +constexpr +inline +std::basic_string +msl(std::femto) noexcept +{ + return {1, 'f'}; +} + +template +constexpr +inline +std::basic_string +msl(std::pico) noexcept +{ + return {1, 'p'}; +} + +template +constexpr +inline +std::basic_string +msl(std::nano) noexcept +{ + return {1, 'n'}; +} + +template +constexpr +inline +typename std::enable_if +< + std::is_same::value, + std::string +>::type +msl(std::micro) noexcept +{ + return "\xC2\xB5"; +} + +template +constexpr +inline +typename std::enable_if +< + !std::is_same::value, + std::basic_string +>::type +msl(std::micro) noexcept +{ + return {1, CharT(static_cast('\xB5'))}; +} + +template +constexpr +inline +std::basic_string +msl(std::milli) noexcept +{ + return {1, 'm'}; +} + +template +constexpr +inline +std::basic_string +msl(std::centi) noexcept +{ + return {1, 'c'}; +} + +template +constexpr +inline +std::basic_string +msl(std::deci) noexcept +{ + return {1, 'd'}; +} + +template +constexpr +inline +std::basic_string +msl(std::deca) noexcept +{ + return {'d', 'a'}; +} + +template +constexpr +inline +std::basic_string +msl(std::hecto) noexcept +{ + return {1, 'h'}; +} + +template +constexpr +inline +std::basic_string +msl(std::kilo) noexcept +{ + return {1, 'k'}; +} + +template +constexpr +inline +std::basic_string +msl(std::mega) noexcept +{ + return {1, 'M'}; +} + +template +constexpr +inline +std::basic_string +msl(std::giga) noexcept +{ + return {1, 'G'}; +} + +template +constexpr +inline +std::basic_string +msl(std::tera) noexcept +{ + return {1, 'T'}; +} + +template +constexpr +inline +std::basic_string +msl(std::peta) noexcept +{ + return {1, 'P'}; +} + +template +constexpr +inline +std::basic_string +msl(std::exa) noexcept +{ + return {1, 'E'}; +} + +template +std::basic_string +get_units(const std::chrono::duration&) +{ + return msl(Period{}) + CharT{'s'}; +} + +template +std::basic_string +get_units(const std::chrono::duration>&) +{ + return {1, 's'}; +} + +template +std::basic_string +get_units(const std::chrono::duration>&) +{ + return {'m', 'i', 'n'}; +} + +template +std::basic_string +get_units(const std::chrono::duration>&) +{ + return {1, 'h'}; +} + +#endif // __cplusplus >= 201402 + +} // namespace detail + +template +inline +std::basic_ostream& +operator<<(std::basic_ostream& os, + const std::chrono::duration& d) +{ + using namespace std::chrono; + return os << d.count() + << detail::get_units(duration{}); +} + +} // namespace date + +#endif // CHRONO_IO_H