From: Louis Brandy Date: Wed, 20 Mar 2013 21:54:45 +0000 (-0700) Subject: StlAllocator.h + MakeUnique.h -> Memory.h X-Git-Tag: v0.22.0~1030 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=244a89966aa1bead86e9c2fb1263bbe8d837be28;p=folly.git StlAllocator.h + MakeUnique.h -> Memory.h Summary: Go with the fat header approach. Merge these two into Memory.h. We could, potentially, include Malloc.h as well, but it fbstring header uses the once define for some special magic. Leave it alone for now. An alternate approach might be moving all three leaner headers into a `memory/` subdir with `folly/Memory.h` just #including the three. Test Plan: fbconfig folly/tests && fbmake runtests_opt Reviewed By: delong.j@fb.com FB internal diff: D745873 --- diff --git a/folly/Memory.h b/folly/Memory.h new file mode 100644 index 00000000..09f10f36 --- /dev/null +++ b/folly/Memory.h @@ -0,0 +1,279 @@ +/* + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FOLLY_MEMORY_H_ +#define FOLLY_MEMORY_H_ + +#include "folly/Traits.h" + +#include +#include +#include +#include +#include + +#include + +namespace folly { + +/** + * For exception safety and consistency with make_shared. Erase me when + * we have std::make_unique(). + * + * @author Louis Brandy (ldbrandy@fb.com) + */ + +template +std::unique_ptr make_unique(Args&&... args) { + return std::unique_ptr(new T(std::forward(args)...)); +} + +/** + * Wrap a SimpleAllocator into a STL-compliant allocator. + * + * 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 + */ + +// This would be so much simpler with std::allocator_traits, but gcc 4.6.2 +// doesn't support it +template class StlAllocator; + +template class StlAllocator { + public: + typedef void value_type; + typedef void* pointer; + typedef const void* const_pointer; + template struct rebind { + typedef StlAllocator other; + }; +}; + +template +class StlAllocator { + public: + typedef T value_type; + typedef T* pointer; + typedef const T* const_pointer; + typedef T& reference; + typedef const T& const_reference; + + typedef ptrdiff_t difference_type; + typedef size_t size_type; + + StlAllocator() : alloc_(nullptr) { } + explicit StlAllocator(Alloc* alloc) : alloc_(alloc) { } + + template StlAllocator(const StlAllocator& other) + : alloc_(other.alloc()) { } + + 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); + } + + size_t max_size() const { + return std::numeric_limits::max(); + } + + T* address(T& x) const { + return std::addressof(x); + } + + const T* address(const T& x) const { + return std::addressof(x); + } + + template + void construct(T* p, Args&&... args) { + new (p) T(std::forward(args)...); + } + + void destroy(T* p) { + p->~T(); + } + + 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_; +}; + +/* + * 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 +template +class allocator_delete { + typedef typename std::remove_reference::type allocator_type; + +public: + allocator_delete() = default; + + explicit allocator_delete(const allocator_type& allocator): + allocator_(allocator) + {} + + explicit allocator_delete(allocator_type&& allocator): + allocator_(std::move(allocator)) + {} + + template + allocator_delete(const allocator_delete& other): + allocator_(other.get_allocator()) + {} + + allocator_type& get_allocator() const { + return allocator_; + } + + void operator()(typename allocator_type::pointer p) const { + if (!p) { + return; + } + + allocator_.destroy(p); + allocator_.deallocate(p, 1); + } + +private: + mutable allocator_type allocator_; +}; + +template +class is_simple_allocator { + FOLLY_CREATE_HAS_MEMBER_FN_TRAITS(has_destroy, destroy); + + typedef typename std::remove_const< + typename std::remove_reference::type + >::type allocator; + typedef typename std::remove_reference::type value_type; + typedef value_type* pointer; + +public: + constexpr static bool value = !has_destroy::value + && !has_destroy::value; +}; + +template +typename std::enable_if< + is_simple_allocator::value, + folly::StlAllocator< + typename std::remove_reference::type, + typename std::remove_reference::type + > +>::type make_stl_allocator(Allocator&& allocator) { + return folly::StlAllocator< + typename std::remove_reference::type, + typename std::remove_reference::type + >(&allocator); +} + +template +typename std::enable_if< + !is_simple_allocator::value, + typename std::remove_reference::type +>::type make_stl_allocator(Allocator&& allocator) { + return std::move(allocator); +} + +template +struct AllocatorUniquePtr { + typedef std::unique_ptr::value, + folly::StlAllocator::type, T>, + typename std::remove_reference::type + >::type + > + > type; +}; + +template +typename AllocatorUniquePtr::type allocate_unique( + Allocator&& allocator, Args&&... args +) { + auto stlAllocator = folly::make_stl_allocator( + std::forward(allocator) + ); + auto p = stlAllocator.allocate(1); + + try { + stlAllocator.construct(p, std::forward(args)...); + + return {p, + folly::allocator_delete(std::move(stlAllocator)) + }; + } catch (...) { + stlAllocator.deallocate(p, 1); + throw; + } +} + +template +std::shared_ptr allocate_shared(Allocator&& allocator, Args&&... args) { + return std::allocate_shared( + folly::make_stl_allocator(std::forward(allocator)), + std::forward(args)... + ); +} + +} // namespace folly + +#endif /* FOLLY_MEMORY_H_ */ diff --git a/folly/test/ArenaSmartPtrTest.cpp b/folly/test/ArenaSmartPtrTest.cpp index 56534116..54b8262a 100644 --- a/folly/test/ArenaSmartPtrTest.cpp +++ b/folly/test/ArenaSmartPtrTest.cpp @@ -18,7 +18,7 @@ * @author: Marcelo Juchem */ -#include "folly/StlAllocator.h" +#include "folly/Memory.h" #include "folly/Arena.h" #include diff --git a/folly/test/ArenaTest.cpp b/folly/test/ArenaTest.cpp index 488b493f..493cd148 100644 --- a/folly/test/ArenaTest.cpp +++ b/folly/test/ArenaTest.cpp @@ -15,7 +15,7 @@ */ #include "folly/Arena.h" -#include "folly/StlAllocator.h" +#include "folly/Memory.h" #include #include diff --git a/folly/test/ThreadCachedArenaTest.cpp b/folly/test/ThreadCachedArenaTest.cpp index 21d222ea..bc720ed0 100644 --- a/folly/test/ThreadCachedArenaTest.cpp +++ b/folly/test/ThreadCachedArenaTest.cpp @@ -15,7 +15,7 @@ */ #include "folly/ThreadCachedArena.h" -#include "folly/StlAllocator.h" +#include "folly/Memory.h" #include #include