libcruft-util/range.cpp

230 lines
5.7 KiB
C++

/*
* 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/.
*
* Copyright 2011-2012 Danny Robson <danny@nerdcruft.net>
*/
#include "range.hpp"
#include "debug/assert.hpp"
#include "maths.hpp"
#include "random.hpp"
#include <ostream>
#include <cmath>
#include <cstdint>
///////////////////////////////////////////////////////////////////////////////
template <typename T>
cruft::range<T>::range (T _lo, T _hi):
lo (_lo),
hi (_hi)
{
sanity ();
}
///////////////////////////////////////////////////////////////////////////////
template <typename T>
T
cruft::range<T>::magnitude (void) const
{
return hi - lo;
}
///////////////////////////////////////////////////////////////////////////////
template <typename T>
bool
cruft::range<T>::contains (T val) const
{
return val >= lo && val <= hi;
}
//-----------------------------------------------------------------------------
template <typename T>
bool
cruft::range<T>::contains (const range <T> &r) const
{
return r.lo >= lo && r.hi <= hi;
}
//-----------------------------------------------------------------------------
template <typename T>
T
cruft::range<T>::at (float t) const
{
return static_cast<T> (lo + (hi - lo) * t);
}
//-----------------------------------------------------------------------------
template <typename T>
T
cruft::range<T>::clamp (T val) const
{
return std::max (lo, std::min (val, hi));
}
//-----------------------------------------------------------------------------
template <typename T>
void
cruft::range<T>::expand (T val)
{
// The arguments to min and max are such that expansion from initial NaN
// values should change both min and max to be that value.
lo = std::min (val, lo);
hi = std::max (val, hi);
}
///////////////////////////////////////////////////////////////////////////////
template <typename T>
cruft::range<T>&
cruft::range<T>::operator*= (T val)
{
lo *= val;
hi *= val;
return *this;
}
//-----------------------------------------------------------------------------
template <typename T>
cruft::range<T>
cruft::range<T>::operator* (T val) const
{
return cruft::range<T> (lo * val, hi * val);
}
//-----------------------------------------------------------------------------
template <typename T>
cruft::range<T>
cruft::range<T>::operator- (T val) const
{
return cruft::range<T> (lo - val, hi - val);
}
//-----------------------------------------------------------------------------
template <typename T>
cruft::range<T>
cruft::range<T>::operator+ (T val) const
{
return cruft::range<T> (
lo + val,
hi + val
);
}
///////////////////////////////////////////////////////////////////////////////
template <typename T>
T
cruft::range<T>::random (void) const
{
if constexpr (std::is_floating_point_v<T>) {
return std::uniform_real_distribution<T> (lo, hi) (cruft::random::generator ());
} else {
return std::uniform_int_distribution<T> (lo, hi) (cruft::random::generator ());
}
}
///////////////////////////////////////////////////////////////////////////////
namespace cruft {
template <>
bool
range<float>::operator ==(const range<float> &rhs) const
{
return almost_equal (lo, rhs.lo) &&
almost_equal (hi, rhs.hi);
}
template <>
bool
range<double>::operator ==(const range<double> &rhs) const
{
return almost_equal (lo, rhs.lo) &&
almost_equal (hi, rhs.hi);
}
}
//-----------------------------------------------------------------------------
template <typename T>
bool
cruft::range<T>::operator ==(const cruft::range<T> &rhs) const
{
return lo == rhs.lo && hi == rhs.hi;
}
///////////////////////////////////////////////////////////////////////////////
template <typename T>
std::ostream&
cruft::operator <<(std::ostream &os, const range<T> &rhs) {
os << '[' << rhs.lo << ", " << rhs.hi << ']';
return os;
}
template std::ostream& cruft::operator<< (std::ostream&, range<i08> const&);
template std::ostream& cruft::operator<< (std::ostream&, range<i16> const&);
template std::ostream& cruft::operator<< (std::ostream&, range<i32> const&);
template std::ostream& cruft::operator<< (std::ostream&, range<i64> const&);
template std::ostream& cruft::operator<< (std::ostream&, range<u08> const&);
template std::ostream& cruft::operator<< (std::ostream&, range<u16> const&);
template std::ostream& cruft::operator<< (std::ostream&, range<u32> const&);
template std::ostream& cruft::operator<< (std::ostream&, range<u64> const&);
template std::ostream& cruft::operator<< (std::ostream&, range<f32> const&);
template std::ostream& cruft::operator<< (std::ostream&, range<f64> const&);
///////////////////////////////////////////////////////////////////////////////
template <typename T>
void
cruft::range<T>::sanity (void) const
{
CHECK (lo <= hi);
}
//-----------------------------------------------------------------------------
namespace cruft {
template <>
void
range<double>::sanity (void) const
{
if (std::isnan (lo) || std::isnan (hi))
return;
CHECK (lo <= hi);
}
}
//-----------------------------------------------------------------------------
template struct cruft::range<double>;
template struct cruft::range<float>;
template struct cruft::range<int8_t>;
template struct cruft::range<int16_t>;
template struct cruft::range<int32_t>;
template struct cruft::range<int64_t>;
template struct cruft::range<uint8_t>;
template struct cruft::range<uint16_t>;
template struct cruft::range<uint32_t>;
template struct cruft::range<uint64_t>;