Program Listing for File range.hpp
↰ Return to documentation for file (rcppsw/math/range.hpp
)
#pragma once
/*******************************************************************************
* Includes
******************************************************************************/
#include <cmath>
#include <iosfwd>
#include <string>
#include "rcppsw/er/client.hpp"
#include "rcppsw/rcppsw.hpp"
#include "rcppsw/utils/string_utils.hpp"
#include "rcppsw/er/stringizable.hpp"
/*******************************************************************************
* Namespaces/Decls
******************************************************************************/
namespace rcppsw::math {
/*******************************************************************************
* Class Definitions
******************************************************************************/
template <typename T>
class range final : public er::client<range<T>>, er::stringizable {
public:
range(void) noexcept : ER_CLIENT_INIT() {}
range(const T& lb, const T& ub) noexcept
: ER_CLIENT_INIT(),
m_initialized(true),
m_lb(lb),
m_ub(ub),
m_span(m_ub - m_lb) {}
RCPPSW_NODISCARD T lb(void) const { return m_lb; }
RCPPSW_NODISCARD T ub(void) const { return m_ub; }
RCPPSW_NODISCARD T span(void) const { return m_span; }
void lb(const T& lb) {
ER_ASSERT(m_initialized, "Range not initialized");
ER_ASSERT(lb < m_ub,
"New lower bound (%s) >= upper bound (%s)",
rcppsw::to_string(lb).c_str(),
rcppsw::to_string(m_ub).c_str());
m_lb = lb;
m_span = m_ub;
m_span -= m_lb;
}
void ub(const T& ub) {
ER_ASSERT(m_initialized, "Range not initialized");
ER_ASSERT(ub > m_lb,
"New upper bound (%s) <= lower bound (%s)",
rcppsw::to_string(ub).c_str(),
rcppsw::to_string(m_lb).c_str());
m_ub = ub;
m_span = m_ub;
m_span -= m_lb;
}
void set(const T& lb, const T& ub) {
ER_ASSERT(lb < ub,
"New lower bound (%s) >= New upper bound (%s)",
rcppsw::to_string(m_lb).c_str(),
rcppsw::to_string(m_ub).c_str());
m_initialized = true;
m_lb = lb;
m_ub = ub;
m_span = m_ub;
m_span -= m_lb;
}
template <typename U = T, RCPPSW_SFINAE_DECLDEF(!std::is_floating_point<U>::value)>
bool contains(const T& value) const {
ER_ASSERT(m_initialized, "Range not initialized");
return value >= m_lb && value <= m_ub;
}
template <typename U = T, RCPPSW_SFINAE_DECLDEF(std::is_floating_point<U>::value)>
bool contains(const T& value) const {
ER_ASSERT(m_initialized, "Range not initialized");
return value >= m_lb && value <= m_ub;
}
bool contains(const range<T>& other) const {
return this->contains(other.m_lb) && this->contains(other.m_ub);
}
bool overlaps_with(const range<T>& other) const {
return this->contains(other.m_lb) || this->contains(other.m_ub) ||
other.contains(this->m_lb) || other.contains(this->m_ub);
}
RCPPSW_NODISCARD RCPPSW_PURE T wrap_value(T value) const {
ER_ASSERT(m_initialized, "Range not initialized");
while (value > m_ub) {
value -= m_span;
}
while (value < m_lb) {
value += m_span;
}
return value;
}
T center(void) const { return (m_lb + m_ub) / 2; }
std::string to_str(void) const override {
return "[" + rcppsw::to_string(m_lb) + "-" + rcppsw::to_string(m_ub) + "]";
}
friend std::ostream& operator<<(std::ostream& stream, const range& c_range) {
stream << c_range.to_str();
return stream;
}
range translate(const T& value) const {
return range(m_lb + value, m_ub + value);
}
range shrink(const T& value) const {
return range(m_lb + value, m_ub - value);
}
range recenter(const T&value) const {
T span = this->span();
return range(static_cast<T>(value - span / 2.0),
static_cast<T>(value + span / 2.0));
}
friend std::istream& operator>>(std::istream& is, range& r) {
T values[2] = { T(), T() };
utils::parse_values<T>(is, 2, values, ':');
r.set(values[0], values[1]);
return is;
}
private:
/* clang-format off */
bool m_initialized{false};
T m_lb{};
T m_ub{};
T m_span{};
/* clang-format on */
};
using rangei = range<int>;
using rangez = range<size_t>;
using ranged = range<double>;
/*******************************************************************************
* Macros
******************************************************************************/
#define RCPPSW_MATH_RANGE_DIRECT_CONV2FLT(prefix) \
static inline ranged prefix##range2drange(const range##prefix& other) { \
return ranged(other.lb(), other.lb()); \
}
#define RCPPSW_MATH_RANGE_SCALED_CONV2FLT(prefix) \
static inline ranged prefix##range2drange(const range##prefix& other, \
double scale) { \
return ranged(other.lb() * scale, other.ub() * scale); \
}
#define RCPPSW_MATH_RANGE_CONV2DISC(dest_prefix, dest_type) \
static inline range##dest_prefix drange2##dest_prefix##range( \
const range##dest_prefix& other, double scale) { \
return range##dest_prefix(static_cast<dest_type>(other.lb() / scale), \
static_cast<dest_type>(other.ub() / scale)); \
}
/*******************************************************************************
* Free Functions
******************************************************************************/
RCPPSW_MATH_RANGE_DIRECT_CONV2FLT(z);
RCPPSW_MATH_RANGE_DIRECT_CONV2FLT(i);
RCPPSW_MATH_RANGE_SCALED_CONV2FLT(z);
RCPPSW_MATH_RANGE_SCALED_CONV2FLT(i);
RCPPSW_MATH_RANGE_CONV2DISC(z, size_t);
} /* namespace rcppsw::math */