forked from Imagelibrary/binutils-gdb
Compare commits
1 Commits
gdb-14.2-r
...
users/palv
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
37c2487312 |
@@ -61,7 +61,7 @@ struct plus_one_int_func_obj
|
|||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
run_tests ()
|
test_function_view ()
|
||||||
{
|
{
|
||||||
/* A simple lambda. */
|
/* A simple lambda. */
|
||||||
auto plus_one_lambda = [] (int val) { return ++val; };
|
auto plus_one_lambda = [] (int val) { return ++val; };
|
||||||
@@ -168,6 +168,86 @@ run_tests ()
|
|||||||
SELF_CHECK (!check_op_eq_null);
|
SELF_CHECK (!check_op_eq_null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* A template function where the function_view type is dependent on a
|
||||||
|
template parameter. */
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static int
|
||||||
|
tmpl_func (T val, gdb::function_view<T (T)> callback)
|
||||||
|
{
|
||||||
|
return callback (val) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
make_fv_test_func (int val)
|
||||||
|
{
|
||||||
|
return val + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A function object with const operator(). */
|
||||||
|
|
||||||
|
struct func_obj_const_op
|
||||||
|
{
|
||||||
|
int operator() (int val) const
|
||||||
|
{
|
||||||
|
return val + 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* A function object with non-const operator(). */
|
||||||
|
|
||||||
|
struct func_obj_non_const_op
|
||||||
|
{
|
||||||
|
int operator() (int val)
|
||||||
|
{
|
||||||
|
return val + 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_make_function_view ()
|
||||||
|
{
|
||||||
|
/* Function reference. */
|
||||||
|
SELF_CHECK (3 == tmpl_func (1, gdb::make_function_view (make_fv_test_func)));
|
||||||
|
|
||||||
|
/* Function pointer. */
|
||||||
|
SELF_CHECK (3 == tmpl_func (1, gdb::make_function_view (&make_fv_test_func)));
|
||||||
|
|
||||||
|
/* Reference to const and non-const function pointers. */
|
||||||
|
typedef int (*func_ptr) (int);
|
||||||
|
func_ptr ptr = make_fv_test_func;
|
||||||
|
const func_ptr cptr = make_fv_test_func;
|
||||||
|
SELF_CHECK (3 == tmpl_func (1, gdb::make_function_view (ptr)));
|
||||||
|
SELF_CHECK (3 == tmpl_func (1, gdb::make_function_view (cptr)));
|
||||||
|
|
||||||
|
/* Lambdas. */
|
||||||
|
|
||||||
|
auto lambda = [] (int val) -> int { return val + 1; };
|
||||||
|
|
||||||
|
/* This wouldn't compile, since tmpl_func is a template and its
|
||||||
|
function_view argument's callable type is a dependent type. The
|
||||||
|
passed argument must be of the exact type of the function's
|
||||||
|
parameter. */
|
||||||
|
// SELF_CHECK (3 == tmpl_func (1, lambda));
|
||||||
|
|
||||||
|
SELF_CHECK (3 == tmpl_func (1, gdb::make_function_view (lambda)));
|
||||||
|
|
||||||
|
/* Regular function objects. */
|
||||||
|
|
||||||
|
func_obj_non_const_op fobj;
|
||||||
|
SELF_CHECK (3 == tmpl_func (1, gdb::make_function_view (fobj)));
|
||||||
|
|
||||||
|
func_obj_const_op cfobj;
|
||||||
|
SELF_CHECK (3 == tmpl_func (1, gdb::make_function_view (cfobj)));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
run_tests ()
|
||||||
|
{
|
||||||
|
test_function_view ();
|
||||||
|
test_make_function_view ();
|
||||||
|
}
|
||||||
|
|
||||||
} /* namespace function_view */
|
} /* namespace function_view */
|
||||||
} /* namespace selftests */
|
} /* namespace selftests */
|
||||||
|
|
||||||
|
|||||||
@@ -148,6 +148,47 @@
|
|||||||
|
|
||||||
iterate_over_foos (process_one_foo);
|
iterate_over_foos (process_one_foo);
|
||||||
|
|
||||||
|
There's also a gdb::make_function_view function that you can use to
|
||||||
|
automatically create a function_view from a callable without having
|
||||||
|
to specify the function_view's template parameter. E.g.:
|
||||||
|
|
||||||
|
auto lambda = [&] (int) { ... };
|
||||||
|
auto fv = gdb::make_function_view (lambda);
|
||||||
|
|
||||||
|
This can be useful for example when calling a template function
|
||||||
|
whose function_view parameter type depends on the function's
|
||||||
|
template parameters. In such case, you can't rely on implicit
|
||||||
|
callable->function_view conversion for the function_view argument.
|
||||||
|
You must pass a function_view argument already of the right type to
|
||||||
|
the template function. E.g., with this:
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void my_function (T v, gdb::function_view<void(T)> callback = nullptr);
|
||||||
|
|
||||||
|
this wouldn't compile:
|
||||||
|
|
||||||
|
auto lambda = [&] (int) { ... };
|
||||||
|
my_function (1, lambda);
|
||||||
|
|
||||||
|
Note that this immediately dangles the temporary lambda object:
|
||||||
|
|
||||||
|
gdb::function_view<void(int)> fv = [&] (int) { ... }; // dangles
|
||||||
|
my_function (fv);
|
||||||
|
|
||||||
|
To avoid the dangling you'd have to use a named temporary for the
|
||||||
|
lambda:
|
||||||
|
|
||||||
|
auto lambda = [&] (int) { ... };
|
||||||
|
gdb::function_view<void(int)> fv = lambda;
|
||||||
|
my_function (fv);
|
||||||
|
|
||||||
|
Using gdb::make_function_view instead automatically deduces the
|
||||||
|
function_view's full type, and, avoids worrying about dangling. For
|
||||||
|
the example above, we could write instead:
|
||||||
|
|
||||||
|
auto lambda = [&] (int) { ... };
|
||||||
|
my_function (1, gdb::make_function_view (lambda));
|
||||||
|
|
||||||
You can find unit tests covering the whole API in
|
You can find unit tests covering the whole API in
|
||||||
unittests/function-view-selftests.c. */
|
unittests/function-view-selftests.c. */
|
||||||
|
|
||||||
@@ -318,6 +359,92 @@ constexpr inline bool
|
|||||||
operator!= (std::nullptr_t, const function_view<Res (Args...)> &f) noexcept
|
operator!= (std::nullptr_t, const function_view<Res (Args...)> &f) noexcept
|
||||||
{ return static_cast<bool> (f); }
|
{ return static_cast<bool> (f); }
|
||||||
|
|
||||||
|
namespace fv_detail {
|
||||||
|
|
||||||
|
/* Helper traits type to automatically find the right function_view
|
||||||
|
type for a callable. */
|
||||||
|
|
||||||
|
/* Use partial specialization to get access to the callable's
|
||||||
|
signature, for all the different callable variants. */
|
||||||
|
|
||||||
|
template<typename>
|
||||||
|
struct function_view_traits;
|
||||||
|
|
||||||
|
/* Main partial specialization with plain function signature type.
|
||||||
|
All others end up redirected here. */
|
||||||
|
template<typename Res, typename... Args>
|
||||||
|
struct function_view_traits<Res (Args...)>
|
||||||
|
{
|
||||||
|
using type = gdb::function_view<Res (Args...)>;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Function pointers. */
|
||||||
|
template<typename Res, typename... Args>
|
||||||
|
struct function_view_traits<Res (*) (Args...)>
|
||||||
|
: function_view_traits<Res (Args...)>
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Function references. */
|
||||||
|
template<typename Res, typename... Args>
|
||||||
|
struct function_view_traits<Res (&) (Args...)>
|
||||||
|
: function_view_traits<Res (Args...)>
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Reference to function pointers. */
|
||||||
|
template<typename Res, typename... Args>
|
||||||
|
struct function_view_traits<Res (*&) (Args...)>
|
||||||
|
: function_view_traits<Res (Args...)>
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Reference to const function pointers. */
|
||||||
|
template<typename Res, typename... Args>
|
||||||
|
struct function_view_traits<Res (* const &) (Args...)>
|
||||||
|
: function_view_traits<Res (Args...)>
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Const member functions. function_view doesn't support these, but
|
||||||
|
we need this in order to extract the type of function objects.
|
||||||
|
Lambdas pass here, after starting at the operator() case,
|
||||||
|
below. */
|
||||||
|
template<typename Res, typename Class, typename... Args>
|
||||||
|
struct function_view_traits<Res (Class::*) (Args...) const>
|
||||||
|
: function_view_traits<Res (Args...)>
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Member functions. Ditto, for function objects with non-const
|
||||||
|
operator(). */
|
||||||
|
template<typename Res, typename Class, typename... Args>
|
||||||
|
struct function_view_traits<Res (Class::*) (Args...)>
|
||||||
|
: function_view_traits<Res (Args...)>
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Function objects, lambdas, std::function, any type that defines
|
||||||
|
operator(). */
|
||||||
|
template<typename FuncObj>
|
||||||
|
struct function_view_traits
|
||||||
|
: function_view_traits <decltype
|
||||||
|
(&std::remove_reference<FuncObj>::type::operator())>
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
} /* namespace fv_detail */
|
||||||
|
|
||||||
|
/* Make a function_view from a callable. Useful to automatically
|
||||||
|
deduce the function_view's template argument type. */
|
||||||
|
template<typename Callable>
|
||||||
|
auto make_function_view (Callable &&callable)
|
||||||
|
-> typename fv_detail::function_view_traits<Callable>::type
|
||||||
|
{
|
||||||
|
using fv = typename fv_detail::function_view_traits<Callable>::type;
|
||||||
|
return fv (std::forward<Callable> (callable));
|
||||||
|
}
|
||||||
|
|
||||||
} /* namespace gdb */
|
} /* namespace gdb */
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user