Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Easy way to implement small buffer optimization for arbitrary type erasure (like in std::function.)

Tags:

c++

c++11

I tend to use type erasure technique quite a bit. It typically looks like this:

class YetAnotherTypeErasure
{
public:
   // interface redirected to pImpl
private:
   // Adapting function
   template ...
   friend YetAnotherTypeErasure make_YetAnotherTypeErasure (...);

   class Interface {...};

   template <typename Adaptee>
   class Concrete final : public Interface { 
     // redirecting Interface to Adaptee
   };

   std::unique_ptr<Interface> pImpl_; // always on the heap
};

std::function does something similar, but it has a small buffer optimization, so if Concrete<Adaptee> is smaller than smth and has nothrow move operations, it will be stored in it. Is there some generic library solution to do it fairly easy? For enforcing small buffer only storing at compile time? Maybe something has been proposed for standardisation?

like image 490
Denis Yaroshevskiy Avatar asked Nov 07 '15 12:11

Denis Yaroshevskiy


2 Answers

I know nothing about the small buffer optimization required by the standard or any proposal, though it is often allowed or encouraged.

Note that some (conditionally) non-throwing requirements on such types effectively require the optimization in practice because alternatives (like non-throwing allocation from emergency buffers) seem insane here.

On the other hand, you can just make your own solution from scratch, based on the standard library (e.g. std::aligned_storage). This may still verbose from the view of users, but not too hard.

Actually I implemented (not proposed then) any with such optimization and some related utilities several years ago. Lately, libstdc++'s implementation of std::experimental::any used the technique almost exactly as this (however, __ prefixed internal names are certainly not good for ordinary library users).

My implementation now uses some common helpers to deal with the storage. These helpers do ease to implement the type erasure storage strategy (at least fit for something similar to any enough). But I am still interested in more general high-level solution to simplify the interface redirecting.

There is also a function implementation based directly on the any implementation above. They support move-only types and sane allocator interface, while std ones not. The function implementation has better performance than std::function in libstdc++ in some cases, thanks to the (partially no-op) default initialization of the underlying any object.

like image 66
FrankHB Avatar answered Sep 30 '22 20:09

FrankHB


I found a reasonably nice solution for everyday code - use std::function

With tiny library support to help with const correctness, the code get's down to 20 lines: https://gcc.godbolt.org/z/GtewFI

like image 33
Denis Yaroshevskiy Avatar answered Sep 30 '22 20:09

Denis Yaroshevskiy