================
@@ -0,0 +1,93 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___FUNCTIONAL_MOVE_ONLY_FUNCTION_H
+#define _LIBCPP___FUNCTIONAL_MOVE_ONLY_FUNCTION_H
+
+#include <__config>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+#if _LIBCPP_STD_VER >= 23
+
+// move_only_function design:
+//
+// move_only_function has a small buffer with a size of `3 * sizeof(void*)` 
bytes. This buffer can only be used when the
+// object that should be stored is trivially relocatable (currently only when 
it is trivially move constructible and
+// trivially destructible). There is also a bool in the lower bits of the vptr 
stored which is set when the contained
+// object is not trivially destructible.
+//
+// trivially relocatable: It would also be possible to store 
nothrow_move_constructible types, but that would mean
+// that move_only_function itself would not be trivially relocatable anymore. 
The decision to keep move_only_function
+// trivially relocatable was made because we expect move_only_function to be 
mostly used to store a functor. To only
+// forward functors there is std::function_ref (not voted in yet, expected in 
C++26).
+//
+// buffer size: We did a survey of six implementations from various vendors. 
Three of them had a buffer size of 24 bytes
+// on 64 bit systems. This also allows storing a std::string or std::vector 
inside the small buffer (once the compiler
+// has full support of trivially_relocatable annotations).
+//
+// trivially-destructible bit: This allows us to keep the overall binary size 
smaller because we don't have to store
+// a pointer to a noop function inside the vtable. It also avoids loading the 
vtable during destruction, potentially
+// resulting in fewer cache misses. The downside is that calling the function 
now also requires setting the lower bits
+// of the pointer to zero, but this is a very fast operation on modern CPUs.
----------------
ldionne wrote:

I would like us to document the design constraints around avoiding 
double-wrapping when constructing a `std::move_ony_function` from a 
`std::copyable_function` that we discussed just now. Gist of it:

This requires having compatible vtables in both implementations, where 
compatible means that the layout is the same but also that the implementation 
of the vtable functions can be swapped for one another. Basically, this means 
we'll need to use small buffer sizes where `sizeof(move_only_function) >= 
sizeof(copyable_function)`, and have the same criteria for when we put it in 
the small buffer (trivially-relocatable?).

IMO these requirements make it important to reuse the same machinery for 
implementing both classes. I am not certain in what form we want to do that 
yet, but I am thinking that there should be a single place where we encode 
these decisions (the small buffer size, the vtable layout, the condition for 
being in the SBO, etc). I don't think those belong in the `__small_buffer` 
class itself since that can be reused for stuff that isn't `move_only_function` 
or `copyable_function`, but it should be somewhere. Do you have thoughts on 
this?

https://github.com/llvm/llvm-project/pull/94670
_______________________________________________
llvm-branch-commits mailing list
llvm-branch-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits

Reply via email to