32 #include <type_traits> 35 #include <boost/mpl/count.hpp> 36 #include <boost/mpl/empty.hpp> 37 #include <boost/mpl/eval_if.hpp> 38 #include <boost/mpl/filter_view.hpp> 39 #include <boost/mpl/front.hpp> 40 #include <boost/mpl/identity.hpp> 41 #include <boost/mpl/if.hpp> 42 #include <boost/mpl/placeholders.hpp> 43 #include <boost/mpl/size.hpp> 44 #include <boost/mpl/vector.hpp> 45 #include <boost/operators.hpp> 57 #if (FOLLY_X64 || FOLLY_PPC64) 58 #define FOLLY_SV_PACK_ATTR FOLLY_PACK_ATTR 59 #define FOLLY_SV_PACK_PUSH FOLLY_PACK_PUSH 60 #define FOLLY_SV_PACK_POP FOLLY_PACK_POP 62 #define FOLLY_SV_PACK_ATTR 63 #define FOLLY_SV_PACK_PUSH 64 #define FOLLY_SV_PACK_POP 75 namespace small_vector_policy {
91 template <
class T, std::
size_t M,
class A,
class B,
class C>
105 typename std::enable_if<
109 if (lastConstructed == realLast) {
114 T* out = realLast - 1;
115 T* in = lastConstructed - 1;
117 for (; in != end && out >= lastConstructed; --in, --out) {
120 for (; in !=
end; --in, --out) {
123 for (; out >= lastConstructed; --out) {
130 if (out < lastConstructed) {
131 out = lastConstructed - 1;
133 for (
auto it = out + 1; it != realLast; ++it) {
144 typename std::enable_if<
148 std::move_backward(first, lastConstructed, realLast);
155 template <
class T,
class Function>
159 for (
size_t i = 0;
i < n; ++
i) {
164 for (std::size_t
i = 0;
i < idx; ++
i) {
171 template <
class SizeType,
bool ShouldUseHeap>
179 return SizeType(~kExternMask);
183 return size_ & ~kExternMask;
187 return kExternMask & size_;
192 size_ |= kExternMask;
194 size_ &= ~kExternMask;
199 assert(sz <= policyMaxSize());
200 size_ = (kExternMask & size_) | SizeType(sz);
208 static bool constexpr kShouldUseHeap = ShouldUseHeap;
211 static SizeType constexpr kExternMask =
212 kShouldUseHeap ? SizeType(1) << (
sizeof(SizeType) * 8 - 1) : 0;
217 template <
class SizeType,
bool ShouldUseHeap>
220 template <
class SizeType>
233 for (; first != last; ++
first, ++idx) {
242 for (std::size_t
i = 0;
i < idx; ++
i) {
253 std::memmove(out, first, (last - first) *
sizeof *first);
262 template <
class T,
class EmplaceFunc>
268 EmplaceFunc&& emplaceFunc) {
271 emplaceFunc(out + pos);
274 this->moveToUninitialized(begin, begin + pos, out);
281 if (begin + pos < end) {
282 this->moveToUninitialized(begin + pos, end, out + pos + 1);
285 for (SizeType
i = 0;
i <= pos; ++
i) {
293 template <
class SizeType>
301 template <
class T,
class EmplaceFunc>
323 namespace mpl = boost::mpl;
326 std::size_t RequestedMaxInline,
331 typedef mpl::vector<InPolicyA, InPolicyB, InPolicyC>
PolicyList;
336 typedef typename mpl::filter_view<
339 typedef typename mpl::eval_if<
340 mpl::empty<Integrals>,
341 mpl::identity<std::size_t>,
346 "Size type should be an unsigned integral type");
349 "Multiple size types specified in small_vector<>");
359 "Multiple copies of small_vector_policy::NoHeap " 360 "supplied; this is probably a mistake");
372 typedef boost::totally_ordered1<
380 return reinterpret_cast<T*
>(
reinterpret_cast<uintptr_t
>(p) | 1);
384 return reinterpret_cast<uintptr_t
>(p) & 1;
388 return reinterpret_cast<T*
>(
reinterpret_cast<uintptr_t
>(p) & ~uintptr_t(1));
391 return static_cast<char*
>(p) + sizeBytes;
399 std::size_t RequestedMaxInline = 1,
400 class PolicyA = void,
401 class PolicyB = void,
402 class PolicyC =
void>
419 static constexpr std::size_t MaxInline{
420 constexpr_max(
sizeof(Value*) /
sizeof(Value), RequestedMaxInline)};
447 if (this->isExtern()) {
456 std::is_nothrow_move_constructible<Value>::
value) {
460 std::uninitialized_copy(
461 std::make_move_iterator(o.begin()),
462 std::make_move_iterator(o.end()),
464 this->setSize(o.size());
473 doConstruct(n, [&](
void* p) {
new (p) value_type(); });
477 doConstruct(n, [&](
void* p) {
new (p) value_type(t); });
485 constructImpl(arg1, arg2, std::is_arithmetic<Arg>());
489 for (
auto&
t : *
this) {
492 if (this->isExtern()) {
523 return !BaseType::kShouldUseHeap ?
static_cast<size_type
>(MaxInline)
524 : BaseType::policyMaxSize();
528 return this->doSize();
543 const_iterator
end()
const {
554 return reverse_iterator(
end());
557 return reverse_iterator(
begin());
561 return const_reverse_iterator(
end());
564 const_reverse_iterator
rend()
const {
565 return const_reverse_iterator(
begin());
571 const_reverse_iterator
crend()
const {
586 if (this->isExtern() && o.isExtern()) {
587 this->swapSizePolicy(o);
589 auto thisCapacity = this->capacity();
592 auto* tmp = u.pdata_.heap_;
593 u.pdata_.heap_ = o.
u.
pdata_.heap_;
596 this->setCapacity(oCapacity);
602 if (!this->isExtern() && !o.isExtern()) {
603 auto& oldSmall =
size() < o.
size() ? *
this : o;
604 auto& oldLarge =
size() < o.
size() ? o : *
this;
606 for (size_type
i = 0;
i < oldSmall.size(); ++
i) {
607 swap(oldSmall[
i], oldLarge[i]);
610 size_type
i = oldSmall.size();
611 const size_type ci =
i;
613 for (; i < oldLarge.size(); ++
i) {
614 auto addr = oldSmall.begin() +
i;
616 oldLarge[
i].~value_type();
620 for (; i < oldLarge.size(); ++
i) {
621 oldLarge[
i].~value_type();
623 oldLarge.setSize(ci);
627 oldLarge.setSize(ci);
632 auto& oldExtern = o.isExtern() ? o : *
this;
633 auto& oldIntern = o.isExtern() ? *
this : o;
635 auto oldExternCapacity = oldExtern.
capacity();
636 auto oldExternHeap = oldExtern.u.pdata_.heap_;
638 auto buff = oldExtern.u.buffer();
641 for (; i < oldIntern.size(); ++
i) {
642 new (&buff[
i]) value_type(
std::move(oldIntern[i]));
643 oldIntern[
i].~value_type();
646 for (size_type kill = 0; kill <
i; ++kill) {
647 buff[kill].~value_type();
649 for (; i < oldIntern.size(); ++
i) {
650 oldIntern[
i].~value_type();
652 oldIntern.setSize(0);
653 oldExtern.u.pdata_.heap_ = oldExternHeap;
654 oldExtern.setCapacity(oldExternCapacity);
657 oldIntern.u.pdata_.heap_ = oldExternHeap;
658 this->swapSizePolicy(o);
659 oldIntern.setCapacity(oldExternCapacity);
669 begin() +
size(), sz -
size(), [&](
void* p) {
new (p) value_type(); });
673 void resize(size_type sz, value_type
const&
v) {
680 begin() +
size(), sz -
size(), [&](
void* p) {
new (p) value_type(v); });
685 return this->isExtern() ? u.heap() : u.buffer();
689 return this->isExtern() ? u.heap() : u.buffer();
692 template <
class...
Args>
695 emplace_back(std::forward<Args>(args)...);
715 return insert(p, value_type(std::forward<Args>(args)...));
723 if (this->isExtern()) {
724 if (u.hasCapacity()) {
725 return u.getCapacity();
727 return malloc_usable_size(u.pdata_.heap_) /
sizeof(value_type);
733 if (!this->isExtern()) {
741 template <
class...
Args>
743 if (capacity() ==
size()) {
749 [&](
void* p) {
new (p) value_type(std::forward<Args>(args)...); },
752 new (
end()) value_type(std::forward<Args>(args)...);
754 this->setSize(
size() + 1);
769 iterator
insert(const_iterator constp, value_type&&
t) {
770 iterator p = unconst(constp);
777 auto offset = p -
begin();
779 if (capacity() ==
size()) {
784 this->setSize(this->
size() + 1);
788 this->setSize(
size() + 1);
791 return begin() + offset;
794 iterator
insert(const_iterator p, value_type
const&
t) {
797 return insert(p, value_type(t));
800 iterator
insert(const_iterator pos, size_type n, value_type
const&
val) {
801 auto offset = pos -
begin();
802 makeSize(
size() + n);
805 this->setSize(
size() + n);
806 std::generate_n(
begin() + offset, n, [&] {
return val; });
807 return begin() + offset;
811 iterator
insert(const_iterator p, Arg arg1, Arg arg2) {
815 return insertImpl(unconst(p), arg1, arg2, std::is_arithmetic<Arg>());
818 iterator
insert(const_iterator p, std::initializer_list<value_type> il) {
819 return insert(p, il.begin(), il.end());
824 (
data() +
size() - 1)->~value_type();
825 this->setSize(
size() - 1);
829 iterator
erase(const_iterator q1, const_iterator q2) {
834 for (
auto it = (
end() - std::distance(q1, q2)); it !=
end(); ++it) {
837 this->setSize(
size() - (q2 - q1));
848 insert(
end(), first, last);
851 void assign(std::initializer_list<value_type> il) {
852 assign(il.begin(), il.end());
855 void assign(size_type n,
const value_type&
t) {
887 reference
at(size_type
i) {
889 throw_exception<std::out_of_range>(
"index out of range");
894 const_reference
at(size_type
i)
const {
896 throw_exception<std::out_of_range>(
"index out of range");
903 return const_cast<iterator
>(it);
910 typedef typename std::iterator_traits<It>::iterator_category categ;
912 auto offset = pos -
begin();
913 while (first != last) {
914 pos = insert(pos, *first++);
917 return begin() + offset;
920 auto distance = std::distance(first, last);
921 auto offset = pos -
begin();
922 makeSize(
size() + distance);
925 this->setSize(
size() + distance);
927 return begin() + offset;
934 return insert(pos, n, val);
942 typedef typename std::iterator_traits<It>::iterator_category categ;
946 while (first != last) {
947 emplace_back(*first++);
952 auto distance = std::distance(first, last);
954 this->setSize(distance);
957 data(), distance, [&](
void* p) {
new (p) value_type(*first++); });
959 if (this->isExtern()) {
966 template <
typename InitFunc>
973 if (this->isExtern()) {
983 doConstruct(n, [&](
void* p) {
new (p) value_type(val); });
990 return std::min((3 * capacity()) / 2 + 1, max_size());
997 template <
typename EmplaceFunc>
998 void makeSize(size_type newSize, EmplaceFunc&& emplaceFunc, size_type pos) {
999 assert(
size() == capacity());
1001 newSize,
true, std::forward<EmplaceFunc>(emplaceFunc), pos);
1014 template <
typename EmplaceFunc>
1018 EmplaceFunc&& emplaceFunc,
1020 if (newSize > max_size()) {
1021 throw std::length_error(
"max_size exceeded in small_vector");
1023 if (newSize <= capacity()) {
1028 assert(this->kShouldUseHeap);
1032 if (!this->kShouldUseHeap) {
1036 newSize =
std::max(newSize, computeNewSize());
1038 auto needBytes = newSize *
sizeof(value_type);
1042 bool heapifyCapacity =
1043 !kHasInlineCapacity && needBytes > kHeapifyCapacityThreshold;
1044 if (heapifyCapacity) {
1045 needBytes += kHeapifyCapacitySize;
1053 value_type* newp =
static_cast<value_type*
>(
1060 this->moveToUninitializedEmplace(
1061 begin(),
end(), newp, pos, std::forward<EmplaceFunc>(emplaceFunc));
1064 this->moveToUninitialized(
begin(),
end(), newp);
1070 for (
auto&
val : *
this) {
1074 if (this->isExtern()) {
1077 auto availableSizeBytes = sizeBytes;
1078 if (heapifyCapacity) {
1080 availableSizeBytes -= kHeapifyCapacitySize;
1082 u.pdata_.heap_ = newh;
1084 this->setExtern(
true);
1085 this->setCapacity(availableSizeBytes /
sizeof(value_type));
1093 assert(this->isExtern());
1094 if (u.hasCapacity()) {
1096 u.setCapacity(newCapacity);
1127 typedef typename std::aligned_storage<
1128 sizeof(value_type) * MaxInline,
1131 typedef typename std::conditional<
1132 sizeof(value_type) * MaxInline != 0,
1133 InlineStorageDataType,
1136 static bool constexpr kHasInlineCapacity =
1140 static size_t constexpr kHeapifyCapacitySize =
sizeof(
1145 static size_t constexpr kHeapifyCapacityThreshold =
1146 100 * kHeapifyCapacitySize;
1148 typedef typename std:: 1154 pdata_.heap_ =
nullptr;
1161 void* vp = &storage_;
1162 return static_cast<value_type*
>(vp);
1169 return static_cast<value_type*
>(pdata_.heap_);
1176 return const_cast<Data*
>(
this)->heap();
1183 return pdata_.getCapacity();
1186 pdata_.setCapacity(c);
1201 template <
class T, std::
size_t MaxInline,
class A,
class B,
class C>
1213 template <
class T,
size_t M,
class A,
class B,
class C>
1223 #undef FOLLY_SV_PACK_ATTR 1224 #undef FOLLY_SV_PACK_PUSH 1225 #undef FOLLY_SV_PACK_POP void reserve(size_type sz)
iterator emplace(const_iterator p, Args &&...args)
T * pointerFlagClear(T *p)
iterator insert(const_iterator p, std::initializer_list< value_type > il)
std::vector< uint8_t > buffer(kBufferSize+16)
iterator insertImpl(iterator pos, It first, It last, std::false_type)
small_vector(std::initializer_list< value_type > il)
const_reference at(size_type i) const
#define FOLLY_GNU_DISABLE_WARNING(warningName)
iterator insertImpl(iterator pos, size_type n, const value_type &val, std::true_type)
#define FOLLY_POP_WARNING
iterator insert(const_iterator p, value_type const &t)
void * checkedMalloc(size_t size)
void setSize(std::size_t sz)
bool operator<(small_vector const &o) const
void swap(small_vector< T, MaxInline, A, B, C > &a, small_vector< T, MaxInline, A, B, C > &b)
reference operator[](size_type i)
iterator insert(const_iterator pos, size_type n, value_type const &val)
#define FOLLY_PUSH_WARNING
reverse_iterator rbegin()
void emplace_back(Args &&...args)
iterator insert(const_iterator p, Arg arg1, Arg arg2)
small_vector(small_vector const &o)
static iterator unconst(const_iterator it)
const_reverse_iterator crbegin() const
SizeType InternalSizeType
small_vector & operator=(small_vector &&o)
#define FOLLY_SV_PACK_POP
std::conditional< sizeof(value_type)*MaxInline!=0, InlineStorageDataType, void * >::type InlineStorageType
static constexpr std::size_t policyMaxSize()
void setCapacity(InternalSizeType c)
small_vector(const std::allocator< Value > &)
mpl::vector< InPolicyA, InPolicyB, InPolicyC > PolicyList
constexpr detail::Map< Move > move
union folly::small_vector::Data u
value_type const & const_reference
const_reference operator[](size_type i) const
void populateMemForward(T *mem, std::size_t n, Function const &op)
static constexpr size_type max_size()
std::enable_if<!folly::is_trivially_copyable< T >::value >::type moveToUninitialized(T *first, T *last, T *out)
auto begin(TestAdlIterable &instance)
iterator erase(const_iterator q1, const_iterator q2)
void resize(size_type sz, value_type const &v)
internal::ArgsMatcher< InnerMatcher > Args(const InnerMatcher &matcher)
#define FOLLY_SV_PACK_PUSH
small_vector & operator=(small_vector const &o)
—— Concurrent Priority Queue Implementation ——
value_type const * heap() const noexcept
void constructImpl(size_type n, value_type const &val, std::true_type)
requires E e noexcept(noexcept(s.error(std::move(e))))
const_reverse_iterator rend() const
std::enable_if< folly::is_trivially_copyable< T >::value >::type moveToUninitialized(T *first, T *last, T *out)
std::conditional< kHasInlineCapacity, HeapPtrWithCapacity, HeapPtr >::type PointerType
value_type * data() noexcept
value_type const * data() const noexcept
bool_constant< true > true_type
InlineStorageType storage_
small_vector(size_type n, value_type const &t)
constexpr T constexpr_max(T a)
std::reverse_iterator< iterator > reverse_iterator
const_reference back() const
void assign(size_type n, const value_type &t)
iterator insert(const_iterator constp, value_type &&t)
void swap(small_vector &o)
void BENCHFUN() push_back(size_t iters, size_t arg)
const_reverse_iterator rbegin() const
void setCapacity(InternalSizeType c)
small_vector(size_type n)
void assign(Arg first, Arg last)
constexpr auto size(C const &c) -> decltype(c.size())
const_iterator begin() const
value_type const * buffer() const noexcept
void doConstruct(size_type n, InitFunc &&func)
constexpr auto empty(C const &c) -> decltype(c.empty())
void push_back(value_type const &t)
void setCapacity(InternalSizeType c)
bool Value(const T &value, M matcher)
mpl::filter_view< PolicyList, std::is_integral< mpl::placeholders::_1 > >::type Integrals
void push_back(value_type &&t)
reference at(size_type i)
std::size_t isExtern() const
void makeSizeInternal(size_type newSize, bool insert, EmplaceFunc &&emplaceFunc, size_type pos)
auto end(TestAdlIterable &instance)
std::ptrdiff_t difference_type
InternalSizeType capacity_
small_vector(Arg arg1, Arg arg2)
size_type computeNewSize() const
void constructImpl(It first, It last, std::false_type)
void swapSizePolicy(IntegralSizePolicyBase &o)
std::is_trivially_copyable< T > is_trivially_copyable
boost::totally_ordered1< small_vector< Value, RequestedMaxInline, InPolicyA, InPolicyB, InPolicyC >, ActualSizePolicy > type
static const char *const value
void * shiftPointer(void *p, size_t sizeBytes)
void resize(size_type sz)
void makeSize(size_type newSize)
**Optimized Holders **The template hazptr_array< M > provides most of the functionality *of M hazptr_holder s but with faster construction destruction *for M
InternalSizeType getCapacity() const
value_type * buffer() noexcept
small_vector(small_vector &&o) noexcept(std::is_nothrow_move_constructible< Value >::value)
const_reference front() const
#define FOLLY_SV_PACK_ATTR
std::reverse_iterator< const_iterator > const_reverse_iterator
std::pair< InIt, OutIt > copy_n(InIt b, typename std::iterator_traits< InIt >::difference_type n, OutIt d)
bool operator==(small_vector const &o) const
std::enable_if< !std::is_default_constructible< T >::value||folly::is_trivially_copyable< T >::value >::type moveObjectsRight(T *first, T *lastConstructed, T *realLast)
void moveToUninitializedEmplace(T *, T *, T *, SizeType, EmplaceFunc &&)
const_reverse_iterator crend() const
void assume_unreachable()
iterator erase(const_iterator q)
void moveToUninitializedEmplace(T *begin, T *end, T *out, SizeType pos, EmplaceFunc &&emplaceFunc)
bool_constant< false > false_type
std::aligned_storage< sizeof(value_type)*MaxInline, alignof(value_type)>::type InlineStorageDataType
mpl::count< PolicyList, small_vector_policy::NoHeap >::type HasNoHeap
mpl::eval_if< mpl::empty< Integrals >, mpl::identity< std::size_t >, mpl::front< Integrals > >::type SizeType
const_iterator cbegin() const
const_iterator end() const
value_type const * const_iterator
void makeSize(size_type newSize, EmplaceFunc &&emplaceFunc, size_type pos)
const_iterator cend() const
IntegralSizePolicy< SizeType,!HasNoHeap::value > ActualSizePolicy
BaseType::InternalSizeType InternalSizeType
void moveToUninitialized(T *, T *, T *)
static constexpr uint64_t data[1]
ThreadPoolListHook * addr
value_type const * const_pointer
InternalSizeType getCapacity() const
InternalSizeType getCapacity() const
bool pointerFlagGet(T *p)
void assign(std::initializer_list< value_type > il)
void setCapacity(size_type newCapacity)
std::size_t doSize() const
Iterator< typename Container::const_iterator > cend(const Container &c)
detail::small_vector_base< Value, RequestedMaxInline, PolicyA, PolicyB, PolicyC >::type BaseType
constexpr detail::First first
size_t goodMallocSize(size_t minSize) noexcept
value_type * heap() noexcept
size_type capacity() const