diff options
author | Daniel Wilhelm <daniel@wili.li> | 2015-10-02 14:52:04 +0200 |
---|---|---|
committer | Daniel Wilhelm <daniel@wili.li> | 2015-10-02 14:52:04 +0200 |
commit | 1845c028b8cb8496d1d78f0da738120e1c31401a (patch) | |
tree | adf9fb436aea09be367aef8ed3b6cdbf6a46e34c /zen/int64.h | |
parent | 6.7 (diff) | |
download | FreeFileSync-1845c028b8cb8496d1d78f0da738120e1c31401a.tar.gz FreeFileSync-1845c028b8cb8496d1d78f0da738120e1c31401a.tar.bz2 FreeFileSync-1845c028b8cb8496d1d78f0da738120e1c31401a.zip |
6.8
Diffstat (limited to 'zen/int64.h')
-rw-r--r-- | zen/int64.h | 222 |
1 files changed, 18 insertions, 204 deletions
diff --git a/zen/int64.h b/zen/int64.h index f658e034..4183c8da 100644 --- a/zen/int64.h +++ b/zen/int64.h @@ -7,251 +7,65 @@ #ifndef FFS_LARGE_64_BIT_INTEGER_H_INCLUDED #define FFS_LARGE_64_BIT_INTEGER_H_INCLUDED -#include <cassert> -#include <limits> #include <cstdint> -#include <cstdint> -#include <ostream> -#include "assert_static.h" -#include "type_tools.h" #ifdef ZEN_WIN #include "win.h" #endif -/* -zen::Int64/zen::UInt64: wrapper classes around std::int64_t/std::uint64_t - - - default initialization with 0 - - debug runtime overflow/underflow checks - - safe and explicit semantics: no unsafe type conversions - - safe conversion to and from Windows 64-bit integers - - specializes std::numeric_limits - - support stream operator<< and operator>> -*/ - namespace zen { -template <class T, class U> inline -void checkRange(U value) -{ - //caveat: std::numeric_limits<T>::min returns minimum positive(!) number for T = double, while behaving correctly for integer types... sigh - assert(double(std::numeric_limits<T>::lowest()) <= double(value) && //new with C++11! - double(std::numeric_limits<T>::max() ) >= double(value)); -} - -class Int64 -{ -public: - //safe implicit conversions - Int64() : value(0) {} - Int64(const Int64& rhs) : value(rhs.value) {} - template <class T> - Int64(T rhs, typename EnableIf<IsSignedInt<T>::value&& sizeof(T) <= sizeof(std::int64_t)>::Type* = nullptr) : - value(static_cast<std::int64_t>(rhs)) {} - - //unsafe explicit but checked conversion for all other integer types - template <class T> explicit Int64(T rhs, typename EnableIf<!(IsSignedInt<T>::value&& sizeof(T) <= sizeof(std::int64_t))>::Type* = nullptr) : - value(static_cast<std::int64_t>(rhs)) { checkRange<std::int64_t>(rhs); } - - Int64& operator=(const Int64& rhs) { value = rhs.value; return *this; } - #ifdef ZEN_WIN - Int64(DWORD low, LONG high) +inline + std::int64_t get64BitInt(DWORD low, LONG high) { - assert_static(sizeof(low) + sizeof(high) == sizeof(value)); + static_assert(sizeof(low) + sizeof(high) == sizeof(std::int64_t), ""); LARGE_INTEGER cvt = {}; cvt.LowPart = low; cvt.HighPart = high; - value = cvt.QuadPart; - } - LONG getHi() const - { - LARGE_INTEGER cvt = {}; - cvt.QuadPart = value; - return cvt.HighPart; + return cvt.QuadPart; } - DWORD getLo() const - { - LARGE_INTEGER cvt = {}; - cvt.QuadPart = value; - return cvt.LowPart; - } -#endif - - Int64& operator+=(const Int64& rhs) { checkRange<std::int64_t>(double(value) + rhs.value); value += rhs.value; return *this; } - Int64& operator-=(const Int64& rhs) { checkRange<std::int64_t>(double(value) - rhs.value); value -= rhs.value; return *this; } - Int64& operator*=(const Int64& rhs) { checkRange<std::int64_t>(double(value) * rhs.value); value *= rhs.value; return *this; } - Int64& operator/=(const Int64& rhs) { assert(rhs.value != 0); value /= rhs.value; return *this; } - Int64& operator%=(const Int64& rhs) { assert(rhs.value != 0); value %= rhs.value; return *this; } - Int64& operator&=(const Int64& rhs) { value &= rhs.value; return *this;} - Int64& operator|=(const Int64& rhs) { value |= rhs.value; return *this;} - Int64& operator<<=(int rhs) { assert(rhs < 0 || (value << rhs) >> rhs == value); value <<= rhs; return *this; } - Int64& operator>>=(int rhs) { assert(rhs > 0 || (value >> rhs) << rhs == value); value >>= rhs; return *this; } - Int64 operator-() const { return -value; } - - inline friend bool operator==(const Int64& lhs, const Int64& rhs) { return lhs.value == rhs.value; } - inline friend bool operator!=(const Int64& lhs, const Int64& rhs) { return lhs.value != rhs.value; } - inline friend bool operator< (const Int64& lhs, const Int64& rhs) { return lhs.value < rhs.value; } - inline friend bool operator> (const Int64& lhs, const Int64& rhs) { return lhs.value > rhs.value; } - inline friend bool operator<=(const Int64& lhs, const Int64& rhs) { return lhs.value <= rhs.value; } - inline friend bool operator>=(const Int64& lhs, const Int64& rhs) { return lhs.value >= rhs.value; } - - //checked conversion to arbitrary target integer type - template <class T> inline friend T to(Int64 number) { checkRange<T>(number.value); return static_cast<T>(number.value); } - template <class T> inline friend std::basic_istream<T>& operator>>(std::basic_istream<T>& lhs, Int64& rhs) { lhs >> rhs.value; return lhs; } - template <class T> inline friend std::basic_ostream<T>& operator<<(std::basic_ostream<T>& lhs, const Int64& rhs) { lhs << rhs.value; return lhs; } +std::int64_t get64BitInt(std::uint64_t low, std::int64_t high) = delete; -private: - std::int64_t value; -}; -inline Int64 operator+ (const Int64& lhs, const Int64& rhs) { return Int64(lhs) += rhs; } -inline Int64 operator- (const Int64& lhs, const Int64& rhs) { return Int64(lhs) -= rhs; } -inline Int64 operator* (const Int64& lhs, const Int64& rhs) { return Int64(lhs) *= rhs; } -inline Int64 operator/ (const Int64& lhs, const Int64& rhs) { return Int64(lhs) /= rhs; } -inline Int64 operator% (const Int64& lhs, const Int64& rhs) { return Int64(lhs) %= rhs; } -inline Int64 operator& (const Int64& lhs, const Int64& rhs) { return Int64(lhs) &= rhs; } -inline Int64 operator| (const Int64& lhs, const Int64& rhs) { return Int64(lhs) |= rhs; } -inline Int64 operator<<(const Int64& lhs, int rhs) { return Int64(lhs) <<= rhs; } -inline Int64 operator>>(const Int64& lhs, int rhs) { return Int64(lhs) >>= rhs; } - - -class UInt64 -{ -public: - //safe implicit conversions - UInt64() : value(0) {} - UInt64(const UInt64& rhs) : value(rhs.value) {} - template <class T> - UInt64(T rhs, typename EnableIf<IsUnsignedInt<T>::value&& sizeof(T) <= sizeof(std::uint64_t)>::Type* = nullptr) : - value(static_cast<std::uint64_t>(rhs)) {} - - //unsafe explicit but checked conversion for all other integer types - template <class T> explicit UInt64(T rhs, typename EnableIf<!(IsUnsignedInt<T>::value&& sizeof(T) <= sizeof(std::uint64_t))>::Type* = nullptr) : - value(static_cast<std::uint64_t>(rhs)) { checkRange<std::uint64_t>(rhs); } - - UInt64& operator=(const UInt64& rhs) { value = rhs.value; return *this; } - -#ifdef ZEN_WIN - UInt64(DWORD low, DWORD high) +inline +std::uint64_t get64BitUInt(DWORD low, DWORD high) { - assert_static(sizeof(low) + sizeof(high) == sizeof(value)); + static_assert(sizeof(low) + sizeof(high) == sizeof(std::uint64_t), ""); ULARGE_INTEGER cvt = {}; cvt.LowPart = low; cvt.HighPart = high; - value = cvt.QuadPart; - } - DWORD getHi() const - { - ULARGE_INTEGER cvt = {}; - cvt.QuadPart = value; - return cvt.HighPart; - } - DWORD getLo() const - { - ULARGE_INTEGER cvt = {}; - cvt.QuadPart = value; - return cvt.LowPart; + return cvt.QuadPart; } -#endif - - UInt64& operator+=(const UInt64& rhs) { checkRange<std::uint64_t>(double(value) + rhs.value); value += rhs.value; return *this; } - UInt64& operator-=(const UInt64& rhs) { checkRange<std::uint64_t>(double(value) - rhs.value); value -= rhs.value; return *this; } - UInt64& operator*=(const UInt64& rhs) { checkRange<std::uint64_t>(double(value) * rhs.value); value *= rhs.value; return *this; } - UInt64& operator/=(const UInt64& rhs) { assert(rhs.value != 0); value /= rhs.value; return *this; } - UInt64& operator%=(const UInt64& rhs) { assert(rhs.value != 0); value %= rhs.value; return *this; } - UInt64& operator&=(const UInt64& rhs) { value &= rhs.value; return *this;} - UInt64& operator|=(const UInt64& rhs) { value |= rhs.value; return *this;} - UInt64& operator<<=(int rhs) { assert(rhs < 0 || (value << rhs) >> rhs == value); value <<= rhs; return *this; } - UInt64& operator>>=(int rhs) { assert(rhs > 0 || (value >> rhs) << rhs == value); value >>= rhs; return *this; } - - inline friend bool operator==(const UInt64& lhs, const UInt64& rhs) { return lhs.value == rhs.value; } - inline friend bool operator!=(const UInt64& lhs, const UInt64& rhs) { return lhs.value != rhs.value; } - inline friend bool operator< (const UInt64& lhs, const UInt64& rhs) { return lhs.value < rhs.value; } - inline friend bool operator> (const UInt64& lhs, const UInt64& rhs) { return lhs.value > rhs.value; } - inline friend bool operator<=(const UInt64& lhs, const UInt64& rhs) { return lhs.value <= rhs.value; } - inline friend bool operator>=(const UInt64& lhs, const UInt64& rhs) { return lhs.value >= rhs.value; } - - //checked conversion to arbitrary target integer type - template <class T> friend T to(UInt64 number); - - template <class T> inline friend std::basic_istream<T>& operator>>(std::basic_istream<T>& lhs, UInt64& rhs) { lhs >> rhs.value; return lhs; } - template <class T> inline friend std::basic_ostream<T>& operator<<(std::basic_ostream<T>& lhs, const UInt64& rhs) { lhs << rhs.value; return lhs; } - -private: - std::uint64_t value; -}; - -template <class T> inline T to(UInt64 number) { checkRange<T>(number.value); return static_cast<T>(number.value); } //Clang 3.2 doesn't properly handle inline-friends defined in class definition -inline UInt64 operator+ (const UInt64& lhs, const UInt64& rhs) { return UInt64(lhs) += rhs; } -inline UInt64 operator- (const UInt64& lhs, const UInt64& rhs) { return UInt64(lhs) -= rhs; } -inline UInt64 operator* (const UInt64& lhs, const UInt64& rhs) { return UInt64(lhs) *= rhs; } -inline UInt64 operator/ (const UInt64& lhs, const UInt64& rhs) { return UInt64(lhs) /= rhs; } -inline UInt64 operator% (const UInt64& lhs, const UInt64& rhs) { return UInt64(lhs) %= rhs; } -inline UInt64 operator& (const UInt64& lhs, const UInt64& rhs) { return UInt64(lhs) &= rhs; } -inline UInt64 operator| (const UInt64& lhs, const UInt64& rhs) { return UInt64(lhs) |= rhs; } -inline UInt64 operator<<(const UInt64& lhs, int rhs) { return UInt64(lhs) <<= rhs; } -inline UInt64 operator>>(const UInt64& lhs, int rhs) { return UInt64(lhs) >>= rhs; } +std::int64_t get64BitUInt(std::uint64_t low, std::uint64_t high) = delete; -template <> inline UInt64 to(Int64 number) { checkRange<std::uint64_t>(number.value); return UInt64(number.value); } -template <> inline Int64 to(UInt64 number) { checkRange<std:: int64_t>(number.value); return Int64(number.value); } - -#ifdef ZEN_WIN //convert FILETIME (number of 100-nanosecond intervals since January 1, 1601 UTC) // to time_t (number of seconds since Jan. 1st 1970 UTC) // //FAT32 time is preserved exactly: FAT32 -> toTimeT -> tofiletime -> FAT32 inline -Int64 toTimeT(const FILETIME& ft) +std::int64_t filetimeToTimeT(const FILETIME& ft) { - return to<Int64>(UInt64(ft.dwLowDateTime, ft.dwHighDateTime) / 10000000U) - Int64(3054539008UL, 2); + return static_cast<std::int64_t>(get64BitUInt(ft.dwLowDateTime, ft.dwHighDateTime) / 10000000U) - get64BitInt(3054539008UL, 2); //caveat: signed/unsigned arithmetics! //timeshift between ansi C time and FILETIME in seconds == 11644473600s } inline -FILETIME toFileTime(const Int64& utcTime) -{ - const UInt64 fileTimeLong = to<UInt64>(utcTime + Int64(3054539008UL, 2)) * 10000000U; - const FILETIME output = { fileTimeLong.getLo(), fileTimeLong.getHi() }; +FILETIME timetToFileTime(std::int64_t utcTime) +{ + ULARGE_INTEGER cvt = {}; + cvt.QuadPart = (utcTime + get64BitInt(3054539008UL, 2)) * 10000000U; //caveat: signed/unsigned arithmetics! + + const FILETIME output = { cvt.LowPart, cvt.HighPart }; return output; } #endif } -//specialize numeric limits -namespace std -{ -assert_static(std::numeric_limits<std:: int64_t>::is_specialized); -assert_static(std::numeric_limits<std::uint64_t>::is_specialized); - -template <> class numeric_limits<zen::Int64> : public numeric_limits<std::int64_t> -{ -public: - static zen::Int64 min() throw() { return numeric_limits<std::int64_t>::min(); } - static zen::Int64 max() throw() { return numeric_limits<std::int64_t>::max(); } -}; - -template <> class numeric_limits<zen::UInt64> : public numeric_limits<std::uint64_t> -{ -public: - static zen::UInt64 min() throw() { return numeric_limits<std::uint64_t>::min(); } - static zen::UInt64 max() throw() { return numeric_limits<std::uint64_t>::max(); } -}; -} - -/* -//specialize zen type trait -namespace zen -> we cannot mix signed/unsigned in general arithmetic operations -> we'll use the ostream-approach -{ -template <> struct IsUnsignedInt<UInt64> : StaticBool<true> {}; -template <> struct IsSignedInt <Int64> : StaticBool<true> {}; -} -*/ #endif //FFS_LARGE_64_BIT_INTEGER_H_INCLUDED |