
* headers.mk: add new headers to distribution. * mln/util/soft_heap.hh: new file. New implementation. New members may be added later. * mln/util/tracked_ptr.hh: Fix an issue while assigning a null tracked_ptr to another tracked_ptr. An internal pointer was not initialized but dereferenced and led to a segfault. * tests/unit_test/Makefile.am, * tests/unit_test/mln_util_soft_heap.cc: add a new unit test. * tests/util/Makefile.am, * tests/util/soft_heap.cc: add a new test. --- milena/ChangeLog | 19 + milena/headers.mk | 1 + milena/mln/util/soft_heap.hh | 1137 ++++++++++++++++++++++++++ milena/mln/util/tracked_ptr.hh | 46 +- milena/tests/unit_test/Makefile.am | 2 + milena/tests/unit_test/mln_util_soft_heap.cc | 11 + milena/tests/util/Makefile.am | 2 + milena/tests/util/soft_heap.cc | 79 ++ 8 files changed, 1273 insertions(+), 24 deletions(-) create mode 100644 milena/mln/util/soft_heap.hh create mode 100644 milena/tests/unit_test/mln_util_soft_heap.cc create mode 100644 milena/tests/util/soft_heap.cc diff --git a/milena/ChangeLog b/milena/ChangeLog index 0166541..583f2d7 100644 --- a/milena/ChangeLog +++ b/milena/ChangeLog @@ -1,5 +1,24 @@ 2009-01-16 Guillaume Lazzara <z@lrde.epita.fr> + Add soft heap implementation. + + * headers.mk: add new headers to distribution. + + * mln/util/soft_heap.hh: new file. New implementation. New members may + be added later. + + * mln/util/tracked_ptr.hh: Fix an issue while assigning a null + tracked_ptr to another tracked_ptr. An internal pointer was not + initialized but dereferenced and led to a segfault. + + * tests/unit_test/Makefile.am, + * tests/unit_test/mln_util_soft_heap.cc: add a new unit test. + + * tests/util/Makefile.am, + * tests/util/soft_heap.cc: add a new test. + +2009-01-16 Guillaume Lazzara <z@lrde.epita.fr> + Rename histo::data as histo::array. * mln/histo/data.hh: rename file as... diff --git a/milena/headers.mk b/milena/headers.mk index fc78f90..9380631 100644 --- a/milena/headers.mk +++ b/milena/headers.mk @@ -64,6 +64,7 @@ mln/registration/icp.hh \ mln/util/graph.hh \ mln/util/max.hh \ mln/util/lazy_set.hh \ +mln/util/soft_heap.hh \ mln/util/set.hh \ mln/util/tree_to_image.hh \ mln/util/lemmings.hh \ diff --git a/milena/mln/util/soft_heap.hh b/milena/mln/util/soft_heap.hh new file mode 100644 index 0000000..144110f --- /dev/null +++ b/milena/mln/util/soft_heap.hh @@ -0,0 +1,1137 @@ +// Copyright (C) 2009 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. This exception does not however invalidate any other +// reasons why the executable file might be covered by the GNU General +// Public License. + +#ifndef MLN_UTIL_FAST_HEAP_HH +# define MLN_UTIL_FAST_HEAP_HH + +/// \file mln/util/soft_heap.hh +/// +/// Define a generic soft heap. +/* + This implementation is not an usual heap, it allows to set an error + rate so that some nodes may be "corrupted". A "corrupted node" means + that its correct order is not totally preserved for performance reasons. + Of course, it will have an impact on the returned values. + As a result, be ware of not using this data structure if the element + order is relevant for to you. + + A corruption threshold can be passed to the constructor. + This threshold means that if nodes have a rank higher than this + threshold they can be "corrupted" and therefore their rank can be + reduced. Tuning this threshold may have an impact on the structure + entropy thus on the returned values order. It may also have an impact + on the performance. + + + More implementation details are available in: + "The soft heap: an approximate priority queue with optimal error rate", + Bernard Chazelle, JACM, 2000. + + URL: http://www.cs.princeton.edu/~chazelle/pubs/sheap.pdf + + \todo try not to use tracked_ptr. + \todo try not to call T::plus_infty(). This is not generic enough but + it works with mln::point<>. +*/ + +# include <mln/core/concept/object.hh> +# include <mln/trait/value_.hh> +# include <mln/util/tracked_ptr.hh> +# include <climits> +# include <stack> + + + +namespace mln +{ + + namespace util + { + + + /// Element of an item list. Store the data (key) used in soft_heap. + template <typename T> + struct ilcell + { + typedef util::tracked_ptr< ilcell<T> > ilcell_t; + + ilcell(); + ilcell(const T& key, ilcell_t next = 0); + + ilcell_t next() const; + const T& key() const; + + void set_next(ilcell_t next); + void set_key(const T& key); + + private: + T key_; + ilcell_t next_; + }; + + + /// Meta-data of an element in the heap. + template <typename T, typename R> + class node + { + + typedef util::tracked_ptr< ilcell<T> > ilcell_t; + + public: + node(); + node(const T& ckey, const R& rank, + node<T,R> *next = 0, node<T,R> *child = 0, + ilcell_t il = 0, ilcell_t il_tail = 0); + ~node(); + + const T& ckey() const; + const R& rank() const; + node<T,R> * next() const; + node<T,R> * child() const; + ilcell_t il() const; + ilcell_t il_tail() const; + + void set_il(ilcell_t il); + void set_il_tail(ilcell_t il_tail); + void set_ckey(const T& ckey); + void set_rank(const R& rank); + void set_next(node<T,R> * next); + void set_child(node<T,R> *child); + + private: + T ckey_; + R rank_; + node<T,R> *next_; + node<T,R> *child_; + ilcell_t il_; + ilcell_t il_tail_; + + }; + + + + + /// Top structure of the soft heap. + template <typename T, typename R> + class head + { + public: + + head(); + head(const R& rank, node<T,R> *queue = 0, head<T,R> *next = 0, + head<T,R> *prev = 0, head<T,R> *suffix_min = 0); + ~head(); + + node<T,R> *queue() const; + head<T,R> *next() const; + head<T,R> *prev() const; + head<T,R> *suffix_min() const; + const R& rank() const; + + void set_queue(node<T,R> *queue); + void set_next(head<T,R> *next); + void set_prev(head<T,R> *prev); + void set_suffix_min(head<T,R> *suffix_min); + void set_rank(const R& rank); + + private: + node<T,R> *queue_; + head<T,R> *next_; + head<T,R> *prev_; + head<T,R> *suffix_min_; + R rank_; + + }; + + + + + /// T key, the data to store in the heap. For instance a point 2d. + /// R rank, for instance int_u8 + template <typename T, typename R> + class soft_heap : public Object< soft_heap<T,R> > + { + typedef util::tracked_ptr< ilcell<T> > ilcell_t; + + public: + + /// Element associated type. + typedef T element; + + + /// Default constructor. + /// A corruption threshold \p r can be specified. + /// This threshold means that if nodes have a rank higher than this + /// threshold they can be "corrupted" and therefore their rank can be + /// reduced. + /// + // FIXME: is it a correct value for r? + soft_heap(unsigned r = 20); + /// Destructor + ~soft_heap(); + + + /// Add a new element \p element. + void push(const T& element); + /// Insert a site \p p (equivalent as 'push'). + void insert(const T& p); + + /// Merge \p sh with this heap. + /// Be ware that after this call, \p sh will be empty. This heap will + /// hold the elements which were part of \p sh. + void take(soft_heap<T,R>& sh); + + /// Returns the element with the lowest priority and remove it from the + /// heap. + T pop_front(); + + /// Return true if there is at least one element. + bool is_valid() const; + + /// Return true if there is at least one element. + bool is_empty() const; + + /// Return the number of element in the heap. + int nelements() const; + + /// Clear the heap. + void clear(); + + /// Internal use only. Return a pointer to the first header struct + /// of this heap. + head<T,R> *head_hook_() const; + + /// Reset the heap to an empty heap. Do *NOT* delete element which may + /// have been inserted. + /// \sa take + void soft_clear_(); + + + + private: + /// Merge a node \p q to this heap. + /// \sa take + void meld(node<T,R> *q); + + /// Update suffix_min pointer according to the new values inserted in + /// the item lists. + void fix_minlist(head<T,R> *h); + + /// After the deletion of an element, this function move/update item lists + /// in the proper nodes. + node<T,R> * sift(node<T,R> *v); + + /// Delete all element in a C-list from \p begin to \p end. \p end is not + /// deleted. + /// The type L must provide 'L *next()'. + /// + /// next + /// + /// |x| -> |x| -> |x| + /// + template <typename L> + void clear_list(L *begin, L *end = 0); + + /// Delete all element in a 2 dimensional C-list. + /// The type L must provide 'L *next()' and 'L *child()'. + /// + /// next + /// + /// |x| -> |x| -> |x| + /// | + /// child v + /// |x| -> |x| + /// + template <typename L> + void deep_clear_list(L *n); + + /// Print which node is part of which head. + void debug_head_list() const; + + /// Display the heap, preserving the hierarchy of the elements. + void println_() const; + + head<T,R> *header_; + head<T,R> *tail_; + + /// Corruption threshold. Must be set once through the constructor. + unsigned r_; + + int nelements_; + }; + + + +# ifndef MLN_INCLUDE_ONLY + + + /*-------` + | ilcell | + \-------*/ + + + template <typename T> + inline + ilcell<T>::ilcell() + { + } + + + template <typename T> + inline + ilcell<T>::ilcell(const T& key, ilcell_t next) + : key_(key), next_(next) + { + } + + + template <typename T> + inline + typename ilcell<T>::ilcell_t + ilcell<T>::next() const + { + return next_; + } + + + template <typename T> + inline + const T& + ilcell<T>::key() const + { + return key_; + } + + + template <typename T> + inline + void + ilcell<T>::set_next(ilcell_t next) + { + next_ = next; + } + + + template <typename T> + inline + void + ilcell<T>::set_key(const T& key) + { + key_ = key; + } + + + + + /*-----` + | node | + \-----*/ + + + template <typename T, typename R> + inline + node<T,R>::node() + : il_(0), il_tail_(0) + { + } + + + template <typename T, typename R> + inline + node<T,R>::node(const T& ckey, const R& rank, + node<T,R> *next, node<T,R> *child, + ilcell_t il, ilcell_t il_tail) + : ckey_(ckey), rank_(rank), next_(next), child_(child), + il_(il), il_tail_(il_tail) + { + } + + + template <typename T, typename R> + inline + node<T,R>::~node() + { + } + + + template <typename T, typename R> + inline + const T& + node<T,R>::ckey() const + { + return ckey_; + } + + + template <typename T, typename R> + inline + const R& + node<T,R>::rank() const + { + return rank_; + } + + + template <typename T, typename R> + inline + node<T,R> * + node<T,R>::next() const + { + return next_; + } + + + template <typename T, typename R> + inline + node<T,R> * + node<T,R>::child() const + { + return child_; + } + + + template <typename T, typename R> + inline + typename node<T,R>::ilcell_t + node<T,R>::il() const + { + return il_; + } + + + template <typename T, typename R> + inline + typename node<T,R>::ilcell_t + node<T,R>::il_tail() const + { + return il_tail_; + } + + + template <typename T, typename R> + inline + void + node<T,R>::set_il(ilcell_t il) + { + il_ = il; + } + + + template <typename T, typename R> + inline + void + node<T,R>::set_il_tail(ilcell_t il_tail) + { + il_tail_ = il_tail; + } + + + template <typename T, typename R> + inline + void + node<T,R>::set_ckey(const T& ckey) + { + ckey_ = ckey; + } + + + template <typename T, typename R> + inline + void + node<T,R>::set_rank(const R& rank) + { + rank_ = rank; + } + + + template <typename T, typename R> + inline + void + node<T,R>::set_next(node<T,R> * next) + { + next_ = next; + } + + + template <typename T, typename R> + inline + void + node<T,R>::set_child(node<T,R> *child) + { + child_ = child; + } + + + + + /*-----` + | head | + \-----*/ + + + template <typename T, typename R> + inline + head<T,R>::head() + { + } + + + template <typename T, typename R> + inline + head<T,R>::head(const R& rank, node<T,R> *queue, head<T,R> *next, + head<T,R> *prev, head<T,R> *suffix_min) + : queue_(queue), next_(next), prev_(prev), + suffix_min_(suffix_min), rank_(rank) + { + } + + + template <typename T, typename R> + inline + head<T,R>::~head() + { + } + + + template <typename T, typename R> + inline + node<T,R> * + head<T,R>::queue() const + { + return queue_; + } + + + template <typename T, typename R> + inline + head<T,R> * + head<T,R>::next() const + { + return next_; + } + + + template <typename T, typename R> + inline + head<T,R> * + head<T,R>::prev() const + { + return prev_; + } + + + template <typename T, typename R> + inline + head<T,R> * + head<T,R>::suffix_min() const + { + return suffix_min_; + } + + + template <typename T, typename R> + inline + const R& + head<T,R>::rank() const + { + return rank_; + } + + + template <typename T, typename R> + inline + void + head<T,R>::set_queue(node<T,R> *queue) + { + queue_ = queue; + } + + + template <typename T, typename R> + inline + void + head<T,R>::set_next(head<T,R> *next) + { + next_ = next; + } + + + template <typename T, typename R> + inline + void + head<T,R>::set_prev(head<T,R> *prev) + { + prev_ = prev; + } + + + template <typename T, typename R> + inline + void + head<T,R>::set_suffix_min(head<T,R> *suffix_min) + { + suffix_min_ = suffix_min; + } + + + template <typename T, typename R> + inline + void + head<T,R>::set_rank(const R& rank) + { + rank_ = rank; + } + + + + + /*------------` + | soft_heap | + \------------*/ + + + template <typename T, typename R> + inline + soft_heap<T,R>::soft_heap(unsigned r) + { + nelements_ = 0; + r_ = r; + header_ = new head<T,R>(mln_max(R)); + tail_ = new head<T,R>(mln_max(R), 0, 0, header_); + header_->set_next(tail_); + } + + + template <typename T, typename R> + inline + soft_heap<T,R>::~soft_heap() + { + head<T,R> *tmp = header_; + while (tmp != 0) + { + deep_clear_list(tmp->queue()); + tmp = tmp->next(); + } + clear_list(header_, tail_->next()); + } + + + template <typename T, typename R> + inline + void + soft_heap<T,R>::push(const T& element) + { + ilcell_t l(new ilcell<T>(element)); + node<T,R> *q = new node<T,R>(element, 0, 0, 0, l, l); + meld(q); + ++nelements_; + } + + + template <typename T, typename R> + inline + void + soft_heap<T,R>::take(soft_heap<T,R>& psh) + { + head<T,R> *head = psh.head_hook_(); + while (head != 0) + { + if (head->queue() != 0) + meld(head->queue()); + head = head->next(); + } + nelements_ += psh.nelements(); + psh.soft_clear_(); + } + + + template <typename T, typename R> + inline + T + soft_heap<T,R>::pop_front() + { + mln_precondition(is_valid()); + + node<T,R> *tmp; + + T min; + int childcount; + head<T,R> *h = header_->next()->suffix_min(); + while (h->queue()->il() == 0) + { + tmp = h->queue(); + childcount = 0; + while (tmp->next() != 0) + { + tmp = tmp->next(); + ++childcount; + } + + if (childcount < h->rank() / 2) + { + h->prev()->set_next(h->next()); + h->next()->set_prev(h->prev()); + fix_minlist(h->prev()); + tmp = h->queue(); + while (tmp->next() != 0) + { + meld(tmp->child()); + tmp = tmp->next(); + } + //FIXME: is it right? + deep_clear_list(h->queue()); + delete h; + } + else + { + h->set_queue(sift(h->queue())); + // FIXME: not generic enough. + if (h->queue()->ckey() == T::plus_infty()) + { + h->prev()->set_next(h->next()); + h->next()->set_prev(h->prev()); + + // Remove h and switch to h->prev. + head<T,R> *h_bak = h; + h = h->prev(); + deep_clear_list(h_bak->queue()); + delete h_bak; + } + fix_minlist(h); + } + h = header_->next()->suffix_min(); + } + + min = h->queue()->il()->key(); + + //Don't need to delete h->queue()->il(). May be used in another node. + h->queue()->set_il(h->queue()->il()->next()); + if (h->queue()->il() == 0) + h->queue()->set_il_tail(0); + + --nelements_; + return min; + } + + + template <typename T, typename R> + inline + bool + soft_heap<T,R>::is_valid() const + { + return header_ != 0 && tail_ != 0; + } + + + template <typename T, typename R> + inline + bool + soft_heap<T,R>::is_empty() const + { + return nelements_ == 0 ; + } + + + template <typename T, typename R> + inline + int + soft_heap<T,R>::nelements() const + { + return nelements_; + } + + + template <typename T, typename R> + inline + void + soft_heap<T,R>::clear() + { + if (header_->next() == tail_) + return; + + head<T,R> *tohead = header_->next(); + head<T,R> *prevtail = tail_->prev(); + prevtail->set_next(0); + tohead->set_prev(0); + header_->set_next(tail_); + tail_->set_prev(header_); + + head<T,R> *tmp = tohead; + while (tmp != 0) + { + deep_clear_list(tmp->queue()); + tmp = tmp->next(); + } + clear_list(tohead); + + nelements_ = 0; + } + + + template <typename T, typename R> + inline + void + soft_heap<T,R>::soft_clear_() + { + clear_list(header_->next(), tail_); + header_->set_next(tail_); + header_->set_prev(0); + tail_->set_next(0); + tail_->set_prev(header_); + nelements_ = 0; + } + + + template <typename T, typename R> + inline + head<T,R> * + soft_heap<T,R>::head_hook_() const + { + return header_; + } + + + template <typename T, typename R> + inline + void + soft_heap<T,R>::meld(node<T,R>* q) + { + head<T,R> *tohead = header_->next(); + while (q->rank() > tohead->rank()) + tohead = tohead->next(); + head<T,R> *prevhead = tohead->prev(); + + node<T,R> *top, *bottom; + + while (q->rank() == tohead->rank()) + { + if (util::ord_strict(q->ckey(), tohead->queue()->ckey())) + { + top = q; + bottom = tohead->queue(); + } + else + { + top = tohead->queue(); + bottom = q; + } + + q = new node<T,R>(top->ckey(), top->rank() + 1, top, bottom, + top->il(), top->il_tail()); + + tohead = tohead->next(); + } + + head<T,R> *h; + if (prevhead == tohead->prev()) + { + h = new head<T,R>(q->rank(), q, tohead, prevhead); + } + else + { + // Do not create a new head. + h = prevhead->next(); + + //Discard/delete everything between h and tohead. + head<T,R> *head_del = h->next(), *tmp_del; + while (head_del != tohead) + { + tmp_del = head_del->next(); + delete head_del; + head_del = tmp_del; + } + + } + h->set_queue(q); + h->set_rank(q->rank()); + h->set_prev(prevhead); + h->set_next(tohead); + + prevhead->set_next(h); + tohead->set_prev(h); + + fix_minlist(h); + } + + + template <typename T, typename R> + inline + void + soft_heap<T,R>::fix_minlist(head<T,R> *h) + { + head<T,R> *tmpmin; + if (h->next() == tail_) + tmpmin = h; + else + tmpmin = h->next()->suffix_min(); + + while (h != header_) + { + if (util::ord_strict(h->queue()->ckey(), tmpmin->queue()->ckey())) + tmpmin = h; + h->set_suffix_min(tmpmin); + h = h->prev(); + } + } + + + template <typename T, typename R> + inline + node<T,R> * + soft_heap<T,R>::sift(node<T,R> *v) + { + node<T,R> *tmp; + // We do not need to free the list since these object are also pointed by + // other structs. + v->set_il(0); + v->set_il_tail(0); + + if (v->next() == 0 && v->child() == 0) + { + //FIXME: not generic enough... + v->set_ckey(T::plus_infty()); + return v; + } + node<T,R> *v_next_bak = v->next(); + v->set_next(sift(v->next())); + + // Cleanup possibly removed nodes. + while (v_next_bak != v->next()) + { + deep_clear_list(v_next_bak->next()); + deep_clear_list(v_next_bak->child()); + tmp = v_next_bak->next(); + delete v_next_bak; + v_next_bak = tmp; + } + + if (util::ord_strict(v->child()->ckey(), v->next()->ckey())) + { + // Swap child and next. + tmp = v->child(); + v->set_child(v->next()); + v->set_next(tmp); + } + + v->set_il(v->next()->il()); + v->set_il_tail(v->next()->il_tail()); + v->set_ckey(v->next()->ckey()); + + if (v->rank() > r_ && (v->rank() % 2 == 1 + || v->child()->rank() < static_cast<unsigned>((v->rank() - 1)))) + { + node<T,R> *v_next_bak = v->next(); + v->set_next(sift(v->next())); + + // Cleanup possibly removed nodes. + while (v_next_bak != v->next()) + { + deep_clear_list(v_next_bak->next()); + deep_clear_list(v_next_bak->child()); + tmp = v_next_bak->next(); + delete v_next_bak; + v_next_bak = tmp; + } + + if (util::ord_strict(v->child()->ckey(), v->next()->ckey())) + { + tmp = v->child(); + v->set_child(v->next()); + v->set_next(tmp); + } + + if (v->next()->ckey() != T::plus_infty() && v->next()->il() != 0) + { + v->next()->il_tail()->set_next(v->il()); + v->set_il(v->next()->il()); + if (v->il_tail() == 0) + v->set_il_tail(v->next()->il_tail()); + v->set_ckey(v->next()->ckey()); + } + } + + if (v->child()->ckey() == T::plus_infty()) + { + if (v->next()->ckey() == T::plus_infty()) + { + // Clear child and next lists. + deep_clear_list(v->child()); + deep_clear_list(v->next()); + + v->set_child(0); + v->set_next(0); + } + else + { + node<T,R> *next_bak = v->next(); + + // There may be several children, we must clear all of them. + deep_clear_list(v->child()); + + v->set_child(v->next()->child()); + v->set_next(v->next()->next()); + delete next_bak; + } + } + + return v; + } + + + template <typename T, typename R> + template <typename L> + inline + void + soft_heap<T,R>::clear_list(L *begin, L *end) + { + L *tmp; + while (begin != end) + { + tmp = begin->next(); + delete begin; + begin = tmp; + } + } + + + template <typename T, typename R> + template <typename L> + inline + void + soft_heap<T,R>::deep_clear_list(L *n) + { + L *current_node, *tmp; + std::stack<L *> st; + + st.push(n); + while (!st.empty()) + { + current_node = st.top(); + st.pop(); + while (current_node != 0) + { + if (current_node->child() != 0) + st.push(current_node->child()); + + tmp = current_node->next(); + delete current_node; + + current_node = tmp; + } + } + } + + + template <typename T, typename R> + inline + void + soft_heap<T,R>::debug_head_list() const + { + head<T,R> *n = header_; + std::cout << "Head list = " << std::endl; + while (n != 0) + { + std::cout << n->id << "("; + + node<T,R> *current_node; + std::stack< node<T,R> *> st; + st.push(n->queue()); + while (!st.empty()) + { + current_node = st.top(); + st.pop(); + while (current_node != 0) + { + if (current_node->child() != 0) + st.push(current_node->child()); + std::cout << current_node->id << ","; + current_node = current_node->next(); + } + } + + std::cout << ") - "; + n = n->next(); + } + std::cout << std::endl; + } + + + template <typename T, typename R> + inline + void + soft_heap<T,R>::println_() const + { + + std::cout << "===============" << std::endl; + head<T,R> *head = header_; + while (head != 0) + { + std::cout << "<Head>" << std::endl; + node<T,R> *node = head->queue(), *child; + while (node != 0) + { + std::cout << " <node>" << std::endl; + + ilcell_t il(node->il()); + while (il != 0) + { + std::cout << il->item() << std::endl; + il = il->next(); + } + + child = node->child(); + while (child != 0) + { + std::cout << " <child>" << std::endl; + ilcell_t il(child->il()); + while (il != 0) + { + std::cout << il->item() << std::endl; + il = il->next(); + } + child = child->child(); + std::cout << " </child>" << std::endl; + } + node = node->next(); + + std::cout << " </node>" << std::endl; + } + std::cout << "</Head>" << std::endl; + head = head->next(); + } + } + + +# endif // ! MLN_INCLUDE_ONLY + + + } // end of namespace mln::util + +} // end of namespace mln + + +#endif // ! MLN_UTIL_FAST_HEAP_HH diff --git a/milena/mln/util/tracked_ptr.hh b/milena/mln/util/tracked_ptr.hh index 6d22451..0148880 100644 --- a/milena/mln/util/tracked_ptr.hh +++ b/milena/mln/util/tracked_ptr.hh @@ -1,4 +1,5 @@ -// Copyright (C) 2006 EPITA Research and Development Laboratory +// Copyright (C) 2006, 2009 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 @@ -28,12 +29,11 @@ #ifndef MLN_UTIL_TRACKED_PTR_HH # define MLN_UTIL_TRACKED_PTR_HH -/*! \file mln/util/tracked_ptr.hh - * - * \brief Definition of a smart pointer for shared data with tracking. - * - * \todo Split defs from decls. - */ +/// \file mln/util/tracked_ptr.hh +/// +/// Definition of a smart pointer for shared data with tracking. +/// +/// \todo Split defs from decls. # include <set> # include <iostream> @@ -63,16 +63,14 @@ namespace mln /// Negation (for arithmetical tests). bool operator !() const; - /*! \brief Mimics the behavior of op-> for a pointer in the const case. - ** - ** \invariant Pointer proxy exists. - */ + /// Mimics the behavior of op-> for a pointer in the const case. + /// + /// \invariant Pointer proxy exists. const T* operator->() const; - /*! \brief Mimics the behavior of op-> for a pointer in the mutable case. - ** - ** \invariant Pointer proxy exists. - */ + /// Mimics the behavior of op-> for a pointer in the mutable case. + /// + /// \invariant Pointer proxy exists. T* operator->(); /// Ctor. @@ -122,10 +120,9 @@ namespace mln } template <typename T> - /*! \brief Mimics the behavior of op-> for a pointer in the const case. - ** - ** \invariant Pointer proxy exists. - */ + /// Mimics the behavior of op-> for a pointer in the const case. + /// + /// \invariant Pointer proxy exists. inline const T* tracked_ptr<T>::operator->() const { @@ -135,10 +132,9 @@ namespace mln } template <typename T> - /*! \brief Mimics the behavior of op-> for a pointer in the mutable case. - ** - ** \invariant Pointer proxy exists. - */ + /// \brief Mimics the behavior of op-> for a pointer in the mutable case. + /// + /// \invariant Pointer proxy exists. inline T* tracked_ptr<T>::operator->() { @@ -201,7 +197,9 @@ namespace mln clean_(); ptr_ = rhs.ptr_; holders_ = rhs.holders_; - holders_->insert(this); + // If ptr == 0, holders_ == 0 so we cannot insert anything in it. + if (holders_ != 0) + holders_->insert(this); return *this; } diff --git a/milena/tests/unit_test/Makefile.am b/milena/tests/unit_test/Makefile.am index e055ee3..2eef268 100644 --- a/milena/tests/unit_test/Makefile.am +++ b/milena/tests/unit_test/Makefile.am @@ -64,6 +64,7 @@ mln_registration_icp \ mln_util_graph \ mln_util_max \ mln_util_lazy_set \ +mln_util_soft_heap \ mln_util_set \ mln_util_tree_to_image \ mln_util_lemmings \ @@ -1074,6 +1075,7 @@ mln_registration_icp_SOURCES = mln_registration_icp.cc mln_util_graph_SOURCES = mln_util_graph.cc mln_util_max_SOURCES = mln_util_max.cc mln_util_lazy_set_SOURCES = mln_util_lazy_set.cc +mln_util_soft_heap_SOURCES = mln_util_soft_heap.cc mln_util_set_SOURCES = mln_util_set.cc mln_util_tree_to_image_SOURCES = mln_util_tree_to_image.cc mln_util_lemmings_SOURCES = mln_util_lemmings.cc diff --git a/milena/tests/unit_test/mln_util_soft_heap.cc b/milena/tests/unit_test/mln_util_soft_heap.cc new file mode 100644 index 0000000..6a98bb0 --- /dev/null +++ b/milena/tests/unit_test/mln_util_soft_heap.cc @@ -0,0 +1,11 @@ +// Unit test for mln/util/soft_heap.hh. +// Generated by ./build_unit_test.sh, do not modify. + +// Include the file twice, so we detect missing inclusion guards. +#include <mln/util/soft_heap.hh> +#include <mln/util/soft_heap.hh> + +int main() +{ + // Nothing. +} diff --git a/milena/tests/util/Makefile.am b/milena/tests/util/Makefile.am index 0e9c5ab..1dcd5c5 100644 --- a/milena/tests/util/Makefile.am +++ b/milena/tests/util/Makefile.am @@ -12,6 +12,7 @@ check_PROGRAMS = \ lazy_set \ lemmings \ ord_pair \ + soft_heap \ tree \ tree_fast \ tree_fast_to_image \ @@ -26,6 +27,7 @@ graph_SOURCES = graph.cc lazy_set_SOURCES = lazy_set.cc lemmings_SOURCES = lemmings.cc ord_pair_SOURCES = ord_pair.cc +soft_heap_SOURCES = soft_heap.cc tree_SOURCES = tree.cc tree_fast_SOURCES = tree_fast.cc tree_fast_to_image_SOURCES = tree_to_image.cc diff --git a/milena/tests/util/soft_heap.cc b/milena/tests/util/soft_heap.cc new file mode 100644 index 0000000..d2bffcc --- /dev/null +++ b/milena/tests/util/soft_heap.cc @@ -0,0 +1,79 @@ +// Copyright (C) 2009 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. This exception does not however invalidate any other +// reasons why the executable file might be covered by the GNU General +// Public License. + +/// \file mln/core/site_set/p_soft_heap.hh +/// +/// Test for the soft heap (approximate priority queue). + +#include <mln/util/soft_heap.hh> +#include <mln/core/alias/point2d.hh> +#include <mln/value/int_u8.hh> + +using mln::point2d; + +point2d p[] = { point2d(4,5), point2d(3,4), point2d(3,2), + point2d(1,6), point2d(2,3), point2d(3,5), + point2d(2,4), point2d(7,2), point2d(9,6), + point2d(7,3) }; + +point2d res[] = { point2d(1,6), point2d(2,3), point2d(2,4), + point2d(3,2), point2d(3,4), point2d(3,5), + point2d(4,5), point2d(7,2), point2d(7,3), + point2d(9,6) }; + + +int main() +{ + using namespace mln; + + util::soft_heap<point2d, value::int_u8> fh; + + for (unsigned i = 0; i < 5; ++i) + fh.push(p[i]); + + util::soft_heap<point2d, value::int_u8> fh2; + for (unsigned i = 5; i < 10; ++i) + fh2.push(p[i]); + + // Merge fh in fh2. + fh2.take(fh); + + // fh2 now holds both its elements and fh's. + unsigned i = 0; + while (!fh2.is_empty()) + mln_assertion(fh2.pop_front() == res[i++]); + + // fh must be empty, fh2 now holds its elements. + mln_assertion(fh.is_empty()); + + for (unsigned i = 5; i < 10; ++i) + fh2.push(p[i]); + + fh2.clear(); + mln_assertion(fh2.nelements() == 0); + mln_assertion(fh2.is_empty()); +} -- 1.5.6.5
participants (1)
-
Guillaume Lazzara