X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=folly%2FMemory.h;h=70bc451cb2221bad6ef984f4018613bdc4859135;hb=0f383c3789e8ca0caa5b086fde1a28af44e0a450;hp=e4db242ba22edc24065a249e67bc5416f47944b3;hpb=36b366265da55fc26201870d1c5c2477ccc12600;p=folly.git diff --git a/folly/Memory.h b/folly/Memory.h index e4db242b..70bc451c 100644 --- a/folly/Memory.h +++ b/folly/Memory.h @@ -1,5 +1,5 @@ /* - * Copyright 2013 Facebook, Inc. + * Copyright 2015 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,15 +17,15 @@ #ifndef FOLLY_MEMORY_H_ #define FOLLY_MEMORY_H_ -#include "folly/Traits.h" +#include -#include -#include -#include +#include +#include #include +#include +#include #include - -#include +#include namespace folly { @@ -34,43 +34,91 @@ 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) { - return std::unique_ptr(new T(std::forward(args)...)); +template, typename... Args> +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... Args> +typename std::enable_if< + std::extent::value != 0, std::unique_ptr>::type +make_unique(Args&&...) = delete; + +/** + * 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::cpp2::FooBarServiceAsyncClient; + */ +template +std::shared_ptr to_shared_ptr(std::unique_ptr&& ptr) { + return std::shared_ptr(std::move(ptr)); } /** - * Wrap a SimpleAllocator into a STL-compliant allocator. + * 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: + * 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. * - * 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); - * } - * }; + * But note that if you pass StlAllocator to a + * standard container it will be larger due to the contained state + * pointer. * - * author: Tudor Bosman + * @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 { @@ -80,7 +128,7 @@ template class StlAllocator { typedef const void* const_pointer; StlAllocator() : alloc_(nullptr) { } - explicit StlAllocator(Alloc* alloc) : alloc_(alloc) { } + explicit StlAllocator(Alloc* a) : alloc_(a) { } Alloc* alloc() const { return alloc_; @@ -115,7 +163,7 @@ 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()) { } @@ -169,49 +217,60 @@ 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: + 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 { - if (!p) { - return; - } - - allocator_.destroy(p); - allocator_.deallocate(p, 1); + void operator()(pointer p) const { + if (!p) return; + const_cast(this)->destroy(p); + const_cast(this)->deallocate(p, 1); } - -private: - mutable allocator_type allocator_; }; template @@ -319,6 +378,12 @@ std::shared_ptr allocate_shared(Allocator&& allocator, Args&&... args) { ); } +/** + * IsArenaAllocator::value describes whether SimpleAllocator has + * no-op deallocate(). + */ +template struct IsArenaAllocator : std::false_type { }; + } // namespace folly #endif /* FOLLY_MEMORY_H_ */