- 04 Nov, 2017 3 commits
-
-
Yedidya Feldblum authored
Summary: [Folly] `constexpr_clamp`. Like `std::clamp` (C++17). Reviewed By: Orvid Differential Revision: D6236825 fbshipit-source-id: 0f6c5dc9a955b148021ee6ed3e86201b53ae090c
-
Lee Howes authored
Summary: Make SemiFuture throw if no executor provided to via because in that situation the deferred work will never run. Reviewed By: yfeldblum Differential Revision: D6233233 fbshipit-source-id: 43b642c46cc0be80b1f13c03bdaf20b8038acec2
-
Yedidya Feldblum authored
Summary: [Folly] Move `folly/SafeAssert.h` to `folly/lang/`. Reviewed By: Orvid Differential Revision: D6230421 fbshipit-source-id: 0086cd6fedd4ce0e7a4d5302a41153ec1a502e74
-
- 03 Nov, 2017 6 commits
-
-
Lee Howes authored
Summary: Fix for function parameter order that shows up in opt build on later diff. Reviewed By: andriigrynenko Differential Revision: D6237125 fbshipit-source-id: fbb7be2c70b32203c658fc239cd74164e01fa1ca
-
Louis Dionne authored
Summary: Closes https://github.com/facebook/folly/pull/705 Reviewed By: yfeldblum Differential Revision: D6234351 Pulled By: Orvid fbshipit-source-id: e71bb3882c783a47ace4d08f134b2e450aaabb6b
-
Dan Melnic authored
Expose the zerocopy buf ID, change the AsyncSocket fd constructor to accept the id, Buff->Buf, make the cmsghdr methods private Summary: Expose the zerocopy buf ID, change the AsyncScokey fd constructor to accept the id, Buff->Buf, make the cmsghdr methods private Reviewed By: djwatson Differential Revision: D6221324 fbshipit-source-id: d0fc4937adf6cf5790d11e406ffd3ec64c558b9c
-
Lee Howes authored
Summary: Conversion check was lost in an earlier refactor. This meant that SemiFuture could be accidentally converted to Future through the value constructor. This should be disabled. Reviewed By: yfeldblum Differential Revision: D6214526 fbshipit-source-id: 3fc2d026ec6062b38b9500c8adf3eee12c0f2693
-
Yedidya Feldblum authored
Summary: [Folly] Alias `std::launder` when it is available. Reviewed By: Orvid Differential Revision: D6221443 fbshipit-source-id: 33136a8744a39db01fb05513d5ed5476ea67559a
-
Eric Niebler authored
Summary: gcc-4.9 does not support features that Poly needs. Disable the tests on that platform. Reviewed By: meyering Differential Revision: D6211674 fbshipit-source-id: 289f029122a45b0f9ec740c62b1faaafb51dcab5
-
- 02 Nov, 2017 5 commits
-
-
Phil Willoughby authored
Summary: This only affects instruction ordering in GCC-compatible compilers to make the value-having branch preferred. Reviewed By: davidtgoldblatt, nbronson, yfeldblum Differential Revision: D6223188 fbshipit-source-id: 57c69b88eda7ee769912874921c45b47ec7a38de
-
Dan Melnic authored
Change kDefaultZeroCopyThreshold to 0 to avoid a regression and avoid a failure while running as not root Summary: Change kDefaultZeroCopyThreshold to 0 to avoid a regression when using a buffer chain that exceeds 32K but each buffer is small. Change the benchmark to set it's own threshold. Also use calloc vs malloc (in the benchmark only) to get around some weird kernel interaction on non zero copy enabled systems - 2 back to back tests report very different results. Reviewed By: djwatson Differential Revision: D6112299 fbshipit-source-id: 3895d3ece2925c4626284ff364495708293edc3e
-
Andrey Ignatov authored
Summary: Now there is no interface to create `IPAddress{,V4,V6}` from a string or `ByteRange` that doesn't throw. All available static methods throw `IPAddressFormatException`. It has a few disadvantages: == 1. It's unsafe == Caller is not forced to catch exception, it's very easy to write `IPAddress(potentiallyInvalidString)` and discover that it can throw when it's already in prod. == 2. It's inconvenient == if caller is aware about exception, (s)he's forced to write `try {} catch` that is inconvenient and leads to code like this: folly::IPAddress taskIp; try { taskIp = folly::IPAddress(kv.second.taskIp); } catch (const folly::IPAddressFormatException&) { // Error handling .. } // Use IP .. == 3. It's expensive == Amended benchmark shows that `IPAddress` constructor is ~10 times slower when a string with invalid IP is passed to it. --- The diff introduces two non-throwing interfaces for all tree flavors of `IPAddress`: `tryFromString()` tries to create IP address from string and returns either corresponding IP address or `enum class IPAddressFormatError` using `folly::Expected`. `tryFromBinary()` does same thing but for `ByteRange` input. The code can be as short as: if (auto maybeIp = IPAddress::tryFromString(ipStr)) { // Use maybeIp.value() .. } The `try` prefix is chosen to be consistent with other interfaces in folly, e.g. `to` and `tryTo`. Reviewed By: yfeldblum Differential Revision: D6211182 fbshipit-source-id: f27cf90997c100a5fd42138e66ff9bb172204c20
-
Yedidya Feldblum authored
Summary: [Folly] Refactor `is_simple_allocator` and callers. * Swap order of template parameters. * Do decaying in the callers instead. * Do a direct invocability test, rather than an indirect test of whether the allocator has a method `destroy` with the expected signature. Reviewed By: ericniebler Differential Revision: D6184062 fbshipit-source-id: aec32e6e323b8c6023b94c258ab2bcddd8c53e09
-
Christopher Dykes authored
Summary: Under C++17's exception specifier rules (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0012r1.html) we need additional specializations to achieve the desired effect. Reviewed By: yfeldblum Differential Revision: D6214359 fbshipit-source-id: a007c2fcea1496bdfe4fdf923b39c1611c6ad9bc
-
- 01 Nov, 2017 8 commits
-
-
Ognjen Dragoljevic authored
Summary: When the key is missing, the standard associative containers throw an exception like `unordered_map::at: key not found`. That's nice, but it would be even better if we would actually know what key is missing. This is not an issue when one is accessing the container directly, but when that access happens several levels deep, such as here within folly formatting logic, we have no way of knowing what key was missing. This poses some difficulties in presenting error to the user. This change makes folly format throw a subclass of `std::out_of_range` exception on a missing key when a string keyed associative container is used for providing parameters. That subclass stores the actual key used so it can be accessed in the exception handler. Existing callers can still catch `std::out_of_range` so they should be unaffected by this change. Reviewed By: ot, yfeldblum Differential Revision: D6202184 fbshipit-source-id: b8a6740aaccc5d8914ad7d099c8b901427f00083
-
Lee Howes authored
Summary: (Note: this ignores all push blocking failures!) Reviewed By: yfeldblum Differential Revision: D6212919 fbshipit-source-id: b066d99e13e97cbab489132bcb91872ed4407f81
-
Yedidya Feldblum authored
Summary: [Folly] Fix unsynchronized accesses in `IOThreadPoolExecutor::getEventBase`. `getEventBase` may be invoked concurrently from two threads - RMWs to `nextThread_` must be synchronized with each other. `getEventBase` may be invoked concurrently with `setNumThreads` - the former's reads of `threadList_.vec_` must be synchronized with the latter's writes to it. Reviewed By: kennyyu Differential Revision: D6206916 fbshipit-source-id: 8bfae158effb5896ab478d0c20310293b037c892
-
Eric Niebler authored
Summary: Address doc criticisms Reviewed By: Orvid Differential Revision: D6210376 fbshipit-source-id: fee11cef1c407b092f891a97f94271a81d3718b8
-
Alisson Gusatti Azzolini authored
Reviewed By: yfeldblum Differential Revision: D6182541 fbshipit-source-id: 31d255819df1f97b13e475903c0627a1ac96b516
-
Maged Michael authored
Summary: Add support for reference counting integrated with the internal structures and operations of the hazard pointer library. The operations are wait-free. The advantages of this approach over combining reference counting with hazard pointers externally are: (1) A long list of linked objects that protected by one reference can all be reclaimed together instead of going through a potentially long series of alternating reclamation and calls to retire() for descendants. (2) Support for iterative deletion as opposed to potential deep recursion of alternating calls to release reference count and object destructors. Reviewed By: djwatson Differential Revision: D6142066 fbshipit-source-id: 02bdfcbd5a2c2d5486d937bb2f9cfb6f192f5e1a
-
Andrii Grynenko authored
Reviewed By: yfeldblum Differential Revision: D6207160 fbshipit-source-id: 57468c9d05cdb3ee6e1d10a3a254a5d1bfddc36f
-
Yedidya Feldblum authored
Summary: [Folly] A macro for creating member-invoke traits. The macro creates a specialized traits container with member types and aliases mimicking `std::invoke_result` and the related traits types and aliases. Reviewed By: aary Differential Revision: D6195087 fbshipit-source-id: 07c2bbab6cccb04dc8ff12e20923351e8f38abfd
-
- 31 Oct, 2017 9 commits
-
-
Lee Howes authored
Adding DeferredExecutor to support deferred execution of tasks on a future returned from an interface. Summary: This adds a DeferredExecutor type that is boostable, which means that it follows the expectation we expect for C++20 that .then and get will trigger boost-blocking behaviour and ensure work makes progress. Unlike discussions for C++ this adds boost blocking to folly only in the specific case of deferring work to run on the caller's executor, to avoid the necessity to pass an executor into a library purely to ensure that finalisation work and future completion occor on a well-defined exewcutor. Reviewed By: yfeldblum Differential Revision: D5828743 fbshipit-source-id: 9a4b69d7deaa33c3cecd6546651b99cc99f0c286
-
Martin Martin authored
Summary: Remove unused field or local var. Reviewed By: terrelln Differential Revision: D6199120 fbshipit-source-id: 616a2b2549c37bcb57d2f8c530b26089f24c2973
-
Teng Qin authored
Summary: In previous discussions, it has been pointed out that `folly::RequestContext::setContext` consumes considerable amount of CPU cycles in production environments. After some investigation, we thought that might be caused by looping over all `RequestData` instances can calling the virtual `onSet` and `onUnset` callback of them. Both the iteration and invoking virtual methods are not cheap. As you can see from this change, most of the derived classes of `RequestData` don't override the `onSet` and `onUnset` methods. Mostly likely they are only used for per-Request tracking. So the natural idea is to skip those instances when iterating and avoid the unnecessary virtual method invoke. I have explored the solution to dynamically examine if the `RequestData` instance added has `onSet` and `onUnset` method overridden. That is possible with GCC's PMF extension, but not [[ http://lists.llvm.org/pipermail/llvm-bugs/2015-July/041164.html | for Clang ]] and probably many other compilers. This definitely won't be very good for `folly`'s probability, even if we gate it by compiler flags. Therefore, this Diff adds the `hasCallback` method to `RequestData` class indicating whether the instance would have `onSet` and `onUnset` overridden. To make it clear to users that they need to correctly override it in order for their `onSet` and `onUnset` callback to work, making it abstract so that user must override it to something and would aware of that. Also made some improvements on documentation. Reviewed By: myreg Differential Revision: D6144049 fbshipit-source-id: 4c9fd72e9efaeb6763d55f63760eaf582ee4839e
-
Teng Qin authored
Summary: Since `folly::RequestContext::get()` returns raw pointer, it could directly use the reference returned by `getStaticContext()` I don't expect this to make much of a difference, just tiny improvements Reviewed By: yfeldblum Differential Revision: D6153353 fbshipit-source-id: 1c41d4fc259aa5cb3e69e50ed24bed1ba9caf6c3
-
Alex Guzman authored
Summary: Adds a function that reads certificates in from a buffer and returns them as a vector of X509 pointers. Reviewed By: yfeldblum Differential Revision: D6133332 fbshipit-source-id: eaaaffcbd4d03f37d9d5b4c99a52b0d968b163ba
-
Yedidya Feldblum authored
Summary: [Folly] Outline most `throw` expressions in `Expected`. They are definitionally cold, but in-line `throw` statements can expand code size more than is desirable. * Inline `throw` statement: https://godbolt.org/g/LPaf7V. * Outline `throw` statement: https://godbolt.org/g/HZBXn6. Reviewed By: Orvid Differential Revision: D6183613 fbshipit-source-id: 28240bb4aa40790d99da783a3c368db81fded124
-
Yedidya Feldblum authored
Summary: [Folly] Remove dep on `Format.h` from `GenerateFingerprintTables.cpp`. `GenerateFingerprintTables.cpp` is a tool used to generate other sources which get built as part of the main library when using the autotools build, so it must be as free of other Folly dependencies as possible. Reviewed By: ot, Orvid Differential Revision: D6183725 fbshipit-source-id: f12b18553c78e085599a5505ae57f12bc0cd44b0
-
Yedidya Feldblum authored
Summary: [Folly] Remove `folly/ContainerTraits.h`. It has some handly helpers, but it is not a real abstraction or utility library. Within Folly, only `folly/Padded.h` uses it, so just rewrite the bit that needs it. Reviewed By: LeeHowes Differential Revision: D6183066 fbshipit-source-id: 24a223fe517d21ff531e0fa80172f15d4f963e51
-
Yedidya Feldblum authored
Summary: [Folly] Move `folly/experimental/AsymmetricMemoryBarrier.h` to `folly/synchronization/AsymmetricMemoryBarrier.h`. Reviewed By: Orvid Differential Revision: D6180676 fbshipit-source-id: f4833318cd365181e202d5f379815e728fba168b
-
- 30 Oct, 2017 8 commits
-
-
Christopher Dykes authored
Summary: By excluding the tools directory, excluding poly, and moving all the tests that have moved around to their new homes. Reviewed By: yfeldblum Differential Revision: D6191644 fbshipit-source-id: bdb39d01a796c1e52257200c0d411a4cb44116ce
-
Felix Leupold authored
Summary: In iOS blocks are initially allocated on the stack and only lazily copied to the heap (e.g when they are assigned to a variable). This means, if you pass a block as an rvalue to a C++ method that keeps moving it around instead of copy assigning it at some point, the block remains on the stack and will get freed once the original method is done (leading to use after free if the block is executed later). This was mitigated by deleting the conversion from ObjC functions to folly functions. Given that all we need is to make sure that the block is allocated on the heap (that is it is an instance of NSMallocBlock rather than NSStackBlock), it seems drastic to ban the conversion. ObjC developers tend to be more familiar with ObjC blocks and will find it convenient to use this conversion. This diff insteads implements the constructor and assignment operator by wrapping the ObjC block in a c++ lambda and capturing it by copy. ARC keeps track of the reference count and automatically releases the block when the lambda is deallocated. Moreover, copy only increase the retain count (instead of doing an actual copy) if the block was already stored on the heap (https://www.cocoawithlove.com/2009/10/how-blocks-are-implemented-and.html section NSMallocBlock never actually copies). Reviewed By: ericniebler Differential Revision: D6109932 fbshipit-source-id: 48bb446d3a66f46affba774cfe1cfb8a60c661de
-
Yedidya Feldblum authored
Summary: [Folly] Simplify `type_t` by lifting the type to be aliased into the structure template parameter list. May also fix curious build failures in some compilers. Reviewed By: akrieger Differential Revision: D6188953 fbshipit-source-id: 96e1c3af9c11959c0899c092933158922efa7e60
-
Lee Howes authored
Summary: To avoid the risk of bugs caused by a Future being cast to a SemiFuture, and losing some of the properties in the process, this splits SemiFuture and Future into unrelated types, sharing a private superclass for code reuse. * Add BasicFuture in futures::detail * Make superclass privately inherited. * Unset executor when constructing SemiFuture from Future. Reviewed By: yfeldblum Differential Revision: D6177780 fbshipit-source-id: dea3116aeec0572bb973c2a561e17785199e86f2
-
Arkady Shapkin authored
Summary: Closes https://github.com/facebook/folly/pull/697 Reviewed By: yfeldblum Differential Revision: D6144274 Pulled By: Orvid fbshipit-source-id: a79a2e36e8fcf271925e97ece2a6adbb3c074216
-
Eric Niebler authored
Summary: `Poly` is a class template that makes it relatively easy to define a type-erasing polymorphic object wrapper. == Type-erasure `std::function` is one example of a type-erasing polymorphic object wrapper; `folly::exception_wrapper` is another. Type-erasure is often used as an alternative to dynamic polymorphism via inheritance-based virtual dispatch. The distinguishing characteristic of type-erasing wrappers are: * **Duck typing:** Types do not need to inherit from an abstract base class in order to be assignable to a type-erasing wrapper; they merely need to satisfy a particular interface. * **Value semantics:** Type-erasing wrappers are objects that can be passed around _by value_. This is in contrast to abstract base classes which must be passed by reference or by pointer or else suffer from _slicing_, which causes them to lose their polymorphic behaviors. Reference semantics make it difficult to reason locally about code. * **Automatic memory management:** When dealing with inheritance-based dynamic polymorphism, it is often necessary to allocate and manage objects on the heap. This leads to a proliferation of `shared_ptr`s and `unique_ptr`s in APIs, complicating their point-of-use. APIs that take type-erasing wrappers, on the other hand, can often store small objects in-situ, with no dynamic allocation. The memory management, if any, is handled for you, and leads to cleaner APIs: consumers of your API don't need to pass `shared_ptr<AbstractBase>`; they can simply pass any object that satisfies the interface you require. (`std::function` is a particularly compelling example of this benefit. Far worse would be an inheritance-based callable solution like `shared_ptr<ICallable<void(int)>>`. ) == Example: Defining a type-erasing function wrapper with `folly::Poly` Defining a polymorphic wrapper with `Poly` is a matter of defining two things: * An *interface*, consisting of public member functions, and * A *mapping* from a concrete type to a set of member function bindings. Below is a (heavily commented) example of a simple implementation of a `std::function`-like polymorphic wrapper. Its interface has only a single member function: `operator()` lang=c++ // An interface for a callable object of a particular signature, Fun // (most interfaces don't need to be templates, FWIW). template <class Fun> struct IFunction; template <class R, class... As> struct IFunction<R(As...)> { // An interface is defined as a nested class template called // Interface that takes a single template parameter, Base, from // which it inherits. template <class Base> struct Interface : Base { // The Interface has public member functions. These become the // public interface of the resulting Poly instantiation. // (Implementation note: Poly<IFunction<Sig>> will publicly // inherit from this struct, which is what gives it the right // member functions.) R operator()(As... as) const { // The definition of each member function in your interface will // always consist of a single line dispatching to folly::call<N>. // The "N" corresponds to the N-th member function in the // list of member function bindings, Members, defined below. // The first argument will always be *this, and the rest of the // arguments should simply forward (if necessary) the member // function's arguments. return static_cast<R>( folly::poly_call<0>(*this, std::forward<As>(as)...)); } }; // The "Members" alias template is a comma-separated list of bound // member functions for a given concrete type "T". The // "FOLLY_POLY_MEMBERS" macro accepts a comma-separated list, and the // (optional) "FOLLY_POLY_MEMBER" macro lets you disambiguate overloads // by explicitly specifying the function signature the target member // function should have. In this case, we require "T" to have a // function call operator with the signature `R(As...) const`. // // If you are using a C++17-compatible compiler, you can do away with // the macros and write this as: // // template <class T> // using Members = // folly::PolyMembers<folly::sig<R(As...) const>(&T::operator())>; // // And since `folly::sig` is only needed for disambiguation in case of // overloads, if you are not concerned about objects with overloaded // function call operators, it could be further simplified to: // // template <class T> using Members = folly::PolyMembers<&T::operator()>; // template <class T> using Members = FOLLY_POLY_MEMBERS( FOLLY_POLY_MEMBER(R(As...) const, &T::operator())); }; // Now that we have defined the interface, we can pass it to Poly to // create our type-erasing wrapper: template <class Fun> using Function = Poly<IFunction<Fun>>; Given the above definition of `Function`, users can now initialize instances of (say) `Function<int(int, int)>` with function objects like `std::plus<int>` and `std::multiplies<int>`, as below: lang=c++ Function<int(int, int)> fun = std::plus<int>{}; assert(5 == fun(2, 3)); fun = std::multiplies<int>{}; assert(6 = fun(2, 3)); == Defining an interface with C++17 With C++17, defining an interface to be used with `Poly` is fairly straightforward. As in the `Function` example above, there is a struct with a nested `Interface` class template and a nested `Members` alias template. No macros are needed with C++17. Imagine we were defining something like a Java-style iterator. If we are using a C++17 compiler, our interface would look something like this: lang=c++ template <class Value> struct IJavaIterator { template <class Base> struct Interface : Base { bool Done() const { return folly::poly_call<0>(*this); } Value Current() const { return folly::poly_call<1>(*this); } void Next() { folly::poly_call<2>(*this); } }; // NOTE: This works in C++17 only: template <class T> using Members = folly::PolyMembers<&T::Done, &T::Current, &T::Next>; }; template <class Value> using JavaIterator = Poly<IJavaIterator>; Given the above definition, `JavaIterator<int>` can be used to hold instances of any type that has `Done`, `Current`, and `Next` member functions with the correct (or compatible) signatures. The presence of overloaded member functions complicates this picture. Often, property members are faked in C++ with `const` and non-`const` member function overloads, like in the interface specified below: lang=c++ struct IIntProperty { template <class Base> struct Interface : Base { int Value() const { return folly::poly_call<0>(*this); } void Value(int i) { folly::poly_call<1>(*this, i); } }; // NOTE: This works in C++17 only: template <class T> using Members = folly::PolyMembers< folly::sig<int() const>(&T::Value), folly::sig<void(int)>(&T::Value)>; }; using IntProperty = Poly<IIntProperty>; Now, any object that has `Value` members of compatible signatures can be assigned to instances of `IntProperty` object. Note how `folly::sig` is used to disambiguate the overloads of `&T::Value`. == Defining an interface with C++14 In C++14, the nice syntax above doesn't work, so we have to resort to macros. The two examples above would look like this: lang=c++ template <class Value> struct IJavaIterator { template <class Base> struct Interface : Base { bool Done() const { return folly::poly_call<0>(*this); } Value Current() const { return folly::poly_call<1>(*this); } void Next() { folly::poly_call<2>(*this); } }; // NOTE: This works in C++14 and C++17: template <class T> using Members = FOLLY_POLY_MEMBERS(&T::Done, &T::Current, &T::Next); }; template <class Value> using JavaIterator = Poly<IJavaIterator>; and lang=c++ struct IIntProperty { template <class Base> struct Interface : Base { int Value() const { return folly::poly_call<0>(*this); } void Value(int i) { return folly::poly_call<1>(*this, i); } }; // NOTE: This works in C++14 and C++17: template <class T> using Members = FOLLY_POLY_MEMBERS( FOLLY_POLY_MEMBER(int() const, &T::Value), FOLLY_POLY_MEMBER(void(int), &T::Value)); }; using IntProperty = Poly<IIntProperty>; == Extending interfaces One typical advantage of inheritance-based solutions to runtime polymorphism is that one polymorphic interface could extend another through inheritance. The same can be accomplished with type-erasing polymorphic wrappers. In the `Poly` library, you can use `folly::PolyExtends` to say that one interface extends another. lang=c++ struct IFoo { template <class Base> struct Interface : Base { void Foo() const { return folly::poly_call<0>(*this); } }; template <class T> using Members = FOLLY_POLY_MEMBERS(&T::Foo); }; // The IFooBar interface extends the IFoo interface struct IFooBar : PolyExtends<IFoo> { template <class Base> struct Interface : Base { void Bar() const { return folly::poly_call<0>(*this); } }; template <class T> using Members = FOLLY_POLY_MEMBERS(&T::Bar); }; using FooBar = Poly<IFooBar>; Given the above definition, instances of type `FooBar` have both `Foo()` and `Bar()` member functions. The sensible conversions exist between a wrapped derived type and a wrapped base type. For instance, assuming `IDerived` extends `IBase` with `Extends`: lang=c++ Poly<IDerived> derived = ...; Poly<IBase> base = derived; // This conversion is OK. As you would expect, there is no conversion in the other direction, and at present there is no `Poly` equivalent to `dynamic_cast`. == Type-erasing polymorphic reference wrappers Sometimes you don't need to own a copy of an object; a reference will do. For that you can use `Poly` to capture a //reference// to an object satisfying an interface rather than the whole object itself. The syntax is intuitive. lang=c++ int i = 42; // Capture a mutable reference to an object of any IRegular type: Poly<IRegular &> intRef = i; assert(42 == folly::poly_cast<int>(intRef)); // Assert that we captured the address of "i": assert(&i == &folly::poly_cast<int>(intRef)); A reference-like `Poly` has a different interface than a value-like `Poly`. Rather than calling member functions with the `obj.fun()` syntax, you would use the `obj->fun()` syntax. This is for the sake of `const`-correctness. For example, consider the code below: lang=c++ struct IFoo { template <class Base> struct Interface { void Foo() { folly::poly_call<0>(*this); } }; template <class T> using Members = folly::PolyMembers<&T::Foo>; }; struct SomeFoo { void Foo() { std::printf("SomeFoo::Foo\n"); } }; SomeFoo foo; Poly<IFoo &> const anyFoo = foo; anyFoo->Foo(); // prints "SomeFoo::Foo" Notice in the above code that the `Foo` member function is non-`const`. Notice also that the `anyFoo` object is `const`. However, since it has captured a non-`const` reference to the `foo` object, it should still be possible to dispatch to the non-`const` `Foo` member function. When instantiated with a reference type, `Poly` has an overloaded `operator->` member that returns a pointer to the `IFoo` interface with the correct `const`-ness, which makes this work. The same mechanism also prevents users from calling non-`const` member functions on `Poly` objects that have captured `const` references, which would violate `const`-correctness. Sensible conversions exist between non-reference and reference `Poly`s. For instance: lang=c++ Poly<IRegular> value = 42; Poly<IRegular &> mutable_ref = value; Poly<IRegular const &> const_ref = mutable_ref; assert(&poly_cast<int>(value) == &poly_cast<int>(mutable_ref)); assert(&poly_cast<int>(value) == &poly_cast<int>(const_ref)); == Non-member functions (C++17) If you wanted to write the interface `ILogicallyNegatable`, which captures all types that can be negated with unary `operator!`, you could do it as we've shown above, by binding `&T::operator!` in the nested `Members` alias template, but that has the problem that it won't work for types that have defined unary `operator!` as a free function. To handle this case, the `Poly` library lets you use a free function instead of a member function when creating a binding. With C++17 you may use a lambda to create a binding, as shown in the example below: lang=c++ struct ILogicallyNegatable { template <class Base> struct Interface : Base { bool operator!() const { return folly::poly_call<0>(*this); } }; template <class T> using Members = folly::PolyMembers< +[](T const& t) -> decltype(!t) { return !t; }>; }; This requires some explanation. The unary `operator+` in front of the lambda is necessary! It causes the lambda to decay to a C-style function pointer, which is one of the types that `folly::PolyMembers` accepts. The `decltype` in the lambda return type is also necessary. Through the magic of SFINAE, it will cause `Poly<ILogicallyNegatable>` to reject any types that don't support unary `operator!`. If you are using a free function to create a binding, the first parameter is implicitly the `this` parameter. It will receive the type-erased object. == Non-member functions (C++14) If you are using a C++14 compiler, the definition of `ILogicallyNegatable` above will fail because lambdas are not `constexpr`. We can get the same effect by writing the lambda as a named free function, as show below: lang=c++ struct ILogicallyNegatable { template <class Base> struct Interface : Base { bool operator!() const { return folly::poly_call<0>(*this); } }; template <class T> static auto negate(T const& t) -> decltype(!t) { return !t; } template <class T> using Members = FOLLY_POLY_MEMBERS(&negate<T>); }; As with the example that uses the lambda in the preceding section, the first parameter is implicitly the `this` parameter. It will receive the type-erased object. == Multi-dispatch What if you want to create an `IAddable` interface for things that can be added? Adding requires //two// objects, both of which are type-erased. This interface requires dispatching on both objects, doing the addition only if the types are the same. For this we make use of the `Self` template alias to define an interface that takes more than one object of the the erased type. lang=c++ struct IAddable { template <class Base> struct Interface : Base { friend Self<Base> operator+(Self<Base> const& a, Self<Base> const& b) const { return folly::poly_call<0>(a, b); } }; template <class T> using Members = folly::PolyMembers< +[](T const& a, T const& b) -> decltype(a + b) { return a + b; }>; }; Given the above defintion of `IAddable` we would be able to do the following: lang=c++ Poly<IAddable> a = 2, b = 3; Poly<IAddable> c = a + b; assert(poly_cast<int>(c) == 5); If `a` and `b` stored objects of different types, a `BadPolyCast` exception would be thrown. == Move-only types If you want to store move-only types, then your interface should extend the `IMoveOnly` interface. == Implementation notes `Poly` will store "small" objects in an internal buffer, avoiding the cost of of dynamic allocations. At present, this size is not configurable; it is pegged at the size of two `double`s. `Poly` objects are always nothrow movable. If you store an object in one that has a potentially throwing move contructor, the object will be stored on the heap, even if it could fit in the internal storage of the `Poly` object. (So be sure to give your objects nothrow move constructors!) `Poly` implements type-erasure in a manner very similar to how the compiler accomplishes virtual dispatch. Every `Poly` object contains a pointer to a table of function pointers. Member function calls involve a double- indirection: once through the v-pointer, and other indirect function call through the function pointer. Reviewed By: yfeldblum Differential Revision: D4897112 fbshipit-source-id: ff1c1156316bfbdd8f2205c4f57932c0067cacac
-
Alexander Pronchenkov authored
Summary: This diff reduces number of memory allocation in folly::ThreadWheelTimekeeper.after() method for a bit. * std::shared_ptr(new T) is replaced with std::make_shared<T>() * folly::Promise is stored by value Reviewed By: yfeldblum Differential Revision: D6172017 fbshipit-source-id: 41bf123f10570c76d64eaac1800b7e65fe381110
-
Murali Vilayannur authored
Summary: A default move constructor/move assignment operator caused a bunch of bugs in my test that was depending on the move constructor to either not close the underlying file descriptor or to ensure that the TemporaryFile object doesn't have a dangling reference to a file descriptor that has already been closed. The current implementation caused both the moved' from and to object to share the same underlying file descriptor and when the former object is destroyed it ends up closing the file descriptor leaving the latter with a dangling file descriptor which could be reused for some other socket(s)/file descriptor by the kernel and ends up causing seg-faults when the latter object is eventually destroyed due to it releasing a file descriptor that now belongs to some other resource. I changed the move constructor/move assignment operator to have the former semantics to not close the underlying file descriptor of the move'd from object (by releasing it and assigning it to the move'd to object). I am not sure if anyone would ever want the alternative semantics because the TemporaryFile object would not be usable without a valid underlying file descriptor Reviewed By: yfeldblum Differential Revision: D6182075 fbshipit-source-id: bc809d704449c1c1182d76cdfa2f7d17b38a719a
-
- 29 Oct, 2017 1 commit
-
-
Yedidya Feldblum authored
Summary: CodeMod: Replace includes of `folly/Hash.h` with `folly/hash/Hash.h`. Reviewed By: luciang Differential Revision: D6156195 fbshipit-source-id: 0941b3c9cf1d17d7cc62595111e506c06ee51236
-