-
Notifications
You must be signed in to change notification settings - Fork 96
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #18 from pfultz2/repeat
Repeat
- Loading branch information
Showing
7 changed files
with
350 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
/*============================================================================= | ||
Copyright (c) 2015 Paul Fultz II | ||
repeat.h | ||
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) | ||
==============================================================================*/ | ||
|
||
#ifndef FIT_GUARD_REPEAT_H | ||
#define FIT_GUARD_REPEAT_H | ||
|
||
/// repeat | ||
/// ====== | ||
/// | ||
/// Description | ||
/// ----------- | ||
/// | ||
/// The `repeat` function adaptor will repeatedly apply a function a given | ||
/// number of times. | ||
/// | ||
/// | ||
/// Synopsis | ||
/// -------- | ||
/// | ||
/// template<class F, class IntegralConstant> | ||
/// constexpr repeat_adaptor<F, IntegralConstant> repeat(F f, IntegralConstant); | ||
/// | ||
/// Requirements | ||
/// ------------ | ||
/// | ||
/// F must be: | ||
/// | ||
/// FunctionObject | ||
/// MoveConstructible | ||
/// | ||
/// IntegralConstant must be: | ||
/// | ||
/// IntegralConstant | ||
/// | ||
/// Example | ||
/// ------- | ||
/// | ||
/// struct increment | ||
/// { | ||
/// template<class T> | ||
/// constexpr T operator()(T x) const | ||
/// { | ||
/// return x + 1; | ||
/// } | ||
/// }; | ||
/// | ||
/// constexpr auto increment_by_5 = fit::repeat(increment(), std::integral_constant<int, 5>()); | ||
/// assert(increment_by_5(1) == 6); | ||
/// | ||
|
||
#include <fit/always.h> | ||
#include <fit/detail/delegate.h> | ||
#include <fit/detail/result_of.h> | ||
#include <fit/detail/move.h> | ||
#include <fit/detail/make.h> | ||
#include <fit/detail/sfinae.h> | ||
#include <fit/detail/static_const_var.h> | ||
|
||
namespace fit { namespace detail { | ||
|
||
template<int N> | ||
struct repeater | ||
{ | ||
template<class F, class... Ts> | ||
constexpr FIT_SFINAE_RESULT(repeater<N-1>, id_<const F&>, result_of<const F&, id_<Ts>...>) | ||
operator()(const F& f, Ts&&... xs) const FIT_SFINAE_RETURNS | ||
( | ||
repeater<N-1>()(f, f(fit::forward<Ts>(xs)...)) | ||
); | ||
}; | ||
|
||
template<> | ||
struct repeater<0> | ||
{ | ||
template<class F, class T> | ||
constexpr T operator()(const F&, T&& x) const | ||
{ | ||
return x; | ||
} | ||
}; | ||
|
||
} | ||
|
||
template<class F, class T> | ||
struct repeat_adaptor : F | ||
{ | ||
FIT_INHERIT_CONSTRUCTOR(repeat_adaptor, F) | ||
|
||
template<class X, FIT_ENABLE_IF_CONVERTIBLE(X, F)> | ||
constexpr repeat_adaptor(X&& x, T) : F(fit::forward<X>(x)) | ||
{} | ||
|
||
template<class... Ts> | ||
constexpr const F& base_function(Ts&&... xs) const | ||
{ | ||
return always_ref(*this)(xs...); | ||
} | ||
|
||
FIT_RETURNS_CLASS(repeat_adaptor); | ||
|
||
template<class... Ts> | ||
constexpr FIT_SFINAE_RESULT(detail::repeater<T::value>, id_<const F&>, id_<Ts>...) | ||
operator()(Ts&&... xs) const FIT_SFINAE_RETURNS | ||
( | ||
detail::repeater<T::value>() | ||
( | ||
FIT_MANGLE_CAST(const F&)(FIT_CONST_THIS->base_function(xs...)), | ||
fit::forward<Ts>(xs)... | ||
) | ||
); | ||
}; | ||
|
||
FIT_DECLARE_STATIC_VAR(repeat, detail::make<repeat_adaptor>); | ||
|
||
} | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
/*============================================================================= | ||
Copyright (c) 2015 Paul Fultz II | ||
repeat_while.h | ||
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) | ||
==============================================================================*/ | ||
|
||
#ifndef FIT_GUARD_REPEAT_WHILE_H | ||
#define FIT_GUARD_REPEAT_WHILE_H | ||
|
||
/// repeat_while | ||
/// ====== | ||
/// | ||
/// Description | ||
/// ----------- | ||
/// | ||
/// The `repeat_while` function adaptor will repeatedly apply a function while | ||
/// the predicate returns an integral constant that is true. As such, the | ||
/// predicate must be depedently-typed since it is never called at runtime. | ||
/// | ||
/// | ||
/// Synopsis | ||
/// -------- | ||
/// | ||
/// template<class F, class Predicate> | ||
/// constexpr repeat_while_adaptor<F, Predicate> repeat_while(F f, Predicate predicate); | ||
/// | ||
/// Requirements | ||
/// ------------ | ||
/// | ||
/// F must be: | ||
/// | ||
/// FunctionObject | ||
/// MoveConstructible | ||
/// | ||
/// Predicate must be: | ||
/// | ||
/// FunctionObject | ||
/// MoveConstructible | ||
/// | ||
/// Example | ||
/// ------- | ||
/// | ||
/// struct increment | ||
/// { | ||
/// template<class T> | ||
/// constexpr std::integral_constant<int, T::value + 1> operator()(T) const | ||
/// { | ||
/// return std::integral_constant<int, T::value + 1>(); | ||
/// } | ||
/// }; | ||
/// | ||
/// struct not_6 | ||
/// { | ||
/// template<class T> | ||
/// constexpr std::integral_constant<bool, (T::value != 6)> | ||
/// operator()(T) const | ||
/// { | ||
/// return std::integral_constant<bool, (T::value != 6)>(); | ||
/// } | ||
/// }; | ||
/// | ||
/// typedef std::integral_constant<int, 1> one; | ||
/// typedef std::integral_constant<int, 6> six; | ||
/// | ||
/// typedef decltype(fit::repeat_while(increment(), not_6())(std::integral_constant<int, 1>())) increment_until_6; | ||
/// | ||
/// | ||
/// constexpr auto increment_until_6 = fit::repeat_while(increment(), not_6()); | ||
/// static_assert(std::is_same<six, decltype(increment_until_6(one()))>::value, "Error"); | ||
/// | ||
|
||
#include <fit/always.h> | ||
#include <fit/detail/delegate.h> | ||
#include <fit/detail/result_of.h> | ||
#include <fit/detail/move.h> | ||
#include <fit/detail/make.h> | ||
#include <fit/detail/sfinae.h> | ||
#include <fit/detail/static_const_var.h> | ||
|
||
namespace fit { namespace detail { | ||
|
||
template<class P, class... Ts> | ||
struct compute_predicate | ||
{ | ||
typedef decltype(std::declval<P>()(std::declval<Ts>()...)) type; | ||
}; | ||
|
||
template<bool B> | ||
struct while_repeater | ||
{ | ||
template<class F, class P, class... Ts> | ||
constexpr FIT_SFINAE_RESULT(while_repeater< | ||
compute_predicate<P, typename result_of<const F&, id_<Ts>...>::type>::type::value | ||
>, id_<const F&>, id_<const P&>, result_of<const F&, id_<Ts>...>) | ||
operator()(const F& f, const P& p, Ts&&... xs) const FIT_SFINAE_RETURNS | ||
( | ||
while_repeater< | ||
compute_predicate<P, decltype(f(fit::forward<Ts>(xs)...))>::type::value | ||
>()(f, p, f(fit::forward<Ts>(xs)...)) | ||
); | ||
}; | ||
|
||
template<> | ||
struct while_repeater<false> | ||
{ | ||
template<class F, class P, class T> | ||
constexpr T operator()(const F&, const P&, T&& x) const | ||
{ | ||
return x; | ||
} | ||
}; | ||
|
||
} | ||
|
||
template<class F, class P> | ||
struct repeat_while_adaptor : F, P | ||
{ | ||
FIT_INHERIT_CONSTRUCTOR(repeat_while_adaptor, F) | ||
|
||
template<class X, class Y, | ||
FIT_ENABLE_IF_CONVERTIBLE(X, F), | ||
FIT_ENABLE_IF_CONVERTIBLE(Y, P) | ||
> | ||
constexpr repeat_while_adaptor(X&& x, Y&& y) | ||
: F(fit::forward<X>(x)), P(fit::forward<Y>(y)) | ||
{} | ||
|
||
template<class... Ts> | ||
constexpr const F& base_function(Ts&&... xs) const | ||
{ | ||
return always_ref(*this)(xs...); | ||
} | ||
|
||
template<class... Ts> | ||
constexpr const P& base_predicate(Ts&&... xs) const | ||
{ | ||
return always_ref(*this)(xs...); | ||
} | ||
|
||
FIT_RETURNS_CLASS(repeat_while_adaptor); | ||
|
||
template<class... Ts> | ||
constexpr FIT_SFINAE_RESULT( | ||
detail::while_repeater< | ||
detail::compute_predicate<P, typename result_of<const F&, id_<Ts>...>::type>::type::value | ||
>, | ||
id_<const F&>, id_<const P&>, id_<Ts>...) | ||
operator()(Ts&&... xs) const FIT_SFINAE_RETURNS | ||
( | ||
detail::while_repeater< | ||
detail::compute_predicate<P, decltype(std::declval<F>()(fit::forward<Ts>(xs)...))>::type::value | ||
>() | ||
( | ||
FIT_MANGLE_CAST(const F&)(FIT_CONST_THIS->base_function(xs...)), | ||
FIT_MANGLE_CAST(const P&)(FIT_CONST_THIS->base_predicate(xs...)), | ||
fit::forward<Ts>(xs)... | ||
) | ||
); | ||
}; | ||
|
||
FIT_DECLARE_STATIC_VAR(repeat_while, detail::make<repeat_while_adaptor>); | ||
|
||
} | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
#include <fit/repeat.h> | ||
#include "test.h" | ||
|
||
|
||
struct increment | ||
{ | ||
template<class T> | ||
constexpr T operator()(T x) const | ||
{ | ||
return x + 1; | ||
} | ||
}; | ||
|
||
FIT_TEST_CASE() | ||
{ | ||
FIT_TEST_CHECK(fit::repeat(increment(), std::integral_constant<int, 5>())(1) == 6); | ||
FIT_STATIC_TEST_CHECK(fit::repeat(increment(), std::integral_constant<int, 5>())(1) == 6); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
#include <fit/repeat_while.h> | ||
#include "test.h" | ||
|
||
// TODO: Test default construction, and static initialization | ||
|
||
struct increment | ||
{ | ||
template<class T> | ||
constexpr std::integral_constant<int, T::value + 1> operator()(T) const | ||
{ | ||
return std::integral_constant<int, T::value + 1>(); | ||
} | ||
}; | ||
|
||
struct not_6 | ||
{ | ||
template<class T> | ||
constexpr std::integral_constant<bool, (T::value != 6)> | ||
operator()(T) const | ||
{ | ||
return std::integral_constant<bool, (T::value != 6)>(); | ||
} | ||
}; | ||
|
||
FIT_TEST_CASE() | ||
{ | ||
static_assert | ||
( | ||
std::is_same< | ||
std::integral_constant<int, 6>, | ||
decltype(fit::repeat_while(increment(), not_6())(std::integral_constant<int, 1>())) | ||
>::value, | ||
"Error" | ||
); | ||
|
||
std::integral_constant<int, 6> x = fit::repeat_while(increment(), not_6())(std::integral_constant<int, 1>()); | ||
fit::test::unused(x); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters