blob: 777441564a1202268a1d1e38e13178017bf9c1c4 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _DECAF_UTIL_CONCURRENT_TIMEUNIT_H_
#define _DECAF_UTIL_CONCURRENT_TIMEUNIT_H_
#include <string>
#include <decaf/util/Config.h>
#include <decaf/lang/Comparable.h>
#include <decaf/util/concurrent/Synchronizable.h>
#include <decaf/lang/exceptions/IllegalArgumentException.h>
#include <decaf/lang/exceptions/InterruptedException.h>
#include <decaf/lang/exceptions/NullPointerException.h>
namespace decaf {
namespace lang {
class Thread;
}
namespace util {
namespace concurrent {
/**
* A TimeUnit represents time durations at a given unit of granularity and
* provides utility methods to convert across units, and to perform timing
* and delay operations in these units. A TimeUnit does not maintain time
* information, but only helps organize and use time representations that
* may be maintained separately across various contexts. A nanosecond is
* defined as one thousandth of a microsecond, a microsecond as one thousandth
* of a millisecond, a millisecond as one thousandth of a second, a minute as
* sixty seconds, an hour as sixty minutes, and a day as twenty four hours.
*
* A TimeUnit is mainly used to inform time-based methods how a given timing
* parameter should be interpreted. For example, the following code will timeout
* in 50 milliseconds if the lock is not available:
*
* Lock lock = ...;
* if ( lock.tryLock( 50, TimeUnit.MILLISECONDS ) ) ...
*
* while this code will timeout in 50 seconds:
*
* Lock lock = ...;
* if ( lock.tryLock( 50, TimeUnit.SECONDS ) ) ...
*
* Note however, that there is no guarantee that a particular timeout implementation
* will be able to notice the passage of time at the same granularity as the given
* TimeUnit.
*/
class DECAF_API TimeUnit : public decaf::lang::Comparable<TimeUnit> {
private:
/** This TimeUnit's index */
int index;
/** Name of the Unit being represented. */
std::string name;
/** Array of Time Unit multipliers */
static const long long multipliers[];
public:
/** The Actual TimeUnit enumerations */
static const TimeUnit NANOSECONDS;
static const TimeUnit MICROSECONDS;
static const TimeUnit MILLISECONDS;
static const TimeUnit SECONDS;
static const TimeUnit MINUTES;
static const TimeUnit HOURS;
static const TimeUnit DAYS;
/** The An Array of TimeUnit Instances */
static const TimeUnit* const values[];
protected:
/**
* Hidden Constructor, this class can not be instantiated directly.
* @param index - Index into the Time Unit set.
* @param name - Name of the unit type being represented.
*/
TimeUnit( int index, const std::string& name );
public:
virtual ~TimeUnit() {}
/**
* Convert the given time duration in the given unit to this unit. Conversions
* from finer to coarser granularities truncate, so lose precision. For example
* converting 999 milliseconds to seconds results in 0. Conversions from coarser
* to finer granularities with arguments that would numerically overflow saturate
* to Long.MIN_VALUE if negative or Long.MAX_VALUE if positive.
* <p>
* For example, to convert 10 minutes to milliseconds, use:
* TimeUnit.MILLISECONDS.convert(10L, TimeUnit.MINUTES)
* <p>
* @param sourceDuration - Duration value to convert.
* @param sourceUnit - Unit type of the source duration.
* @return the converted duration in this unit, or Long.MIN_VALUE if conversion
* would negatively overflow, or Long.MAX_VALUE if it would positively overflow.
*/
long long convert( long long sourceDuration, const TimeUnit& sourceUnit ) const;
/**
* Equivalent to <tt>NANOSECONDS.convert(duration, this)</tt>.
* @param duration the duration
* @return the converted duration,
* or <tt>Long.MIN_VALUE</tt> if conversion would negatively
* overflow, or <tt>Long.MAX_VALUE</tt> if it would positively overflow.
* @see #convert
*/
long long toNanos( long long duration ) const {
return doConvert( this->index, NANOSECONDS.index, duration );
}
/**
* Equivalent to <tt>MICROSECONDS.convert(duration, this)</tt>.
* @param duration the duration
* @return the converted duration,
* or <tt>Long.MIN_VALUE</tt> if conversion would negatively
* overflow, or <tt>Long.MAX_VALUE</tt> if it would positively overflow.
* @see #convert
*/
long long toMicros( long long duration ) const {
return doConvert( this->index, MICROSECONDS.index, duration );
}
/**
* Equivalent to <tt>MILLISECONDS.convert(duration, this)</tt>.
* @param duration the duration
* @return the converted duration,
* or <tt>Long.MIN_VALUE</tt> if conversion would negatively
* overflow, or <tt>Long.MAX_VALUE</tt> if it would positively overflow.
* @see #convert
*/
long long toMillis( long long duration ) const {
return doConvert( this->index, MILLISECONDS.index, duration );
}
/**
* Equivalent to <tt>SECONDS.convert(duration, this)</tt>.
* @param duration the duration
* @return the converted duration.
* @see #convert
*/
long long toSeconds( long long duration ) const {
return doConvert( this->index, SECONDS.index, duration );
}
/**
* Equivalent to <tt>MINUTES.convert(duration, this)</tt>.
* @param duration the duration
* @return the converted duration.
* @see #convert
*/
long long toMinutes( long long duration ) const {
return doConvert( this->index, MINUTES.index, duration );
}
/**
* Equivalent to <tt>HOURS.convert(duration, this)</tt>.
* @param duration the duration
* @return the converted duration.
* @see #convert
*/
long long toHours( long long duration ) const {
return doConvert( this->index, HOURS.index, duration );
}
/**
* Equivalent to <tt>DAYS.convert(duration, this)</tt>.
* @param duration the duration
* @return the converted duration.
* @see #convert
*/
long long toDays( long long duration ) const {
return doConvert( this->index, DAYS.index, duration );
}
/**
* Perform a timed <tt>Object.wait</tt> using this time unit.
* This is a convenience method that converts timeout arguments
* into the form required by the <tt>Object.wait</tt> method.
*
* <p>For example, you could implement a blocking <tt>poll</tt>
* method (see {@link BlockingQueue#poll BlockingQueue.poll})
* using:
*
* <pre>
* Object poll( long long timeout, const TimeUnit& unit )
*
* while( empty ) {
* unit.timedWait(this, timeout);
* ...
* }
* }</pre>
*
* @param obj the object to wait on
* @param timeout the maximum time to wait.
*
* @throws InterruptedException if interrupted while waiting.
* @throws NullPointerException if the Synchronizable object is null.
*
* @see Synchronizable#wait( long long, long long )
*/
void timedWait( Synchronizable* obj, long long timeout ) const;
/**
* Perform a timed <tt>Thread.join</tt> using this time unit.
* This is a convenience method that converts time arguments into the
* form required by the <tt>Thread.join</tt> method.
*
* @param thread the thread to wait for
* @param timeout the maximum time to wait
*
* @throws InterruptedException if interrupted while waiting.
* @throws NullPointerException if the thread object is null.
*
* @see Thread#join( long long, long long )
*/
void timedJoin( decaf::lang::Thread* thread, long long timeout );
/**
* Perform a <tt>Thread.sleep</tt> using this unit.
* This is a convenience method that converts time arguments into the
* form required by the <tt>Thread.sleep</tt> method.
* @param timeout the minimum time to sleep
* @see Thread#sleep
*/
void sleep( long long timeout ) const;
/**
* Converts the TimeUnit type to the Name of the TimeUnit.
* @return String name of the TimeUnit
*/
virtual std::string toString() const;
public: // Static Methods
/**
* Returns the TimeUnit constant of this type with the specified name. The
* string must match exactly an identifier used to declare an TimeUnit constant
* in this type. (Extraneous whitespace characters are not permitted.)
*
* @param name
* The Name of the TimeUnit constant to be returned.
* @return
* A constant reference to the TimeUnit Constant with the given name.
* @throws IllegalArgumentException
* if this enum type has no constant with the specified name
*/
static const TimeUnit& valueOf( const std::string& name );
public:
virtual int compareTo( const TimeUnit& value ) const;
virtual bool equals( const TimeUnit& value ) const;
virtual bool operator==( const TimeUnit& value ) const;
virtual bool operator<( const TimeUnit& value ) const;
private:
/* Perform the actual conversion */
long long doConvert( int srcIndex, int destIndex, long long duration ) const;
/*
* Utility method to compute the excess-nanosecond argument to
* wait, sleep, join.
*/
int excessNanos( long long time, long long ms ) const;
/**
* Scale d by m, checking for overflow.
* @param duration - The amount of time to scale by the multiplier.
* @param multiplier - The scaling factor.
* @param overflow - The value at which d * m would cause an overflow.
*/
static long long scale( long long duration, long long multiplier, long long overflow );
};
}}}
#endif /*_DECAF_UTIL_CONCURRENT_TIMEUNIT_H_*/