X-Git-Url: http://plrg.eecs.uci.edu/git/?p=folly.git;a=blobdiff_plain;f=folly%2FMemory.h;h=ce0ff05d3290605f6dd08ba28ad2caae4aca47b4;hp=442dd4f688445e554eecaa41fecdbcde6645effc;hb=3764ca2b6e84a6a3614943b7df00646677dc1bea;hpb=6848287d30fcbb18bb277ea85001e8864e28ea9e diff --git a/folly/Memory.h b/folly/Memory.h index 442dd4f6..ce0ff05d 100644 --- a/folly/Memory.h +++ b/folly/Memory.h @@ -1,5 +1,5 @@ /* - * Copyright 2016 Facebook, Inc. + * Copyright 2017 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,6 +17,7 @@ #pragma once #include +#include #include #include @@ -24,6 +25,7 @@ #include #include #include +#include #include namespace folly { @@ -36,29 +38,28 @@ namespace folly { * @author Xu Ning (xning@fb.com) */ -#if __cplusplus >= 201402L || \ - (defined __cpp_lib_make_unique && __cpp_lib_make_unique >= 201304L) || \ - (defined(_MSC_VER) && _MSC_VER >= 1900) +#if __cplusplus >= 201402L || __cpp_lib_make_unique >= 201304L || \ + (__ANDROID__ && __cplusplus >= 201300L) || _MSC_VER >= 1900 /* using override */ using std::make_unique; #else -template +template typename std::enable_if::value, std::unique_ptr>::type make_unique(Args&&... args) { return std::unique_ptr(new T(std::forward(args)...)); } // Allows 'make_unique(10)'. (N3690 s20.9.1.4 p3-4) -template +template typename std::enable_if::value, std::unique_ptr>::type make_unique(const size_t n) { return std::unique_ptr(new typename std::remove_extent::type[n]()); } // Disallows 'make_unique()'. (N3690 s20.9.1.4 p5) -template +template typename std::enable_if< std::extent::value != 0, std::unique_ptr>::type make_unique(Args&&...) = delete; @@ -108,14 +109,42 @@ struct static_function_deleter { * * Useful when `T` is long, such as: * - * using T = foobar::cpp2::FooBarServiceAsyncClient; + * using T = foobar::FooBarAsyncClient; */ template std::shared_ptr to_shared_ptr(std::unique_ptr&& ptr) { return std::shared_ptr(std::move(ptr)); } -using SysBufferDeleter = static_function_deleter; +/** + * to_weak_ptr + * + * Make a weak_ptr and return it from a shared_ptr without specifying the + * template type parameter and letting the compiler deduce it. + * + * So you can write this: + * + * auto wptr = to_weak_ptr(getSomethingShared()); + * + * Instead of this: + * + * auto wptr = weak_ptr(getSomethingShared()); + * + * Useful when `T` is long, such as: + * + * using T = foobar::FooBarAsyncClient; + */ +template +std::weak_ptr to_weak_ptr(const std::shared_ptr& ptr) { + return std::weak_ptr(ptr); +} + +struct SysBufferDeleter { + void operator()(void* p) const { + ::free(p); + } +}; + using SysBufferUniquePtr = std::unique_ptr; inline SysBufferUniquePtr allocate_sys_buffer(size_t size) { return SysBufferUniquePtr(::malloc(size)); @@ -138,7 +167,9 @@ class SysAlloc { public: void* allocate(size_t size) { void* p = ::malloc(size); - if (!p) throw std::bad_alloc(); + if (!p) { + throw std::bad_alloc(); + } return p; } void deallocate(void* p) { @@ -284,7 +315,7 @@ class allocator_delete { typedef typename std::remove_reference::type allocator_type; -public: + public: typedef typename Allocator::pointer pointer; allocator_delete() = default; @@ -307,31 +338,31 @@ public: } void operator()(pointer p) const { - if (!p) return; + if (!p) { + return; + } const_cast(this)->destroy(p); const_cast(this)->deallocate(p, 1); } }; -template -class is_simple_allocator { - FOLLY_CREATE_HAS_MEMBER_FN_TRAITS(has_destroy, destroy); +namespace detail { - typedef typename std::remove_const< - typename std::remove_reference::type - >::type allocator; - typedef typename std::remove_reference::type value_type; - typedef value_type* pointer; +FOLLY_CREATE_MEMBER_INVOKE_TRAITS(destroy_invoke_traits, destroy); -public: - constexpr static bool value = !has_destroy::value - && !has_destroy::value; -}; +} // namespace detail + +template +using is_simple_allocator = + Negation>; template struct as_stl_allocator { typedef typename std::conditional< - is_simple_allocator::value, + is_simple_allocator< + typename std::remove_reference::type, + typename std::remove_reference::type + >::value, folly::StlAllocator< typename std::remove_reference::type, typename std::remove_reference::type @@ -342,7 +373,10 @@ struct as_stl_allocator { template typename std::enable_if< - is_simple_allocator::value, + is_simple_allocator< + typename std::remove_reference::type, + typename std::remove_reference::type + >::value, folly::StlAllocator< typename std::remove_reference::type, typename std::remove_reference::type @@ -356,7 +390,10 @@ typename std::enable_if< template typename std::enable_if< - !is_simple_allocator::value, + !is_simple_allocator< + typename std::remove_reference::type, + typename std::remove_reference::type + >::value, typename std::remove_reference::type >::type make_stl_allocator(Allocator&& allocator) { return std::move(allocator); @@ -374,7 +411,10 @@ struct AllocatorUniquePtr { typedef std::unique_ptr::value, + is_simple_allocator< + typename std::remove_reference::type, + typename std::remove_reference::type + >::value, folly::StlAllocator::type, T>, typename std::remove_reference::type >::type @@ -424,4 +464,93 @@ std::shared_ptr allocate_shared(Allocator&& allocator, Args&&... args) { */ template struct IsArenaAllocator : std::false_type { }; -} // namespace folly +/* + * folly::enable_shared_from_this + * + * To be removed once C++17 becomes a minimum requirement for folly. + */ +#if __cplusplus >= 201700L || \ + __cpp_lib_enable_shared_from_this >= 201603L + +// Guaranteed to have std::enable_shared_from_this::weak_from_this(). Prefer +// type alias over our own class. +/* using override */ using std::enable_shared_from_this; + +#else + +/** + * Extends std::enabled_shared_from_this. Offers weak_from_this() to pre-C++17 + * code. Use as drop-in replacement for std::enable_shared_from_this. + * + * C++14 has no direct means of creating a std::weak_ptr, one must always + * create a (temporary) std::shared_ptr first. C++17 adds weak_from_this() to + * std::enable_shared_from_this to avoid that overhead. Alas code that must + * compile under different language versions cannot call + * std::enable_shared_from_this::weak_from_this() directly. Hence this class. + * + * @example + * class MyClass : public folly::enable_shared_from_this {}; + * + * int main() { + * std::shared_ptr sp = std::make_shared(); + * std::weak_ptr wp = sp->weak_from_this(); + * } + */ +template +class enable_shared_from_this : public std::enable_shared_from_this { + public: + constexpr enable_shared_from_this() noexcept = default; + + std::weak_ptr weak_from_this() noexcept { + return weak_from_this_(this); + } + + std::weak_ptr weak_from_this() const noexcept { + return weak_from_this_(this); + } + + private: + // Uses SFINAE to detect and call + // std::enable_shared_from_this::weak_from_this() if available. Falls + // back to std::enable_shared_from_this::shared_from_this() otherwise. + template + auto weak_from_this_(std::enable_shared_from_this* base_ptr) + noexcept -> decltype(base_ptr->weak_from_this()) { + return base_ptr->weak_from_this(); + } + + template + auto weak_from_this_(std::enable_shared_from_this const* base_ptr) + const noexcept -> decltype(base_ptr->weak_from_this()) { + return base_ptr->weak_from_this(); + } + + template + std::weak_ptr weak_from_this_(...) noexcept { + try { + return this->shared_from_this(); + } catch (std::bad_weak_ptr const&) { + // C++17 requires that weak_from_this() on an object not owned by a + // shared_ptr returns an empty weak_ptr. Sadly, in C++14, + // shared_from_this() on such an object is undefined behavior, and there + // is nothing we can do to detect and handle the situation in a portable + // manner. But in case a compiler is nice enough to implement C++17 + // semantics of shared_from_this() and throws a bad_weak_ptr, we catch it + // and return an empty weak_ptr. + return std::weak_ptr{}; + } + } + + template + std::weak_ptr weak_from_this_(...) const noexcept { + try { + return this->shared_from_this(); + } catch (std::bad_weak_ptr const&) { + return std::weak_ptr{}; + } + } +}; + +#endif + +} // namespace folly