2251: Add iterators on the n-faces of a complex.
* mln/core/faces_iter.hh: New. * mln/core/complex.hh: Add forward declarations for faces_fwd_iter_ and faces_bkd_iter_. (mln::complex<D>::fwd_fiter<N>, mln::complex<D>::bkd_fiter<N>): New inner classes. * mln/core/face.hh (mln::face_handle<N, D>::set_cplx) (mln::face_handle<N, D>::set_face_id): New mutators. * mln/core/macros.hh (mln_fiter, mln_fiter_) (mln_fwd_fiter, mln_fwd_fiter_, mln_bkd_fiter, mln_bkd_fiter_): New macros. * tests/core/complex.cc (main): Exercise iterators on n-faces. --- milena/ChangeLog | 18 ++ milena/mln/core/complex.hh | 19 ++- milena/mln/core/face.hh | 19 ++ milena/mln/core/faces_iter.hh | 448 +++++++++++++++++++++++++++++++++++++++++ milena/mln/core/macros.hh | 18 ++ milena/tests/core/complex.cc | 43 +++- 6 files changed, 549 insertions(+), 16 deletions(-) create mode 100644 milena/mln/core/faces_iter.hh diff --git a/milena/ChangeLog b/milena/ChangeLog index e766670..f164de6 100644 --- a/milena/ChangeLog +++ b/milena/ChangeLog @@ -1,5 +1,23 @@ 2008-09-12 Roland Levillain <roland@lrde.epita.fr> + Add iterators on the n-faces of a complex. + + * mln/core/faces_iter.hh: New. + * mln/core/complex.hh: Add forward declarations for + faces_fwd_iter_ and faces_bkd_iter_. + (mln::complex<D>::fwd_fiter<N>, mln::complex<D>::bkd_fiter<N>): + New inner classes. + * mln/core/face.hh + (mln::face_handle<N, D>::set_cplx) + (mln::face_handle<N, D>::set_face_id): + New mutators. + * mln/core/macros.hh (mln_fiter, mln_fiter_) + (mln_fwd_fiter, mln_fwd_fiter_, mln_bkd_fiter, mln_bkd_fiter_): + New macros. + * tests/core/complex.cc (main): Exercise iterators on n-faces. + +2008-09-12 Roland Levillain <roland@lrde.epita.fr> + Factor iterators on complexes. * mln/core/complex_iter.hh (mln::internal::complex_iter_<D, E>): diff --git a/milena/mln/core/complex.hh b/milena/mln/core/complex.hh index c0c1b80..3b4571b 100644 --- a/milena/mln/core/complex.hh +++ b/milena/mln/core/complex.hh @@ -31,10 +31,8 @@ /// \file mln/core/complex.hh /// \brief Structures for general complexes. /// -/// A complexes defines a topological space which can be used as a +/// A complex defines a topological space which can be used as a /// support for an image (i.e., as site sets). -/// -/// FIXME: More. # include <cstddef> @@ -44,8 +42,8 @@ # include <mln/metal/bool.hh> # include <mln/core/face.hh> - # include <mln/core/complex_iter.hh> +# include <mln/core/faces_iter.hh> namespace mln @@ -59,6 +57,8 @@ namespace mln } template <unsigned D> class complex_fwd_iter_; template <unsigned D> class complex_bkd_iter_; + template <unsigned N, unsigned D> class faces_fwd_iter_; + template <unsigned N, unsigned D> class faces_bkd_iter_; /*----------. @@ -70,11 +70,18 @@ namespace mln class complex : private internal::faces_set_mixin<D, D> { public: - /// Forward mln::Iterator associated type. + /// Forward mln::Iterator type iterating on all faces. typedef complex_fwd_iter_<D> fwd_citer; - /// Backward mln::Iterator associated type. + /// Backward mln::Iterator type iterating on all faces. typedef complex_bkd_iter_<D> bkd_citer; + /// Forward mln::Iterator type iterating on \p N-faces. + template <unsigned N> + struct fwd_fiter { typedef faces_fwd_iter_<N, D> ret; }; + /// Backward mln::Iterator type iterating on \p N-faces. + template <unsigned N> + struct bkd_fiter { typedef faces_bkd_iter_<N, D> ret; }; + /// Complex construction. /// \{ /// \brief Add a 0-face to the complex. diff --git a/milena/mln/core/face.hh b/milena/mln/core/face.hh index 7de0e8d..4e8e958 100644 --- a/milena/mln/core/face.hh +++ b/milena/mln/core/face.hh @@ -165,6 +165,11 @@ namespace mln // FIXME: Rename as `id'? unsigned face_id() const; + /// Set the complex the face belongs to. + void set_cplx(complex<D>& cplx); + /// Set the id of the face. + void set_face_id(unsigned face_id); + /// Return the mln::face pointed by this handle. face<N, D>& to_face() const; /// \} @@ -421,6 +426,20 @@ namespace mln } template <unsigned N, unsigned D> + void + face_handle<N, D>::set_cplx(complex<D>& cplx) + { + cplx_ = &cplx; + } + + template <unsigned N, unsigned D> + void + face_handle<N, D>::set_face_id(unsigned face_id) + { + face_id_ = face_id; + } + + template <unsigned N, unsigned D> face<N, D>& face_handle<N, D>::to_face() const { diff --git a/milena/mln/core/faces_iter.hh b/milena/mln/core/faces_iter.hh new file mode 100644 index 0000000..25dd2c2 --- /dev/null +++ b/milena/mln/core/faces_iter.hh @@ -0,0 +1,448 @@ +// Copyright (C) 2008 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of the Olena Library. This library is free +// software; you can redistribute it and/or modify it under the terms +// of the GNU General Public License version 2 as published by the +// Free Software Foundation. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this library; see the file COPYING. If not, write to +// the Free Software Foundation, 51 Franklin Street, Fifth Floor, +// Boston, MA 02111-1307, USA. +// +// As a special exception, you may use this file as part of a free +// software library without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to +// produce an executable, this file does not by itself cause the +// resulting executable to be covered by the GNU General Public +// License. +// reasons why the executable file might be covered by the GNU General +// Public License. + +#ifndef MLN_CORE_FACES_ITER_HH +# define MLN_CORE_FACES_ITER_HH + +/// \file mln/core/faces_iter.hh +/// \brief Definition of forward and backward iterators on the n-faces +/// of a complex. + +# include <limits> + +# include <mln/core/concept/iterator.hh> +# include <mln/core/complex.hh> + +namespace mln +{ + + // Fwd decls. + template <unsigned D> class complex; + + /*---------------------------------. + | internal::faces_iter_<N, D, E>. | + `---------------------------------*/ + + // FIXME: Maybe we should have a `face' parameter instead of N & D. + // This way, we could merge this class and + // internal::complex_iter_x<D, E>. + + namespace internal + { + /// \brief Factoring classe for iterators on all the \p N-faces of + /// a mln::complex<D>. + /// + /// \arg \p N The dimension of the face associated to this iterator. + /// \arg \p D The dimension of the complex this iterator belongs to. + /// \arg \p E The type exact type of the iterator. + template <unsigned N, unsigned D, typename E> + class faces_iter_ : public Iterator<E> + { + typedef faces_iter_<N, D, E> self_; + + public: + typedef face_handle<N, D> face; + + /// Construction and assignment. + /// \{ + /* FIXME: Keep this non-const? See a (big) comment about this in + milena/tests/complex_image.cc. */ + faces_iter_(complex<D>& c); + faces_iter_(const self_& rhs); + self_& operator= (const self_& rhs); + /// \} + + /// Manipulation. + /// \{ + /// Test if the iterator is valid. + bool is_valid() const; + /// Invalidate the iterator. + void invalidate(); + /// \} + + /// Conversion and accessors. + /// \{ + /// Reference to the corresponding face handle. + const face& to_face () const; + /// Convert the iterator into an face handle. + operator face() const; + /// \} + + protected: + /// The face handle this iterator is pointing to. + face face_; + + private: + /// \brief An invalid value for both the dimension and the id of + /// the face. + /// + /// Use a function instead of a static constant, since `static' + /// variables needs to be compiled once, which requires a compiled + /// library to avoid duplicate symbols, which is something that + /// was not really planned in Milena. A function tagged `inlined' + /// can appear multiple times in a program, and solves this + /// problem. We rely on the compiler to inline this call. + /// + /// Of course, we could have used UINT_MAX, but it is not very + /// C++. + unsigned invalid_unsigned_() const; + }; + + + /* FIXME: This hand-made delegation is painful. We should rely on + the general mechanism provided by Point_Site. But then again, we + need to refine/adjust the interface of Point_Site w.r.t. the + mandatory conversions to points. */ + template <unsigned N, unsigned D, typename E> + inline + std::ostream& + operator<<(std::ostream& ostr, const faces_iter_<N, D, E>& p); + + } // end of mln::internal + + + /*------------------------. + | faces_fwd_iter_<N, D>. | + `------------------------*/ + + /// \brief Forward iterator on all the faces of a mln::complex<D>. + /// + /// \arg \p N The dimension of the face associated to this iterator. + /// \arg \p D The dimension of the complex this iterator belongs to. + template <unsigned N, unsigned D> + class faces_fwd_iter_ + : public internal::faces_iter_< N, D, faces_fwd_iter_<N, D> > + { + typedef faces_fwd_iter_<N, D> self_; + typedef internal::faces_iter_< N, D, self_ > super_; + + public: + using super_::is_valid; + using super_::invalidate; + + public: + /// Construction and assignment. + /// \{ + // FIXME: See above (internal::faces_iter_'s default ctor). + faces_fwd_iter_(complex<D>& c); + faces_fwd_iter_(const self_& rhs); + self_& operator= (const self_& rhs); + /// \} + + /// Manipulation. + /// \{ + /// Test if the iterator is valid. + void start(); + /// Go to the next point. + void next_(); + /// \} + + private: + using super_::face_; + }; + + + /*------------------------. + | faces_bkd_iter_<N, D>. | + `------------------------*/ + + /// \brief Backward iterator on all the faces of a mln::complex<D>. + /// + /// \arg \p N The dimension of the face associated to this iterator. + /// \arg \p D The dimension of the complex this iterator belongs to. + template <unsigned N, unsigned D> + class faces_bkd_iter_ + : public internal::faces_iter_< N, D, faces_bkd_iter_<N, D> > + { + typedef faces_bkd_iter_<N, D> self_; + typedef internal::faces_iter_< N, D, self_ > super_; + + public: + using super_::is_valid; + using super_::invalidate; + + public: + /// Construction and assignment. + /// \{ + // FIXME: See above (internal::faces_iter_'s default ctor). + faces_bkd_iter_(complex<D>& c); + faces_bkd_iter_(const self_& rhs); + self_& operator= (const self_& rhs); + /// \} + + /// Manipulation. + /// \{ + /// Start an iteration. + void start(); + /// Go to the next point. + void next_(); + /// \} + + private: + using super_::face_; + }; + + + +# ifndef MLN_INCLUDE_ONLY + + /*---------------------------------. + | internal::faces_iter_<N, D, E>. | + `---------------------------------*/ + + namespace internal + { + + template <unsigned N, unsigned D, typename E> + inline + faces_iter_<N, D, E>::faces_iter_(complex<D>& c) + { + // Ensure N is compatible with D. + metal::bool_< N <= D >::check(); + + face_.set_cplx(c); + // Invalidate face_. + invalidate(); + } + + template <unsigned N, unsigned D, typename E> + inline + faces_iter_<N, D, E>::faces_iter_(const faces_iter_<N, D, E>& rhs) + : face_(rhs.face_) + { + // Ensure N is compatible with D. + metal::bool_< N <= D >::check(); + } + + template <unsigned N, unsigned D, typename E> + inline + faces_iter_<N, D, E>& + faces_iter_<N, D, E>::operator=(const faces_iter_<N, D, E>& rhs) + { + if (&rhs == this) + return *this; + face_ = rhs.face_; + return *this; + } + + template <unsigned N, unsigned D, typename E> + inline + bool + faces_iter_<N, D, E>::is_valid() const + { + return face_.is_valid(); + } + + template <unsigned N, unsigned D, typename E> + inline + void + faces_iter_<N, D, E>::invalidate() + { + face_.set_face_id(invalid_unsigned_()); + } + + template <unsigned N, unsigned D, typename E> + inline + const face_handle<N, D>& + faces_iter_<N, D, E>::to_face() const + { + return face_; + } + + template <unsigned N, unsigned D, typename E> + inline + faces_iter_<N, D, E>::operator face_handle<N, D>() const + { + mln_precondition(is_valid()); + return face_; + } + + template <unsigned N, unsigned D, typename E> + unsigned + faces_iter_<N, D, E>::invalid_unsigned_() const + { + return std::numeric_limits<unsigned>::max(); + } + + template <unsigned N, unsigned D, typename E> + inline + std::ostream& + operator<<(std::ostream& ostr, const faces_iter_<N, D, E>& p) + { + /* FIXME: We should use p.to_face() here, but as it lacks the + precondition the conversion operator has, so we use the latter. + + We should + - rename `to_face' as `to_face_'; + - write a new `to_face' routine checking the validity of the + iterator; + - have the conversion operator to face use this new `to_face' + routine; + - adjust former clients of `to_face' + + This is a general remark that applies to all iterators of + Milena. */ + typename faces_iter_<N, D, E>::face f = p; + return ostr << "(dim = " << N << ", id = " << f.face_id() << ')'; + } + + } // end of mln::internal + + + /*------------------------. + | faces_fwd_iter_<N, D>. | + `------------------------*/ + + template <unsigned N, unsigned D> + inline + faces_fwd_iter_<N, D>::faces_fwd_iter_(complex<D>& c) + : super_(c) + { + // Ensure N is compatible with D. + metal::bool_< N <= D >::check(); + } + + template <unsigned N, unsigned D> + inline + faces_fwd_iter_<N, D>::faces_fwd_iter_(const faces_fwd_iter_<N, D>& rhs) + : super_(rhs) + { + // Ensure N is compatible with D. + metal::bool_< N <= D >::check(); + } + + template <unsigned N, unsigned D> + inline + faces_fwd_iter_<N, D>& + faces_fwd_iter_<N, D>::operator=(const faces_fwd_iter_<N, D>& rhs) + { + if (&rhs == this) + return *this; + super_::operator=(rhs); + return *this; + } + + template <unsigned N, unsigned D> + inline + void + faces_fwd_iter_<N, D>::start() + { + face_.set_face_id(0u); + } + + template <unsigned N, unsigned D> + inline + void + faces_fwd_iter_<N, D>::next_() + { + if (is_valid()) + { + unsigned face_id = face_.face_id(); + if (face_id + 1 < face_.cplx().template nfaces<N>()) + /* FIXME: Provide accessor face_handle::n() returning + a mutable reference? This way, we could just write + + ++face_.face_id(); + + instead of the following. */ + face_.set_face_id(face_id + 1); + else + invalidate(); + } + } + + + /*------------------------. + | faces_bkd_iter_<N, D>. | + `------------------------*/ + + // FIXME: Resume here. + + template <unsigned N, unsigned D> + inline + faces_bkd_iter_<N, D>::faces_bkd_iter_(complex<D>& c) + : super_(c) + { + // Ensure N is compatible with D. + metal::bool_< N <= D >::check(); + } + + template <unsigned N, unsigned D> + inline + faces_bkd_iter_<N, D>::faces_bkd_iter_(const faces_bkd_iter_<N, D>& rhs) + : super_(rhs) + { + // Ensure N is compatible with D. + metal::bool_< N <= D >::check(); + } + + template <unsigned N, unsigned D> + inline + faces_bkd_iter_<N, D>& + faces_bkd_iter_<N, D>::operator=(const faces_bkd_iter_<N, D>& rhs) + { + if (&rhs == this) + return *this; + super_::operator=(rhs); + return *this; + } + + template <unsigned N, unsigned D> + inline + void + faces_bkd_iter_<N, D>::start() + { + face_.set_face_id(face_.cplx().template nfaces<N>() - 1); + } + + template <unsigned N, unsigned D> + inline + void + faces_bkd_iter_<N, D>::next_() + { + if (is_valid()) + { + unsigned face_id = face_.face_id(); + if (face_id > 0) + /* FIXME: Provide accessor face_handle::n() returning + a mutable reference? This way, we could just write + + ++face_.face_id(); + + instead of the following. */ + face_.set_face_id(face_id - 1); + else + invalidate(); + } + } + +# endif // ! MLN_INCLUDE_ONLY + +} // end of mln + + +#endif // ! MLN_CORE_FACES_ITER_HH diff --git a/milena/mln/core/macros.hh b/milena/mln/core/macros.hh index a7376ca..d098814 100644 --- a/milena/mln/core/macros.hh +++ b/milena/mln/core/macros.hh @@ -51,6 +51,12 @@ # define mln_bkd_citer_(T) T::bkd_citer /// \} +/// Shortcuts to access the (N-faces) bkd_fiter type associated to T. +/// \{ +# define mln_bkd_fiter(N, T) typename T::template bkd_fiter< N >::ret +# define mln_bkd_fiter_(N, T) T:: bkd_fiter< N >::ret +/// \} + /// Shortcuts to access the bkd_niter type associated to T. /// \{ # define mln_bkd_niter(T) typename T::bkd_niter @@ -123,12 +129,24 @@ // f +/// Shortcuts to access the (N-faces) fiter type associated to T. +/// \{ +# define mln_fiter(N, T) typename T::template fwd_fiter< N >::ret +# define mln_fiter_(N, T) T:: fwd_fiter< N >::ret +/// \} + /// Shortcuts to access the fwd_citer type associated to T. /// \{ # define mln_fwd_citer(T) typename T::fwd_citer # define mln_fwd_citer_(T) T::fwd_citer /// \} +/// Shortcuts to access the (N-faces) fwd_fiter type associated to T. +/// \{ +# define mln_fwd_fiter(N, T) typename T::template fwd_fiter< N >::ret +# define mln_fwd_fiter_(N, T) T:: fwd_fiter< N >::ret +/// \} + /// Shortcuts to access the fwd_niter type associated to T. /// \{ # define mln_fwd_niter(T) typename T::fwd_niter diff --git a/milena/tests/core/complex.cc b/milena/tests/core/complex.cc index 91bae55..49ec3d4 100644 --- a/milena/tests/core/complex.cc +++ b/milena/tests/core/complex.cc @@ -32,11 +32,15 @@ #include <mln/core/complex.hh> +using namespace mln; + + +// Forward declaration. +template <unsigned N, unsigned D> void test_faces_iter(complex<D>& c); + int main() { - using namespace mln; - /* A 2-d (simplicial) complex and its adjacency graph. v0 e3 v3 @@ -94,7 +98,8 @@ int main() << "Using ``dynamic'' manipulators." << std::endl << " number of 0-faces: c.nfaces(0) = " << c.nfaces(0) << std::endl << " number of 1-faces: c.nfaces(1) = " << c.nfaces(1) << std::endl - << " number of 2-faces: c.nfaces(2) = " << c.nfaces(2) << std::endl; + << " number of 2-faces: c.nfaces(2) = " << c.nfaces(2) << std::endl + << std::endl; /*-------------------. | Handles and data. | @@ -110,24 +115,31 @@ int main() mln_assertion(&face1 == &face2); - /*------------. | Iteration. | `------------*/ // FIXME: Possibly split this test (create a test for iterators). + // --------------- // + // Iterator on C. // + // --------------- // + // Iterators on a complex (not complex_image), or more precisely on // (all) the faces of complex C. mln_fwd_citer_(complex<D>) fwd_f(c); - for_all(fwd_f) - std::cout << fwd_f << std::endl; - + mln_bkd_citer_(complex<D>) bkd_f(c); + for_all_2(fwd_f, bkd_f) + std::cout << fwd_f << ' ' << bkd_f << std::endl; std::cout << std::endl; - mln_bkd_citer_(complex<D>) bkd_f(c); - for_all(bkd_f) - std::cout << bkd_f << std::endl; + // -------------------------- // + // Iterator on n-faces of C. // + // -------------------------- // + + test_faces_iter<0>(c); + test_faces_iter<1>(c); + test_faces_iter<2>(c); /* FIXME: Exercice more iterators (see milena/tests/core/complex_image.cc) and ticket #162 @@ -135,3 +147,14 @@ int main() // ... } + +template <unsigned N, unsigned D> +void +test_faces_iter(complex<D>& c) +{ + mln_fwd_fiter(N, complex<D>) fwd_nf(c); + mln_bkd_fiter(N, complex<D>) bkd_nf(c); + for_all_2(fwd_nf, bkd_nf) + std::cout << fwd_nf << ' ' << bkd_nf << std::endl; + std::cout << std::endl; +} -- 1.6.0.1
participants (1)
-
Roland Levillain