* 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(a)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(a)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