/* * 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 #include #include #include #include #include #include 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 { 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. *

* For example, to convert 10 minutes to milliseconds, use: * TimeUnit.MILLISECONDS.convert(10L, TimeUnit.MINUTES) *

* @param sourceDuration - Duration value to convert. * @param sourceUnit - Unit type of the source duration. * @returns 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 NANOSECONDS.convert(duration, this). * @param duration the duration * @return the converted duration, * or Long.MIN_VALUE if conversion would negatively * overflow, or Long.MAX_VALUE if it would positively overflow. * @see #convert */ long long toNanos( long long duration ) const { return doConvert( this->index, NANOSECONDS.index, duration ); } /** * Equivalent to MICROSECONDS.convert(duration, this). * @param duration the duration * @return the converted duration, * or Long.MIN_VALUE if conversion would negatively * overflow, or Long.MAX_VALUE if it would positively overflow. * @see #convert */ long long toMicros( long long duration ) const { return doConvert( this->index, MICROSECONDS.index, duration ); } /** * Equivalent to MILLISECONDS.convert(duration, this). * @param duration the duration * @return the converted duration, * or Long.MIN_VALUE if conversion would negatively * overflow, or Long.MAX_VALUE if it would positively overflow. * @see #convert */ long long toMillis( long long duration ) const { return doConvert( this->index, MILLISECONDS.index, duration ); } /** * Equivalent to SECONDS.convert(duration, this). * @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 MINUTES.convert(duration, this). * @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 HOURS.convert(duration, this). * @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 DAYS.convert(duration, this). * @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 Object.wait using this time unit. * This is a convenience method that converts timeout arguments * into the form required by the Object.wait method. * *

For example, you could implement a blocking poll * method (see {@link BlockingQueue#poll BlockingQueue.poll}) * using: * *

         *    Object poll( long long timeout, const TimeUnit& unit )
         *
         *      while( empty ) {
         *        unit.timedWait(this, timeout);
         *        ...
         *      }
         *  }
* * @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 Thread.join using this time unit. * This is a convenience method that converts time arguments into the * form required by the Thread.join 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 Thread.sleep using this unit. * This is a convenience method that converts time arguments into the * form required by the Thread.sleep 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. * @returns * 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_*/