olena-2.0-31-g25a6947 New value types.

* mln/value/next.hh: Add support for unsignedh. * mln/value/range.hh, * mln/value/unsignedh.hh, * tests/value/range.cc, * tests/value/unsignedh.cc: New. * tests/value/Makefile.am: Add targets. --- milena/ChangeLog | 13 + milena/mln/value/next.hh | 20 +- milena/mln/value/range.hh | 425 ++++++++++++++++++++ milena/mln/value/unsignedh.hh | 415 +++++++++++++++++++ milena/tests/value/Makefile.am | 16 +- .../range.cc} | 62 ++-- .../tests/{fun/i2v/array.cc => value/unsignedh.cc} | 22 +- 7 files changed, 930 insertions(+), 43 deletions(-) create mode 100644 milena/mln/value/range.hh create mode 100644 milena/mln/value/unsignedh.hh copy milena/tests/{world/k1/fill_0_1_faces_internal_border.cc => value/range.cc} (61%) copy milena/tests/{fun/i2v/array.cc => value/unsignedh.cc} (80%) diff --git a/milena/ChangeLog b/milena/ChangeLog index 525ab23..4ff88af 100644 --- a/milena/ChangeLog +++ b/milena/ChangeLog @@ -1,5 +1,18 @@ 2012-09-28 Guillaume Lazzara <z@lrde.epita.fr> + New value types. + + * mln/value/next.hh: Add support for unsignedh. + + * mln/value/range.hh, + * mln/value/unsignedh.hh, + * tests/value/range.cc, + * tests/value/unsignedh.cc: New. + + * tests/value/Makefile.am: Add targets. + +2012-09-28 Guillaume Lazzara <z@lrde.epita.fr> + New routine for filling internal border in K1. * mln/world/k1/fill_0_1_faces_internal_border.hh, diff --git a/milena/mln/value/next.hh b/milena/mln/value/next.hh index e1dac48..b9bc06e 100644 --- a/milena/mln/value/next.hh +++ b/milena/mln/value/next.hh @@ -1,4 +1,5 @@ -// Copyright (C) 2010 EPITA Research and Development Laboratory (LRDE) +// Copyright (C) 2010, 2012 EPITA Research and Development Laboratory +// (LRDE) // // This file is part of Olena. // @@ -28,9 +29,10 @@ /// \file /// -/// Return a given value incremented by 1. +/// Return the next value. # include <mln/value/label.hh> +# include <mln/value/unsignedh.hh> namespace mln @@ -74,6 +76,14 @@ namespace mln return v.next(); } + + inline + mln::value::unsignedh + next_unsignedh(const mln::value::unsignedh& v) + { + return mln::value::succ(v); + } + } // end of namespace mln::value::implementation @@ -91,6 +101,12 @@ namespace mln return implementation::next_label(v); } + inline + unsignedh + next_dispatch(const unsignedh& v) + { + return implementation::next_unsignedh(v); + } template <typename V> inline diff --git a/milena/mln/value/range.hh b/milena/mln/value/range.hh new file mode 100644 index 0000000..ca8f2f4 --- /dev/null +++ b/milena/mln/value/range.hh @@ -0,0 +1,425 @@ +// Copyright (C) 2012 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena 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 Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project 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_VALUE_RANGE_HH +# define MLN_VALUE_RANGE_HH + +/// \file +/// +/// Define a range value. + +# include <cstdlib> +# include <iostream> +# include <mln/value/next.hh> + +namespace mln +{ + + namespace value + { + + template <typename T> + class range + { + public: + range(); + + template <typename T_> + range(T_ value); + + range(T lower, T upper); + + range& operator=(const range& rhs); + + template <typename T_> + range& operator=(T_ value); + + bool has(const T& v) const; + + T length() const; + + unsigned nelements() const; + + bool is_degenerated() const; + + const T& lower() const; + const T& upper() const; + + const T& first() const; + const T& last() const; + + operator T() const; + + private: + T lower_; + T upper_; + }; + +// comparison + + template <typename T> + bool + operator==(const range<T>& lhs, const range<T>& rhs); + + template <typename T> + bool + operator!=(const range<T>& lhs, const range<T>& rhs); + +// deactivation of ordering related operators + + template <typename T> + void operator<(const range<T>&, const range<T>&); + + template <typename T> + void operator<=(const range<T>&, const range<T>&); + + template <typename T> + void operator>(const range<T>&, const range<T>&); + + template <typename T> + void operator>=(const range<T>&, const range<T>&); + +// set ops + + template <typename T> + bool + are_adjacent(const range<T>& r1, const range<T>& r2); + + template <typename T> + bool + do_intersect(const range<T>& r1, const range<T>& r2); + + template <typename T> + range<T> + inter(const range<T>& r1, const range<T>& r2); + +// min / max + + template <typename T> + range<T> + min(const range<T>& r1, const range<T>& r2); + + template <typename T> + range<T> + max(const range<T>& r1, const range<T>& r2); + +// mean + + template <typename T> + range<T> + mean(const range<T>& r1, const range<T>& r2); + +// span + + template <typename T> + range<T> + span(const range<T>& r1, const range<T>& r2); + +// op<< + + template <typename T> + std::ostream& + operator<<(std::ostream& ostr, const range<T>& i); + + } // end of namespace mln::value + +} // end of namespace mln + + +// for sorting purpose + +namespace std +{ + + template <typename T> + struct less< mln::value::range<T> > + { + bool operator()(const mln::value::range<T>& l, + const mln::value::range<T>& r) const; + }; + +} // std + + + +# ifndef MLN_INCLUDE_ONLY + + +namespace mln +{ + + namespace value + { + + + template <typename T> + range<T>::range() + { + } + + template <typename T> + template <typename T_> + range<T>::range(T_ value) + { + lower_ = upper_ = value; + } + + template <typename T> + range<T>::range(T lower, T upper) + { + if (upper < lower) + std::abort(); + lower_ = lower; + upper_ = upper; + } + + template <typename T> + range<T>& + range<T>::operator=(const range& rhs) + { + lower_ = rhs.lower_; + upper_ = rhs.upper_; + return *this; + } + + template <typename T> + template <typename T_> + range<T>& + range<T>::operator=(T_ value) + { + lower_ = upper_ = value; + return *this; + } + + template <typename T> + bool + range<T>::has(const T& v) const + { + return lower_ <= v && v <= upper_; + } + + template <typename T> + T + range<T>::length() const + { + return upper_ - lower_; + } + + template <typename T> + unsigned + range<T>::nelements() const + { + unsigned n = 1; + T v = lower_; + for (; v != upper_; v = value::next(v)) + n += 1; + + return n; + } + + template <typename T> + bool + range<T>::is_degenerated() const + { + return upper_ == lower_; + } + + template <typename T> + const T& + range<T>::lower() const + { + return lower_; + } + + template <typename T> + const T& + range<T>::upper() const + { + return upper_; + } + + template <typename T> + const T& + range<T>::first() const + { + return lower_; + } + + template <typename T> + const T& + range<T>::last() const + { + return upper_; + } + + template <typename T> + range<T>::operator T() const + { + if (! is_degenerated()) + std::abort(); + return upper_; + } + + +// comparison + + template <typename T> + bool + operator==(const range<T>& lhs, const range<T>& rhs) + { + return lhs.lower() == rhs.lower() && lhs.upper() == rhs.upper(); + } + + template <typename T> + bool + operator!=(const range<T>& lhs, const range<T>& rhs) + { + return ! (lhs == rhs); + } + + +// deactivation of ordering related operators + + template <typename T> + void operator<(const range<T>&, const range<T>&); + + template <typename T> + void operator<=(const range<T>&, const range<T>&); + + template <typename T> + void operator>(const range<T>&, const range<T>&); + + template <typename T> + void operator>=(const range<T>&, const range<T>&); + + + +// set ops + + template <typename T> + bool + are_adjacent(const range<T>& r1, const range<T>& r2) + { + return span(r1, r2).length() == r1.length() + r2.length() + + (value::next(r2.lower()) - r2.lower()); + } + + template <typename T> + bool + do_intersect(const range<T>& r1, const range<T>& r2) + { + return span(r1, r2).length() <= r1.length() + r2.length(); + } + + template <typename T> + range<T> + inter(const range<T>& r1, const range<T>& r2) + { + if (! do_intersect(r1, r2)) + std::abort(); + return range<T>(std::max(r1.lower(), r2.lower()), + std::min(r1.upper(), r2.upper())); + } + + + +// min / max + + template <typename T> + range<T> + min(const range<T>& r1, const range<T>& r2) + { + return range<T>(std::min(r1.lower(), r2.lower()), + std::min(r1.upper(), r2.upper())); + } + + template <typename T> + range<T> + max(const range<T>& r1, const range<T>& r2) + { + return range<T>(std::max(r1.lower(), r2.lower()), + std::max(r1.upper(), r2.upper())); + } + + +// mean + + template <typename T> + range<T> + mean(const range<T>& r1, const range<T>& r2) + { + return range<T>(mean(r1.lower(), r2.lower()), + mean(r1.upper(), r2.upper())); + } + + +// span + + template <typename T> + range<T> + span(const range<T>& r1, const range<T>& r2) + { + return range<T>(std::min(r1.lower(), r2.lower()), + std::max(r1.upper(), r2.upper())); + } + + + +// op<< + + template <typename T> + std::ostream& + operator<<(std::ostream& ostr, const range<T>& i) + { + if (i.is_degenerated()) + return ostr << i.lower(); + else + return ostr << '[' << i.lower() << ',' << i.upper() << ']'; + } + + + } // end of namespace mln::value + +} // end of namespace mln + + +namespace std +{ + + template <typename T> + bool less< mln::value::range<T> >::operator()(const mln::value::range<T>& l, + const mln::value::range<T>& r) const + { + if (! l.is_degenerated() || ! r.is_degenerated()) + std::abort(); + return l.lower() < r.lower(); + } + +} // std + + +# endif // ! MLN_INCLUDE_ONLY + +#endif // ndef MLN_VALUE_RANGE_HH diff --git a/milena/mln/value/unsignedh.hh b/milena/mln/value/unsignedh.hh new file mode 100644 index 0000000..1f0281c --- /dev/null +++ b/milena/mln/value/unsignedh.hh @@ -0,0 +1,415 @@ +// Copyright (C) 2012 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena 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 Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project 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_VALUE_UNSIGNEDH_HH +# define MLN_VALUE_UNSIGNEDH_HH + +/// \file +/// +/// Define a semi-unsigned value class. + +# include <cstdlib> +# include <iostream> +# include <sstream> + +// FIXME: parameterize unsignedh so that we also can have +// Z/4 and so on... + +namespace mln +{ + + namespace value + { + + + class unsignedh + { + public: + unsignedh(); + unsignedh(const unsignedh& rhs); + unsignedh(unsigned i); + unsignedh(int i); + + unsignedh& operator=(const unsignedh& rhs); + unsignedh& operator=(unsigned i); + unsignedh& operator=(int i); + + unsigned enc() const; + + /// Construct an unsignedh with value v + static unsignedh make(unsigned v); + /// Construct an unsignedh with value v. The given value is + /// rounded to the closest integer or half value. +// static unsignedh make(float v); + + bool is_integer() const; + + unsigned to_unsigned() const; + + /// Set this unsignedh to its next value and return itself. + unsignedh& goto_succ(); + + /// Set this unsignedh to its previous value and return itself. + unsignedh& goto_pred(); + + operator std::string() const; + + private: + unsigned enc_; + }; + + + extern const unsignedh half; + + +// next + + unsignedh succ(unsignedh i); + unsignedh pred(unsignedh i); + +// rounding + + unsignedh floor(unsignedh i); + unsignedh ceil(unsignedh i); + + +// comparison + + bool operator==(unsignedh l, unsignedh r); + bool operator<=(unsignedh l, unsignedh r); + bool operator!=(unsignedh l, unsignedh r); + bool operator>=(unsignedh l, unsignedh r); + bool operator>(unsignedh l, unsignedh r); + bool operator<(unsignedh l, unsignedh r); + +// arithmetics + + unsignedh operator+(unsignedh l, unsignedh r); + void operator+=(unsignedh& l, unsignedh r); + unsignedh operator-(unsignedh l, unsignedh r); + void operator-=(unsignedh& l, unsignedh r); + unsignedh operator/(unsignedh l, unsigned r); + +// other ops + + unsignedh min(unsignedh u1, unsignedh u2); + unsignedh max(unsignedh u1, unsignedh u2); + unsignedh mean(unsignedh u1, unsignedh u2); + +// for a transparent use of both unsigned and unsignedh +// FIXME: is it useful? + + unsigned decode(unsigned u); + void encode(unsigned u, unsigned& dst); + unsigned decode(unsignedh u); + void encode(unsigned u, unsignedh& dst); + +// << + + std::ostream& + operator<<(std::ostream& ostr, const unsignedh& i); + + +# ifndef MLN_INCLUDE_ONLY + + inline + unsignedh::unsignedh() + { + } + + inline + unsignedh::unsignedh(const unsignedh& rhs) + : enc_(rhs.enc_) + { + } + + + inline + unsignedh::unsignedh(unsigned i) + { + enc_ = 2 * i; + } + + inline + unsignedh::unsignedh(int i) + { + if (i < 0) + std::abort(); + enc_ = 2 * i; + } + + inline + unsignedh& + unsignedh::operator=(const unsignedh& rhs) + { + enc_ = rhs.enc_; + return *this; + } + + inline + unsignedh& + unsignedh::operator=(unsigned i) + { + enc_ = 2 * i; + return *this; + } + + inline + unsignedh& + unsignedh::operator=(int i) + { + if (i < 0) + std::abort(); + enc_ = 2 * i; + return *this; + } + + inline + unsigned + unsignedh::enc() const + { + return enc_; + } + + inline + unsignedh unsignedh::make(unsigned enc) + { + unsignedh i; + i.enc_ = enc; + return i; + } + + inline + bool + unsignedh::is_integer() const + { + return enc_ % 2 == 0; + } + + inline + unsigned + unsignedh::to_unsigned() const + { + if (! this->is_integer()) + std::abort(); + return enc_ / 2; + } + + inline + unsignedh& + unsignedh::goto_succ() + { + enc_ += 1; + return *this; + } + + inline + unsignedh& + unsignedh::goto_pred() + { + if (enc_ == 0) + std::abort(); + enc_ -= 1; + return *this; + } + + inline + unsignedh::operator std::string() const + { + std::stringstream s; + s << *this; + return s.str(); + } + + + +// half + +# ifndef MLN_WO_GLOBAL_VARS + + const unsignedh half = unsignedh::make(1u); + +# endif // ! MLN_WO_GLOBAL_VARS + + +// next + + unsignedh succ(unsignedh i) + { + return unsignedh::make(i.enc() + 1); + } + + unsignedh pred(unsignedh i) + { + if (i.enc() == 0) + std::abort(); + return unsignedh::make(i.enc() - 1); + } + + + +// rounding + + unsignedh floor(unsignedh i) + { + return i.is_integer() ? i : pred(i); + } + + unsignedh ceil(unsignedh i) + { + return i.is_integer() ? i : succ(i); + } + + + +// comparison + + bool operator==(unsignedh l, unsignedh r) + { + return l.enc() == r.enc(); + } + + bool operator<=(unsignedh l, unsignedh r) + { + return l.enc() <= r.enc(); + } + + bool operator!=(unsignedh l, unsignedh r) + { + return ! (l == r); + } + + bool operator>=(unsignedh l, unsignedh r) + { + return r <= l; + } + + bool operator>(unsignedh l, unsignedh r) + { + return ! (l <= r); + } + + bool operator<(unsignedh l, unsignedh r) + { + return r > l; + } + + + +// arithmetics + + unsignedh operator+(unsignedh l, unsignedh r) + { + return unsignedh::make(l.enc() + r.enc()); + } + + void operator+=(unsignedh& l, unsignedh r) + { + l = l + r; + } + + unsignedh operator-(unsignedh l, unsignedh r) + { + if (r > l) + std::abort(); + return unsignedh::make(l.enc() - r.enc()); + } + + void operator-=(unsignedh& l, unsignedh r) + { + if (r > l) + std::abort(); + l = l - r; + } + + unsignedh operator/(unsignedh l, unsigned r) + { + if (l.enc() % r != 0) + std::abort(); + return unsignedh::make(l.enc() / r); + } + + + +// other ops + + unsignedh min(unsignedh u1, unsignedh u2) + { + return unsignedh::make(u1.enc() < u2.enc() ? u1.enc() : u2.enc()); + } + + unsignedh max(unsignedh u1, unsignedh u2) + { + return unsignedh::make(u1.enc() > u2.enc() ? u1.enc() : u2.enc()); + } + + unsignedh mean(unsignedh u1, unsignedh u2) + { + return (u1 + u2) / 2; + } + + +// for a transparent use of both unsigned and unsignedh +// FIXME: is it useful? + + unsigned decode(unsigned u) + { + return u; + } + + void encode(unsigned u, unsigned& dst) + { + dst = u; + } + + unsigned decode(unsignedh u) + { + return u.enc(); + } + + void encode(unsigned u, unsignedh& dst) + { + dst = unsignedh::make(u); + } + + +// << + + std::ostream& + operator<<(std::ostream& ostr, const unsignedh& i) + { + if (i.is_integer()) + return ostr << i.to_unsigned(); + else + return ostr << floor(i).to_unsigned() << ".5"; + } + +# endif // ! MLN_INCLUDE_ONLY + + } // end of namespace mln::value + +} // end of namespace mln + +#endif // ndef UNSIGNEDH_HH diff --git a/milena/tests/value/Makefile.am b/milena/tests/value/Makefile.am index 975d471..fb654fa 100644 --- a/milena/tests/value/Makefile.am +++ b/milena/tests/value/Makefile.am @@ -31,15 +31,17 @@ check_PROGRAMS = \ interop \ label \ proxy \ + range \ rgb8 \ scalar \ set \ - sign -# float01 -# float01_bis -# float01_f -# graylevel -# graylevel_f + sign \ + unsignedh +# float01 +# float01_bis +# float01_f +# graylevel +# graylevel_f bool_SOURCES = bool.cc equiv_SOURCES = equiv.cc @@ -54,10 +56,12 @@ int_u8_SOURCES = int_u8.cc interop_SOURCES = interop.cc label_SOURCES = label.cc proxy_SOURCES = proxy.cc +range_SOURCES = range.cc rgb8_SOURCES = rgb8.cc scalar_SOURCES = scalar.cc set_SOURCES = set.cc sign_SOURCES = sign.cc +unsignedh_SOURCES = unsignedh.cc #<<lrde # FIXME: Not distributed (yet). diff --git a/milena/tests/world/k1/fill_0_1_faces_internal_border.cc b/milena/tests/value/range.cc similarity index 61% copy from milena/tests/world/k1/fill_0_1_faces_internal_border.cc copy to milena/tests/value/range.cc index fbb9f73..22421ed 100644 --- a/milena/tests/world/k1/fill_0_1_faces_internal_border.cc +++ b/milena/tests/value/range.cc @@ -25,35 +25,47 @@ /// \file -#include <mln/core/image/image2d.hh> -#include <mln/make/box2d.hh> -#include <mln/data/compare.hh> -#include <mln/world/k1/fill_0_1_faces_internal_border.hh> +#include <cassert> +#include <vector> +#include <algorithm> + +#include <mln/value/unsignedh.hh> +#include <mln/value/range.hh> + +static const char *ref[] = { "1", "1.5", "2", "2.5", "3", "3.5", "4", "4.5", "5" }; int main() { - using namespace mln; - - int refvals[5][5] = { - {1, 1, 1, 1, 1 }, - {1, 2, 0, 2, 1 }, - {1, 0, 0, 0, 1 }, - {1, 2, 0, 2, 1 }, - {1, 1, 1, 1, 1 } - }; - image2d<int> ref = make::image(refvals, point2d(-1, -1)); - - int vals[5][5] = { - {0, 0, 0, 0, 0 }, - {0, 2, 0, 2, 0 }, - {0, 0, 0, 0, 0 }, - {0, 2, 0, 2, 0 }, - {0, 0, 0, 0, 0 } - }; - image2d<int> imak1 = make::image(vals, point2d(-1, -1)); + using namespace mln::value; + + typedef range<unsignedh> R; + + { + R r(0, 0); + assert(r.is_degenerated()); + assert(r.length() == 0); + assert(r.nelements() == 1); + } + + { + assert(are_adjacent(R(0,1), R(1+half,2))); + } { - world::k1::fill_0_1_faces_internal_border(imak1, 1); - mln_assertion(ref == imak1); + std::vector<R> v; + v.push_back(R(0,0)); + std::sort(v.begin(), v.end(), std::less<R>()); } + + { + R r(1, 5); + assert(!r.is_degenerated()); + assert(r.length() == 4); + assert(r.nelements() == 9); + + int ref_i = 0; + for (unsignedh v = r.first(); v != r.last(); v.goto_succ()) + mln_assertion(static_cast<std::string>(v) == ref[ref_i++]); + } + } diff --git a/milena/tests/fun/i2v/array.cc b/milena/tests/value/unsignedh.cc similarity index 80% copy from milena/tests/fun/i2v/array.cc copy to milena/tests/value/unsignedh.cc index 2633b41..ca98a59 100644 --- a/milena/tests/fun/i2v/array.cc +++ b/milena/tests/value/unsignedh.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2009 EPITA Research and Development Laboratory (LRDE) +// Copyright (C) 2012 EPITA Research and Development Laboratory (LRDE) // // This file is part of Olena. // @@ -23,20 +23,22 @@ // exception does not however invalidate any other reasons why the // executable file might be covered by the GNU General Public License. -#include <mln/fun/i2v/array.hh> +/// \file + +#include <cassert> +#include <mln/value/unsignedh.hh> int main() { - using namespace mln; + using namespace mln::value; - fun::i2v::array<int> f; - mln_assertion(f.size() == 0u); + unsignedh i = 2; + i.goto_succ(); - f.append(0); - mln_assertion(f(0) == 0); + // i == 2.5 + assert(i == 2 + half); - f.append(1); - mln_assertion(f(1) == 1); - mln_assertion(f.size() == 2u); + // (2.5 + 0.5) / 2 == 1.5 + assert(mean(i, half) == 1 + half); } -- 1.7.2.5
participants (1)
-
Guillaume Lazzara