Commit 79345bbc authored by Jordan DeLong's avatar Jordan DeLong Committed by Sara Golemon

Make folly::allocator_delete take advantage of EBO

Summary: It wasn't.

Test Plan:
I have a case using this that now passes a static_assert
that it's the same size as the default_deleter version.  I didn't add
a static_assert in folly's tests because right now
is_simple_allocator<int,std::allocator<int>>::value is true (I think
because the tested members come from a base class), which breaks easy
test cases.

Reviewed By: andrei.alexandrescu@fb.com

FB internal diff: D833142
parent 1b68b53f
...@@ -42,15 +42,21 @@ std::unique_ptr<T, Dp> make_unique(Args&&... args) { ...@@ -42,15 +42,21 @@ std::unique_ptr<T, Dp> make_unique(Args&&... args) {
return std::unique_ptr<T, Dp>(new T(std::forward<Args>(args)...)); return std::unique_ptr<T, Dp>(new T(std::forward<Args>(args)...));
} }
/** /*
* Wrap a SimpleAllocator into a STL-compliant allocator. * 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.
*
* A SimpleAllocator must provide two methods:
* *
* The SimpleAllocator must provide two methods:
* void* allocate(size_t size); * void* allocate(size_t size);
* void deallocate(void* ptr); * 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 * which, respectively, allocate a block of size bytes (aligned to the
* allocation can't be satisfied, and free a previously allocated block. * 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 * Note that the following allocator resembles the standard allocator
* quite well: * quite well:
...@@ -67,11 +73,15 @@ std::unique_ptr<T, Dp> make_unique(Args&&... args) { ...@@ -67,11 +73,15 @@ std::unique_ptr<T, Dp> make_unique(Args&&... args) {
* } * }
* }; * };
* *
* But note that if you pass StlAllocator<MallocAllocator,...> to a
* standard container it will be larger due to the contained state
* pointer.
*
* author: Tudor Bosman <tudorb@fb.com> * author: Tudor Bosman <tudorb@fb.com>
*/ */
// This would be so much simpler with std::allocator_traits, but gcc 4.6.2 // 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 Alloc, class T> class StlAllocator; template <class Alloc, class T> class StlAllocator;
template <class Alloc> class StlAllocator<Alloc, void> { template <class Alloc> class StlAllocator<Alloc, void> {
...@@ -177,54 +187,49 @@ class StlAllocator { ...@@ -177,54 +187,49 @@ class StlAllocator {
*/ */
template <typename T, typename Allocator> template <typename T, typename Allocator>
typename Allocator::template rebind<T>::other rebind_allocator( typename Allocator::template rebind<T>::other rebind_allocator(
Allocator const &allocator Allocator const& allocator
) { ) {
return typename Allocator::template rebind<T>::other(allocator); return typename Allocator::template rebind<T>::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 <marcelo@fb.com> * @author: Marcelo Juchem <marcelo@fb.com>
*/ */
// A deleter implementation based on std::default_delete, // Derives from the allocator to take advantage of the empty base
// which uses a custom allocator to free memory // optimization when possible.
template <typename Allocator> template <typename Allocator>
class allocator_delete { class allocator_delete
: private std::remove_reference<Allocator>::type
{
typedef typename std::remove_reference<Allocator>::type allocator_type; typedef typename std::remove_reference<Allocator>::type allocator_type;
public: public:
allocator_delete() = default; allocator_delete() = default;
explicit allocator_delete(const allocator_type& allocator): explicit allocator_delete(const allocator_type& allocator)
allocator_(allocator) : allocator_type(allocator)
{} {}
explicit allocator_delete(allocator_type&& allocator): explicit allocator_delete(allocator_type&& allocator)
allocator_(std::move(allocator)) : allocator_type(std::move(allocator))
{} {}
template <typename U> template <typename U>
allocator_delete(const allocator_delete<U>& other): allocator_delete(const allocator_delete<U>& other)
allocator_(other.get_allocator()) : allocator_type(other.get_allocator())
{} {}
allocator_type& get_allocator() const { allocator_type& get_allocator() const { return *this; }
return allocator_;
}
void operator()(typename allocator_type::pointer p) const { void operator()(typename allocator_type::pointer p) const {
if (!p) { if (!p) return;
return; const_cast<allocator_delete*>(this)->destroy(p);
} const_cast<allocator_delete*>(this)->deallocate(p, 1);
allocator_.destroy(p);
allocator_.deallocate(p, 1);
} }
private:
mutable allocator_type allocator_;
}; };
template <typename T, typename Allocator> template <typename T, typename Allocator>
......
...@@ -25,6 +25,11 @@ ...@@ -25,6 +25,11 @@
using namespace folly; using namespace folly;
static_assert(
is_simple_allocator<int,SysArena>::value,
"SysArena should be a simple allocator"
);
struct global_counter { struct global_counter {
global_counter(): count_(0) {} global_counter(): count_(0) {}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment