diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index cbf8f23eb..44416fa44 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -12,8 +12,6 @@ function(boost_hana_add_example name) add_dependencies(examples example.${name}) endfunction() -boost_hana_add_example(bool.logical.eval_if) - boost_hana_add_example(core.convert) boost_hana_add_example(core.defaults) boost_hana_add_example(core.instance) @@ -82,6 +80,8 @@ boost_hana_add_example(list.to) boost_hana_add_example(list.zip) boost_hana_add_example(list.zip_with) +boost_hana_add_example(logical.default_instance.eval_if) + boost_hana_add_example(maybe.api) boost_hana_add_example(maybe.comparable) boost_hana_add_example(maybe.functor) diff --git a/example/bool/logical/eval_if.cpp b/example/logical/default_instance/eval_if.cpp similarity index 100% rename from example/bool/logical/eval_if.cpp rename to example/logical/default_instance/eval_if.cpp diff --git a/include/boost/hana/foldable.hpp b/include/boost/hana/foldable.hpp index 75bdbec02..93b4a1821 100644 --- a/include/boost/hana/foldable.hpp +++ b/include/boost/hana/foldable.hpp @@ -387,10 +387,7 @@ namespace boost { namespace hana { template static constexpr auto count_impl(Pred pred, Foldable_ foldable) { auto inc = [=](auto counter, auto x) { - //! @todo - //! We use `!!pred(x)` to allow ints and other stuff. - //! Remove this once we get a proper `Logical` type class. - return if_(!!pred(x), counter + size_t<1>, counter); + return if_(pred(x), counter + size_t<1>, counter); }; return foldl(inc, size_t<0>, foldable); } @@ -412,11 +409,11 @@ namespace boost { namespace hana { template static constexpr auto all_impl(Pred pred, Foldable_ foldable) - { return !any([=](auto x) { return !pred(x); }, foldable); } + { return not_(any([=](auto x) { return not_(pred(x)); }, foldable)); } template static constexpr auto none_impl(Pred pred, Foldable_ foldable) - { return !any(pred, foldable); } + { return not_(any(pred, foldable)); } // any_of, all_of, none_of diff --git a/include/boost/hana/integral.hpp b/include/boost/hana/integral.hpp index 2cb9717f2..b54eb6eff 100644 --- a/include/boost/hana/integral.hpp +++ b/include/boost/hana/integral.hpp @@ -38,6 +38,10 @@ namespace boost { namespace hana { template static constexpr auto eval_if_impl(decltype(false_), Then, Else e) { return e([](auto x) { return x; }); } + + template + static constexpr auto not_impl(Cond c) + { return bool_; } }; namespace integral_detail { diff --git a/include/boost/hana/iterable.hpp b/include/boost/hana/iterable.hpp index 298de88e8..542859764 100644 --- a/include/boost/hana/iterable.hpp +++ b/include/boost/hana/iterable.hpp @@ -190,20 +190,20 @@ namespace boost { namespace hana { template static constexpr auto drop_while_impl(Pred pred, Iterable_ iterable) { - return if_(is_empty(iterable), + return eval_if(is_empty(iterable), always(iterable), - [=](auto it) { - return if_(pred(head(it)), - [=](auto it) { return drop_while_impl(pred, tail(it)); }, - always(it) - )(it); + [=](auto _) { + return eval_if(pred(_(head)(iterable)), + [=](auto _) { return drop_while_impl(pred, _(tail)(iterable)); }, + always(iterable) + ); } - )(iterable); + ); } template static constexpr auto drop_until_impl(Pred pred, Iterable_ iterable) { - return drop_while([=](auto x) { return !pred(x); }, iterable); + return drop_while([=](auto x) { return not_(pred(x)); }, iterable); } }; }; diff --git a/include/boost/hana/list.hpp b/include/boost/hana/list.hpp index b23e92e43..02506c1f0 100644 --- a/include/boost/hana/list.hpp +++ b/include/boost/hana/list.hpp @@ -514,7 +514,7 @@ namespace boost { namespace hana { //! ### Example //! @snippet example/list/take_until.cpp main BOOST_HANA_CONSTEXPR_LAMBDA auto take_until = [](auto predicate, auto xs) { - return take_while([=](auto x) { return !predicate(x); }, xs); + return take_while([=](auto x) { return not_(predicate(x)); }, xs); }; /*! diff --git a/include/boost/hana/logical.hpp b/include/boost/hana/logical.hpp index ba0733d10..176344d19 100644 --- a/include/boost/hana/logical.hpp +++ b/include/boost/hana/logical.hpp @@ -23,12 +23,13 @@ namespace boost { namespace hana { -------------------------------------------------------------------------- ## Minimal complete definition - `eval_if` + `eval_if` and `not_` ------------------------------------------------------------------------- @todo - Use a non-naive implementation for variadic `and_` and `or_`. + - Use a non-naive implementation for variadic `and_` and `or_`. + - Consider making this a real boolean algebra. @bug We don't short-circuit right now. Don't forget to change the examples and @@ -55,11 +56,17 @@ namespace boost { namespace hana { //! @snippet example/integral/logical/eval_if.cpp main //! //! ### Example (runtime or `constexpr` condition) - //! @snippet example/bool/logical/eval_if.cpp main + //! @snippet example/logical/default_instance/eval_if.cpp main BOOST_HANA_CONSTEXPR_LAMBDA auto eval_if = [](auto logical, auto then_branch, auto else_branch) { return Logical>::eval_if_impl(logical, then_branch, else_branch); }; + //! Negates a `Logical`. + //! @method{Logical} + BOOST_HANA_CONSTEXPR_LAMBDA auto not_ = [](auto logical) { + return Logical>::not_impl(logical); + }; + struct _and { template constexpr auto operator()(X x, Y y) const @@ -138,6 +145,12 @@ namespace boost { namespace hana { template constexpr auto operator||(X x, Y y) { return or_(x, y); } + + //! Equivalent to `not_`. + //! @method{boost::hana::Logical} + template + constexpr auto operator!(X x) + { return not_(x); } } @@ -168,13 +181,18 @@ namespace boost { namespace hana { template struct Logical : instance::template with { }; - template <> - struct Logical : defaults::with { + template + struct instance::with + : defaults::template with + { template static constexpr auto eval_if_impl(bool cond, Then t, Else e) { auto id = [](auto x) { return x; }; return cond ? t(id) : e(id); } + + static constexpr auto not_impl(bool cond) + { return !cond; } }; }} // end namespace boost::hana diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index aa586e589..f197fbf08 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -117,8 +117,9 @@ boost_hana_add_test(list.zip) boost_hana_add_test(list.zip_with) boost_hana_add_test(logical.and) -boost_hana_add_test(logical.bool) +boost_hana_add_test(logical.default_instance) boost_hana_add_test(logical.if) +boost_hana_add_test(logical.not) boost_hana_add_test(logical.or) boost_hana_add_test(maybe.api) diff --git a/test/foldable/all_of.cpp b/test/foldable/all_of.cpp index 0634a0749..3a663ec2c 100644 --- a/test/foldable/all_of.cpp +++ b/test/foldable/all_of.cpp @@ -15,11 +15,7 @@ Distributed under the Boost Software License, Version 1.0. using namespace boost::hana; -struct invalid_value { - using hana_datatype = invalid_value; - //! @todo This should be part of Logical's mcd. - invalid_value operator!() const { assert(false); return *this; } -}; +struct invalid_value { using hana_datatype = invalid_value; }; struct invalid_type { }; namespace boost { namespace hana { @@ -28,6 +24,9 @@ namespace boost { namespace hana { template static bool eval_if_impl(invalid_value, T, F) { assert(false); return true; } + + static auto not_impl(invalid_value self) + { assert(false); return self; } }; }} diff --git a/test/integral/logical.cpp b/test/integral/logical.cpp index 7a328523b..b3caa9797 100644 --- a/test/integral/logical.cpp +++ b/test/integral/logical.cpp @@ -49,11 +49,17 @@ auto test_or = [](auto true_, auto false_) { // BOOST_HANA_STATIC_ASSERT(!and_(false_, invalid, invalid)); }; +auto test_not = [](auto true_, auto false_) { + BOOST_HANA_STATIC_ASSERT(not_(false_)); + BOOST_HANA_STATIC_ASSERT(not_(not_(true_))); +}; + auto test = [](auto true_, auto false_) { test_eval_if(true_, false_); test_if(true_, false_); test_and(true_, false_); test_or(true_, false_); + test_not(true_, false_); }; int main() { diff --git a/test/logical/and.cpp b/test/logical/and.cpp index 7a7598849..68602a814 100644 --- a/test/logical/and.cpp +++ b/test/logical/and.cpp @@ -28,4 +28,11 @@ int main() { BOOST_HANA_STATIC_ASSERT(!and_(logical, logical, logical)); BOOST_HANA_STATIC_ASSERT(!and_(logical, logical, invalid)); // BOOST_HANA_STATIC_ASSERT(!and_(logical, invalid, invalid)); + + // operators + using operators::operator&&; + BOOST_HANA_STATIC_ASSERT((logical && logical) == and_(logical, logical)); + BOOST_HANA_STATIC_ASSERT((logical && logical) == and_(logical, logical)); + BOOST_HANA_STATIC_ASSERT((logical && logical) == and_(logical, logical)); + BOOST_HANA_STATIC_ASSERT((logical && logical) == and_(logical, logical)); } diff --git a/test/logical/bool.cpp b/test/logical/bool.cpp deleted file mode 100644 index 34ee8a0c8..000000000 --- a/test/logical/bool.cpp +++ /dev/null @@ -1,25 +0,0 @@ -/* -@copyright Louis Dionne 2014 -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - */ - -#include - -#include -using namespace boost::hana; - - -int main() { - BOOST_HANA_STATIC_ASSERT(eval_if(true, - [](auto) { return true; }, - [](auto id) { return 1 / id(0); } - ) == true); - BOOST_HANA_STATIC_ASSERT(eval_if(false, - [](auto id) { return 1 / id(0); }, - [](auto) { return false; } - ) == false); - - BOOST_HANA_STATIC_ASSERT(if_(true, true, false) == true); - BOOST_HANA_STATIC_ASSERT(if_(false, true, false) == false); -} diff --git a/test/logical/default_instance.cpp b/test/logical/default_instance.cpp new file mode 100644 index 000000000..fbbd17d60 --- /dev/null +++ b/test/logical/default_instance.cpp @@ -0,0 +1,37 @@ +/* +@copyright Louis Dionne 2014 +Distributed under the Boost Software License, Version 1.0. +(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + */ + +#include + +#include + +#include +using namespace boost::hana; + + +BOOST_HANA_CONSTEXPR_LAMBDA auto test = [](auto true_, auto false_) { + assert(eval_if(true_, + [=](auto) { return true_; }, + [](auto id) { return 1 / id(0); } + ) == true_); + assert(eval_if(false_, + [](auto id) { return 1 / id(0); }, + [=](auto) { return false_; } + ) == false_); + + assert(if_(true_, true_, false_) == true_); + assert(if_(false_, true_, false_) == false_); + + assert(not_(not_(true_))); + assert(not_(false_)); +}; + +int main() { + test(true, false); + test(1, 0); + test(2ll, 0ll); + test(2, false); +} diff --git a/test/logical/minimal_logical.hpp b/test/logical/minimal_logical.hpp index 136458e69..d43bf3272 100644 --- a/test/logical/minimal_logical.hpp +++ b/test/logical/minimal_logical.hpp @@ -15,9 +15,14 @@ struct MinimalLogical; template struct _logical { using hana_datatype = MinimalLogical; - constexpr bool operator!() const { return !b; } + explicit constexpr operator bool() const { return b; } }; +// required for the tests +template +constexpr bool operator==(_logical, _logical) +{ return b1 == b2; } + template constexpr _logical logical{}; @@ -32,6 +37,10 @@ namespace boost { namespace hana { template static constexpr auto eval_if_impl(_logical, Then, Else e) { return e([](auto x) { return x; }); } + + template + static constexpr auto not_impl(_logical) + { return logical; } }; }} diff --git a/test/logical/not.cpp b/test/logical/not.cpp new file mode 100644 index 000000000..f26d5243f --- /dev/null +++ b/test/logical/not.cpp @@ -0,0 +1,21 @@ +/* +@copyright Louis Dionne 2014 +Distributed under the Boost Software License, Version 1.0. +(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + */ + +#include + +#include + +#include "minimal_logical.hpp" +using namespace boost::hana; + + +int main() { + // not_ is part of the mcd, so there's nothing to test except operators + + using operators::operator!; + BOOST_HANA_STATIC_ASSERT(!logical == not_(logical)); + BOOST_HANA_STATIC_ASSERT(!logical == not_(logical)); +} diff --git a/test/logical/or.cpp b/test/logical/or.cpp index 5ef7d496c..ce8a04326 100644 --- a/test/logical/or.cpp +++ b/test/logical/or.cpp @@ -28,4 +28,11 @@ int main() { BOOST_HANA_STATIC_ASSERT(or_(logical, logical, logical)); // BOOST_HANA_STATIC_ASSERT(or_(logical, logical, invalid)); // BOOST_HANA_STATIC_ASSERT(or_(logical, invalid, invalid)); + + // operators + using operators::operator||; + BOOST_HANA_STATIC_ASSERT((logical || logical) == or_(logical, logical)); + BOOST_HANA_STATIC_ASSERT((logical || logical) == or_(logical, logical)); + BOOST_HANA_STATIC_ASSERT((logical || logical) == or_(logical, logical)); + BOOST_HANA_STATIC_ASSERT((logical || logical) == or_(logical, logical)); }