URL:
https://svn.lrde.epita.fr/svn/oln/trunk/milena
ChangeLog:
2007-09-19 Matthieu Garrigues <garrigues(a)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