/* * Copyright (c) 2015, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of Intel Corporation nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /** \file * \brief Data types used to represent depth quantities. */ #ifndef DEPTH_H #define DEPTH_H #include "ue2common.h" #ifdef DUMP_SUPPORT #include #endif #include namespace ue2 { /** * \brief Exception thrown if a depth operation overflows. */ struct DepthOverflowError {}; /** * \brief Type used to represent depth information; value is either a count, * or the special values "infinity" and "unreachable". */ class depth { public: depth() : val(val_unreachable) {} depth(u32 v) : val(v) { if (v > max_value()) { DEBUG_PRINTF("depth %u too large to represent!\n", v); throw DepthOverflowError(); } } static depth unreachable() { depth d; d.val = val_unreachable; return d; } static depth infinity() { depth d; d.val = val_infinity; return d; } /** \brief Returns the max finite value representable as a depth. */ static constexpr u32 max_value() { return val_infinity - 1; } bool is_finite() const { return val < val_infinity; } bool is_infinite() const { return val == val_infinity; } bool is_unreachable() const { return val == val_unreachable; } bool is_reachable() const { return !is_unreachable(); } /** \brief Convert a finite depth to an integer. */ operator u32() const { if (!is_finite()) { throw DepthOverflowError(); } return val; } bool operator<(const depth &d) const { return val < d.val; } bool operator>(const depth &d) const { return val > d.val; } bool operator<=(const depth &d) const { return val <= d.val; } bool operator>=(const depth &d) const { return val >= d.val; } bool operator==(const depth &d) const { return val == d.val; } bool operator!=(const depth &d) const { return val != d.val; } // The following comparison operators exist for use against integer types // that are bigger than what we can safely convert to depth (such as those // in extparam). bool operator<(u64a d) const { if (!is_finite()) { return false; } return val < d; } bool operator<=(u64a d) const { if (!is_finite()) { return false; } return val <= d; } bool operator==(u64a d) const { if (!is_finite()) { return false; } return val == d; } bool operator>(u64a d) const { return !(*this <= d); } bool operator>=(u64a d) const { return !(*this < d); } bool operator!=(u64a d) const { return !(*this == d); } depth operator+(const depth &d) const { if (is_unreachable() || d.is_unreachable()) { return unreachable(); } if (is_infinite() || d.is_infinite()) { return infinity(); } u64a rv = val + d.val; if (rv >= val_infinity) { DEBUG_PRINTF("depth %llu too large to represent!\n", rv); throw DepthOverflowError(); } return depth((u32)rv); } depth &operator+=(const depth &d) { depth rv = *this + d; *this = rv; return *this; } depth operator-(const depth &d) const { if (!d.is_finite()) { throw DepthOverflowError(); } if (is_unreachable()) { return unreachable(); } if (is_infinite()) { return infinity(); } if (val < d.val) { throw DepthOverflowError(); } u32 rv = val - d.val; return depth(rv); } depth &operator-=(const depth &d) { depth rv = *this - d; *this = rv; return *this; } depth operator+(s32 d) const { if (is_unreachable()) { return unreachable(); } if (is_infinite()) { return infinity(); } s64a rv = val + d; if (rv < 0 || (u64a)rv >= val_infinity) { DEBUG_PRINTF("depth %lld too large to represent!\n", rv); throw DepthOverflowError(); } return depth((u32)rv); } depth operator+=(s32 d) { depth rv = *this + d; *this = rv; return *this; } #ifdef DUMP_SUPPORT /** \brief Render as a string, useful for debugging. */ std::string str() const; #endif friend size_t hash_value(const depth &d) { return d.val; } private: static constexpr u32 val_infinity = (1u << 31) - 1; static constexpr u32 val_unreachable = 1u << 31; u32 val; }; /** * \brief Encapsulates a min/max pair. */ struct DepthMinMax { depth min; depth max; DepthMinMax() : min(depth::infinity()), max(depth(0)) {} DepthMinMax(const depth &mn, const depth &mx) : min(mn), max(mx) {} bool operator<(const DepthMinMax &b) const { if (min != b.min) { return min < b.min; } return max < b.max; } bool operator==(const DepthMinMax &b) const { return min == b.min && max == b.max; } bool operator!=(const DepthMinMax &b) const { return !(*this == b); } #ifdef DUMP_SUPPORT /** \brief Render as a string, useful for debugging. */ std::string str() const; #endif }; inline size_t hash_value(const DepthMinMax &d) { size_t val = 0; boost::hash_combine(val, d.min); boost::hash_combine(val, d.max); return val; } /** * \brief Merge two DepthMinMax values together to produce their union. */ DepthMinMax unionDepthMinMax(const DepthMinMax &a, const DepthMinMax &b); } // namespace ue2 #endif // DEPTH_H