TimeValueC.h (9048B)
1 /** @file 2 @brief Header defining a dependency-free, cross-platform substitute for 3 struct timeval 4 5 Must be c-safe! 6 7 @date 2014 8 9 @author 10 Sensics, Inc. 11 <http://sensics.com/osvr> 12 */ 13 14 /* 15 // Copyright 2014 Sensics, Inc. 16 // 17 // Licensed under the Apache License, Version 2.0 (the "License"); 18 // you may not use this file except in compliance with the License. 19 // You may obtain a copy of the License at 20 // 21 // http://www.apache.org/licenses/LICENSE-2.0 22 // 23 // Unless required by applicable law or agreed to in writing, software 24 // distributed under the License is distributed on an "AS IS" BASIS, 25 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 26 // See the License for the specific language governing permissions and 27 // limitations under the License. 28 */ 29 30 #ifndef INCLUDED_TimeValueC_h_GUID_A02C6917_124D_4CB3_E63E_07F2DA7144E9 31 #define INCLUDED_TimeValueC_h_GUID_A02C6917_124D_4CB3_E63E_07F2DA7144E9 32 33 /* Internal Includes */ 34 #include <osvr/Util/Export.h> 35 #include <osvr/Util/APIBaseC.h> 36 #include <osvr/Util/AnnotationMacrosC.h> 37 #include <osvr/Util/PlatformConfig.h> 38 #include <osvr/Util/StdInt.h> 39 #include <osvr/Util/BoolC.h> 40 41 /* Library/third-party includes */ 42 /* none */ 43 44 /* Standard includes */ 45 /* none */ 46 47 OSVR_EXTERN_C_BEGIN 48 49 /** @defgroup UtilTime Timestamp interaction 50 @ingroup Util 51 52 This provides a level of interoperability with struct timeval on systems 53 with that facility. It provides a neutral representation with sufficiently 54 large types. 55 56 For C++ code, use of std::chrono or boost::chrono instead is recommended. 57 58 Note that these time values may not necessarily correlate between processes 59 so should not be used to estimate or measure latency, etc. 60 61 @{ 62 */ 63 64 /** @brief The signed integer type storing the seconds in a struct 65 OSVR_TimeValue */ 66 typedef int64_t OSVR_TimeValue_Seconds; 67 /** @brief The signed integer type storing the microseconds in a struct 68 OSVR_TimeValue */ 69 typedef int32_t OSVR_TimeValue_Microseconds; 70 71 /** @brief Standardized, portable parallel to struct timeval for representing 72 both absolute times and time intervals. 73 74 Where interpreted as an absolute time, its meaning is to be considered the 75 same as that of the POSIX struct timeval: 76 time since 00:00 Coordinated Universal Time (UTC), January 1, 1970. 77 78 For best results, please keep normalized. Output of all functions here 79 is normalized. 80 */ 81 typedef struct OSVR_TimeValue { 82 /** @brief Seconds portion of the time value. */ 83 OSVR_TimeValue_Seconds seconds; 84 /** @brief Microseconds portion of the time value. */ 85 OSVR_TimeValue_Microseconds microseconds; 86 } OSVR_TimeValue; 87 88 #ifdef OSVR_HAVE_STRUCT_TIMEVAL 89 /** @brief Gets the current time in the TimeValue. Parallel to gettimeofday. */ 90 OSVR_UTIL_EXPORT void osvrTimeValueGetNow(OSVR_OUT OSVR_TimeValue* dest) 91 OSVR_FUNC_NONNULL((1)); 92 93 struct timeval; /* forward declaration */ 94 95 /** @brief Converts from a TimeValue struct to your system's struct timeval. 96 97 @param dest Pointer to an empty struct timeval for your platform. 98 @param src A pointer to an OSVR_TimeValue you'd like to convert from. 99 100 If either parameter is NULL, the function will return without doing 101 anything. 102 */ 103 OSVR_UTIL_EXPORT void osvrTimeValueToStructTimeval( 104 OSVR_OUT struct timeval* dest, OSVR_IN_PTR const OSVR_TimeValue* src) 105 OSVR_FUNC_NONNULL((1, 2)); 106 107 /** @brief Converts from a TimeValue struct to your system's struct timeval. 108 @param dest An OSVR_TimeValue destination pointer. 109 @param src Pointer to a struct timeval you'd like to convert from. 110 111 The result is normalized. 112 113 If either parameter is NULL, the function will return without doing 114 anything. 115 */ 116 OSVR_UTIL_EXPORT void osvrStructTimevalToTimeValue( 117 OSVR_OUT OSVR_TimeValue* dest, OSVR_IN_PTR const struct timeval* src) 118 OSVR_FUNC_NONNULL((1, 2)); 119 #endif 120 121 /** @brief "Normalizes" a time value so that the absolute number of microseconds 122 is less than 1,000,000, and that the sign of both components is the same. 123 124 @param tv Address of a struct TimeValue to normalize in place. 125 126 If the given pointer is NULL, this function returns without doing anything. 127 */ 128 OSVR_UTIL_EXPORT void osvrTimeValueNormalize(OSVR_INOUT_PTR OSVR_TimeValue* tv) 129 OSVR_FUNC_NONNULL((1)); 130 131 /** @brief Sums two time values, replacing the first with the result. 132 133 @param tvA Destination and first source. 134 @param tvB second source 135 136 If a given pointer is NULL, this function returns without doing anything. 137 138 Both parameters are expected to be in normalized form. 139 */ 140 OSVR_UTIL_EXPORT void osvrTimeValueSum(OSVR_INOUT_PTR OSVR_TimeValue* tvA, 141 OSVR_IN_PTR const OSVR_TimeValue* tvB) 142 OSVR_FUNC_NONNULL((1, 2)); 143 144 /** @brief Computes the difference between two time values, replacing the first 145 with the result. 146 147 Effectively, `*tvA = *tvA - *tvB` 148 149 @param tvA Destination and first source. 150 @param tvB second source 151 152 If a given pointer is NULL, this function returns without doing anything. 153 154 Both parameters are expected to be in normalized form. 155 */ 156 OSVR_UTIL_EXPORT void osvrTimeValueDifference( 157 OSVR_INOUT_PTR OSVR_TimeValue* tvA, OSVR_IN_PTR const OSVR_TimeValue* tvB) 158 OSVR_FUNC_NONNULL((1, 2)); 159 160 /** @brief Compares two time values (assumed to be normalized), returning 161 the same values as strcmp 162 163 @return <0 if A is earlier than B, 0 if they are the same, and >0 if A 164 is later than B. 165 */ 166 OSVR_UTIL_EXPORT int osvrTimeValueCmp(OSVR_IN_PTR const OSVR_TimeValue* tvA, 167 OSVR_IN_PTR const OSVR_TimeValue* tvB) 168 OSVR_FUNC_NONNULL((1, 2)); 169 170 OSVR_EXTERN_C_END 171 172 /** @brief Compute the difference between the two time values, returning the 173 duration as a double-precision floating-point number of seconds. 174 175 Effectively, `ret = *tvA - *tvB` 176 177 @param tvA first source. 178 @param tvB second source 179 @return Duration of timespan in seconds (floating-point) 180 */ 181 OSVR_INLINE double osvrTimeValueDurationSeconds( 182 OSVR_IN_PTR const OSVR_TimeValue* tvA, 183 OSVR_IN_PTR const OSVR_TimeValue* tvB) { 184 OSVR_TimeValue A = *tvA; 185 osvrTimeValueDifference(&A, tvB); 186 double dt = A.seconds + A.microseconds / 1000000.0; 187 return dt; 188 } 189 190 /** @brief True if A is later than B */ 191 OSVR_INLINE OSVR_CBool 192 osvrTimeValueGreater(OSVR_IN_PTR const OSVR_TimeValue* tvA, 193 OSVR_IN_PTR const OSVR_TimeValue* tvB) { 194 if (!tvA || !tvB) { 195 return OSVR_FALSE; 196 } 197 return ((tvA->seconds > tvB->seconds) || 198 (tvA->seconds == tvB->seconds && 199 tvA->microseconds > tvB->microseconds)) 200 ? OSVR_TRUE 201 : OSVR_FALSE; 202 } 203 204 #ifdef __cplusplus 205 206 # include <cmath> 207 # include <cassert> 208 209 /// Returns true if the time value is normalized. Typically used in assertions. 210 inline bool osvrTimeValueIsNormalized(const OSVR_TimeValue& tv) { 211 # ifdef __APPLE__ 212 // apparently standard library used on mac only has floating-point abs? 213 return std::abs(double(tv.microseconds)) < 1000000 && 214 # else 215 return std::abs(tv.microseconds) < 1000000 && 216 # endif 217 ((tv.seconds > 0) == (tv.microseconds > 0)); 218 } 219 220 /// True if A is later than B 221 inline bool osvrTimeValueGreater(const OSVR_TimeValue& tvA, 222 const OSVR_TimeValue& tvB) { 223 assert(osvrTimeValueIsNormalized(tvA) && 224 "First timevalue argument to comparison was not normalized!"); 225 assert(osvrTimeValueIsNormalized(tvB) && 226 "Second timevalue argument to comparison was not normalized!"); 227 return (tvA.seconds > tvB.seconds) || 228 (tvA.seconds == tvB.seconds && tvA.microseconds > tvB.microseconds); 229 } 230 231 /// Operator > overload for time values 232 inline bool operator>(const OSVR_TimeValue& tvA, const OSVR_TimeValue& tvB) { 233 return osvrTimeValueGreater(tvA, tvB); 234 } 235 236 /// Operator < overload for time values 237 inline bool operator<(const OSVR_TimeValue& tvA, const OSVR_TimeValue& tvB) { 238 // Change the order of arguments before forwarding. 239 return osvrTimeValueGreater(tvB, tvA); 240 } 241 242 /// Operator == overload for time values 243 inline bool operator==(const OSVR_TimeValue& tvA, const OSVR_TimeValue& tvB) { 244 assert(osvrTimeValueIsNormalized(tvA) && 245 "First timevalue argument to equality comparison was not normalized!"); 246 assert( 247 osvrTimeValueIsNormalized(tvB) && 248 "Second timevalue argument to equality comparison was not normalized!"); 249 return (tvA.seconds == tvB.seconds) && (tvA.microseconds == tvB.microseconds); 250 } 251 /// Operator == overload for time values 252 inline bool operator!=(const OSVR_TimeValue& tvA, const OSVR_TimeValue& tvB) { 253 assert(osvrTimeValueIsNormalized(tvA) && 254 "First timevalue argument to " 255 "inequality comparison was not " 256 "normalized!"); 257 assert(osvrTimeValueIsNormalized(tvB) && 258 "Second timevalue argument to " 259 "inequality comparison was not " 260 "normalized!"); 261 return (tvA.seconds != tvB.seconds) || (tvA.microseconds != tvB.microseconds); 262 } 263 #endif 264 265 /** @} */ 266 267 #endif