X-Git-Url: http://plrg.eecs.uci.edu/git/?p=folly.git;a=blobdiff_plain;f=folly%2FMemory.h;h=ce0ff05d3290605f6dd08ba28ad2caae4aca47b4;hp=09f10f36b351ae79c2aee496b20628c3c8a30304;hb=ba4282e472390a2d9ba23672b8844b9f23db0916;hpb=244a89966aa1bead86e9c2fb1263bbe8d837be28 diff --git a/folly/Memory.h b/folly/Memory.h index 09f10f36..ce0ff05d 100644 --- a/folly/Memory.h +++ b/folly/Memory.h @@ -1,5 +1,5 @@ /* - * Copyright 2013 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. @@ -14,18 +14,19 @@ * limitations under the License. */ -#ifndef FOLLY_MEMORY_H_ -#define FOLLY_MEMORY_H_ +#pragma once -#include "folly/Traits.h" +#include +#include -#include -#include -#include +#include +#include #include +#include +#include #include - -#include +#include +#include namespace folly { @@ -34,43 +35,163 @@ namespace folly { * we have std::make_unique(). * * @author Louis Brandy (ldbrandy@fb.com) + * @author Xu Ning (xning@fb.com) */ -template -std::unique_ptr make_unique(Args&&... args) { +#if __cplusplus >= 201402L || __cpp_lib_make_unique >= 201304L || \ + (__ANDROID__ && __cplusplus >= 201300L) || _MSC_VER >= 1900 + +/* using override */ using std::make_unique; + +#else + +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 +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 +typename std::enable_if< + std::extent::value != 0, std::unique_ptr>::type +make_unique(Args&&...) = delete; + +#endif + /** - * Wrap a SimpleAllocator into a STL-compliant allocator. + * static_function_deleter + * + * So you can write this: + * + * using RSA_deleter = folly::static_function_deleter; + * auto rsa = std::unique_ptr(RSA_new()); + * RSA_generate_key_ex(rsa.get(), bits, exponent, nullptr); + * rsa = nullptr; // calls RSA_free(rsa.get()) + * + * This would be sweet as well for BIO, but unfortunately BIO_free has signature + * int(BIO*) while we require signature void(BIO*). So you would need to make a + * wrapper for it: + * + * inline void BIO_free_fb(BIO* bio) { CHECK_EQ(1, BIO_free(bio)); } + * using BIO_deleter = folly::static_function_deleter; + * auto buf = std::unique_ptr(BIO_new(BIO_s_mem())); + * buf = nullptr; // calls BIO_free(buf.get()) + */ + +template +struct static_function_deleter { + void operator()(T* t) const { + f(t); + } +}; + +/** + * to_shared_ptr + * + * Convert unique_ptr to shared_ptr without specifying the template type + * parameter and letting the compiler deduce it. + * + * So you can write this: + * + * auto sptr = to_shared_ptr(getSomethingUnique()); + * + * Instead of this: + * + * auto sptr = shared_ptr(getSomethingUnique()); + * + * Useful when `T` is long, such as: + * + * using T = foobar::FooBarAsyncClient; + */ +template +std::shared_ptr to_shared_ptr(std::unique_ptr&& ptr) { + return std::shared_ptr(std::move(ptr)); +} + +/** + * 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)); +} + +/** + * A SimpleAllocator must provide two methods: * - * The SimpleAllocator must provide two methods: * void* allocate(size_t size); * void deallocate(void* ptr); - * which, respectively, allocate a block of size bytes (aligned to the maximum - * alignment required on your system), throwing std::bad_alloc if the - * allocation can't be satisfied, and free a previously allocated block. - * - * Note that the following allocator resembles the standard allocator - * quite well: - * - * class MallocAllocator { - * public: - * void* allocate(size_t size) { - * void* p = malloc(size); - * if (!p) throw std::bad_alloc(); - * return p; - * } - * void deallocate(void* p) { - * free(p); - * } - * }; * - * author: Tudor Bosman + * which, respectively, allocate a block of size bytes (aligned to the + * maximum alignment required on your system), throwing std::bad_alloc + * if the allocation can't be satisfied, and free a previously + * allocated block. + * + * SysAlloc resembles the standard allocator. + */ +class SysAlloc { + public: + void* allocate(size_t size) { + void* p = ::malloc(size); + if (!p) { + throw std::bad_alloc(); + } + return p; + } + void deallocate(void* p) { + ::free(p); + } +}; + +/** + * StlAllocator wraps a SimpleAllocator into a STL-compliant + * allocator, maintaining an instance pointer to the simple allocator + * object. The underlying SimpleAllocator object must outlive all + * instances of StlAllocator using it. + * + * But note that if you pass StlAllocator to a + * standard container it will be larger due to the contained state + * pointer. + * + * @author: Tudor Bosman */ // This would be so much simpler with std::allocator_traits, but gcc 4.6.2 -// doesn't support it +// doesn't support it. template class StlAllocator; template class StlAllocator { @@ -78,9 +199,28 @@ template class StlAllocator { typedef void value_type; typedef void* pointer; typedef const void* const_pointer; + + StlAllocator() : alloc_(nullptr) { } + explicit StlAllocator(Alloc* a) : alloc_(a) { } + + Alloc* alloc() const { + return alloc_; + } + template struct rebind { typedef StlAllocator other; }; + + bool operator!=(const StlAllocator& other) const { + return alloc_ != other.alloc_; + } + + bool operator==(const StlAllocator& other) const { + return alloc_ == other.alloc_; + } + + private: + Alloc* alloc_; }; template @@ -96,18 +236,16 @@ class StlAllocator { typedef size_t size_type; StlAllocator() : alloc_(nullptr) { } - explicit StlAllocator(Alloc* alloc) : alloc_(alloc) { } + explicit StlAllocator(Alloc* a) : alloc_(a) { } template StlAllocator(const StlAllocator& other) : alloc_(other.alloc()) { } - T* allocate(size_t n, const void* hint = nullptr) { + T* allocate(size_t n, const void* /* hint */ = nullptr) { return static_cast(alloc_->allocate(n * sizeof(T))); } - void deallocate(T* p, size_t n) { - alloc_->deallocate(p); - } + void deallocate(T* p, size_t /* n */) { alloc_->deallocate(p); } size_t max_size() const { return std::numeric_limits::max(); @@ -150,69 +288,95 @@ class StlAllocator { Alloc* alloc_; }; +/** + * Helper function to obtain rebound allocators + * + * @author: Marcelo Juchem + */ +template +typename Allocator::template rebind::other rebind_allocator( + Allocator const& allocator +) { + return typename Allocator::template rebind::other(allocator); +} + /* - * Helper classes/functions for creating a unique_ptr using a custom allocator + * Helper classes/functions for creating a unique_ptr using a custom + * allocator. * * @author: Marcelo Juchem */ -// A deleter implementation based on std::default_delete, -// which uses a custom allocator to free memory +// Derives from the allocator to take advantage of the empty base +// optimization when possible. template -class allocator_delete { +class allocator_delete + : private std::remove_reference::type +{ typedef typename std::remove_reference::type allocator_type; -public: + public: + typedef typename Allocator::pointer pointer; + allocator_delete() = default; - explicit allocator_delete(const allocator_type& allocator): - allocator_(allocator) + explicit allocator_delete(const allocator_type& allocator) + : allocator_type(allocator) {} - explicit allocator_delete(allocator_type&& allocator): - allocator_(std::move(allocator)) + explicit allocator_delete(allocator_type&& allocator) + : allocator_type(std::move(allocator)) {} template - allocator_delete(const allocator_delete& other): - allocator_(other.get_allocator()) + allocator_delete(const allocator_delete& other) + : allocator_type(other.get_allocator()) {} allocator_type& get_allocator() const { - return allocator_; + return *const_cast(this); } - void operator()(typename allocator_type::pointer p) const { + void operator()(pointer p) const { if (!p) { return; } - - allocator_.destroy(p); - allocator_.deallocate(p, 1); + const_cast(this)->destroy(p); + const_cast(this)->deallocate(p, 1); } - -private: - mutable allocator_type allocator_; }; -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); + +} // namespace detail -public: - constexpr static bool value = !has_destroy::value - && !has_destroy::value; +template +using is_simple_allocator = + Negation>; + +template +struct as_stl_allocator { + typedef typename std::conditional< + 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 + >, + typename std::remove_reference::type + >::type type; }; 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 @@ -226,18 +390,31 @@ 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); } +/** + * AllocatorUniquePtr: a unique_ptr that supports both STL-style + * allocators and SimpleAllocator + * + * @author: Marcelo Juchem + */ + template 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 @@ -245,6 +422,13 @@ struct AllocatorUniquePtr { > type; }; +/** + * Functions to allocate a unique_ptr / shared_ptr, supporting both + * STL-style allocators and SimpleAllocator, analog to std::allocate_shared + * + * @author: Marcelo Juchem + */ + template typename AllocatorUniquePtr::type allocate_unique( Allocator&& allocator, Args&&... args @@ -274,6 +458,99 @@ std::shared_ptr allocate_shared(Allocator&& allocator, Args&&... args) { ); } -} // namespace folly +/** + * IsArenaAllocator::value describes whether SimpleAllocator has + * no-op deallocate(). + */ +template struct IsArenaAllocator : std::false_type { }; + +/* + * 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 -#endif /* FOLLY_MEMORY_H_ */ +} // namespace folly