X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=folly%2FFBVector.h;h=036882a4930414a1c8def4cafae5785c66454720;hb=a5f4fbe06a9962f5f230960fb418cb2d5ecb88b2;hp=a85f7570e55ade8f0f17b95fe17ac3b762bdecd1;hpb=52fceaf485e63d459d2df5858ffdbeaafe851dbf;p=folly.git diff --git a/folly/FBVector.h b/folly/FBVector.h index a85f7570..036882a4 100644 --- a/folly/FBVector.h +++ b/folly/FBVector.h @@ -1,5 +1,5 @@ /* - * Copyright 2014 Facebook, Inc. + * Copyright 2016 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,8 +22,7 @@ * optimizations for use with relocatable types and jemalloc. */ -#ifndef FOLLY_FBVECTOR_H -#define FOLLY_FBVECTOR_H +#pragma once //============================================================================= // headers @@ -36,120 +35,21 @@ #include #include -#include "folly/Likely.h" -#include "folly/Malloc.h" -#include "folly/Traits.h" +#include +#include +#include +#include #include -// some files expected these from FBVector -#include -#include "folly/Foreach.h" -#include -#include - //============================================================================= // forward declaration -#ifdef FOLLY_BENCHMARK_USE_NS_IFOLLY -namespace Ifolly { -#else namespace folly { -#endif template > class fbvector; } -//============================================================================= -// compatibility - -#if __GNUC__ < 4 || __GNUC__ == 4 && __GNUC_MINOR__ < 7 -// PLEASE UPGRADE TO GCC 4.7 or above -#define FOLLY_FBV_COMPATIBILITY_MODE -#endif - -#ifndef FOLLY_FBV_COMPATIBILITY_MODE - -namespace folly { - -template -struct fbv_allocator_traits - : std::allocator_traits {}; - -template -struct fbv_is_nothrow_move_constructible - : std::is_nothrow_move_constructible {}; - -template -struct fbv_is_nothrow_constructible - : std::is_nothrow_constructible {}; - -template -struct fbv_is_copy_constructible - : std::is_copy_constructible {}; - -} - -#else - -namespace folly { - -template -struct fbv_allocator_traits { - static_assert(sizeof(A) == 0, - "If you want to use a custom allocator, then you must upgrade to gcc 4.7"); - // for some old code that deals with this case, see D566719, diff number 10. -}; - -template -struct fbv_allocator_traits> { - typedef std::allocator A; - - typedef T* pointer; - typedef const T* const_pointer; - typedef size_t size_type; - - typedef std::false_type propagate_on_container_copy_assignment; - typedef std::false_type propagate_on_container_move_assignment; - typedef std::false_type propagate_on_container_swap; - - static pointer allocate(A& a, size_type n) { - return static_cast(::operator new(n * sizeof(T))); - } - static void deallocate(A& a, pointer p, size_type n) { - ::operator delete(p); - } - - template - static void construct(A& a, R* p, Args&&... args) { - new (p) R(std::forward(args)...); - } - template - static void destroy(A& a, R* p) { - p->~R(); - } - - static A select_on_container_copy_construction(const A& a) { - return a; - } -}; - -template -struct fbv_is_nothrow_move_constructible - : std::false_type {}; - -template -struct fbv_is_nothrow_constructible - : std::false_type {}; - -template -struct fbv_is_copy_constructible - : std::true_type {}; - -} - -#endif - //============================================================================= // unrolling @@ -170,11 +70,7 @@ struct fbv_is_copy_constructible // // /////////////////////////////////////////////////////////////////////////////// -#ifdef FOLLY_BENCHMARK_USE_NS_IFOLLY -namespace Ifolly { -#else namespace folly { -#endif template class fbvector : private boost::totally_ordered> { @@ -184,7 +80,7 @@ class fbvector : private boost::totally_ordered> { // implementation private: - typedef folly::fbv_allocator_traits A; + typedef std::allocator_traits A; struct Impl : public Allocator { // typedefs @@ -196,16 +92,16 @@ private: // constructors Impl() : Allocator(), b_(nullptr), e_(nullptr), z_(nullptr) {} - Impl(const Allocator& a) + /* implicit */ Impl(const Allocator& a) : Allocator(a), b_(nullptr), e_(nullptr), z_(nullptr) {} - Impl(Allocator&& a) + /* implicit */ Impl(Allocator&& a) : Allocator(std::move(a)), b_(nullptr), e_(nullptr), z_(nullptr) {} - Impl(size_type n, const Allocator& a = Allocator()) + /* implicit */ Impl(size_type n, const Allocator& a = Allocator()) : Allocator(a) { init(n); } - Impl(Impl&& other) + Impl(Impl&& other) noexcept : Allocator(std::move(other)), b_(other.b_), e_(other.e_), z_(other.z_) { other.b_ = other.e_ = other.z_ = nullptr; } @@ -221,7 +117,7 @@ private: if (usingStdAllocator::value) { return static_cast(malloc(n * sizeof(T))); } else { - return folly::fbv_allocator_traits::allocate(*this, n); + return std::allocator_traits::allocate(*this, n); } } @@ -229,7 +125,7 @@ private: if (usingStdAllocator::value) { free(p); } else { - folly::fbv_allocator_traits::deallocate(*this, p, n); + std::allocator_traits::deallocate(*this, p, n); } } @@ -267,8 +163,7 @@ private: } } - void - set(pointer newB, size_type newSize, size_type newCap) { + void set(pointer newB, size_type newSize, size_type newCap) { z_ = newB + newCap; e_ = newB + newSize; b_ = newB; @@ -360,7 +255,7 @@ private: if (usingStdAllocator::value) { new (p) U(std::forward(args)...); } else { - folly::fbv_allocator_traits::construct( + std::allocator_traits::construct( impl_, p, std::forward(args)...); } } @@ -372,7 +267,7 @@ private: template static void S_construct_a(Allocator& a, U* p, Args&&... args) { - folly::fbv_allocator_traits::construct( + std::allocator_traits::construct( a, p, std::forward(args)...); } @@ -384,7 +279,7 @@ private: if (usingStdAllocator::value) { *p = arg; } else { - folly::fbv_allocator_traits::construct(impl_, p, arg); + std::allocator_traits::construct(impl_, p, arg); } } @@ -397,7 +292,7 @@ private: template ::value>::type> static void S_construct_a(Allocator& a, U* p, U arg) { - folly::fbv_allocator_traits::construct(a, p, arg); + std::allocator_traits::construct(a, p, arg); } // const& optimization @@ -407,7 +302,7 @@ private: if (usingStdAllocator::value) { new (p) U(value); } else { - folly::fbv_allocator_traits::construct(impl_, p, value); + std::allocator_traits::construct(impl_, p, value); } } @@ -420,7 +315,7 @@ private: template ::value>::type> static void S_construct_a(Allocator& a, U* p, const U& value) { - folly::fbv_allocator_traits::construct(a, p, value); + std::allocator_traits::construct(a, p, value); } //--------------------------------------------------------------------------- @@ -430,7 +325,7 @@ private: if (usingStdAllocator::value) { if (!boost::has_trivial_destructor::value) p->~T(); } else { - folly::fbv_allocator_traits::destroy(impl_, p); + std::allocator_traits::destroy(impl_, p); } } @@ -461,7 +356,7 @@ private: // allocator static void S_destroy_range_a(Allocator& a, T* first, T* last) noexcept { for (; first != last; ++first) - folly::fbv_allocator_traits::destroy(a, first); + std::allocator_traits::destroy(a, first); } // optimized @@ -523,7 +418,7 @@ private: auto e = dest + sz; try { for (; b != e; ++b) - folly::fbv_allocator_traits::construct(a, b, + std::allocator_traits::construct(a, b, std::forward(args)...); } catch (...) { S_destroy_range_a(a, dest, b); @@ -605,7 +500,7 @@ private: auto b = dest; try { for (; first != last; ++first, ++b) - folly::fbv_allocator_traits::construct(a, b, *first); + std::allocator_traits::construct(a, b, *first); } catch (...) { S_destroy_range_a(a, dest, b); throw; @@ -627,7 +522,9 @@ private: static void S_uninitialized_copy_bits(T* dest, const T* first, const T* last) { - std::memcpy(dest, first, (last - first) * sizeof(T)); + if (last != first) { + std::memcpy((void*)dest, (void*)first, (last - first) * sizeof(T)); + } } static void @@ -635,7 +532,9 @@ private: std::move_iterator last) { T* bFirst = first.base(); T* bLast = last.base(); - std::memcpy(dest, bFirst, (bLast - bFirst) * sizeof(T)); + if (bLast != bFirst) { + std::memcpy((void*)dest, (void*)bFirst, (bLast - bFirst) * sizeof(T)); + } } template @@ -660,7 +559,7 @@ private: static const T* S_copy_n(T* dest, const T* first, size_type n) { if (folly::IsTriviallyCopyable::value) { - std::memcpy(dest, first, n * sizeof(T)); + std::memcpy((void*)dest, (void*)first, n * sizeof(T)); return first + n; } else { return S_copy_n(dest, first, n); @@ -671,7 +570,7 @@ private: S_copy_n(T* dest, std::move_iterator mIt, size_type n) { if (folly::IsTriviallyCopyable::value) { T* first = mIt.base(); - std::memcpy(dest, first, n * sizeof(T)); + std::memcpy((void*)dest, (void*)first, n * sizeof(T)); return std::make_move_iterator(first + n); } else { return S_copy_n>(dest, mIt, n); @@ -730,9 +629,9 @@ private: > relocate_use_memcpy; typedef std::integral_constant::value + (std::is_nothrow_move_constructible::value && usingStdAllocator::value) - || !folly::fbv_is_copy_constructible::value + || !std::is_copy_constructible::value > relocate_use_move; // move @@ -741,7 +640,9 @@ private: } void relocate_move_or_memcpy(T* dest, T* first, T* last, std::true_type) { - std::memcpy(dest, first, (last - first) * sizeof(T)); + if (first != nullptr) { + std::memcpy((void*)dest, (void*)first, (last - first) * sizeof(T)); + } } void relocate_move_or_memcpy(T* dest, T* first, T* last, std::false_type) { @@ -757,7 +658,7 @@ private: } // done - void relocate_done(T* dest, T* first, T* last) noexcept { + void relocate_done(T* /*dest*/, T* first, T* last) noexcept { if (folly::IsRelocatable::value && usingStdAllocator::value) { // used memcpy; data has been relocated, do not call destructor } else { @@ -769,11 +670,11 @@ private: void relocate_undo(T* dest, T* first, T* last) noexcept { if (folly::IsRelocatable::value && usingStdAllocator::value) { // used memcpy, old data is still valid, nothing to do - } else if (folly::fbv_is_nothrow_move_constructible::value && + } else if (std::is_nothrow_move_constructible::value && usingStdAllocator::value) { // noexcept move everything back, aka relocate_move relocate_move(first, dest, dest + (last - first)); - } else if (!folly::fbv_is_copy_constructible::value) { + } else if (!std::is_copy_constructible::value) { // weak guarantee D_destroy_range_a(dest, dest + (last - first)); } else { @@ -803,12 +704,7 @@ public: template ::iterator_category> fbvector(It first, It last, const Allocator& a = Allocator()) - #ifndef FOLLY_FBV_COMPATIBILITY_MODE : fbvector(first, last, a, Category()) {} - #else - : impl_(std::distance(first, last), a) - { fbvector_init(first, last, Category()); } - #endif fbvector(const fbvector& other) : impl_(other.size(), A::select_on_container_copy_construction(other.impl_)) @@ -817,14 +713,9 @@ public: fbvector(fbvector&& other) noexcept : impl_(std::move(other.impl_)) {} fbvector(const fbvector& other, const Allocator& a) - #ifndef FOLLY_FBV_COMPATIBILITY_MODE : fbvector(other.begin(), other.end(), a) {} - #else - : impl_(other.size(), a) - { fbvector_init(other.begin(), other.end(), std::forward_iterator_tag()); } - #endif - fbvector(fbvector&& other, const Allocator& a) : impl_(a) { + /* may throw */ fbvector(fbvector&& other, const Allocator& a) : impl_(a) { if (impl_ == other.impl_) { impl_.swapData(other.impl_); } else { @@ -834,12 +725,7 @@ public: } fbvector(std::initializer_list il, const Allocator& a = Allocator()) - #ifndef FOLLY_FBV_COMPATIBILITY_MODE : fbvector(il.begin(), il.end(), a) {} - #else - : impl_(std::distance(il.begin(), il.end()), a) - { fbvector_init(il.begin(), il.end(), std::forward_iterator_tag()); } - #endif ~fbvector() = default; // the cleanup occurs in impl_ @@ -908,7 +794,6 @@ public: private: - #ifndef FOLLY_FBV_COMPATIBILITY_MODE // contract dispatch for iterator types fbvector(It first, It last) template fbvector(ForwardIterator first, ForwardIterator last, @@ -922,21 +807,6 @@ private: : impl_(a) { for (; first != last; ++first) emplace_back(*first); } - #else - // contract dispatch for iterator types without constructor forwarding - template - void - fbvector_init(ForwardIterator first, ForwardIterator last, - std::forward_iterator_tag) - { M_uninitialized_copy_e(first, last); } - - template - void - fbvector_init(InputIterator first, InputIterator last, - std::input_iterator_tag) - { for (; first != last; ++first) emplace_back(*first); } - #endif - // contract dispatch for allocator movement in operator=(fbvector&&) void moveFrom(fbvector&& other, std::true_type) { @@ -955,7 +825,7 @@ private: template void assign(ForwardIterator first, ForwardIterator last, std::forward_iterator_tag) { - auto const newSize = std::distance(first, last); + const size_t newSize = std::distance(first, last); if (newSize > capacity()) { impl_.reset(newSize); M_uninitialized_copy_e(first, last); @@ -1100,6 +970,11 @@ public: } void shrink_to_fit() noexcept { + if (empty()) { + impl_.reset(); + return; + } + auto const newCapacityBytes = folly::goodMallocSize(size() * sizeof(T)); auto const newCap = newCapacityBytes / sizeof(T); auto const oldCap = capacity(); @@ -1107,10 +982,11 @@ public: if (newCap >= oldCap) return; void* p = impl_.b_; - if ((rallocm && usingStdAllocator::value) && + // xallocx() will shrink to precisely newCapacityBytes (which was generated + // by goodMallocSize()) if it successfully shrinks in place. + if ((usingJEMalloc() && usingStdAllocator::value) && newCapacityBytes >= folly::jemallocMinInPlaceExpandable && - rallocm(&p, nullptr, newCapacityBytes, 0, ALLOCM_NO_MOVE) - == ALLOCM_SUCCESS) { + xallocx(p, newCapacityBytes, 0, 0) == newCapacityBytes) { impl_.z_ += newCap - oldCap; } else { T* newB; // intentionally uninitialized @@ -1136,7 +1012,7 @@ public: private: bool reserve_in_place(size_type n) { - if (!usingStdAllocator::value || !rallocm) return false; + if (!usingStdAllocator::value || !usingJEMalloc()) return false; // jemalloc can never grow in place blocks smaller than 4096 bytes. if ((impl_.z_ - impl_.b_) * sizeof(T) < @@ -1144,8 +1020,7 @@ private: auto const newCapacityBytes = folly::goodMallocSize(n * sizeof(T)); void* p = impl_.b_; - if (rallocm(&p, nullptr, newCapacityBytes, 0, ALLOCM_NO_MOVE) - == ALLOCM_SUCCESS) { + if (xallocx(p, newCapacityBytes, 0, 0) == newCapacityBytes) { impl_.z_ = impl_.b_ + newCapacityBytes / sizeof(T); return true; } @@ -1277,14 +1152,16 @@ private: // size_type computePushBackCapacity() const { - return empty() ? std::max(64 / sizeof(T), size_type(1)) - : capacity() < folly::jemallocMinInPlaceExpandable / sizeof(T) - ? capacity() * 2 - : sizeof(T) > folly::jemallocMinInPlaceExpandable / 2 && capacity() == 1 - ? 2 - : capacity() > 4096 * 32 / sizeof(T) - ? capacity() * 2 - : (capacity() * 3 + 1) / 2; + if (capacity() == 0) { + return std::max(64 / sizeof(T), size_type(1)); + } + if (capacity() < folly::jemallocMinInPlaceExpandable / sizeof(T)) { + return capacity() * 2; + } + if (capacity() > 4096 * 32 / sizeof(T)) { + return capacity() * 2; + } + return (capacity() * 3 + 1) / 2; } template @@ -1309,7 +1186,7 @@ public: if (folly::IsRelocatable::value && usingStdAllocator::value) { D_destroy_range_a((iterator)first, (iterator)last); if (last - first >= cend() - last) { - std::memcpy((iterator)first, last, (cend() - last) * sizeof(T)); + std::memcpy((void*)first, (void*)last, (cend() - last) * sizeof(T)); } else { std::memmove((iterator)first, last, (cend() - last) * sizeof(T)); } @@ -1387,7 +1264,7 @@ private: // we have the private section first because it defines some macros // These three functions, make_window, wrap_frame, and // insert_use_fresh_memory, can be combined into a uniform interface. // Since that interface involves a lot of case-work, it is built into - // some macros: FOLLY_FBVECTOR_INSERT_(START|TRY|END) + // some macros: FOLLY_FBVECTOR_INSERT_(PRE|START|TRY|END) // Macros are used in an attempt to let GCC perform better optimizations, // especially control flow optimization. // @@ -1396,11 +1273,8 @@ private: // we have the private section first because it defines some macros // window void make_window(iterator position, size_type n) { - assert(isValid(position)); - assert(size() + n <= capacity()); - assert(n != 0); - - auto tail = std::distance(position, impl_.e_); + // The result is guaranteed to be non-negative, so use an unsigned type: + size_type tail = std::distance(position, impl_.e_); if (tail <= n) { relocate_move(position + n, position, impl_.e_); @@ -1412,9 +1286,15 @@ private: // we have the private section first because it defines some macros impl_.e_ += n; } else { D_uninitialized_move_a(impl_.e_, impl_.e_ - n, impl_.e_); + try { + std::copy_backward(std::make_move_iterator(position), + std::make_move_iterator(impl_.e_ - n), impl_.e_); + } catch (...) { + D_destroy_range_a(impl_.e_ - n, impl_.e_ + n); + impl_.e_ -= n; + throw; + } impl_.e_ += n; - std::copy_backward(std::make_move_iterator(position), - std::make_move_iterator(impl_.e_ - n), impl_.e_); D_destroy_range_a(position, position + n); } } @@ -1446,8 +1326,8 @@ private: // we have the private section first because it defines some macros //--------------------------------------------------------------------------- // use fresh? - bool insert_use_fresh(const_iterator cposition, size_type n) { - if (cposition == cend()) { + bool insert_use_fresh(bool at_end, size_type n) { + if (at_end) { if (size() + n <= capacity()) return false; if (reserve_in_place(size() + n)) return false; return true; @@ -1461,19 +1341,33 @@ private: // we have the private section first because it defines some macros //--------------------------------------------------------------------------- // interface + #define FOLLY_FBVECTOR_INSERT_PRE(cpos, n) \ + if (n == 0) return (iterator)cpos; \ + bool at_end = cpos == cend(); \ + bool fresh = insert_use_fresh(at_end, n); \ + if (!at_end) { \ + if (!fresh) { + + // check for internal data (technically not required by the standard) + #define FOLLY_FBVECTOR_INSERT_START(cpos, n) \ - assert(isValid(cpos)); \ + } \ + assert(isValid(cpos)); \ + } \ T* position = const_cast(cpos); \ size_type idx = std::distance(impl_.b_, position); \ - bool fresh = insert_use_fresh(position, n); \ T* b; \ - size_type newCap = 0; \ + size_type newCap; /* intentionally uninitialized */ \ \ if (fresh) { \ newCap = computeInsertCapacity(n); \ b = M_allocate(newCap); \ } else { \ - make_window(position, n); \ + if (!at_end) { \ + make_window(position, n); \ + } else { \ + impl_.e_ += n; \ + } \ b = impl_.b_; \ } \ \ @@ -1488,7 +1382,11 @@ private: // we have the private section first because it defines some macros if (fresh) { \ M_deallocate(b, newCap); \ } else { \ - undo_window(position, n); \ + if (!at_end) { \ + undo_window(position, n); \ + } else { \ + impl_.e_ -= n; \ + } \ } \ throw; \ } \ @@ -1518,6 +1416,7 @@ public: template iterator emplace(const_iterator cpos, Args&&... args) { + FOLLY_FBVECTOR_INSERT_PRE(cpos, 1) FOLLY_FBVECTOR_INSERT_START(cpos, 1) M_construct(start, std::forward(args)...); FOLLY_FBVECTOR_INSERT_TRY(cpos, 1) @@ -1526,8 +1425,8 @@ public: } iterator insert(const_iterator cpos, const T& value) { - if (dataIsInternal(value)) return insert(cpos, T(value)); - + FOLLY_FBVECTOR_INSERT_PRE(cpos, 1) + if (dataIsInternal(value)) return insert(cpos, T(value)); FOLLY_FBVECTOR_INSERT_START(cpos, 1) M_construct(start, value); FOLLY_FBVECTOR_INSERT_TRY(cpos, 1) @@ -1536,8 +1435,8 @@ public: } iterator insert(const_iterator cpos, T&& value) { - if (dataIsInternal(value)) return insert(cpos, T(std::move(value))); - + FOLLY_FBVECTOR_INSERT_PRE(cpos, 1) + if (dataIsInternal(value)) return insert(cpos, T(std::move(value))); FOLLY_FBVECTOR_INSERT_START(cpos, 1) M_construct(start, std::move(value)); FOLLY_FBVECTOR_INSERT_TRY(cpos, 1) @@ -1546,9 +1445,8 @@ public: } iterator insert(const_iterator cpos, size_type n, VT value) { - if (n == 0) return (iterator)cpos; - if (dataIsInternalAndNotVT(value)) return insert(cpos, n, T(value)); - + FOLLY_FBVECTOR_INSERT_PRE(cpos, n) + if (dataIsInternalAndNotVT(value)) return insert(cpos, n, T(value)); FOLLY_FBVECTOR_INSERT_START(cpos, n) D_uninitialized_fill_n_a(start, n, value); FOLLY_FBVECTOR_INSERT_TRY(cpos, n) @@ -1574,8 +1472,7 @@ private: iterator insert(const_iterator cpos, FIt first, FIt last, std::forward_iterator_tag) { size_type n = std::distance(first, last); - if (n == 0) return (iterator)cpos; - + FOLLY_FBVECTOR_INSERT_PRE(cpos, n) FOLLY_FBVECTOR_INSERT_START(cpos, n) D_uninitialized_copy_a(start, first, last); FOLLY_FBVECTOR_INSERT_TRY(cpos, n) @@ -1638,17 +1535,17 @@ void fbvector::emplace_back_aux(Args&&... args) { size_type byte_sz = folly::goodMallocSize( computePushBackCapacity() * sizeof(T)); if (usingStdAllocator::value - && rallocm + && usingJEMalloc() && ((impl_.z_ - impl_.b_) * sizeof(T) >= folly::jemallocMinInPlaceExpandable)) { // Try to reserve in place. - // Ask rallocm to allocate in place at least size()+1 and at most sz space. - // rallocm will allocate as much as possible within that range, which + // Ask xallocx to allocate in place at least size()+1 and at most sz space. + // xallocx will allocate as much as possible within that range, which // is the best possible outcome: if sz space is available, take it all, // otherwise take as much as possible. If nothing is available, then fail. // In this fashion, we never relocate if there is a possibility of - // expanding in place, and we never relocate by less than the desired - // amount unless we cannot expand further. Hence we will not relocate + // expanding in place, and we never reallocate by less than the desired + // amount unless we cannot expand further. Hence we will not reallocate // sub-optimally twice in a row (modulo the blocking memory being freed). size_type lower = folly::goodMallocSize(sizeof(T) + size() * sizeof(T)); size_type upper = byte_sz; @@ -1657,8 +1554,7 @@ void fbvector::emplace_back_aux(Args&&... args) { void* p = impl_.b_; size_t actual; - if (rallocm(&p, &actual, lower, extra, ALLOCM_NO_MOVE) - == ALLOCM_SUCCESS) { + if ((actual = xallocx(p, lower, extra, 0)) >= lower) { impl_.z_ = impl_.b_ + actual / sizeof(T); M_construct(impl_.e_, std::forward(args)...); ++impl_.e_; @@ -1713,6 +1609,16 @@ void swap(fbvector& lhs, fbvector& rhs) noexcept { //----------------------------------------------------------------------------- // other +namespace detail { + +// Format support. +template +struct IndexableTraits> + : public IndexableTraitsSeq> { +}; + +} // namespace detail + template void compactResize(fbvector* v, size_t sz) { v->resize(sz); @@ -1758,5 +1664,3 @@ void attach(fbvector& v, T* data, size_t sz, size_t cap) { } } // namespace folly - -#endif // FOLLY_FBVECTOR_H