diff -r 000000000000 -r 6474c204b198 mfbt/Casting.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mfbt/Casting.h Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,202 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* Cast operations to supplement the built-in casting operations. */ + +#ifndef mozilla_Casting_h +#define mozilla_Casting_h + +#include "mozilla/Assertions.h" +#include "mozilla/TypeTraits.h" + +#include + +namespace mozilla { + +/** + * Return a value of type |To|, containing the underlying bit pattern of |from|. + * + * |To| and |From| must be types of the same size; be careful of cross-platform + * size differences, or this might fail to compile on some but not all + * platforms. + */ +template +inline To +BitwiseCast(const From from) +{ + static_assert(sizeof(From) == sizeof(To), + "To and From must have the same size"); + union { + From from; + To to; + } u; + u.from = from; + return u.to; +} + +namespace detail { + +enum ToSignedness { ToIsSigned, ToIsUnsigned }; +enum FromSignedness { FromIsSigned, FromIsUnsigned }; + +template::value ? FromIsSigned : FromIsUnsigned, + ToSignedness = IsSigned::value ? ToIsSigned : ToIsUnsigned> +struct BoundsCheckImpl; + +// Implicit conversions on operands to binary operations make this all a bit +// hard to verify. Attempt to ease the pain below by *only* comparing values +// that are obviously the same type (and will undergo no further conversions), +// even when it's not strictly necessary, for explicitness. + +enum UUComparison { FromIsBigger, FromIsNotBigger }; + +// Unsigned-to-unsigned range check + +template sizeof(To)) ? FromIsBigger : FromIsNotBigger> +struct UnsignedUnsignedCheck; + +template +struct UnsignedUnsignedCheck +{ + public: + static bool checkBounds(const From from) { + return from <= From(To(-1)); + } +}; + +template +struct UnsignedUnsignedCheck +{ + public: + static bool checkBounds(const From from) { + return true; + } +}; + +template +struct BoundsCheckImpl +{ + public: + static bool checkBounds(const From from) { + return UnsignedUnsignedCheck::checkBounds(from); + } +}; + +// Signed-to-unsigned range check + +template +struct BoundsCheckImpl +{ + public: + static bool checkBounds(const From from) { + if (from < 0) + return false; + if (sizeof(To) >= sizeof(From)) + return true; + return from <= From(To(-1)); + } +}; + +// Unsigned-to-signed range check + +enum USComparison { FromIsSmaller, FromIsNotSmaller }; + +template +struct UnsignedSignedCheck; + +template +struct UnsignedSignedCheck +{ + public: + static bool checkBounds(const From from) { + return true; + } +}; + +template +struct UnsignedSignedCheck +{ + public: + static bool checkBounds(const From from) { + const To MaxValue = To((1ULL << (CHAR_BIT * sizeof(To) - 1)) - 1); + return from <= From(MaxValue); + } +}; + +template +struct BoundsCheckImpl +{ + public: + static bool checkBounds(const From from) { + return UnsignedSignedCheck::checkBounds(from); + } +}; + +// Signed-to-signed range check + +template +struct BoundsCheckImpl +{ + public: + static bool checkBounds(const From from) { + if (sizeof(From) <= sizeof(To)) + return true; + const To MaxValue = To((1ULL << (CHAR_BIT * sizeof(To) - 1)) - 1); + const To MinValue = -MaxValue - To(1); + return From(MinValue) <= from && + From(from) <= From(MaxValue); + } +}; + +template::value && IsIntegral::value> +class BoundsChecker; + +template +class BoundsChecker +{ + public: + static bool checkBounds(const From from) { return true; } +}; + +template +class BoundsChecker +{ + public: + static bool checkBounds(const From from) { + return BoundsCheckImpl::checkBounds(from); + } +}; + +template +inline bool +IsInBounds(const From from) +{ + return BoundsChecker::checkBounds(from); +} + +} // namespace detail + +/** + * Cast a value of integral type |From| to a value of integral type |To|, + * asserting that the cast will be a safe cast per C++ (that is, that |to| is in + * the range of values permitted for the type |From|). + */ +template +inline To +SafeCast(const From from) +{ + MOZ_ASSERT((detail::IsInBounds(from))); + return static_cast(from); +} + +} // namespace mozilla + +#endif /* mozilla_Casting_h */