X-Git-Url: http://plrg.eecs.uci.edu/git/?p=folly.git;a=blobdiff_plain;f=folly%2Fsmall_vector.h;h=26e92657d2f473865d4d0092e2c675b739e98a6c;hp=71893a3c387780186455b5a8aa351aacf3dcc6a9;hb=2d16fa08610b9c37dc13cfce06561ff0f57de7f4;hpb=fbfe105970bcf88e8c123046f84bebdfe24f8801 diff --git a/folly/small_vector.h b/folly/small_vector.h index 71893a3c..26e92657 100644 --- a/folly/small_vector.h +++ b/folly/small_vector.h @@ -1,5 +1,5 @@ /* - * Copyright 2017 Facebook, Inc. + * Copyright 2011-present Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,9 +26,11 @@ #include #include #include +#include #include #include #include +#include #include #include @@ -43,14 +45,14 @@ #include #include -#include +#include #include -#include #include #include #include +#include +#include #include -#include #include #include @@ -74,7 +76,7 @@ struct NoHeap; ////////////////////////////////////////////////////////////////////// -} // small_vector_policy +} // namespace small_vector_policy ////////////////////////////////////////////////////////////////////// @@ -85,14 +87,134 @@ class small_vector; namespace detail { +/* + * Move objects in memory to the right into some uninitialized + * memory, where the region overlaps. This doesn't just use + * std::move_backward because move_backward only works if all the + * memory is initialized to type T already. + */ +template +typename std::enable_if::type +moveObjectsRight(T* first, T* lastConstructed, T* realLast) { + if (lastConstructed == realLast) { + return; + } + + T* end = first - 1; // Past the end going backwards. + T* out = realLast - 1; + T* in = lastConstructed - 1; + try { + for (; in != end && out >= lastConstructed; --in, --out) { + new (out) T(std::move(*in)); + } + for (; in != end; --in, --out) { + *out = std::move(*in); + } + for (; out >= lastConstructed; --out) { + new (out) T(); + } + } catch (...) { + // We want to make sure the same stuff is uninitialized memory + // if we exit via an exception (this is to make sure we provide + // the basic exception safety guarantee for insert functions). + if (out < lastConstructed) { + out = lastConstructed - 1; + } + for (auto it = out + 1; it != realLast; ++it) { + it->~T(); + } + throw; + } +} + +// Specialization for trivially copyable types. The call to +// std::move_backward here will just turn into a memmove. (TODO: +// change to std::is_trivially_copyable when that works.) +template +typename std::enable_if::type +moveObjectsRight(T* first, T* lastConstructed, T* realLast) { + std::move_backward(first, lastConstructed, realLast); +} + +/* + * Populate a region of memory using `op' to construct elements. If + * anything throws, undo what we did. + */ +template +void populateMemForward(T* mem, std::size_t n, Function const& op) { + std::size_t idx = 0; + try { + for (size_t i = 0; i < n; ++i) { + op(&mem[idx]); + ++idx; + } + } catch (...) { + for (std::size_t i = 0; i < idx; ++i) { + mem[i].~T(); + } + throw; + } +} + +template +struct IntegralSizePolicyBase { + typedef SizeType InternalSizeType; + + IntegralSizePolicyBase() : size_(0) {} + + protected: + static constexpr std::size_t policyMaxSize() { + return SizeType(~kExternMask); + } + + std::size_t doSize() const { + return size_ & ~kExternMask; + } + + std::size_t isExtern() const { + return kExternMask & size_; + } + + void setExtern(bool b) { + if (b) { + size_ |= kExternMask; + } else { + size_ &= ~kExternMask; + } + } + + void setSize(std::size_t sz) { + assert(sz <= policyMaxSize()); + size_ = (kExternMask & size_) | SizeType(sz); + } + + void swapSizePolicy(IntegralSizePolicyBase& o) { + std::swap(size_, o.size_); + } + + protected: + static bool constexpr kShouldUseHeap = ShouldUseHeap; + + private: + static SizeType constexpr kExternMask = + kShouldUseHeap ? SizeType(1) << (sizeof(SizeType) * 8 - 1) : 0; + + SizeType size_; +}; + +template +struct IntegralSizePolicy; + +template +struct IntegralSizePolicy + : public IntegralSizePolicyBase { + public: /* * Move a range to a range of uninitialized memory. Assumes the * ranges don't overlap. */ template - typename std::enable_if< - !FOLLY_IS_TRIVIALLY_COPYABLE(T) - >::type + typename std::enable_if::type moveToUninitialized(T* first, T* last, T* out) { std::size_t idx = 0; try { @@ -114,32 +236,30 @@ namespace detail { // Specialization for trivially copyable types. template - typename std::enable_if< - FOLLY_IS_TRIVIALLY_COPYABLE(T) - >::type + typename std::enable_if::type moveToUninitialized(T* first, T* last, T* out) { std::memmove(out, first, (last - first) * sizeof *first); } /* * Move a range to a range of uninitialized memory. Assumes the - * ranges don't overlap. Inserts an element at out + pos using emplaceFunc(). - * out will contain (end - begin) + 1 elements on success and none on failure. - * If emplaceFunc() throws [begin, end) is unmodified. + * ranges don't overlap. Inserts an element at out + pos using + * emplaceFunc(). out will contain (end - begin) + 1 elements on success and + * none on failure. If emplaceFunc() throws [begin, end) is unmodified. */ - template + template void moveToUninitializedEmplace( T* begin, T* end, T* out, - Size pos, + SizeType pos, EmplaceFunc&& emplaceFunc) { // Must be called first so that if it throws [begin, end) is unmodified. // We have to support the strong exception guarantee for emplace_back(). emplaceFunc(out + pos); // move old elements to the left of the new one try { - detail::moveToUninitialized(begin, begin + pos, out); + this->moveToUninitialized(begin, begin + pos, out); } catch (...) { out[pos].~T(); throw; @@ -147,221 +267,118 @@ namespace detail { // move old elements to the right of the new one try { if (begin + pos < end) { - detail::moveToUninitialized(begin + pos, end, out + pos + 1); + this->moveToUninitialized(begin + pos, end, out + pos + 1); } } catch (...) { - for (Size i = 0; i <= pos; ++i) { + for (SizeType i = 0; i <= pos; ++i) { out[i].~T(); } throw; } } +}; - /* - * Move objects in memory to the right into some uninitialized - * memory, where the region overlaps. This doesn't just use - * std::move_backward because move_backward only works if all the - * memory is initialized to type T already. - */ - template - typename std::enable_if< - !FOLLY_IS_TRIVIALLY_COPYABLE(T) - >::type - moveObjectsRight(T* first, T* lastConstructed, T* realLast) { - if (lastConstructed == realLast) { - return; - } - - T* end = first - 1; // Past the end going backwards. - T* out = realLast - 1; - T* in = lastConstructed - 1; - try { - for (; in != end && out >= lastConstructed; --in, --out) { - new (out) T(std::move(*in)); - } - for (; in != end; --in, --out) { - *out = std::move(*in); - } - for (; out >= lastConstructed; --out) { - new (out) T(); - } - } catch (...) { - // We want to make sure the same stuff is uninitialized memory - // if we exit via an exception (this is to make sure we provide - // the basic exception safety guarantee for insert functions). - if (out < lastConstructed) { - out = lastConstructed - 1; - } - for (auto it = out + 1; it != realLast; ++it) { - it->~T(); - } - throw; - } - } - - // Specialization for trivially copyable types. The call to - // std::move_backward here will just turn into a memmove. (TODO: - // change to std::is_trivially_copyable when that works.) +template +struct IntegralSizePolicy + : public IntegralSizePolicyBase { + public: template - typename std::enable_if< - FOLLY_IS_TRIVIALLY_COPYABLE(T) - >::type - moveObjectsRight(T* first, T* lastConstructed, T* realLast) { - std::move_backward(first, lastConstructed, realLast); + void moveToUninitialized(T* /*first*/, T* /*last*/, T* /*out*/) { + assume_unreachable(); } - - /* - * Populate a region of memory using `op' to construct elements. If - * anything throws, undo what we did. - */ - template - void populateMemForward(T* mem, std::size_t n, Function const& op) { - std::size_t idx = 0; - try { - for (size_t i = 0; i < n; ++i) { - op(&mem[idx]); - ++idx; - } - } catch (...) { - for (std::size_t i = 0; i < idx; ++i) { - mem[i].~T(); - } - throw; - } + template + void moveToUninitializedEmplace( + T* /* begin */, + T* /* end */, + T* /* out */, + SizeType /* pos */, + EmplaceFunc&& /* emplaceFunc */) { + assume_unreachable(); } +}; - template - struct IntegralSizePolicy { - typedef SizeType InternalSizeType; - - IntegralSizePolicy() : size_(0) {} - - protected: - static constexpr std::size_t policyMaxSize() { - return SizeType(~kExternMask); - } - - std::size_t doSize() const { - return size_ & ~kExternMask; - } - - std::size_t isExtern() const { - return kExternMask & size_; - } - - void setExtern(bool b) { - if (b) { - size_ |= kExternMask; - } else { - size_ &= ~kExternMask; - } - } - - void setSize(std::size_t sz) { - assert(sz <= policyMaxSize()); - size_ = (kExternMask & size_) | SizeType(sz); - } - - void swapSizePolicy(IntegralSizePolicy& o) { - std::swap(size_, o.size_); - } - - protected: - static bool const kShouldUseHeap = ShouldUseHeap; - - private: - static SizeType const kExternMask = - kShouldUseHeap ? SizeType(1) << (sizeof(SizeType) * 8 - 1) - : 0; - - SizeType size_; - }; +/* + * If you're just trying to use this class, ignore everything about + * this next small_vector_base class thing. + * + * The purpose of this junk is to minimize sizeof(small_vector<>) + * and allow specifying the template parameters in whatever order is + * convenient for the user. There's a few extra steps here to try + * to keep the error messages at least semi-reasonable. + * + * Apologies for all the black magic. + */ +namespace mpl = boost::mpl; +template < + class Value, + std::size_t RequestedMaxInline, + class InPolicyA, + class InPolicyB, + class InPolicyC> +struct small_vector_base { + typedef mpl::vector PolicyList; /* - * If you're just trying to use this class, ignore everything about - * this next small_vector_base class thing. - * - * The purpose of this junk is to minimize sizeof(small_vector<>) - * and allow specifying the template parameters in whatever order is - * convenient for the user. There's a few extra steps here to try - * to keep the error messages at least semi-reasonable. - * - * Apologies for all the black magic. + * Determine the size type */ - namespace mpl = boost::mpl; - template < - class Value, - std::size_t RequestedMaxInline, - class InPolicyA, - class InPolicyB, - class InPolicyC> - struct small_vector_base { - typedef mpl::vector PolicyList; - - /* - * Determine the size type - */ - typedef typename mpl::filter_view< + typedef typename mpl::filter_view< PolicyList, - boost::is_integral - >::type Integrals; - typedef typename mpl::eval_if< + boost::is_integral>::type Integrals; + typedef typename mpl::eval_if< mpl::empty, mpl::identity, - mpl::front - >::type SizeType; + mpl::front>::type SizeType; - static_assert(std::is_unsigned::value, - "Size type should be an unsigned integral type"); - static_assert(mpl::size::value == 0 || - mpl::size::value == 1, - "Multiple size types specified in small_vector<>"); + static_assert( + std::is_unsigned::value, + "Size type should be an unsigned integral type"); + static_assert( + mpl::size::value == 0 || mpl::size::value == 1, + "Multiple size types specified in small_vector<>"); - /* - * Determine whether we should allow spilling to the heap or not. - */ - typedef typename mpl::count< - PolicyList,small_vector_policy::NoHeap - >::type HasNoHeap; + /* + * Determine whether we should allow spilling to the heap or not. + */ + typedef typename mpl::count::type + HasNoHeap; - static_assert(HasNoHeap::value == 0 || HasNoHeap::value == 1, - "Multiple copies of small_vector_policy::NoHeap " - "supplied; this is probably a mistake"); + static_assert( + HasNoHeap::value == 0 || HasNoHeap::value == 1, + "Multiple copies of small_vector_policy::NoHeap " + "supplied; this is probably a mistake"); - /* - * Make the real policy base classes. - */ - typedef IntegralSizePolicy - ActualSizePolicy; + /* + * Make the real policy base classes. + */ + typedef IntegralSizePolicy ActualSizePolicy; - /* - * Now inherit from them all. This is done in such a convoluted - * way to make sure we get the empty base optimizaton on all these - * types to keep sizeof(small_vector<>) minimal. - */ - typedef boost::totally_ordered1< - small_vector, - ActualSizePolicy - > type; - }; + /* + * Now inherit from them all. This is done in such a convoluted + * way to make sure we get the empty base optimizaton on all these + * types to keep sizeof(small_vector<>) minimal. + */ + typedef boost::totally_ordered1< + small_vector, + ActualSizePolicy> + type; +}; - template - T* pointerFlagSet(T* p) { - return reinterpret_cast(reinterpret_cast(p) | 1); - } - template - bool pointerFlagGet(T* p) { - return reinterpret_cast(p) & 1; - } - template - T* pointerFlagClear(T* p) { - return reinterpret_cast( - reinterpret_cast(p) & ~uintptr_t(1)); - } - inline void* shiftPointer(void* p, size_t sizeBytes) { - return static_cast(p) + sizeBytes; - } +template +T* pointerFlagSet(T* p) { + return reinterpret_cast(reinterpret_cast(p) | 1); +} +template +bool pointerFlagGet(T* p) { + return reinterpret_cast(p) & 1; +} +template +T* pointerFlagClear(T* p) { + return reinterpret_cast(reinterpret_cast(p) & ~uintptr_t(1)); +} +inline void* shiftPointer(void* p, size_t sizeBytes) { + return static_cast(p) + sizeBytes; } +} // namespace detail ////////////////////////////////////////////////////////////////////// FOLLY_PACK_PUSH @@ -371,14 +388,15 @@ template < class PolicyA = void, class PolicyB = void, class PolicyC = void> -class small_vector - : public detail::small_vector_base< - Value,RequestedMaxInline,PolicyA,PolicyB,PolicyC - >::type -{ - typedef typename detail::small_vector_base< - Value,RequestedMaxInline,PolicyA,PolicyB,PolicyC - >::type BaseType; +class small_vector : public detail::small_vector_base< + Value, + RequestedMaxInline, + PolicyA, + PolicyB, + PolicyC>::type { + typedef typename detail:: + small_vector_base:: + type BaseType; typedef typename BaseType::InternalSizeType InternalSizeType; /* @@ -390,18 +408,22 @@ class small_vector constexpr_max(sizeof(Value*) / sizeof(Value), RequestedMaxInline)}; public: - typedef std::size_t size_type; - typedef Value value_type; - typedef value_type& reference; - typedef value_type const& const_reference; - typedef value_type* iterator; - typedef value_type const* const_iterator; - typedef std::ptrdiff_t difference_type; - - typedef std::reverse_iterator reverse_iterator; + typedef std::size_t size_type; + typedef Value value_type; + typedef value_type& reference; + typedef value_type const& const_reference; + typedef value_type* iterator; + typedef value_type* pointer; + typedef value_type const* const_iterator; + typedef std::ptrdiff_t difference_type; + + typedef std::reverse_iterator reverse_iterator; typedef std::reverse_iterator const_reverse_iterator; - explicit small_vector() = default; + small_vector() = default; + // Allocator is unused here. It is taken in for compatibility with std::vector + // interface, but it will be ignored. + small_vector(const std::allocator&) {} small_vector(small_vector const& o) { auto n = o.size(); @@ -417,14 +439,15 @@ class small_vector this->setSize(n); } - small_vector(small_vector&& o) - noexcept(std::is_nothrow_move_constructible::value) { + small_vector(small_vector&& o) noexcept( + std::is_nothrow_move_constructible::value) { if (o.isExtern()) { swap(o); } else { - std::uninitialized_copy(std::make_move_iterator(o.begin()), - std::make_move_iterator(o.end()), - begin()); + std::uninitialized_copy( + std::make_move_iterator(o.begin()), + std::make_move_iterator(o.end()), + begin()); this->setSize(o.size()); } } @@ -442,7 +465,7 @@ class small_vector } template - explicit small_vector(Arg arg1, Arg arg2) { + explicit small_vector(Arg arg1, Arg arg2) { // Forward using std::is_arithmetic to get to the proper // implementation; this disambiguates between the iterators and // (size_t, value_type) meaning for this constructor. @@ -466,7 +489,9 @@ class small_vector small_vector& operator=(small_vector&& o) { // TODO: optimization: // if both are internal, use move assignment where possible - if (this == &o) return *this; + if (this == &o) { + return *this; + } clear(); swap(o); return *this; @@ -485,18 +510,38 @@ class small_vector : BaseType::policyMaxSize(); } - size_type size() const { return this->doSize(); } - bool empty() const { return !size(); } + size_type size() const { + return this->doSize(); + } + bool empty() const { + return !size(); + } - iterator begin() { return data(); } - iterator end() { return data() + size(); } - const_iterator begin() const { return data(); } - const_iterator end() const { return data() + size(); } - const_iterator cbegin() const { return begin(); } - const_iterator cend() const { return end(); } + iterator begin() { + return data(); + } + iterator end() { + return data() + size(); + } + const_iterator begin() const { + return data(); + } + const_iterator end() const { + return data() + size(); + } + const_iterator cbegin() const { + return begin(); + } + const_iterator cend() const { + return end(); + } - reverse_iterator rbegin() { return reverse_iterator(end()); } - reverse_iterator rend() { return reverse_iterator(begin()); } + reverse_iterator rbegin() { + return reverse_iterator(end()); + } + reverse_iterator rend() { + return reverse_iterator(begin()); + } const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); @@ -506,8 +551,12 @@ class small_vector return const_reverse_iterator(begin()); } - const_reverse_iterator crbegin() const { return rbegin(); } - const_reverse_iterator crend() const { return rend(); } + const_reverse_iterator crbegin() const { + return rbegin(); + } + const_reverse_iterator crend() const { + return rend(); + } /* * Usually one of the simplest functions in a Container-like class @@ -570,7 +619,7 @@ class small_vector auto& oldIntern = o.isExtern() ? *this : o; auto oldExternCapacity = oldExtern.capacity(); - auto oldExternHeap = oldExtern.u.pdata_.heap_; + auto oldExternHeap = oldExtern.u.pdata_.heap_; auto buff = oldExtern.u.buffer(); size_type i = 0; @@ -602,9 +651,8 @@ class small_vector return; } makeSize(sz); - detail::populateMemForward(begin() + size(), sz - size(), - [&] (void* p) { new (p) value_type(); } - ); + detail::populateMemForward( + begin() + size(), sz - size(), [&](void* p) { new (p) value_type(); }); this->setSize(sz); } @@ -614,9 +662,8 @@ class small_vector return; } makeSize(sz); - detail::populateMemForward(begin() + size(), sz - size(), - [&] (void* p) { new (p) value_type(v); } - ); + detail::populateMemForward( + begin() + size(), sz - size(), [&](void* p) { new (p) value_type(v); }); this->setSize(sz); } @@ -722,14 +769,12 @@ class small_vector offset); this->setSize(this->size() + 1); } else { - detail::moveObjectsRight(data() + offset, - data() + size(), - data() + size() + 1); + detail::moveObjectsRight( + data() + offset, data() + size(), data() + size() + 1); this->setSize(size() + 1); data()[offset] = std::move(t); } return begin() + offset; - } iterator insert(const_iterator p, value_type const& t) { @@ -741,9 +786,8 @@ class small_vector iterator insert(const_iterator pos, size_type n, value_type const& val) { auto offset = pos - begin(); makeSize(size() + n); - detail::moveObjectsRight(data() + offset, - data() + size(), - data() + size() + n); + detail::moveObjectsRight( + data() + offset, data() + size(), data() + size() + n); this->setSize(size() + n); std::generate_n(begin() + offset, n, [&] { return val; }); return begin() + offset; @@ -769,7 +813,9 @@ class small_vector } iterator erase(const_iterator q1, const_iterator q2) { - if (q1 == q2) return unconst(q1); + if (q1 == q2) { + return unconst(q1); + } std::move(unconst(q2), end(), unconst(q1)); for (auto it = (end() - std::distance(q1, q2)); it != end(); ++it) { it->~value_type(); @@ -797,10 +843,22 @@ class small_vector insert(end(), n, t); } - reference front() { assert(!empty()); return *begin(); } - reference back() { assert(!empty()); return *(end() - 1); } - const_reference front() const { assert(!empty()); return *begin(); } - const_reference back() const { assert(!empty()); return *(end() - 1); } + reference front() { + assert(!empty()); + return *begin(); + } + reference back() { + assert(!empty()); + return *(end() - 1); + } + const_reference front() const { + assert(!empty()); + return *begin(); + } + const_reference back() const { + assert(!empty()); + return *(end() - 1); + } reference operator[](size_type i) { assert(i < size()); @@ -826,8 +884,7 @@ class small_vector return (*this)[i]; } -private: - + private: static iterator unconst(const_iterator it) { return const_cast(it); } @@ -837,7 +894,7 @@ private: template iterator insertImpl(iterator pos, It first, It last, std::false_type) { typedef typename std::iterator_traits::iterator_category categ; - if (std::is_same::value) { + if (std::is_same::value) { auto offset = pos - begin(); while (first != last) { pos = insert(pos, *first++); @@ -849,16 +906,15 @@ private: auto distance = std::distance(first, last); auto offset = pos - begin(); makeSize(size() + distance); - detail::moveObjectsRight(data() + offset, - data() + size(), - data() + size() + distance); + detail::moveObjectsRight( + data() + offset, data() + size(), data() + size() + distance); this->setSize(size() + distance); std::copy_n(first, distance, begin() + offset); return begin() + offset; } - iterator insertImpl(iterator pos, size_type n, const value_type& val, - std::true_type) { + iterator + insertImpl(iterator pos, size_type n, const value_type& val, std::true_type) { // The true_type means this should call the size_t,value_type // overload. (See insert().) return insert(pos, n, val); @@ -870,7 +926,7 @@ private: template void constructImpl(It first, It last, std::false_type) { typedef typename std::iterator_traits::iterator_category categ; - if (std::is_same::value) { + if (std::is_same::value) { // With iterators that only allow a single pass, we can't really // do anything sane here. while (first != last) { @@ -883,9 +939,8 @@ private: makeSize(distance); this->setSize(distance); try { - detail::populateMemForward(data(), distance, - [&] (void* p) { new (p) value_type(*first++); } - ); + detail::populateMemForward( + data(), distance, [&](void* p) { new (p) value_type(*first++); }); } catch (...) { if (this->isExtern()) { u.freeHeap(); @@ -955,6 +1010,15 @@ private: assert(!insert); return; } + + assert(this->kShouldUseHeap); + // This branch isn't needed for correctness, but allows the optimizer to + // skip generating code for the rest of this function in NoHeap + // small_vectors. + if (!this->kShouldUseHeap) { + return; + } + newSize = std::max(newSize, computeNewSize()); auto needBytes = newSize * sizeof(value_type); @@ -962,7 +1026,7 @@ private: // allocation is grown to over some threshold, we should store // a capacity at the front of the heap allocation. bool heapifyCapacity = - !kHasInlineCapacity && needBytes > kHeapifyCapacityThreshold; + !kHasInlineCapacity && needBytes > kHeapifyCapacityThreshold; if (heapifyCapacity) { needBytes += kHeapifyCapacitySize; } @@ -973,18 +1037,17 @@ private: assert(!detail::pointerFlagGet(newh)); value_type* newp = static_cast( - heapifyCapacity ? - detail::shiftPointer(newh, kHeapifyCapacitySize) : - newh); + heapifyCapacity ? detail::shiftPointer(newh, kHeapifyCapacitySize) + : newh); try { if (insert) { // move and insert the new element - detail::moveToUninitializedEmplace( + this->moveToUninitializedEmplace( begin(), end(), newp, pos, std::forward(emplaceFunc)); } else { // move without inserting new element - detail::moveToUninitialized(begin(), end(), newp); + this->moveToUninitialized(begin(), end(), newp); } } catch (...) { free(newh); @@ -1020,7 +1083,7 @@ private: } } -private: + private: struct HeapPtrWithCapacity { void* heap_; InternalSizeType capacity_; @@ -1051,38 +1114,35 @@ private: typedef unsigned char InlineStorageDataType[sizeof(value_type) * MaxInline]; #else typedef typename std::aligned_storage< - sizeof(value_type) * MaxInline, - alignof(value_type) - >::type InlineStorageDataType; + sizeof(value_type) * MaxInline, + alignof(value_type)>::type InlineStorageDataType; #endif typedef typename std::conditional< - sizeof(value_type) * MaxInline != 0, - InlineStorageDataType, - void* - >::type InlineStorageType; + sizeof(value_type) * MaxInline != 0, + InlineStorageDataType, + void*>::type InlineStorageType; - static bool const kHasInlineCapacity = - sizeof(HeapPtrWithCapacity) < sizeof(InlineStorageType); + static bool constexpr kHasInlineCapacity = + sizeof(HeapPtrWithCapacity) < sizeof(InlineStorageType); // This value should we multiple of word size. - static size_t const kHeapifyCapacitySize = sizeof( - typename std::aligned_storage< - sizeof(InternalSizeType), - alignof(value_type) - >::type); + static size_t constexpr kHeapifyCapacitySize = sizeof( + typename std:: + aligned_storage::type); + // Threshold to control capacity heapifying. - static size_t const kHeapifyCapacityThreshold = - 100 * kHeapifyCapacitySize; + static size_t constexpr kHeapifyCapacityThreshold = + 100 * kHeapifyCapacitySize; - typedef typename std::conditional< - kHasInlineCapacity, - HeapPtrWithCapacity, - HeapPtr - >::type PointerType; + typedef typename std:: + conditional::type + PointerType; union Data { - explicit Data() { pdata_.heap_ = 0; } + explicit Data() { + pdata_.heap_ = nullptr; + } PointerType pdata_; InlineStorageType storage_; @@ -1129,8 +1189,9 @@ FOLLY_PACK_POP // Basic guarantee only, or provides the nothrow guarantee iff T has a // nothrow move or copy constructor. template -void swap(small_vector& a, - small_vector& b) { +void swap( + small_vector& a, + small_vector& b) { a.swap(b); } @@ -1141,11 +1202,10 @@ namespace detail { // Format support. template struct IndexableTraits> - : public IndexableTraitsSeq> { -}; + : public IndexableTraitsSeq> {}; -} // namespace detail +} // namespace detail -} // namespace folly +} // namespace folly FOLLY_POP_WARNING