diff --git a/include/boost/algorithm/detail/minmax_macro_comeau.hpp b/include/boost/algorithm/detail/minmax_macro_comeau.hpp new file mode 100755 index 0000000..f4aa91a --- /dev/null +++ b/include/boost/algorithm/detail/minmax_macro_comeau.hpp @@ -0,0 +1,176 @@ +/////////////////////////////////////////////////////////////////////////////// +// minmax_macro_comeau.hpp header file +// +// Copyright 2006 Eric Niebler. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// Credits: +// Scott Meyers - for carefully detailing the shortcomings of +// std::min and std::max in his article "Min, max and more" +// Andrei Alexandrescu - for the suggestion that ?: operator couls be useful +// in solving Scott's long-standing min/max challenge. + +#ifndef BOOST_MIN + +#include +#include +#include +#include +#include + +namespace boost { namespace minmax_macro_detail_ +{ + template + Type *encode_type(Type &) { return 0; } + + template + Type const *encode_type(Type const &) { return 0; } + + /////////////////////////////////////////////////////////////////////////////// + // max_impl + template + struct max_impl + { + max_impl(Left &left, Right &right) + : left_(left) + , right_(right) + {} + + struct private_type_ { typedef private_type_ type; }; + + // can't ever return an array or an abstract type by value + typedef BOOST_DEDUCED_TYPENAME boost::mpl::eval_if< + boost::mpl::or_, boost::is_array > + , private_type_ + , boost::remove_const + >::type value_type; + + operator value_type() + { + return this->left_ < this->right_ ? this->right_ : this->left_; + } + + operator Ret &() const + { + return this->left_ < this->right_ ? this->right_ : this->left_; + } + + private: + Left &left_; + Right &right_; + }; + + + /////////////////////////////////////////////////////////////////////////////// + // max_fun + template + max_impl + max_fun(Left &left, Right &right, Ret *) + { + return max_impl(left, right); + } + + template + max_impl + max_fun(Left const &left, Right &right, Ret *) + { + return max_impl(left, right); + } + + template + max_impl + max_fun(Left &left, Right const &right, Ret *) + { + return max_impl(left, right); + } + + template + max_impl + max_fun(Left const &left, Right const &right, Ret *) + { + return max_impl(left, right); + } + +#define BOOST_MAX(a,b)\ + (true\ + ? boost::minmax_macro_detail_::max_fun((a), (b), \ + (true? 0 : boost::minmax_macro_detail_::encode_type(true? (a) : (b))))\ + : (true? (a) : (b))) + + + /////////////////////////////////////////////////////////////////////////////// + // min_impl + template + struct min_impl + { + min_impl(Left &left, Right &right) + : left_(left) + , right_(right) + {} + + struct private_type_ { typedef private_type_ type; }; + + // can't ever return an array or an abstract type by value + typedef BOOST_DEDUCED_TYPENAME boost::mpl::eval_if< + boost::mpl::or_, boost::is_array > + , private_type_ + , boost::remove_const + >::type value_type; + + operator value_type() + { + return this->left_ < this->right_ ? this->left_ : this->right_; + } + + operator Ret &() const + { + return this->left_ < this->right_ ? this->left_ : this->right_; + } + + private: + Left &left_; + Right &right_; + }; + + + /////////////////////////////////////////////////////////////////////////////// + // min_fun + template + min_impl + min_fun(Left &left, Right &right, Ret *) + { + return min_impl(left, right); + } + + template + min_impl + min_fun(Left const &left, Right &right, Ret *) + { + return min_impl(left, right); + } + + template + min_impl + min_fun(Left &left, Right const &right, Ret *) + { + return min_impl(left, right); + } + + template + min_impl + min_fun(Left const &left, Right const &right, Ret *) + { + return min_impl(left, right); + } + +#define BOOST_MIN(a,b)\ + (true\ + ? boost::minmax_macro_detail_::min_fun((a), (b), \ + (true? 0 : boost::minmax_macro_detail_::encode_type(true? (a) : (b))))\ + : (true? (a) : (b))) + +}} + +#endif diff --git a/include/boost/algorithm/detail/minmax_macro_msvc.hpp b/include/boost/algorithm/detail/minmax_macro_msvc.hpp new file mode 100755 index 0000000..71af5d8 --- /dev/null +++ b/include/boost/algorithm/detail/minmax_macro_msvc.hpp @@ -0,0 +1,167 @@ +/////////////////////////////////////////////////////////////////////////////// +// minmax_macro_msvc.hpp header file +// +// Copyright 2006 Eric Niebler. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// Credits: +// Scott Meyers - for carefully detailing the shortcomings of +// std::min and std::max in his article "Min, max and more" +// Andrei Alexandrescu - for the suggestion that ?: operator couls be useful +// in solving Scott's long-standing min/max challenge. + +#ifndef BOOST_MIN + +#include +#include +#include +#include +#include + +namespace boost { namespace minmax_macro_detail_ +{ + + /////////////////////////////////////////////////////////////////////////////// + // Define some utilities for assessing the properties of expressions + // + typedef char yes_type; + typedef char (&no_type)[2]; + yes_type is_true(boost::mpl::true_ *); + no_type is_true(boost::mpl::false_ *); + +// Extracts the desired property from the expression without evaluating it +#define BOOST_MINMAX_PROTECT(expr) \ + (static_cast *>(0)) + + template + inline boost::mpl::and_ *and_(Bool1 *, Bool2 *) { return 0; } + + template + inline boost::mpl::not_ *not_(Bool *) { return 0; } + + template + inline boost::mpl::false_ *is_rvalue_(T &, int) { return 0; } + + template + inline boost::mpl::true_ *is_rvalue_(T const &, ...) { return 0; } + + template + inline boost::is_array *is_array_(T const &) { return 0; } + + /////////////////////////////////////////////////////////////////////////////// + // Detect at compile-time whether an expression yields an rvalue or + // an lvalue. This is rather non-standard, but MSVC seems to like it. + /////////////////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////////////////// + // rvalue_probe + // + template + struct rvalue_probe + { + struct private_type_ {}; + // can't ever return an array by value + typedef typename boost::mpl::if_< + boost::mpl::or_, boost::is_array >, private_type_, T + >::type value_type; + operator value_type(); + operator T &() const; + }; + + template + rvalue_probe const make_probe(T const &t); + +# define BOOST_MINMAX_IS_RVALUE(T) \ + BOOST_MINMAX_PROTECT( \ + boost::minmax_macro_detail_::and_( \ + boost::minmax_macro_detail_::not_(boost::minmax_macro_detail_::is_array_(T)) \ + , boost::minmax_macro_detail_::is_rvalue_( \ + (true ? boost::minmax_macro_detail_::make_probe(T) : (T)), 0))) + + template + Type *encode_type(Type &) { return 0; } + + template + Type const *encode_type(Type const &) { return 0; } + + /////////////////////////////////////////////////////////////////////////////// + // max_fun + template + typename mpl::if_::type + max_fun(Left &left, Right &right, Ret *, IsRvalue *) + { + return left < right ? right : left; + } + + template + typename mpl::if_::type + max_fun(Left const &left, Right &right, Ret *, IsRvalue *) + { + return left < right ? right : left; + } + + template + typename mpl::if_::type + max_fun(Left &left, Right const &right, Ret *, IsRvalue *) + { + return left < right ? right : left; + } + + template + typename mpl::if_::type + max_fun(Left const &left, Right const &right, Ret *, IsRvalue *) + { + return left < right ? right : left; + } + +#define BOOST_MAX(a,b)\ + boost::minmax_macro_detail_::max_fun(\ + (a) \ + , (b) \ + , (true? 0 : boost::minmax_macro_detail_::encode_type(true? (a) : (b))) \ + , BOOST_MINMAX_IS_RVALUE(true? (a) : (b))) + + + /////////////////////////////////////////////////////////////////////////////// + // min_fun + template + typename mpl::if_::type + min_fun(Left &left, Right &right, Ret *, IsRvalue *) + { + return left < right ? left : right; + } + + template + typename mpl::if_::type + min_fun(Left const &left, Right &right, Ret *, IsRvalue *) + { + return left < right ? left : right; + } + + template + typename mpl::if_::type + min_fun(Left &left, Right const &right, Ret *, IsRvalue *) + { + return left < right ? left : right; + } + + template + typename mpl::if_::type + min_fun(Left const &left, Right const &right, Ret *, IsRvalue *) + { + return left < right ? left : right; + } + + +#define BOOST_MIN(a,b)\ + boost::minmax_macro_detail_::min_fun(\ + (a) \ + , (b) \ + , (true? 0 : boost::minmax_macro_detail_::encode_type(true? (a) : (b))) \ + , BOOST_MINMAX_IS_RVALUE(true? (a) : (b))) + +}} + +#endif diff --git a/include/boost/algorithm/minmax_macro.hpp b/include/boost/algorithm/minmax_macro.hpp new file mode 100755 index 0000000..34265d4 --- /dev/null +++ b/include/boost/algorithm/minmax_macro.hpp @@ -0,0 +1,164 @@ +/////////////////////////////////////////////////////////////////////////////// +// minmax_macro.hpp header file +// +// Copyright 2006 Eric Niebler. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// Credits: +// Scott Meyers - for carefully detailing the shortcomings of +// std::min and std::max in his article "Min, max and more" +// Andrei Alexandrescu - for the suggestion that ?: operator couls be useful +// in solving Scott's long-standing min/max challenge. + +#ifndef BOOST_MIN + +#include + +#if BOOST_WORKAROUND(__COMO_VERSION__, BOOST_TESTED_AT(4245)) + +# include + +#elif BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1400)) + +# include + +#else + +namespace boost { namespace minmax_macro_detail_ +{ + + /////////////////////////////////////////////////////////////////////////////// + // max_impl + template + struct max_impl + { + max_impl(Left &left, Right &right) + : left_(left) + , right_(right) + {} + + template + operator Rvalue () + { + return this->left_ < this->right_ ? this->right_ : this->left_; + } + + template + operator Lvalue &() const + { + return this->left_ < this->right_ ? this->right_ : this->left_; + } + + #if BOOST_WORKAROUND(__GNUC__, BOOST_TESTED_AT(3)) + operator max_impl & () { return *this; } + #endif + + private: + Left &left_; + Right &right_; + }; + + /////////////////////////////////////////////////////////////////////////////// + // max_fun + template + max_impl + max_fun(Left &left, Right &right) + { + return max_impl(left, right); + } + + template + max_impl + max_fun(Left const &left, Right &right) + { + return max_impl(left, right); + } + + template + max_impl + max_fun(Left &left, Right const &right) + { + return max_impl(left, right); + } + + template + max_impl + max_fun(Left const &left, Right const &right) + { + return max_impl(left, right); + } + +#define BOOST_MAX(a,b)\ + (true? boost::minmax_macro_detail_::max_fun((a), (b)) : (true? (a) : (b))) + + /////////////////////////////////////////////////////////////////////////////// + // min_impl + template + struct min_impl + { + min_impl(Left &left, Right &right) + : left_(left) + , right_(right) + {} + + template + operator Rvalue () + { + return this->left_ < this->right_ ? this->left_ : this->right_; + } + + template + operator Lvalue &() const + { + return this->left_ < this->right_ ? this->left_ : this->right_; + } + + #if BOOST_WORKAROUND(__GNUC__, BOOST_TESTED_AT(3)) + operator min_impl & () { return *this; } + #endif + + private: + Left &left_; + Right &right_; + }; + + /////////////////////////////////////////////////////////////////////////////// + // min_fun + template + min_impl + min_fun(Left &left, Right &right) + { + return min_impl(left, right); + } + + template + min_impl + min_fun(Left const &left, Right &right) + { + return min_impl(left, right); + } + + template + min_impl + min_fun(Left &left, Right const &right) + { + return min_impl(left, right); + } + + template + min_impl + min_fun(Left const &left, Right const &right) + { + return min_impl(left, right); + } + +#define BOOST_MIN(a,b)\ + (true? boost::minmax_macro_detail_::min_fun((a), (b)) : (true? (a) : (b))) + +}} + +#endif + +#endif diff --git a/minmax_macro/test/Jamfile.v2 b/minmax_macro/test/Jamfile.v2 new file mode 100755 index 0000000..041dffb --- /dev/null +++ b/minmax_macro/test/Jamfile.v2 @@ -0,0 +1,21 @@ +# (C) Copyright 2004: Eric Niebler +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +# bring in rules for testing +import testing ; + +project + : requirements + /boost/test//boost_unit_test_framework + static + ../../../.. + ; + +test-suite "minmax_macro" + : [ run basic.cpp ] + [ run promotions.cpp ] + [ run rvalue_lvalue.cpp ] + [ run tricky.cpp ] + [ run eval_once.cpp ] + ; diff --git a/minmax_macro/test/basic.cpp b/minmax_macro/test/basic.cpp new file mode 100755 index 0000000..fa693f2 --- /dev/null +++ b/minmax_macro/test/basic.cpp @@ -0,0 +1,44 @@ +/////////////////////////////////////////////////////////////////////////////// +// basic.hpp test file +// +// Copyright 2006 Eric Niebler. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +void basic_min_test() +{ + BOOST_CHECK_EQUAL(1, BOOST_MIN(1,2)); + BOOST_CHECK_EQUAL(1, BOOST_MIN(2,1)); + + int one=1, two=2; + BOOST_CHECK_EQUAL(one, BOOST_MIN(one,two)); + BOOST_CHECK_EQUAL(one, BOOST_MIN(two,one)); +} + +void basic_max_test() +{ + BOOST_CHECK_EQUAL(2, BOOST_MAX(1,2)); + BOOST_CHECK_EQUAL(2, BOOST_MAX(2,1)); + + int one=1, two=2; + BOOST_CHECK_EQUAL(two, BOOST_MAX(one,two)); + BOOST_CHECK_EQUAL(two, BOOST_MAX(two,one)); +} + +/////////////////////////////////////////////////////////////////////////////// +// init_unit_test_suite +// +boost::unit_test::test_suite* init_unit_test_suite( int argc, char* argv[] ) +{ + boost::unit_test::test_suite *test = BOOST_TEST_SUITE("basic min/max test"); + + test->add(BOOST_TEST_CASE(&basic_min_test)); + test->add(BOOST_TEST_CASE(&basic_max_test)); + + return test; +} diff --git a/minmax_macro/test/eval_once.cpp b/minmax_macro/test/eval_once.cpp new file mode 100755 index 0000000..0bec23b --- /dev/null +++ b/minmax_macro/test/eval_once.cpp @@ -0,0 +1,37 @@ +/////////////////////////////////////////////////////////////////////////////// +// eval_once.hpp test file +// +// Copyright 2006 Eric Niebler. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +void test_eval_once() +{ + int i = 0; + int j = 1; + + int k = BOOST_MIN(i++,j); + BOOST_CHECK_EQUAL(1, i); + BOOST_CHECK_EQUAL(0, k); + + k = BOOST_MAX(i,++j); + BOOST_CHECK_EQUAL(2, j); + BOOST_CHECK_EQUAL(2, k); +} + +/////////////////////////////////////////////////////////////////////////////// +// init_unit_test_suite +// +boost::unit_test::test_suite* init_unit_test_suite( int argc, char* argv[] ) +{ + boost::unit_test::test_suite *test = BOOST_TEST_SUITE("eval_once min/max test"); + + test->add(BOOST_TEST_CASE(&test_eval_once)); + + return test; +} diff --git a/minmax_macro/test/promotions.cpp b/minmax_macro/test/promotions.cpp new file mode 100755 index 0000000..c1b520a --- /dev/null +++ b/minmax_macro/test/promotions.cpp @@ -0,0 +1,54 @@ +/////////////////////////////////////////////////////////////////////////////// +// promotions.hpp test file +// +// Copyright 2006 Eric Niebler. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include +#include +#include + +template void check_is_same(T) +{ + BOOST_MPL_ASSERT((boost::is_same)); +} + +void test_promotions() +{ + char ch = 0; + short sh = 0; + int in = 0; + unsigned un = 0; + float fl = 0; + double db = 0; + + check_is_same(BOOST_MIN(ch,sh)); + check_is_same(BOOST_MAX(ch,sh)); + check_is_same(BOOST_MIN(ch,in)); + check_is_same(BOOST_MAX(ch,in)); + + check_is_same(BOOST_MIN(un,in)); + check_is_same(BOOST_MAX(un,in)); + + check_is_same(BOOST_MIN(in,fl)); + check_is_same(BOOST_MAX(in,fl)); + + check_is_same(BOOST_MIN(db,fl)); + check_is_same(BOOST_MAX(db,fl)); +} + +/////////////////////////////////////////////////////////////////////////////// +// init_unit_test_suite +// +boost::unit_test::test_suite* init_unit_test_suite( int argc, char* argv[] ) +{ + boost::unit_test::test_suite *test = BOOST_TEST_SUITE("promotions min/max test"); + + test->add(BOOST_TEST_CASE(&test_promotions)); + + return test; +} diff --git a/minmax_macro/test/rvalue_lvalue.cpp b/minmax_macro/test/rvalue_lvalue.cpp new file mode 100755 index 0000000..c268329 --- /dev/null +++ b/minmax_macro/test/rvalue_lvalue.cpp @@ -0,0 +1,94 @@ +/////////////////////////////////////////////////////////////////////////////// +// rvalue_lvalue.hpp test file +// +// Copyright 2006 Eric Niebler. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// Test code from Howard Hinnant (TODO: get permission!) + +#include +#include + +class A +{ +private: + int i_; +public: + A(int i) : i_(i) {} + ~A() {i_ = 0;} + + A(const A& a) : i_(a.i_) {} + + operator int() const {return i_;} + + friend bool operator<(const A& x, const A& y) + {return x.i_ < y.i_;} + + friend bool operator==(const A& x, const A& y) + {return x.i_ == y.i_;} +}; + +void test_rvalue_lvalue() +{ + // lvalues of the same type: + { + A a3(3); + A a2(2); + BOOST_MIN(a2, a3) = A(1); // a2 == 1, no copy, no move + BOOST_CHECK_EQUAL(a2, A(1)); + BOOST_CHECK_EQUAL(a3, A(3)); + } + + //{ + // // lvalues of the same type with different cv + // const A a3(3); + // A a2(2); + // BOOST_MIN(a2, a3) = A(1); // illegal operands 'const A' = 'A' + //} + + { + const A a3(3); + A a2(2); + const A& a_ref = BOOST_MIN(a2, a3); + a2 = A(1); // a_ref == 1, a_ref refers to a2, no copy, no move + BOOST_CHECK_EQUAL(a_ref, A(1)); + } + + { + // lvalue / rvalue mix of the same type + A a3(3); + const A& a_ref = BOOST_MIN(A(2), a3); + BOOST_CHECK_EQUAL(a_ref, A(2)); + // a_ref refers to temporary returned (by value) from BOOST_MIN, a_ref == 2, A(A&&) executed to move from A(2) + // A(const A&) - or some copy constructor - required to be accessible + } + + { + A a1(1); + const A& a_ref = BOOST_MIN(A(2), a1); + BOOST_CHECK_EQUAL(a_ref, A(1)); + // a_ref refers to temporary returned (by value) from BOOST_MIN, a_ref == 1, A(const A&) executed to copy from a1 + } + + { + // rvalue / rvalue + const A& a_ref = BOOST_MIN(A(2), A(3)); + BOOST_CHECK_EQUAL(a_ref, A(2)); + // a_ref refers to temporary returned (by value) from BOOST_MIN, a_ref == 2, A(A&&) executed to move from A(2) + // accessible copy constructor not required + } +} + +/////////////////////////////////////////////////////////////////////////////// +// init_unit_test_suite +// +boost::unit_test::test_suite* init_unit_test_suite( int argc, char* argv[] ) +{ + boost::unit_test::test_suite *test = BOOST_TEST_SUITE("rvalue/lvalue min/max test"); + + test->add(BOOST_TEST_CASE(&test_rvalue_lvalue)); + + return test; +} diff --git a/minmax_macro/test/tricky.cpp b/minmax_macro/test/tricky.cpp new file mode 100755 index 0000000..83b3a26 --- /dev/null +++ b/minmax_macro/test/tricky.cpp @@ -0,0 +1,44 @@ +/////////////////////////////////////////////////////////////////////////////// +// tricky.hpp test file +// +// Copyright 2006 Eric Niebler. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +struct Base +{ + virtual bool operator <(Base const &) const = 0; +}; + +struct Derived : Base +{ + virtual bool operator <(Base const &that) const + { + return dynamic_cast(this) < dynamic_cast(&that); + } +}; + +void test_tricky() +{ + Derived d; + Base &b = d; + + Base &lvalue = BOOST_MIN(d,b); +} + +/////////////////////////////////////////////////////////////////////////////// +// init_unit_test_suite +// +boost::unit_test::test_suite* init_unit_test_suite( int argc, char* argv[] ) +{ + boost::unit_test::test_suite *test = BOOST_TEST_SUITE("tricky min/max test"); + + test->add(BOOST_TEST_CASE(&test_tricky)); + + return test; +}