milena r1133: add tracked pointer for images

URL: https://svn.lrde.epita.fr/svn/oln/trunk/milena ChangeLog: 2007-09-19 Matthieu Garrigues <garrigues@lrde.epita.fr> add tracked pointer for images * image2d_b.hh: * image2d_b_data.hh: move image data into an imaage2d_b_data class, then hold it with a tracked pointer to avoid useless data copy like in olena * internal/tracked_ptr.hh: tracked pointer class from olena. fix a bug related to invariant_ call to optimize data access. --- image2d_b.hh | 135 +++++------------------ image2d_b_data.hh | 131 ++++++++++++++++++++++ internal/tracked_ptr.hh | 281 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 443 insertions(+), 104 deletions(-) Index: trunk/milena/mln/core/image2d_b_data.hh =================================================================== --- trunk/milena/mln/core/image2d_b_data.hh (revision 0) +++ trunk/milena/mln/core/image2d_b_data.hh (revision 1133) @@ -0,0 +1,131 @@ +// Copyright (C) 2007 EPITA Research and Development Laboratory +// +// 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. This exception does not however invalidate any other +// reasons why the executable file might be covered by the GNU General +// Public License. + +#ifndef MLN_IMAGE2D_B_DATA_HH +# define MLN_IMAGE2D_B_DATA_HH + +/*! \file mln/core/image2d_b_data.hh + * + * \brief Definition of the basic mln::image2d_b_data class. + */ + +# include <mln/core/internal/image_base.hh> +# include <mln/core/box2d.hh> + +# include <mln/fun/i2v/all.hh> + +namespace mln +{ + template <typename T> + struct image2d_b_data + { + public: + image2d_b_data(const box2d& b, unsigned bdr); + ~image2d_b_data(); + + T* buffer_; + T** array_; + + box2d b_; // theoretical box + unsigned bdr_; + box2d vb_; // virtual box, i.e., box including the virtual border + + void update_vb_(); + void allocate_(); + void deallocate_(); + + }; + + + template <typename T> + image2d_b_data<T>::image2d_b_data(const box2d& b, unsigned bdr) + : buffer_(0), + array_ (0), + b_ (b), + bdr_ (bdr) + { + allocate_(); + } + + template <typename T> + image2d_b_data<T>::~image2d_b_data() + { + deallocate_(); + } + + + // private + + template <typename T> + void + image2d_b_data<T>::update_vb_() + { + vb_.pmin() = b_.pmin() - dpoint2d(all(bdr_)); + vb_.pmax() = b_.pmax() + dpoint2d(all(bdr_)); + } + + template <typename T> + void + image2d_b_data<T>::allocate_() + { + update_vb_(); + unsigned + nr = vb_.len(0), + nc = vb_.len(1); + buffer_ = new T[nr * nc]; + array_ = new T*[nr]; + T* buf = buffer_ - vb_.pmin().col(); + for (unsigned i = 0; i < nr; ++i) + { + array_[i] = buf; + buf += nc; + } + array_ -= vb_.pmin().row(); + mln_postcondition(vb_.len(0) == b_.len(0) + 2 * bdr_); + mln_postcondition(vb_.len(1) == b_.len(1) + 2 * bdr_); + } + + template <typename T> + void + image2d_b_data<T>::deallocate_() + { + if (buffer_) + { + delete[] buffer_; + buffer_ = 0; + } + if (array_) + { + array_ += vb_.pmin().row(); + delete[] array_; + array_ = 0; + } + } + +} + +#endif // ! MLN_IMAGE2D_B_DATA_HH Index: trunk/milena/mln/core/internal/tracked_ptr.hh =================================================================== --- trunk/milena/mln/core/internal/tracked_ptr.hh (revision 0) +++ trunk/milena/mln/core/internal/tracked_ptr.hh (revision 1133) @@ -0,0 +1,281 @@ +// Copyright (C) 2006 EPITA Research and Development Laboratory +// +// 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. This exception does not however invalidate any other +// reasons why the executable file might be covered by the GNU General +// Public License. + +#ifndef MLN_CORE_INTERNAL_TRACKED_PTR_HH +# define MLN_CORE_INTERNAL_TRACKED_PTR_HH + +# include <set> +# include <ostream> + +# include <mln/core/contract.hh> + + +namespace mln +{ + + template <typename T> + struct tracked_ptr + { + typedef tracked_ptr<T> self_t; + typedef std::set<self_t*> holders_t; + + T* ptr_; + holders_t* holders_; + + /// Coercion towards Boolean (for arithmetical tests). + operator bool() const; + + /// Negation (for arithmetical tests). + bool operator not() const; + + /*! \brief Mimics the behavior of op-> for a pointer in the const case. + ** + ** \invariant Pointer proxy exists. + */ + const T*const operator->() const; + + /*! \brief Mimics the behavior of op-> for a pointer in the mutable case. + ** + ** \invariant Pointer proxy exists. + */ + T*const operator->(); + + /// Ctor. + tracked_ptr(); + + /// Ctor. + tracked_ptr(T* ptr); + + /// Cpy ctor. + tracked_ptr(const tracked_ptr<T>& rhs); + + /// Assignment. + tracked_ptr<T>& operator=(const tracked_ptr<T>& rhs); + + /// Assignment. + tracked_ptr<T>& operator=(T* ptr); + + /// Dtor. + ~tracked_ptr(); + + bool run_() const; + + void clean_(); + + }; + + + + +# ifndef MLN_INCLUDE_ONLY + + template <typename T> + tracked_ptr<T>::operator bool() const + { + mln_invariant(run_()); + return ptr_ != 0; + } + + template <typename T> + /// Negation (for arithmetical tests). + bool tracked_ptr<T>::operator not() const + { + mln_invariant(run_()); + return not bool(*this); + } + + template <typename T> + /*! \brief Mimics the behavior of op-> for a pointer in the const case. + ** + ** \invariant Pointer proxy exists. + */ + const T*const tracked_ptr<T>::operator->() const + { + mln_invariant(run_()); + mln_precondition(ptr_ != 0); + return ptr_; + } + + template <typename T> + /*! \brief Mimics the behavior of op-> for a pointer in the mutable case. + ** + ** \invariant Pointer proxy exists. + */ + T*const tracked_ptr<T>::operator->() + { + mln_invariant(run_()); + mln_precondition(ptr_ != 0); + return ptr_; + } + + template <typename T> + /// Ctor. + tracked_ptr<T>::tracked_ptr() : + ptr_(0), + holders_(0) + { + mln_invariant(run_()); + } + + template <typename T> + /// Ctor. + tracked_ptr<T>::tracked_ptr(T* ptr) : + ptr_(ptr) + { + typedef std::set<tracked_ptr<T>*> holders_t; + + if (ptr == 0) + holders_ = 0; + else + { + holders_ = new holders_t; + holders_->insert(this); + } + mln_invariant(run_()); + } + + template <typename T> + /// Cpy ctor. + tracked_ptr<T>::tracked_ptr(const tracked_ptr<T>& rhs) : + ptr_(rhs.ptr_), + holders_(rhs.holders_) + { + mln_invariant(rhs.run_()); + if (ptr_ != 0) + holders_->insert(this); + mln_invariant(run_()); + } + + template <typename T> + /// Assignment. + tracked_ptr<T>& tracked_ptr<T>::operator=(const tracked_ptr<T>& rhs) + { + mln_invariant(run_()); + mln_invariant(rhs.run_()); + if (&rhs == this or rhs.ptr_ == ptr_) + // no-op + return *this; + clean_(); + ptr_ = rhs.ptr_; + holders_ = rhs.holders_; + holders_->insert(this); + return *this; + } + + template <typename T> + /// Assignment. + tracked_ptr<T>& tracked_ptr<T>::operator=(T* ptr) + { + typedef std::set<tracked_ptr<T>*> holders_t; + + mln_invariant(run_()); + if (ptr == ptr_) + // no-op + return *this; + clean_(); + ptr_ = ptr; + if (ptr == 0) + holders_ = 0; + else + { + holders_ = new holders_t; + holders_->insert(this); + } + return *this; + } + + /// Dtor. + template <typename T> + tracked_ptr<T>::~tracked_ptr() + { + clean_(); + } + + template <typename T> + bool tracked_ptr<T>::run_() const + { + typedef std::set<tracked_ptr<T>*> holders_t; + + mln_invariant((ptr_ and holders_) or (not ptr_ and not holders_)); + if (ptr_ == 0) + return true; + mln_invariant(holders_->size() > 0); + tracked_ptr<T>* this_ = const_cast<tracked_ptr<T>*>(this); + mln_invariant(holders_->find(this_) != holders_->end()); + this_ = 0; + typename holders_t::const_iterator i; + for (i = holders_->begin(); i != holders_->end(); ++i) + mln_invariant((*i)->ptr_ == ptr_); + return true; + } + + template <typename T> + void tracked_ptr<T>::clean_() + { + mln_invariant(run_()); + if (ptr_ == 0) + // no-op + return; + if (holders_->size() == 1) + { + delete ptr_; + delete holders_; + } + else + holders_->erase(this); + ptr_ = 0; + holders_ = 0; + mln_invariant(run_()); + } + + template <typename T> + std::ostream& operator<<(std::ostream& ostr, const tracked_ptr<T>& tp) + { + typedef std::set<tracked_ptr<T>*> holders_t; + + ostr << "tracked_ptr @ " << (&tp) + << " { ptr = " << tp.ptr_ + << " / holders = "; + if (tp.holders_ == 0) + ostr << "0"; + else + { + typename holders_t::const_iterator i; + for (i = tp.holders_->begin(); i != tp.holders_->end(); ++i) + ostr << (*i) << ' '; + } + ostr << " }"; + return ostr; + } + + +# endif + +} // end of namespace mln + + +#endif // ! MLN_CORE_INTERNAL_TRACKED_PTR_HH Index: trunk/milena/mln/core/image2d_b.hh =================================================================== --- trunk/milena/mln/core/image2d_b.hh (revision 1132) +++ trunk/milena/mln/core/image2d_b.hh (revision 1133) @@ -42,6 +42,9 @@ # include <mln/core/line_piter.hh> +# include <mln/core/internal/tracked_ptr.hh> +# include <mln/core/image2d_b_data.hh> + // FIXME: // # include <mln/core/pixter2d_b.hh> @@ -128,6 +131,9 @@ /// Destructor. ~image2d_b(); + /// detach data from an image (free it if nobody else hold it) + void destroy(); + /// Initialize an empty image. void init_with(int nrows, int ncols, unsigned bdr = border::thickness); @@ -190,16 +196,7 @@ private: - T* buffer_; - T** array_; - - box2d b_; // theoretical box - unsigned bdr_; - box2d vb_; // virtual box, i.e., box including the virtual border - - void update_vb_(); - void allocate_(); - void deallocate_(); + tracked_ptr< image2d_b_data<T> > data_; typedef internal::image_base_< box2d, image2d_b<T> > super; }; @@ -212,16 +209,13 @@ template <typename T> image2d_b<T>::image2d_b() - : buffer_(0), - array_ (0) + : data_(0) { - bdr_ = border::thickness; // default value in ctors. } template <typename T> image2d_b<T>::image2d_b(int nrows, int ncols, unsigned bdr) - : buffer_(0), - array_ (0) + : data_(0) { init_with(nrows, ncols, bdr); } @@ -231,15 +225,11 @@ image2d_b<T>::init_with(int nrows, int ncols, unsigned bdr) { mln_precondition(! this->has_data()); - b_ = make::box2d(nrows, ncols); - bdr_ = bdr; - allocate_(); + data_ = new image2d_b_data<T>(make::box2d(nrows, ncols), bdr); } template <typename T> image2d_b<T>::image2d_b(const box2d& b, unsigned bdr) - : buffer_(0), - array_ (0) { init_with(b, bdr); } @@ -249,21 +239,14 @@ image2d_b<T>::init_with(const box2d& b, unsigned bdr) { mln_precondition(! this->has_data()); - b_ = b; - bdr_ = bdr; - allocate_(); + data_ = new image2d_b_data<T>(b, bdr); } template <typename T> image2d_b<T>::image2d_b(const image2d_b<T>& rhs) : super(rhs), - b_(rhs.domain()), - bdr_(rhs.border()) + data_(rhs.data_) { - allocate_(); - std::memcpy(this->buffer_, - rhs.buffer_, - ncells() * sizeof(T)); } // assignment @@ -275,14 +258,8 @@ mln_precondition(rhs.has_data()); if (& rhs == this) return *this; - if (this->has_data()) - this->deallocate_(); - this->b_ = rhs.domain(); - this->bdr_ = rhs.border(); - allocate_(); - std::memcpy(this->buffer_, - rhs.buffer_, - ncells() * sizeof(T)); + + this->data_ = rhs.data_; return *this; } @@ -292,7 +269,7 @@ bool image2d_b<T>::has_data() const { - return buffer_ != 0 && array_ != 0; + return data_ != 0; } template <typename T> @@ -307,7 +284,7 @@ image2d_b<T>::domain() const { mln_precondition(this->has_data()); - return b_; + return data_->b_; } template <typename T> @@ -315,7 +292,7 @@ image2d_b<T>::border() const { mln_precondition(this->has_data()); - return bdr_; + return data_->bdr_; } template <typename T> @@ -323,7 +300,7 @@ image2d_b<T>::ncells() const { mln_precondition(this->has_data()); - return vb_.npoints(); + return data_->vb_.npoints(); } template <typename T> @@ -331,7 +308,7 @@ image2d_b<T>::owns_(const point2d& p) const { mln_precondition(this->has_data()); - return vb_.has(p); + return data_->vb_.has(p); } template <typename T> @@ -339,7 +316,7 @@ image2d_b<T>::operator()(const point2d& p) const { mln_precondition(this->owns_(p)); - return array_[p.row()][p.col()]; + return data_->array_[p.row()][p.col()]; } template <typename T> @@ -347,7 +324,7 @@ image2d_b<T>::operator()(const point2d& p) { mln_precondition(this->owns_(p)); - return array_[p.row()][p.col()]; + return data_->array_[p.row()][p.col()]; } template <typename T> @@ -355,7 +332,7 @@ image2d_b<T>::operator[](unsigned o) const { mln_precondition(o < ncells()); - return *(buffer_ + o); + return *(data_->buffer_ + o); } template <typename T> @@ -363,7 +340,7 @@ image2d_b<T>::operator[](unsigned o) { mln_precondition(o < ncells()); - return *(buffer_ + o); + return *(data_->buffer_ + o); } template <typename T> @@ -371,7 +348,7 @@ image2d_b<T>::at(int row, int col) const { mln_precondition(this->owns_(make::point2d(row, col))); - return array_[row][col]; + return data_->array_[row][col]; } template <typename T> @@ -379,13 +356,12 @@ image2d_b<T>::at(int row, int col) { mln_precondition(this->owns_(make::point2d(row, col))); - return array_[row][col]; + return data_->array_[row][col]; } template <typename T> image2d_b<T>::~image2d_b() { - deallocate_(); } template <typename T> @@ -393,7 +369,7 @@ image2d_b<T>::buffer() const { mln_precondition(this->has_data()); - return buffer_; + return data_->buffer_; } template <typename T> @@ -401,7 +377,7 @@ image2d_b<T>::buffer() { mln_precondition(this->has_data()); - return buffer_; + return data_->buffer_; } template <typename T> @@ -409,7 +385,7 @@ image2d_b<T>::offset(const dpoint2d& dp) const { mln_precondition(this->has_data()); - int o = dp[0] * vb_.len(1) + dp[1]; + int o = dp[0] * data_->vb_.len(1) + dp[1]; return o; } @@ -418,61 +394,12 @@ image2d_b<T>::point_at_offset(unsigned o) const { mln_precondition(o < ncells()); - point2d p = make::point2d(o / vb_.len(1) + vb_.min_row(), - o % vb_.len(1) + vb_.min_col()); - mln_postcondition(& this->operator()(p) == this->buffer_ + o); + point2d p = make::point2d(o / data_->vb_.len(1) + data_->vb_.min_row(), + o % data_->vb_.len(1) + data_->vb_.min_col()); + mln_postcondition(& this->operator()(p) == this->data_->buffer_ + o); return p; } - - // private - - template <typename T> - void - image2d_b<T>::update_vb_() - { - vb_.pmin() = b_.pmin() - dpoint2d(all(bdr_)); - vb_.pmax() = b_.pmax() + dpoint2d(all(bdr_)); - } - - template <typename T> - void - image2d_b<T>::allocate_() - { - update_vb_(); - unsigned - nr = vb_.len(0), - nc = vb_.len(1); - buffer_ = new T[nr * nc]; - array_ = new T*[nr]; - T* buf = buffer_ - vb_.pmin().col(); - for (unsigned i = 0; i < nr; ++i) - { - array_[i] = buf; - buf += nc; - } - array_ -= vb_.pmin().row(); - mln_postcondition(vb_.len(0) == b_.len(0) + 2 * bdr_); - mln_postcondition(vb_.len(1) == b_.len(1) + 2 * bdr_); - } - - template <typename T> - void - image2d_b<T>::deallocate_() - { - if (buffer_) - { - delete[] buffer_; - buffer_ = 0; - } - if (array_) - { - array_ += vb_.pmin().row(); - delete[] array_; - array_ = 0; - } - } - # endif // ! MLN_INCLUDE_ONLY } // end of namespace mln
participants (1)
-
Matthieu Garrigues