extent/region: simplify iteration over ranges
This commit is contained in:
parent
7568e34649
commit
af77aad894
99
extent.cpp
99
extent.cpp
@ -23,7 +23,6 @@
|
|||||||
#include <numeric>
|
#include <numeric>
|
||||||
|
|
||||||
using util::extent;
|
using util::extent;
|
||||||
using util::extent_range;
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
@ -86,91 +85,6 @@ extent<S,T>::empty (void) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
template <size_t S, typename T>
|
|
||||||
extent_range<S,T>::extent_range (extent<S,T> _target):
|
|
||||||
m_target (_target)
|
|
||||||
{ ; }
|
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
template <size_t S, typename T>
|
|
||||||
typename extent_range<S,T>::iterator
|
|
||||||
extent_range<S,T>::begin (void) const
|
|
||||||
{
|
|
||||||
return { m_target, util::point<S,T> (0) };
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
template <size_t S, typename T>
|
|
||||||
typename extent_range<S,T>::iterator
|
|
||||||
extent_range<S,T>::end (void) const
|
|
||||||
{
|
|
||||||
util::point<S,T> cursor (0);
|
|
||||||
cursor[S-1] = m_target[S-1];
|
|
||||||
|
|
||||||
return { m_target, cursor };
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
template <size_t S, typename T>
|
|
||||||
extent_range<S,T>::iterator::iterator (extent<S,T> _target, util::point<S,T> _cursor):
|
|
||||||
m_cursor (_cursor),
|
|
||||||
m_target (_target)
|
|
||||||
{
|
|
||||||
static_assert (std::is_integral<T>::value, "range stepping size is ill-defined for non-integral types");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
template <size_t S, typename T>
|
|
||||||
util::point<S,T>
|
|
||||||
extent_range<S,T>::iterator::operator* (void) const
|
|
||||||
{
|
|
||||||
return m_cursor;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
template <size_t S, typename T>
|
|
||||||
typename extent_range<S,T>::iterator&
|
|
||||||
extent_range<S,T>::iterator::operator++ (void)
|
|
||||||
{
|
|
||||||
++m_cursor[0];
|
|
||||||
|
|
||||||
for (size_t i = 0; i < S - 1; ++i) {
|
|
||||||
if (m_cursor[i] != m_target[i])
|
|
||||||
break;
|
|
||||||
|
|
||||||
m_cursor[i] = 0;
|
|
||||||
m_cursor[i+1]++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
template <size_t S, typename T>
|
|
||||||
bool
|
|
||||||
extent_range<S,T>::iterator::operator== (const iterator &rhs) const
|
|
||||||
{
|
|
||||||
return m_cursor == rhs.m_cursor;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
template <size_t S, typename T>
|
|
||||||
bool
|
|
||||||
extent_range<S,T>::iterator::operator!= (const iterator &rhs) const
|
|
||||||
{
|
|
||||||
return m_cursor != rhs.m_cursor;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
namespace util::debug {
|
namespace util::debug {
|
||||||
template <size_t S, typename T>
|
template <size_t S, typename T>
|
||||||
@ -196,11 +110,6 @@ INSTANTIATE_S_T(1,T) \
|
|||||||
INSTANTIATE_S_T(2,T) \
|
INSTANTIATE_S_T(2,T) \
|
||||||
INSTANTIATE_S_T(3,T)
|
INSTANTIATE_S_T(3,T)
|
||||||
|
|
||||||
#define INSTANTIATE_INT(T) \
|
|
||||||
template struct util::extent_range<1,T>; \
|
|
||||||
template struct util::extent_range<2,T>; \
|
|
||||||
template struct util::extent_range<3,T>;
|
|
||||||
|
|
||||||
INSTANTIATE( int16_t)
|
INSTANTIATE( int16_t)
|
||||||
INSTANTIATE( int32_t)
|
INSTANTIATE( int32_t)
|
||||||
INSTANTIATE( int64_t)
|
INSTANTIATE( int64_t)
|
||||||
@ -211,11 +120,3 @@ INSTANTIATE(uint64_t)
|
|||||||
|
|
||||||
INSTANTIATE(float)
|
INSTANTIATE(float)
|
||||||
INSTANTIATE(double)
|
INSTANTIATE(double)
|
||||||
|
|
||||||
INSTANTIATE_INT( int16_t)
|
|
||||||
INSTANTIATE_INT( int32_t)
|
|
||||||
INSTANTIATE_INT( int64_t)
|
|
||||||
|
|
||||||
INSTANTIATE_INT(uint16_t)
|
|
||||||
INSTANTIATE_INT(uint32_t)
|
|
||||||
INSTANTIATE_INT(uint64_t)
|
|
||||||
|
82
extent.hpp
82
extent.hpp
@ -106,47 +106,63 @@ namespace util {
|
|||||||
{
|
{
|
||||||
return extent<S,T> { 0 };
|
return extent<S,T> { 0 };
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
template <size_t S, typename T>
|
|
||||||
struct extent_range {
|
///////////////////////////////////////////////////////////////////////
|
||||||
|
class iterator {
|
||||||
public:
|
public:
|
||||||
struct iterator : public std::iterator<
|
using iterator_category = std::forward_iterator_tag;
|
||||||
std::forward_iterator_tag,
|
using value_type = point<S,T>;
|
||||||
::util::point<S,T>,
|
using difference_type = size_t;
|
||||||
size_t
|
using pointer = value_type*;
|
||||||
> {
|
using reference = value_type&;
|
||||||
public:
|
|
||||||
iterator (::util::extent<S,T>, ::util::point<S,T>);
|
|
||||||
|
|
||||||
point<S,T> operator* () const;
|
|
||||||
iterator& operator++ (void);
|
|
||||||
|
|
||||||
bool operator!= (const iterator &rhs) const;
|
iterator (point<S,T> _cursor, extent<S,T> _target):
|
||||||
bool operator== (const iterator &rhs) const;
|
m_cursor (_cursor),
|
||||||
|
m_target (_target)
|
||||||
|
{ ; }
|
||||||
|
|
||||||
|
|
||||||
|
point<S,T> operator* () { return m_cursor; }
|
||||||
|
point<S,T> operator* () const { return m_cursor; }
|
||||||
|
|
||||||
|
iterator& operator++ (void)&
|
||||||
|
{
|
||||||
|
++m_cursor[0];
|
||||||
|
|
||||||
|
for (size_t i = 0; i < S - 1; ++i) {
|
||||||
|
if (m_cursor[i] < m_target[i])
|
||||||
|
break;
|
||||||
|
|
||||||
|
m_cursor[i] = 0;
|
||||||
|
m_cursor[i+1]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool operator!= (const iterator &rhs) const { return m_cursor != rhs.m_cursor; }
|
||||||
|
bool operator== (const iterator &rhs) const { return m_cursor == rhs.m_cursor; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
point<S,T> m_cursor;
|
point<S,T> m_cursor;
|
||||||
extent<S,T> m_target;
|
extent<S,T> m_target;
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit extent_range (extent<S,T> target);
|
|
||||||
|
|
||||||
iterator begin (void) const;
|
auto step (void) const
|
||||||
iterator end (void) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
extent<S,T> m_target;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
template <size_t S, typename T>
|
|
||||||
extent_range<S,T>
|
|
||||||
make_range (extent<S,T> e)
|
|
||||||
{
|
{
|
||||||
return extent_range<S,T> {e};
|
point<S,T> last {0};
|
||||||
|
last[S-1] = this->data[S-1];
|
||||||
|
|
||||||
|
return util::view {
|
||||||
|
iterator {point<S,T> {0}, *this},
|
||||||
|
iterator {last, *this}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
@ -168,16 +184,6 @@ namespace util {
|
|||||||
|
|
||||||
typedef extent3<unsigned> extent3u;
|
typedef extent3<unsigned> extent3u;
|
||||||
typedef extent3<float> extent3f;
|
typedef extent3<float> extent3f;
|
||||||
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
|
||||||
template <typename T> using extent_range2 = extent_range<2,T>;
|
|
||||||
template <typename T> using extent_range3 = extent_range<3,T>;
|
|
||||||
|
|
||||||
|
|
||||||
using extent_range2u = extent_range2<typename extent2u::value_type>;
|
|
||||||
using extent_range2i = extent_range2<typename extent2i::value_type>;
|
|
||||||
using extent_range3u = extent_range2<typename extent3u::value_type>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
138
region.hpp
138
region.hpp
@ -140,6 +140,59 @@ namespace util {
|
|||||||
static constexpr region<S,T> zero (void)
|
static constexpr region<S,T> zero (void)
|
||||||
{ return { point_t {0}, extent_t {0} }; }
|
{ return { point_t {0}, extent_t {0} }; }
|
||||||
|
|
||||||
|
|
||||||
|
class iterator {
|
||||||
|
public:
|
||||||
|
using iterator_category = std::forward_iterator_tag;
|
||||||
|
using difference_type = std::size_t;
|
||||||
|
using value_type = point_t;
|
||||||
|
using pointer = value_type*;
|
||||||
|
using reference = value_type&;
|
||||||
|
|
||||||
|
iterator (point_t _lo, point_t _hi):
|
||||||
|
cursor (_lo),
|
||||||
|
lo (_lo),
|
||||||
|
hi (_hi)
|
||||||
|
{ ; }
|
||||||
|
|
||||||
|
|
||||||
|
const point_t& operator* (void) const& { return cursor; }
|
||||||
|
|
||||||
|
iterator&
|
||||||
|
operator++ (void)
|
||||||
|
{
|
||||||
|
cursor[0] += 1;
|
||||||
|
|
||||||
|
for (size_t s = 0; s < S-1; ++s) {
|
||||||
|
if (cursor[s] <= hi[s])
|
||||||
|
return *this;
|
||||||
|
|
||||||
|
cursor[s] = lo[s];
|
||||||
|
cursor[s+1]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator== (const iterator &rhs) const { return cursor == rhs.cursor; }
|
||||||
|
bool operator!= (const iterator &rhs) const { return cursor != rhs.cursor; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
point_t cursor, lo, hi;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto step (void) const
|
||||||
|
{
|
||||||
|
point_t last = p;
|
||||||
|
last[S-1] = (p + e)[S-1] + 1;
|
||||||
|
|
||||||
|
return util::view {
|
||||||
|
iterator { p, p + e },
|
||||||
|
iterator { last, p + e }
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
void sanity (void) const;
|
void sanity (void) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -157,96 +210,17 @@ namespace util {
|
|||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
/// construct a point iterator across a given region, generating each
|
|
||||||
/// valid point in row-major sequence.
|
|
||||||
///
|
|
||||||
/// this is only defined for integral types as it's not clear how to
|
|
||||||
/// handle floats; it's _super_ unlikely anyone actually wants to visit
|
|
||||||
/// every single floating point value for a region (and if so they can
|
|
||||||
/// damn well code that monstrosity themselves).
|
|
||||||
template <
|
|
||||||
typename T,
|
|
||||||
std::size_t S,
|
|
||||||
typename = std::enable_if_t<
|
|
||||||
std::is_integral_v<T>, void
|
|
||||||
>
|
|
||||||
>
|
|
||||||
auto
|
|
||||||
make_range (region<S,T> r)
|
|
||||||
{
|
|
||||||
using region_t = region<S,T>;
|
|
||||||
using point_t = typename region_t::point_t;
|
|
||||||
using vector_t = util::vector<S,T>;
|
|
||||||
|
|
||||||
// this range object is mostly a wrapper around the existing
|
|
||||||
// extent_range object with a constant offset. it's not going to be as
|
|
||||||
// performant, but when we discover this is an issue we can do write a
|
|
||||||
// better version of this object & iterator.
|
|
||||||
class region_range {
|
|
||||||
public:
|
|
||||||
class iterator : public std::iterator<std::forward_iterator_tag, point_t, size_t> {
|
|
||||||
public:
|
|
||||||
iterator (typename extent_range<S,T>::iterator _inner, vector_t _offset):
|
|
||||||
m_inner (_inner),
|
|
||||||
m_offset (_offset)
|
|
||||||
{ ; }
|
|
||||||
|
|
||||||
|
|
||||||
point_t operator* (void) const { return *m_inner + m_offset; }
|
|
||||||
|
|
||||||
iterator&
|
|
||||||
operator++ (void)
|
|
||||||
{
|
|
||||||
++m_inner;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool operator== (const iterator &rhs) const
|
|
||||||
{
|
|
||||||
assert (m_offset == rhs.m_offset);
|
|
||||||
return m_inner == rhs.m_inner;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool operator!= (const iterator &rhs) const
|
|
||||||
{ return !(*this == rhs); }
|
|
||||||
|
|
||||||
|
|
||||||
private:
|
|
||||||
typename extent_range<S,T>::iterator m_inner;
|
|
||||||
vector_t m_offset;
|
|
||||||
};
|
|
||||||
|
|
||||||
region_range (region_t _r):
|
|
||||||
m_range { _r.e + T{1} },
|
|
||||||
m_offset { _r.p.template as<util::vector> () }
|
|
||||||
{ ; }
|
|
||||||
|
|
||||||
iterator begin (void) const { return { m_range.begin (), m_offset }; }
|
|
||||||
iterator end (void) const { return { m_range.end (), m_offset }; }
|
|
||||||
|
|
||||||
iterator cbegin (void) const { return begin (); }
|
|
||||||
iterator cend (void) const { return end (); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
const extent_range<S,T> m_range;
|
|
||||||
const vector_t m_offset;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
return region_range { r };
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
template <typename T> using region2 = region<2,T>;
|
template <typename T> using region2 = region<2,T>;
|
||||||
template <typename T> using region3 = region<3,T>;
|
template <typename T> using region3 = region<3,T>;
|
||||||
|
|
||||||
|
|
||||||
using region2u = region2<unsigned>;
|
using region2u = region2<unsigned>;
|
||||||
using region2i = region2<int>;
|
using region2i = region2<int>;
|
||||||
using region2f = region2<float>;
|
using region2f = region2<float>;
|
||||||
using region2d = region2<double>;
|
using region2d = region2<double>;
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
template <size_t S, typename T>
|
template <size_t S, typename T>
|
||||||
std::ostream& operator<< (std::ostream&, const util::region<S,T>&);
|
std::ostream& operator<< (std::ostream&, const util::region<S,T>&);
|
||||||
}
|
}
|
||||||
|
@ -17,16 +17,21 @@ main (void)
|
|||||||
static constexpr util::point2u EXPECTED[] = {
|
static constexpr util::point2u EXPECTED[] = {
|
||||||
{ 0, 0 }, { 1, 0 }, { 2, 0 },
|
{ 0, 0 }, { 1, 0 }, { 2, 0 },
|
||||||
{ 0, 1 }, { 1, 1 }, { 2, 1 },
|
{ 0, 1 }, { 1, 1 }, { 2, 1 },
|
||||||
{ 0, 2 }, { 1, 2 }, { 2, 2 },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
size_t offset = 0;
|
size_t offset = 0;
|
||||||
unsigned success = 0;
|
bool success = true;
|
||||||
|
|
||||||
for (auto p: util::extent_range2u ({3, 3}))
|
for (auto p: util::extent2u {3,2}.step ()) {
|
||||||
success += EXPECTED[offset++] == p ? 1 : 0;
|
if (offset >= std::size (EXPECTED)) {
|
||||||
|
success = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
tap.expect_eq (success, std::size (EXPECTED), "extent_range2u iteration");
|
success = success && util::all (EXPECTED[offset++] == p);
|
||||||
|
}
|
||||||
|
|
||||||
|
tap.expect (success, "extent_range2u iteration");
|
||||||
}
|
}
|
||||||
|
|
||||||
return tap.status ();
|
return tap.status ();
|
||||||
|
@ -85,18 +85,16 @@ main (int, char **)
|
|||||||
{
|
{
|
||||||
const util::region2i REGION {
|
const util::region2i REGION {
|
||||||
util::point2i { -1, 1 },
|
util::point2i { -1, 1 },
|
||||||
util::point2i { 1, 3 }
|
util::point2i { 1, 2 }
|
||||||
};
|
};
|
||||||
|
|
||||||
const util::point2i EXPECTED[] = {
|
const util::point2i EXPECTED[] = {
|
||||||
{ -1, 1 }, { 0, 1 }, { 1, 1 },
|
{ -1, 1 }, { 0, 1 }, { 1, 1 },
|
||||||
{ -1, 2 }, { 0, 2 }, { 1, 2 },
|
{ -1, 2 }, { 0, 2 }, { 1, 2 },
|
||||||
{ -1, 3 }, { 0, 3 }, { 1, 3 },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<util::point2i> values;
|
std::vector<util::point2i> values;
|
||||||
auto sequence = util::make_range (REGION);
|
std::copy (std::cbegin (REGION.step ()), std::cend (REGION.step ()), std::back_inserter (values));
|
||||||
std::copy (std::cbegin (sequence), std::cend (sequence), std::back_inserter (values));
|
|
||||||
|
|
||||||
bool success = values.size () == std::size (EXPECTED)
|
bool success = values.size () == std::size (EXPECTED)
|
||||||
&& std::equal (std::cbegin (values), std::cend (values),
|
&& std::equal (std::cbegin (values), std::cend (values),
|
||||||
@ -104,8 +102,5 @@ main (int, char **)
|
|||||||
tap.expect (success, "make_range(region2i)");
|
tap.expect (success, "make_range(region2i)");
|
||||||
};
|
};
|
||||||
|
|
||||||
//CHECK (region<2,intmax_t> (0, 0, 10, 10).includes (point2d (0.4, 0.01)));
|
|
||||||
//CHECK (region<2,intmax_t> (0, 0, 10, 10).contains (point2d (0.4, 0.01)));
|
|
||||||
|
|
||||||
return tap.status ();
|
return tap.status ();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user