+ // allocation
+ // note that 'allocate' and 'deallocate' are inherited from Allocator
+ T* D_allocate(size_type n) {
+ if (usingStdAllocator::value) {
+ return static_cast<T*>(malloc(n * sizeof(T)));
+ } else {
+ return std::allocator_traits<Allocator>::allocate(*this, n);
+ }
+ }
+
+ void D_deallocate(T* p, size_type n) noexcept {
+ if (usingStdAllocator::value) {
+ free(p);
+ } else {
+ std::allocator_traits<Allocator>::deallocate(*this, p, n);
+ }
+ }
+
+ // helpers
+ void swapData(Impl& other) {
+ std::swap(b_, other.b_);
+ std::swap(e_, other.e_);
+ std::swap(z_, other.z_);
+ }
+
+ // data ops
+ inline void destroy() noexcept {
+ if (b_) {
+ // THIS DISPATCH CODE IS DUPLICATED IN fbvector::D_destroy_range_a.
+ // It has been inlined here for speed. It calls the static fbvector
+ // methods to perform the actual destruction.
+ if (usingStdAllocator::value) {
+ S_destroy_range(b_, e_);
+ } else {
+ S_destroy_range_a(*this, b_, e_);
+ }
+
+ D_deallocate(b_, size_type(z_ - b_));
+ }
+ }
+
+ void init(size_type n) {
+ if (UNLIKELY(n == 0)) {
+ b_ = e_ = z_ = nullptr;
+ } else {
+ size_type sz = folly::goodMallocSize(n * sizeof(T)) / sizeof(T);
+ b_ = D_allocate(sz);
+ e_ = b_;
+ z_ = b_ + sz;
+ }
+ }
+
+ void set(pointer newB, size_type newSize, size_type newCap) {
+ z_ = newB + newCap;
+ e_ = newB + newSize;
+ b_ = newB;
+ }
+
+ void reset(size_type newCap) {
+ destroy();
+ try {
+ init(newCap);
+ } catch (...) {
+ init(0);
+ throw;
+ }
+ }
+ void reset() { // same as reset(0)
+ destroy();
+ b_ = e_ = z_ = nullptr;
+ }
+ } impl_;
+
+ static void swap(Impl& a, Impl& b) {
+ using std::swap;
+ if (!usingStdAllocator::value) {
+ swap<Allocator>(a, b);
+ }
+ a.swapData(b);
+ }
+
+ //===========================================================================
+ //---------------------------------------------------------------------------
+ // types and constants
+ public:
+ typedef T value_type;
+ typedef value_type& reference;
+ typedef const value_type& const_reference;
+ typedef T* iterator;
+ typedef const T* const_iterator;
+ typedef size_t size_type;
+ typedef typename std::make_signed<size_type>::type difference_type;
+ typedef Allocator allocator_type;
+ typedef typename A::pointer pointer;
+ typedef typename A::const_pointer const_pointer;
+ typedef std::reverse_iterator<iterator> reverse_iterator;
+ typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+
+ private:
+ typedef std::integral_constant<bool,
+ IsTriviallyCopyable<T>::value &&
+ sizeof(T) <= 16 // don't force large structures to be passed by value
+ > should_pass_by_value;
+ typedef typename std::conditional<
+ should_pass_by_value::value, T, const T&>::type VT;
+ typedef typename std::conditional<
+ should_pass_by_value::value, T, T&&>::type MT;
+
+ typedef std::integral_constant<bool,
+ std::is_same<Allocator, std::allocator<T>>::value> usingStdAllocator;
+ typedef std::integral_constant<bool,
+ usingStdAllocator::value ||
+ A::propagate_on_container_move_assignment::value> moveIsSwap;
+
+ //===========================================================================
+ //---------------------------------------------------------------------------
+ // allocator helpers
+ private:
+ //---------------------------------------------------------------------------
+ // allocate
+
+ T* M_allocate(size_type n) {
+ return impl_.D_allocate(n);
+ }
+
+ //---------------------------------------------------------------------------
+ // deallocate
+
+ void M_deallocate(T* p, size_type n) noexcept {
+ impl_.D_deallocate(p, n);
+ }
+
+ //---------------------------------------------------------------------------
+ // construct
+
+ // GCC is very sensitive to the exact way that construct is called. For
+ // that reason there are several different specializations of construct.
+
+ template <typename U, typename... Args>
+ void M_construct(U* p, Args&&... args) {
+ if (usingStdAllocator::value) {
+ new (p) U(std::forward<Args>(args)...);
+ } else {
+ std::allocator_traits<Allocator>::construct(
+ impl_, p, std::forward<Args>(args)...);
+ }