xref: /freebsd-12.1/contrib/libc++/src/debug.cpp (revision aed8d94e)
17a984708SDavid Chisnall //===-------------------------- debug.cpp ---------------------------------===//
27a984708SDavid Chisnall //
37a984708SDavid Chisnall //                     The LLVM Compiler Infrastructure
47a984708SDavid Chisnall //
57a984708SDavid Chisnall // This file is dual licensed under the MIT and the University of Illinois Open
67a984708SDavid Chisnall // Source Licenses. See LICENSE.TXT for details.
77a984708SDavid Chisnall //
87a984708SDavid Chisnall //===----------------------------------------------------------------------===//
97a984708SDavid Chisnall 
107a984708SDavid Chisnall #include "__config"
117a984708SDavid Chisnall #include "__debug"
127a984708SDavid Chisnall #include "functional"
137a984708SDavid Chisnall #include "algorithm"
14*aed8d94eSDimitry Andric #include "string"
15*aed8d94eSDimitry Andric #include "cstdio"
167a984708SDavid Chisnall #include "__hash_table"
177a984708SDavid Chisnall #include "mutex"
187a984708SDavid Chisnall 
197a984708SDavid Chisnall _LIBCPP_BEGIN_NAMESPACE_STD
207a984708SDavid Chisnall 
make_what_str(__libcpp_debug_info const & info)21*aed8d94eSDimitry Andric static std::string make_what_str(__libcpp_debug_info const& info) {
22*aed8d94eSDimitry Andric   string msg = info.__file_;
23*aed8d94eSDimitry Andric   msg += ":" + to_string(info.__line_) + ": _LIBCPP_ASSERT '";
24*aed8d94eSDimitry Andric   msg += info.__pred_;
25*aed8d94eSDimitry Andric   msg += "' failed. ";
26*aed8d94eSDimitry Andric   msg += info.__msg_;
27*aed8d94eSDimitry Andric   return msg;
28*aed8d94eSDimitry Andric }
29*aed8d94eSDimitry Andric 
30*aed8d94eSDimitry Andric _LIBCPP_SAFE_STATIC __libcpp_debug_function_type
31*aed8d94eSDimitry Andric     __libcpp_debug_function = __libcpp_abort_debug_function;
32*aed8d94eSDimitry Andric 
__libcpp_set_debug_function(__libcpp_debug_function_type __func)33*aed8d94eSDimitry Andric bool __libcpp_set_debug_function(__libcpp_debug_function_type __func) {
34*aed8d94eSDimitry Andric   __libcpp_debug_function = __func;
35*aed8d94eSDimitry Andric   return true;
36*aed8d94eSDimitry Andric }
37*aed8d94eSDimitry Andric 
__libcpp_abort_debug_function(__libcpp_debug_info const & info)38*aed8d94eSDimitry Andric _LIBCPP_NORETURN void __libcpp_abort_debug_function(__libcpp_debug_info const& info) {
39*aed8d94eSDimitry Andric   std::fprintf(stderr, "%s\n", make_what_str(info).c_str());
40*aed8d94eSDimitry Andric   std::abort();
41*aed8d94eSDimitry Andric }
42*aed8d94eSDimitry Andric 
__libcpp_throw_debug_function(__libcpp_debug_info const & info)43*aed8d94eSDimitry Andric _LIBCPP_NORETURN void __libcpp_throw_debug_function(__libcpp_debug_info const& info) {
44*aed8d94eSDimitry Andric #ifndef _LIBCPP_NO_EXCEPTIONS
45*aed8d94eSDimitry Andric   throw __libcpp_debug_exception(info);
46*aed8d94eSDimitry Andric #else
47*aed8d94eSDimitry Andric   __libcpp_abort_debug_function(info);
48*aed8d94eSDimitry Andric #endif
49*aed8d94eSDimitry Andric }
50*aed8d94eSDimitry Andric 
51*aed8d94eSDimitry Andric struct __libcpp_debug_exception::__libcpp_debug_exception_imp {
52*aed8d94eSDimitry Andric   __libcpp_debug_info __info_;
53*aed8d94eSDimitry Andric   std::string __what_str_;
54*aed8d94eSDimitry Andric };
55*aed8d94eSDimitry Andric 
__libcpp_debug_exception()56*aed8d94eSDimitry Andric __libcpp_debug_exception::__libcpp_debug_exception() _NOEXCEPT
57*aed8d94eSDimitry Andric     : __imp_(nullptr) {
58*aed8d94eSDimitry Andric }
59*aed8d94eSDimitry Andric 
__libcpp_debug_exception(__libcpp_debug_info const & info)60*aed8d94eSDimitry Andric __libcpp_debug_exception::__libcpp_debug_exception(
61*aed8d94eSDimitry Andric     __libcpp_debug_info const& info) : __imp_(new __libcpp_debug_exception_imp)
62*aed8d94eSDimitry Andric {
63*aed8d94eSDimitry Andric   __imp_->__info_ = info;
64*aed8d94eSDimitry Andric   __imp_->__what_str_ = make_what_str(info);
65*aed8d94eSDimitry Andric }
__libcpp_debug_exception(__libcpp_debug_exception const & other)66*aed8d94eSDimitry Andric __libcpp_debug_exception::__libcpp_debug_exception(
67*aed8d94eSDimitry Andric     __libcpp_debug_exception const& other) : __imp_(nullptr) {
68*aed8d94eSDimitry Andric   if (other.__imp_)
69*aed8d94eSDimitry Andric     __imp_ = new __libcpp_debug_exception_imp(*other.__imp_);
70*aed8d94eSDimitry Andric }
71*aed8d94eSDimitry Andric 
~__libcpp_debug_exception()72*aed8d94eSDimitry Andric __libcpp_debug_exception::~__libcpp_debug_exception() _NOEXCEPT {
73*aed8d94eSDimitry Andric   if (__imp_)
74*aed8d94eSDimitry Andric     delete __imp_;
75*aed8d94eSDimitry Andric }
76*aed8d94eSDimitry Andric 
what() const77*aed8d94eSDimitry Andric const char* __libcpp_debug_exception::what() const _NOEXCEPT {
78*aed8d94eSDimitry Andric   if (__imp_)
79*aed8d94eSDimitry Andric     return __imp_->__what_str_.c_str();
80*aed8d94eSDimitry Andric   return "__libcpp_debug_exception";
81*aed8d94eSDimitry Andric }
82*aed8d94eSDimitry Andric 
831bf9f7c1SDimitry Andric _LIBCPP_FUNC_VIS
847a984708SDavid Chisnall __libcpp_db*
__get_db()857a984708SDavid Chisnall __get_db()
867a984708SDavid Chisnall {
877a984708SDavid Chisnall     static __libcpp_db db;
887a984708SDavid Chisnall     return &db;
89cfdf2879SDavid Chisnall }
907a984708SDavid Chisnall 
911bf9f7c1SDimitry Andric _LIBCPP_FUNC_VIS
927a984708SDavid Chisnall const __libcpp_db*
__get_const_db()937a984708SDavid Chisnall __get_const_db()
947a984708SDavid Chisnall {
957a984708SDavid Chisnall     return __get_db();
967a984708SDavid Chisnall }
977a984708SDavid Chisnall 
987a984708SDavid Chisnall namespace
997a984708SDavid Chisnall {
1007a984708SDavid Chisnall 
101d72607e9SDimitry Andric #ifndef _LIBCPP_HAS_NO_THREADS
1027a984708SDavid Chisnall typedef mutex mutex_type;
1037a984708SDavid Chisnall typedef lock_guard<mutex_type> WLock;
1047a984708SDavid Chisnall typedef lock_guard<mutex_type> RLock;
1057a984708SDavid Chisnall 
1067a984708SDavid Chisnall mutex_type&
mut()1077a984708SDavid Chisnall mut()
1087a984708SDavid Chisnall {
1097a984708SDavid Chisnall     static mutex_type m;
1107a984708SDavid Chisnall     return m;
1117a984708SDavid Chisnall }
112d72607e9SDimitry Andric #endif // !_LIBCPP_HAS_NO_THREADS
1137a984708SDavid Chisnall 
1147a984708SDavid Chisnall }  // unnamed namespace
1157a984708SDavid Chisnall 
~__i_node()1167a984708SDavid Chisnall __i_node::~__i_node()
1177a984708SDavid Chisnall {
1187a984708SDavid Chisnall     if (__next_)
1197a984708SDavid Chisnall     {
1207a984708SDavid Chisnall         __next_->~__i_node();
1217a984708SDavid Chisnall         free(__next_);
1227a984708SDavid Chisnall     }
1237a984708SDavid Chisnall }
1247a984708SDavid Chisnall 
~__c_node()1257a984708SDavid Chisnall __c_node::~__c_node()
1267a984708SDavid Chisnall {
1277a984708SDavid Chisnall     free(beg_);
1287a984708SDavid Chisnall     if (__next_)
1297a984708SDavid Chisnall     {
1307a984708SDavid Chisnall         __next_->~__c_node();
1317a984708SDavid Chisnall         free(__next_);
1327a984708SDavid Chisnall     }
1337a984708SDavid Chisnall }
1347a984708SDavid Chisnall 
__libcpp_db()1357a984708SDavid Chisnall __libcpp_db::__libcpp_db()
1367a984708SDavid Chisnall     : __cbeg_(nullptr),
1377a984708SDavid Chisnall       __cend_(nullptr),
1387a984708SDavid Chisnall       __csz_(0),
1397a984708SDavid Chisnall       __ibeg_(nullptr),
1407a984708SDavid Chisnall       __iend_(nullptr),
1417a984708SDavid Chisnall       __isz_(0)
1427a984708SDavid Chisnall {
1437a984708SDavid Chisnall }
1447a984708SDavid Chisnall 
~__libcpp_db()1457a984708SDavid Chisnall __libcpp_db::~__libcpp_db()
1467a984708SDavid Chisnall {
1477a984708SDavid Chisnall     if (__cbeg_)
1487a984708SDavid Chisnall     {
1497a984708SDavid Chisnall         for (__c_node** p = __cbeg_; p != __cend_; ++p)
1507a984708SDavid Chisnall         {
1517a984708SDavid Chisnall             if (*p != nullptr)
1527a984708SDavid Chisnall             {
1537a984708SDavid Chisnall                 (*p)->~__c_node();
1547a984708SDavid Chisnall                 free(*p);
1557a984708SDavid Chisnall             }
1567a984708SDavid Chisnall         }
1577a984708SDavid Chisnall         free(__cbeg_);
1587a984708SDavid Chisnall     }
1597a984708SDavid Chisnall     if (__ibeg_)
1607a984708SDavid Chisnall     {
1617a984708SDavid Chisnall         for (__i_node** p = __ibeg_; p != __iend_; ++p)
1627a984708SDavid Chisnall         {
1637a984708SDavid Chisnall             if (*p != nullptr)
1647a984708SDavid Chisnall             {
1657a984708SDavid Chisnall                 (*p)->~__i_node();
1667a984708SDavid Chisnall                 free(*p);
1677a984708SDavid Chisnall             }
1687a984708SDavid Chisnall         }
1697a984708SDavid Chisnall         free(__ibeg_);
1707a984708SDavid Chisnall     }
1717a984708SDavid Chisnall }
1727a984708SDavid Chisnall 
1737a984708SDavid Chisnall void*
__find_c_from_i(void * __i) const1747a984708SDavid Chisnall __libcpp_db::__find_c_from_i(void* __i) const
1757a984708SDavid Chisnall {
176d72607e9SDimitry Andric #ifndef _LIBCPP_HAS_NO_THREADS
1777a984708SDavid Chisnall     RLock _(mut());
178d72607e9SDimitry Andric #endif
1797a984708SDavid Chisnall     __i_node* i = __find_iterator(__i);
1801bf9f7c1SDimitry Andric     _LIBCPP_ASSERT(i != nullptr, "iterator not found in debug database.");
1817a984708SDavid Chisnall     return i->__c_ != nullptr ? i->__c_->__c_ : nullptr;
1827a984708SDavid Chisnall }
1837a984708SDavid Chisnall 
1847a984708SDavid Chisnall void
__insert_ic(void * __i,const void * __c)1857a984708SDavid Chisnall __libcpp_db::__insert_ic(void* __i, const void* __c)
1867a984708SDavid Chisnall {
187d72607e9SDimitry Andric #ifndef _LIBCPP_HAS_NO_THREADS
1887a984708SDavid Chisnall     WLock _(mut());
189d72607e9SDimitry Andric #endif
1904f7ab58eSDimitry Andric     if (__cbeg_ == __cend_)
1914f7ab58eSDimitry Andric         return;
19294e3ee44SDavid Chisnall     size_t hc = hash<const void*>()(__c) % static_cast<size_t>(__cend_ - __cbeg_);
1937a984708SDavid Chisnall     __c_node* c = __cbeg_[hc];
1944f7ab58eSDimitry Andric     if (c == nullptr)
1954f7ab58eSDimitry Andric         return;
1967a984708SDavid Chisnall     while (c->__c_ != __c)
1977a984708SDavid Chisnall     {
1987a984708SDavid Chisnall         c = c->__next_;
1994f7ab58eSDimitry Andric         if (c == nullptr)
2004f7ab58eSDimitry Andric             return;
2017a984708SDavid Chisnall     }
2024f7ab58eSDimitry Andric     __i_node* i = __insert_iterator(__i);
2037a984708SDavid Chisnall     c->__add(i);
2047a984708SDavid Chisnall     i->__c_ = c;
2057a984708SDavid Chisnall }
2067a984708SDavid Chisnall 
2077a984708SDavid Chisnall __c_node*
__insert_c(void * __c)2087a984708SDavid Chisnall __libcpp_db::__insert_c(void* __c)
2097a984708SDavid Chisnall {
210d72607e9SDimitry Andric #ifndef _LIBCPP_HAS_NO_THREADS
2117a984708SDavid Chisnall     WLock _(mut());
212d72607e9SDimitry Andric #endif
21394e3ee44SDavid Chisnall     if (__csz_ + 1 > static_cast<size_t>(__cend_ - __cbeg_))
2147a984708SDavid Chisnall     {
21594e3ee44SDavid Chisnall         size_t nc = __next_prime(2*static_cast<size_t>(__cend_ - __cbeg_) + 1);
2164bab9fd9SDavid Chisnall         __c_node** cbeg = static_cast<__c_node**>(calloc(nc, sizeof(void*)));
2177a984708SDavid Chisnall         if (cbeg == nullptr)
218*aed8d94eSDimitry Andric             __throw_bad_alloc();
219*aed8d94eSDimitry Andric 
2207a984708SDavid Chisnall         for (__c_node** p = __cbeg_; p != __cend_; ++p)
2217a984708SDavid Chisnall         {
2227a984708SDavid Chisnall             __c_node* q = *p;
2237a984708SDavid Chisnall             while (q != nullptr)
2247a984708SDavid Chisnall             {
2257a984708SDavid Chisnall                 size_t h = hash<void*>()(q->__c_) % nc;
2267a984708SDavid Chisnall                 __c_node* r = q->__next_;
2277a984708SDavid Chisnall                 q->__next_ = cbeg[h];
2287a984708SDavid Chisnall                 cbeg[h] = q;
2297a984708SDavid Chisnall                 q = r;
2307a984708SDavid Chisnall             }
2317a984708SDavid Chisnall         }
2327a984708SDavid Chisnall         free(__cbeg_);
2337a984708SDavid Chisnall         __cbeg_ = cbeg;
2347a984708SDavid Chisnall         __cend_ = __cbeg_ + nc;
2357a984708SDavid Chisnall     }
23694e3ee44SDavid Chisnall     size_t hc = hash<void*>()(__c) % static_cast<size_t>(__cend_ - __cbeg_);
2377a984708SDavid Chisnall     __c_node* p = __cbeg_[hc];
2384bab9fd9SDavid Chisnall     __c_node* r = __cbeg_[hc] =
2394bab9fd9SDavid Chisnall       static_cast<__c_node*>(malloc(sizeof(__c_node)));
2407a984708SDavid Chisnall     if (__cbeg_[hc] == nullptr)
241*aed8d94eSDimitry Andric         __throw_bad_alloc();
242*aed8d94eSDimitry Andric 
2437a984708SDavid Chisnall     r->__c_ = __c;
2447a984708SDavid Chisnall     r->__next_ = p;
2457a984708SDavid Chisnall     ++__csz_;
2467a984708SDavid Chisnall     return r;
2477a984708SDavid Chisnall }
2487a984708SDavid Chisnall 
2497a984708SDavid Chisnall void
__erase_i(void * __i)2507a984708SDavid Chisnall __libcpp_db::__erase_i(void* __i)
2517a984708SDavid Chisnall {
252d72607e9SDimitry Andric #ifndef _LIBCPP_HAS_NO_THREADS
2537a984708SDavid Chisnall     WLock _(mut());
254d72607e9SDimitry Andric #endif
2557a984708SDavid Chisnall     if (__ibeg_ != __iend_)
2567a984708SDavid Chisnall     {
25794e3ee44SDavid Chisnall         size_t hi = hash<void*>()(__i) % static_cast<size_t>(__iend_ - __ibeg_);
2587a984708SDavid Chisnall         __i_node* p = __ibeg_[hi];
2597a984708SDavid Chisnall         if (p != nullptr)
2607a984708SDavid Chisnall         {
2617a984708SDavid Chisnall             __i_node* q = nullptr;
2627a984708SDavid Chisnall             while (p->__i_ != __i)
2637a984708SDavid Chisnall             {
2647a984708SDavid Chisnall                 q = p;
2657a984708SDavid Chisnall                 p = p->__next_;
2667a984708SDavid Chisnall                 if (p == nullptr)
2677a984708SDavid Chisnall                     return;
2687a984708SDavid Chisnall             }
2697a984708SDavid Chisnall             if (q == nullptr)
2707a984708SDavid Chisnall                 __ibeg_[hi] = p->__next_;
2717a984708SDavid Chisnall             else
2727a984708SDavid Chisnall                 q->__next_ = p->__next_;
2737a984708SDavid Chisnall             __c_node* c = p->__c_;
2747a984708SDavid Chisnall             --__isz_;
2757a984708SDavid Chisnall             if (c != nullptr)
2767a984708SDavid Chisnall                 c->__remove(p);
277854fa44bSDimitry Andric             free(p);
2787a984708SDavid Chisnall         }
2797a984708SDavid Chisnall     }
2807a984708SDavid Chisnall }
2817a984708SDavid Chisnall 
2827a984708SDavid Chisnall void
__invalidate_all(void * __c)2837a984708SDavid Chisnall __libcpp_db::__invalidate_all(void* __c)
2847a984708SDavid Chisnall {
285d72607e9SDimitry Andric #ifndef _LIBCPP_HAS_NO_THREADS
2867a984708SDavid Chisnall     WLock _(mut());
287d72607e9SDimitry Andric #endif
2884f7ab58eSDimitry Andric     if (__cend_ != __cbeg_)
2894f7ab58eSDimitry Andric     {
29094e3ee44SDavid Chisnall         size_t hc = hash<void*>()(__c) % static_cast<size_t>(__cend_ - __cbeg_);
2917a984708SDavid Chisnall         __c_node* p = __cbeg_[hc];
2924f7ab58eSDimitry Andric         if (p == nullptr)
2934f7ab58eSDimitry Andric             return;
2947a984708SDavid Chisnall         while (p->__c_ != __c)
2957a984708SDavid Chisnall         {
2967a984708SDavid Chisnall             p = p->__next_;
2974f7ab58eSDimitry Andric             if (p == nullptr)
2984f7ab58eSDimitry Andric                 return;
2997a984708SDavid Chisnall         }
3007a984708SDavid Chisnall         while (p->end_ != p->beg_)
3017a984708SDavid Chisnall         {
3027a984708SDavid Chisnall             --p->end_;
3037a984708SDavid Chisnall             (*p->end_)->__c_ = nullptr;
3047a984708SDavid Chisnall         }
3057a984708SDavid Chisnall     }
3064f7ab58eSDimitry Andric }
3077a984708SDavid Chisnall 
3087a984708SDavid Chisnall __c_node*
__find_c_and_lock(void * __c) const3097a984708SDavid Chisnall __libcpp_db::__find_c_and_lock(void* __c) const
3107a984708SDavid Chisnall {
311d72607e9SDimitry Andric #ifndef _LIBCPP_HAS_NO_THREADS
3127a984708SDavid Chisnall     mut().lock();
313d72607e9SDimitry Andric #endif
3144f7ab58eSDimitry Andric     if (__cend_ == __cbeg_)
3154f7ab58eSDimitry Andric     {
316d72607e9SDimitry Andric #ifndef _LIBCPP_HAS_NO_THREADS
3174f7ab58eSDimitry Andric         mut().unlock();
318d72607e9SDimitry Andric #endif
3194f7ab58eSDimitry Andric         return nullptr;
3204f7ab58eSDimitry Andric     }
32194e3ee44SDavid Chisnall     size_t hc = hash<void*>()(__c) % static_cast<size_t>(__cend_ - __cbeg_);
3227a984708SDavid Chisnall     __c_node* p = __cbeg_[hc];
3234f7ab58eSDimitry Andric     if (p == nullptr)
3244f7ab58eSDimitry Andric     {
325d72607e9SDimitry Andric #ifndef _LIBCPP_HAS_NO_THREADS
3264f7ab58eSDimitry Andric         mut().unlock();
327d72607e9SDimitry Andric #endif
3284f7ab58eSDimitry Andric         return nullptr;
3294f7ab58eSDimitry Andric     }
3307a984708SDavid Chisnall     while (p->__c_ != __c)
3317a984708SDavid Chisnall     {
3327a984708SDavid Chisnall         p = p->__next_;
3334f7ab58eSDimitry Andric         if (p == nullptr)
3344f7ab58eSDimitry Andric         {
335d72607e9SDimitry Andric #ifndef _LIBCPP_HAS_NO_THREADS
3364f7ab58eSDimitry Andric             mut().unlock();
337d72607e9SDimitry Andric #endif
3384f7ab58eSDimitry Andric             return nullptr;
3394f7ab58eSDimitry Andric         }
3407a984708SDavid Chisnall     }
3417a984708SDavid Chisnall     return p;
3427a984708SDavid Chisnall }
3437a984708SDavid Chisnall 
3447a984708SDavid Chisnall __c_node*
__find_c(void * __c) const3457a984708SDavid Chisnall __libcpp_db::__find_c(void* __c) const
3467a984708SDavid Chisnall {
34794e3ee44SDavid Chisnall     size_t hc = hash<void*>()(__c) % static_cast<size_t>(__cend_ - __cbeg_);
3487a984708SDavid Chisnall     __c_node* p = __cbeg_[hc];
3497a984708SDavid Chisnall     _LIBCPP_ASSERT(p != nullptr, "debug mode internal logic error __find_c A");
3507a984708SDavid Chisnall     while (p->__c_ != __c)
3517a984708SDavid Chisnall     {
3527a984708SDavid Chisnall         p = p->__next_;
3537a984708SDavid Chisnall         _LIBCPP_ASSERT(p != nullptr, "debug mode internal logic error __find_c B");
3547a984708SDavid Chisnall     }
3557a984708SDavid Chisnall     return p;
3567a984708SDavid Chisnall }
3577a984708SDavid Chisnall 
3587a984708SDavid Chisnall void
unlock() const3597a984708SDavid Chisnall __libcpp_db::unlock() const
3607a984708SDavid Chisnall {
361d72607e9SDimitry Andric #ifndef _LIBCPP_HAS_NO_THREADS
3627a984708SDavid Chisnall     mut().unlock();
363d72607e9SDimitry Andric #endif
3647a984708SDavid Chisnall }
3657a984708SDavid Chisnall 
3667a984708SDavid Chisnall void
__erase_c(void * __c)3677a984708SDavid Chisnall __libcpp_db::__erase_c(void* __c)
3687a984708SDavid Chisnall {
369d72607e9SDimitry Andric #ifndef _LIBCPP_HAS_NO_THREADS
3707a984708SDavid Chisnall     WLock _(mut());
371d72607e9SDimitry Andric #endif
3724f7ab58eSDimitry Andric     if (__cend_ != __cbeg_)
3734f7ab58eSDimitry Andric     {
37494e3ee44SDavid Chisnall         size_t hc = hash<void*>()(__c) % static_cast<size_t>(__cend_ - __cbeg_);
3757a984708SDavid Chisnall         __c_node* p = __cbeg_[hc];
3764f7ab58eSDimitry Andric         if (p == nullptr)
3774f7ab58eSDimitry Andric             return;
3787a984708SDavid Chisnall         __c_node* q = nullptr;
3797a984708SDavid Chisnall         _LIBCPP_ASSERT(p != nullptr, "debug mode internal logic error __erase_c A");
3807a984708SDavid Chisnall         while (p->__c_ != __c)
3817a984708SDavid Chisnall         {
3827a984708SDavid Chisnall             q = p;
3837a984708SDavid Chisnall             p = p->__next_;
3844f7ab58eSDimitry Andric             if (p == nullptr)
3854f7ab58eSDimitry Andric                 return;
3867a984708SDavid Chisnall             _LIBCPP_ASSERT(p != nullptr, "debug mode internal logic error __erase_c B");
3877a984708SDavid Chisnall         }
3887a984708SDavid Chisnall         if (q == nullptr)
3897a984708SDavid Chisnall             __cbeg_[hc] = p->__next_;
3907a984708SDavid Chisnall         else
3917a984708SDavid Chisnall             q->__next_ = p->__next_;
3927a984708SDavid Chisnall         while (p->end_ != p->beg_)
3937a984708SDavid Chisnall         {
3947a984708SDavid Chisnall             --p->end_;
3957a984708SDavid Chisnall             (*p->end_)->__c_ = nullptr;
3967a984708SDavid Chisnall         }
3977a984708SDavid Chisnall         free(p->beg_);
3987a984708SDavid Chisnall         free(p);
3997a984708SDavid Chisnall         --__csz_;
4007a984708SDavid Chisnall     }
4014f7ab58eSDimitry Andric }
4027a984708SDavid Chisnall 
4037a984708SDavid Chisnall void
__iterator_copy(void * __i,const void * __i0)4047a984708SDavid Chisnall __libcpp_db::__iterator_copy(void* __i, const void* __i0)
4057a984708SDavid Chisnall {
406d72607e9SDimitry Andric #ifndef _LIBCPP_HAS_NO_THREADS
4077a984708SDavid Chisnall     WLock _(mut());
408d72607e9SDimitry Andric #endif
4097a984708SDavid Chisnall     __i_node* i = __find_iterator(__i);
4107a984708SDavid Chisnall     __i_node* i0 = __find_iterator(__i0);
4117a984708SDavid Chisnall     __c_node* c0 = i0 != nullptr ? i0->__c_ : nullptr;
4121bf9f7c1SDimitry Andric     if (i == nullptr && i0 != nullptr)
4137a984708SDavid Chisnall         i = __insert_iterator(__i);
4147a984708SDavid Chisnall     __c_node* c = i != nullptr ? i->__c_ : nullptr;
4157a984708SDavid Chisnall     if (c != c0)
4167a984708SDavid Chisnall     {
4177a984708SDavid Chisnall         if (c != nullptr)
4187a984708SDavid Chisnall             c->__remove(i);
4197a984708SDavid Chisnall         if (i != nullptr)
4207a984708SDavid Chisnall         {
4217a984708SDavid Chisnall             i->__c_ = nullptr;
4227a984708SDavid Chisnall             if (c0 != nullptr)
4237a984708SDavid Chisnall             {
4247a984708SDavid Chisnall                 i->__c_ = c0;
4257a984708SDavid Chisnall                 i->__c_->__add(i);
4267a984708SDavid Chisnall             }
4277a984708SDavid Chisnall         }
4287a984708SDavid Chisnall     }
4297a984708SDavid Chisnall }
4307a984708SDavid Chisnall 
4317a984708SDavid Chisnall bool
__dereferenceable(const void * __i) const4327a984708SDavid Chisnall __libcpp_db::__dereferenceable(const void* __i) const
4337a984708SDavid Chisnall {
434d72607e9SDimitry Andric #ifndef _LIBCPP_HAS_NO_THREADS
4357a984708SDavid Chisnall     RLock _(mut());
436d72607e9SDimitry Andric #endif
4377a984708SDavid Chisnall     __i_node* i = __find_iterator(__i);
4387a984708SDavid Chisnall     return i != nullptr && i->__c_ != nullptr && i->__c_->__dereferenceable(__i);
4397a984708SDavid Chisnall }
4407a984708SDavid Chisnall 
4417a984708SDavid Chisnall bool
__decrementable(const void * __i) const4427a984708SDavid Chisnall __libcpp_db::__decrementable(const void* __i) const
4437a984708SDavid Chisnall {
444d72607e9SDimitry Andric #ifndef _LIBCPP_HAS_NO_THREADS
4457a984708SDavid Chisnall     RLock _(mut());
446d72607e9SDimitry Andric #endif
4477a984708SDavid Chisnall     __i_node* i = __find_iterator(__i);
4487a984708SDavid Chisnall     return i != nullptr && i->__c_ != nullptr && i->__c_->__decrementable(__i);
4497a984708SDavid Chisnall }
4507a984708SDavid Chisnall 
4517a984708SDavid Chisnall bool
__addable(const void * __i,ptrdiff_t __n) const4527a984708SDavid Chisnall __libcpp_db::__addable(const void* __i, ptrdiff_t __n) const
4537a984708SDavid Chisnall {
454d72607e9SDimitry Andric #ifndef _LIBCPP_HAS_NO_THREADS
4557a984708SDavid Chisnall     RLock _(mut());
456d72607e9SDimitry Andric #endif
4577a984708SDavid Chisnall     __i_node* i = __find_iterator(__i);
4587a984708SDavid Chisnall     return i != nullptr && i->__c_ != nullptr && i->__c_->__addable(__i, __n);
4597a984708SDavid Chisnall }
4607a984708SDavid Chisnall 
4617a984708SDavid Chisnall bool
__subscriptable(const void * __i,ptrdiff_t __n) const4627a984708SDavid Chisnall __libcpp_db::__subscriptable(const void* __i, ptrdiff_t __n) const
4637a984708SDavid Chisnall {
464d72607e9SDimitry Andric #ifndef _LIBCPP_HAS_NO_THREADS
4657a984708SDavid Chisnall     RLock _(mut());
466d72607e9SDimitry Andric #endif
4677a984708SDavid Chisnall     __i_node* i = __find_iterator(__i);
4687a984708SDavid Chisnall     return i != nullptr && i->__c_ != nullptr && i->__c_->__subscriptable(__i, __n);
4697a984708SDavid Chisnall }
4707a984708SDavid Chisnall 
4717a984708SDavid Chisnall bool
__less_than_comparable(const void * __i,const void * __j) const4724f7ab58eSDimitry Andric __libcpp_db::__less_than_comparable(const void* __i, const void* __j) const
4737a984708SDavid Chisnall {
474d72607e9SDimitry Andric #ifndef _LIBCPP_HAS_NO_THREADS
4757a984708SDavid Chisnall     RLock _(mut());
476d72607e9SDimitry Andric #endif
4777a984708SDavid Chisnall     __i_node* i = __find_iterator(__i);
4787a984708SDavid Chisnall     __i_node* j = __find_iterator(__j);
4797a984708SDavid Chisnall     __c_node* ci = i != nullptr ? i->__c_ : nullptr;
4807a984708SDavid Chisnall     __c_node* cj = j != nullptr ? j->__c_ : nullptr;
4817a984708SDavid Chisnall     return ci != nullptr && ci == cj;
4827a984708SDavid Chisnall }
4837a984708SDavid Chisnall 
4847a984708SDavid Chisnall void
swap(void * c1,void * c2)4857a984708SDavid Chisnall __libcpp_db::swap(void* c1, void* c2)
4867a984708SDavid Chisnall {
487d72607e9SDimitry Andric #ifndef _LIBCPP_HAS_NO_THREADS
4887a984708SDavid Chisnall     WLock _(mut());
489d72607e9SDimitry Andric #endif
49094e3ee44SDavid Chisnall     size_t hc = hash<void*>()(c1) % static_cast<size_t>(__cend_ - __cbeg_);
4917a984708SDavid Chisnall     __c_node* p1 = __cbeg_[hc];
4927a984708SDavid Chisnall     _LIBCPP_ASSERT(p1 != nullptr, "debug mode internal logic error swap A");
4937a984708SDavid Chisnall     while (p1->__c_ != c1)
4947a984708SDavid Chisnall     {
4957a984708SDavid Chisnall         p1 = p1->__next_;
4967a984708SDavid Chisnall         _LIBCPP_ASSERT(p1 != nullptr, "debug mode internal logic error swap B");
4977a984708SDavid Chisnall     }
49894e3ee44SDavid Chisnall     hc = hash<void*>()(c2) % static_cast<size_t>(__cend_ - __cbeg_);
4997a984708SDavid Chisnall     __c_node* p2 = __cbeg_[hc];
5007a984708SDavid Chisnall     _LIBCPP_ASSERT(p2 != nullptr, "debug mode internal logic error swap C");
5017a984708SDavid Chisnall     while (p2->__c_ != c2)
5027a984708SDavid Chisnall     {
5037a984708SDavid Chisnall         p2 = p2->__next_;
5047a984708SDavid Chisnall         _LIBCPP_ASSERT(p2 != nullptr, "debug mode internal logic error swap D");
5057a984708SDavid Chisnall     }
5067a984708SDavid Chisnall     std::swap(p1->beg_, p2->beg_);
5077a984708SDavid Chisnall     std::swap(p1->end_, p2->end_);
5087a984708SDavid Chisnall     std::swap(p1->cap_, p2->cap_);
5097a984708SDavid Chisnall     for (__i_node** p = p1->beg_; p != p1->end_; ++p)
5107a984708SDavid Chisnall         (*p)->__c_ = p1;
5117a984708SDavid Chisnall     for (__i_node** p = p2->beg_; p != p2->end_; ++p)
5127a984708SDavid Chisnall         (*p)->__c_ = p2;
5137a984708SDavid Chisnall }
5147a984708SDavid Chisnall 
5157a984708SDavid Chisnall void
__insert_i(void * __i)5167a984708SDavid Chisnall __libcpp_db::__insert_i(void* __i)
5177a984708SDavid Chisnall {
518d72607e9SDimitry Andric #ifndef _LIBCPP_HAS_NO_THREADS
5197a984708SDavid Chisnall     WLock _(mut());
520d72607e9SDimitry Andric #endif
5217a984708SDavid Chisnall     __insert_iterator(__i);
5227a984708SDavid Chisnall }
5237a984708SDavid Chisnall 
5247a984708SDavid Chisnall void
__add(__i_node * i)5257a984708SDavid Chisnall __c_node::__add(__i_node* i)
5267a984708SDavid Chisnall {
5277a984708SDavid Chisnall     if (end_ == cap_)
5287a984708SDavid Chisnall     {
52994e3ee44SDavid Chisnall         size_t nc = 2*static_cast<size_t>(cap_ - beg_);
5307a984708SDavid Chisnall         if (nc == 0)
5317a984708SDavid Chisnall             nc = 1;
5324bab9fd9SDavid Chisnall         __i_node** beg =
5334bab9fd9SDavid Chisnall            static_cast<__i_node**>(malloc(nc * sizeof(__i_node*)));
5347a984708SDavid Chisnall         if (beg == nullptr)
535*aed8d94eSDimitry Andric             __throw_bad_alloc();
536*aed8d94eSDimitry Andric 
5377a984708SDavid Chisnall         if (nc > 1)
5387a984708SDavid Chisnall             memcpy(beg, beg_, nc/2*sizeof(__i_node*));
5397a984708SDavid Chisnall         free(beg_);
5407a984708SDavid Chisnall         beg_ = beg;
5417a984708SDavid Chisnall         end_ = beg_ + nc/2;
5427a984708SDavid Chisnall         cap_ = beg_ + nc;
5437a984708SDavid Chisnall     }
5447a984708SDavid Chisnall     *end_++ = i;
5457a984708SDavid Chisnall }
5467a984708SDavid Chisnall 
5477a984708SDavid Chisnall // private api
5487a984708SDavid Chisnall 
5497a984708SDavid Chisnall _LIBCPP_HIDDEN
5507a984708SDavid Chisnall __i_node*
__insert_iterator(void * __i)5517a984708SDavid Chisnall __libcpp_db::__insert_iterator(void* __i)
5527a984708SDavid Chisnall {
55394e3ee44SDavid Chisnall     if (__isz_ + 1 > static_cast<size_t>(__iend_ - __ibeg_))
5547a984708SDavid Chisnall     {
55594e3ee44SDavid Chisnall         size_t nc = __next_prime(2*static_cast<size_t>(__iend_ - __ibeg_) + 1);
5564bab9fd9SDavid Chisnall         __i_node** ibeg = static_cast<__i_node**>(calloc(nc, sizeof(void*)));
5577a984708SDavid Chisnall         if (ibeg == nullptr)
558*aed8d94eSDimitry Andric             __throw_bad_alloc();
559*aed8d94eSDimitry Andric 
5607a984708SDavid Chisnall         for (__i_node** p = __ibeg_; p != __iend_; ++p)
5617a984708SDavid Chisnall         {
5627a984708SDavid Chisnall             __i_node* q = *p;
5637a984708SDavid Chisnall             while (q != nullptr)
5647a984708SDavid Chisnall             {
5657a984708SDavid Chisnall                 size_t h = hash<void*>()(q->__i_) % nc;
5667a984708SDavid Chisnall                 __i_node* r = q->__next_;
5677a984708SDavid Chisnall                 q->__next_ = ibeg[h];
5687a984708SDavid Chisnall                 ibeg[h] = q;
5697a984708SDavid Chisnall                 q = r;
5707a984708SDavid Chisnall             }
5717a984708SDavid Chisnall         }
5727a984708SDavid Chisnall         free(__ibeg_);
5737a984708SDavid Chisnall         __ibeg_ = ibeg;
5747a984708SDavid Chisnall         __iend_ = __ibeg_ + nc;
5757a984708SDavid Chisnall     }
57694e3ee44SDavid Chisnall     size_t hi = hash<void*>()(__i) % static_cast<size_t>(__iend_ - __ibeg_);
5777a984708SDavid Chisnall     __i_node* p = __ibeg_[hi];
5784bab9fd9SDavid Chisnall     __i_node* r = __ibeg_[hi] =
5794bab9fd9SDavid Chisnall       static_cast<__i_node*>(malloc(sizeof(__i_node)));
5807a984708SDavid Chisnall     if (r == nullptr)
581*aed8d94eSDimitry Andric         __throw_bad_alloc();
582*aed8d94eSDimitry Andric 
5837a984708SDavid Chisnall     ::new(r) __i_node(__i, p, nullptr);
5847a984708SDavid Chisnall     ++__isz_;
5857a984708SDavid Chisnall     return r;
5867a984708SDavid Chisnall }
5877a984708SDavid Chisnall 
5887a984708SDavid Chisnall _LIBCPP_HIDDEN
5897a984708SDavid Chisnall __i_node*
__find_iterator(const void * __i) const5907a984708SDavid Chisnall __libcpp_db::__find_iterator(const void* __i) const
5917a984708SDavid Chisnall {
5927a984708SDavid Chisnall     __i_node* r = nullptr;
5937a984708SDavid Chisnall     if (__ibeg_ != __iend_)
5947a984708SDavid Chisnall     {
59594e3ee44SDavid Chisnall         size_t h = hash<const void*>()(__i) % static_cast<size_t>(__iend_ - __ibeg_);
5967a984708SDavid Chisnall         for (__i_node* nd = __ibeg_[h]; nd != nullptr; nd = nd->__next_)
5977a984708SDavid Chisnall         {
5987a984708SDavid Chisnall             if (nd->__i_ == __i)
5997a984708SDavid Chisnall             {
6007a984708SDavid Chisnall                 r = nd;
6017a984708SDavid Chisnall                 break;
6027a984708SDavid Chisnall             }
6037a984708SDavid Chisnall         }
6047a984708SDavid Chisnall     }
6057a984708SDavid Chisnall     return r;
6067a984708SDavid Chisnall }
6077a984708SDavid Chisnall 
6087a984708SDavid Chisnall _LIBCPP_HIDDEN
6097a984708SDavid Chisnall void
__remove(__i_node * p)6107a984708SDavid Chisnall __c_node::__remove(__i_node* p)
6117a984708SDavid Chisnall {
6127a984708SDavid Chisnall     __i_node** r = find(beg_, end_, p);
6137a984708SDavid Chisnall     _LIBCPP_ASSERT(r != end_, "debug mode internal logic error __c_node::__remove");
6147a984708SDavid Chisnall     if (--end_ != r)
61594e3ee44SDavid Chisnall         memmove(r, r+1, static_cast<size_t>(end_ - r)*sizeof(__i_node*));
6167a984708SDavid Chisnall }
6177a984708SDavid Chisnall 
6187a984708SDavid Chisnall _LIBCPP_END_NAMESPACE_STD
619