r2210: Add forward and backward iterators on complexes.

* mln/core/complex_iter.hh: New * mln/core/complex.hh: Add forward declarations for class complex_fwd_iter_ and class complex_bkd_iter_. (mln::complex<D>::fwd_citer, mln::complex<D>::bkd_citer): New typedefs. * mln/core/macros.hh (mln_citer, mln_citer_) (mln_bkd_citer, mln_bkd_citer_, mln_fwd_citer, mln_fwd_citer_): New shortcut macros. * tests/core/complex.cc: Exercise iterators on complexes. --- milena/ChangeLog | 14 ++ milena/mln/core/complex.hh | 11 +- milena/mln/core/complex_iter.hh | 449 +++++++++++++++++++++++++++++++++++++++ milena/mln/core/macros.hh | 18 ++ milena/tests/core/complex.cc | 24 ++ 5 files changed, 515 insertions(+), 1 deletions(-) create mode 100644 milena/mln/core/complex_iter.hh diff --git a/milena/ChangeLog b/milena/ChangeLog index 65eba6d..1778c8e 100644 --- a/milena/ChangeLog +++ b/milena/ChangeLog @@ -1,3 +1,17 @@ +2008-09-10 Roland Levillain <roland@lrde.epita.fr> + + Add forward and backward iterators on complexes. + + * mln/core/complex_iter.hh: New + * mln/core/complex.hh: Add forward declarations for class + complex_fwd_iter_ and class complex_bkd_iter_. + (mln::complex<D>::fwd_citer, mln::complex<D>::bkd_citer): + New typedefs. + * mln/core/macros.hh (mln_citer, mln_citer_) + (mln_bkd_citer, mln_bkd_citer_, mln_fwd_citer, mln_fwd_citer_): + New shortcut macros. + * tests/core/complex.cc: Exercise iterators on complexes. + 2008-09-05 Ugo Jardonnet <ugo.jardonnet@lrde.epita.fr> Minor fix : Translation Rotation. diff --git a/milena/mln/core/complex.hh b/milena/mln/core/complex.hh index 6715acd..c0c1b80 100644 --- a/milena/mln/core/complex.hh +++ b/milena/mln/core/complex.hh @@ -45,16 +45,20 @@ # include <mln/core/face.hh> +# include <mln/core/complex_iter.hh> + namespace mln { - // Forward declaration. + // Forward declarations. namespace internal { template <unsigned N, unsigned D> struct faces_set_mixin; } + template <unsigned D> class complex_fwd_iter_; + template <unsigned D> class complex_bkd_iter_; /*----------. @@ -66,6 +70,11 @@ namespace mln class complex : private internal::faces_set_mixin<D, D> { public: + /// Forward mln::Iterator associated type. + typedef complex_fwd_iter_<D> fwd_citer; + /// Backward mln::Iterator associated type. + typedef complex_bkd_iter_<D> bkd_citer; + /// Complex construction. /// \{ /// \brief Add a 0-face to the complex. diff --git a/milena/mln/core/complex_iter.hh b/milena/mln/core/complex_iter.hh new file mode 100644 index 0000000..f2701e3 --- /dev/null +++ b/milena/mln/core/complex_iter.hh @@ -0,0 +1,449 @@ +// 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_COMPLEX_ITER_HH +# define MLN_CORE_COMPLEX_ITER_HH + +/// \file mln/core/complex_iter.hh +/// \brief Definition of forward and backward iterators on complexes. + + +# include <limits> + +# include <mln/core/concept/iterator.hh> +# include <mln/core/complex.hh> + + +// Factor complex_fwd_iter_<D> and complex_bkd_iter_<D>? + +namespace mln +{ + + // Fwd decls. + template <unsigned D> class complex; + + + /*-----------------------. + | complex_fwd_iter_<D>. | + `-----------------------*/ + + /// \brief Forward iterator on all the faces of mln::complex<D>. + template <unsigned D> + class complex_fwd_iter_ : public Iterator< complex_fwd_iter_<D> > + { + typedef complex_fwd_iter_<D> self_; + + public: + typedef any_face_handle<D> face; + + /// Construction and assignment. + /// \{ + /* FIXME: Keep this non-const? See a (big) comment about this in + milena/tests/complex_image.cc. */ + complex_fwd_iter_(complex<D>& c); + complex_fwd_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(); + /// Start an iteration. + void start(); + + /// Go to the next point. + void next_(); + /// \} + + /// Conversion and accessors. + /// \{ + /// Reference to the corresponding any-face handle. + const face& to_face () const; + /// Convert the iterator into an any-face handle. + operator face() const; + /// \} + + private: + /// The face handle this iterator is pointing to. + face face_; + + /// \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 D> + inline + std::ostream& + operator<<(std::ostream& ostr, const complex_fwd_iter_<D>& p); + + + /*-----------------------. + | complex_bkd_iter_<D>. | + `-----------------------*/ + + /// \brief Backward iterator on all the faces of mln::complex<D>. + template <unsigned D> + class complex_bkd_iter_ : public Iterator< complex_bkd_iter_<D> > + { + typedef complex_bkd_iter_<D> self_; + + public: + typedef any_face_handle<D> face; + + /// Construction and assignment. + /// \{ + /* FIXME: Keep this non-const? See a (big) comment about this in + milena/tests/complex_image.cc. */ + complex_bkd_iter_(complex<D>& c); + complex_bkd_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(); + /// Start an iteration. + void start(); + + /// Go to the next point. + void next_(); + /// \} + + /// Conversion and accessors. + /// \{ + /// Reference to the corresponding any-face handle. + const face& to_face () const; + /// Convert the iterator into an any-face handle. + operator face() const; + /// \} + + private: + /// The face handle this iterator is pointing to. + face face_; + + /// \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 D> + inline + std::ostream& + operator<<(std::ostream& ostr, const complex_bkd_iter_<D>& p); + + + +# ifndef MLN_INCLUDE_ONLY + + /*-----------------------. + | complex_fwd_iter_<D>. | + `-----------------------*/ + + template <unsigned D> + inline + complex_fwd_iter_<D>::complex_fwd_iter_(complex<D>& c) + { + face_.set_cplx(c); + // Invalidate face_. + invalidate(); + } + + template <unsigned D> + inline + complex_fwd_iter_<D>::complex_fwd_iter_(const complex_fwd_iter_<D>& rhs) + : face_(rhs.face_) + { + } + + template <unsigned D> + inline + complex_fwd_iter_<D>& + complex_fwd_iter_<D>::operator=(const complex_fwd_iter_<D>& rhs) + { + if (&rhs == this) + return *this; + face_ = rhs.face_; + return *this; + } + + template <unsigned D> + inline + bool + complex_fwd_iter_<D>::is_valid() const + { + return face_.is_valid(); + } + + template <unsigned D> + inline + void + complex_fwd_iter_<D>::invalidate() + { + face_.set_n(invalid_unsigned_()); + face_.set_face_id(invalid_unsigned_()); + } + + template <unsigned D> + inline + void + complex_fwd_iter_<D>::start() + { + face_.set_n(0u); + face_.set_face_id(0u); + } + + template <unsigned D> + inline + void + complex_fwd_iter_<D>::next_() + { + if (is_valid()) + { + unsigned n = face_.n(); + unsigned face_id = face_.face_id(); + + if (face_id + 1 < face_.cplx().nfaces(n)) + /* FIXME: Provide accessor any_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 + // Start to iterate on the faces of the next dimension if + // possible. + if (n <= D) + { + // FIXME: Same remark as above. + face_.set_n(n + 1); + face_.set_face_id(0u); + } + else + invalidate(); + } + } + + template <unsigned D> + inline + const any_face_handle<D>& + complex_fwd_iter_<D>::to_face() const + { + return face_; + } + + template <unsigned D> + inline + complex_fwd_iter_<D>::operator any_face_handle<D>() const + { + mln_precondition(is_valid()); + return face_; + } + + template <unsigned D> + unsigned + complex_fwd_iter_<D>::invalid_unsigned_() const + { + return std::numeric_limits<unsigned>::max(); + } + + + template <unsigned D> + inline + std::ostream& + operator<<(std::ostream& ostr, const complex_fwd_iter_<D>& p) + { + return ostr << "(dim = " << p.to_face().n() + << ", id = " << p.to_face().face_id() << ')'; + } + + + /*-----------------------. + | complex_bkd_iter_<D>. | + `-----------------------*/ + + template <unsigned D> + inline + complex_bkd_iter_<D>::complex_bkd_iter_(complex<D>& c) + { + face_.set_cplx(c); + // Invalidate face_. + invalidate(); + } + + template <unsigned D> + inline + complex_bkd_iter_<D>::complex_bkd_iter_(const complex_bkd_iter_<D>& rhs) + : face_(rhs.face_) + { + } + + template <unsigned D> + inline + complex_bkd_iter_<D>& + complex_bkd_iter_<D>::operator=(const complex_bkd_iter_<D>& rhs) + { + if (&rhs == this) + return *this; + face_ = rhs.face_; + return *this; + } + + template <unsigned D> + inline + bool + complex_bkd_iter_<D>::is_valid() const + { + return face_.is_valid(); + } + + template <unsigned D> + inline + void + complex_bkd_iter_<D>::invalidate() + { + face_.set_n(invalid_unsigned_()); + face_.set_face_id(invalid_unsigned_()); + } + + template <unsigned D> + inline + void + complex_bkd_iter_<D>::start() + { + face_.set_n(D); + face_.set_face_id(face_.cplx().template nfaces<D>() - 1); + } + + template <unsigned D> + inline + void + complex_bkd_iter_<D>::next_() + { + if (is_valid()) + { + unsigned n = face_.n(); + unsigned face_id = face_.face_id(); + + if (face_id > 0) + /* FIXME: Provide accessor any_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 + // Start to iterate on the faces of the previous dimension + // if it exists. + if (n > 0) + { + // FIXME: Same remark as above. + face_.set_n(n - 1); + face_.set_face_id(face_.cplx().nfaces(n - 1) - 1); + } + else + invalidate(); + } + } + + template <unsigned D> + inline + const any_face_handle<D>& + complex_bkd_iter_<D>::to_face() const + { + return face_; + } + + template <unsigned D> + inline + complex_bkd_iter_<D>::operator any_face_handle<D>() const + { + mln_precondition(is_valid()); + return face_; + } + + template <unsigned D> + unsigned + complex_bkd_iter_<D>::invalid_unsigned_() const + { + return std::numeric_limits<unsigned>::max(); + } + + + template <unsigned D> + inline + std::ostream& + operator<<(std::ostream& ostr, const complex_bkd_iter_<D>& p) + { + return ostr << "(dim = " << p.to_face().n() + << ", id = " << p.to_face().face_id() << ')'; + } + +# endif // ! MLN_INCLUDE_ONLY + +} // end of mln + + +#endif // ! MLN_CORE_COMPLEX_ITER_HH diff --git a/milena/mln/core/macros.hh b/milena/mln/core/macros.hh index 705509f..a7376ca 100644 --- a/milena/mln/core/macros.hh +++ b/milena/mln/core/macros.hh @@ -45,6 +45,12 @@ // b +/// Shortcuts to access the bkd_citer type associated to T. +/// \{ +# define mln_bkd_citer(T) typename T::bkd_citer +# define mln_bkd_citer_(T) T::bkd_citer +/// \} + /// Shortcuts to access the bkd_niter type associated to T. /// \{ # define mln_bkd_niter(T) typename T::bkd_niter @@ -78,6 +84,12 @@ // c +/// Shortcuts to access the citer type associated to T. +/// \{ +# define mln_citer(T) typename T::fwd_citer +# define mln_citer_(T) T::fwd_citer +/// \} + /// Shortcuts to access the coord type associated to T. /// \{ # define mln_coord(T) typename T::coord @@ -111,6 +123,12 @@ // f +/// 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 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 ad3f991..1bacd6e 100644 --- a/milena/tests/core/complex.cc +++ b/milena/tests/core/complex.cc @@ -109,4 +109,28 @@ int main() const face<1, D>& face2 = af.to_face<1>(); mln_assertion(&face1 == &face2); + + + /*------------. + | Iteration. | + `------------*/ + + // Iterators on a complex (not complex_image), or more precisely on + // the faces of a complex. + + mln_fwd_citer_(complex<D>) ff(c); + for_all(ff) + std::cout << ff << std::endl; + + std::cout << std::endl; + + mln_bkd_citer_(complex<D>) bf(c); + for_all(bf) + std::cout << bf << std::endl; + + /* FIXME: Exercice more iterators (see + milena/tests/core/complex_image.cc) and ticket #162 + (https://trac.lrde.org/olena/ticket/162) */ + // ... + } -- 1.5.6.5

Roland Levillain <roland@lrde.epita.fr> writes:
* mln/core/complex_iter.hh: New * mln/core/complex.hh: Add forward declarations for class complex_fwd_iter_ and class complex_bkd_iter_. (mln::complex<D>::fwd_citer, mln::complex<D>::bkd_citer): New typedefs. * mln/core/macros.hh (mln_citer, mln_citer_) (mln_bkd_citer, mln_bkd_citer_, mln_fwd_citer, mln_fwd_citer_): New shortcut macros. * tests/core/complex.cc: Exercise iterators on complexes.
Patch made with Git + Cola + Alexandre's `dcommit' script. All of them are very very cool tools! Cola (http://cola.tuxfamily.org/, an alternative to git-gui) is not in Debian, but its author provides a Debian package: http://cola.tuxfamily.org/releases/ I used it because the current git-gui in Debian cannot add ``split hunks'' to the index (i.e. choose selected lines among the ones from a patch to be committed). All of this is very cool, and I'm very eager to share my (little) Git-knowledge with you (the Olena Team, and people from the lab).
participants (1)
-
Roland Levillain