vectorscan/src/util/depth.h
2015-11-10 14:36:38 +11:00

261 lines
7.1 KiB
C++

/*
* 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 <string>
#endif
#include <boost/functional/hash/hash_fwd.hpp>
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