A New Interface for C++ std::duration Type

ISO/IEC JTC1 SC22 WG21 N2539 = 08-0049 - 2008-02-25

Paul E. McKenney, paulmck@linux.vnet.ibm.com
Michael Wong, michaelw@ca.ibm.com

Disposition

Consideration of this proposal is deferred until TR2.

Introduction

This document presents a new interface for time durations as proposed by the POSIX C++ Binding Working Group at the 2008 Bellevue meeting. This document is based on the latest Working Draft (n2521), Why duration Should Be a Type in C++0x (n2526), and Custom Time Duration Support (n2498). It accepts the findings in n2526 for a need to minimize the number of distinct interfaces for time duration, and represents a follow-up on the alternatives as proposed in n2526.

Rationale

See Why duration Should Be a Type in C++0x (n2526).

Prior Approaches

See See Why duration Should Be a Type in C++0x (n2526).

Proposal

We propose maintaining a single implementation-defined type that holds time durations, with member functions that permit conversions from that implementation-defined type to and from nanoseconds, microseconds, milliseconds, seconds, minutes, and hours. We strongly suggest that implementations use the same units for duration as are used for system_time. We further propose that this type occupy the std namespace rather then a part of std::thread namespace, as we see this as a generally useful type rather then one that is specifically useful to thread.


namespace std {
    class duration
    {
    public:
	// traits information
        typedef implementation-defined tick_type;
        static const tick_type ticks_per_second = implementation-defined;
        static const tick_type seconds_per_tick = implementation-defined;
        static const bool is_subsecond = implementation-defined;
	typedef enum duration_unit {
		duration_native,
		duration_nanoseconds, duration_microseconds,
		duration_milliseconds, duration_seconds,
		duration_minutes, duration_hours
	} duration_unit;

	// construct/copy/destroy
	duration(duration_unit u, long long t = 0);
	duration(duration_unit u, double t = 0.0);
	duration(long long tps, long long stp, long long t = 0);
	duration(long long tps, long long stp, double t = 0.0);

	// modifiers
	duration& operator+=(const duration &d);
	duration& operator-=(const duration &d);
	duration& operator*=(long multiplier);
	duration& operator*=(double multiplier);
	duration& operator/=(long divisor);
	duration& operator/=(double divisor);

	// observers
        tick_type count() const;
	long long nanoseconds() const;
	double d_nanoseconds() const;
	long long microseconds() const;
	double d_microseconds() const;
	long long milliseconds() const;
	double d_milliseconds() const;
	long long seconds() const;
	double d_seconds() const;
	long long minutes() const;
	double d_minutes() const;
	long long hours() const;
	double d_hours() const;
	long long user_defined(long long tps, long long stp) const;
	double d_user_defined(long long tps, long long stp) const;

	// operations
	tick_type operator-() const;
    };
}

tick_type

Implementation-defined type that defines the underlying timer tick.

ticks_per_second

The number of ticks per second or zero when the number of ticks per second is less than one and the number of seconds per tick is integral.

seconds_per_tick

The number of seconds per tick or zero when the number of seconds per tick is less than one and the number of ticks per second is integral.

seconds_per_tick

The number of seconds per tick or zero when the number of seconds per tick is less than one and the number of ticks per second is integral.

is_subsecond

This is equal to 1 when seconds_per_tick==0.

duration_unit

Allows the user to specify a limited number of predefined time units, including nanoseconds, microseconds, milliseconds, seconds, minutes, hours, and an implementation-defined native time unit.

duration (constructors)

Allows constructing a native-time value from either a standard (nanoseconds through hours) or user-defined time value. The user can specify either an integral or a floating-point value. The tps and stp arguments are analogous to the ticks_per_second and seconds_per_tick members.

operator +=

Increments the specified duration object by the duration object passed in as the argument. The duration constructors may be used to add time durations in any desired units.

operator -=

Decrements the specified duration object by the duration object passed in as the argument. The duration constructors may be used to subtract time durations in any desired units.

operator *=

Multiplies the specified duration object by the specified integral or floating-point argument.

operator /=

Divides the specified duration object by the specified integral or floating-point argument.

count

Returns the implementation-defined number of ticks.

nanoseconds, d_nanoseconds

Returns the duration in nanoseconds.

microseconds, d_microseconds

Returns the duration in microseconds.

milliseconds, d_milliseconds

Returns the duration in milliseconds.

seconds, d_seconds

Returns the duration in seconds.

minutes, d_minutes

Returns the duration in minutes.

hours, d_hours

Returns the duration in hours.

user_defined, d_user_defined

Returns the duration in user-defined units.

Differences From n2521

This proposal differs from the language in n2521 in the following respects:

  1. There are no separate types for the different time units. This proposal uses an enum which must be specified on the constructor to avoid unit-omission bugs.
  2. There are no conversion operators from one time unit to another, for example, from microseconds to milliseconds. This effect could be obtained via conversion through the duration class, but division by the constant 1,000 should suffice given that the ratio of microseconds to milliseconds is unlikely to change in the foreseeable future. This latter approach also has the advantage of avoiding roundoff errors due to coarse-grained implementations.
  3. This proposal provides the additive, multiplicative, constancy of units, and library coherence and interoperability desiderata called out in Why duration Should Be a Type in C++0x (n2526).
  4. There are floating-point arguments to the constructor, permitting easy specification of fractions of time units, while also permitting the implementation to avoid unnecessary round-off errors even in face of non-integral tick frequencies.
  5. This proposal allows the full range of rational-number time bases to be specified. For example, specifying ticks_per_second==3 and seconds_per_tick==2 would result in three ticks every two seconds.

Alternatives Considered

Appendix: User-Defined Literals to Specify Durations

There are at least two ways to apply user-defined literals to specify durations:

  1. Specify a separate type for each unit type. To avoid an explosion of conversion methods, specify a superclass with implementation-defined units. For each subclass, there is a method to convert to the superclass and another to convert from the superclass. With this infrastructure in place, each subclass implements a User-defined literals (n2378) suffixes.
  2. Fold all units into the duration type. This places the conversions into the user-defined literal operators.

One issue with both of these approaches is that user-defined literals have a global namespace.