Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support etl::inplace_function #1046

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

jiangyilism
Copy link

Provide similar api to std::function.

Current use case is mainly to hold a r-value lambda object, which etl::delegate is unsuitable since etl::delegate does not extend the lifetime of r-value lambda object.

Store a callable inside the inplace_function object's member field in a type-erasure way.
The member field, i.e. storage or buffer, has a compile-time fixed size.
The size is specified either by the macro ETL_INPLACE_FUNCTION_DEFAULT_CAPACITY or a non-type template parameter.

The implementation is inspired by:

  1. SG14 inplace_function
  2. folly::Function
  3. function2

using dtor_func_t = void (*)(storage_ptr_t);

const invoke_func_t invoke_func{[](storage_ptr_t, Args&&...) -> R
{ return R(); }};
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

std::function throws std::bad_function_call if operator() is called on an empty object while etl::inplace_function safely returns a default-constructed object in this case.
That means type typename R is required to be default-constructible.
void type is fine here ( https://timsong-cpp.github.io/cppwp/std14/expr.type.conv )
But this will not compile since std::is_default_constructible_v<Type_a> is false:

  struct Type_a
  {
    Type_a(int32_t val) : val_(val) {}

    int32_t val_;
  };

etl::inplace_function<Type_a()> func0;

This deviation from std::function is by designed and also tested in test_inplace_function.cpp

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In etl::delegate an ETL error is raised.
ETL_ASSERT(is_valid(), ETL_ERROR(delegate_uninitialised));

Also in etl::delegate there are call_if and call_or member functions that handle uninitialised objects.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated to make it raise etl::bad_inplace_function_call when an empty etl::inplace_function is invoked with operator() . (Similar to std::bad_function_call)
std::function does not support call_if() and call_or(). Do you suggest adding these 2 member func?

https://github.com/ETLCPP/etl
https://www.etlcpp.com

Copyright(c) 2025 BMW AG
Copy link
Contributor

@jwellbelove jwellbelove Mar 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How close a copy is this of the implementations that 'inspired' you?
There may be copyright implications.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The closest open source implementation is SG14 inplace_function.
etl::inplace_function compiled object memory layout will be almost identical (except alignment).
The main differences:

  1. etl is compatible with c++11 while others, including SG14, typically requires c++14
  2. etl one has no member/non-member function swap(), operator==(nullptr_t), operator!=(nullptr_t) .
  3. etl does not utilize aligned storage, which will be deprecated in c++23.
  4. etl renames most of the class and variable names, except the name "inplace_function", which can be renamed too.
  5. etl simplifies some template meta programming with etl type_traits header
  6. move almost all stuffs in private namespace into private sections of classes.

typename T,
typename C = etl::decay_t<T>,
typename = etl::enable_if_t<
!private_inplace_function::is_inplace_function<C>::value && etl::is_invocable_r<R, C&, Args...>::value>>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This class has limited usefulness as is restricted to STL and C++14 and above.
Many of the users of the ETL do not/cannot use the STL.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

etl::is_invocable_r depends on ETL_USING_CPP11 but not STL.
I updated to make etl::inplace_function compatible to c++11.

Chiang, Yi added 2 commits March 8, 2025 01:20
Provide similar api to std::function.
Store a callable inside the inplace_function object's member field in a
type-erasure way. The member field, i.e. storage or buffer, has a
compile-time fixed size. The size is specify either by the macro
ETL_INPLACE_FUNCTION_DEFAULT_CAPACITY or a non-type template parameter.

The implementation is inspired by:
1. SG14 inplace_function
2. folly::Function
3. function2
@jiangyilism jiangyilism force-pushed the yichiang/support_inplace_function branch from f20d0ab to af095d7 Compare March 10, 2025 08:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: In progress
Development

Successfully merging this pull request may close these issues.

3 participants