// boost/chrono/stopwatches/stopwatch.hpp -----------------------------// // Copyright 2011 Vicente J. Botet Escriba // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // See http://www.boost.org/libs/libs/chrono/stopwatches for documentation. #ifndef BOOST_CHRONO_STOPWATCHES_STOPWATCH_HPP #define BOOST_CHRONO_STOPWATCHES_STOPWATCH_HPP #include <boost/chrono/config.hpp> #include <boost/chrono/stopwatches/stopwatch_scoped.hpp> #include <boost/chrono/stopwatches/collectors/no_memory.hpp> // default laps_collector #include <boost/chrono/stopwatches/dont_start.hpp> #include <boost/chrono/system_clocks.hpp> // default_clock #include <boost/chrono/detail/system.hpp> #include <utility> namespace boost { namespace chrono { /** * A stopwatch is a model of @c Stopwatch taking as parameters the @c Clock and the @c LapsCollector. * * The main difference respect to a @c simple_stopwatch is that the user can stop it. * Each sequence of start-stop results in a new elapsed duration sample that is provided to the LapsCollector. * * It is up to the LapsCollector to do whatever it wants with each sample. * A LapCollector must define a store(duration const&) and a clear() functions. * * The library provides LapsCollectors that forget the sample, store the * last one, cummulates the samples in an accumulator set or store them in a container. * For simplicity the default LapCollector is the one that forget the samples. * * Even if it is preferable to use process or thread wide clocks, * the default of the Clock parameter is high_resolution_clock, * as it is the single one ensured on all platforms. */ template<typename Clock=high_resolution_clock, typename LapsCollector=no_memory<typename Clock::duration> > class stopwatch { public: typedef LapsCollector laps_collector; typedef Clock clock; typedef typename Clock::duration duration; typedef typename Clock::time_point time_point; typedef typename Clock::rep rep; typedef typename Clock::period period; BOOST_STATIC_CONSTEXPR bool is_steady = Clock::is_steady; /** * Default constructor. * * Effects: Starts the stopwatch. * Post-conditions: is_running(). */ stopwatch() : start_(duration::zero()), running_(false), laps_collector_() { start(); } #if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING /** * Default constructor. * * Effects: Assign the error code if any internal error occur while retrieving the current time. * Effects: Starts the stopwatch. * Post-conditions: is_running() if no error occur. */ explicit stopwatch( system::error_code & ec ) : start_(duration::zero()), running_(false), laps_collector_() { start(ec); } #endif /** * Not starting constructor. * * Effects: Don't starts the stopwatch. * Post-conditions: ! is_running() if no error occur. */ explicit stopwatch( const dont_start_t& ) : start_(duration::zero()), running_(false), laps_collector_() { } /** * Starting constructor from a LapsCollector instance. * * Effects: Copies the LapsCollector. Starts the stopwatch. * Post-conditions: is_running() if no error occur. * * Remark: The LapsCollector is copied and owned by the stopwatch. */ explicit stopwatch( laps_collector const& acc ) : start_(duration::zero()), running_(false), laps_collector_(acc) { start(); } #if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING /** * Starting constructor from a LapsCollector instance. * * Effects: Assign the error code if any internal error occur while retrieving the current time. * Effects: Copies the LapsCollector. Starts the stopwatch. * Post-conditions: is_running() if no error occur. * * Remark: The LapsCollector is copied and owned by the stopwatch. */ explicit stopwatch( laps_collector const& acc, system::error_code & ec ) : start_(duration::zero()), running_(false), laps_collector_(acc) { start(ec); } #endif /** * Not starting constructor from a LapsCollector instance. * * Effects: Copies the LapsCollector. Don't starts the stopwatch. * Post-conditions: ! is_running() if no error occur. * * Remark: The LapsCollector is copied and owned by the stopwatch. */ stopwatch( laps_collector const& acc, const dont_start_t& ) : start_(duration::zero()), running_(false), laps_collector_(acc) { } /** * Destructor. * * Effects: Do nothing. */ ~stopwatch() BOOST_NOEXCEPT { } /** * Restart the stopwatch. * * Effects: Assign the error code if any internal error occur while retrieving the current time. * Effects: As if stop(); start() were called, but ensuring that the start time is the same as the stop time. * * Post-conditions: is_running() if no error occur. */ void restart() { time_point tmp = clock::now(); if (is_running()) { laps_collector_.store(tmp - start_); } else { running_ = true; } start_ = tmp; } #if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING /** * Restart the stopwatch. * * Effects: Assign the error code if any internal error occur while retrieving the current time. * Effects: As if stop(); start() were called, but ensuring that the start time is the same as the stop time. * * Post-conditions: is_running() if no error occur. */ void restart( system::error_code & ec ) { time_point tmp = clock::now(ec); if (!BOOST_CHRONO_IS_THROWS(ec) && ec) return; if (is_running()) { laps_collector_.store(tmp - start_); } else { running_ = true; } start_ = tmp; } #endif /** * Start the stopwatch. * * Effects: Memorize the current time. * * Post-conditions: is_running(). */ void start() { start_ = clock::now(); running_ = true; } #if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING /** * Start the stopwatch. * * Effects: Assign the error code if any internal error occur while retrieving the current time. * Effects: Memorize the current time. * * Post-conditions: @c is_running() if no error occur. */ void start( system::error_code & ec ) { time_point tmp = clock::now(ec); if (!BOOST_CHRONO_IS_THROWS(ec) && ec) return; start_ = tmp; running_ = true; } #endif /** * Start the stopwatch. * * Requires: is_running(). * Effects: Stores the elapsed time since start time into the LapCollector. * * Throws: Any exception that the LapCollector can throw. * * Post-conditions: !is_running() if no error occur. */ void stop() { if (is_running()) { laps_collector_.store(clock::now() - start_); start_ = time_point(duration::zero()); running_ = false; } } #if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING /** * Start the stopwatch. * * Requires: is_running(). * Effects: Assign the error code if any internal error occur while retrieving the current time. * Effects: Stores the elapsed time since start time into the LapCollector if no internal error occurs. * * Throws: Any exception that the LapCollector can Throw. * * Post-conditions: !is_running() if no error occur. */ void stop( system::error_code & ec ) { if (is_running()) { time_point tmp = clock::now(ec); if (!BOOST_CHRONO_IS_THROWS(ec) && ec) return; laps_collector_.store(tmp - start_); start_ = time_point(duration::zero()); running_ = false; } } #endif /** * States if the Stopwatch is running. */ bool is_running() const { return running_; } /** * Elapsed time getter for the current lap. * * Returns: the elapsed time since the last start if no internal error occur. * */ duration elapsed_current_lap() const { if (is_running()) { return clock::now() - start_; } else { return duration::zero(); } } #if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING /** * Elapsed time getter for the current lap. * * Effects: Assign the error code if any internal error occur while retrieving the current time. * * Returns: the elapsed time since the start if no internal error occur. * */ duration elapsed_current_lap( system::error_code & ec ) const { if (is_running()) { time_point tmp = clock::now(ec); if (!BOOST_CHRONO_IS_THROWS(ec) && ec) return duration::zero(); return tmp - start_; } else { return duration::zero(); } } #endif /** * Elapsed time getter. * * Effects: Assign the error code if any internal error occur while retrieving the current time. * * Returns: the elapsed time since the start if no internal error occur. * */ duration elapsed() const { return laps_collector_.elapsed()+elapsed_current_lap(); } #if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING /** * Elapsed time getter. * * Effects: Assign the error code if any internal error occur while retrieving the current time. * * Returns: the elapsed time since the start if no internal error occur. * */ duration elapsed( system::error_code & ec ) const { duration tmp = elapsed_current_lap(ec); if (!BOOST_CHRONO_IS_THROWS(ec) && ec) return duration::zero(); return laps_collector_.elapsed() + tmp; } #endif /** * Elapsed time for the last lap. * * Returns: the elapsed time of the last lap. * */ duration last() const { return laps_collector_.last(); } /** * Resets the stopwatch. * * Effects: Resets the LapCollector. * * Post-conditions: !is_running() if no error occur. * */ void reset() { laps_collector_.reset(); running_ = false; start_ = time_point(duration::zero()); } /** * LapsCollector getter. * * Returns: the LapCollector instance. * */ laps_collector const& get_laps_collector() BOOST_NOEXCEPT { return laps_collector_; } /** * Useful typedef for scoped run */ typedef stopwatch_runner<stopwatch<Clock, LapsCollector> > scoped_run; /** * Useful typedef for scoped stop */ typedef stopwatch_stopper<stopwatch<Clock, LapsCollector> > scoped_stop; private: time_point start_; bool running_; laps_collector laps_collector_; }; } // namespace chrono } // namespace boost #endif // header