#ifndef __JRANGE__ #define __JRANGE__ #include #include #include "JLang/JClass.hh" #include "JTools/JPair.hh" namespace JTOOLS { namespace { using JLANG::JClass; } /** * Range of values. */ template > class JRange : public JPair { public: typedef JRange JRange_t; typedef typename JClass::argument_type argument_type; /** * Default constructor. * This range corresponds to the maximal possible range. */ JRange() : JPair(getMinimum(), getMaximum()) {} /** * Constructor. * * \param x lower limit * \param y upper limit */ JRange(argument_type x, argument_type y) : JPair(x, y) {} /** * Get lower limit. * * \return lower limit */ T getLowerLimit() const { return this->first; } /** * Get upper limit. * * \return upper limit */ T getUpperLimit() const { return this->second; } /** * Set lower limit. * * \param x lower limit */ void setLowerLimit(argument_type x) { this->first = x; } /** * Set upper limit. * * \param y upper limit */ void setUpperLimit(argument_type y) { this->second = y; } /** * Set lower and uppper limit. * * \param x lower limit * \param y upper limit */ void setRange(argument_type x, argument_type y) { this->first = x; this->second = y; } /** * Get length (difference between upper and lower limit). * * \return length */ T getLength() const { return getUpperLimit() - getLowerLimit(); } /** * Check validity of range. * * \return true if lower limit less than upper limit; else false */ bool is_valid() const { return compare(getLowerLimit(), getUpperLimit()); } /** * Test whether value is inside range. * * \param x value * \return true if lower limit <= value <= upper limit; else false */ bool operator()(argument_type x) const { return (!compare(x, getLowerLimit()) && !compare(getUpperLimit(), x)); } /** * Constrain value to range. * This method returns the original value if it is in this range, else * lower limit if value < lower limit or upper limit if value > upper limit. * * \param x value * \return lower limit <= x <= upper limit */ T constrain(argument_type x) const { if (compare(x, getLowerLimit())) return getLowerLimit(); if (compare(getUpperLimit(), x)) return getUpperLimit(); return x; } /** * Test overlap with given range. * The result is equivalent to join(range).is_valid(). * * \param range range * \return true if there is a non-zero overlap; else false */ bool overlap(const JRange_t& range) const { return (compare(getLowerLimit(), range.getUpperLimit()) && compare(range.getLowerLimit(), getUpperLimit())); } /** * Get minimum possible value. * * \return minimum possible value */ static T getMinimum() { return -std::numeric_limits::max(); } /** * Get maximum possible value. * * \return maximum possible value */ static T getMaximum() { return +std::numeric_limits::max(); } /** * Include given value to range. * The new lower limit is the minimim of the original lower limit and given value and * the new upper limit is the maximum of the original upper limit and given value; * * \param x value * \return range */ JRange_t include(argument_type x) { if (compare(x, getLowerLimit())) setLowerLimit(x); if (compare(getUpperLimit(), x)) setUpperLimit(x); return *this; } /** * Join ranges. * The new lower limit is the maximim of the two lower limits and * the new upper limit is the minimum of the two upper limits. * This operation results in an equal or smaller range and * may result in an unphysical range (i.e. lower limit > upper limit). * * \param range range */ JRange_t& join(const JRange_t& range) { if (compare(getLowerLimit(), range.getLowerLimit())) setLowerLimit(range.getLowerLimit()); if (compare(range.getUpperLimit(), getUpperLimit())) setUpperLimit(range.getUpperLimit()); return *this; } /** * Combine ranges. * The new lower limit is the minimim of the two lower limits and * the new upper limit is the maximum of the two upper limits. * This operation results in an equal or larger range. * * \param range range */ JRange_t& combine(const JRange_t& range) { if (compare(range.getLowerLimit(), getLowerLimit())) setLowerLimit(range.getLowerLimit()); if (compare(getUpperLimit(), range.getUpperLimit())) setUpperLimit(range.getUpperLimit()); return *this; } /** * Add offset. * The new lower limit is the sum of the the original lower limit and value and * the new upper limit is the sum of the the original upper limit and value. * * \param x offset */ JRange_t& add(argument_type x) { setLowerLimit(getLowerLimit() + x); setUpperLimit(getUpperLimit() + x); return *this; } /** * Add offset. * The new lower limit is the sum of the two lower limits and * the new upper limit is the sum of the two upper limits. * * \param range offset */ JRange_t& add(const JRange_t& range) { setLowerLimit(getLowerLimit() + range.getLowerLimit()); setUpperLimit(getUpperLimit() + range.getUpperLimit()); return *this; } /** * Default range. * This range corresponds to an unphysical range. */ static const JRange JDEFAULT_RANGE; /** * Function object. * * \param first first argument * \param second second argument * \return true if first < second; else false */ JComparator_t compare; }; /** * Default range. * This range corresponds to an unphysical range. */ template const JRange JRange::JDEFAULT_RANGE(JRange::getMaximum(), JRange::getMinimum()); /** * Equal operator for ranges. * * \param first first range * \param second second range * \result true if first range equal to second range; else false */ template inline bool operator==(const JRange& first, const JRange& second) { return (!first.compare(first .getLowerLimit(), second.getLowerLimit()) && !first.compare(second.getLowerLimit(), first .getLowerLimit()) && !first.compare(first .getUpperLimit(), second.getUpperLimit()) && !first.compare(second.getUpperLimit(), first .getUpperLimit())); } /** * Not equal operator for ranges. * * \param first first range * \param second second range * \result true if first range not equal to second range; else false */ template inline bool operator!=(const JRange& first, const JRange& second) { return (first.compare(first .getLowerLimit(), second.getLowerLimit()) || first.compare(second.getLowerLimit(), first .getLowerLimit()) || first.compare(first .getUpperLimit(), second.getUpperLimit()) || first.compare(second.getUpperLimit(), first .getUpperLimit())); } /** * Add ranges. * The new lower limit is the sum of the two lower limits and * the new upper limit is the sum of the two upper limits. * * \param first first range * \param second second range * \result range */ template inline JRange operator+(const JRange& first, const JRange& second) { return JRange(first).add(second); } /** * Auxiliary method to create range of values. * * \param x lower limit * \param y upper limit * \return range */ template inline JRange make_range(T x, T y) { return JRange(x,y); } } #endif