2125: Add more services to complexes.

https://svn.lrde.epita.fr/svn/oln/trunk/milena Index: ChangeLog from Roland Levillain <roland@lrde.epita.fr> Add more services to complexes. * mln/core/complex.hh (mln::complex<D>::nfaces()) (mln::complex<D>::nfaces(unsigned)): New methods. (mln::complex<D>::fold_left_) (mln::complex<D>::apply_if_dim_matches_) (mln::internal::faces_set_mixin<N, D>::fold_left_): (mln::internal::faces_set_mixin<N, D>::apply_if_dim_matches_): New methods. (mln::internal::add_size) (mln::internal::get_size): New meta-functors. complex.hh | 323 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 316 insertions(+), 7 deletions(-) Index: mln/core/complex.hh --- mln/core/complex.hh (revision 2125) +++ mln/core/complex.hh (working copy) @@ -38,6 +38,7 @@ # include <cstddef> +# include <limits> # include <iosfwd> # include <mln/metal/bool.hh> @@ -67,7 +68,6 @@ public: /// Complex construction. /// \{ - /// \brief Add a 0-face to the complex. face_handle<0u, D> add_face(); @@ -79,9 +79,31 @@ face_handle<N + 1, D> add_face(const faces_set<N, D>& adjacent_faces); /// \} + /// \brief Static manipulators. + /// + /// These methods use statically-known input. + /// \{ + /// \brief Return the total number of faces, whatever their + /// dimension. + std::size_t nfaces() const; + /// \brief Return the number of \p N-faces. template <unsigned N> std::size_t nfaces() const; + /// \} + + /// \brief Dynamic manipulators. + /// + /// These methods use input know as run time. + /// \{ + /// \brief Return the number of \a n-faces. + /// + /// Warning, this function has a complexity linear in term of N, + /// since each faces_set is checked (the present implementation + /// does not provide a direct access to faces_set through a + /// dynamic value of the dimension). + std::size_t nfaces(unsigned n) const; + /// \} /// Pretty-printing. /// \{ @@ -104,6 +126,32 @@ const face<N, D>& face_(unsigned face_id) const; /// \} + /// Functional meta-manipulators. + /// \{ + /* FIXME: Use something more constraining than the STL's + UnaryFunction/BinaryFunction. Use Function or Function_v2v? + Or a new subclass of Function? */ + + /* FIXME: Replace F and ACCU by a Milena accumulator? */ + + /** \brief Apply a kind of static fold left operator to the + implicit list of faces_set using a functor \a f and a value \a + accu. + + Argument \a is called an "accumulator", but with a slightly + different meaning than mln:accu members. + + We might want to use TypeLists or something similar, is they + provide an explicit static fold left operator. */ + template <typename BinaryFunction, typename T> + T fold_left_(const BinaryFunction& f, const T& accu) const; + + /// \brief Apply a functor \a f to this list of \a n-faces. + template <typename UnaryFunction> + typename UnaryFunction::result_type + apply_if_dim_matches_(unsigned n, const UnaryFunction& f) const; + /// \} + /// \brief connect two faces. /// /// \param f1 A face of dimension \p N @@ -146,8 +194,8 @@ /// Faces of highest dimension (\p D). template <unsigned D> - struct faces_set_mixin<D, D> : faces_set_mixin<D - 1, D>, - lower_dim_faces_set_mixin<D, D> + struct faces_set_mixin<D, D> : public faces_set_mixin<D - 1, D>, + public lower_dim_faces_set_mixin<D, D> { std::vector< face<D, D> > faces_; @@ -157,13 +205,26 @@ void print(std::ostream& ostr) const; void print_rec_asc(std::ostream& ostr) const; /// \} + + /// Functional meta-manipulators. + /// \{ + /// \brief Fold left. + /// \see mln::complex<D>::fold_left_. + template <typename BinaryFunction, typename T> + T fold_left_(const BinaryFunction& f, const T& accu) const; + /// \brief Apply a functor \a f to the list of faces if \a n == \p D. + /// \see mln::complex<D>::apply_if_dim_matches_. + template <typename UnaryFunction> + typename UnaryFunction::result_type + apply_if_dim_matches_(unsigned n, const UnaryFunction& f) const; + /// \} }; /// Faces of intermediate dimension (greater than 0, lower than \p D). template <unsigned N, unsigned D> - struct faces_set_mixin : faces_set_mixin<N - 1, D>, - lower_dim_faces_set_mixin<N, D>, - higher_dim_faces_set_mixin<N, D> + struct faces_set_mixin : public faces_set_mixin<N - 1, D>, + public lower_dim_faces_set_mixin<N, D>, + public higher_dim_faces_set_mixin<N, D> { std::vector< face<N, D> > faces_; @@ -175,11 +236,24 @@ /// (in ascending dimension). void print_rec_asc(std::ostream& ostr) const; /// \} + + /// Functional meta-manipulators. + /// \{ + /// \brief Fold left. + /// \see mln::complex<D>::fold_left_. + template <typename BinaryFunction, typename T> + T fold_left_(const BinaryFunction& f, const T& accu) const; + /// \brief Apply a functor \a f to the list of faces if \a n == \p N. + /// \see mln::complex<D>::apply_if_dim_matches_. + template <typename UnaryFunction> + typename UnaryFunction::result_type + apply_if_dim_matches_(unsigned n, const UnaryFunction& f) const; + /// \} }; /// Faces of lowest dimension (0). template <unsigned D> - struct faces_set_mixin<0u, D> : higher_dim_faces_set_mixin<0u, D> + struct faces_set_mixin<0u, D> : public higher_dim_faces_set_mixin<0u, D> { std::vector< face<0u, D> > faces_; @@ -189,6 +263,19 @@ void print(std::ostream& ostr) const; void print_rec_asc(std::ostream& ostr) const; /// \} + + /// Functional meta-manipulators. + /// \{ + /// \brief Fold left. + /// \see mln::complex<D>::fold_left_. + template <typename BinaryFunction, typename T> + T fold_left_(const BinaryFunction& f, const T& accu) const; + /// \brief Apply a functor \a f to the list of faces if \a n == 0. + /// \see mln::complex<D>::apply_if_dim_matches_. + template <typename UnaryFunction> + typename UnaryFunction::result_type + apply_if_dim_matches_(unsigned n, const UnaryFunction& f) const; + /// \} }; /// Faces of a 0-complex. @@ -203,6 +290,19 @@ void print(std::ostream& ostr) const; void print_rec_asc(std::ostream& ostr) const; /// \} + + /// Functional meta-manipulators. + /// \{ + /// \brief Fold left. + /// \see mln::complex<D>::fold_left_. + template <typename BinaryFunction, typename T> + T fold_left_(const BinaryFunction& f, const T& accu) const; + /// \brief Apply a functor \a f to the list of faces if \a n == 0. + /// \see mln::complex<D>::apply_if_dim_matches_. + template <typename UnaryFunction> + typename UnaryFunction::result_type + apply_if_dim_matches_(unsigned n, const UnaryFunction& f) const; + /// \} }; /// \} @@ -233,6 +333,10 @@ # ifndef MLN_INCLUDE_ONLY + /*-----------------------. + | Complex construction. | + `-----------------------*/ + template <unsigned D> face_handle<0u, D> complex<D>::add_face() @@ -278,6 +382,64 @@ return fh; } + + /*-------. + | Misc. | + `-------*/ + + namespace internal + { + + /// A binary meta-functor defined by: + /// + /// \code + /// add_size : x, c -> x + c.size() + /// \endcode + /// + /// \see mln::complex<D>::nfaces (static version). + /// \see mln::complex<D>::fold_left_. + struct add_size + { + template <typename T, typename Container> + T operator()(const T& x, const Container& c) const + { + return x + c.size(); + } + }; + + /// An unary meta-functor defined by: + /// + /// \code + /// add_size : c -> c.size() + /// \endcode + /// + /// \see mln::complex<D>::nfaces (dynamic version). + /// \see mln::complex<D>::apply_if_dim_matches_. + struct get_size + { + typedef std::size_t result_type; + + template <typename Container> + typename Container::size_type operator()(const Container& c) const + { + return c.size(); + } + }; + + } // end of namespace mln::internal + + + /*----------------------. + | Static manipulators. | + `----------------------*/ + + template <unsigned D> + std::size_t + complex<D>::nfaces() const + { + return fold_left_(internal::add_size(), 0); + } + template <unsigned D> template <unsigned N> std::size_t @@ -286,6 +448,25 @@ return internal::faces_set_mixin<N, D>::faces_.size(); } + + /*-----------------------. + | Dynamic manipulators. | + `-----------------------*/ + + template <unsigned D> + std::size_t + complex<D>::nfaces(unsigned n) const + { + // Ensure N is compatible with D. + mln_precondition(n <= D); + return apply_if_dim_matches_(n, internal::get_size()); + } + + + /*-------------------. + | Internal methods. | + `-------------------*/ + template <unsigned D> template <unsigned N> face<N, D>& @@ -462,6 +643,134 @@ } // end of namespace mln::internal + + /*-------------------------------. + | Functional meta-manipulators. | + `-------------------------------*/ + + /* ------------------------------- */ + /* ``Static Fold Left'' Operator. */ + /* ------------------------------- */ + + template <unsigned D> + template <typename BinaryFunction, typename T> + T + complex<D>::fold_left_(const BinaryFunction& f, const T& accu) const + { + return internal::faces_set_mixin<D, D>::fold_left_(f, accu); + } + + namespace internal + { + + // FIXME: Try to factor. + + template <unsigned D> + template <typename BinaryFunction, typename T> + T + faces_set_mixin<D, D>::fold_left_(const BinaryFunction& f, + const T& accu) const + { + return faces_set_mixin<D - 1, D>::fold_left_(f, f(accu, faces_)); + } + + template <unsigned N, unsigned D> + template <typename BinaryFunction, typename T> + T + faces_set_mixin<N, D>::fold_left_(const BinaryFunction& f, + const T& accu) const + { + return faces_set_mixin<N - 1, D>::fold_left_(f, f(accu, faces_)); + } + + template <unsigned D> + template <typename BinaryFunction, typename T> + T + faces_set_mixin<0u, D>::fold_left_(const BinaryFunction& f, + const T& accu) const + { + return f(accu, faces_); + } + + template <typename BinaryFunction, typename T> + T + faces_set_mixin<0u, 0u>::fold_left_(const BinaryFunction& f, + const T& accu) const + { + return f(accu, faces_); + } + + } // end of namespace mln::internal + + + /* ------------------------------------------------ */ + /* ``Static Apply-If-Dimension-Matches'' Operator. */ + /* ------------------------------------------------ */ + + template <unsigned D> + template <typename UnaryFunction> + typename UnaryFunction::result_type + complex<D>::apply_if_dim_matches_(unsigned n, const UnaryFunction& f) const + { + // Ensure N is compatible with D. + mln_precondition(n <= D); + return internal::faces_set_mixin<D, D>::apply_if_dim_matches_(n, f); + } + + namespace internal + { + + // FIXME: Try to factor. + + template <unsigned D> + template <typename UnaryFunction> + typename UnaryFunction::result_type + faces_set_mixin<D, D>::apply_if_dim_matches_(unsigned n, + const UnaryFunction& f) const + { + // Ensure N and D are compatible. + mln_precondition(n <= D); + return n == D ? + f(faces_) : + faces_set_mixin<D - 1, D>::apply_if_dim_matches_(n, f); + } + + template <unsigned N, unsigned D> + template <typename UnaryFunction> + typename UnaryFunction::result_type + faces_set_mixin<N, D>::apply_if_dim_matches_(unsigned n, + const UnaryFunction& f) const + { + // Ensure N and D are compatible. + mln_precondition(n <= D); + return n == N ? + f(faces_) : + faces_set_mixin<N - 1, D>::apply_if_dim_matches_(n, f); + } + + template <unsigned D> + template <typename UnaryFunction> + typename UnaryFunction::result_type + faces_set_mixin<0u, D>::apply_if_dim_matches_(unsigned n, + const UnaryFunction& f) const + { + // If we reached this method, then N should be 0. + mln_precondition(n == 0); + return f(faces_); + } + + template <typename UnaryFunction> + typename UnaryFunction::result_type + faces_set_mixin<0u, 0u>::apply_if_dim_matches_(unsigned n, + const UnaryFunction& f) const + { + // If we reached this method, then N should be 0. + mln_precondition(n == 0); + return f(faces_); + } + + } // end of namespace mln::internal + # endif // ! MLN_INCLUDE_ONLY } // end of namespace mln
participants (1)
-
Roland Levillain