FTL: Introduce ftl::Function<F,N> et al.

ftl::Function<F, N> is a container for function object, and can mostly
be used in place of std::function<F>.

Unlike std::function<F>, a ftl::Function<F, N>:

  * Uses a static amount of memory (controlled by N), and never any
    dynamic allocation.
  * Satisfies the std::is_trivially_copyable<> trait.
  * Satisfies the std::is_trivially_destructible<> trait.

However to satisfy those constraints, the contained function object must
also satisfy those constraints, meaning certain types (like
std::unique_ptr's) cannot be part of the contained function object type.

The size of a ftl::Function<F, N> is guaranteed to be:

    sizeof(std::intptr_t) * (N + 2)

If not specified, N defaults to zero, which is big enough to store a lambda
that captures a single pointer (such as "this" for forwarding to a
member function.

By comparison, sizeof(std::function) == sizeof(std::intptr_t) * 4, at
least with on x86-64 with clang 15.

Compile time checks are performed that the constraints are all satisfied,
and that the value of N is large enough to contain the desired function
object type.

ftl::make_function is a helper function to construct a ftl::Function,
and will deduce the template type arguments. In addition to constructing
a ftl::Function for a function object, ftl::make_function has overloads
for creating a ftl::Function which will invoke a member function or a free
(non-member) function.

ftl::no_op is a helper value to construct a ftl::Function<F, N> that
does nothing, except default construct a return value, if one is needed.

A unit test is also included to demonstrate and verify the
implementation, including asserting that function objects which don't
meet the requirements cannot be used. The test also asserts some
non-obvious corner cases for handling argument and return value
conversions to match how std::function behaves.

Bug: 279581095
Test: atest ftl_test
Change-Id: I268facb106a248d0766e931595291036bc606fb7
diff --git a/include/ftl/details/function.h b/include/ftl/details/function.h
new file mode 100644
index 0000000..35c5a8b
--- /dev/null
+++ b/include/ftl/details/function.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <array>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <type_traits>
+
+namespace android::ftl::details {
+
+// The maximum allowed value for the template argument `N` in
+// `ftl::Function<F, N>`.
+constexpr size_t kFunctionMaximumN = 14;
+
+// Converts a member function pointer type `Ret(Class::*)(Args...)` to an equivalent non-member
+// function type `Ret(Args...)`.
+
+template <typename>
+struct remove_member_function_pointer;
+
+template <typename Class, typename Ret, typename... Args>
+struct remove_member_function_pointer<Ret (Class::*)(Args...)> {
+  using type = Ret(Args...);
+};
+
+template <typename Class, typename Ret, typename... Args>
+struct remove_member_function_pointer<Ret (Class::*)(Args...) const> {
+  using type = Ret(Args...);
+};
+
+template <auto MemberFunction>
+using remove_member_function_pointer_t =
+    typename remove_member_function_pointer<decltype(MemberFunction)>::type;
+
+// Helper functions for binding to the supported targets.
+
+template <typename Ret, typename... Args>
+auto bind_opaque_no_op() -> Ret (*)(void*, Args...) {
+  return [](void*, Args...) -> Ret {
+    if constexpr (!std::is_void_v<Ret>) {
+      return Ret{};
+    }
+  };
+}
+
+template <typename F, typename Ret, typename... Args>
+auto bind_opaque_function_object(const F&) -> Ret (*)(void*, Args...) {
+  return [](void* opaque, Args... args) -> Ret {
+    return std::invoke(*static_cast<F*>(opaque), std::forward<Args>(args)...);
+  };
+}
+
+template <auto MemberFunction, typename Class, typename Ret, typename... Args>
+auto bind_member_function(Class* instance, Ret (*)(Args...) = nullptr) {
+  return [instance](Args... args) -> Ret {
+    return std::invoke(MemberFunction, instance, std::forward<Args>(args)...);
+  };
+}
+
+template <auto FreeFunction, typename Ret, typename... Args>
+auto bind_free_function(Ret (*)(Args...) = nullptr) {
+  return [](Args... args) -> Ret { return std::invoke(FreeFunction, std::forward<Args>(args)...); };
+}
+
+// Traits class for the opaque storage used by Function.
+
+template <std::size_t N>
+struct function_opaque_storage {
+  // The actual type used for the opaque storage. An `N` of zero specifies the minimum useful size,
+  // which allows a lambda with zero or one capture args.
+  using type = std::array<std::intptr_t, N + 1>;
+
+  template <typename S>
+  static constexpr bool require_trivially_copyable = std::is_trivially_copyable_v<S>;
+
+  template <typename S>
+  static constexpr bool require_trivially_destructible = std::is_trivially_destructible_v<S>;
+
+  template <typename S>
+  static constexpr bool require_will_fit_in_opaque_storage = sizeof(S) <= sizeof(type);
+
+  template <typename S>
+  static constexpr bool require_alignment_compatible =
+      std::alignment_of_v<S> <= std::alignment_of_v<type>;
+
+  // Copies `src` into the opaque storage, and returns that storage.
+  template <typename S>
+  static type opaque_copy(const S& src) {
+    // TODO: Replace with C++20 concepts/constraints which can give more details.
+    static_assert(require_trivially_copyable<S>,
+                  "ftl::Function can only store lambdas that capture trivially copyable data.");
+    static_assert(
+        require_trivially_destructible<S>,
+        "ftl::Function can only store lambdas that capture trivially destructible data.");
+    static_assert(require_will_fit_in_opaque_storage<S>,
+                  "ftl::Function has limited storage for lambda captured state. Maybe you need to "
+                  "increase N?");
+    static_assert(require_alignment_compatible<S>);
+
+    type opaque;
+    std::memcpy(opaque.data(), &src, sizeof(S));
+    return opaque;
+  }
+};
+
+// Traits class to help determine the template parameters to use for a ftl::Function, given a
+// function object.
+
+template <typename F, typename = decltype(&F::operator())>
+struct function_traits {
+  // The function type `F` with which to instantiate the `Function<F, N>` template.
+  using type = remove_member_function_pointer_t<&F::operator()>;
+
+  // The (minimum) size `N` with which to instantiate the `Function<F, N>` template.
+  static constexpr std::size_t size =
+      (std::max(sizeof(std::intptr_t), sizeof(F)) - 1) / sizeof(std::intptr_t);
+};
+
+}  // namespace android::ftl::details