From 5a9b44a37a8573b0d89665c0221e1f28da91c442 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Kami=C5=84ski?= Date: Wed, 22 Nov 2017 22:01:02 +0100 Subject: [PATCH] Implemented test for casting non-wall clocks and detecting that clocks cannot be casted. Added test that detects if clock_cast(Source) properly SFINAEs if clock's are not castable, this includes test for steady_clock that is not castable to any wall-clock. Secondly added steady_based_clock based on steady_clock (as name indicates), that clock_cast may be extended to clock non-related to wall-time (sys/utc) using conversion traits. Final example is pair of ambiguous clocks (amb1/amb2_clock) that can convert to each other either using sys_clock or utc_clock. Then the conversion from amb2 to amb1 is disambiguated via trait specialization. --- test/tz_test/noncatsable_clock_casts.pass.cpp | 247 ++++++++++++++++++ 1 file changed, 247 insertions(+) create mode 100644 test/tz_test/noncatsable_clock_casts.pass.cpp diff --git a/test/tz_test/noncatsable_clock_casts.pass.cpp b/test/tz_test/noncatsable_clock_casts.pass.cpp new file mode 100644 index 0000000..a59e1d0 --- /dev/null +++ b/test/tz_test/noncatsable_clock_casts.pass.cpp @@ -0,0 +1,247 @@ +// The MIT License (MIT) +// +// Copyright (c) 2017 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 "tz.h" +#include +#include + +template +struct is_clock_castable + : std::false_type +{}; + +template +struct is_clock_castable(typename SourceClock::time_point()), void())> + : std::true_type +{}; + + +//Clock based on steady clock, not related to wall time (sys_clock/utc_clock) +struct steady_based_clock +{ + using duration = std::chrono::steady_clock::duration; + using rep = duration::rep; + using period = duration::period; + using time_point = std::chrono::time_point; + + static time_point now() + { + return time_point(std::chrono::steady_clock::now().time_since_epoch()); + } +}; + +//Traits that allow conversion between steady_clock and steady_based clock +//Does not use wall-time clocks as rally (sys/utc) +namespace date +{ + template<> + struct clock_time_conversion + { + template + std::chrono::time_point + operator()(std::chrono::time_point const& tp) const + { + using res = std::chrono::time_point; + return res(tp.time_since_epoch()); + } + }; + + template<> + struct clock_time_conversion + { + template + std::chrono::time_point + operator()(std::chrono::time_point const& tp) const + { + using res = std::chrono::time_point; + return res(tp.time_since_epoch()); + } + }; +} + +//Ambigous clocks both providing to/from_sys and to/from_utc +//They are mock_ups just returning zero time_point +struct amb1_clock +{ + using duration = std::chrono::seconds; + using rep = duration::rep; + using period = duration::period; + using time_point = std::chrono::time_point; + + static time_point now() + { + return {}; + } + + template + static + std::chrono::time_point + to_sys(std::chrono::time_point const&) + { + return {}; + } + + template + static + std::chrono::time_point + from_sys(std::chrono::time_point const&) + { + return {}; + } + + template + static + std::chrono::time_point + to_utc(std::chrono::time_point const&) + { + return {}; + } + + template + static + std::chrono::time_point + from_utc(std::chrono::time_point const&) + { + return {}; + } +}; + +struct amb2_clock +{ + using duration = std::chrono::seconds; + using rep = duration::rep; + using period = duration::period; + using time_point = std::chrono::time_point; + + static time_point now() + { + return {}; + } + + template + static + std::chrono::time_point + to_sys(std::chrono::time_point const&) + { + return {}; + } + + template + static + std::chrono::time_point + from_sys(std::chrono::time_point const&) + { + return {}; + } + + template + static + std::chrono::time_point + to_utc(std::chrono::time_point const&) + { + return {}; + } + + template + static + std::chrono::time_point + from_utc(std::chrono::time_point const&) + { + return {}; + } +}; + +namespace date +{ + //Disambiguates that sys_clock is preffered + template<> + struct clock_time_conversion + { + template + std::chrono::time_point + operator()(std::chrono::time_point const& tp) const + { + return amb1_clock::from_sys(amb2_clock::to_sys(tp)); + } + }; +} + +int +main() +{ + using namespace date; + using namespace std::chrono; + using sys_clock = std::chrono::system_clock; + + //steady_clock (must be different that sys_clock) + static_assert(is_clock_castable::value, "steady_clock -> steady_clock"); + static_assert(!is_clock_castable::value, "steady_clock -> sys_clock"); + static_assert(!is_clock_castable::value, "sys_clock -> steady_clock"); + static_assert(!is_clock_castable::value, "steady_clock -> utc_clock"); + static_assert(!is_clock_castable::value, "utc_clock -> steady_clock"); + static_assert(!is_clock_castable::value, "steady_clock -> tai_clock"); + static_assert(!is_clock_castable::value, "tai_clock -> steady_clock"); + + //steady_based_clock (unrelated to sys_clock and utc_clocks) + static_assert(is_clock_castable::value, "steady_based_clock -> steady_based_clock"); + static_assert(!is_clock_castable::value, "steady_based_clock -> sys_clock"); + static_assert(!is_clock_castable::value, "sys_clock -> steady_based_clock"); + static_assert(!is_clock_castable::value, "steady_based_clock -> utc_clock"); + static_assert(!is_clock_castable::value, "utc_clock -> steady_based_clock"); + static_assert(!is_clock_castable::value, "steady_based_clock -> tai_clock"); + static_assert(!is_clock_castable::value, "tai_clock -> steady_based_clock"); + + //steady_based <-> steady_clock + { + auto s1 = steady_clock::time_point(steady_clock::duration(200)); + auto s2 = steady_based_clock::time_point(steady_based_clock::duration(200)); + + assert(clock_cast(s1) == s2); + assert(clock_cast(s2) == s1); + } + + //ambX <-> sys/utc works as one rally can be used in each case, or one lead to quicker conversione + static_assert(is_clock_castable::value, "amb1_clock -> amb1_clock"); + static_assert(is_clock_castable::value, "amb1_clock -> sys_clock"); + static_assert(is_clock_castable::value, "sys_clock -> amb1_clock"); + static_assert(is_clock_castable::value, "amb1_clock -> utc_clock"); + static_assert(is_clock_castable::value, "utc_clock -> amb1_clock"); + static_assert(is_clock_castable::value, "amb1_clock -> tai_clock"); + static_assert(is_clock_castable::value, "tai_clock -> amb1_clock"); + static_assert(is_clock_castable::value, "amb1_clock -> tai_clock"); + static_assert(is_clock_castable::value, "gps_clock -> amb1_clock"); + static_assert(is_clock_castable::value, "amb2_clock -> amb2_clock"); + static_assert(is_clock_castable::value, "amb2_clock -> sys_clock"); + static_assert(is_clock_castable::value, "sys_clock -> amb2_clock"); + static_assert(is_clock_castable::value, "amb2_clock -> utc_clock"); + static_assert(is_clock_castable::value, "utc_clock -> amb2_clock"); + static_assert(is_clock_castable::value, "amb2_clock -> tai_clock"); + static_assert(is_clock_castable::value, "tai_clock -> amb2_clock"); + static_assert(is_clock_castable::value, "amb2_clock -> tai_clock"); + static_assert(is_clock_castable::value, "gps_clock -> amb2_clock"); + + //amb1 -> amb2: ambigous because can either go trough sys_clock or utc_clock + static_assert(!is_clock_castable::value, "amb1_clock -> amb2_clock"); + + //amb2 -> amb1: disambiguated via trait specialization + static_assert(is_clock_castable::value, "amb2_clock -> amb1_clock"); +}