2078: Make the computation of the bbox of an mln::p_set<P> lazy.

https://svn.lrde.epita.fr/svn/oln/trunk/milena Now, mln::p_set<P>'s and mln::p_array<P>'s implementations are much closer one another. Index: ChangeLog from Roland Levillain <roland@lrde.epita.fr> Make the computation of the bbox of an mln::p_set<P> lazy. * mln/core/p_set.hh (mln::p_set<P>::point): New typedef. Use it... (mln::p_set<P>::bbox): ...in the declaration of this method. (mln::p_set<P>::bb_): Make it mutable. Change type from `accu::bbox<P>' to `accu::bbox<point>'. (mln::p_set<P>::bb_needs_update_): New attribute. (mln::p_set<P>::update_bb_): New method. (p_set<P>::p_set): Adjust ctor. (mln::p_set<P>::insert) (mln::p_set<P>::remove) (mln::p_set<P>::clear) (mln::p_set<P>::bbox): Adjust methods. * tests/core/point_set_compatibility.cc: Exercise p_set< graph_psite<point2d> >. mln/core/p_set.hh | 66 ++++++++++++++++++++++++---------- tests/core/point_set_compatibility.cc | 35 ++++++++++++++---- 2 files changed, 75 insertions(+), 26 deletions(-) Index: mln/core/p_set.hh --- mln/core/p_set.hh (revision 2077) +++ mln/core/p_set.hh (working copy) @@ -28,10 +28,9 @@ #ifndef MLN_CORE_P_SET_HH # define MLN_CORE_P_SET_HH -/*! \file mln/core/p_set.hh - * - * \brief Definition of a point set class based on std::set. - */ +/// \file mln/core/p_set.hh +/// \brief Definition of a point set class based on std::set, that can +/// behave also as a vector. # include <mln/core/internal/point_set_base.hh> # include <mln/core/internal/set_of.hh> @@ -42,13 +41,14 @@ namespace mln { - /*! \brief Point set class based on std::set. - * - * This is a mathematical set of points (not a multi-set). The - * parameter \p P shall be a Point type. - * - * \todo Test if \p P being a Point_Site is ok. - */ + /// \brief Point set class based on std::set. + /// + /// This is a mathematical set of points (not a multi-set). The + /// parameter \p P shall be a Point type or a Point_Site. + /// + /// FIXME: If \p is a Point_Site, but not a Point, the method + /// mln::p_set<P>::bbox will not compile (see below). (Will be fixed + /// with the merge with branch cleanup-2008.) template <typename P> class p_set : public internal::point_set_base_< P, p_set<P> >, private internal::set_of_<P> @@ -56,6 +56,16 @@ typedef internal::set_of_<P> super_; public: + /* FIXME: Should be removed as soon as branch cleanup-2008 is + merged with the trunk. */ + typedef mln_point(P) point; + + /* FIXME: mln::p_set uses the same iterators as mln::p_array, + because mln::p_set also have the interface of an array. We + might want to keep this, but we should change the name of the + iterator, either by using an alias (typedef), of by giving them + their own type (which could share code with + mln::p_array_{fwd,bkd}_piter_, of course). */ /// Forward Point_Iterator associated type. typedef p_array_fwd_piter_<P> fwd_piter; @@ -87,12 +97,16 @@ /// Clear this set. void clear(); + /* FIXME: Won't work if P is not (implicitly) convertible to + mln_point(P). */ /// Give the exact bounding box. - const box_<mln_point(P)>& bbox() const; + const box_<point>& bbox() const; protected: + mutable accu::bbox<point> bb_; + mutable bool bb_needs_update_; - accu::bbox<P> bb_; + void update_bb_() const; // FIXME: Add invariant bb_.is_valid() <=> npoints() != 0 }; @@ -102,11 +116,24 @@ template <typename P> inline p_set<P>::p_set() + : bb_needs_update_(false) { } template <typename P> inline + void + p_set<P>::update_bb_() const + { + bb_.init(); + for (typename std::set<P>::const_iterator i = this->s_.begin(); + i != this->s_.end(); ++i) + bb_.take(*i); + bb_needs_update_ = false; + } + + template <typename P> + inline bool p_set<P>::has(const P& p) const { @@ -127,7 +154,8 @@ p_set<P>::insert(const P& p) { this->super_::insert(p); - bb_.take(p); + if (! bb_needs_update_) + bb_needs_update_ = true; return *this; } @@ -137,11 +165,8 @@ p_set<P>::remove(const P& p) { this->super_::remove(p); - // Rebuild the bounding box. - bb_.init(); - for (typename std::set<P>::const_iterator i = this->s_.begin(); - i != this->s_.end(); ++i) - bb_.take(*i); + if (! bb_needs_update_) + bb_needs_update_ = true; return *this; } @@ -161,6 +186,7 @@ { this->super_::clear(); bb_.init(); + bb_needs_update_ = false; } template <typename P> @@ -169,6 +195,8 @@ p_set<P>::bbox() const { mln_precondition(npoints() != 0); + if (bb_needs_update_) + update_bb_(); return bb_.to_result(); } Index: tests/core/point_set_compatibility.cc --- tests/core/point_set_compatibility.cc (revision 2077) +++ tests/core/point_set_compatibility.cc (working copy) @@ -32,6 +32,7 @@ #include <mln/core/point2d.hh> #include <mln/core/p_array.hh> +#include <mln/core/p_set.hh> #include <mln/core/graph_psite.hh> #include <mln/core/p_graph_piter.hh> @@ -69,21 +70,41 @@ // Graph point set. + typedef p_graph<point2d> pg_t; p_graph<point2d> pg(g); - - - // Array of graph point sites. typedef graph_psite<point2d> gpsite_t; - p_array<gpsite_t> pa; + { + // Array of graph point sites. + typedef p_array<gpsite_t> pa_t; + pa_t pa; // Tests: copying all psites from PG to PA. - p_graph_fwd_piter_<point2d> p(pg); + mln_piter_(pg_t) p(pg); for_all (p) pa.append (p); // Test: create and use an iterator over PA. - p_array_fwd_piter_<gpsite_t> p2(pa); + mln_piter_(pa_t) p2(pa); for_all (p2) - std::cout << p2 << std::endl; + std::cout << p2 << ' '; + std::cout << std::endl; + } + + { + // Set of graph point sites. + typedef p_set<gpsite_t> ps_t; + ps_t ps; + + // Tests: copying all psites from PG to PS. + mln_piter_(pg_t) p(pg); + for_all (p) + ps.insert(p); + + // Test: create and use an iterator over PS. + mln_piter_(ps_t) p2(ps); + for_all (p2) + std::cout << p2 << ' '; + std::cout << std::endl; + } }
participants (1)
-
Roland Levillain