llvm-project/libcxx/include/vector

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

3324 lines
115 KiB
Plaintext
Raw Normal View History

2010-05-12 03:42:16 +08:00
// -*- C++ -*-
//===----------------------------------------------------------------------===//
2010-05-12 03:42:16 +08:00
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2010-05-12 03:42:16 +08:00
//
//===----------------------------------------------------------------------===//
#ifndef _LIBCPP_VECTOR
#define _LIBCPP_VECTOR
/*
vector synopsis
namespace std
{
template <class T, class Allocator = allocator<T> >
2010-05-12 03:42:16 +08:00
class vector
{
public:
typedef T value_type;
2010-05-12 03:42:16 +08:00
typedef Allocator allocator_type;
typedef typename allocator_type::reference reference;
typedef typename allocator_type::const_reference const_reference;
typedef implementation-defined iterator;
typedef implementation-defined const_iterator;
typedef typename allocator_type::size_type size_type;
typedef typename allocator_type::difference_type difference_type;
typedef typename allocator_type::pointer pointer;
typedef typename allocator_type::const_pointer const_pointer;
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
vector()
noexcept(is_nothrow_default_constructible<allocator_type>::value);
explicit vector(const allocator_type&);
2010-05-12 03:42:16 +08:00
explicit vector(size_type n);
explicit vector(size_type n, const allocator_type&); // C++14
2010-05-12 03:42:16 +08:00
vector(size_type n, const value_type& value, const allocator_type& = allocator_type());
template <class InputIterator>
vector(InputIterator first, InputIterator last, const allocator_type& = allocator_type());
vector(const vector& x);
vector(vector&& x)
noexcept(is_nothrow_move_constructible<allocator_type>::value);
2010-05-12 03:42:16 +08:00
vector(initializer_list<value_type> il);
vector(initializer_list<value_type> il, const allocator_type& a);
~vector();
vector& operator=(const vector& x);
vector& operator=(vector&& x)
noexcept(
allocator_type::propagate_on_container_move_assignment::value ||
allocator_type::is_always_equal::value); // C++17
2010-05-12 03:42:16 +08:00
vector& operator=(initializer_list<value_type> il);
template <class InputIterator>
void assign(InputIterator first, InputIterator last);
void assign(size_type n, const value_type& u);
void assign(initializer_list<value_type> il);
allocator_type get_allocator() const noexcept;
2010-05-12 03:42:16 +08:00
iterator begin() noexcept;
const_iterator begin() const noexcept;
iterator end() noexcept;
const_iterator end() const noexcept;
2010-05-12 03:42:16 +08:00
reverse_iterator rbegin() noexcept;
const_reverse_iterator rbegin() const noexcept;
reverse_iterator rend() noexcept;
const_reverse_iterator rend() const noexcept;
2010-05-12 03:42:16 +08:00
const_iterator cbegin() const noexcept;
const_iterator cend() const noexcept;
const_reverse_iterator crbegin() const noexcept;
const_reverse_iterator crend() const noexcept;
2010-05-12 03:42:16 +08:00
size_type size() const noexcept;
size_type max_size() const noexcept;
size_type capacity() const noexcept;
bool empty() const noexcept;
2010-05-12 03:42:16 +08:00
void reserve(size_type n);
void shrink_to_fit() noexcept;
2010-05-12 03:42:16 +08:00
reference operator[](size_type n);
const_reference operator[](size_type n) const;
reference at(size_type n);
const_reference at(size_type n) const;
reference front();
const_reference front() const;
reference back();
const_reference back() const;
value_type* data() noexcept;
const value_type* data() const noexcept;
2010-05-12 03:42:16 +08:00
void push_back(const value_type& x);
void push_back(value_type&& x);
template <class... Args>
reference emplace_back(Args&&... args); // reference in C++17
2010-05-12 03:42:16 +08:00
void pop_back();
template <class... Args> iterator emplace(const_iterator position, Args&&... args);
iterator insert(const_iterator position, const value_type& x);
iterator insert(const_iterator position, value_type&& x);
iterator insert(const_iterator position, size_type n, const value_type& x);
template <class InputIterator>
iterator insert(const_iterator position, InputIterator first, InputIterator last);
iterator insert(const_iterator position, initializer_list<value_type> il);
iterator erase(const_iterator position);
iterator erase(const_iterator first, const_iterator last);
void clear() noexcept;
2010-05-12 03:42:16 +08:00
void resize(size_type sz);
void resize(size_type sz, const value_type& c);
void swap(vector&)
noexcept(allocator_traits<allocator_type>::propagate_on_container_swap::value ||
allocator_traits<allocator_type>::is_always_equal::value); // C++17
2010-05-12 03:42:16 +08:00
bool __invariants() const;
};
2010-05-12 03:42:16 +08:00
template <class Allocator = allocator<T> >
2010-05-12 03:42:16 +08:00
class vector<bool, Allocator>
{
public:
typedef bool value_type;
2010-05-12 03:42:16 +08:00
typedef Allocator allocator_type;
typedef implementation-defined iterator;
typedef implementation-defined const_iterator;
typedef typename allocator_type::size_type size_type;
typedef typename allocator_type::difference_type difference_type;
typedef iterator pointer;
typedef const_iterator const_pointer;
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
class reference
{
public:
reference(const reference&) noexcept;
operator bool() const noexcept;
reference& operator=(bool x) noexcept;
reference& operator=(const reference& x) noexcept;
iterator operator&() const noexcept;
void flip() noexcept;
2010-05-12 03:42:16 +08:00
};
class const_reference
{
public:
const_reference(const reference&) noexcept;
operator bool() const noexcept;
const_iterator operator&() const noexcept;
2010-05-12 03:42:16 +08:00
};
vector()
noexcept(is_nothrow_default_constructible<allocator_type>::value);
explicit vector(const allocator_type&);
explicit vector(size_type n, const allocator_type& a = allocator_type()); // C++14
vector(size_type n, const value_type& value, const allocator_type& = allocator_type());
2010-05-12 03:42:16 +08:00
template <class InputIterator>
vector(InputIterator first, InputIterator last, const allocator_type& = allocator_type());
vector(const vector& x);
vector(vector&& x)
noexcept(is_nothrow_move_constructible<allocator_type>::value);
2010-05-12 03:42:16 +08:00
vector(initializer_list<value_type> il);
vector(initializer_list<value_type> il, const allocator_type& a);
~vector();
vector& operator=(const vector& x);
vector& operator=(vector&& x)
noexcept(
allocator_type::propagate_on_container_move_assignment::value ||
allocator_type::is_always_equal::value); // C++17
2010-05-12 03:42:16 +08:00
vector& operator=(initializer_list<value_type> il);
template <class InputIterator>
void assign(InputIterator first, InputIterator last);
void assign(size_type n, const value_type& u);
void assign(initializer_list<value_type> il);
allocator_type get_allocator() const noexcept;
2010-05-12 03:42:16 +08:00
iterator begin() noexcept;
const_iterator begin() const noexcept;
iterator end() noexcept;
const_iterator end() const noexcept;
2010-05-12 03:42:16 +08:00
reverse_iterator rbegin() noexcept;
const_reverse_iterator rbegin() const noexcept;
reverse_iterator rend() noexcept;
const_reverse_iterator rend() const noexcept;
2010-05-12 03:42:16 +08:00
const_iterator cbegin() const noexcept;
const_iterator cend() const noexcept;
const_reverse_iterator crbegin() const noexcept;
const_reverse_iterator crend() const noexcept;
2010-05-12 03:42:16 +08:00
size_type size() const noexcept;
size_type max_size() const noexcept;
size_type capacity() const noexcept;
bool empty() const noexcept;
2010-05-12 03:42:16 +08:00
void reserve(size_type n);
void shrink_to_fit() noexcept;
2010-05-12 03:42:16 +08:00
reference operator[](size_type n);
const_reference operator[](size_type n) const;
reference at(size_type n);
const_reference at(size_type n) const;
reference front();
const_reference front() const;
reference back();
const_reference back() const;
void push_back(const value_type& x);
template <class... Args> reference emplace_back(Args&&... args); // C++14; reference in C++17
2010-05-12 03:42:16 +08:00
void pop_back();
template <class... Args> iterator emplace(const_iterator position, Args&&... args); // C++14
2010-05-12 03:42:16 +08:00
iterator insert(const_iterator position, const value_type& x);
iterator insert(const_iterator position, size_type n, const value_type& x);
template <class InputIterator>
iterator insert(const_iterator position, InputIterator first, InputIterator last);
iterator insert(const_iterator position, initializer_list<value_type> il);
iterator erase(const_iterator position);
iterator erase(const_iterator first, const_iterator last);
void clear() noexcept;
2010-05-12 03:42:16 +08:00
void resize(size_type sz);
void resize(size_type sz, value_type x);
void swap(vector&)
noexcept(allocator_traits<allocator_type>::propagate_on_container_swap::value ||
allocator_traits<allocator_type>::is_always_equal::value); // C++17
void flip() noexcept;
2010-05-12 03:42:16 +08:00
bool __invariants() const;
};
2010-05-12 03:42:16 +08:00
template <class InputIterator, class Allocator = allocator<typename iterator_traits<InputIterator>::value_type>>
vector(InputIterator, InputIterator, Allocator = Allocator())
-> vector<typename iterator_traits<InputIterator>::value_type, Allocator>; // C++17
2010-05-12 03:42:16 +08:00
template <class Allocator> struct hash<std::vector<bool, Allocator>>;
template <class T, class Allocator> bool operator==(const vector<T,Allocator>& x, const vector<T,Allocator>& y);
template <class T, class Allocator> bool operator< (const vector<T,Allocator>& x, const vector<T,Allocator>& y);
template <class T, class Allocator> bool operator!=(const vector<T,Allocator>& x, const vector<T,Allocator>& y);
template <class T, class Allocator> bool operator> (const vector<T,Allocator>& x, const vector<T,Allocator>& y);
template <class T, class Allocator> bool operator>=(const vector<T,Allocator>& x, const vector<T,Allocator>& y);
template <class T, class Allocator> bool operator<=(const vector<T,Allocator>& x, const vector<T,Allocator>& y);
template <class T, class Allocator>
void swap(vector<T,Allocator>& x, vector<T,Allocator>& y)
noexcept(noexcept(x.swap(y)));
2010-05-12 03:42:16 +08:00
template <class T, class Allocator, class U>
typename vector<T, Allocator>::size_type
erase(vector<T, Allocator>& c, const U& value); // C++20
template <class T, class Allocator, class Predicate>
typename vector<T, Allocator>::size_type
erase_if(vector<T, Allocator>& c, Predicate pred); // C++20
2010-05-12 03:42:16 +08:00
} // std
*/
#include <__algorithm/copy.h>
#include <__algorithm/equal.h>
#include <__algorithm/fill_n.h>
#include <__algorithm/lexicographical_compare.h>
#include <__algorithm/remove.h>
#include <__algorithm/remove_if.h>
#include <__algorithm/rotate.h>
#include <__algorithm/unwrap_iter.h>
#include <__assert> // all public C++ headers provide the assertion handler
2010-05-12 03:42:16 +08:00
#include <__bit_reference>
#include <__config>
#include <__debug>
#include <__format/enable_insertable.h>
#include <__functional/hash.h>
#include <__functional/unary_function.h>
#include <__iterator/advance.h>
#include <__iterator/iterator_traits.h>
#include <__iterator/reverse_iterator.h>
#include <__iterator/wrap_iter.h>
#include <__memory/allocate_at_least.h>
#include <__memory/pointer_traits.h>
#include <__memory/swap_allocator.h>
#include <__split_buffer>
#include <__utility/forward.h>
#include <__utility/move.h>
#include <__utility/swap.h>
2010-05-12 03:42:16 +08:00
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iosfwd> // for forward declaration of vector
#include <limits>
2010-05-12 03:42:16 +08:00
#include <memory>
#include <stdexcept>
#include <type_traits>
#include <version>
Ok, 3 major changes for debug mode in one commit: 1. I had been detecting and trapping iterator == and \!= among iterators in different containers as an error. But the trapping itself is actually an error. Consider: #include <iostream> #include <vector> #include <algorithm> template <class C> void display(const C& c) { std::cout << "{"; bool first = true; for (const auto& x : c) { if (\!first) std::cout << ", "; first = false; std::cout << x; } std::cout << "}\n"; } int main() { typedef std::vector<int> V; V v1 = {1, 3, 5}; V v2 = {2, 4, 6}; display(v1); display(v2); V::iterator i = std::find(v1.begin(), v1.end(), 1); V::iterator j = std::find(v2.begin(), v2.end(), 2); if (*i == *j) i = j; // perfectly legal // ... if (i \!= j) // the only way to check v2.push_back(*i); display(v1); display(v2); } It is legal to assign an iterator from one container to another of the same type. This is required to work. One might want to test whether or not such an assignment had been made. The way one performs such a check is using the iterator's ==, \!= operator. This is a logical and necessary function and does not constitute an error. 2. I had a header circular dependence bug when _LIBCPP_DEBUG2 is defined. This caused a problem in several of the libc++ tests. Fixed. 3. There is a serious problem when _LIBCPP_DEBUG2=1 at the moment in that std::basic_string is inoperable. std::basic_string uses __wrap_iterator to implement its iterators. __wrap_iterator has been rigged up in debug mode to support vector. But string hasn't been rigged up yet. This means that one gets false positives when using std::string in debug mode. I've upped std::string's priority in www/debug_mode.html. llvm-svn: 187636
2013-08-02 08:26:35 +08:00
[libc++] Re-add transitive includes that had been removed since LLVM 14 This commit re-adds transitive includes that had been removed by 4cd04d1687f1, c36870c8e79c, a83f4b9cda57, 1458458b558d, 2e2f3158c604, and 489637e66dd3. This should cover almost all the includes that had been removed since LLVM 14 and that would contribute to breaking user code when releasing LLVM 15. It is possible to disable the inclusion of these headers by defining _LIBCPP_REMOVE_TRANSITIVE_INCLUDES. The intent is that vendors will enable that macro and start fixing downstream issues immediately. We can then remove the macro (and the transitive includes) by default in a future release. That way, we will break users only once by removing transitive includes in bulk instead of doing it bit by bit a every release, which is more disruptive for users. Note 1: The set of headers to re-add was found by re-generating the transitive include test on a checkout of release/14.x, which provided the list of all transitive includes we used to provide. Note 2: Several includes of <vector>, <optional>, <array> and <unordered_map> have been added in this commit. These transitive inclusions were added when we implemented boyer_moore_searcher in <functional>. Note 3: This is a best effort patch to try and resolve downstream breakage caused since branching LLVM 14. I wasn't able to perfectly mirror transitive includes in LLVM 14 for a few headers, so I added a release note explaining it. To summarize, adding boyer_moore_searcher created a bunch of circular dependencies, so we have to break backwards compatibility in a few cases. Differential Revision: https://reviews.llvm.org/D128661
2022-06-28 03:53:41 +08:00
#ifndef _LIBCPP_REMOVE_TRANSITIVE_INCLUDES
# include <algorithm>
# include <typeinfo>
# include <utility>
#endif
// standard-mandated includes
// [iterator.range]
#include <__iterator/access.h>
#include <__iterator/data.h>
#include <__iterator/empty.h>
#include <__iterator/reverse_access.h>
#include <__iterator/size.h>
// [vector.syn]
#include <compare>
#include <initializer_list>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif
2010-05-12 03:42:16 +08:00
_LIBCPP_PUSH_MACROS
#include <__undef_macros>
2010-05-12 03:42:16 +08:00
_LIBCPP_BEGIN_NAMESPACE_STD
template <class _Tp, class _Allocator /* = allocator<_Tp> */>
class _LIBCPP_TEMPLATE_VIS vector
2010-05-12 03:42:16 +08:00
{
private:
typedef allocator<_Tp> __default_allocator_type;
public:
typedef vector __self;
typedef _Tp value_type;
typedef _Allocator allocator_type;
typedef allocator_traits<allocator_type> __alloc_traits;
typedef value_type& reference;
typedef const value_type& const_reference;
typedef typename __alloc_traits::size_type size_type;
typedef typename __alloc_traits::difference_type difference_type;
typedef typename __alloc_traits::pointer pointer;
typedef typename __alloc_traits::const_pointer const_pointer;
typedef __wrap_iter<pointer> iterator;
typedef __wrap_iter<const_pointer> const_iterator;
typedef _VSTD::reverse_iterator<iterator> reverse_iterator;
typedef _VSTD::reverse_iterator<const_iterator> const_reverse_iterator;
2010-05-12 03:42:16 +08:00
static_assert((is_same<typename allocator_type::value_type, value_type>::value),
"Allocator::value_type must be same type as value_type");
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY
vector() _NOEXCEPT_(is_nothrow_default_constructible<allocator_type>::value)
{
_VSTD::__debug_db_insert_c(this);
}
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY explicit vector(const allocator_type& __a)
#if _LIBCPP_STD_VER <= 14
_NOEXCEPT_(is_nothrow_copy_constructible<allocator_type>::value)
#else
_NOEXCEPT
#endif
: __end_cap_(nullptr, __a)
{
_VSTD::__debug_db_insert_c(this);
}
_LIBCPP_CONSTEXPR_AFTER_CXX17 explicit vector(size_type __n);
#if _LIBCPP_STD_VER > 11
_LIBCPP_CONSTEXPR_AFTER_CXX17 explicit vector(size_type __n, const allocator_type& __a);
#endif
_LIBCPP_CONSTEXPR_AFTER_CXX17 vector(size_type __n, const value_type& __x);
template <class = __enable_if_t<__is_allocator<_Allocator>::value> >
_LIBCPP_CONSTEXPR_AFTER_CXX17
vector(size_type __n, const value_type& __x, const allocator_type& __a)
: __end_cap_(nullptr, __a)
{
_VSTD::__debug_db_insert_c(this);
if (__n > 0)
{
__vallocate(__n);
__construct_at_end(__n, __x);
}
}
2010-05-12 03:42:16 +08:00
template <class _InputIterator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
vector(_InputIterator __first,
typename enable_if<__is_exactly_cpp17_input_iterator<_InputIterator>::value &&
is_constructible<
value_type,
typename iterator_traits<_InputIterator>::reference>::value,
_InputIterator>::type __last);
2010-05-12 03:42:16 +08:00
template <class _InputIterator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
vector(_InputIterator __first, _InputIterator __last, const allocator_type& __a,
typename enable_if<__is_exactly_cpp17_input_iterator<_InputIterator>::value &&
is_constructible<
value_type,
typename iterator_traits<_InputIterator>::reference>::value>::type* = 0);
2010-05-12 03:42:16 +08:00
template <class _ForwardIterator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
vector(_ForwardIterator __first,
typename enable_if<__is_cpp17_forward_iterator<_ForwardIterator>::value &&
is_constructible<
value_type,
typename iterator_traits<_ForwardIterator>::reference>::value,
_ForwardIterator>::type __last);
2010-05-12 03:42:16 +08:00
template <class _ForwardIterator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
vector(_ForwardIterator __first, _ForwardIterator __last, const allocator_type& __a,
typename enable_if<__is_cpp17_forward_iterator<_ForwardIterator>::value &&
is_constructible<
value_type,
typename iterator_traits<_ForwardIterator>::reference>::value>::type* = 0);
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY
~vector()
{
__annotate_delete();
std::__debug_db_erase_c(this);
if (this->__begin_ != nullptr)
{
__clear();
__alloc_traits::deallocate(__alloc(), this->__begin_, capacity());
}
}
2010-05-12 03:42:16 +08:00
_LIBCPP_CONSTEXPR_AFTER_CXX17 vector(const vector& __x);
_LIBCPP_CONSTEXPR_AFTER_CXX17 vector(const vector& __x, const __type_identity_t<allocator_type>& __a);
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY
2010-05-12 03:42:16 +08:00
vector& operator=(const vector& __x);
#ifndef _LIBCPP_CXX03_LANG
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY
vector(initializer_list<value_type> __il);
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY
vector(initializer_list<value_type> __il, const allocator_type& __a);
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY
vector& operator=(initializer_list<value_type> __il)
{assign(__il.begin(), __il.end()); return *this;}
#endif // !_LIBCPP_CXX03_LANG
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY
vector(vector&& __x)
#if _LIBCPP_STD_VER > 14
noexcept;
#else
_NOEXCEPT_(is_nothrow_move_constructible<allocator_type>::value);
#endif
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY
vector(vector&& __x, const __type_identity_t<allocator_type>& __a);
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY
vector& operator=(vector&& __x)
_NOEXCEPT_((__noexcept_move_assign_container<_Allocator, __alloc_traits>::value));
2010-05-12 03:42:16 +08:00
template <class _InputIterator>
_LIBCPP_CONSTEXPR_AFTER_CXX17 typename enable_if <__is_exactly_cpp17_input_iterator<_InputIterator>::value &&
is_constructible<
value_type,
typename iterator_traits<_InputIterator>::reference>::value,
2010-05-12 03:42:16 +08:00
void
>::type
assign(_InputIterator __first, _InputIterator __last);
template <class _ForwardIterator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
typename enable_if
<
__is_cpp17_forward_iterator<_ForwardIterator>::value &&
is_constructible<
value_type,
typename iterator_traits<_ForwardIterator>::reference>::value,
2010-05-12 03:42:16 +08:00
void
>::type
assign(_ForwardIterator __first, _ForwardIterator __last);
_LIBCPP_CONSTEXPR_AFTER_CXX17 void assign(size_type __n, const_reference __u);
#ifndef _LIBCPP_CXX03_LANG
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY
2010-05-12 03:42:16 +08:00
void assign(initializer_list<value_type> __il)
{assign(__il.begin(), __il.end());}
#endif
2010-05-12 03:42:16 +08:00
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY
allocator_type get_allocator() const _NOEXCEPT
{return this->__alloc();}
2010-05-12 03:42:16 +08:00
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY iterator begin() _NOEXCEPT;
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY const_iterator begin() const _NOEXCEPT;
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY iterator end() _NOEXCEPT;
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY const_iterator end() const _NOEXCEPT;
2010-05-12 03:42:16 +08:00
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY
reverse_iterator rbegin() _NOEXCEPT
{return reverse_iterator(end());}
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY
const_reverse_iterator rbegin() const _NOEXCEPT
{return const_reverse_iterator(end());}
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY
reverse_iterator rend() _NOEXCEPT
{return reverse_iterator(begin());}
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY
const_reverse_iterator rend() const _NOEXCEPT
{return const_reverse_iterator(begin());}
2010-05-12 03:42:16 +08:00
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY
const_iterator cbegin() const _NOEXCEPT
{return begin();}
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY
const_iterator cend() const _NOEXCEPT
{return end();}
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY
const_reverse_iterator crbegin() const _NOEXCEPT
{return rbegin();}
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY
const_reverse_iterator crend() const _NOEXCEPT
{return rend();}
2010-05-12 03:42:16 +08:00
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY
size_type size() const _NOEXCEPT
{return static_cast<size_type>(this->__end_ - this->__begin_);}
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY
size_type capacity() const _NOEXCEPT
{return static_cast<size_type>(__end_cap() - this->__begin_);}
_LIBCPP_NODISCARD_AFTER_CXX17 _LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY
bool empty() const _NOEXCEPT
{return this->__begin_ == this->__end_;}
_LIBCPP_CONSTEXPR_AFTER_CXX17 size_type max_size() const _NOEXCEPT;
_LIBCPP_CONSTEXPR_AFTER_CXX17 void reserve(size_type __n);
_LIBCPP_CONSTEXPR_AFTER_CXX17 void shrink_to_fit() _NOEXCEPT;
2010-05-12 03:42:16 +08:00
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY reference operator[](size_type __n) _NOEXCEPT;
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY const_reference operator[](size_type __n) const _NOEXCEPT;
_LIBCPP_CONSTEXPR_AFTER_CXX17 reference at(size_type __n);
_LIBCPP_CONSTEXPR_AFTER_CXX17 const_reference at(size_type __n) const;
2010-05-12 03:42:16 +08:00
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY reference front() _NOEXCEPT
{
_LIBCPP_ASSERT(!empty(), "front() called on an empty vector");
return *this->__begin_;
}
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY const_reference front() const _NOEXCEPT
{
_LIBCPP_ASSERT(!empty(), "front() called on an empty vector");
return *this->__begin_;
}
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY reference back() _NOEXCEPT
{
_LIBCPP_ASSERT(!empty(), "back() called on an empty vector");
return *(this->__end_ - 1);
}
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY const_reference back() const _NOEXCEPT
{
_LIBCPP_ASSERT(!empty(), "back() called on an empty vector");
return *(this->__end_ - 1);
}
2010-05-12 03:42:16 +08:00
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY
value_type* data() _NOEXCEPT
{return _VSTD::__to_address(this->__begin_);}
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY
const value_type* data() const _NOEXCEPT
{return _VSTD::__to_address(this->__begin_);}
2010-05-12 03:42:16 +08:00
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY void push_back(const_reference __x);
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY void push_back(value_type&& __x);
2010-05-12 03:42:16 +08:00
template <class... _Args>
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY
#if _LIBCPP_STD_VER > 14
reference emplace_back(_Args&&... __args);
#else
void emplace_back(_Args&&... __args);
#endif
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY
2010-05-12 03:42:16 +08:00
void pop_back();
_LIBCPP_CONSTEXPR_AFTER_CXX17 iterator insert(const_iterator __position, const_reference __x);
_LIBCPP_CONSTEXPR_AFTER_CXX17 iterator insert(const_iterator __position, value_type&& __x);
2010-05-12 03:42:16 +08:00
template <class... _Args>
_LIBCPP_CONSTEXPR_AFTER_CXX17 iterator emplace(const_iterator __position, _Args&&... __args);
_LIBCPP_CONSTEXPR_AFTER_CXX17 iterator insert(const_iterator __position, size_type __n, const_reference __x);
2010-05-12 03:42:16 +08:00
template <class _InputIterator>
_LIBCPP_CONSTEXPR_AFTER_CXX17 typename enable_if <__is_exactly_cpp17_input_iterator<_InputIterator>::value &&
is_constructible<
value_type,
typename iterator_traits<_InputIterator>::reference>::value,
2010-05-12 03:42:16 +08:00
iterator
>::type
insert(const_iterator __position, _InputIterator __first, _InputIterator __last);
template <class _ForwardIterator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
typename enable_if
<
__is_cpp17_forward_iterator<_ForwardIterator>::value &&
is_constructible<
value_type,
typename iterator_traits<_ForwardIterator>::reference>::value,
2010-05-12 03:42:16 +08:00
iterator
>::type
insert(const_iterator __position, _ForwardIterator __first, _ForwardIterator __last);
#ifndef _LIBCPP_CXX03_LANG
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY
2010-05-12 03:42:16 +08:00
iterator insert(const_iterator __position, initializer_list<value_type> __il)
{return insert(__position, __il.begin(), __il.end());}
#endif
2010-05-12 03:42:16 +08:00
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY iterator erase(const_iterator __position);
_LIBCPP_CONSTEXPR_AFTER_CXX17 iterator erase(const_iterator __first, const_iterator __last);
2010-05-12 03:42:16 +08:00
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY
void clear() _NOEXCEPT
{
size_type __old_size = size();
__clear();
__annotate_shrink(__old_size);
std::__debug_db_invalidate_all(this);
}
2010-05-12 03:42:16 +08:00
_LIBCPP_CONSTEXPR_AFTER_CXX17 void resize(size_type __sz);
_LIBCPP_CONSTEXPR_AFTER_CXX17 void resize(size_type __sz, const_reference __x);
2010-05-12 03:42:16 +08:00
_LIBCPP_CONSTEXPR_AFTER_CXX17 void swap(vector&)
#if _LIBCPP_STD_VER >= 14
_NOEXCEPT;
#else
_NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value ||
__is_nothrow_swappable<allocator_type>::value);
#endif
2010-05-12 03:42:16 +08:00
_LIBCPP_CONSTEXPR_AFTER_CXX17 bool __invariants() const;
2010-05-12 03:42:16 +08:00
#ifdef _LIBCPP_ENABLE_DEBUG_MODE
bool __dereferenceable(const const_iterator* __i) const;
bool __decrementable(const const_iterator* __i) const;
bool __addable(const const_iterator* __i, ptrdiff_t __n) const;
bool __subscriptable(const const_iterator* __i, ptrdiff_t __n) const;
#endif // _LIBCPP_ENABLE_DEBUG_MODE
2010-05-12 03:42:16 +08:00
private:
pointer __begin_ = nullptr;
pointer __end_ = nullptr;
__compressed_pair<pointer, allocator_type> __end_cap_ =
__compressed_pair<pointer, allocator_type>(nullptr, __default_init_tag());
_LIBCPP_INLINE_VISIBILITY void __invalidate_iterators_past(pointer __new_last);
// Allocate space for __n objects
// throws length_error if __n > max_size()
// throws (probably bad_alloc) if memory run out
// Precondition: __begin_ == __end_ == __end_cap() == 0
// Precondition: __n > 0
// Postcondition: capacity() >= __n
// Postcondition: size() == 0
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_HIDE_FROM_ABI void __vallocate(size_type __n) {
if (__n > max_size())
__throw_length_error();
auto __allocation = std::__allocate_at_least(__alloc(), __n);
__begin_ = __allocation.ptr;
__end_ = __allocation.ptr;
__end_cap() = __begin_ + __allocation.count;
__annotate_new(0);
}
_LIBCPP_CONSTEXPR_AFTER_CXX17 void __vdeallocate() _NOEXCEPT;
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY size_type __recommend(size_type __new_size) const;
_LIBCPP_CONSTEXPR_AFTER_CXX17 void __construct_at_end(size_type __n);
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY
2010-05-12 03:42:16 +08:00
void __construct_at_end(size_type __n, const_reference __x);
template <class _ForwardIterator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
typename enable_if
<
__is_cpp17_forward_iterator<_ForwardIterator>::value,
2010-05-12 03:42:16 +08:00
void
>::type
__construct_at_end(_ForwardIterator __first, _ForwardIterator __last, size_type __n);
_LIBCPP_CONSTEXPR_AFTER_CXX17 void __append(size_type __n);
_LIBCPP_CONSTEXPR_AFTER_CXX17 void __append(size_type __n, const_reference __x);
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY
iterator __make_iter(pointer __p) _NOEXCEPT;
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY
const_iterator __make_iter(const_pointer __p) const _NOEXCEPT;
_LIBCPP_CONSTEXPR_AFTER_CXX17 void __swap_out_circular_buffer(__split_buffer<value_type, allocator_type&>& __v);
_LIBCPP_CONSTEXPR_AFTER_CXX17 pointer __swap_out_circular_buffer(__split_buffer<value_type, allocator_type&>& __v, pointer __p);
_LIBCPP_CONSTEXPR_AFTER_CXX17 void __move_range(pointer __from_s, pointer __from_e, pointer __to);
_LIBCPP_CONSTEXPR_AFTER_CXX17 void __move_assign(vector& __c, true_type)
_NOEXCEPT_(is_nothrow_move_assignable<allocator_type>::value);
_LIBCPP_CONSTEXPR_AFTER_CXX17 void __move_assign(vector& __c, false_type)
_NOEXCEPT_(__alloc_traits::is_always_equal::value);
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY
void __destruct_at_end(pointer __new_last) _NOEXCEPT
{
if (!__libcpp_is_constant_evaluated())
__invalidate_iterators_past(__new_last);
size_type __old_size = size();
__base_destruct_at_end(__new_last);
__annotate_shrink(__old_size);
}
template <class _Up>
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY
inline void __push_back_slow_path(_Up&& __x);
template <class... _Args>
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY
inline void __emplace_back_slow_path(_Args&&... __args);
// The following functions are no-ops outside of AddressSanitizer mode.
// We call annotatations only for the default Allocator because other allocators
// may not meet the AddressSanitizer alignment constraints.
// See the documentation for __sanitizer_annotate_contiguous_container for more details.
#ifndef _LIBCPP_HAS_NO_ASAN
_LIBCPP_CONSTEXPR_AFTER_CXX17
void __annotate_contiguous_container(const void *__beg, const void *__end,
const void *__old_mid,
const void *__new_mid) const
{
if (!__libcpp_is_constant_evaluated() && __beg && is_same<allocator_type, __default_allocator_type>::value)
__sanitizer_annotate_contiguous_container(__beg, __end, __old_mid, __new_mid);
}
#else
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY
void __annotate_contiguous_container(const void*, const void*, const void*,
Fix PR35637: suboptimal codegen for `vector<unsigned char>`. The optimizer is petulant and temperamental. In this case LLVM failed to lower the the "insert at end" loop used by`vector<unsigned char>` to a `memset` despite `memset` being substantially faster over a range of bytes. LLVM has the ability to lower loops to `memset` whet appropriate, but the odd nature of libc++'s loops prevented the optimization from taking places. This patch addresses the issue by rewriting the loops from the form `do [ ... --__n; } while (__n > 0);` to instead use a for loop over a pointer range (For example: `for (auto *__i = ...; __i < __e; ++__i)`). This patch also rewrites the asan annotations to unposion all additional memory at the start of the loop instead of once per iterations. This could potentially permit false negatives where the constructor of element N attempts to access element N + 1 during its construction. The before and after results for the `BM_ConstructSize/vector_byte/5140480_mean` benchmark (run 5 times) are: -------------------------------------------------------------------------------------------- Benchmark Time CPU Iterations -------------------------------------------------------------------------------------------- Before ------ BM_ConstructSize/vector_byte/5140480_mean 12530140 ns 12469693 ns N/A BM_ConstructSize/vector_byte/5140480_median 12512818 ns 12445571 ns N/A BM_ConstructSize/vector_byte/5140480_stddev 106224 ns 107907 ns 5 ----- After ----- BM_ConstructSize/vector_byte/5140480_mean 167285 ns 166500 ns N/A BM_ConstructSize/vector_byte/5140480_median 166749 ns 166069 ns N/A BM_ConstructSize/vector_byte/5140480_stddev 3242 ns 3184 ns 5 llvm-svn: 367183
2019-07-28 12:37:02 +08:00
const void*) const _NOEXCEPT {}
#endif
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY
Fix PR35637: suboptimal codegen for `vector<unsigned char>`. The optimizer is petulant and temperamental. In this case LLVM failed to lower the the "insert at end" loop used by`vector<unsigned char>` to a `memset` despite `memset` being substantially faster over a range of bytes. LLVM has the ability to lower loops to `memset` whet appropriate, but the odd nature of libc++'s loops prevented the optimization from taking places. This patch addresses the issue by rewriting the loops from the form `do [ ... --__n; } while (__n > 0);` to instead use a for loop over a pointer range (For example: `for (auto *__i = ...; __i < __e; ++__i)`). This patch also rewrites the asan annotations to unposion all additional memory at the start of the loop instead of once per iterations. This could potentially permit false negatives where the constructor of element N attempts to access element N + 1 during its construction. The before and after results for the `BM_ConstructSize/vector_byte/5140480_mean` benchmark (run 5 times) are: -------------------------------------------------------------------------------------------- Benchmark Time CPU Iterations -------------------------------------------------------------------------------------------- Before ------ BM_ConstructSize/vector_byte/5140480_mean 12530140 ns 12469693 ns N/A BM_ConstructSize/vector_byte/5140480_median 12512818 ns 12445571 ns N/A BM_ConstructSize/vector_byte/5140480_stddev 106224 ns 107907 ns 5 ----- After ----- BM_ConstructSize/vector_byte/5140480_mean 167285 ns 166500 ns N/A BM_ConstructSize/vector_byte/5140480_median 166749 ns 166069 ns N/A BM_ConstructSize/vector_byte/5140480_stddev 3242 ns 3184 ns 5 llvm-svn: 367183
2019-07-28 12:37:02 +08:00
void __annotate_new(size_type __current_size) const _NOEXCEPT {
__annotate_contiguous_container(data(), data() + capacity(),
data() + capacity(), data() + __current_size);
}
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY
Fix PR35637: suboptimal codegen for `vector<unsigned char>`. The optimizer is petulant and temperamental. In this case LLVM failed to lower the the "insert at end" loop used by`vector<unsigned char>` to a `memset` despite `memset` being substantially faster over a range of bytes. LLVM has the ability to lower loops to `memset` whet appropriate, but the odd nature of libc++'s loops prevented the optimization from taking places. This patch addresses the issue by rewriting the loops from the form `do [ ... --__n; } while (__n > 0);` to instead use a for loop over a pointer range (For example: `for (auto *__i = ...; __i < __e; ++__i)`). This patch also rewrites the asan annotations to unposion all additional memory at the start of the loop instead of once per iterations. This could potentially permit false negatives where the constructor of element N attempts to access element N + 1 during its construction. The before and after results for the `BM_ConstructSize/vector_byte/5140480_mean` benchmark (run 5 times) are: -------------------------------------------------------------------------------------------- Benchmark Time CPU Iterations -------------------------------------------------------------------------------------------- Before ------ BM_ConstructSize/vector_byte/5140480_mean 12530140 ns 12469693 ns N/A BM_ConstructSize/vector_byte/5140480_median 12512818 ns 12445571 ns N/A BM_ConstructSize/vector_byte/5140480_stddev 106224 ns 107907 ns 5 ----- After ----- BM_ConstructSize/vector_byte/5140480_mean 167285 ns 166500 ns N/A BM_ConstructSize/vector_byte/5140480_median 166749 ns 166069 ns N/A BM_ConstructSize/vector_byte/5140480_stddev 3242 ns 3184 ns 5 llvm-svn: 367183
2019-07-28 12:37:02 +08:00
void __annotate_delete() const _NOEXCEPT {
__annotate_contiguous_container(data(), data() + capacity(),
data() + size(), data() + capacity());
}
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY
Fix PR35637: suboptimal codegen for `vector<unsigned char>`. The optimizer is petulant and temperamental. In this case LLVM failed to lower the the "insert at end" loop used by`vector<unsigned char>` to a `memset` despite `memset` being substantially faster over a range of bytes. LLVM has the ability to lower loops to `memset` whet appropriate, but the odd nature of libc++'s loops prevented the optimization from taking places. This patch addresses the issue by rewriting the loops from the form `do [ ... --__n; } while (__n > 0);` to instead use a for loop over a pointer range (For example: `for (auto *__i = ...; __i < __e; ++__i)`). This patch also rewrites the asan annotations to unposion all additional memory at the start of the loop instead of once per iterations. This could potentially permit false negatives where the constructor of element N attempts to access element N + 1 during its construction. The before and after results for the `BM_ConstructSize/vector_byte/5140480_mean` benchmark (run 5 times) are: -------------------------------------------------------------------------------------------- Benchmark Time CPU Iterations -------------------------------------------------------------------------------------------- Before ------ BM_ConstructSize/vector_byte/5140480_mean 12530140 ns 12469693 ns N/A BM_ConstructSize/vector_byte/5140480_median 12512818 ns 12445571 ns N/A BM_ConstructSize/vector_byte/5140480_stddev 106224 ns 107907 ns 5 ----- After ----- BM_ConstructSize/vector_byte/5140480_mean 167285 ns 166500 ns N/A BM_ConstructSize/vector_byte/5140480_median 166749 ns 166069 ns N/A BM_ConstructSize/vector_byte/5140480_stddev 3242 ns 3184 ns 5 llvm-svn: 367183
2019-07-28 12:37:02 +08:00
void __annotate_increase(size_type __n) const _NOEXCEPT
{
__annotate_contiguous_container(data(), data() + capacity(),
data() + size(), data() + size() + __n);
}
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY
Fix PR35637: suboptimal codegen for `vector<unsigned char>`. The optimizer is petulant and temperamental. In this case LLVM failed to lower the the "insert at end" loop used by`vector<unsigned char>` to a `memset` despite `memset` being substantially faster over a range of bytes. LLVM has the ability to lower loops to `memset` whet appropriate, but the odd nature of libc++'s loops prevented the optimization from taking places. This patch addresses the issue by rewriting the loops from the form `do [ ... --__n; } while (__n > 0);` to instead use a for loop over a pointer range (For example: `for (auto *__i = ...; __i < __e; ++__i)`). This patch also rewrites the asan annotations to unposion all additional memory at the start of the loop instead of once per iterations. This could potentially permit false negatives where the constructor of element N attempts to access element N + 1 during its construction. The before and after results for the `BM_ConstructSize/vector_byte/5140480_mean` benchmark (run 5 times) are: -------------------------------------------------------------------------------------------- Benchmark Time CPU Iterations -------------------------------------------------------------------------------------------- Before ------ BM_ConstructSize/vector_byte/5140480_mean 12530140 ns 12469693 ns N/A BM_ConstructSize/vector_byte/5140480_median 12512818 ns 12445571 ns N/A BM_ConstructSize/vector_byte/5140480_stddev 106224 ns 107907 ns 5 ----- After ----- BM_ConstructSize/vector_byte/5140480_mean 167285 ns 166500 ns N/A BM_ConstructSize/vector_byte/5140480_median 166749 ns 166069 ns N/A BM_ConstructSize/vector_byte/5140480_stddev 3242 ns 3184 ns 5 llvm-svn: 367183
2019-07-28 12:37:02 +08:00
void __annotate_shrink(size_type __old_size) const _NOEXCEPT
{
__annotate_contiguous_container(data(), data() + capacity(),
data() + __old_size, data() + size());
}
Fix PR35637: suboptimal codegen for `vector<unsigned char>`. The optimizer is petulant and temperamental. In this case LLVM failed to lower the the "insert at end" loop used by`vector<unsigned char>` to a `memset` despite `memset` being substantially faster over a range of bytes. LLVM has the ability to lower loops to `memset` whet appropriate, but the odd nature of libc++'s loops prevented the optimization from taking places. This patch addresses the issue by rewriting the loops from the form `do [ ... --__n; } while (__n > 0);` to instead use a for loop over a pointer range (For example: `for (auto *__i = ...; __i < __e; ++__i)`). This patch also rewrites the asan annotations to unposion all additional memory at the start of the loop instead of once per iterations. This could potentially permit false negatives where the constructor of element N attempts to access element N + 1 during its construction. The before and after results for the `BM_ConstructSize/vector_byte/5140480_mean` benchmark (run 5 times) are: -------------------------------------------------------------------------------------------- Benchmark Time CPU Iterations -------------------------------------------------------------------------------------------- Before ------ BM_ConstructSize/vector_byte/5140480_mean 12530140 ns 12469693 ns N/A BM_ConstructSize/vector_byte/5140480_median 12512818 ns 12445571 ns N/A BM_ConstructSize/vector_byte/5140480_stddev 106224 ns 107907 ns 5 ----- After ----- BM_ConstructSize/vector_byte/5140480_mean 167285 ns 166500 ns N/A BM_ConstructSize/vector_byte/5140480_median 166749 ns 166069 ns N/A BM_ConstructSize/vector_byte/5140480_stddev 3242 ns 3184 ns 5 llvm-svn: 367183
2019-07-28 12:37:02 +08:00
struct _ConstructTransaction {
_LIBCPP_CONSTEXPR_AFTER_CXX17
Fix PR35637: suboptimal codegen for `vector<unsigned char>`. The optimizer is petulant and temperamental. In this case LLVM failed to lower the the "insert at end" loop used by`vector<unsigned char>` to a `memset` despite `memset` being substantially faster over a range of bytes. LLVM has the ability to lower loops to `memset` whet appropriate, but the odd nature of libc++'s loops prevented the optimization from taking places. This patch addresses the issue by rewriting the loops from the form `do [ ... --__n; } while (__n > 0);` to instead use a for loop over a pointer range (For example: `for (auto *__i = ...; __i < __e; ++__i)`). This patch also rewrites the asan annotations to unposion all additional memory at the start of the loop instead of once per iterations. This could potentially permit false negatives where the constructor of element N attempts to access element N + 1 during its construction. The before and after results for the `BM_ConstructSize/vector_byte/5140480_mean` benchmark (run 5 times) are: -------------------------------------------------------------------------------------------- Benchmark Time CPU Iterations -------------------------------------------------------------------------------------------- Before ------ BM_ConstructSize/vector_byte/5140480_mean 12530140 ns 12469693 ns N/A BM_ConstructSize/vector_byte/5140480_median 12512818 ns 12445571 ns N/A BM_ConstructSize/vector_byte/5140480_stddev 106224 ns 107907 ns 5 ----- After ----- BM_ConstructSize/vector_byte/5140480_mean 167285 ns 166500 ns N/A BM_ConstructSize/vector_byte/5140480_median 166749 ns 166069 ns N/A BM_ConstructSize/vector_byte/5140480_stddev 3242 ns 3184 ns 5 llvm-svn: 367183
2019-07-28 12:37:02 +08:00
explicit _ConstructTransaction(vector &__v, size_type __n)
: __v_(__v), __pos_(__v.__end_), __new_end_(__v.__end_ + __n) {
#ifndef _LIBCPP_HAS_NO_ASAN
Fix PR35637: suboptimal codegen for `vector<unsigned char>`. The optimizer is petulant and temperamental. In this case LLVM failed to lower the the "insert at end" loop used by`vector<unsigned char>` to a `memset` despite `memset` being substantially faster over a range of bytes. LLVM has the ability to lower loops to `memset` whet appropriate, but the odd nature of libc++'s loops prevented the optimization from taking places. This patch addresses the issue by rewriting the loops from the form `do [ ... --__n; } while (__n > 0);` to instead use a for loop over a pointer range (For example: `for (auto *__i = ...; __i < __e; ++__i)`). This patch also rewrites the asan annotations to unposion all additional memory at the start of the loop instead of once per iterations. This could potentially permit false negatives where the constructor of element N attempts to access element N + 1 during its construction. The before and after results for the `BM_ConstructSize/vector_byte/5140480_mean` benchmark (run 5 times) are: -------------------------------------------------------------------------------------------- Benchmark Time CPU Iterations -------------------------------------------------------------------------------------------- Before ------ BM_ConstructSize/vector_byte/5140480_mean 12530140 ns 12469693 ns N/A BM_ConstructSize/vector_byte/5140480_median 12512818 ns 12445571 ns N/A BM_ConstructSize/vector_byte/5140480_stddev 106224 ns 107907 ns 5 ----- After ----- BM_ConstructSize/vector_byte/5140480_mean 167285 ns 166500 ns N/A BM_ConstructSize/vector_byte/5140480_median 166749 ns 166069 ns N/A BM_ConstructSize/vector_byte/5140480_stddev 3242 ns 3184 ns 5 llvm-svn: 367183
2019-07-28 12:37:02 +08:00
__v_.__annotate_increase(__n);
#endif
}
_LIBCPP_CONSTEXPR_AFTER_CXX17 ~_ConstructTransaction() {
Fix PR35637: suboptimal codegen for `vector<unsigned char>`. The optimizer is petulant and temperamental. In this case LLVM failed to lower the the "insert at end" loop used by`vector<unsigned char>` to a `memset` despite `memset` being substantially faster over a range of bytes. LLVM has the ability to lower loops to `memset` whet appropriate, but the odd nature of libc++'s loops prevented the optimization from taking places. This patch addresses the issue by rewriting the loops from the form `do [ ... --__n; } while (__n > 0);` to instead use a for loop over a pointer range (For example: `for (auto *__i = ...; __i < __e; ++__i)`). This patch also rewrites the asan annotations to unposion all additional memory at the start of the loop instead of once per iterations. This could potentially permit false negatives where the constructor of element N attempts to access element N + 1 during its construction. The before and after results for the `BM_ConstructSize/vector_byte/5140480_mean` benchmark (run 5 times) are: -------------------------------------------------------------------------------------------- Benchmark Time CPU Iterations -------------------------------------------------------------------------------------------- Before ------ BM_ConstructSize/vector_byte/5140480_mean 12530140 ns 12469693 ns N/A BM_ConstructSize/vector_byte/5140480_median 12512818 ns 12445571 ns N/A BM_ConstructSize/vector_byte/5140480_stddev 106224 ns 107907 ns 5 ----- After ----- BM_ConstructSize/vector_byte/5140480_mean 167285 ns 166500 ns N/A BM_ConstructSize/vector_byte/5140480_median 166749 ns 166069 ns N/A BM_ConstructSize/vector_byte/5140480_stddev 3242 ns 3184 ns 5 llvm-svn: 367183
2019-07-28 12:37:02 +08:00
__v_.__end_ = __pos_;
#ifndef _LIBCPP_HAS_NO_ASAN
if (__pos_ != __new_end_) {
__v_.__annotate_shrink(__new_end_ - __v_.__begin_);
}
#endif
Fix PR35637: suboptimal codegen for `vector<unsigned char>`. The optimizer is petulant and temperamental. In this case LLVM failed to lower the the "insert at end" loop used by`vector<unsigned char>` to a `memset` despite `memset` being substantially faster over a range of bytes. LLVM has the ability to lower loops to `memset` whet appropriate, but the odd nature of libc++'s loops prevented the optimization from taking places. This patch addresses the issue by rewriting the loops from the form `do [ ... --__n; } while (__n > 0);` to instead use a for loop over a pointer range (For example: `for (auto *__i = ...; __i < __e; ++__i)`). This patch also rewrites the asan annotations to unposion all additional memory at the start of the loop instead of once per iterations. This could potentially permit false negatives where the constructor of element N attempts to access element N + 1 during its construction. The before and after results for the `BM_ConstructSize/vector_byte/5140480_mean` benchmark (run 5 times) are: -------------------------------------------------------------------------------------------- Benchmark Time CPU Iterations -------------------------------------------------------------------------------------------- Before ------ BM_ConstructSize/vector_byte/5140480_mean 12530140 ns 12469693 ns N/A BM_ConstructSize/vector_byte/5140480_median 12512818 ns 12445571 ns N/A BM_ConstructSize/vector_byte/5140480_stddev 106224 ns 107907 ns 5 ----- After ----- BM_ConstructSize/vector_byte/5140480_mean 167285 ns 166500 ns N/A BM_ConstructSize/vector_byte/5140480_median 166749 ns 166069 ns N/A BM_ConstructSize/vector_byte/5140480_stddev 3242 ns 3184 ns 5 llvm-svn: 367183
2019-07-28 12:37:02 +08:00
}
Fix PR35637: suboptimal codegen for `vector<unsigned char>`. The optimizer is petulant and temperamental. In this case LLVM failed to lower the the "insert at end" loop used by`vector<unsigned char>` to a `memset` despite `memset` being substantially faster over a range of bytes. LLVM has the ability to lower loops to `memset` whet appropriate, but the odd nature of libc++'s loops prevented the optimization from taking places. This patch addresses the issue by rewriting the loops from the form `do [ ... --__n; } while (__n > 0);` to instead use a for loop over a pointer range (For example: `for (auto *__i = ...; __i < __e; ++__i)`). This patch also rewrites the asan annotations to unposion all additional memory at the start of the loop instead of once per iterations. This could potentially permit false negatives where the constructor of element N attempts to access element N + 1 during its construction. The before and after results for the `BM_ConstructSize/vector_byte/5140480_mean` benchmark (run 5 times) are: -------------------------------------------------------------------------------------------- Benchmark Time CPU Iterations -------------------------------------------------------------------------------------------- Before ------ BM_ConstructSize/vector_byte/5140480_mean 12530140 ns 12469693 ns N/A BM_ConstructSize/vector_byte/5140480_median 12512818 ns 12445571 ns N/A BM_ConstructSize/vector_byte/5140480_stddev 106224 ns 107907 ns 5 ----- After ----- BM_ConstructSize/vector_byte/5140480_mean 167285 ns 166500 ns N/A BM_ConstructSize/vector_byte/5140480_median 166749 ns 166069 ns N/A BM_ConstructSize/vector_byte/5140480_stddev 3242 ns 3184 ns 5 llvm-svn: 367183
2019-07-28 12:37:02 +08:00
vector &__v_;
pointer __pos_;
const_pointer const __new_end_;
private:
_ConstructTransaction(_ConstructTransaction const&) = delete;
_ConstructTransaction& operator=(_ConstructTransaction const&) = delete;
};
template <class ..._Args>
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY
Fix PR35637: suboptimal codegen for `vector<unsigned char>`. The optimizer is petulant and temperamental. In this case LLVM failed to lower the the "insert at end" loop used by`vector<unsigned char>` to a `memset` despite `memset` being substantially faster over a range of bytes. LLVM has the ability to lower loops to `memset` whet appropriate, but the odd nature of libc++'s loops prevented the optimization from taking places. This patch addresses the issue by rewriting the loops from the form `do [ ... --__n; } while (__n > 0);` to instead use a for loop over a pointer range (For example: `for (auto *__i = ...; __i < __e; ++__i)`). This patch also rewrites the asan annotations to unposion all additional memory at the start of the loop instead of once per iterations. This could potentially permit false negatives where the constructor of element N attempts to access element N + 1 during its construction. The before and after results for the `BM_ConstructSize/vector_byte/5140480_mean` benchmark (run 5 times) are: -------------------------------------------------------------------------------------------- Benchmark Time CPU Iterations -------------------------------------------------------------------------------------------- Before ------ BM_ConstructSize/vector_byte/5140480_mean 12530140 ns 12469693 ns N/A BM_ConstructSize/vector_byte/5140480_median 12512818 ns 12445571 ns N/A BM_ConstructSize/vector_byte/5140480_stddev 106224 ns 107907 ns 5 ----- After ----- BM_ConstructSize/vector_byte/5140480_mean 167285 ns 166500 ns N/A BM_ConstructSize/vector_byte/5140480_median 166749 ns 166069 ns N/A BM_ConstructSize/vector_byte/5140480_stddev 3242 ns 3184 ns 5 llvm-svn: 367183
2019-07-28 12:37:02 +08:00
void __construct_one_at_end(_Args&& ...__args) {
_ConstructTransaction __tx(*this, 1);
__alloc_traits::construct(this->__alloc(), _VSTD::__to_address(__tx.__pos_),
Fix PR35637: suboptimal codegen for `vector<unsigned char>`. The optimizer is petulant and temperamental. In this case LLVM failed to lower the the "insert at end" loop used by`vector<unsigned char>` to a `memset` despite `memset` being substantially faster over a range of bytes. LLVM has the ability to lower loops to `memset` whet appropriate, but the odd nature of libc++'s loops prevented the optimization from taking places. This patch addresses the issue by rewriting the loops from the form `do [ ... --__n; } while (__n > 0);` to instead use a for loop over a pointer range (For example: `for (auto *__i = ...; __i < __e; ++__i)`). This patch also rewrites the asan annotations to unposion all additional memory at the start of the loop instead of once per iterations. This could potentially permit false negatives where the constructor of element N attempts to access element N + 1 during its construction. The before and after results for the `BM_ConstructSize/vector_byte/5140480_mean` benchmark (run 5 times) are: -------------------------------------------------------------------------------------------- Benchmark Time CPU Iterations -------------------------------------------------------------------------------------------- Before ------ BM_ConstructSize/vector_byte/5140480_mean 12530140 ns 12469693 ns N/A BM_ConstructSize/vector_byte/5140480_median 12512818 ns 12445571 ns N/A BM_ConstructSize/vector_byte/5140480_stddev 106224 ns 107907 ns 5 ----- After ----- BM_ConstructSize/vector_byte/5140480_mean 167285 ns 166500 ns N/A BM_ConstructSize/vector_byte/5140480_median 166749 ns 166069 ns N/A BM_ConstructSize/vector_byte/5140480_stddev 3242 ns 3184 ns 5 llvm-svn: 367183
2019-07-28 12:37:02 +08:00
_VSTD::forward<_Args>(__args)...);
++__tx.__pos_;
}
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY
allocator_type& __alloc() _NOEXCEPT
{return this->__end_cap_.second();}
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY
const allocator_type& __alloc() const _NOEXCEPT
{return this->__end_cap_.second();}
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY
pointer& __end_cap() _NOEXCEPT
{return this->__end_cap_.first();}
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY
const pointer& __end_cap() const _NOEXCEPT
{return this->__end_cap_.first();}
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY
void __clear() _NOEXCEPT {__base_destruct_at_end(this->__begin_);}
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY
void __base_destruct_at_end(pointer __new_last) _NOEXCEPT {
pointer __soon_to_be_end = this->__end_;
while (__new_last != __soon_to_be_end)
__alloc_traits::destroy(__alloc(), _VSTD::__to_address(--__soon_to_be_end));
this->__end_ = __new_last;
}
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY
void __copy_assign_alloc(const vector& __c)
{__copy_assign_alloc(__c, integral_constant<bool,
__alloc_traits::propagate_on_container_copy_assignment::value>());}
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY
void __move_assign_alloc(vector& __c)
_NOEXCEPT_(
!__alloc_traits::propagate_on_container_move_assignment::value ||
is_nothrow_move_assignable<allocator_type>::value)
{__move_assign_alloc(__c, integral_constant<bool,
__alloc_traits::propagate_on_container_move_assignment::value>());}
_LIBCPP_NORETURN _LIBCPP_HIDE_FROM_ABI
void __throw_length_error() const {
_VSTD::__throw_length_error("vector");
}
_LIBCPP_NORETURN _LIBCPP_HIDE_FROM_ABI
void __throw_out_of_range() const {
_VSTD::__throw_out_of_range("vector");
}
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY
void __copy_assign_alloc(const vector& __c, true_type)
{
if (__alloc() != __c.__alloc())
{
__clear();
__alloc_traits::deallocate(__alloc(), this->__begin_, capacity());
this->__begin_ = this->__end_ = __end_cap() = nullptr;
}
__alloc() = __c.__alloc();
}
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY
void __copy_assign_alloc(const vector&, false_type)
{}
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY
void __move_assign_alloc(vector& __c, true_type)
_NOEXCEPT_(is_nothrow_move_assignable<allocator_type>::value)
{
__alloc() = _VSTD::move(__c.__alloc());
}
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY
void __move_assign_alloc(vector&, false_type)
_NOEXCEPT
{}
2010-05-12 03:42:16 +08:00
};
#if _LIBCPP_STD_VER >= 17
template<class _InputIterator,
class _Alloc = allocator<__iter_value_type<_InputIterator>>,
class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value>,
[libc++] Use enable_if_t instead of _EnableIf I just ran into a compiler error involving __bind_back and some overloads that were being disabled with _EnableIf. I noticed that the error message was quite bad and did not mention the reason for the overload being excluded. Specifically, the error looked like this: candidate template ignored: substitution failure [with _Args = <ContiguousView>]: no member named '_EnableIfImpl' in 'std::_MetaBase<false>' Instead, when using enable_if or enable_if_t, the compiler is clever and can produce better diagnostics, like so: candidate template ignored: requirement 'is_invocable_v< std::__bind_back_op<1, std::integer_sequence<unsigned long, 0>>, std::ranges::views::__transform::__fn &, std::tuple<PlusOne> &, ContiguousView>' was not satisfied [with _Args = <ContiguousView>] Basically, it tries to do a poor man's implementation of concepts, which is already a lot better than simply complaining about substitution failure. Hence, this commit uses enable_if_t instead of _EnableIf whenever possible. That is both more straightforward than using the internal helper, and also leads to better error messages in those cases. I understand the motivation for _EnableIf's implementation was to improve compile-time performance, however I believe striving to improve error messages is even more important for our QOI, hence this patch. Furthermore, it is unclear that _EnableIf actually improved compile-time performance in any noticeable way (see discussion in the review for details). Differential Revision: https://reviews.llvm.org/D108216
2021-08-18 00:26:09 +08:00
class = enable_if_t<__is_allocator<_Alloc>::value>
>
vector(_InputIterator, _InputIterator)
-> vector<__iter_value_type<_InputIterator>, _Alloc>;
template<class _InputIterator,
class _Alloc,
class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value>,
[libc++] Use enable_if_t instead of _EnableIf I just ran into a compiler error involving __bind_back and some overloads that were being disabled with _EnableIf. I noticed that the error message was quite bad and did not mention the reason for the overload being excluded. Specifically, the error looked like this: candidate template ignored: substitution failure [with _Args = <ContiguousView>]: no member named '_EnableIfImpl' in 'std::_MetaBase<false>' Instead, when using enable_if or enable_if_t, the compiler is clever and can produce better diagnostics, like so: candidate template ignored: requirement 'is_invocable_v< std::__bind_back_op<1, std::integer_sequence<unsigned long, 0>>, std::ranges::views::__transform::__fn &, std::tuple<PlusOne> &, ContiguousView>' was not satisfied [with _Args = <ContiguousView>] Basically, it tries to do a poor man's implementation of concepts, which is already a lot better than simply complaining about substitution failure. Hence, this commit uses enable_if_t instead of _EnableIf whenever possible. That is both more straightforward than using the internal helper, and also leads to better error messages in those cases. I understand the motivation for _EnableIf's implementation was to improve compile-time performance, however I believe striving to improve error messages is even more important for our QOI, hence this patch. Furthermore, it is unclear that _EnableIf actually improved compile-time performance in any noticeable way (see discussion in the review for details). Differential Revision: https://reviews.llvm.org/D108216
2021-08-18 00:26:09 +08:00
class = enable_if_t<__is_allocator<_Alloc>::value>
>
vector(_InputIterator, _InputIterator, _Alloc)
-> vector<__iter_value_type<_InputIterator>, _Alloc>;
#endif
2010-05-12 03:42:16 +08:00
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
void
vector<_Tp, _Allocator>::__swap_out_circular_buffer(__split_buffer<value_type, allocator_type&>& __v)
{
__annotate_delete();
using _RevIter = std::reverse_iterator<pointer>;
__v.__begin_ = std::__uninitialized_allocator_move_if_noexcept(
__alloc(), _RevIter(__end_), _RevIter(__begin_), _RevIter(__v.__begin_))
.base();
_VSTD::swap(this->__begin_, __v.__begin_);
_VSTD::swap(this->__end_, __v.__end_);
_VSTD::swap(this->__end_cap(), __v.__end_cap());
2010-05-12 03:42:16 +08:00
__v.__first_ = __v.__begin_;
__annotate_new(size());
std::__debug_db_invalidate_all(this);
2010-05-12 03:42:16 +08:00
}
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
typename vector<_Tp, _Allocator>::pointer
vector<_Tp, _Allocator>::__swap_out_circular_buffer(__split_buffer<value_type, allocator_type&>& __v, pointer __p)
{
__annotate_delete();
2010-05-12 03:42:16 +08:00
pointer __r = __v.__begin_;
using _RevIter = std::reverse_iterator<pointer>;
__v.__begin_ = std::__uninitialized_allocator_move_if_noexcept(
__alloc(), _RevIter(__p), _RevIter(__begin_), _RevIter(__v.__begin_))
.base();
__v.__end_ = std::__uninitialized_allocator_move_if_noexcept(__alloc(), __p, __end_, __v.__end_);
_VSTD::swap(this->__begin_, __v.__begin_);
_VSTD::swap(this->__end_, __v.__end_);
_VSTD::swap(this->__end_cap(), __v.__end_cap());
2010-05-12 03:42:16 +08:00
__v.__first_ = __v.__begin_;
__annotate_new(size());
std::__debug_db_invalidate_all(this);
2010-05-12 03:42:16 +08:00
return __r;
}
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
void
vector<_Tp, _Allocator>::__vdeallocate() _NOEXCEPT
2010-05-12 03:42:16 +08:00
{
if (this->__begin_ != nullptr)
2010-05-12 03:42:16 +08:00
{
clear();
__alloc_traits::deallocate(this->__alloc(), this->__begin_, capacity());
this->__begin_ = this->__end_ = this->__end_cap() = nullptr;
2010-05-12 03:42:16 +08:00
}
}
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
typename vector<_Tp, _Allocator>::size_type
vector<_Tp, _Allocator>::max_size() const _NOEXCEPT
2010-05-12 03:42:16 +08:00
{
return _VSTD::min<size_type>(__alloc_traits::max_size(this->__alloc()),
numeric_limits<difference_type>::max());
2010-05-12 03:42:16 +08:00
}
// Precondition: __new_size > capacity()
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
inline _LIBCPP_INLINE_VISIBILITY
2010-05-12 03:42:16 +08:00
typename vector<_Tp, _Allocator>::size_type
vector<_Tp, _Allocator>::__recommend(size_type __new_size) const
{
const size_type __ms = max_size();
if (__new_size > __ms)
this->__throw_length_error();
const size_type __cap = capacity();
if (__cap >= __ms / 2)
return __ms;
return _VSTD::max<size_type>(2 * __cap, __new_size);
2010-05-12 03:42:16 +08:00
}
// Default constructs __n objects starting at __end_
// throws if construction throws
// Precondition: __n > 0
// Precondition: size() + __n <= capacity()
// Postcondition: size() == size() + __n
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
void
vector<_Tp, _Allocator>::__construct_at_end(size_type __n)
{
Fix PR35637: suboptimal codegen for `vector<unsigned char>`. The optimizer is petulant and temperamental. In this case LLVM failed to lower the the "insert at end" loop used by`vector<unsigned char>` to a `memset` despite `memset` being substantially faster over a range of bytes. LLVM has the ability to lower loops to `memset` whet appropriate, but the odd nature of libc++'s loops prevented the optimization from taking places. This patch addresses the issue by rewriting the loops from the form `do [ ... --__n; } while (__n > 0);` to instead use a for loop over a pointer range (For example: `for (auto *__i = ...; __i < __e; ++__i)`). This patch also rewrites the asan annotations to unposion all additional memory at the start of the loop instead of once per iterations. This could potentially permit false negatives where the constructor of element N attempts to access element N + 1 during its construction. The before and after results for the `BM_ConstructSize/vector_byte/5140480_mean` benchmark (run 5 times) are: -------------------------------------------------------------------------------------------- Benchmark Time CPU Iterations -------------------------------------------------------------------------------------------- Before ------ BM_ConstructSize/vector_byte/5140480_mean 12530140 ns 12469693 ns N/A BM_ConstructSize/vector_byte/5140480_median 12512818 ns 12445571 ns N/A BM_ConstructSize/vector_byte/5140480_stddev 106224 ns 107907 ns 5 ----- After ----- BM_ConstructSize/vector_byte/5140480_mean 167285 ns 166500 ns N/A BM_ConstructSize/vector_byte/5140480_median 166749 ns 166069 ns N/A BM_ConstructSize/vector_byte/5140480_stddev 3242 ns 3184 ns 5 llvm-svn: 367183
2019-07-28 12:37:02 +08:00
_ConstructTransaction __tx(*this, __n);
const_pointer __new_end = __tx.__new_end_;
for (pointer __pos = __tx.__pos_; __pos != __new_end; __tx.__pos_ = ++__pos) {
__alloc_traits::construct(this->__alloc(), _VSTD::__to_address(__pos));
Fix PR35637: suboptimal codegen for `vector<unsigned char>`. The optimizer is petulant and temperamental. In this case LLVM failed to lower the the "insert at end" loop used by`vector<unsigned char>` to a `memset` despite `memset` being substantially faster over a range of bytes. LLVM has the ability to lower loops to `memset` whet appropriate, but the odd nature of libc++'s loops prevented the optimization from taking places. This patch addresses the issue by rewriting the loops from the form `do [ ... --__n; } while (__n > 0);` to instead use a for loop over a pointer range (For example: `for (auto *__i = ...; __i < __e; ++__i)`). This patch also rewrites the asan annotations to unposion all additional memory at the start of the loop instead of once per iterations. This could potentially permit false negatives where the constructor of element N attempts to access element N + 1 during its construction. The before and after results for the `BM_ConstructSize/vector_byte/5140480_mean` benchmark (run 5 times) are: -------------------------------------------------------------------------------------------- Benchmark Time CPU Iterations -------------------------------------------------------------------------------------------- Before ------ BM_ConstructSize/vector_byte/5140480_mean 12530140 ns 12469693 ns N/A BM_ConstructSize/vector_byte/5140480_median 12512818 ns 12445571 ns N/A BM_ConstructSize/vector_byte/5140480_stddev 106224 ns 107907 ns 5 ----- After ----- BM_ConstructSize/vector_byte/5140480_mean 167285 ns 166500 ns N/A BM_ConstructSize/vector_byte/5140480_median 166749 ns 166069 ns N/A BM_ConstructSize/vector_byte/5140480_stddev 3242 ns 3184 ns 5 llvm-svn: 367183
2019-07-28 12:37:02 +08:00
}
2010-05-12 03:42:16 +08:00
}
// Copy constructs __n objects starting at __end_ from __x
// throws if construction throws
// Precondition: __n > 0
// Precondition: size() + __n <= capacity()
// Postcondition: size() == old size() + __n
// Postcondition: [i] == __x for all i in [size() - __n, __n)
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
inline
2010-05-12 03:42:16 +08:00
void
vector<_Tp, _Allocator>::__construct_at_end(size_type __n, const_reference __x)
{
Fix PR35637: suboptimal codegen for `vector<unsigned char>`. The optimizer is petulant and temperamental. In this case LLVM failed to lower the the "insert at end" loop used by`vector<unsigned char>` to a `memset` despite `memset` being substantially faster over a range of bytes. LLVM has the ability to lower loops to `memset` whet appropriate, but the odd nature of libc++'s loops prevented the optimization from taking places. This patch addresses the issue by rewriting the loops from the form `do [ ... --__n; } while (__n > 0);` to instead use a for loop over a pointer range (For example: `for (auto *__i = ...; __i < __e; ++__i)`). This patch also rewrites the asan annotations to unposion all additional memory at the start of the loop instead of once per iterations. This could potentially permit false negatives where the constructor of element N attempts to access element N + 1 during its construction. The before and after results for the `BM_ConstructSize/vector_byte/5140480_mean` benchmark (run 5 times) are: -------------------------------------------------------------------------------------------- Benchmark Time CPU Iterations -------------------------------------------------------------------------------------------- Before ------ BM_ConstructSize/vector_byte/5140480_mean 12530140 ns 12469693 ns N/A BM_ConstructSize/vector_byte/5140480_median 12512818 ns 12445571 ns N/A BM_ConstructSize/vector_byte/5140480_stddev 106224 ns 107907 ns 5 ----- After ----- BM_ConstructSize/vector_byte/5140480_mean 167285 ns 166500 ns N/A BM_ConstructSize/vector_byte/5140480_median 166749 ns 166069 ns N/A BM_ConstructSize/vector_byte/5140480_stddev 3242 ns 3184 ns 5 llvm-svn: 367183
2019-07-28 12:37:02 +08:00
_ConstructTransaction __tx(*this, __n);
const_pointer __new_end = __tx.__new_end_;
for (pointer __pos = __tx.__pos_; __pos != __new_end; __tx.__pos_ = ++__pos) {
__alloc_traits::construct(this->__alloc(), _VSTD::__to_address(__pos), __x);
Fix PR35637: suboptimal codegen for `vector<unsigned char>`. The optimizer is petulant and temperamental. In this case LLVM failed to lower the the "insert at end" loop used by`vector<unsigned char>` to a `memset` despite `memset` being substantially faster over a range of bytes. LLVM has the ability to lower loops to `memset` whet appropriate, but the odd nature of libc++'s loops prevented the optimization from taking places. This patch addresses the issue by rewriting the loops from the form `do [ ... --__n; } while (__n > 0);` to instead use a for loop over a pointer range (For example: `for (auto *__i = ...; __i < __e; ++__i)`). This patch also rewrites the asan annotations to unposion all additional memory at the start of the loop instead of once per iterations. This could potentially permit false negatives where the constructor of element N attempts to access element N + 1 during its construction. The before and after results for the `BM_ConstructSize/vector_byte/5140480_mean` benchmark (run 5 times) are: -------------------------------------------------------------------------------------------- Benchmark Time CPU Iterations -------------------------------------------------------------------------------------------- Before ------ BM_ConstructSize/vector_byte/5140480_mean 12530140 ns 12469693 ns N/A BM_ConstructSize/vector_byte/5140480_median 12512818 ns 12445571 ns N/A BM_ConstructSize/vector_byte/5140480_stddev 106224 ns 107907 ns 5 ----- After ----- BM_ConstructSize/vector_byte/5140480_mean 167285 ns 166500 ns N/A BM_ConstructSize/vector_byte/5140480_median 166749 ns 166069 ns N/A BM_ConstructSize/vector_byte/5140480_stddev 3242 ns 3184 ns 5 llvm-svn: 367183
2019-07-28 12:37:02 +08:00
}
2010-05-12 03:42:16 +08:00
}
template <class _Tp, class _Allocator>
template <class _ForwardIterator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
typename enable_if
<
__is_cpp17_forward_iterator<_ForwardIterator>::value,
2010-05-12 03:42:16 +08:00
void
>::type
vector<_Tp, _Allocator>::__construct_at_end(_ForwardIterator __first, _ForwardIterator __last, size_type __n)
2010-05-12 03:42:16 +08:00
{
_ConstructTransaction __tx(*this, __n);
__tx.__pos_ = std::__uninitialized_allocator_copy(__alloc(), __first, __last, __tx.__pos_);
2010-05-12 03:42:16 +08:00
}
// Default constructs __n objects starting at __end_
// throws if construction throws
// Postcondition: size() == size() + __n
// Exception safety: strong.
2010-05-12 03:42:16 +08:00
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
void
vector<_Tp, _Allocator>::__append(size_type __n)
{
if (static_cast<size_type>(this->__end_cap() - this->__end_) >= __n)
this->__construct_at_end(__n);
else
{
allocator_type& __a = this->__alloc();
__split_buffer<value_type, allocator_type&> __v(__recommend(size() + __n), size(), __a);
__v.__construct_at_end(__n);
__swap_out_circular_buffer(__v);
}
}
// Default constructs __n objects starting at __end_
// throws if construction throws
// Postcondition: size() == size() + __n
// Exception safety: strong.
2010-05-12 03:42:16 +08:00
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
void
vector<_Tp, _Allocator>::__append(size_type __n, const_reference __x)
{
if (static_cast<size_type>(this->__end_cap() - this->__end_) >= __n)
this->__construct_at_end(__n, __x);
else
{
allocator_type& __a = this->__alloc();
__split_buffer<value_type, allocator_type&> __v(__recommend(size() + __n), size(), __a);
__v.__construct_at_end(__n, __x);
__swap_out_circular_buffer(__v);
}
}
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
vector<_Tp, _Allocator>::vector(size_type __n)
{
_VSTD::__debug_db_insert_c(this);
2010-05-12 03:42:16 +08:00
if (__n > 0)
{
__vallocate(__n);
2010-05-12 03:42:16 +08:00
__construct_at_end(__n);
}
}
#if _LIBCPP_STD_VER > 11
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
vector<_Tp, _Allocator>::vector(size_type __n, const allocator_type& __a)
: __end_cap_(nullptr, __a)
{
_VSTD::__debug_db_insert_c(this);
if (__n > 0)
{
__vallocate(__n);
__construct_at_end(__n);
}
}
#endif
2010-05-12 03:42:16 +08:00
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
vector<_Tp, _Allocator>::vector(size_type __n, const value_type& __x)
2010-05-12 03:42:16 +08:00
{
_VSTD::__debug_db_insert_c(this);
2010-05-12 03:42:16 +08:00
if (__n > 0)
{
__vallocate(__n);
2010-05-12 03:42:16 +08:00
__construct_at_end(__n, __x);
}
}
template <class _Tp, class _Allocator>
template <class _InputIterator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
vector<_Tp, _Allocator>::vector(_InputIterator __first,
typename enable_if<__is_exactly_cpp17_input_iterator<_InputIterator>::value &&
is_constructible<
value_type,
typename iterator_traits<_InputIterator>::reference>::value,
_InputIterator>::type __last)
2010-05-12 03:42:16 +08:00
{
_VSTD::__debug_db_insert_c(this);
for (; __first != __last; ++__first)
emplace_back(*__first);
2010-05-12 03:42:16 +08:00
}
template <class _Tp, class _Allocator>
template <class _InputIterator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
vector<_Tp, _Allocator>::vector(_InputIterator __first, _InputIterator __last, const allocator_type& __a,
typename enable_if<__is_exactly_cpp17_input_iterator<_InputIterator>::value &&
is_constructible<
value_type,
typename iterator_traits<_InputIterator>::reference>::value>::type*)
: __end_cap_(nullptr, __a)
2010-05-12 03:42:16 +08:00
{
_VSTD::__debug_db_insert_c(this);
for (; __first != __last; ++__first)
emplace_back(*__first);
2010-05-12 03:42:16 +08:00
}
template <class _Tp, class _Allocator>
template <class _ForwardIterator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
vector<_Tp, _Allocator>::vector(_ForwardIterator __first,
typename enable_if<__is_cpp17_forward_iterator<_ForwardIterator>::value &&
is_constructible<
value_type,
typename iterator_traits<_ForwardIterator>::reference>::value,
_ForwardIterator>::type __last)
2010-05-12 03:42:16 +08:00
{
_VSTD::__debug_db_insert_c(this);
size_type __n = static_cast<size_type>(_VSTD::distance(__first, __last));
2010-05-12 03:42:16 +08:00
if (__n > 0)
{
__vallocate(__n);
__construct_at_end(__first, __last, __n);
2010-05-12 03:42:16 +08:00
}
}
template <class _Tp, class _Allocator>
template <class _ForwardIterator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
vector<_Tp, _Allocator>::vector(_ForwardIterator __first, _ForwardIterator __last, const allocator_type& __a,
typename enable_if<__is_cpp17_forward_iterator<_ForwardIterator>::value &&
is_constructible<
value_type,
typename iterator_traits<_ForwardIterator>::reference>::value>::type*)
: __end_cap_(nullptr, __a)
2010-05-12 03:42:16 +08:00
{
_VSTD::__debug_db_insert_c(this);
size_type __n = static_cast<size_type>(_VSTD::distance(__first, __last));
2010-05-12 03:42:16 +08:00
if (__n > 0)
{
__vallocate(__n);
__construct_at_end(__first, __last, __n);
2010-05-12 03:42:16 +08:00
}
}
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
vector<_Tp, _Allocator>::vector(const vector& __x)
: __end_cap_(nullptr, __alloc_traits::select_on_container_copy_construction(__x.__alloc()))
2010-05-12 03:42:16 +08:00
{
_VSTD::__debug_db_insert_c(this);
2010-05-12 03:42:16 +08:00
size_type __n = __x.size();
if (__n > 0)
{
__vallocate(__n);
__construct_at_end(__x.__begin_, __x.__end_, __n);
2010-05-12 03:42:16 +08:00
}
}
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
vector<_Tp, _Allocator>::vector(const vector& __x, const __type_identity_t<allocator_type>& __a)
: __end_cap_(nullptr, __a)
2010-05-12 03:42:16 +08:00
{
_VSTD::__debug_db_insert_c(this);
2010-05-12 03:42:16 +08:00
size_type __n = __x.size();
if (__n > 0)
{
__vallocate(__n);
__construct_at_end(__x.__begin_, __x.__end_, __n);
2010-05-12 03:42:16 +08:00
}
}
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
inline _LIBCPP_INLINE_VISIBILITY
2010-05-12 03:42:16 +08:00
vector<_Tp, _Allocator>::vector(vector&& __x)
#if _LIBCPP_STD_VER > 14
noexcept
#else
_NOEXCEPT_(is_nothrow_move_constructible<allocator_type>::value)
#endif
: __end_cap_(nullptr, _VSTD::move(__x.__alloc()))
2010-05-12 03:42:16 +08:00
{
_VSTD::__debug_db_insert_c(this);
std::__debug_db_swap(this, std::addressof(__x));
this->__begin_ = __x.__begin_;
this->__end_ = __x.__end_;
this->__end_cap() = __x.__end_cap();
__x.__begin_ = __x.__end_ = __x.__end_cap() = nullptr;
2010-05-12 03:42:16 +08:00
}
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
inline _LIBCPP_INLINE_VISIBILITY
vector<_Tp, _Allocator>::vector(vector&& __x, const __type_identity_t<allocator_type>& __a)
: __end_cap_(nullptr, __a)
2010-05-12 03:42:16 +08:00
{
_VSTD::__debug_db_insert_c(this);
2010-05-12 03:42:16 +08:00
if (__a == __x.__alloc())
{
this->__begin_ = __x.__begin_;
this->__end_ = __x.__end_;
this->__end_cap() = __x.__end_cap();
__x.__begin_ = __x.__end_ = __x.__end_cap() = nullptr;
std::__debug_db_swap(this, std::addressof(__x));
2010-05-12 03:42:16 +08:00
}
else
{
typedef move_iterator<iterator> _Ip;
assign(_Ip(__x.begin()), _Ip(__x.end()));
2010-05-12 03:42:16 +08:00
}
}
#ifndef _LIBCPP_CXX03_LANG
2010-05-12 03:42:16 +08:00
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
inline _LIBCPP_INLINE_VISIBILITY
2010-05-12 03:42:16 +08:00
vector<_Tp, _Allocator>::vector(initializer_list<value_type> __il)
{
_VSTD::__debug_db_insert_c(this);
2010-05-12 03:42:16 +08:00
if (__il.size() > 0)
{
__vallocate(__il.size());
__construct_at_end(__il.begin(), __il.end(), __il.size());
2010-05-12 03:42:16 +08:00
}
}
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
inline _LIBCPP_INLINE_VISIBILITY
2010-05-12 03:42:16 +08:00
vector<_Tp, _Allocator>::vector(initializer_list<value_type> __il, const allocator_type& __a)
: __end_cap_(nullptr, __a)
2010-05-12 03:42:16 +08:00
{
_VSTD::__debug_db_insert_c(this);
2010-05-12 03:42:16 +08:00
if (__il.size() > 0)
{
__vallocate(__il.size());
__construct_at_end(__il.begin(), __il.end(), __il.size());
2010-05-12 03:42:16 +08:00
}
}
#endif // _LIBCPP_CXX03_LANG
2010-05-12 03:42:16 +08:00
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
inline _LIBCPP_INLINE_VISIBILITY
2010-05-12 03:42:16 +08:00
vector<_Tp, _Allocator>&
vector<_Tp, _Allocator>::operator=(vector&& __x)
_NOEXCEPT_((__noexcept_move_assign_container<_Allocator, __alloc_traits>::value))
2010-05-12 03:42:16 +08:00
{
__move_assign(__x, integral_constant<bool,
__alloc_traits::propagate_on_container_move_assignment::value>());
return *this;
}
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
void
vector<_Tp, _Allocator>::__move_assign(vector& __c, false_type)
_NOEXCEPT_(__alloc_traits::is_always_equal::value)
2010-05-12 03:42:16 +08:00
{
if (__alloc() != __c.__alloc())
2010-05-12 03:42:16 +08:00
{
typedef move_iterator<iterator> _Ip;
assign(_Ip(__c.begin()), _Ip(__c.end()));
2010-05-12 03:42:16 +08:00
}
else
__move_assign(__c, true_type());
}
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
void
vector<_Tp, _Allocator>::__move_assign(vector& __c, true_type)
_NOEXCEPT_(is_nothrow_move_assignable<allocator_type>::value)
2010-05-12 03:42:16 +08:00
{
__vdeallocate();
__move_assign_alloc(__c); // this can throw
2010-05-12 03:42:16 +08:00
this->__begin_ = __c.__begin_;
this->__end_ = __c.__end_;
this->__end_cap() = __c.__end_cap();
__c.__begin_ = __c.__end_ = __c.__end_cap() = nullptr;
std::__debug_db_swap(this, std::addressof(__c));
2010-05-12 03:42:16 +08:00
}
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
inline _LIBCPP_INLINE_VISIBILITY
2010-05-12 03:42:16 +08:00
vector<_Tp, _Allocator>&
vector<_Tp, _Allocator>::operator=(const vector& __x)
{
if (this != _VSTD::addressof(__x))
2010-05-12 03:42:16 +08:00
{
__copy_assign_alloc(__x);
2010-05-12 03:42:16 +08:00
assign(__x.__begin_, __x.__end_);
}
return *this;
}
template <class _Tp, class _Allocator>
template <class _InputIterator>
_LIBCPP_CONSTEXPR_AFTER_CXX17 typename enable_if <__is_exactly_cpp17_input_iterator<_InputIterator>::value &&
is_constructible<
_Tp,
typename iterator_traits<_InputIterator>::reference>::value,
2010-05-12 03:42:16 +08:00
void
>::type
vector<_Tp, _Allocator>::assign(_InputIterator __first, _InputIterator __last)
{
clear();
for (; __first != __last; ++__first)
emplace_back(*__first);
2010-05-12 03:42:16 +08:00
}
template <class _Tp, class _Allocator>
template <class _ForwardIterator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
typename enable_if
<
__is_cpp17_forward_iterator<_ForwardIterator>::value &&
is_constructible<
_Tp,
typename iterator_traits<_ForwardIterator>::reference>::value,
2010-05-12 03:42:16 +08:00
void
>::type
vector<_Tp, _Allocator>::assign(_ForwardIterator __first, _ForwardIterator __last)
{
size_type __new_size = static_cast<size_type>(_VSTD::distance(__first, __last));
if (__new_size <= capacity())
2010-05-12 03:42:16 +08:00
{
_ForwardIterator __mid = __last;
bool __growing = false;
if (__new_size > size())
2010-05-12 03:42:16 +08:00
{
__growing = true;
__mid = __first;
_VSTD::advance(__mid, size());
2010-05-12 03:42:16 +08:00
}
pointer __m = _VSTD::copy(__first, __mid, this->__begin_);
2010-05-12 03:42:16 +08:00
if (__growing)
__construct_at_end(__mid, __last, __new_size - size());
2010-05-12 03:42:16 +08:00
else
this->__destruct_at_end(__m);
}
else
{
__vdeallocate();
__vallocate(__recommend(__new_size));
__construct_at_end(__first, __last, __new_size);
2010-05-12 03:42:16 +08:00
}
std::__debug_db_invalidate_all(this);
2010-05-12 03:42:16 +08:00
}
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
void
vector<_Tp, _Allocator>::assign(size_type __n, const_reference __u)
{
if (__n <= capacity())
{
size_type __s = size();
_VSTD::fill_n(this->__begin_, _VSTD::min(__n, __s), __u);
2010-05-12 03:42:16 +08:00
if (__n > __s)
__construct_at_end(__n - __s, __u);
else
this->__destruct_at_end(this->__begin_ + __n);
2010-05-12 03:42:16 +08:00
}
else
{
__vdeallocate();
__vallocate(__recommend(static_cast<size_type>(__n)));
2010-05-12 03:42:16 +08:00
__construct_at_end(__n, __u);
}
std::__debug_db_invalidate_all(this);
2010-05-12 03:42:16 +08:00
}
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
inline _LIBCPP_INLINE_VISIBILITY
2010-05-12 03:42:16 +08:00
typename vector<_Tp, _Allocator>::iterator
vector<_Tp, _Allocator>::begin() _NOEXCEPT
2010-05-12 03:42:16 +08:00
{
return iterator(this, this->__begin_);
2010-05-12 03:42:16 +08:00
}
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
inline _LIBCPP_INLINE_VISIBILITY
2010-05-12 03:42:16 +08:00
typename vector<_Tp, _Allocator>::const_iterator
vector<_Tp, _Allocator>::begin() const _NOEXCEPT
2010-05-12 03:42:16 +08:00
{
return const_iterator(this, this->__begin_);
2010-05-12 03:42:16 +08:00
}
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
inline _LIBCPP_INLINE_VISIBILITY
2010-05-12 03:42:16 +08:00
typename vector<_Tp, _Allocator>::iterator
vector<_Tp, _Allocator>::end() _NOEXCEPT
2010-05-12 03:42:16 +08:00
{
return iterator(this, this->__end_);
2010-05-12 03:42:16 +08:00
}
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
inline _LIBCPP_INLINE_VISIBILITY
2010-05-12 03:42:16 +08:00
typename vector<_Tp, _Allocator>::const_iterator
vector<_Tp, _Allocator>::end() const _NOEXCEPT
2010-05-12 03:42:16 +08:00
{
return const_iterator(this, this->__end_);
2010-05-12 03:42:16 +08:00
}
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
inline _LIBCPP_INLINE_VISIBILITY
2010-05-12 03:42:16 +08:00
typename vector<_Tp, _Allocator>::reference
vector<_Tp, _Allocator>::operator[](size_type __n) _NOEXCEPT
2010-05-12 03:42:16 +08:00
{
_LIBCPP_ASSERT(__n < size(), "vector[] index out of bounds");
2010-05-12 03:42:16 +08:00
return this->__begin_[__n];
}
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
inline _LIBCPP_INLINE_VISIBILITY
2010-05-12 03:42:16 +08:00
typename vector<_Tp, _Allocator>::const_reference
vector<_Tp, _Allocator>::operator[](size_type __n) const _NOEXCEPT
2010-05-12 03:42:16 +08:00
{
_LIBCPP_ASSERT(__n < size(), "vector[] index out of bounds");
2010-05-12 03:42:16 +08:00
return this->__begin_[__n];
}
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
typename vector<_Tp, _Allocator>::reference
vector<_Tp, _Allocator>::at(size_type __n)
{
if (__n >= size())
this->__throw_out_of_range();
return this->__begin_[__n];
}
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
typename vector<_Tp, _Allocator>::const_reference
vector<_Tp, _Allocator>::at(size_type __n) const
{
if (__n >= size())
this->__throw_out_of_range();
return this->__begin_[__n];
}
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
void
vector<_Tp, _Allocator>::reserve(size_type __n)
{
if (__n > capacity())
{
if (__n > max_size())
this->__throw_length_error();
2010-05-12 03:42:16 +08:00
allocator_type& __a = this->__alloc();
__split_buffer<value_type, allocator_type&> __v(__n, size(), __a);
2010-05-12 03:42:16 +08:00
__swap_out_circular_buffer(__v);
}
}
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
void
vector<_Tp, _Allocator>::shrink_to_fit() _NOEXCEPT
2010-05-12 03:42:16 +08:00
{
if (capacity() > size())
{
#ifndef _LIBCPP_NO_EXCEPTIONS
try
{
#endif // _LIBCPP_NO_EXCEPTIONS
2010-05-12 03:42:16 +08:00
allocator_type& __a = this->__alloc();
__split_buffer<value_type, allocator_type&> __v(size(), size(), __a);
2010-05-12 03:42:16 +08:00
__swap_out_circular_buffer(__v);
#ifndef _LIBCPP_NO_EXCEPTIONS
}
catch (...)
{
}
#endif // _LIBCPP_NO_EXCEPTIONS
2010-05-12 03:42:16 +08:00
}
}
template <class _Tp, class _Allocator>
template <class _Up>
_LIBCPP_CONSTEXPR_AFTER_CXX17
void
vector<_Tp, _Allocator>::__push_back_slow_path(_Up&& __x)
{
allocator_type& __a = this->__alloc();
__split_buffer<value_type, allocator_type&> __v(__recommend(size() + 1), size(), __a);
// __v.push_back(_VSTD::forward<_Up>(__x));
__alloc_traits::construct(__a, _VSTD::__to_address(__v.__end_), _VSTD::forward<_Up>(__x));
__v.__end_++;
__swap_out_circular_buffer(__v);
}
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
inline _LIBCPP_INLINE_VISIBILITY
2010-05-12 03:42:16 +08:00
void
vector<_Tp, _Allocator>::push_back(const_reference __x)
{
if (this->__end_ != this->__end_cap())
2010-05-12 03:42:16 +08:00
{
Fix PR35637: suboptimal codegen for `vector<unsigned char>`. The optimizer is petulant and temperamental. In this case LLVM failed to lower the the "insert at end" loop used by`vector<unsigned char>` to a `memset` despite `memset` being substantially faster over a range of bytes. LLVM has the ability to lower loops to `memset` whet appropriate, but the odd nature of libc++'s loops prevented the optimization from taking places. This patch addresses the issue by rewriting the loops from the form `do [ ... --__n; } while (__n > 0);` to instead use a for loop over a pointer range (For example: `for (auto *__i = ...; __i < __e; ++__i)`). This patch also rewrites the asan annotations to unposion all additional memory at the start of the loop instead of once per iterations. This could potentially permit false negatives where the constructor of element N attempts to access element N + 1 during its construction. The before and after results for the `BM_ConstructSize/vector_byte/5140480_mean` benchmark (run 5 times) are: -------------------------------------------------------------------------------------------- Benchmark Time CPU Iterations -------------------------------------------------------------------------------------------- Before ------ BM_ConstructSize/vector_byte/5140480_mean 12530140 ns 12469693 ns N/A BM_ConstructSize/vector_byte/5140480_median 12512818 ns 12445571 ns N/A BM_ConstructSize/vector_byte/5140480_stddev 106224 ns 107907 ns 5 ----- After ----- BM_ConstructSize/vector_byte/5140480_mean 167285 ns 166500 ns N/A BM_ConstructSize/vector_byte/5140480_median 166749 ns 166069 ns N/A BM_ConstructSize/vector_byte/5140480_stddev 3242 ns 3184 ns 5 llvm-svn: 367183
2019-07-28 12:37:02 +08:00
__construct_one_at_end(__x);
2010-05-12 03:42:16 +08:00
}
else
__push_back_slow_path(__x);
2010-05-12 03:42:16 +08:00
}
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
inline _LIBCPP_INLINE_VISIBILITY
2010-05-12 03:42:16 +08:00
void
vector<_Tp, _Allocator>::push_back(value_type&& __x)
{
if (this->__end_ < this->__end_cap())
{
Fix PR35637: suboptimal codegen for `vector<unsigned char>`. The optimizer is petulant and temperamental. In this case LLVM failed to lower the the "insert at end" loop used by`vector<unsigned char>` to a `memset` despite `memset` being substantially faster over a range of bytes. LLVM has the ability to lower loops to `memset` whet appropriate, but the odd nature of libc++'s loops prevented the optimization from taking places. This patch addresses the issue by rewriting the loops from the form `do [ ... --__n; } while (__n > 0);` to instead use a for loop over a pointer range (For example: `for (auto *__i = ...; __i < __e; ++__i)`). This patch also rewrites the asan annotations to unposion all additional memory at the start of the loop instead of once per iterations. This could potentially permit false negatives where the constructor of element N attempts to access element N + 1 during its construction. The before and after results for the `BM_ConstructSize/vector_byte/5140480_mean` benchmark (run 5 times) are: -------------------------------------------------------------------------------------------- Benchmark Time CPU Iterations -------------------------------------------------------------------------------------------- Before ------ BM_ConstructSize/vector_byte/5140480_mean 12530140 ns 12469693 ns N/A BM_ConstructSize/vector_byte/5140480_median 12512818 ns 12445571 ns N/A BM_ConstructSize/vector_byte/5140480_stddev 106224 ns 107907 ns 5 ----- After ----- BM_ConstructSize/vector_byte/5140480_mean 167285 ns 166500 ns N/A BM_ConstructSize/vector_byte/5140480_median 166749 ns 166069 ns N/A BM_ConstructSize/vector_byte/5140480_stddev 3242 ns 3184 ns 5 llvm-svn: 367183
2019-07-28 12:37:02 +08:00
__construct_one_at_end(_VSTD::move(__x));
2010-05-12 03:42:16 +08:00
}
else
__push_back_slow_path(_VSTD::move(__x));
2010-05-12 03:42:16 +08:00
}
template <class _Tp, class _Allocator>
template <class... _Args>
_LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
void
vector<_Tp, _Allocator>::__emplace_back_slow_path(_Args&&... __args)
{
allocator_type& __a = this->__alloc();
__split_buffer<value_type, allocator_type&> __v(__recommend(size() + 1), size(), __a);
// __v.emplace_back(_VSTD::forward<_Args>(__args)...);
__alloc_traits::construct(__a, _VSTD::__to_address(__v.__end_), _VSTD::forward<_Args>(__args)...);
__v.__end_++;
__swap_out_circular_buffer(__v);
}
template <class _Tp, class _Allocator>
template <class... _Args>
_LIBCPP_CONSTEXPR_AFTER_CXX17
inline
#if _LIBCPP_STD_VER > 14
typename vector<_Tp, _Allocator>::reference
#else
void
#endif
2010-05-12 03:42:16 +08:00
vector<_Tp, _Allocator>::emplace_back(_Args&&... __args)
{
if (this->__end_ < this->__end_cap())
{
Fix PR35637: suboptimal codegen for `vector<unsigned char>`. The optimizer is petulant and temperamental. In this case LLVM failed to lower the the "insert at end" loop used by`vector<unsigned char>` to a `memset` despite `memset` being substantially faster over a range of bytes. LLVM has the ability to lower loops to `memset` whet appropriate, but the odd nature of libc++'s loops prevented the optimization from taking places. This patch addresses the issue by rewriting the loops from the form `do [ ... --__n; } while (__n > 0);` to instead use a for loop over a pointer range (For example: `for (auto *__i = ...; __i < __e; ++__i)`). This patch also rewrites the asan annotations to unposion all additional memory at the start of the loop instead of once per iterations. This could potentially permit false negatives where the constructor of element N attempts to access element N + 1 during its construction. The before and after results for the `BM_ConstructSize/vector_byte/5140480_mean` benchmark (run 5 times) are: -------------------------------------------------------------------------------------------- Benchmark Time CPU Iterations -------------------------------------------------------------------------------------------- Before ------ BM_ConstructSize/vector_byte/5140480_mean 12530140 ns 12469693 ns N/A BM_ConstructSize/vector_byte/5140480_median 12512818 ns 12445571 ns N/A BM_ConstructSize/vector_byte/5140480_stddev 106224 ns 107907 ns 5 ----- After ----- BM_ConstructSize/vector_byte/5140480_mean 167285 ns 166500 ns N/A BM_ConstructSize/vector_byte/5140480_median 166749 ns 166069 ns N/A BM_ConstructSize/vector_byte/5140480_stddev 3242 ns 3184 ns 5 llvm-svn: 367183
2019-07-28 12:37:02 +08:00
__construct_one_at_end(_VSTD::forward<_Args>(__args)...);
2010-05-12 03:42:16 +08:00
}
else
__emplace_back_slow_path(_VSTD::forward<_Args>(__args)...);
#if _LIBCPP_STD_VER > 14
return this->back();
#endif
2010-05-12 03:42:16 +08:00
}
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
inline
2010-05-12 03:42:16 +08:00
void
vector<_Tp, _Allocator>::pop_back()
{
_LIBCPP_ASSERT(!empty(), "vector::pop_back called on an empty vector");
2010-05-12 03:42:16 +08:00
this->__destruct_at_end(this->__end_ - 1);
}
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
inline _LIBCPP_INLINE_VISIBILITY
2010-05-12 03:42:16 +08:00
typename vector<_Tp, _Allocator>::iterator
vector<_Tp, _Allocator>::erase(const_iterator __position)
{
_LIBCPP_DEBUG_ASSERT(__get_const_db()->__find_c_from_i(_VSTD::addressof(__position)) == this,
"vector::erase(iterator) called with an iterator not referring to this vector");
_LIBCPP_ASSERT(__position != end(),
"vector::erase(iterator) called with a non-dereferenceable iterator");
difference_type __ps = __position - cbegin();
pointer __p = this->__begin_ + __ps;
this->__destruct_at_end(_VSTD::move(__p + 1, this->__end_, __p));
if (!__libcpp_is_constant_evaluated())
this->__invalidate_iterators_past(__p - 1);
iterator __r = iterator(this, __p);
2010-05-12 03:42:16 +08:00
return __r;
}
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
typename vector<_Tp, _Allocator>::iterator
vector<_Tp, _Allocator>::erase(const_iterator __first, const_iterator __last)
{
_LIBCPP_DEBUG_ASSERT(__get_const_db()->__find_c_from_i(_VSTD::addressof(__first)) == this,
"vector::erase(iterator, iterator) called with an iterator not referring to this vector");
_LIBCPP_DEBUG_ASSERT(__get_const_db()->__find_c_from_i(_VSTD::addressof(__last)) == this,
"vector::erase(iterator, iterator) called with an iterator not referring to this vector");
_LIBCPP_ASSERT(__first <= __last, "vector::erase(first, last) called with invalid range");
2010-05-12 03:42:16 +08:00
pointer __p = this->__begin_ + (__first - begin());
if (__first != __last) {
this->__destruct_at_end(_VSTD::move(__p + (__last - __first), this->__end_, __p));
if (!__libcpp_is_constant_evaluated())
this->__invalidate_iterators_past(__p - 1);
}
iterator __r = iterator(this, __p);
2010-05-12 03:42:16 +08:00
return __r;
}
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
void
vector<_Tp, _Allocator>::__move_range(pointer __from_s, pointer __from_e, pointer __to)
{
pointer __old_last = this->__end_;
difference_type __n = __old_last - __to;
Fix PR35637: suboptimal codegen for `vector<unsigned char>`. The optimizer is petulant and temperamental. In this case LLVM failed to lower the the "insert at end" loop used by`vector<unsigned char>` to a `memset` despite `memset` being substantially faster over a range of bytes. LLVM has the ability to lower loops to `memset` whet appropriate, but the odd nature of libc++'s loops prevented the optimization from taking places. This patch addresses the issue by rewriting the loops from the form `do [ ... --__n; } while (__n > 0);` to instead use a for loop over a pointer range (For example: `for (auto *__i = ...; __i < __e; ++__i)`). This patch also rewrites the asan annotations to unposion all additional memory at the start of the loop instead of once per iterations. This could potentially permit false negatives where the constructor of element N attempts to access element N + 1 during its construction. The before and after results for the `BM_ConstructSize/vector_byte/5140480_mean` benchmark (run 5 times) are: -------------------------------------------------------------------------------------------- Benchmark Time CPU Iterations -------------------------------------------------------------------------------------------- Before ------ BM_ConstructSize/vector_byte/5140480_mean 12530140 ns 12469693 ns N/A BM_ConstructSize/vector_byte/5140480_median 12512818 ns 12445571 ns N/A BM_ConstructSize/vector_byte/5140480_stddev 106224 ns 107907 ns 5 ----- After ----- BM_ConstructSize/vector_byte/5140480_mean 167285 ns 166500 ns N/A BM_ConstructSize/vector_byte/5140480_median 166749 ns 166069 ns N/A BM_ConstructSize/vector_byte/5140480_stddev 3242 ns 3184 ns 5 llvm-svn: 367183
2019-07-28 12:37:02 +08:00
{
pointer __i = __from_s + __n;
_ConstructTransaction __tx(*this, __from_e - __i);
for (pointer __pos = __tx.__pos_; __i < __from_e;
++__i, (void) ++__pos, __tx.__pos_ = __pos) {
Fix PR35637: suboptimal codegen for `vector<unsigned char>`. The optimizer is petulant and temperamental. In this case LLVM failed to lower the the "insert at end" loop used by`vector<unsigned char>` to a `memset` despite `memset` being substantially faster over a range of bytes. LLVM has the ability to lower loops to `memset` whet appropriate, but the odd nature of libc++'s loops prevented the optimization from taking places. This patch addresses the issue by rewriting the loops from the form `do [ ... --__n; } while (__n > 0);` to instead use a for loop over a pointer range (For example: `for (auto *__i = ...; __i < __e; ++__i)`). This patch also rewrites the asan annotations to unposion all additional memory at the start of the loop instead of once per iterations. This could potentially permit false negatives where the constructor of element N attempts to access element N + 1 during its construction. The before and after results for the `BM_ConstructSize/vector_byte/5140480_mean` benchmark (run 5 times) are: -------------------------------------------------------------------------------------------- Benchmark Time CPU Iterations -------------------------------------------------------------------------------------------- Before ------ BM_ConstructSize/vector_byte/5140480_mean 12530140 ns 12469693 ns N/A BM_ConstructSize/vector_byte/5140480_median 12512818 ns 12445571 ns N/A BM_ConstructSize/vector_byte/5140480_stddev 106224 ns 107907 ns 5 ----- After ----- BM_ConstructSize/vector_byte/5140480_mean 167285 ns 166500 ns N/A BM_ConstructSize/vector_byte/5140480_median 166749 ns 166069 ns N/A BM_ConstructSize/vector_byte/5140480_stddev 3242 ns 3184 ns 5 llvm-svn: 367183
2019-07-28 12:37:02 +08:00
__alloc_traits::construct(this->__alloc(),
_VSTD::__to_address(__pos),
Fix PR35637: suboptimal codegen for `vector<unsigned char>`. The optimizer is petulant and temperamental. In this case LLVM failed to lower the the "insert at end" loop used by`vector<unsigned char>` to a `memset` despite `memset` being substantially faster over a range of bytes. LLVM has the ability to lower loops to `memset` whet appropriate, but the odd nature of libc++'s loops prevented the optimization from taking places. This patch addresses the issue by rewriting the loops from the form `do [ ... --__n; } while (__n > 0);` to instead use a for loop over a pointer range (For example: `for (auto *__i = ...; __i < __e; ++__i)`). This patch also rewrites the asan annotations to unposion all additional memory at the start of the loop instead of once per iterations. This could potentially permit false negatives where the constructor of element N attempts to access element N + 1 during its construction. The before and after results for the `BM_ConstructSize/vector_byte/5140480_mean` benchmark (run 5 times) are: -------------------------------------------------------------------------------------------- Benchmark Time CPU Iterations -------------------------------------------------------------------------------------------- Before ------ BM_ConstructSize/vector_byte/5140480_mean 12530140 ns 12469693 ns N/A BM_ConstructSize/vector_byte/5140480_median 12512818 ns 12445571 ns N/A BM_ConstructSize/vector_byte/5140480_stddev 106224 ns 107907 ns 5 ----- After ----- BM_ConstructSize/vector_byte/5140480_mean 167285 ns 166500 ns N/A BM_ConstructSize/vector_byte/5140480_median 166749 ns 166069 ns N/A BM_ConstructSize/vector_byte/5140480_stddev 3242 ns 3184 ns 5 llvm-svn: 367183
2019-07-28 12:37:02 +08:00
_VSTD::move(*__i));
}
}
_VSTD::move_backward(__from_s, __from_s + __n, __old_last);
2010-05-12 03:42:16 +08:00
}
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
typename vector<_Tp, _Allocator>::iterator
vector<_Tp, _Allocator>::insert(const_iterator __position, const_reference __x)
{
_LIBCPP_DEBUG_ASSERT(__get_const_db()->__find_c_from_i(_VSTD::addressof(__position)) == this,
"vector::insert(iterator, x) called with an iterator not referring to this vector");
2010-05-12 03:42:16 +08:00
pointer __p = this->__begin_ + (__position - begin());
// We can't compare unrelated pointers inside constant expressions
if (!__libcpp_is_constant_evaluated() && this->__end_ < this->__end_cap())
2010-05-12 03:42:16 +08:00
{
if (__p == this->__end_)
{
Fix PR35637: suboptimal codegen for `vector<unsigned char>`. The optimizer is petulant and temperamental. In this case LLVM failed to lower the the "insert at end" loop used by`vector<unsigned char>` to a `memset` despite `memset` being substantially faster over a range of bytes. LLVM has the ability to lower loops to `memset` whet appropriate, but the odd nature of libc++'s loops prevented the optimization from taking places. This patch addresses the issue by rewriting the loops from the form `do [ ... --__n; } while (__n > 0);` to instead use a for loop over a pointer range (For example: `for (auto *__i = ...; __i < __e; ++__i)`). This patch also rewrites the asan annotations to unposion all additional memory at the start of the loop instead of once per iterations. This could potentially permit false negatives where the constructor of element N attempts to access element N + 1 during its construction. The before and after results for the `BM_ConstructSize/vector_byte/5140480_mean` benchmark (run 5 times) are: -------------------------------------------------------------------------------------------- Benchmark Time CPU Iterations -------------------------------------------------------------------------------------------- Before ------ BM_ConstructSize/vector_byte/5140480_mean 12530140 ns 12469693 ns N/A BM_ConstructSize/vector_byte/5140480_median 12512818 ns 12445571 ns N/A BM_ConstructSize/vector_byte/5140480_stddev 106224 ns 107907 ns 5 ----- After ----- BM_ConstructSize/vector_byte/5140480_mean 167285 ns 166500 ns N/A BM_ConstructSize/vector_byte/5140480_median 166749 ns 166069 ns N/A BM_ConstructSize/vector_byte/5140480_stddev 3242 ns 3184 ns 5 llvm-svn: 367183
2019-07-28 12:37:02 +08:00
__construct_one_at_end(__x);
2010-05-12 03:42:16 +08:00
}
else
{
__move_range(__p, this->__end_, __p + 1);
const_pointer __xr = pointer_traits<const_pointer>::pointer_to(__x);
if (__p <= __xr && __xr < this->__end_)
++__xr;
*__p = *__xr;
}
}
else
{
allocator_type& __a = this->__alloc();
__split_buffer<value_type, allocator_type&> __v(__recommend(size() + 1), __p - this->__begin_, __a);
__v.push_back(__x);
__p = __swap_out_circular_buffer(__v, __p);
}
return iterator(this, __p);
2010-05-12 03:42:16 +08:00
}
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
typename vector<_Tp, _Allocator>::iterator
vector<_Tp, _Allocator>::insert(const_iterator __position, value_type&& __x)
{
_LIBCPP_DEBUG_ASSERT(__get_const_db()->__find_c_from_i(_VSTD::addressof(__position)) == this,
"vector::insert(iterator, x) called with an iterator not referring to this vector");
2010-05-12 03:42:16 +08:00
pointer __p = this->__begin_ + (__position - begin());
if (this->__end_ < this->__end_cap())
{
if (__p == this->__end_)
{
Fix PR35637: suboptimal codegen for `vector<unsigned char>`. The optimizer is petulant and temperamental. In this case LLVM failed to lower the the "insert at end" loop used by`vector<unsigned char>` to a `memset` despite `memset` being substantially faster over a range of bytes. LLVM has the ability to lower loops to `memset` whet appropriate, but the odd nature of libc++'s loops prevented the optimization from taking places. This patch addresses the issue by rewriting the loops from the form `do [ ... --__n; } while (__n > 0);` to instead use a for loop over a pointer range (For example: `for (auto *__i = ...; __i < __e; ++__i)`). This patch also rewrites the asan annotations to unposion all additional memory at the start of the loop instead of once per iterations. This could potentially permit false negatives where the constructor of element N attempts to access element N + 1 during its construction. The before and after results for the `BM_ConstructSize/vector_byte/5140480_mean` benchmark (run 5 times) are: -------------------------------------------------------------------------------------------- Benchmark Time CPU Iterations -------------------------------------------------------------------------------------------- Before ------ BM_ConstructSize/vector_byte/5140480_mean 12530140 ns 12469693 ns N/A BM_ConstructSize/vector_byte/5140480_median 12512818 ns 12445571 ns N/A BM_ConstructSize/vector_byte/5140480_stddev 106224 ns 107907 ns 5 ----- After ----- BM_ConstructSize/vector_byte/5140480_mean 167285 ns 166500 ns N/A BM_ConstructSize/vector_byte/5140480_median 166749 ns 166069 ns N/A BM_ConstructSize/vector_byte/5140480_stddev 3242 ns 3184 ns 5 llvm-svn: 367183
2019-07-28 12:37:02 +08:00
__construct_one_at_end(_VSTD::move(__x));
2010-05-12 03:42:16 +08:00
}
else
{
__move_range(__p, this->__end_, __p + 1);
*__p = _VSTD::move(__x);
2010-05-12 03:42:16 +08:00
}
}
else
{
allocator_type& __a = this->__alloc();
__split_buffer<value_type, allocator_type&> __v(__recommend(size() + 1), __p - this->__begin_, __a);
__v.push_back(_VSTD::move(__x));
2010-05-12 03:42:16 +08:00
__p = __swap_out_circular_buffer(__v, __p);
}
return iterator(this, __p);
2010-05-12 03:42:16 +08:00
}
template <class _Tp, class _Allocator>
template <class... _Args>
_LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
typename vector<_Tp, _Allocator>::iterator
vector<_Tp, _Allocator>::emplace(const_iterator __position, _Args&&... __args)
{
_LIBCPP_DEBUG_ASSERT(__get_const_db()->__find_c_from_i(_VSTD::addressof(__position)) == this,
"vector::emplace(iterator, x) called with an iterator not referring to this vector");
2010-05-12 03:42:16 +08:00
pointer __p = this->__begin_ + (__position - begin());
if (this->__end_ < this->__end_cap())
{
if (__p == this->__end_)
{
Fix PR35637: suboptimal codegen for `vector<unsigned char>`. The optimizer is petulant and temperamental. In this case LLVM failed to lower the the "insert at end" loop used by`vector<unsigned char>` to a `memset` despite `memset` being substantially faster over a range of bytes. LLVM has the ability to lower loops to `memset` whet appropriate, but the odd nature of libc++'s loops prevented the optimization from taking places. This patch addresses the issue by rewriting the loops from the form `do [ ... --__n; } while (__n > 0);` to instead use a for loop over a pointer range (For example: `for (auto *__i = ...; __i < __e; ++__i)`). This patch also rewrites the asan annotations to unposion all additional memory at the start of the loop instead of once per iterations. This could potentially permit false negatives where the constructor of element N attempts to access element N + 1 during its construction. The before and after results for the `BM_ConstructSize/vector_byte/5140480_mean` benchmark (run 5 times) are: -------------------------------------------------------------------------------------------- Benchmark Time CPU Iterations -------------------------------------------------------------------------------------------- Before ------ BM_ConstructSize/vector_byte/5140480_mean 12530140 ns 12469693 ns N/A BM_ConstructSize/vector_byte/5140480_median 12512818 ns 12445571 ns N/A BM_ConstructSize/vector_byte/5140480_stddev 106224 ns 107907 ns 5 ----- After ----- BM_ConstructSize/vector_byte/5140480_mean 167285 ns 166500 ns N/A BM_ConstructSize/vector_byte/5140480_median 166749 ns 166069 ns N/A BM_ConstructSize/vector_byte/5140480_stddev 3242 ns 3184 ns 5 llvm-svn: 367183
2019-07-28 12:37:02 +08:00
__construct_one_at_end(_VSTD::forward<_Args>(__args)...);
2010-05-12 03:42:16 +08:00
}
else
{
__temp_value<value_type, _Allocator> __tmp(this->__alloc(), _VSTD::forward<_Args>(__args)...);
2010-05-12 03:42:16 +08:00
__move_range(__p, this->__end_, __p + 1);
*__p = _VSTD::move(__tmp.get());
2010-05-12 03:42:16 +08:00
}
}
else
{
allocator_type& __a = this->__alloc();
__split_buffer<value_type, allocator_type&> __v(__recommend(size() + 1), __p - this->__begin_, __a);
__v.emplace_back(_VSTD::forward<_Args>(__args)...);
2010-05-12 03:42:16 +08:00
__p = __swap_out_circular_buffer(__v, __p);
}
return iterator(this, __p);
2010-05-12 03:42:16 +08:00
}
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
typename vector<_Tp, _Allocator>::iterator
vector<_Tp, _Allocator>::insert(const_iterator __position, size_type __n, const_reference __x)
{
_LIBCPP_DEBUG_ASSERT(__get_const_db()->__find_c_from_i(_VSTD::addressof(__position)) == this,
"vector::insert(iterator, n, x) called with an iterator not referring to this vector");
2010-05-12 03:42:16 +08:00
pointer __p = this->__begin_ + (__position - begin());
if (__n > 0)
{
// We can't compare unrelated pointers inside constant expressions
if (!__libcpp_is_constant_evaluated() && __n <= static_cast<size_type>(this->__end_cap() - this->__end_))
2010-05-12 03:42:16 +08:00
{
size_type __old_n = __n;
pointer __old_last = this->__end_;
if (__n > static_cast<size_type>(this->__end_ - __p))
{
size_type __cx = __n - (this->__end_ - __p);
__construct_at_end(__cx, __x);
__n -= __cx;
}
if (__n > 0)
{
__move_range(__p, __old_last, __p + __old_n);
const_pointer __xr = pointer_traits<const_pointer>::pointer_to(__x);
if (__p <= __xr && __xr < this->__end_)
__xr += __old_n;
_VSTD::fill_n(__p, __n, *__xr);
2010-05-12 03:42:16 +08:00
}
}
else
{
allocator_type& __a = this->__alloc();
__split_buffer<value_type, allocator_type&> __v(__recommend(size() + __n), __p - this->__begin_, __a);
__v.__construct_at_end(__n, __x);
__p = __swap_out_circular_buffer(__v, __p);
}
}
return iterator(this, __p);
2010-05-12 03:42:16 +08:00
}
template <class _Tp, class _Allocator>
template <class _InputIterator>
_LIBCPP_CONSTEXPR_AFTER_CXX17 typename enable_if <__is_exactly_cpp17_input_iterator<_InputIterator>::value &&
is_constructible<
_Tp,
typename iterator_traits<_InputIterator>::reference>::value,
2010-05-12 03:42:16 +08:00
typename vector<_Tp, _Allocator>::iterator
>::type
vector<_Tp, _Allocator>::insert(const_iterator __position, _InputIterator __first, _InputIterator __last)
{
_LIBCPP_DEBUG_ASSERT(__get_const_db()->__find_c_from_i(_VSTD::addressof(__position)) == this,
"vector::insert(iterator, range) called with an iterator not referring to this vector");
2010-05-12 03:42:16 +08:00
difference_type __off = __position - begin();
pointer __p = this->__begin_ + __off;
allocator_type& __a = this->__alloc();
pointer __old_last = this->__end_;
for (; this->__end_ != this->__end_cap() && __first != __last; ++__first)
{
Fix PR35637: suboptimal codegen for `vector<unsigned char>`. The optimizer is petulant and temperamental. In this case LLVM failed to lower the the "insert at end" loop used by`vector<unsigned char>` to a `memset` despite `memset` being substantially faster over a range of bytes. LLVM has the ability to lower loops to `memset` whet appropriate, but the odd nature of libc++'s loops prevented the optimization from taking places. This patch addresses the issue by rewriting the loops from the form `do [ ... --__n; } while (__n > 0);` to instead use a for loop over a pointer range (For example: `for (auto *__i = ...; __i < __e; ++__i)`). This patch also rewrites the asan annotations to unposion all additional memory at the start of the loop instead of once per iterations. This could potentially permit false negatives where the constructor of element N attempts to access element N + 1 during its construction. The before and after results for the `BM_ConstructSize/vector_byte/5140480_mean` benchmark (run 5 times) are: -------------------------------------------------------------------------------------------- Benchmark Time CPU Iterations -------------------------------------------------------------------------------------------- Before ------ BM_ConstructSize/vector_byte/5140480_mean 12530140 ns 12469693 ns N/A BM_ConstructSize/vector_byte/5140480_median 12512818 ns 12445571 ns N/A BM_ConstructSize/vector_byte/5140480_stddev 106224 ns 107907 ns 5 ----- After ----- BM_ConstructSize/vector_byte/5140480_mean 167285 ns 166500 ns N/A BM_ConstructSize/vector_byte/5140480_median 166749 ns 166069 ns N/A BM_ConstructSize/vector_byte/5140480_stddev 3242 ns 3184 ns 5 llvm-svn: 367183
2019-07-28 12:37:02 +08:00
__construct_one_at_end(*__first);
2010-05-12 03:42:16 +08:00
}
__split_buffer<value_type, allocator_type&> __v(__a);
if (__first != __last)
{
#ifndef _LIBCPP_NO_EXCEPTIONS
try
{
#endif // _LIBCPP_NO_EXCEPTIONS
2010-05-12 03:42:16 +08:00
__v.__construct_at_end(__first, __last);
difference_type __old_size = __old_last - this->__begin_;
difference_type __old_p = __p - this->__begin_;
reserve(__recommend(size() + __v.size()));
__p = this->__begin_ + __old_p;
__old_last = this->__begin_ + __old_size;
#ifndef _LIBCPP_NO_EXCEPTIONS
}
catch (...)
{
erase(iterator(this, __old_last), end());
2010-05-12 03:42:16 +08:00
throw;
}
#endif // _LIBCPP_NO_EXCEPTIONS
2010-05-12 03:42:16 +08:00
}
__p = _VSTD::rotate(__p, __old_last, this->__end_);
insert(iterator(this, __p), _VSTD::make_move_iterator(__v.begin()),
_VSTD::make_move_iterator(__v.end()));
2010-05-12 03:42:16 +08:00
return begin() + __off;
}
template <class _Tp, class _Allocator>
template <class _ForwardIterator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
typename enable_if
<
__is_cpp17_forward_iterator<_ForwardIterator>::value &&
is_constructible<
_Tp,
typename iterator_traits<_ForwardIterator>::reference>::value,
2010-05-12 03:42:16 +08:00
typename vector<_Tp, _Allocator>::iterator
>::type
vector<_Tp, _Allocator>::insert(const_iterator __position, _ForwardIterator __first, _ForwardIterator __last)
{
_LIBCPP_DEBUG_ASSERT(__get_const_db()->__find_c_from_i(_VSTD::addressof(__position)) == this,
"vector::insert(iterator, range) called with an iterator not referring to this vector");
2010-05-12 03:42:16 +08:00
pointer __p = this->__begin_ + (__position - begin());
difference_type __n = _VSTD::distance(__first, __last);
2010-05-12 03:42:16 +08:00
if (__n > 0)
{
if (__n <= this->__end_cap() - this->__end_)
{
size_type __old_n = __n;
pointer __old_last = this->__end_;
_ForwardIterator __m = __last;
difference_type __dx = this->__end_ - __p;
if (__n > __dx)
{
__m = __first;
difference_type __diff = this->__end_ - __p;
_VSTD::advance(__m, __diff);
__construct_at_end(__m, __last, __n - __diff);
2010-05-12 03:42:16 +08:00
__n = __dx;
}
if (__n > 0)
{
__move_range(__p, __old_last, __p + __old_n);
_VSTD::copy(__first, __m, __p);
2010-05-12 03:42:16 +08:00
}
}
else
{
allocator_type& __a = this->__alloc();
__split_buffer<value_type, allocator_type&> __v(__recommend(size() + __n), __p - this->__begin_, __a);
__v.__construct_at_end(__first, __last);
__p = __swap_out_circular_buffer(__v, __p);
}
}
return iterator(this, __p);
2010-05-12 03:42:16 +08:00
}
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
void
vector<_Tp, _Allocator>::resize(size_type __sz)
{
size_type __cs = size();
if (__cs < __sz)
this->__append(__sz - __cs);
else if (__cs > __sz)
this->__destruct_at_end(this->__begin_ + __sz);
}
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
void
vector<_Tp, _Allocator>::resize(size_type __sz, const_reference __x)
{
size_type __cs = size();
if (__cs < __sz)
this->__append(__sz - __cs, __x);
else if (__cs > __sz)
this->__destruct_at_end(this->__begin_ + __sz);
}
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
void
vector<_Tp, _Allocator>::swap(vector& __x)
#if _LIBCPP_STD_VER >= 14
_NOEXCEPT
#else
_NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value ||
__is_nothrow_swappable<allocator_type>::value)
#endif
2010-05-12 03:42:16 +08:00
{
_LIBCPP_ASSERT(__alloc_traits::propagate_on_container_swap::value ||
this->__alloc() == __x.__alloc(),
"vector::swap: Either propagate_on_container_swap must be true"
" or the allocators must compare equal");
_VSTD::swap(this->__begin_, __x.__begin_);
_VSTD::swap(this->__end_, __x.__end_);
_VSTD::swap(this->__end_cap(), __x.__end_cap());
_VSTD::__swap_allocator(this->__alloc(), __x.__alloc(),
integral_constant<bool,__alloc_traits::propagate_on_container_swap::value>());
std::__debug_db_swap(this, std::addressof(__x));
2010-05-12 03:42:16 +08:00
}
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
bool
vector<_Tp, _Allocator>::__invariants() const
{
if (this->__begin_ == nullptr)
2010-05-12 03:42:16 +08:00
{
if (this->__end_ != nullptr || this->__end_cap() != nullptr)
2010-05-12 03:42:16 +08:00
return false;
}
else
{
if (this->__begin_ > this->__end_)
return false;
if (this->__begin_ == this->__end_cap())
return false;
if (this->__end_ > this->__end_cap())
return false;
}
return true;
}
#ifdef _LIBCPP_ENABLE_DEBUG_MODE
template <class _Tp, class _Allocator>
bool
vector<_Tp, _Allocator>::__dereferenceable(const const_iterator* __i) const
{
return this->__begin_ <= __i->base() && __i->base() < this->__end_;
}
template <class _Tp, class _Allocator>
bool
vector<_Tp, _Allocator>::__decrementable(const const_iterator* __i) const
{
return this->__begin_ < __i->base() && __i->base() <= this->__end_;
}
template <class _Tp, class _Allocator>
bool
vector<_Tp, _Allocator>::__addable(const const_iterator* __i, ptrdiff_t __n) const
{
const_pointer __p = __i->base() + __n;
return this->__begin_ <= __p && __p <= this->__end_;
}
template <class _Tp, class _Allocator>
bool
vector<_Tp, _Allocator>::__subscriptable(const const_iterator* __i, ptrdiff_t __n) const
{
const_pointer __p = __i->base() + __n;
return this->__begin_ <= __p && __p < this->__end_;
}
#endif // _LIBCPP_ENABLE_DEBUG_MODE
template <class _Tp, class _Allocator>
inline _LIBCPP_INLINE_VISIBILITY
void
vector<_Tp, _Allocator>::__invalidate_iterators_past(pointer __new_last) {
#ifdef _LIBCPP_ENABLE_DEBUG_MODE
__c_node* __c = __get_db()->__find_c_and_lock(this);
for (__i_node** __p = __c->end_; __p != __c->beg_; ) {
--__p;
const_iterator* __i = static_cast<const_iterator*>((*__p)->__i_);
if (__i->base() > __new_last) {
(*__p)->__c_ = nullptr;
if (--__c->end_ != __p)
_VSTD::memmove(__p, __p+1, (__c->end_ - __p)*sizeof(__i_node*));
}
}
__get_db()->unlock();
#else
((void)__new_last);
#endif
}
2010-05-12 03:42:16 +08:00
// vector<bool>
template <class _Allocator> class vector<bool, _Allocator>;
template <class _Allocator> struct hash<vector<bool, _Allocator> >;
template <class _Allocator>
struct __has_storage_type<vector<bool, _Allocator> >
{
static const bool value = true;
};
2010-05-12 03:42:16 +08:00
template <class _Allocator>
class _LIBCPP_TEMPLATE_VIS vector<bool, _Allocator>
2010-05-12 03:42:16 +08:00
{
public:
typedef vector __self;
typedef bool value_type;
2010-05-12 03:42:16 +08:00
typedef _Allocator allocator_type;
typedef allocator_traits<allocator_type> __alloc_traits;
typedef typename __alloc_traits::size_type size_type;
typedef typename __alloc_traits::difference_type difference_type;
typedef size_type __storage_type;
2010-05-12 03:42:16 +08:00
typedef __bit_iterator<vector, false> pointer;
typedef __bit_iterator<vector, true> const_pointer;
typedef pointer iterator;
typedef const_pointer const_iterator;
typedef _VSTD::reverse_iterator<iterator> reverse_iterator;
typedef _VSTD::reverse_iterator<const_iterator> const_reverse_iterator;
2010-05-12 03:42:16 +08:00
private:
typedef typename __rebind_alloc_helper<__alloc_traits, __storage_type>::type __storage_allocator;
2010-05-12 03:42:16 +08:00
typedef allocator_traits<__storage_allocator> __storage_traits;
typedef typename __storage_traits::pointer __storage_pointer;
typedef typename __storage_traits::const_pointer __const_storage_pointer;
__storage_pointer __begin_;
size_type __size_;
__compressed_pair<size_type, __storage_allocator> __cap_alloc_;
public:
typedef __bit_reference<vector> reference;
#ifdef _LIBCPP_ABI_BITSET_VECTOR_BOOL_CONST_SUBSCRIPT_RETURN_BOOL
using const_reference = bool;
#else
typedef __bit_const_reference<vector> const_reference;
#endif
private:
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
size_type& __cap() _NOEXCEPT
{return __cap_alloc_.first();}
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
const size_type& __cap() const _NOEXCEPT
{return __cap_alloc_.first();}
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
__storage_allocator& __alloc() _NOEXCEPT
{return __cap_alloc_.second();}
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
const __storage_allocator& __alloc() const _NOEXCEPT
{return __cap_alloc_.second();}
2010-05-12 03:42:16 +08:00
static const unsigned __bits_per_word = static_cast<unsigned>(sizeof(__storage_type) * CHAR_BIT);
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
static size_type __internal_cap_to_external(size_type __n) _NOEXCEPT
2010-05-12 03:42:16 +08:00
{return __n * __bits_per_word;}
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
static size_type __external_cap_to_internal(size_type __n) _NOEXCEPT
2010-05-12 03:42:16 +08:00
{return (__n - 1) / __bits_per_word + 1;}
public:
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
vector() _NOEXCEPT_(is_nothrow_default_constructible<allocator_type>::value);
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 explicit vector(const allocator_type& __a)
#if _LIBCPP_STD_VER <= 14
_NOEXCEPT_(is_nothrow_copy_constructible<allocator_type>::value);
#else
_NOEXCEPT;
#endif
_LIBCPP_CONSTEXPR_AFTER_CXX17 ~vector();
_LIBCPP_CONSTEXPR_AFTER_CXX17 explicit vector(size_type __n);
#if _LIBCPP_STD_VER > 11
_LIBCPP_CONSTEXPR_AFTER_CXX17 explicit vector(size_type __n, const allocator_type& __a);
#endif
_LIBCPP_CONSTEXPR_AFTER_CXX17 vector(size_type __n, const value_type& __v);
_LIBCPP_CONSTEXPR_AFTER_CXX17 vector(size_type __n, const value_type& __v, const allocator_type& __a);
2010-05-12 03:42:16 +08:00
template <class _InputIterator>
_LIBCPP_CONSTEXPR_AFTER_CXX17 vector(_InputIterator __first, _InputIterator __last,
typename enable_if<__is_exactly_cpp17_input_iterator<_InputIterator>::value>::type* = 0);
2010-05-12 03:42:16 +08:00
template <class _InputIterator>
_LIBCPP_CONSTEXPR_AFTER_CXX17 vector(_InputIterator __first, _InputIterator __last, const allocator_type& __a,
typename enable_if<__is_exactly_cpp17_input_iterator<_InputIterator>::value>::type* = 0);
2010-05-12 03:42:16 +08:00
template <class _ForwardIterator>
_LIBCPP_CONSTEXPR_AFTER_CXX17 vector(_ForwardIterator __first, _ForwardIterator __last,
typename enable_if<__is_cpp17_forward_iterator<_ForwardIterator>::value>::type* = 0);
2010-05-12 03:42:16 +08:00
template <class _ForwardIterator>
_LIBCPP_CONSTEXPR_AFTER_CXX17 vector(_ForwardIterator __first, _ForwardIterator __last, const allocator_type& __a,
typename enable_if<__is_cpp17_forward_iterator<_ForwardIterator>::value>::type* = 0);
2010-05-12 03:42:16 +08:00
_LIBCPP_CONSTEXPR_AFTER_CXX17 vector(const vector& __v);
_LIBCPP_CONSTEXPR_AFTER_CXX17 vector(const vector& __v, const allocator_type& __a);
_LIBCPP_CONSTEXPR_AFTER_CXX17 vector& operator=(const vector& __v);
#ifndef _LIBCPP_CXX03_LANG
_LIBCPP_CONSTEXPR_AFTER_CXX17 vector(initializer_list<value_type> __il);
_LIBCPP_CONSTEXPR_AFTER_CXX17 vector(initializer_list<value_type> __il, const allocator_type& __a);
2010-05-12 03:42:16 +08:00
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
vector& operator=(initializer_list<value_type> __il)
{assign(__il.begin(), __il.end()); return *this;}
#endif // !_LIBCPP_CXX03_LANG
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
vector(vector&& __v)
#if _LIBCPP_STD_VER > 14
noexcept;
#else
_NOEXCEPT_(is_nothrow_move_constructible<allocator_type>::value);
#endif
_LIBCPP_CONSTEXPR_AFTER_CXX17 vector(vector&& __v, const __type_identity_t<allocator_type>& __a);
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
vector& operator=(vector&& __v)
_NOEXCEPT_((__noexcept_move_assign_container<_Allocator, __alloc_traits>::value));
2010-05-12 03:42:16 +08:00
template <class _InputIterator>
typename enable_if <__is_exactly_cpp17_input_iterator<_InputIterator>::value,
2010-05-12 03:42:16 +08:00
void
>::type
_LIBCPP_CONSTEXPR_AFTER_CXX17 assign(_InputIterator __first, _InputIterator __last);
2010-05-12 03:42:16 +08:00
template <class _ForwardIterator>
typename enable_if
<
__is_cpp17_forward_iterator<_ForwardIterator>::value,
2010-05-12 03:42:16 +08:00
void
>::type
_LIBCPP_CONSTEXPR_AFTER_CXX17 assign(_ForwardIterator __first, _ForwardIterator __last);
2010-05-12 03:42:16 +08:00
_LIBCPP_CONSTEXPR_AFTER_CXX17 void assign(size_type __n, const value_type& __x);
#ifndef _LIBCPP_CXX03_LANG
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
void assign(initializer_list<value_type> __il)
{assign(__il.begin(), __il.end());}
#endif
2010-05-12 03:42:16 +08:00
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 allocator_type get_allocator() const _NOEXCEPT
2010-05-12 03:42:16 +08:00
{return allocator_type(this->__alloc());}
_LIBCPP_CONSTEXPR_AFTER_CXX17 size_type max_size() const _NOEXCEPT;
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
size_type capacity() const _NOEXCEPT
{return __internal_cap_to_external(__cap());}
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
size_type size() const _NOEXCEPT
{return __size_;}
_LIBCPP_NODISCARD_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
bool empty() const _NOEXCEPT
{return __size_ == 0;}
_LIBCPP_CONSTEXPR_AFTER_CXX17 void reserve(size_type __n);
_LIBCPP_CONSTEXPR_AFTER_CXX17 void shrink_to_fit() _NOEXCEPT;
2010-05-12 03:42:16 +08:00
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
iterator begin() _NOEXCEPT
{return __make_iter(0);}
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
const_iterator begin() const _NOEXCEPT
{return __make_iter(0);}
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
iterator end() _NOEXCEPT
{return __make_iter(__size_);}
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
const_iterator end() const _NOEXCEPT
{return __make_iter(__size_);}
2010-05-12 03:42:16 +08:00
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
reverse_iterator rbegin() _NOEXCEPT
{return reverse_iterator(end());}
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
const_reverse_iterator rbegin() const _NOEXCEPT
{return const_reverse_iterator(end());}
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
reverse_iterator rend() _NOEXCEPT
{return reverse_iterator(begin());}
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
const_reverse_iterator rend() const _NOEXCEPT
{return const_reverse_iterator(begin());}
2010-05-12 03:42:16 +08:00
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
const_iterator cbegin() const _NOEXCEPT
{return __make_iter(0);}
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
const_iterator cend() const _NOEXCEPT
{return __make_iter(__size_);}
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
const_reverse_iterator crbegin() const _NOEXCEPT
{return rbegin();}
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
const_reverse_iterator crend() const _NOEXCEPT
{return rend();}
2010-05-12 03:42:16 +08:00
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 reference operator[](size_type __n) {return __make_ref(__n);}
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 const_reference operator[](size_type __n) const {return __make_ref(__n);}
2010-05-12 03:42:16 +08:00
reference at(size_type __n);
const_reference at(size_type __n) const;
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 reference front() {return __make_ref(0);}
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 const_reference front() const {return __make_ref(0);}
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 reference back() {return __make_ref(__size_ - 1);}
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 const_reference back() const {return __make_ref(__size_ - 1);}
2010-05-12 03:42:16 +08:00
_LIBCPP_CONSTEXPR_AFTER_CXX17 void push_back(const value_type& __x);
#if _LIBCPP_STD_VER > 11
template <class... _Args>
#if _LIBCPP_STD_VER > 14
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 reference emplace_back(_Args&&... __args)
#else
_LIBCPP_INLINE_VISIBILITY void emplace_back(_Args&&... __args)
#endif
{
push_back ( value_type ( _VSTD::forward<_Args>(__args)... ));
#if _LIBCPP_STD_VER > 14
return this->back();
#endif
}
#endif
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 void pop_back() {--__size_;}
2010-05-12 03:42:16 +08:00
#if _LIBCPP_STD_VER > 11
template <class... _Args>
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 iterator emplace(const_iterator __position, _Args&&... __args)
{ return insert ( __position, value_type ( _VSTD::forward<_Args>(__args)... )); }
#endif
_LIBCPP_CONSTEXPR_AFTER_CXX17 iterator insert(const_iterator __position, const value_type& __x);
_LIBCPP_CONSTEXPR_AFTER_CXX17 iterator insert(const_iterator __position, size_type __n, const value_type& __x);
2010-05-12 03:42:16 +08:00
template <class _InputIterator>
typename enable_if <__is_exactly_cpp17_input_iterator<_InputIterator>::value,
2010-05-12 03:42:16 +08:00
iterator
>::type
_LIBCPP_CONSTEXPR_AFTER_CXX17 insert(const_iterator __position, _InputIterator __first, _InputIterator __last);
2010-05-12 03:42:16 +08:00
template <class _ForwardIterator>
typename enable_if
<
__is_cpp17_forward_iterator<_ForwardIterator>::value,
2010-05-12 03:42:16 +08:00
iterator
>::type
_LIBCPP_CONSTEXPR_AFTER_CXX17 insert(const_iterator __position, _ForwardIterator __first, _ForwardIterator __last);
#ifndef _LIBCPP_CXX03_LANG
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
iterator insert(const_iterator __position, initializer_list<value_type> __il)
{return insert(__position, __il.begin(), __il.end());}
#endif
2010-05-12 03:42:16 +08:00
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 iterator erase(const_iterator __position);
_LIBCPP_CONSTEXPR_AFTER_CXX17 iterator erase(const_iterator __first, const_iterator __last);
2010-05-12 03:42:16 +08:00
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
void clear() _NOEXCEPT {__size_ = 0;}
2010-05-12 03:42:16 +08:00
_LIBCPP_CONSTEXPR_AFTER_CXX17 void swap(vector&)
#if _LIBCPP_STD_VER >= 14
_NOEXCEPT;
#else
_NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value ||
__is_nothrow_swappable<allocator_type>::value);
#endif
_LIBCPP_CONSTEXPR_AFTER_CXX17 static void swap(reference __x, reference __y) _NOEXCEPT { _VSTD::swap(__x, __y); }
2010-05-12 03:42:16 +08:00
_LIBCPP_CONSTEXPR_AFTER_CXX17 void resize(size_type __sz, value_type __x = false);
_LIBCPP_CONSTEXPR_AFTER_CXX17 void flip() _NOEXCEPT;
2010-05-12 03:42:16 +08:00
_LIBCPP_CONSTEXPR_AFTER_CXX17 bool __invariants() const;
2010-05-12 03:42:16 +08:00
private:
_LIBCPP_NORETURN _LIBCPP_HIDE_FROM_ABI
void __throw_length_error() const {
_VSTD::__throw_length_error("vector");
}
_LIBCPP_NORETURN _LIBCPP_HIDE_FROM_ABI
void __throw_out_of_range() const {
_VSTD::__throw_out_of_range("vector");
}
// Allocate space for __n objects
// throws length_error if __n > max_size()
// throws (probably bad_alloc) if memory run out
// Precondition: __begin_ == __end_ == __cap() == 0
// Precondition: __n > 0
// Postcondition: capacity() >= __n
// Postcondition: size() == 0
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 void __vallocate(size_type __n) {
if (__n > max_size())
__throw_length_error();
auto __allocation = std::__allocate_at_least(__alloc(), __external_cap_to_internal(__n));
__begin_ = __allocation.ptr;
__size_ = 0;
__cap() = __allocation.count;
if (__libcpp_is_constant_evaluated()) {
for (size_type __i = 0; __i != __cap(); ++__i)
std::__construct_at(std::__to_address(__begin_) + __i);
}
}
_LIBCPP_CONSTEXPR_AFTER_CXX17 void __vdeallocate() _NOEXCEPT;
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
static size_type __align_it(size_type __new_size) _NOEXCEPT
{return (__new_size + (__bits_per_word-1)) & ~((size_type)__bits_per_word-1);}
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 size_type __recommend(size_type __new_size) const;
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 void __construct_at_end(size_type __n, bool __x);
2010-05-12 03:42:16 +08:00
template <class _ForwardIterator>
typename enable_if
<
__is_cpp17_forward_iterator<_ForwardIterator>::value,
2010-05-12 03:42:16 +08:00
void
>::type
_LIBCPP_CONSTEXPR_AFTER_CXX17 __construct_at_end(_ForwardIterator __first, _ForwardIterator __last);
_LIBCPP_CONSTEXPR_AFTER_CXX17 void __append(size_type __n, const_reference __x);
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
reference __make_ref(size_type __pos) _NOEXCEPT
2010-05-12 03:42:16 +08:00
{return reference(__begin_ + __pos / __bits_per_word, __storage_type(1) << __pos % __bits_per_word);}
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
const_reference __make_ref(size_type __pos) const _NOEXCEPT {
return __bit_const_reference<vector>(__begin_ + __pos / __bits_per_word,
__storage_type(1) << __pos % __bits_per_word);
}
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
iterator __make_iter(size_type __pos) _NOEXCEPT
2010-05-12 03:42:16 +08:00
{return iterator(__begin_ + __pos / __bits_per_word, static_cast<unsigned>(__pos % __bits_per_word));}
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
const_iterator __make_iter(size_type __pos) const _NOEXCEPT
2010-05-12 03:42:16 +08:00
{return const_iterator(__begin_ + __pos / __bits_per_word, static_cast<unsigned>(__pos % __bits_per_word));}
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
iterator __const_iterator_cast(const_iterator __p) _NOEXCEPT
{return begin() + (__p - cbegin());}
2010-05-12 03:42:16 +08:00
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
void __copy_assign_alloc(const vector& __v)
{__copy_assign_alloc(__v, integral_constant<bool,
__storage_traits::propagate_on_container_copy_assignment::value>());}
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
void __copy_assign_alloc(const vector& __c, true_type)
{
if (__alloc() != __c.__alloc())
__vdeallocate();
2010-05-12 03:42:16 +08:00
__alloc() = __c.__alloc();
}
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
void __copy_assign_alloc(const vector&, false_type)
2010-05-12 03:42:16 +08:00
{}
_LIBCPP_CONSTEXPR_AFTER_CXX17 void __move_assign(vector& __c, false_type);
_LIBCPP_CONSTEXPR_AFTER_CXX17 void __move_assign(vector& __c, true_type)
_NOEXCEPT_(is_nothrow_move_assignable<allocator_type>::value);
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
void __move_assign_alloc(vector& __c)
_NOEXCEPT_(
!__storage_traits::propagate_on_container_move_assignment::value ||
is_nothrow_move_assignable<allocator_type>::value)
2010-05-12 03:42:16 +08:00
{__move_assign_alloc(__c, integral_constant<bool,
__storage_traits::propagate_on_container_move_assignment::value>());}
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
void __move_assign_alloc(vector& __c, true_type)
_NOEXCEPT_(is_nothrow_move_assignable<allocator_type>::value)
2010-05-12 03:42:16 +08:00
{
__alloc() = _VSTD::move(__c.__alloc());
2010-05-12 03:42:16 +08:00
}
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
void __move_assign_alloc(vector&, false_type)
_NOEXCEPT
2010-05-12 03:42:16 +08:00
{}
_LIBCPP_CONSTEXPR_AFTER_CXX17 size_t __hash_code() const _NOEXCEPT;
2010-05-12 03:42:16 +08:00
friend class __bit_reference<vector>;
friend class __bit_const_reference<vector>;
friend class __bit_iterator<vector, false>;
friend class __bit_iterator<vector, true>;
friend struct __bit_array<vector>;
friend struct _LIBCPP_TEMPLATE_VIS hash<vector>;
2010-05-12 03:42:16 +08:00
};
template <class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17 void
vector<bool, _Allocator>::__vdeallocate() _NOEXCEPT
2010-05-12 03:42:16 +08:00
{
if (this->__begin_ != nullptr)
2010-05-12 03:42:16 +08:00
{
__storage_traits::deallocate(this->__alloc(), this->__begin_, __cap());
std::__debug_db_invalidate_all(this);
this->__begin_ = nullptr;
2010-05-12 03:42:16 +08:00
this->__size_ = this->__cap() = 0;
}
}
template <class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
typename vector<bool, _Allocator>::size_type
vector<bool, _Allocator>::max_size() const _NOEXCEPT
2010-05-12 03:42:16 +08:00
{
size_type __amax = __storage_traits::max_size(__alloc());
size_type __nmax = numeric_limits<size_type>::max() / 2; // end() >= begin(), always
if (__nmax / __bits_per_word <= __amax)
return __nmax;
return __internal_cap_to_external(__amax);
}
// Precondition: __new_size > capacity()
template <class _Allocator>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
typename vector<bool, _Allocator>::size_type
vector<bool, _Allocator>::__recommend(size_type __new_size) const
{
const size_type __ms = max_size();
if (__new_size > __ms)
this->__throw_length_error();
const size_type __cap = capacity();
if (__cap >= __ms / 2)
return __ms;
return _VSTD::max(2 * __cap, __align_it(__new_size));
2010-05-12 03:42:16 +08:00
}
// Default constructs __n objects starting at __end_
// Precondition: __n > 0
// Precondition: size() + __n <= capacity()
// Postcondition: size() == size() + __n
template <class _Allocator>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
void
vector<bool, _Allocator>::__construct_at_end(size_type __n, bool __x)
{
size_type __old_size = this->__size_;
this->__size_ += __n;
if (__old_size == 0 || ((__old_size - 1) / __bits_per_word) != ((this->__size_ - 1) / __bits_per_word))
{
if (this->__size_ <= __bits_per_word)
this->__begin_[0] = __storage_type(0);
else
this->__begin_[(this->__size_ - 1) / __bits_per_word] = __storage_type(0);
}
_VSTD::fill_n(__make_iter(__old_size), __n, __x);
2010-05-12 03:42:16 +08:00
}
template <class _Allocator>
template <class _ForwardIterator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
typename enable_if
<
__is_cpp17_forward_iterator<_ForwardIterator>::value,
2010-05-12 03:42:16 +08:00
void
>::type
vector<bool, _Allocator>::__construct_at_end(_ForwardIterator __first, _ForwardIterator __last)
{
size_type __old_size = this->__size_;
this->__size_ += _VSTD::distance(__first, __last);
if (__old_size == 0 || ((__old_size - 1) / __bits_per_word) != ((this->__size_ - 1) / __bits_per_word))
{
if (this->__size_ <= __bits_per_word)
this->__begin_[0] = __storage_type(0);
else
this->__begin_[(this->__size_ - 1) / __bits_per_word] = __storage_type(0);
}
_VSTD::copy(__first, __last, __make_iter(__old_size));
2010-05-12 03:42:16 +08:00
}
template <class _Allocator>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
vector<bool, _Allocator>::vector()
_NOEXCEPT_(is_nothrow_default_constructible<allocator_type>::value)
: __begin_(nullptr),
2010-05-12 03:42:16 +08:00
__size_(0),
__cap_alloc_(0, __default_init_tag())
2010-05-12 03:42:16 +08:00
{
}
template <class _Allocator>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
vector<bool, _Allocator>::vector(const allocator_type& __a)
#if _LIBCPP_STD_VER <= 14
_NOEXCEPT_(is_nothrow_copy_constructible<allocator_type>::value)
#else
_NOEXCEPT
#endif
: __begin_(nullptr),
2010-05-12 03:42:16 +08:00
__size_(0),
__cap_alloc_(0, static_cast<__storage_allocator>(__a))
{
}
template <class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
vector<bool, _Allocator>::vector(size_type __n)
: __begin_(nullptr),
2010-05-12 03:42:16 +08:00
__size_(0),
__cap_alloc_(0, __default_init_tag())
2010-05-12 03:42:16 +08:00
{
if (__n > 0)
{
__vallocate(__n);
2010-05-12 03:42:16 +08:00
__construct_at_end(__n, false);
}
}
#if _LIBCPP_STD_VER > 11
template <class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
vector<bool, _Allocator>::vector(size_type __n, const allocator_type& __a)
: __begin_(nullptr),
__size_(0),
__cap_alloc_(0, static_cast<__storage_allocator>(__a))
{
if (__n > 0)
{
__vallocate(__n);
__construct_at_end(__n, false);
}
}
#endif
2010-05-12 03:42:16 +08:00
template <class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
vector<bool, _Allocator>::vector(size_type __n, const value_type& __x)
: __begin_(nullptr),
2010-05-12 03:42:16 +08:00
__size_(0),
__cap_alloc_(0, __default_init_tag())
2010-05-12 03:42:16 +08:00
{
if (__n > 0)
{
__vallocate(__n);
2010-05-12 03:42:16 +08:00
__construct_at_end(__n, __x);
}
}
template <class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
vector<bool, _Allocator>::vector(size_type __n, const value_type& __x, const allocator_type& __a)
: __begin_(nullptr),
2010-05-12 03:42:16 +08:00
__size_(0),
__cap_alloc_(0, static_cast<__storage_allocator>(__a))
{
if (__n > 0)
{
__vallocate(__n);
2010-05-12 03:42:16 +08:00
__construct_at_end(__n, __x);
}
}
template <class _Allocator>
template <class _InputIterator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
vector<bool, _Allocator>::vector(_InputIterator __first, _InputIterator __last,
typename enable_if<__is_exactly_cpp17_input_iterator<_InputIterator>::value>::type*)
: __begin_(nullptr),
2010-05-12 03:42:16 +08:00
__size_(0),
__cap_alloc_(0, __default_init_tag())
2010-05-12 03:42:16 +08:00
{
#ifndef _LIBCPP_NO_EXCEPTIONS
try
{
#endif // _LIBCPP_NO_EXCEPTIONS
2010-05-12 03:42:16 +08:00
for (; __first != __last; ++__first)
push_back(*__first);
#ifndef _LIBCPP_NO_EXCEPTIONS
}
catch (...)
{
if (__begin_ != nullptr)
2010-05-12 03:42:16 +08:00
__storage_traits::deallocate(__alloc(), __begin_, __cap());
std::__debug_db_invalidate_all(this);
2010-05-12 03:42:16 +08:00
throw;
}
#endif // _LIBCPP_NO_EXCEPTIONS
2010-05-12 03:42:16 +08:00
}
template <class _Allocator>
template <class _InputIterator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
vector<bool, _Allocator>::vector(_InputIterator __first, _InputIterator __last, const allocator_type& __a,
typename enable_if<__is_exactly_cpp17_input_iterator<_InputIterator>::value>::type*)
: __begin_(nullptr),
2010-05-12 03:42:16 +08:00
__size_(0),
__cap_alloc_(0, static_cast<__storage_allocator>(__a))
{
#ifndef _LIBCPP_NO_EXCEPTIONS
try
{
#endif // _LIBCPP_NO_EXCEPTIONS
2010-05-12 03:42:16 +08:00
for (; __first != __last; ++__first)
push_back(*__first);
#ifndef _LIBCPP_NO_EXCEPTIONS
}
catch (...)
{
if (__begin_ != nullptr)
2010-05-12 03:42:16 +08:00
__storage_traits::deallocate(__alloc(), __begin_, __cap());
std::__debug_db_invalidate_all(this);
2010-05-12 03:42:16 +08:00
throw;
}
#endif // _LIBCPP_NO_EXCEPTIONS
2010-05-12 03:42:16 +08:00
}
template <class _Allocator>
template <class _ForwardIterator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
vector<bool, _Allocator>::vector(_ForwardIterator __first, _ForwardIterator __last,
typename enable_if<__is_cpp17_forward_iterator<_ForwardIterator>::value>::type*)
: __begin_(nullptr),
2010-05-12 03:42:16 +08:00
__size_(0),
__cap_alloc_(0, __default_init_tag())
2010-05-12 03:42:16 +08:00
{
size_type __n = static_cast<size_type>(_VSTD::distance(__first, __last));
2010-05-12 03:42:16 +08:00
if (__n > 0)
{
__vallocate(__n);
2010-05-12 03:42:16 +08:00
__construct_at_end(__first, __last);
}
}
template <class _Allocator>
template <class _ForwardIterator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
vector<bool, _Allocator>::vector(_ForwardIterator __first, _ForwardIterator __last, const allocator_type& __a,
typename enable_if<__is_cpp17_forward_iterator<_ForwardIterator>::value>::type*)
: __begin_(nullptr),
2010-05-12 03:42:16 +08:00
__size_(0),
__cap_alloc_(0, static_cast<__storage_allocator>(__a))
{
size_type __n = static_cast<size_type>(_VSTD::distance(__first, __last));
2010-05-12 03:42:16 +08:00
if (__n > 0)
{
__vallocate(__n);
2010-05-12 03:42:16 +08:00
__construct_at_end(__first, __last);
}
}
#ifndef _LIBCPP_CXX03_LANG
2010-05-12 03:42:16 +08:00
template <class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
vector<bool, _Allocator>::vector(initializer_list<value_type> __il)
: __begin_(nullptr),
2010-05-12 03:42:16 +08:00
__size_(0),
__cap_alloc_(0, __default_init_tag())
2010-05-12 03:42:16 +08:00
{
size_type __n = static_cast<size_type>(__il.size());
if (__n > 0)
{
__vallocate(__n);
2010-05-12 03:42:16 +08:00
__construct_at_end(__il.begin(), __il.end());
}
}
template <class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
vector<bool, _Allocator>::vector(initializer_list<value_type> __il, const allocator_type& __a)
: __begin_(nullptr),
2010-05-12 03:42:16 +08:00
__size_(0),
__cap_alloc_(0, static_cast<__storage_allocator>(__a))
{
size_type __n = static_cast<size_type>(__il.size());
if (__n > 0)
{
__vallocate(__n);
2010-05-12 03:42:16 +08:00
__construct_at_end(__il.begin(), __il.end());
}
}
#endif // _LIBCPP_CXX03_LANG
2010-05-12 03:42:16 +08:00
template <class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
vector<bool, _Allocator>::~vector()
{
if (__begin_ != nullptr)
2010-05-12 03:42:16 +08:00
__storage_traits::deallocate(__alloc(), __begin_, __cap());
std::__debug_db_invalidate_all(this);
2010-05-12 03:42:16 +08:00
}
template <class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
vector<bool, _Allocator>::vector(const vector& __v)
: __begin_(nullptr),
2010-05-12 03:42:16 +08:00
__size_(0),
__cap_alloc_(0, __storage_traits::select_on_container_copy_construction(__v.__alloc()))
{
if (__v.size() > 0)
{
__vallocate(__v.size());
2010-05-12 03:42:16 +08:00
__construct_at_end(__v.begin(), __v.end());
}
}
template <class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
vector<bool, _Allocator>::vector(const vector& __v, const allocator_type& __a)
: __begin_(nullptr),
2010-05-12 03:42:16 +08:00
__size_(0),
__cap_alloc_(0, __a)
{
if (__v.size() > 0)
{
__vallocate(__v.size());
2010-05-12 03:42:16 +08:00
__construct_at_end(__v.begin(), __v.end());
}
}
template <class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
vector<bool, _Allocator>&
vector<bool, _Allocator>::operator=(const vector& __v)
{
if (this != _VSTD::addressof(__v))
2010-05-12 03:42:16 +08:00
{
__copy_assign_alloc(__v);
if (__v.__size_)
{
if (__v.__size_ > capacity())
{
__vdeallocate();
__vallocate(__v.__size_);
2010-05-12 03:42:16 +08:00
}
_VSTD::copy(__v.__begin_, __v.__begin_ + __external_cap_to_internal(__v.__size_), __begin_);
2010-05-12 03:42:16 +08:00
}
__size_ = __v.__size_;
}
return *this;
}
template <class _Allocator>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 vector<bool, _Allocator>::vector(vector&& __v)
#if _LIBCPP_STD_VER > 14
_NOEXCEPT
#else
_NOEXCEPT_(is_nothrow_move_constructible<allocator_type>::value)
#endif
2010-05-12 03:42:16 +08:00
: __begin_(__v.__begin_),
__size_(__v.__size_),
__cap_alloc_(_VSTD::move(__v.__cap_alloc_)) {
__v.__begin_ = nullptr;
2010-05-12 03:42:16 +08:00
__v.__size_ = 0;
__v.__cap() = 0;
}
template <class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
vector<bool, _Allocator>::vector(vector&& __v, const __type_identity_t<allocator_type>& __a)
: __begin_(nullptr),
2010-05-12 03:42:16 +08:00
__size_(0),
__cap_alloc_(0, __a)
{
if (__a == allocator_type(__v.__alloc()))
{
this->__begin_ = __v.__begin_;
this->__size_ = __v.__size_;
this->__cap() = __v.__cap();
__v.__begin_ = nullptr;
__v.__cap() = __v.__size_ = 0;
}
else if (__v.size() > 0)
{
__vallocate(__v.size());
2010-05-12 03:42:16 +08:00
__construct_at_end(__v.begin(), __v.end());
}
}
template <class _Allocator>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
vector<bool, _Allocator>&
vector<bool, _Allocator>::operator=(vector&& __v)
_NOEXCEPT_((__noexcept_move_assign_container<_Allocator, __alloc_traits>::value))
2010-05-12 03:42:16 +08:00
{
__move_assign(__v, integral_constant<bool,
__storage_traits::propagate_on_container_move_assignment::value>());
return *this;
2010-05-12 03:42:16 +08:00
}
template <class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17 void
2010-05-12 03:42:16 +08:00
vector<bool, _Allocator>::__move_assign(vector& __c, false_type)
{
if (__alloc() != __c.__alloc())
assign(__c.begin(), __c.end());
else
__move_assign(__c, true_type());
}
template <class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17 void
2010-05-12 03:42:16 +08:00
vector<bool, _Allocator>::__move_assign(vector& __c, true_type)
_NOEXCEPT_(is_nothrow_move_assignable<allocator_type>::value)
2010-05-12 03:42:16 +08:00
{
__vdeallocate();
__move_assign_alloc(__c);
2010-05-12 03:42:16 +08:00
this->__begin_ = __c.__begin_;
this->__size_ = __c.__size_;
this->__cap() = __c.__cap();
__c.__begin_ = nullptr;
__c.__cap() = __c.__size_ = 0;
}
2010-05-12 03:42:16 +08:00
template <class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17 void
2010-05-12 03:42:16 +08:00
vector<bool, _Allocator>::assign(size_type __n, const value_type& __x)
{
__size_ = 0;
if (__n > 0)
{
size_type __c = capacity();
if (__n <= __c)
__size_ = __n;
else
{
vector __v(get_allocator());
2010-05-12 03:42:16 +08:00
__v.reserve(__recommend(__n));
__v.__size_ = __n;
swap(__v);
}
_VSTD::fill_n(begin(), __n, __x);
2010-05-12 03:42:16 +08:00
}
std::__debug_db_invalidate_all(this);
2010-05-12 03:42:16 +08:00
}
template <class _Allocator>
template <class _InputIterator>
_LIBCPP_CONSTEXPR_AFTER_CXX17 typename enable_if <__is_exactly_cpp17_input_iterator<_InputIterator>::value,
2010-05-12 03:42:16 +08:00
void
>::type
vector<bool, _Allocator>::assign(_InputIterator __first, _InputIterator __last)
{
clear();
for (; __first != __last; ++__first)
push_back(*__first);
}
template <class _Allocator>
template <class _ForwardIterator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
typename enable_if
<
__is_cpp17_forward_iterator<_ForwardIterator>::value,
2010-05-12 03:42:16 +08:00
void
>::type
vector<bool, _Allocator>::assign(_ForwardIterator __first, _ForwardIterator __last)
{
clear();
difference_type __ns = _VSTD::distance(__first, __last);
_LIBCPP_ASSERT(__ns >= 0, "invalid range specified");
const size_t __n = static_cast<size_type>(__ns);
2010-05-12 03:42:16 +08:00
if (__n)
{
if (__n > capacity())
{
__vdeallocate();
__vallocate(__n);
2010-05-12 03:42:16 +08:00
}
__construct_at_end(__first, __last);
}
}
template <class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17 void
2010-05-12 03:42:16 +08:00
vector<bool, _Allocator>::reserve(size_type __n)
{
if (__n > capacity())
{
if (__n > max_size())
this->__throw_length_error();
vector __v(this->get_allocator());
__v.__vallocate(__n);
2010-05-12 03:42:16 +08:00
__v.__construct_at_end(this->begin(), this->end());
swap(__v);
std::__debug_db_invalidate_all(this);
2010-05-12 03:42:16 +08:00
}
}
template <class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17 void
vector<bool, _Allocator>::shrink_to_fit() _NOEXCEPT
2010-05-12 03:42:16 +08:00
{
if (__external_cap_to_internal(size()) > __cap())
{
#ifndef _LIBCPP_NO_EXCEPTIONS
try
{
#endif // _LIBCPP_NO_EXCEPTIONS
2010-05-12 03:42:16 +08:00
vector(*this, allocator_type(__alloc())).swap(*this);
#ifndef _LIBCPP_NO_EXCEPTIONS
}
catch (...)
{
}
#endif // _LIBCPP_NO_EXCEPTIONS
2010-05-12 03:42:16 +08:00
}
}
template <class _Allocator>
typename vector<bool, _Allocator>::reference
vector<bool, _Allocator>::at(size_type __n)
{
if (__n >= size())
this->__throw_out_of_range();
return (*this)[__n];
}
template <class _Allocator>
typename vector<bool, _Allocator>::const_reference
vector<bool, _Allocator>::at(size_type __n) const
{
if (__n >= size())
this->__throw_out_of_range();
return (*this)[__n];
}
template <class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17 void
2010-05-12 03:42:16 +08:00
vector<bool, _Allocator>::push_back(const value_type& __x)
{
if (this->__size_ == this->capacity())
reserve(__recommend(this->__size_ + 1));
++this->__size_;
back() = __x;
}
template <class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17 typename vector<bool, _Allocator>::iterator
2010-05-12 03:42:16 +08:00
vector<bool, _Allocator>::insert(const_iterator __position, const value_type& __x)
{
iterator __r;
if (size() < capacity())
{
const_iterator __old_end = end();
++__size_;
_VSTD::copy_backward(__position, __old_end, end());
2010-05-12 03:42:16 +08:00
__r = __const_iterator_cast(__position);
}
else
{
vector __v(get_allocator());
2010-05-12 03:42:16 +08:00
__v.reserve(__recommend(__size_ + 1));
__v.__size_ = __size_ + 1;
__r = _VSTD::copy(cbegin(), __position, __v.begin());
_VSTD::copy_backward(__position, cend(), __v.end());
2010-05-12 03:42:16 +08:00
swap(__v);
}
*__r = __x;
return __r;
}
template <class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17 typename vector<bool, _Allocator>::iterator
2010-05-12 03:42:16 +08:00
vector<bool, _Allocator>::insert(const_iterator __position, size_type __n, const value_type& __x)
{
iterator __r;
size_type __c = capacity();
if (__n <= __c && size() <= __c - __n)
{
const_iterator __old_end = end();
__size_ += __n;
_VSTD::copy_backward(__position, __old_end, end());
2010-05-12 03:42:16 +08:00
__r = __const_iterator_cast(__position);
}
else
{
vector __v(get_allocator());
2010-05-12 03:42:16 +08:00
__v.reserve(__recommend(__size_ + __n));
__v.__size_ = __size_ + __n;
__r = _VSTD::copy(cbegin(), __position, __v.begin());
_VSTD::copy_backward(__position, cend(), __v.end());
2010-05-12 03:42:16 +08:00
swap(__v);
}
_VSTD::fill_n(__r, __n, __x);
2010-05-12 03:42:16 +08:00
return __r;
}
template <class _Allocator>
template <class _InputIterator>
_LIBCPP_CONSTEXPR_AFTER_CXX17 typename enable_if <__is_exactly_cpp17_input_iterator<_InputIterator>::value,
2010-05-12 03:42:16 +08:00
typename vector<bool, _Allocator>::iterator
>::type
vector<bool, _Allocator>::insert(const_iterator __position, _InputIterator __first, _InputIterator __last)
{
difference_type __off = __position - begin();
iterator __p = __const_iterator_cast(__position);
iterator __old_end = end();
for (; size() != capacity() && __first != __last; ++__first)
{
++this->__size_;
back() = *__first;
}
vector __v(get_allocator());
2010-05-12 03:42:16 +08:00
if (__first != __last)
{
#ifndef _LIBCPP_NO_EXCEPTIONS
try
{
#endif // _LIBCPP_NO_EXCEPTIONS
2010-05-12 03:42:16 +08:00
__v.assign(__first, __last);
difference_type __old_size = static_cast<difference_type>(__old_end - begin());
difference_type __old_p = __p - begin();
reserve(__recommend(size() + __v.size()));
__p = begin() + __old_p;
__old_end = begin() + __old_size;
#ifndef _LIBCPP_NO_EXCEPTIONS
}
catch (...)
{
erase(__old_end, end());
throw;
}
#endif // _LIBCPP_NO_EXCEPTIONS
2010-05-12 03:42:16 +08:00
}
__p = _VSTD::rotate(__p, __old_end, end());
2010-05-12 03:42:16 +08:00
insert(__p, __v.begin(), __v.end());
return begin() + __off;
}
template <class _Allocator>
template <class _ForwardIterator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
typename enable_if
<
__is_cpp17_forward_iterator<_ForwardIterator>::value,
2010-05-12 03:42:16 +08:00
typename vector<bool, _Allocator>::iterator
>::type
vector<bool, _Allocator>::insert(const_iterator __position, _ForwardIterator __first, _ForwardIterator __last)
{
const difference_type __n_signed = _VSTD::distance(__first, __last);
_LIBCPP_ASSERT(__n_signed >= 0, "invalid range specified");
const size_type __n = static_cast<size_type>(__n_signed);
2010-05-12 03:42:16 +08:00
iterator __r;
size_type __c = capacity();
if (__n <= __c && size() <= __c - __n)
{
const_iterator __old_end = end();
__size_ += __n;
_VSTD::copy_backward(__position, __old_end, end());
2010-05-12 03:42:16 +08:00
__r = __const_iterator_cast(__position);
}
else
{
vector __v(get_allocator());
2010-05-12 03:42:16 +08:00
__v.reserve(__recommend(__size_ + __n));
__v.__size_ = __size_ + __n;
__r = _VSTD::copy(cbegin(), __position, __v.begin());
_VSTD::copy_backward(__position, cend(), __v.end());
2010-05-12 03:42:16 +08:00
swap(__v);
}
_VSTD::copy(__first, __last, __r);
2010-05-12 03:42:16 +08:00
return __r;
}
template <class _Allocator>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
typename vector<bool, _Allocator>::iterator
vector<bool, _Allocator>::erase(const_iterator __position)
{
iterator __r = __const_iterator_cast(__position);
_VSTD::copy(__position + 1, this->cend(), __r);
2010-05-12 03:42:16 +08:00
--__size_;
return __r;
}
template <class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
2010-05-12 03:42:16 +08:00
typename vector<bool, _Allocator>::iterator
vector<bool, _Allocator>::erase(const_iterator __first, const_iterator __last)
{
iterator __r = __const_iterator_cast(__first);
difference_type __d = __last - __first;
_VSTD::copy(__last, this->cend(), __r);
2010-05-12 03:42:16 +08:00
__size_ -= __d;
return __r;
}
template <class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17 void
2010-05-12 03:42:16 +08:00
vector<bool, _Allocator>::swap(vector& __x)
#if _LIBCPP_STD_VER >= 14
_NOEXCEPT
#else
_NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value ||
__is_nothrow_swappable<allocator_type>::value)
#endif
2010-05-12 03:42:16 +08:00
{
_VSTD::swap(this->__begin_, __x.__begin_);
_VSTD::swap(this->__size_, __x.__size_);
_VSTD::swap(this->__cap(), __x.__cap());
_VSTD::__swap_allocator(this->__alloc(), __x.__alloc(),
integral_constant<bool, __alloc_traits::propagate_on_container_swap::value>());
2010-05-12 03:42:16 +08:00
}
template <class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17 void
2010-05-12 03:42:16 +08:00
vector<bool, _Allocator>::resize(size_type __sz, value_type __x)
{
size_type __cs = size();
if (__cs < __sz)
{
iterator __r;
size_type __c = capacity();
size_type __n = __sz - __cs;
if (__n <= __c && __cs <= __c - __n)
{
__r = end();
__size_ += __n;
}
else
{
vector __v(get_allocator());
2010-05-12 03:42:16 +08:00
__v.reserve(__recommend(__size_ + __n));
__v.__size_ = __size_ + __n;
__r = _VSTD::copy(cbegin(), cend(), __v.begin());
2010-05-12 03:42:16 +08:00
swap(__v);
}
_VSTD::fill_n(__r, __n, __x);
2010-05-12 03:42:16 +08:00
}
else
__size_ = __sz;
}
template <class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17 void
vector<bool, _Allocator>::flip() _NOEXCEPT
2010-05-12 03:42:16 +08:00
{
// do middle whole words
size_type __n = __size_;
__storage_pointer __p = __begin_;
for (; __n >= __bits_per_word; ++__p, __n -= __bits_per_word)
*__p = ~*__p;
// do last partial word
if (__n > 0)
{
__storage_type __m = ~__storage_type(0) >> (__bits_per_word - __n);
__storage_type __b = *__p & __m;
*__p &= ~__m;
*__p |= ~__b & __m;
}
}
template <class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17 bool
2010-05-12 03:42:16 +08:00
vector<bool, _Allocator>::__invariants() const
{
if (this->__begin_ == nullptr)
2010-05-12 03:42:16 +08:00
{
if (this->__size_ != 0 || this->__cap() != 0)
return false;
}
else
{
if (this->__cap() == 0)
return false;
if (this->__size_ > this->capacity())
return false;
}
return true;
}
template <class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17 size_t
vector<bool, _Allocator>::__hash_code() const _NOEXCEPT
2010-05-12 03:42:16 +08:00
{
size_t __h = 0;
// do middle whole words
size_type __n = __size_;
__storage_pointer __p = __begin_;
for (; __n >= __bits_per_word; ++__p, __n -= __bits_per_word)
__h ^= *__p;
// do last partial word
if (__n > 0)
{
const __storage_type __m = ~__storage_type(0) >> (__bits_per_word - __n);
__h ^= *__p & __m;
}
return __h;
}
template <class _Allocator>
struct _LIBCPP_TEMPLATE_VIS hash<vector<bool, _Allocator> >
: public __unary_function<vector<bool, _Allocator>, size_t>
2010-05-12 03:42:16 +08:00
{
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
size_t operator()(const vector<bool, _Allocator>& __vec) const _NOEXCEPT
2010-05-12 03:42:16 +08:00
{return __vec.__hash_code();}
};
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
inline _LIBCPP_INLINE_VISIBILITY
2010-05-12 03:42:16 +08:00
bool
operator==(const vector<_Tp, _Allocator>& __x, const vector<_Tp, _Allocator>& __y)
{
const typename vector<_Tp, _Allocator>::size_type __sz = __x.size();
return __sz == __y.size() && _VSTD::equal(__x.begin(), __x.end(), __y.begin());
2010-05-12 03:42:16 +08:00
}
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
inline _LIBCPP_INLINE_VISIBILITY
2010-05-12 03:42:16 +08:00
bool
operator!=(const vector<_Tp, _Allocator>& __x, const vector<_Tp, _Allocator>& __y)
{
return !(__x == __y);
}
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
inline _LIBCPP_INLINE_VISIBILITY
2010-05-12 03:42:16 +08:00
bool
operator< (const vector<_Tp, _Allocator>& __x, const vector<_Tp, _Allocator>& __y)
{
return _VSTD::lexicographical_compare(__x.begin(), __x.end(), __y.begin(), __y.end());
2010-05-12 03:42:16 +08:00
}
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
inline _LIBCPP_INLINE_VISIBILITY
2010-05-12 03:42:16 +08:00
bool
operator> (const vector<_Tp, _Allocator>& __x, const vector<_Tp, _Allocator>& __y)
{
return __y < __x;
}
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
inline _LIBCPP_INLINE_VISIBILITY
2010-05-12 03:42:16 +08:00
bool
operator>=(const vector<_Tp, _Allocator>& __x, const vector<_Tp, _Allocator>& __y)
{
return !(__x < __y);
}
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
inline _LIBCPP_INLINE_VISIBILITY
2010-05-12 03:42:16 +08:00
bool
operator<=(const vector<_Tp, _Allocator>& __x, const vector<_Tp, _Allocator>& __y)
{
return !(__y < __x);
}
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_AFTER_CXX17
inline _LIBCPP_INLINE_VISIBILITY
2010-05-12 03:42:16 +08:00
void
swap(vector<_Tp, _Allocator>& __x, vector<_Tp, _Allocator>& __y)
_NOEXCEPT_(_NOEXCEPT_(__x.swap(__y)))
2010-05-12 03:42:16 +08:00
{
__x.swap(__y);
}
#if _LIBCPP_STD_VER > 17
template <class _Tp, class _Allocator, class _Up>
_LIBCPP_CONSTEXPR_AFTER_CXX17
inline _LIBCPP_INLINE_VISIBILITY typename vector<_Tp, _Allocator>::size_type
erase(vector<_Tp, _Allocator>& __c, const _Up& __v) {
auto __old_size = __c.size();
__c.erase(_VSTD::remove(__c.begin(), __c.end(), __v), __c.end());
return __old_size - __c.size();
}
template <class _Tp, class _Allocator, class _Predicate>
_LIBCPP_CONSTEXPR_AFTER_CXX17
inline _LIBCPP_INLINE_VISIBILITY typename vector<_Tp, _Allocator>::size_type
erase_if(vector<_Tp, _Allocator>& __c, _Predicate __pred) {
auto __old_size = __c.size();
__c.erase(_VSTD::remove_if(__c.begin(), __c.end(), __pred), __c.end());
return __old_size - __c.size();
}
template <>
inline constexpr bool __format::__enable_insertable<std::vector<char>> = true;
#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
template <>
inline constexpr bool __format::__enable_insertable<std::vector<wchar_t>> = true;
#endif
#endif // _LIBCPP_STD_VER > 17
2010-05-12 03:42:16 +08:00
_LIBCPP_END_NAMESPACE_STD
_LIBCPP_POP_MACROS
#endif // _LIBCPP_VECTOR