// bslmt_saturatedtimeconversionimputil.h -*-C++-*- // ---------------------------------------------------------------------------- // NOTICE // // This component is not up to date with current BDE coding standards, and // should not be used as an example for new development. // ---------------------------------------------------------------------------- #ifndef INCLUDED_BSLMT_SATURATEDTIMECONVERSIONIMPUTIL #define INCLUDED_BSLMT_SATURATEDTIMECONVERSIONIMPUTIL #include <bsls_ident.h> BSLS_IDENT("$Id: $") //@PURPOSE: Provide special narrowing conversions for time types. // //@CLASSES: // bslmt::SaturatedTimeConversionImpUtil: saturating time conversions. // //@SEE_ALSO: // //@DESCRIPTION: This component defines a namespace containing static functions // that perform narrowing conversions on time-related types, // 'bslmt::SaturatedTimeConversionImpUtil'. The provided conversions // "saturate", meaning that for input values outside the representable range of // the destination variable, the destination variable will be set to its // maximum or minimum value (whichever is closer to the input value). Such // saturating conversions are typically used to implement functions with a // time-out (e.g., 'bslmt::Condition::timedWait') where a user-supplied // time-out must be converted to a different time type before calling a // system-library function. In such situations it is often simpler, safer, and // within contract to perform a saturating conversion, rather than either // return an error status or define complex undefined behavior for the // function. // ///Conversion to Milliseconds ///-------------------------- // This component defines an overloaded function named 'toMillisec'. In // addition to the saturating behavior defined above, 'toMillisec' may also // involve a loss of precision but without a concomitant loss of value. In // particular, the converted value will be the smallest representable value // greater than or equal to the original value. // // For example, when 'bsls::TimeInterval(0, 1234567)' is converted to an // 'unsigned int' using 'toMillisec', the result is 2 since 1234567 nanoseconds // includes a fractional millisecond. // ///Usage ///----- // Suppose we need to assign a value held in a 'bsls::TimeInterval' to an // 'unsigned int', where the 'unsigned int' is to contain an equivalent time // interval expressed in milliseconds. A 'bsls::TimeInterval' is able to // represent intervals that are outside the range of intervals that can be // represented by an 'unsigned int' number of milliseconds (e.g., any negative // time interval). 'bslmt::SaturatedTimeConversionImpUtil' handles values // outside the representable range of the destination type by "saturating", // that is values outside the representable range of the destination type will // be assigned the maximum or minimum representable value of the destination // type (whichever is closer to the source value). // // First, we define variables of our source ('bsls::TimeInterval') and // destination ('unsigned int') types: //.. // unsigned int destinationInterval; // bsls::TimeInterval sourceInterval; //.. // Then, we try a value that does not require saturation and observe that // 'toMillisec' converts it without modification (beyond loss of precision): //.. // sourceInterval.setInterval(4, 321000000); // bslmt::SaturatedTimeConversionImpUtil::toMillisec( // &destinationInterval, sourceInterval); // assert(4321 == destinationInterval); //.. // Next, we calculate the maximum value that can be represented in an // 'unsigned int' number of milliseconds, and verify that converting an // equivalent 'bsls::TimeInterval' does not modify the value: //.. // const unsigned int maxDestinationInterval = // bsl::numeric_limits<unsigned int>::max(); // bsls::TimeInterval maximumTimeInterval( // maxDestinationInterval / 1000, // (maxDestinationInterval % 1000) * 1000 * 1000); // bslmt::SaturatedTimeConversionImpUtil::toMillisec( // &destinationInterval, maximumTimeInterval); // assert(maxDestinationInterval == destinationInterval); //.. // Now, we attempt to convert a value greater than the maximum representable in // an 'unsigned int' milliseconds and verify that the resulting value is the // maximum representable 'unsigned int' value: //.. // bsls::TimeInterval aboveMaxInterval = maximumTimeInterval + // bsls::TimeInterval(0, 1000 * 1000); // bslmt::SaturatedTimeConversionImpUtil::toMillisec( // &destinationInterval, aboveMaxInterval); // assert(maxDestinationInterval == destinationInterval); //.. // Next, we try a value less than 0 and observe the result of the saturated // conversion is 0 (the minimum representable value): //.. // bsls::TimeInterval belowMinimumInterval(-1, 0); // bslmt::SaturatedTimeConversionImpUtil::toMillisec( // &destinationInterval, belowMinimumInterval); // assert(0 == destinationInterval); //.. // Finally, when we convert a 'bsls::TimeInterval' containing a fractional // millisecond using 'toMillisec', the converted value is greater than the // input value: //.. // bsls::TimeInterval piMSec(0, 3141593); // 'pi' millseconds // unsigned int mSec; // bslmt::SaturatedTimeConversionImpUtil::toMillisec(&mSec, piMSec); // assert(4 == mSec); //.. #include <bslscm_version.h> #include <bslmt_platform.h> #include <bslmf_assert.h> #include <bslmf_issame.h> #include <bsls_platform.h> #include <bsls_timeinterval.h> #include <bsls_types.h> #include <bsl_limits.h> #include <bsl_ctime.h> #include <time.h> // POSIX timespec #ifdef BSLS_PLATFORM_OS_DARWIN #include <mach/clock_types.h> // for 'mach_timespec_t' #endif namespace BloombergLP { namespace bslmt { // ==================================== // class SaturatedTimeConversionImpUtil // ==================================== struct SaturatedTimeConversionImpUtil { // This 'struct' provides a namespace for utility functions that convert // time values between different time representations, and "saturate" when // values are outside the range of values that may be represented in the // destination type (meaning that values above the maximum representable // value of the result type are set to the maximum value of the result // type, and values below the minimum representable value of the result // type are set to the minimum value for the result type). // TYPES // Here we define type 'TimeSpec' -- an alias to 'timespec' on Unix, but // defined as a struct on Windows, to guarantee that 'TimeSpec' exists on // all platforms. #ifdef BSLMT_PLATFORM_POSIX_THREADS typedef timespec TimeSpec; #else struct TimeSpec { // Provide type for Windows platform bsls::Types::Int64 tv_sec; int tv_nsec; }; #endif // CLASS METHODS #if BSLS_PLATFORM_OS_DARWIN static void toTimeSpec(mach_timespec_t *dst, const bsls::TimeInterval& src); #endif static void toTimeSpec(TimeSpec *dst, const bsls::TimeInterval& src); // Assign to the specified 'dst' the value of the specified 'src', and // if 'src' is less than the lowest representable value of '*dst', set // '*dst' to the minimum value it can represent, and if 'src' is // greater than the highest representable value of '*dst', set '*dst' // to the maximum value that it can represent. static void toTimeT(bsl::time_t *dst, const bsls::Types::Int64 src); // Assign to the specified 'dst' the value of the specified 'src', and // if 'src' is less than the lowest representable 'time_t' value, set // 'dst' to the minimum 'time_t' value, and if 'src' is greater than // the highest representable 'time_t' value, set 'dst' to the maximum // 'time_t' value. static void toMillisec(unsigned int *dst, const bsls::TimeInterval& src); static void toMillisec(unsigned long *dst, const bsls::TimeInterval& src); static void toMillisec(bsls::Types::Uint64 *dst, const bsls::TimeInterval& src); // Assign to the specified 'dst' the value of the specified 'src' // converted to milliseconds, and if that value is a negative time // interval, set 'dst' to 0, and if that value is greater than the // maximum representable value of 'dst' set 'dst' to its maximum // representable value. See {Conversion to Milliseconds}. }; } // close package namespace } // close enterprise namespace #endif // ---------------------------------------------------------------------------- // Copyright 2015 Bloomberg Finance L.P. // // Licensed 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. // ----------------------------- END-OF-FILE ----------------------------------