#include <folly/FormatTraits.h>
#include <folly/Likely.h>
-#include <folly/Malloc.h>
#include <folly/Traits.h>
+#include <folly/memory/Malloc.h>
#include <folly/portability/BitsFunctexcept.h>
//=============================================================================
// forward declaration
namespace folly {
- template <class T, class Allocator = std::allocator<T>>
- class fbvector;
-}
+template <class T, class Allocator = std::allocator<T>>
+class fbvector;
+} // namespace folly
//=============================================================================
// unrolling
//===========================================================================
//---------------------------------------------------------------------------
// implementation
-private:
-
+ private:
typedef std::allocator_traits<Allocator> A;
struct Impl : public Allocator {
static void swap(Impl& a, Impl& b) {
using std::swap;
- if (!usingStdAllocator::value) swap<Allocator>(a, b);
+ if (!usingStdAllocator::value) {
+ swap<Allocator>(a, b);
+ }
a.swapData(b);
}
//===========================================================================
//---------------------------------------------------------------------------
// types and constants
-public:
-
+ public:
typedef T value_type;
typedef value_type& reference;
typedef const value_type& const_reference;
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
-private:
-
+ private:
typedef std::integral_constant<bool,
IsTriviallyCopyable<T>::value &&
sizeof(T) <= 16 // don't force large structures to be passed by value
//===========================================================================
//---------------------------------------------------------------------------
// allocator helpers
-private:
-
+ private:
//---------------------------------------------------------------------------
// allocate
void M_destroy(T* p) noexcept {
if (usingStdAllocator::value) {
- if (!std::is_trivially_destructible<T>::value)
+ if (!std::is_trivially_destructible<T>::value) {
p->~T();
+ }
} else {
std::allocator_traits<Allocator>::destroy(impl_, p);
}
//===========================================================================
//---------------------------------------------------------------------------
// algorithmic helpers
-private:
-
+ private:
//---------------------------------------------------------------------------
// destroy_range
// allocator
static void S_destroy_range_a(Allocator& a, T* first, T* last) noexcept {
- for (; first != last; ++first)
+ for (; first != last; ++first) {
std::allocator_traits<Allocator>::destroy(a, first);
+ }
}
// optimized
auto b = dest;
auto e = dest + sz;
try {
- for (; b != e; ++b)
+ for (; b != e; ++b) {
std::allocator_traits<Allocator>::construct(a, b,
std::forward<Args>(args)...);
+ }
} catch (...) {
S_destroy_range_a(a, dest, b);
throw;
auto b = dest;
auto e = dest + n;
try {
- for (; b != e; ++b) S_construct(b);
+ for (; b != e; ++b) {
+ S_construct(b);
+ }
} catch (...) {
--b;
- for (; b >= dest; --b) b->~T();
+ for (; b >= dest; --b) {
+ b->~T();
+ }
throw;
}
}
auto b = dest;
auto e = dest + n;
try {
- for (; b != e; ++b) S_construct(b, value);
+ for (; b != e; ++b) {
+ S_construct(b, value);
+ }
} catch (...) {
S_destroy_range(dest, b);
throw;
S_uninitialized_copy_a(Allocator& a, T* dest, It first, It last) {
auto b = dest;
try {
- for (; first != last; ++first, ++b)
+ for (; first != last; ++first, ++b) {
std::allocator_traits<Allocator>::construct(a, b, *first);
+ }
} catch (...) {
S_destroy_range_a(a, dest, b);
throw;
static void S_uninitialized_copy(T* dest, It first, It last) {
auto b = dest;
try {
- for (; first != last; ++first, ++b)
+ for (; first != last; ++first, ++b) {
S_construct(b, *first);
+ }
} catch (...) {
S_destroy_range(dest, b);
throw;
template <typename It>
static It S_copy_n(T* dest, It first, size_type n) {
auto e = dest + n;
- for (; dest != e; ++dest, ++first) *dest = *first;
+ for (; dest != e; ++dest, ++first) {
+ *dest = *first;
+ }
return first;
}
//===========================================================================
//---------------------------------------------------------------------------
// relocation helpers
-private:
-
+ private:
// Relocation is divided into three parts:
//
// 1: relocate_move
//===========================================================================
//---------------------------------------------------------------------------
// construct/copy/destroy
-public:
-
+ public:
fbvector() = default;
explicit fbvector(const Allocator& a) : impl_(a) {}
~fbvector() = default; // the cleanup occurs in impl_
fbvector& operator=(const fbvector& other) {
- if (UNLIKELY(this == &other)) return *this;
+ if (UNLIKELY(this == &other)) {
+ return *this;
+ }
if (!usingStdAllocator::value &&
A::propagate_on_container_copy_assignment::value) {
}
fbvector& operator=(fbvector&& other) {
- if (UNLIKELY(this == &other)) return *this;
+ if (UNLIKELY(this == &other)) {
+ return *this;
+ }
moveFrom(std::move(other), moveIsSwap());
return *this;
}
return impl_;
}
-private:
-
+ private:
// contract dispatch for iterator types fbvector(It first, It last)
template <class ForwardIterator>
fbvector(ForwardIterator first, ForwardIterator last,
{ M_uninitialized_copy_e(first, last); }
template <class InputIterator>
- fbvector(InputIterator first, InputIterator last,
- const Allocator& a, std::input_iterator_tag)
- : impl_(a)
- { for (; first != last; ++first) emplace_back(*first); }
+ fbvector(
+ InputIterator first,
+ InputIterator last,
+ const Allocator& a,
+ std::input_iterator_tag)
+ : impl_(a) {
+ for (; first != last; ++first) {
+ emplace_back(*first);
+ }
+ }
// contract dispatch for allocator movement in operator=(fbvector&&)
void
if (p != impl_.e_) {
M_destroy_range_e(p);
} else {
- for (; first != last; ++first) emplace_back(*first);
+ for (; first != last; ++first) {
+ emplace_back(*first);
+ }
}
}
// contract dispatch for aliasing under VT optimization
bool dataIsInternalAndNotVT(const T& t) {
- if (should_pass_by_value::value) return false;
+ if (should_pass_by_value::value) {
+ return false;
+ }
return dataIsInternal(t);
}
bool dataIsInternal(const T& t) {
//===========================================================================
//---------------------------------------------------------------------------
// iterators
-public:
-
+ public:
iterator begin() noexcept {
return impl_.b_;
}
//===========================================================================
//---------------------------------------------------------------------------
// capacity
-public:
-
+ public:
size_type size() const noexcept {
return size_type(impl_.e_ - impl_.b_);
}
}
void reserve(size_type n) {
- if (n <= capacity()) return;
- if (impl_.b_ && reserve_in_place(n)) return;
+ if (n <= capacity()) {
+ return;
+ }
+ if (impl_.b_ && reserve_in_place(n)) {
+ return;
+ }
auto newCap = folly::goodMallocSize(n * sizeof(T)) / sizeof(T);
auto newB = M_allocate(newCap);
M_deallocate(newB, newCap);
throw;
}
- if (impl_.b_)
+ if (impl_.b_) {
M_deallocate(impl_.b_, size_type(impl_.z_ - impl_.b_));
+ }
impl_.z_ = newB + newCap;
impl_.e_ = newB + (impl_.e_ - impl_.b_);
impl_.b_ = newB;
auto const newCap = newCapacityBytes / sizeof(T);
auto const oldCap = capacity();
- if (newCap >= oldCap) return;
+ if (newCap >= oldCap) {
+ return;
+ }
void* p = impl_.b_;
// xallocx() will shrink to precisely newCapacityBytes (which was generated
} catch (...) {
return;
}
- if (impl_.b_)
+ if (impl_.b_) {
M_deallocate(impl_.b_, size_type(impl_.z_ - impl_.b_));
+ }
impl_.z_ = newB + newCap;
impl_.e_ = newB + (impl_.e_ - impl_.b_);
impl_.b_ = newB;
}
}
-private:
-
+ private:
bool reserve_in_place(size_type n) {
- if (!usingStdAllocator::value || !usingJEMalloc()) 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) <
- folly::jemallocMinInPlaceExpandable) return false;
+ folly::jemallocMinInPlaceExpandable) {
+ return false;
+ }
auto const newCapacityBytes = folly::goodMallocSize(n * sizeof(T));
void* p = impl_.b_;
//===========================================================================
//---------------------------------------------------------------------------
// element access
-public:
-
+ public:
reference operator[](size_type n) {
assert(n < size());
return impl_.b_[n];
//===========================================================================
//---------------------------------------------------------------------------
// data access
-public:
-
+ public:
T* data() noexcept {
return impl_.b_;
}
//===========================================================================
//---------------------------------------------------------------------------
// modifiers (common)
-public:
-
+ public:
template <class... Args>
void emplace_back(Args&&... args) {
if (impl_.e_ != impl_.z_) {
}
void swap(fbvector& other) noexcept {
- if (!usingStdAllocator::value &&
- A::propagate_on_container_swap::value)
+ if (!usingStdAllocator::value && A::propagate_on_container_swap::value) {
swap(impl_, other.impl_);
- else impl_.swapData(other.impl_);
+ } else {
+ impl_.swapData(other.impl_);
+ }
}
void clear() noexcept {
M_destroy_range_e(impl_.b_);
}
-private:
-
+ private:
// std::vector implements a similar function with a different growth
// strategy: empty() ? 1 : capacity() * 2.
//
//===========================================================================
//---------------------------------------------------------------------------
// modifiers (erase)
-public:
-
+ public:
iterator erase(const_iterator position) {
return erase(position, position + 1);
}
//===========================================================================
//---------------------------------------------------------------------------
// modifiers (insert)
-private: // we have the private section first because it defines some macros
-
+ private: // we have the private section first because it defines some macros
bool isValid(const_iterator it) {
return cbegin() <= it && it <= 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;
+ if (size() + n <= capacity()) {
+ return false;
+ }
+ if (reserve_in_place(size() + n)) {
+ return false;
+ }
return true;
}
- if (size() + n > capacity()) return true;
+ if (size() + n > capacity()) {
+ return true;
+ }
return false;
}
//---------------------------------------------------------------------------
// insert dispatch for iterator types
-private:
-
+ private:
template <class FIt>
iterator insert(const_iterator cpos, FIt first, FIt last,
std::forward_iterator_tag) {
std::make_move_iterator(end()),
A::select_on_container_copy_construction(impl_));
M_destroy_range_e(position);
- for (; first != last; ++first) emplace_back(*first);
+ for (; first != last; ++first) {
+ emplace_back(*first);
+ }
insert(cend(), std::make_move_iterator(storage.begin()),
std::make_move_iterator(storage.end()));
return impl_.b_ + idx;
//===========================================================================
//---------------------------------------------------------------------------
// lexicographical functions
-public:
-
+ public:
bool operator==(const fbvector& other) const {
return size() == other.size() && std::equal(begin(), end(), other.begin());
}
//===========================================================================
//---------------------------------------------------------------------------
// friends
-private:
-
+ private:
template <class _T, class _A>
friend _T* relinquish(fbvector<_T, _A>&);
M_deallocate(newB, sz);
throw;
}
- if (impl_.b_) M_deallocate(impl_.b_, size());
+ if (impl_.b_) {
+ M_deallocate(impl_.b_, size());
+ }
impl_.b_ = newB;
impl_.e_ = newE;
impl_.z_ = newB + sz;
: public IndexableTraitsSeq<fbvector<T, A>> {
};
-} // namespace detail
+} // namespace detail
template <class T, class A>
void compactResize(fbvector<T, A>* v, size_t sz) {