Debug mode for string. This commit also marks the first time libc++ debug-mode has found a bug (found one in regex). Had to play with extern templates a bit to get this to work since string is heavily used within libc++.dylib.
git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@189114 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/string b/include/string
index 7439b56..761ff52 100644
--- a/include/string
+++ b/include/string
@@ -447,7 +447,7 @@
#ifndef _LIBCPP_HAS_NO_UNICODE_CHARS
#include <cstdint>
#endif
-#if defined(_LIBCPP_NO_EXCEPTIONS) || defined(_LIBCPP_DEBUG)
+#if defined(_LIBCPP_NO_EXCEPTIONS)
#include <cassert>
#endif
@@ -605,6 +605,7 @@
_CharT*
char_traits<_CharT>::copy(char_type* __s1, const char_type* __s2, size_t __n)
{
+ _LIBCPP_ASSERT(__s2 < __s1 || __s2 >= __s1+__n, "char_traits::copy overlapped range");
char_type* __r = __s1;
for (; __n; --__n, ++__s1, ++__s2)
assign(*__s1, *__s2);
@@ -656,7 +657,10 @@
{return (char_type*)memmove(__s1, __s2, __n);}
_LIBCPP_INLINE_VISIBILITY
static char_type* copy(char_type* __s1, const char_type* __s2, size_t __n)
- {return (char_type*)memcpy(__s1, __s2, __n);}
+ {
+ _LIBCPP_ASSERT(__s2 < __s1 || __s2 >= __s1+__n, "char_traits::copy overlapped range");
+ return (char_type*)memcpy(__s1, __s2, __n);
+ }
_LIBCPP_INLINE_VISIBILITY
static char_type* assign(char_type* __s, size_t __n, char_type __a)
{return (char_type*)memset(__s, to_int_type(__a), __n);}
@@ -713,7 +717,10 @@
{return (char_type*)wmemmove(__s1, __s2, __n);}
_LIBCPP_INLINE_VISIBILITY
static char_type* copy(char_type* __s1, const char_type* __s2, size_t __n)
- {return (char_type*)wmemcpy(__s1, __s2, __n);}
+ {
+ _LIBCPP_ASSERT(__s2 < __s1 || __s2 >= __s1+__n, "char_traits::copy overlapped range");
+ return (char_type*)wmemcpy(__s1, __s2, __n);
+ }
_LIBCPP_INLINE_VISIBILITY
static char_type* assign(char_type* __s, size_t __n, char_type __a)
{return (char_type*)wmemset(__s, __a, __n);}
@@ -841,6 +848,7 @@
char16_t*
char_traits<char16_t>::copy(char_type* __s1, const char_type* __s2, size_t __n)
{
+ _LIBCPP_ASSERT(__s2 < __s1 || __s2 >= __s1+__n, "char_traits::copy overlapped range");
char_type* __r = __s1;
for (; __n; --__n, ++__s1, ++__s2)
assign(*__s1, *__s2);
@@ -961,6 +969,7 @@
char32_t*
char_traits<char32_t>::copy(char_type* __s1, const char_type* __s2, size_t __n)
{
+ _LIBCPP_ASSERT(__s2 < __s1 || __s2 >= __s1+__n, "char_traits::copy overlapped range");
char_type* __r = __s1;
for (; __n; --__n, ++__s1, ++__s2)
assign(*__s1, *__s2);
@@ -1072,13 +1081,13 @@
typedef const value_type& const_reference;
typedef typename __alloc_traits::pointer pointer;
typedef typename __alloc_traits::const_pointer const_pointer;
-#ifdef _LIBCPP_DEBUG
- typedef __debug_iter<basic_string, pointer> iterator;
- typedef __debug_iter<basic_string, const_pointer> const_iterator;
- friend class __debug_iter<basic_string, pointer>;
- friend class __debug_iter<basic_string, const_pointer>;
-#elif defined(_LIBCPP_RAW_ITERATORS)
+ static_assert(is_pod<value_type>::value, "Character type of basic_string must be a POD");
+ static_assert((is_same<_CharT, value_type>::value),
+ "traits_type::char_type must be the same type as CharT");
+ static_assert((is_same<typename allocator_type::value_type, value_type>::value),
+ "Allocator::value_type must be same type as value_type");
+#if defined(_LIBCPP_RAW_ITERATORS)
typedef pointer iterator;
typedef const_pointer const_iterator;
#else // defined(_LIBCPP_RAW_ITERATORS)
@@ -1152,9 +1161,9 @@
#endif // _LIBCPP_ALTERNATE_STRING_LAYOUT
- union __lx{__long __lx; __short __lxx;};
+ union __ulx{__long __lx; __short __lxx;};
- enum {__n_words = sizeof(__lx) / sizeof(size_type)};
+ enum {__n_words = sizeof(__ulx) / sizeof(size_type)};
struct __raw
{
@@ -1173,15 +1182,6 @@
__compressed_pair<__rep, allocator_type> __r_;
-#ifdef _LIBCPP_DEBUG
-
- pair<iterator*, const_iterator*> __iterator_list_;
-
- _LIBCPP_INLINE_VISIBILITY iterator*& __get_iterator_list(iterator*) {return __iterator_list_.first;}
- _LIBCPP_INLINE_VISIBILITY const_iterator*& __get_iterator_list(const_iterator*) {return __iterator_list_.second;}
-
-#endif // _LIBCPP_DEBUG
-
public:
static const size_type npos = -1;
@@ -1239,7 +1239,20 @@
basic_string& operator=(initializer_list<value_type> __il) {return assign(__il.begin(), __il.size());}
#endif // _LIBCPP_HAS_NO_GENERALIZED_INITIALIZERS
-#ifndef _LIBCPP_DEBUG
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ _LIBCPP_INLINE_VISIBILITY
+ iterator begin() _NOEXCEPT
+ {return iterator(this, __get_pointer());}
+ _LIBCPP_INLINE_VISIBILITY
+ const_iterator begin() const _NOEXCEPT
+ {return const_iterator(this, __get_pointer());}
+ _LIBCPP_INLINE_VISIBILITY
+ iterator end() _NOEXCEPT
+ {return iterator(this, __get_pointer() + size());}
+ _LIBCPP_INLINE_VISIBILITY
+ const_iterator end() const _NOEXCEPT
+ {return const_iterator(this, __get_pointer() + size());}
+#else
_LIBCPP_INLINE_VISIBILITY
iterator begin() _NOEXCEPT
{return iterator(__get_pointer());}
@@ -1252,12 +1265,7 @@
_LIBCPP_INLINE_VISIBILITY
const_iterator end() const _NOEXCEPT
{return const_iterator(__get_pointer() + size());}
-#else // _LIBCPP_DEBUG
- _LIBCPP_INLINE_VISIBILITY iterator begin() {return iterator(this, __get_pointer());}
- _LIBCPP_INLINE_VISIBILITY const_iterator begin() const {return const_iterator(this, data());}
- _LIBCPP_INLINE_VISIBILITY iterator end() {return iterator(this, __get_pointer() + size());}
- _LIBCPP_INLINE_VISIBILITY const_iterator end() const {return const_iterator(this, data() + size());}
-#endif // _LIBCPP_DEBUG
+#endif // _LIBCPP_DEBUG_LEVEL >= 2
_LIBCPP_INLINE_VISIBILITY
reverse_iterator rbegin() _NOEXCEPT
{return reverse_iterator(end());}
@@ -1520,6 +1528,15 @@
bool __is_long() const _NOEXCEPT
{return bool(__r_.first().__s.__size_ & __short_mask);}
+#if _LIBCPP_DEBUG_LEVEL >= 2
+
+ 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_DEBUG_LEVEL >= 2
+
private:
_LIBCPP_INLINE_VISIBILITY
allocator_type& __alloc() _NOEXCEPT
@@ -1732,60 +1749,43 @@
};
template <class _CharT, class _Traits, class _Allocator>
-#ifndef _LIBCPP_DEBUG
_LIBCPP_INLINE_VISIBILITY inline
-#endif
void
basic_string<_CharT, _Traits, _Allocator>::__invalidate_all_iterators()
{
-#ifdef _LIBCPP_DEBUG
- iterator::__remove_all(this);
- const_iterator::__remove_all(this);
-#endif // _LIBCPP_DEBUG
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__invalidate_all(this);
+#endif // _LIBCPP_DEBUG_LEVEL >= 2
}
template <class _CharT, class _Traits, class _Allocator>
-#ifndef _LIBCPP_DEBUG
_LIBCPP_INLINE_VISIBILITY inline
-#endif
void
basic_string<_CharT, _Traits, _Allocator>::__invalidate_iterators_past(size_type
-#ifdef _LIBCPP_DEBUG
+#if _LIBCPP_DEBUG_LEVEL >= 2
__pos
#endif
)
{
-#ifdef _LIBCPP_DEBUG
- const_iterator __beg = begin();
- if (__iterator_list_.first)
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __c_node* __c = __get_db()->__find_c_and_lock(this);
+ if (__c)
{
- for (iterator* __p = __iterator_list_.first; __p;)
+ const_pointer __new_last = __get_pointer() + __pos;
+ for (__i_node** __p = __c->end_; __p != __c->beg_; )
{
- if (*__p - __beg > static_cast<difference_type>(__pos))
+ --__p;
+ const_iterator* __i = static_cast<const_iterator*>((*__p)->__i_);
+ if (__i->base() > __new_last)
{
- iterator* __n = __p;
- __p = __p->__next;
- __n->__remove_owner();
+ (*__p)->__c_ = nullptr;
+ if (--__c->end_ != __p)
+ memmove(__p, __p+1, (__c->end_ - __p)*sizeof(__i_node*));
}
- else
- __p = __p->__next;
}
+ __get_db()->unlock();
}
- if (__iterator_list_.second)
- {
- for (const_iterator* __p = __iterator_list_.second; __p;)
- {
- if (*__p - __beg > static_cast<difference_type>(__pos))
- {
- const_iterator* __n = __p;
- __p = __p->__next;
- __n->__remove_owner();
- }
- else
- __p = __p->__next;
- }
- }
-#endif // _LIBCPP_DEBUG
+#endif // _LIBCPP_DEBUG_LEVEL >= 2
}
template <class _CharT, class _Traits, class _Allocator>
@@ -1793,6 +1793,9 @@
basic_string<_CharT, _Traits, _Allocator>::basic_string()
_NOEXCEPT_(is_nothrow_default_constructible<allocator_type>::value)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
__zero();
}
@@ -1801,6 +1804,9 @@
basic_string<_CharT, _Traits, _Allocator>::basic_string(const allocator_type& __a)
: __r_(__a)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
__zero();
}
@@ -1856,10 +1862,11 @@
_LIBCPP_INLINE_VISIBILITY inline
basic_string<_CharT, _Traits, _Allocator>::basic_string(const value_type* __s)
{
-#ifdef _LIBCPP_DEBUG
- assert(__s != 0);
-#endif
+ _LIBCPP_ASSERT(__s != nullptr, "basic_string(const char*) detected nullptr");
__init(__s, traits_type::length(__s));
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
}
template <class _CharT, class _Traits, class _Allocator>
@@ -1867,20 +1874,22 @@
basic_string<_CharT, _Traits, _Allocator>::basic_string(const value_type* __s, const allocator_type& __a)
: __r_(__a)
{
-#ifdef _LIBCPP_DEBUG
- assert(__s != 0);
-#endif
+ _LIBCPP_ASSERT(__s != nullptr, "basic_string(const char*, allocator) detected nullptr");
__init(__s, traits_type::length(__s));
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
}
template <class _CharT, class _Traits, class _Allocator>
_LIBCPP_INLINE_VISIBILITY inline
basic_string<_CharT, _Traits, _Allocator>::basic_string(const value_type* __s, size_type __n)
{
-#ifdef _LIBCPP_DEBUG
- assert(__s != 0);
-#endif
+ _LIBCPP_ASSERT(__n == 0 || __s != nullptr, "basic_string(const char*, n) detected nullptr");
__init(__s, __n);
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
}
template <class _CharT, class _Traits, class _Allocator>
@@ -1888,10 +1897,11 @@
basic_string<_CharT, _Traits, _Allocator>::basic_string(const value_type* __s, size_type __n, const allocator_type& __a)
: __r_(__a)
{
-#ifdef _LIBCPP_DEBUG
- assert(__s != 0);
-#endif
+ _LIBCPP_ASSERT(__n == 0 || __s != nullptr, "basic_string(const char*, n, allocator) detected nullptr");
__init(__s, __n);
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
}
template <class _CharT, class _Traits, class _Allocator>
@@ -1902,6 +1912,9 @@
__r_.first().__r = __str.__r_.first().__r;
else
__init(_VSTD::__to_raw_pointer(__str.__get_long_pointer()), __str.__get_long_size());
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
}
template <class _CharT, class _Traits, class _Allocator>
@@ -1912,6 +1925,9 @@
__r_.first().__r = __str.__r_.first().__r;
else
__init(_VSTD::__to_raw_pointer(__str.__get_long_pointer()), __str.__get_long_size());
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
}
#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
@@ -1923,8 +1939,10 @@
: __r_(_VSTD::move(__str.__r_))
{
__str.__zero();
-#ifdef _LIBCPP_DEBUG
- __str.__invalidate_all_iterators();
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+ if (__is_long())
+ __get_db()->swap(this, &__str);
#endif
}
@@ -1938,8 +1956,10 @@
else
__init(_VSTD::__to_raw_pointer(__str.__get_long_pointer()), __str.__get_long_size());
__str.__zero();
-#ifdef _LIBCPP_DEBUG
- __str.__invalidate_all_iterators();
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+ if (__is_long())
+ __get_db()->swap(this, &__str);
#endif
}
@@ -1974,6 +1994,9 @@
basic_string<_CharT, _Traits, _Allocator>::basic_string(size_type __n, value_type __c)
{
__init(__n, __c);
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
}
template <class _CharT, class _Traits, class _Allocator>
@@ -1982,6 +2005,9 @@
: __r_(__a)
{
__init(__n, __c);
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
}
template <class _CharT, class _Traits, class _Allocator>
@@ -1993,6 +2019,9 @@
if (__pos > __str_sz)
this->__throw_out_of_range();
__init(__str.data() + __pos, _VSTD::min(__n, __str_sz - __pos));
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
}
template <class _CharT, class _Traits, class _Allocator>
@@ -2060,6 +2089,9 @@
basic_string<_CharT, _Traits, _Allocator>::basic_string(_InputIterator __first, _InputIterator __last)
{
__init(__first, __last);
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
}
template <class _CharT, class _Traits, class _Allocator>
@@ -2070,6 +2102,9 @@
: __r_(__a)
{
__init(__first, __last);
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
}
#ifndef _LIBCPP_HAS_NO_GENERALIZED_INITIALIZERS
@@ -2079,6 +2114,9 @@
basic_string<_CharT, _Traits, _Allocator>::basic_string(initializer_list<value_type> __il)
{
__init(__il.begin(), __il.end());
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
}
template <class _CharT, class _Traits, class _Allocator>
@@ -2087,6 +2125,9 @@
: __r_(__a)
{
__init(__il.begin(), __il.end());
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
}
#endif // _LIBCPP_HAS_NO_GENERALIZED_INITIALIZERS
@@ -2094,7 +2135,9 @@
template <class _CharT, class _Traits, class _Allocator>
basic_string<_CharT, _Traits, _Allocator>::~basic_string()
{
- __invalidate_all_iterators();
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__erase_c(this);
+#endif
if (__is_long())
__alloc_traits::deallocate(__alloc(), __get_long_pointer(), __get_long_cap());
}
@@ -2166,9 +2209,7 @@
basic_string<_CharT, _Traits, _Allocator>&
basic_string<_CharT, _Traits, _Allocator>::assign(const value_type* __s, size_type __n)
{
-#ifdef _LIBCPP_DEBUG
- assert(__s != 0);
-#endif
+ _LIBCPP_ASSERT(__n == 0 || __s != nullptr, "string::assign recieved nullptr");
size_type __cap = capacity();
if (__cap >= __n)
{
@@ -2342,9 +2383,7 @@
basic_string<_CharT, _Traits, _Allocator>&
basic_string<_CharT, _Traits, _Allocator>::assign(const value_type* __s)
{
-#ifdef _LIBCPP_DEBUG
- assert(__s != 0);
-#endif
+ _LIBCPP_ASSERT(__s != nullptr, "string::assign recieved nullptr");
return assign(__s, traits_type::length(__s));
}
@@ -2354,9 +2393,7 @@
basic_string<_CharT, _Traits, _Allocator>&
basic_string<_CharT, _Traits, _Allocator>::append(const value_type* __s, size_type __n)
{
-#ifdef _LIBCPP_DEBUG
- assert(__s != 0);
-#endif
+ _LIBCPP_ASSERT(__n == 0 || __s != nullptr, "string::append recieved nullptr");
size_type __cap = capacity();
size_type __sz = size();
if (__cap - __sz >= __n)
@@ -2493,9 +2530,7 @@
basic_string<_CharT, _Traits, _Allocator>&
basic_string<_CharT, _Traits, _Allocator>::append(const value_type* __s)
{
-#ifdef _LIBCPP_DEBUG
- assert(__s != 0);
-#endif
+ _LIBCPP_ASSERT(__s != nullptr, "string::append recieved nullptr");
return append(__s, traits_type::length(__s));
}
@@ -2505,9 +2540,7 @@
basic_string<_CharT, _Traits, _Allocator>&
basic_string<_CharT, _Traits, _Allocator>::insert(size_type __pos, const value_type* __s, size_type __n)
{
-#ifdef _LIBCPP_DEBUG
- assert(__s != 0);
-#endif
+ _LIBCPP_ASSERT(__n == 0 || __s != nullptr, "string::insert recieved nullptr");
size_type __sz = size();
if (__pos > __sz)
this->__throw_out_of_range();
@@ -2576,13 +2609,22 @@
>::type
basic_string<_CharT, _Traits, _Allocator>::insert(const_iterator __pos, _InputIterator __first, _InputIterator __last)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ _LIBCPP_ASSERT(__get_const_db()->__find_c_from_i(&__pos) == this,
+ "string::insert(iterator, range) called with an iterator not"
+ " referring to this string");
+#endif
size_type __old_sz = size();
difference_type __ip = __pos - begin();
for (; __first != __last; ++__first)
push_back(*__first);
pointer __p = __get_pointer();
_VSTD::rotate(__p + __ip, __p + __old_sz, __p + size());
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ return iterator(this, __p + __ip);
+#else
return iterator(__p + __ip);
+#endif
}
template <class _CharT, class _Traits, class _Allocator>
@@ -2594,6 +2636,11 @@
>::type
basic_string<_CharT, _Traits, _Allocator>::insert(const_iterator __pos, _ForwardIterator __first, _ForwardIterator __last)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ _LIBCPP_ASSERT(__get_const_db()->__find_c_from_i(&__pos) == this,
+ "string::insert(iterator, range) called with an iterator not"
+ " referring to this string");
+#endif
size_type __ip = static_cast<size_type>(__pos - begin());
size_type __sz = size();
size_type __cap = capacity();
@@ -2645,9 +2692,7 @@
basic_string<_CharT, _Traits, _Allocator>&
basic_string<_CharT, _Traits, _Allocator>::insert(size_type __pos, const value_type* __s)
{
-#ifdef _LIBCPP_DEBUG
- assert(__s != 0);
-#endif
+ _LIBCPP_ASSERT(__s != nullptr, "string::insert recieved nullptr");
return insert(__pos, __s, traits_type::length(__s));
}
@@ -2682,6 +2727,11 @@
typename basic_string<_CharT, _Traits, _Allocator>::iterator
basic_string<_CharT, _Traits, _Allocator>::insert(const_iterator __pos, size_type __n, value_type __c)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ _LIBCPP_ASSERT(__get_const_db()->__find_c_from_i(&__pos) == this,
+ "string::insert(iterator, n, value) called with an iterator not"
+ " referring to this string");
+#endif
difference_type __p = __pos - begin();
insert(static_cast<size_type>(__p), __n, __c);
return begin() + __p;
@@ -2693,9 +2743,7 @@
basic_string<_CharT, _Traits, _Allocator>&
basic_string<_CharT, _Traits, _Allocator>::replace(size_type __pos, size_type __n1, const value_type* __s, size_type __n2)
{
-#ifdef _LIBCPP_DEBUG
- assert(__s != 0);
-#endif
+ _LIBCPP_ASSERT(__n2 == 0 || __s != nullptr, "string::replace recieved nullptr");
size_type __sz = size();
if (__pos > __sz)
this->__throw_out_of_range();
@@ -2827,9 +2875,7 @@
basic_string<_CharT, _Traits, _Allocator>&
basic_string<_CharT, _Traits, _Allocator>::replace(size_type __pos, size_type __n1, const value_type* __s)
{
-#ifdef _LIBCPP_DEBUG
- assert(__s != 0);
-#endif
+ _LIBCPP_ASSERT(__s != nullptr, "string::replace recieved nullptr");
return replace(__pos, __n1, __s, traits_type::length(__s));
}
@@ -2895,6 +2941,13 @@
typename basic_string<_CharT, _Traits, _Allocator>::iterator
basic_string<_CharT, _Traits, _Allocator>::erase(const_iterator __pos)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ _LIBCPP_ASSERT(__get_const_db()->__find_c_from_i(&__pos) == this,
+ "string::erase(iterator) called with an iterator not"
+ " referring to this string");
+#endif
+ _LIBCPP_ASSERT(__pos != end(),
+ "string::erase(iterator) called with a non-dereferenceable iterator");
iterator __b = begin();
size_type __r = static_cast<size_type>(__pos - __b);
erase(__r, 1);
@@ -2906,6 +2959,12 @@
typename basic_string<_CharT, _Traits, _Allocator>::iterator
basic_string<_CharT, _Traits, _Allocator>::erase(const_iterator __first, const_iterator __last)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ _LIBCPP_ASSERT(__get_const_db()->__find_c_from_i(&__first) == this,
+ "string::erase(iterator, iterator) called with an iterator not"
+ " referring to this string");
+#endif
+ _LIBCPP_ASSERT(__first <= __last, "string::erase(first, last) called with invalid range");
iterator __b = begin();
size_type __r = static_cast<size_type>(__first - __b);
erase(__r, static_cast<size_type>(__last - __first));
@@ -2917,9 +2976,7 @@
void
basic_string<_CharT, _Traits, _Allocator>::pop_back()
{
-#ifdef _LIBCPP_DEBUG
- assert(!empty());
-#endif
+ _LIBCPP_ASSERT(!empty(), "string::pop_back(): string is already empty");
size_type __sz;
if (__is_long())
{
@@ -3064,9 +3121,7 @@
typename basic_string<_CharT, _Traits, _Allocator>::const_reference
basic_string<_CharT, _Traits, _Allocator>::operator[](size_type __pos) const
{
-#ifdef __LIBCPP_DEBUG
- assert(__pos <= size());
-#endif
+ _LIBCPP_ASSERT(__pos <= size(), "string index out of bounds");
return *(data() + __pos);
}
@@ -3075,9 +3130,7 @@
typename basic_string<_CharT, _Traits, _Allocator>::reference
basic_string<_CharT, _Traits, _Allocator>::operator[](size_type __pos)
{
-#ifdef __LIBCPP_DEBUG
- assert(__pos < size());
-#endif
+ _LIBCPP_ASSERT(__pos <= size(), "string index out of bounds");
return *(__get_pointer() + __pos);
}
@@ -3104,9 +3157,7 @@
typename basic_string<_CharT, _Traits, _Allocator>::reference
basic_string<_CharT, _Traits, _Allocator>::front()
{
-#ifdef _LIBCPP_DEBUG
- assert(!empty());
-#endif
+ _LIBCPP_ASSERT(!empty(), "string::front(): string is empty");
return *__get_pointer();
}
@@ -3115,9 +3166,7 @@
typename basic_string<_CharT, _Traits, _Allocator>::const_reference
basic_string<_CharT, _Traits, _Allocator>::front() const
{
-#ifdef _LIBCPP_DEBUG
- assert(!empty());
-#endif
+ _LIBCPP_ASSERT(!empty(), "string::front(): string is empty");
return *data();
}
@@ -3126,9 +3175,7 @@
typename basic_string<_CharT, _Traits, _Allocator>::reference
basic_string<_CharT, _Traits, _Allocator>::back()
{
-#ifdef _LIBCPP_DEBUG
- assert(!empty());
-#endif
+ _LIBCPP_ASSERT(!empty(), "string::back(): string is empty");
return *(__get_pointer() + size() - 1);
}
@@ -3137,9 +3184,7 @@
typename basic_string<_CharT, _Traits, _Allocator>::const_reference
basic_string<_CharT, _Traits, _Allocator>::back() const
{
-#ifdef _LIBCPP_DEBUG
- assert(!empty());
-#endif
+ _LIBCPP_ASSERT(!empty(), "string::back(): string is empty");
return *(data() + size() - 1);
}
@@ -3170,12 +3215,15 @@
_NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value ||
__is_nothrow_swappable<allocator_type>::value)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ if (!__is_long())
+ __get_db()->__invalidate_all(this);
+ if (!__str.__is_long())
+ __get_db()->__invalidate_all(&__str);
+ __get_db()->swap(this, &__str);
+#endif
_VSTD::swap(__r_.first(), __str.__r_.first());
__swap_alloc(__alloc(), __str.__alloc());
-#ifdef _LIBCPP_DEBUG
- __invalidate_all_iterators();
- __str.__invalidate_all_iterators();
-#endif // _LIBCPP_DEBUG
}
// find
@@ -3195,9 +3243,7 @@
size_type __pos,
size_type __n) const _NOEXCEPT
{
-#ifdef _LIBCPP_DEBUG
- assert(__s != 0);
-#endif
+ _LIBCPP_ASSERT(__n == 0 || __s != nullptr, "string::find(): recieved nullptr");
size_type __sz = size();
if (__pos > __sz || __sz - __pos < __n)
return npos;
@@ -3226,9 +3272,7 @@
basic_string<_CharT, _Traits, _Allocator>::find(const value_type* __s,
size_type __pos) const _NOEXCEPT
{
-#ifdef _LIBCPP_DEBUG
- assert(__s != 0);
-#endif
+ _LIBCPP_ASSERT(__s != nullptr, "string::find(): recieved nullptr");
return find(__s, __pos, traits_type::length(__s));
}
@@ -3255,9 +3299,7 @@
size_type __pos,
size_type __n) const _NOEXCEPT
{
-#ifdef _LIBCPP_DEBUG
- assert(__s != 0);
-#endif
+ _LIBCPP_ASSERT(__n == 0 || __s != nullptr, "string::rfind(): recieved nullptr");
size_type __sz = size();
__pos = _VSTD::min(__pos, __sz);
if (__n < __sz - __pos)
@@ -3287,9 +3329,7 @@
basic_string<_CharT, _Traits, _Allocator>::rfind(const value_type* __s,
size_type __pos) const _NOEXCEPT
{
-#ifdef _LIBCPP_DEBUG
- assert(__s != 0);
-#endif
+ _LIBCPP_ASSERT(__s != nullptr, "string::rfind(): recieved nullptr");
return rfind(__s, __pos, traits_type::length(__s));
}
@@ -3323,9 +3363,7 @@
size_type __pos,
size_type __n) const _NOEXCEPT
{
-#ifdef _LIBCPP_DEBUG
- assert(__s != 0);
-#endif
+ _LIBCPP_ASSERT(__n == 0 || __s != nullptr, "string::find_first_of(): recieved nullptr");
size_type __sz = size();
if (__pos >= __sz || __n == 0)
return npos;
@@ -3352,9 +3390,7 @@
basic_string<_CharT, _Traits, _Allocator>::find_first_of(const value_type* __s,
size_type __pos) const _NOEXCEPT
{
-#ifdef _LIBCPP_DEBUG
- assert(__s != 0);
-#endif
+ _LIBCPP_ASSERT(__s != nullptr, "string::find_first_of(): recieved nullptr");
return find_first_of(__s, __pos, traits_type::length(__s));
}
@@ -3375,9 +3411,7 @@
size_type __pos,
size_type __n) const _NOEXCEPT
{
-#ifdef _LIBCPP_DEBUG
- assert(__s != 0);
-#endif
+ _LIBCPP_ASSERT(__n == 0 || __s != nullptr, "string::find_last_of(): recieved nullptr");
if (__n != 0)
{
size_type __sz = size();
@@ -3411,9 +3445,7 @@
basic_string<_CharT, _Traits, _Allocator>::find_last_of(const value_type* __s,
size_type __pos) const _NOEXCEPT
{
-#ifdef _LIBCPP_DEBUG
- assert(__s != 0);
-#endif
+ _LIBCPP_ASSERT(__s != nullptr, "string::find_last_of(): recieved nullptr");
return find_last_of(__s, __pos, traits_type::length(__s));
}
@@ -3434,9 +3466,7 @@
size_type __pos,
size_type __n) const _NOEXCEPT
{
-#ifdef _LIBCPP_DEBUG
- assert(__s != 0);
-#endif
+ _LIBCPP_ASSERT(__n == 0 || __s != nullptr, "string::find_first_not_of(): recieved nullptr");
size_type __sz = size();
if (__pos < __sz)
{
@@ -3464,9 +3494,7 @@
basic_string<_CharT, _Traits, _Allocator>::find_first_not_of(const value_type* __s,
size_type __pos) const _NOEXCEPT
{
-#ifdef _LIBCPP_DEBUG
- assert(__s != 0);
-#endif
+ _LIBCPP_ASSERT(__s != nullptr, "string::find_first_not_of(): recieved nullptr");
return find_first_not_of(__s, __pos, traits_type::length(__s));
}
@@ -3496,9 +3524,7 @@
size_type __pos,
size_type __n) const _NOEXCEPT
{
-#ifdef _LIBCPP_DEBUG
- assert(__s != 0);
-#endif
+ _LIBCPP_ASSERT(__n == 0 || __s != nullptr, "string::find_last_not_of(): recieved nullptr");
size_type __sz = size();
if (__pos < __sz)
++__pos;
@@ -3526,9 +3552,7 @@
basic_string<_CharT, _Traits, _Allocator>::find_last_not_of(const value_type* __s,
size_type __pos) const _NOEXCEPT
{
-#ifdef _LIBCPP_DEBUG
- assert(__s != 0);
-#endif
+ _LIBCPP_ASSERT(__s != nullptr, "string::find_last_not_of(): recieved nullptr");
return find_last_not_of(__s, __pos, traits_type::length(__s));
}
@@ -3599,9 +3623,7 @@
int
basic_string<_CharT, _Traits, _Allocator>::compare(const value_type* __s) const _NOEXCEPT
{
-#ifdef _LIBCPP_DEBUG
- assert(__s != 0);
-#endif
+ _LIBCPP_ASSERT(__s != nullptr, "string::compare(): recieved nullptr");
return compare(0, npos, __s, traits_type::length(__s));
}
@@ -3611,9 +3633,7 @@
size_type __n1,
const value_type* __s) const
{
-#ifdef _LIBCPP_DEBUG
- assert(__s != 0);
-#endif
+ _LIBCPP_ASSERT(__s != nullptr, "string::compare(): recieved nullptr");
return compare(__pos1, __n1, __s, traits_type::length(__s));
}
@@ -3624,9 +3644,7 @@
const value_type* __s,
size_type __n2) const
{
-#ifdef _LIBCPP_DEBUG
- assert(__s != 0);
-#endif
+ _LIBCPP_ASSERT(__n2 == 0 || __s != nullptr, "string::compare(): recieved nullptr");
size_type __sz = size();
if (__pos1 > __sz || __n2 == npos)
this->__throw_out_of_range();
@@ -4102,6 +4120,42 @@
#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
+#if _LIBCPP_DEBUG_LEVEL >= 2
+
+template<class _CharT, class _Traits, class _Allocator>
+bool
+basic_string<_CharT, _Traits, _Allocator>::__dereferenceable(const const_iterator* __i) const
+{
+ return this->data() <= _VSTD::__to_raw_pointer(__i->base()) &&
+ _VSTD::__to_raw_pointer(__i->base()) < this->data() + this->size();
+}
+
+template<class _CharT, class _Traits, class _Allocator>
+bool
+basic_string<_CharT, _Traits, _Allocator>::__decrementable(const const_iterator* __i) const
+{
+ return this->data() < _VSTD::__to_raw_pointer(__i->base()) &&
+ _VSTD::__to_raw_pointer(__i->base()) <= this->data() + this->size();
+}
+
+template<class _CharT, class _Traits, class _Allocator>
+bool
+basic_string<_CharT, _Traits, _Allocator>::__addable(const const_iterator* __i, ptrdiff_t __n) const
+{
+ const value_type* __p = _VSTD::__to_raw_pointer(__i->base()) + __n;
+ return this->data() <= __p && __p <= this->data() + this->size();
+}
+
+template<class _CharT, class _Traits, class _Allocator>
+bool
+basic_string<_CharT, _Traits, _Allocator>::__subscriptable(const const_iterator* __i, ptrdiff_t __n) const
+{
+ const value_type* __p = _VSTD::__to_raw_pointer(__i->base()) + __n;
+ return this->data() <= __p && __p < this->data() + this->size();
+}
+
+#endif // _LIBCPP_DEBUG_LEVEL >= 2
+
#if _LIBCPP_STD_VER > 11
// Literal suffixes for basic_string [basic.string.literals]
// inline // Deviation from N3690.
@@ -4140,10 +4194,7 @@
_LIBCPP_EXTERN_TEMPLATE(class _LIBCPP_TYPE_VIS basic_string<char>)
_LIBCPP_EXTERN_TEMPLATE(class _LIBCPP_TYPE_VIS basic_string<wchar_t>)
-
-extern template
- string
- operator+<char, char_traits<char>, allocator<char> >(char const*, string const&);
+_LIBCPP_EXTERN_TEMPLATE(string operator+<char, char_traits<char>, allocator<char> >(char const*, string const&))
_LIBCPP_END_NAMESPACE_STD