minmax_macro v0.1

[SVN r3105]
This commit is contained in:
Eric Niebler
2006-07-24 20:31:01 +00:00
parent b683dba9be
commit e82315742a
9 changed files with 801 additions and 0 deletions

View File

@ -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 <boost/mpl/or.hpp>
#include <boost/mpl/eval_if.hpp>
#include <boost/type_traits/is_array.hpp>
#include <boost/type_traits/is_abstract.hpp>
#include <boost/type_traits/remove_const.hpp>
namespace boost { namespace minmax_macro_detail_
{
template<typename Type>
Type *encode_type(Type &) { return 0; }
template<typename Type>
Type const *encode_type(Type const &) { return 0; }
///////////////////////////////////////////////////////////////////////////////
// max_impl
template<typename Ret, typename Left, typename Right>
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_abstract<Ret>, boost::is_array<Ret> >
, private_type_
, boost::remove_const<Ret>
>::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<typename Left, typename Right, typename Ret>
max_impl<Ret, Left, Right>
max_fun(Left &left, Right &right, Ret *)
{
return max_impl<Ret, Left, Right>(left, right);
}
template<typename Left, typename Right, typename Ret>
max_impl<Ret, Left const, Right>
max_fun(Left const &left, Right &right, Ret *)
{
return max_impl<Ret, Left const, Right>(left, right);
}
template<typename Left, typename Right, typename Ret>
max_impl<Ret, Left, Right const>
max_fun(Left &left, Right const &right, Ret *)
{
return max_impl<Ret, Left, Right const>(left, right);
}
template<typename Left, typename Right, typename Ret>
max_impl<Ret, Left const, Right const>
max_fun(Left const &left, Right const &right, Ret *)
{
return max_impl<Ret, Left const, Right const>(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<typename Ret, typename Left, typename Right>
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_abstract<Ret>, boost::is_array<Ret> >
, private_type_
, boost::remove_const<Ret>
>::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<typename Left, typename Right, typename Ret>
min_impl<Ret, Left, Right>
min_fun(Left &left, Right &right, Ret *)
{
return min_impl<Ret, Left, Right>(left, right);
}
template<typename Left, typename Right, typename Ret>
min_impl<Ret, Left const, Right>
min_fun(Left const &left, Right &right, Ret *)
{
return min_impl<Ret, Left const, Right>(left, right);
}
template<typename Left, typename Right, typename Ret>
min_impl<Ret, Left, Right const>
min_fun(Left &left, Right const &right, Ret *)
{
return min_impl<Ret, Left, Right const>(left, right);
}
template<typename Left, typename Right, typename Ret>
min_impl<Ret, Left const, Right const>
min_fun(Left const &left, Right const &right, Ret *)
{
return min_impl<Ret, Left const, Right const>(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

View File

@ -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 <boost/mpl/if.hpp>
#include <boost/mpl/bool.hpp>
#include <boost/mpl/logical.hpp>
#include <boost/type_traits/is_array.hpp>
#include <boost/type_traits/is_abstract.hpp>
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<boost::mpl::bool_<1 == sizeof(boost::minmax_macro_detail_::is_true(expr))> *>(0))
template<typename Bool1, typename Bool2>
inline boost::mpl::and_<Bool1, Bool2> *and_(Bool1 *, Bool2 *) { return 0; }
template<typename Bool>
inline boost::mpl::not_<Bool> *not_(Bool *) { return 0; }
template<typename T>
inline boost::mpl::false_ *is_rvalue_(T &, int) { return 0; }
template<typename T>
inline boost::mpl::true_ *is_rvalue_(T const &, ...) { return 0; }
template<typename T>
inline boost::is_array<T> *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<typename T>
struct rvalue_probe
{
struct private_type_ {};
// can't ever return an array by value
typedef typename boost::mpl::if_<
boost::mpl::or_<boost::is_abstract<T>, boost::is_array<T> >, private_type_, T
>::type value_type;
operator value_type();
operator T &() const;
};
template<typename T>
rvalue_probe<T> 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<typename Type>
Type *encode_type(Type &) { return 0; }
template<typename Type>
Type const *encode_type(Type const &) { return 0; }
///////////////////////////////////////////////////////////////////////////////
// max_fun
template<typename Left, typename Right, typename Ret, typename IsRvalue>
typename mpl::if_<IsRvalue, Ret, Ret &>::type
max_fun(Left &left, Right &right, Ret *, IsRvalue *)
{
return left < right ? right : left;
}
template<typename Left, typename Right, typename Ret, typename IsRvalue>
typename mpl::if_<IsRvalue, Ret, Ret &>::type
max_fun(Left const &left, Right &right, Ret *, IsRvalue *)
{
return left < right ? right : left;
}
template<typename Left, typename Right, typename Ret, typename IsRvalue>
typename mpl::if_<IsRvalue, Ret, Ret &>::type
max_fun(Left &left, Right const &right, Ret *, IsRvalue *)
{
return left < right ? right : left;
}
template<typename Left, typename Right, typename Ret, typename IsRvalue>
typename mpl::if_<IsRvalue, Ret, Ret &>::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 Left, typename Right, typename Ret, typename IsRvalue>
typename mpl::if_<IsRvalue, Ret, Ret &>::type
min_fun(Left &left, Right &right, Ret *, IsRvalue *)
{
return left < right ? left : right;
}
template<typename Left, typename Right, typename Ret, typename IsRvalue>
typename mpl::if_<IsRvalue, Ret, Ret &>::type
min_fun(Left const &left, Right &right, Ret *, IsRvalue *)
{
return left < right ? left : right;
}
template<typename Left, typename Right, typename Ret, typename IsRvalue>
typename mpl::if_<IsRvalue, Ret, Ret &>::type
min_fun(Left &left, Right const &right, Ret *, IsRvalue *)
{
return left < right ? left : right;
}
template<typename Left, typename Right, typename Ret, typename IsRvalue>
typename mpl::if_<IsRvalue, Ret, Ret &>::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

View File

@ -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 <boost/detail/workaround.hpp>
#if BOOST_WORKAROUND(__COMO_VERSION__, BOOST_TESTED_AT(4245))
# include <boost/algorithm/detail/minmax_macro_comeau.hpp>
#elif BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1400))
# include <boost/algorithm/detail/minmax_macro_msvc.hpp>
#else
namespace boost { namespace minmax_macro_detail_
{
///////////////////////////////////////////////////////////////////////////////
// max_impl
template<typename Left, typename Right>
struct max_impl
{
max_impl(Left &left, Right &right)
: left_(left)
, right_(right)
{}
template<typename Rvalue>
operator Rvalue ()
{
return this->left_ < this->right_ ? this->right_ : this->left_;
}
template<typename Lvalue>
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<typename Left, typename Right>
max_impl<Left, Right>
max_fun(Left &left, Right &right)
{
return max_impl<Left, Right>(left, right);
}
template<typename Left, typename Right>
max_impl<Left const, Right>
max_fun(Left const &left, Right &right)
{
return max_impl<Left const, Right>(left, right);
}
template<typename Left, typename Right>
max_impl<Left, Right const>
max_fun(Left &left, Right const &right)
{
return max_impl<Left, Right const>(left, right);
}
template<typename Left, typename Right>
max_impl<Left const, Right const>
max_fun(Left const &left, Right const &right)
{
return max_impl<Left const, Right const>(left, right);
}
#define BOOST_MAX(a,b)\
(true? boost::minmax_macro_detail_::max_fun((a), (b)) : (true? (a) : (b)))
///////////////////////////////////////////////////////////////////////////////
// min_impl
template<typename Left, typename Right>
struct min_impl
{
min_impl(Left &left, Right &right)
: left_(left)
, right_(right)
{}
template<typename Rvalue>
operator Rvalue ()
{
return this->left_ < this->right_ ? this->left_ : this->right_;
}
template<typename Lvalue>
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<typename Left, typename Right>
min_impl<Left, Right>
min_fun(Left &left, Right &right)
{
return min_impl<Left, Right>(left, right);
}
template<typename Left, typename Right>
min_impl<Left const, Right>
min_fun(Left const &left, Right &right)
{
return min_impl<Left const, Right>(left, right);
}
template<typename Left, typename Right>
min_impl<Left, Right const>
min_fun(Left &left, Right const &right)
{
return min_impl<Left, Right const>(left, right);
}
template<typename Left, typename Right>
min_impl<Left const, Right const>
min_fun(Left const &left, Right const &right)
{
return min_impl<Left const, Right const>(left, right);
}
#define BOOST_MIN(a,b)\
(true? boost::minmax_macro_detail_::min_fun((a), (b)) : (true? (a) : (b)))
}}
#endif
#endif

21
minmax_macro/test/Jamfile.v2 Executable file
View File

@ -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
<library>/boost/test//boost_unit_test_framework
<link>static
<include>../../../..
;
test-suite "minmax_macro"
: [ run basic.cpp ]
[ run promotions.cpp ]
[ run rvalue_lvalue.cpp ]
[ run tricky.cpp ]
[ run eval_once.cpp ]
;

44
minmax_macro/test/basic.cpp Executable file
View File

@ -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 <boost/test/unit_test.hpp>
#include <boost/algorithm/minmax_macro.hpp>
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;
}

37
minmax_macro/test/eval_once.cpp Executable file
View File

@ -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 <boost/test/unit_test.hpp>
#include <boost/algorithm/minmax_macro.hpp>
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;
}

View File

@ -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 <boost/test/unit_test.hpp>
#include <boost/mpl/assert.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/algorithm/minmax_macro.hpp>
template<typename Result, typename T> void check_is_same(T)
{
BOOST_MPL_ASSERT((boost::is_same<T,Result>));
}
void test_promotions()
{
char ch = 0;
short sh = 0;
int in = 0;
unsigned un = 0;
float fl = 0;
double db = 0;
check_is_same<int>(BOOST_MIN(ch,sh));
check_is_same<int>(BOOST_MAX(ch,sh));
check_is_same<int>(BOOST_MIN(ch,in));
check_is_same<int>(BOOST_MAX(ch,in));
check_is_same<unsigned>(BOOST_MIN(un,in));
check_is_same<unsigned>(BOOST_MAX(un,in));
check_is_same<float>(BOOST_MIN(in,fl));
check_is_same<float>(BOOST_MAX(in,fl));
check_is_same<double>(BOOST_MIN(db,fl));
check_is_same<double>(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;
}

View File

@ -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 <boost/test/included/unit_test.hpp>
#include <boost/algorithm/minmax_macro.hpp>
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;
}

44
minmax_macro/test/tricky.cpp Executable file
View File

@ -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 <boost/test/unit_test.hpp>
#include <boost/algorithm/minmax_macro.hpp>
struct Base
{
virtual bool operator <(Base const &) const = 0;
};
struct Derived : Base
{
virtual bool operator <(Base const &that) const
{
return dynamic_cast<void const*>(this) < dynamic_cast<void const*>(&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;
}