xref: /llvm-project-15.0.7/libcxx/src/debug.cpp (revision bbb0f2c7)
1eb8650a7SLouis Dionne //===----------------------------------------------------------------------===//
2f554add5SHoward Hinnant //
357b08b09SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
457b08b09SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
557b08b09SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6f554add5SHoward Hinnant //
7f554add5SHoward Hinnant //===----------------------------------------------------------------------===//
8f554add5SHoward Hinnant 
9*bbb0f2c7SArthur O'Dwyer #include <__config>
10*bbb0f2c7SArthur O'Dwyer #include <__debug>
11*bbb0f2c7SArthur O'Dwyer #include <__hash_table>
12*bbb0f2c7SArthur O'Dwyer #include <algorithm>
13*bbb0f2c7SArthur O'Dwyer #include <cstdio>
14*bbb0f2c7SArthur O'Dwyer #include <functional>
15*bbb0f2c7SArthur O'Dwyer #include <string>
16*bbb0f2c7SArthur O'Dwyer 
17996e62eeSPetr Hosek #ifndef _LIBCPP_HAS_NO_THREADS
18*bbb0f2c7SArthur O'Dwyer #  include <mutex>
19a9b5fff5SMichał Górny #  if defined(__ELF__) && defined(_LIBCPP_LINK_PTHREAD_LIB)
20996e62eeSPetr Hosek #    pragma comment(lib, "pthread")
21996e62eeSPetr Hosek #  endif
22996e62eeSPetr Hosek #endif
23f554add5SHoward Hinnant 
24f554add5SHoward Hinnant _LIBCPP_BEGIN_NAMESPACE_STD
25f554add5SHoward Hinnant 
2661b302f9SEric Fiselier std::string __libcpp_debug_info::what() const {
2761b302f9SEric Fiselier   string msg = __file_;
2861b302f9SEric Fiselier   msg += ":" + to_string(__line_) + ": _LIBCPP_ASSERT '";
2961b302f9SEric Fiselier   msg += __pred_;
30687d3213SEric Fiselier   msg += "' failed. ";
3161b302f9SEric Fiselier   msg += __msg_;
32687d3213SEric Fiselier   return msg;
33687d3213SEric Fiselier }
3461b302f9SEric Fiselier _LIBCPP_NORETURN void __libcpp_abort_debug_function(__libcpp_debug_info const& info) {
3561b302f9SEric Fiselier     std::fprintf(stderr, "%s\n", info.what().c_str());
3661b302f9SEric Fiselier     std::abort();
3761b302f9SEric Fiselier }
38687d3213SEric Fiselier 
3905337a75SArthur O'Dwyer constinit __libcpp_debug_function_type __libcpp_debug_function = __libcpp_abort_debug_function;
40687d3213SEric Fiselier 
41687d3213SEric Fiselier bool __libcpp_set_debug_function(__libcpp_debug_function_type __func) {
42687d3213SEric Fiselier   __libcpp_debug_function = __func;
43687d3213SEric Fiselier   return true;
44687d3213SEric Fiselier }
45687d3213SEric Fiselier 
466e41256fSHoward Hinnant _LIBCPP_FUNC_VIS
47f554add5SHoward Hinnant __libcpp_db*
48f554add5SHoward Hinnant __get_db()
49f554add5SHoward Hinnant {
5081875a67SLouis Dionne     static _LIBCPP_NO_DESTROY __libcpp_db db;
51f554add5SHoward Hinnant     return &db;
52267e3e1eSHoward Hinnant }
53f554add5SHoward Hinnant 
546e41256fSHoward Hinnant _LIBCPP_FUNC_VIS
55f554add5SHoward Hinnant const __libcpp_db*
56f554add5SHoward Hinnant __get_const_db()
57f554add5SHoward Hinnant {
58f554add5SHoward Hinnant     return __get_db();
59f554add5SHoward Hinnant }
60f554add5SHoward Hinnant 
61f554add5SHoward Hinnant namespace
62f554add5SHoward Hinnant {
63f554add5SHoward Hinnant 
64b3fcc67fSJonathan Roelofs #ifndef _LIBCPP_HAS_NO_THREADS
65f554add5SHoward Hinnant typedef mutex mutex_type;
66f554add5SHoward Hinnant typedef lock_guard<mutex_type> WLock;
67f554add5SHoward Hinnant typedef lock_guard<mutex_type> RLock;
68f554add5SHoward Hinnant 
69f554add5SHoward Hinnant mutex_type&
70f554add5SHoward Hinnant mut()
71f554add5SHoward Hinnant {
7281875a67SLouis Dionne     static _LIBCPP_NO_DESTROY mutex_type m;
73f554add5SHoward Hinnant     return m;
74f554add5SHoward Hinnant }
75b3fcc67fSJonathan Roelofs #endif // !_LIBCPP_HAS_NO_THREADS
76f554add5SHoward Hinnant 
77f554add5SHoward Hinnant }  // unnamed namespace
78f554add5SHoward Hinnant 
79f554add5SHoward Hinnant __i_node::~__i_node()
80f554add5SHoward Hinnant {
81f554add5SHoward Hinnant     if (__next_)
82f554add5SHoward Hinnant     {
83f554add5SHoward Hinnant         __next_->~__i_node();
84f554add5SHoward Hinnant         free(__next_);
85f554add5SHoward Hinnant     }
86f554add5SHoward Hinnant }
87f554add5SHoward Hinnant 
88f554add5SHoward Hinnant __c_node::~__c_node()
89f554add5SHoward Hinnant {
90f554add5SHoward Hinnant     free(beg_);
91f554add5SHoward Hinnant     if (__next_)
92f554add5SHoward Hinnant     {
93f554add5SHoward Hinnant         __next_->~__c_node();
94f554add5SHoward Hinnant         free(__next_);
95f554add5SHoward Hinnant     }
96f554add5SHoward Hinnant }
97f554add5SHoward Hinnant 
98f554add5SHoward Hinnant __libcpp_db::__libcpp_db()
99f554add5SHoward Hinnant     : __cbeg_(nullptr),
100f554add5SHoward Hinnant       __cend_(nullptr),
101f554add5SHoward Hinnant       __csz_(0),
102f554add5SHoward Hinnant       __ibeg_(nullptr),
103f554add5SHoward Hinnant       __iend_(nullptr),
104f554add5SHoward Hinnant       __isz_(0)
105f554add5SHoward Hinnant {
106f554add5SHoward Hinnant }
107f554add5SHoward Hinnant 
108f554add5SHoward Hinnant __libcpp_db::~__libcpp_db()
109f554add5SHoward Hinnant {
110f554add5SHoward Hinnant     if (__cbeg_)
111f554add5SHoward Hinnant     {
112f554add5SHoward Hinnant         for (__c_node** p = __cbeg_; p != __cend_; ++p)
113f554add5SHoward Hinnant         {
114f554add5SHoward Hinnant             if (*p != nullptr)
115f554add5SHoward Hinnant             {
116f554add5SHoward Hinnant                 (*p)->~__c_node();
117f554add5SHoward Hinnant                 free(*p);
118f554add5SHoward Hinnant             }
119f554add5SHoward Hinnant         }
120f554add5SHoward Hinnant         free(__cbeg_);
121f554add5SHoward Hinnant     }
122f554add5SHoward Hinnant     if (__ibeg_)
123f554add5SHoward Hinnant     {
124f554add5SHoward Hinnant         for (__i_node** p = __ibeg_; p != __iend_; ++p)
125f554add5SHoward Hinnant         {
126f554add5SHoward Hinnant             if (*p != nullptr)
127f554add5SHoward Hinnant             {
128f554add5SHoward Hinnant                 (*p)->~__i_node();
129f554add5SHoward Hinnant                 free(*p);
130f554add5SHoward Hinnant             }
131f554add5SHoward Hinnant         }
132f554add5SHoward Hinnant         free(__ibeg_);
133f554add5SHoward Hinnant     }
134f554add5SHoward Hinnant }
135f554add5SHoward Hinnant 
136f554add5SHoward Hinnant void*
137f554add5SHoward Hinnant __libcpp_db::__find_c_from_i(void* __i) const
138f554add5SHoward Hinnant {
139b3fcc67fSJonathan Roelofs #ifndef _LIBCPP_HAS_NO_THREADS
140f554add5SHoward Hinnant     RLock _(mut());
141b3fcc67fSJonathan Roelofs #endif
142f554add5SHoward Hinnant     __i_node* i = __find_iterator(__i);
143f7509231SHoward Hinnant     _LIBCPP_ASSERT(i != nullptr, "iterator not found in debug database.");
144c36bfc49SHoward Hinnant     return i->__c_ != nullptr ? i->__c_->__c_ : nullptr;
145f554add5SHoward Hinnant }
146f554add5SHoward Hinnant 
147f554add5SHoward Hinnant void
148f554add5SHoward Hinnant __libcpp_db::__insert_ic(void* __i, const void* __c)
149f554add5SHoward Hinnant {
150b3fcc67fSJonathan Roelofs #ifndef _LIBCPP_HAS_NO_THREADS
151f554add5SHoward Hinnant     WLock _(mut());
152b3fcc67fSJonathan Roelofs #endif
153fc88dbd2SHoward Hinnant     if (__cbeg_ == __cend_)
154fc88dbd2SHoward Hinnant         return;
155c206366fSHoward Hinnant     size_t hc = hash<const void*>()(__c) % static_cast<size_t>(__cend_ - __cbeg_);
156f554add5SHoward Hinnant     __c_node* c = __cbeg_[hc];
157fc88dbd2SHoward Hinnant     if (c == nullptr)
158fc88dbd2SHoward Hinnant         return;
159f554add5SHoward Hinnant     while (c->__c_ != __c)
160f554add5SHoward Hinnant     {
161f554add5SHoward Hinnant         c = c->__next_;
162fc88dbd2SHoward Hinnant         if (c == nullptr)
163fc88dbd2SHoward Hinnant             return;
164f554add5SHoward Hinnant     }
165fc88dbd2SHoward Hinnant     __i_node* i = __insert_iterator(__i);
166f554add5SHoward Hinnant     c->__add(i);
167f554add5SHoward Hinnant     i->__c_ = c;
168f554add5SHoward Hinnant }
169f554add5SHoward Hinnant 
1701c014d75SEric Fiselier void
1711c014d75SEric Fiselier __libcpp_db::__insert_c(void* __c, __libcpp_db::_InsertConstruct *__fn)
172f554add5SHoward Hinnant {
173b3fcc67fSJonathan Roelofs #ifndef _LIBCPP_HAS_NO_THREADS
174f554add5SHoward Hinnant     WLock _(mut());
175b3fcc67fSJonathan Roelofs #endif
176c206366fSHoward Hinnant     if (__csz_ + 1 > static_cast<size_t>(__cend_ - __cbeg_))
177f554add5SHoward Hinnant     {
178c206366fSHoward Hinnant         size_t nc = __next_prime(2*static_cast<size_t>(__cend_ - __cbeg_) + 1);
179cb843f5bSLouis Dionne         __c_node** cbeg = static_cast<__c_node**>(calloc(nc, sizeof(__c_node*)));
180f554add5SHoward Hinnant         if (cbeg == nullptr)
181d437fa5cSMarshall Clow             __throw_bad_alloc();
182d437fa5cSMarshall Clow 
183f554add5SHoward Hinnant         for (__c_node** p = __cbeg_; p != __cend_; ++p)
184f554add5SHoward Hinnant         {
185f554add5SHoward Hinnant             __c_node* q = *p;
186f554add5SHoward Hinnant             while (q != nullptr)
187f554add5SHoward Hinnant             {
188f554add5SHoward Hinnant                 size_t h = hash<void*>()(q->__c_) % nc;
189f554add5SHoward Hinnant                 __c_node* r = q->__next_;
190f554add5SHoward Hinnant                 q->__next_ = cbeg[h];
191f554add5SHoward Hinnant                 cbeg[h] = q;
192f554add5SHoward Hinnant                 q = r;
193f554add5SHoward Hinnant             }
194f554add5SHoward Hinnant         }
195f554add5SHoward Hinnant         free(__cbeg_);
196f554add5SHoward Hinnant         __cbeg_ = cbeg;
197f554add5SHoward Hinnant         __cend_ = __cbeg_ + nc;
198f554add5SHoward Hinnant     }
199c206366fSHoward Hinnant     size_t hc = hash<void*>()(__c) % static_cast<size_t>(__cend_ - __cbeg_);
200f554add5SHoward Hinnant     __c_node* p = __cbeg_[hc];
2011c014d75SEric Fiselier     void *buf = malloc(sizeof(__c_node));
2021c014d75SEric Fiselier     if (buf == nullptr)
203d437fa5cSMarshall Clow       __throw_bad_alloc();
2041c014d75SEric Fiselier     __cbeg_[hc] = __fn(buf, __c, p);
205d437fa5cSMarshall Clow 
206f554add5SHoward Hinnant     ++__csz_;
207f554add5SHoward Hinnant }
208f554add5SHoward Hinnant 
209f554add5SHoward Hinnant void
210f554add5SHoward Hinnant __libcpp_db::__erase_i(void* __i)
211f554add5SHoward Hinnant {
212b3fcc67fSJonathan Roelofs #ifndef _LIBCPP_HAS_NO_THREADS
213f554add5SHoward Hinnant     WLock _(mut());
214b3fcc67fSJonathan Roelofs #endif
215f554add5SHoward Hinnant     if (__ibeg_ != __iend_)
216f554add5SHoward Hinnant     {
217c206366fSHoward Hinnant         size_t hi = hash<void*>()(__i) % static_cast<size_t>(__iend_ - __ibeg_);
218f554add5SHoward Hinnant         __i_node* p = __ibeg_[hi];
219f554add5SHoward Hinnant         if (p != nullptr)
220f554add5SHoward Hinnant         {
221f554add5SHoward Hinnant             __i_node* q = nullptr;
222f554add5SHoward Hinnant             while (p->__i_ != __i)
223f554add5SHoward Hinnant             {
224f554add5SHoward Hinnant                 q = p;
225f554add5SHoward Hinnant                 p = p->__next_;
226f554add5SHoward Hinnant                 if (p == nullptr)
227f554add5SHoward Hinnant                     return;
228f554add5SHoward Hinnant             }
229f554add5SHoward Hinnant             if (q == nullptr)
230f554add5SHoward Hinnant                 __ibeg_[hi] = p->__next_;
231f554add5SHoward Hinnant             else
232f554add5SHoward Hinnant                 q->__next_ = p->__next_;
233f554add5SHoward Hinnant             __c_node* c = p->__c_;
234f554add5SHoward Hinnant             --__isz_;
235f554add5SHoward Hinnant             if (c != nullptr)
236f554add5SHoward Hinnant                 c->__remove(p);
23761bff619SEric Fiselier             free(p);
238f554add5SHoward Hinnant         }
239f554add5SHoward Hinnant     }
240f554add5SHoward Hinnant }
241f554add5SHoward Hinnant 
242f554add5SHoward Hinnant void
243f554add5SHoward Hinnant __libcpp_db::__invalidate_all(void* __c)
244f554add5SHoward Hinnant {
245b3fcc67fSJonathan Roelofs #ifndef _LIBCPP_HAS_NO_THREADS
246f554add5SHoward Hinnant     WLock _(mut());
247b3fcc67fSJonathan Roelofs #endif
248fc88dbd2SHoward Hinnant     if (__cend_ != __cbeg_)
249fc88dbd2SHoward Hinnant     {
250c206366fSHoward Hinnant         size_t hc = hash<void*>()(__c) % static_cast<size_t>(__cend_ - __cbeg_);
251f554add5SHoward Hinnant         __c_node* p = __cbeg_[hc];
252fc88dbd2SHoward Hinnant         if (p == nullptr)
253fc88dbd2SHoward Hinnant             return;
254f554add5SHoward Hinnant         while (p->__c_ != __c)
255f554add5SHoward Hinnant         {
256f554add5SHoward Hinnant             p = p->__next_;
257fc88dbd2SHoward Hinnant             if (p == nullptr)
258fc88dbd2SHoward Hinnant                 return;
259f554add5SHoward Hinnant         }
260f554add5SHoward Hinnant         while (p->end_ != p->beg_)
261f554add5SHoward Hinnant         {
262f554add5SHoward Hinnant             --p->end_;
263f554add5SHoward Hinnant             (*p->end_)->__c_ = nullptr;
264f554add5SHoward Hinnant         }
265f554add5SHoward Hinnant     }
266fc88dbd2SHoward Hinnant }
267f554add5SHoward Hinnant 
268f554add5SHoward Hinnant __c_node*
269f554add5SHoward Hinnant __libcpp_db::__find_c_and_lock(void* __c) const
270f554add5SHoward Hinnant {
271b3fcc67fSJonathan Roelofs #ifndef _LIBCPP_HAS_NO_THREADS
272f554add5SHoward Hinnant     mut().lock();
273b3fcc67fSJonathan Roelofs #endif
274fc88dbd2SHoward Hinnant     if (__cend_ == __cbeg_)
275fc88dbd2SHoward Hinnant     {
276b3fcc67fSJonathan Roelofs #ifndef _LIBCPP_HAS_NO_THREADS
277fc88dbd2SHoward Hinnant         mut().unlock();
278b3fcc67fSJonathan Roelofs #endif
279fc88dbd2SHoward Hinnant         return nullptr;
280fc88dbd2SHoward Hinnant     }
281c206366fSHoward Hinnant     size_t hc = hash<void*>()(__c) % static_cast<size_t>(__cend_ - __cbeg_);
282f554add5SHoward Hinnant     __c_node* p = __cbeg_[hc];
283fc88dbd2SHoward Hinnant     if (p == nullptr)
284fc88dbd2SHoward Hinnant     {
285b3fcc67fSJonathan Roelofs #ifndef _LIBCPP_HAS_NO_THREADS
286fc88dbd2SHoward Hinnant         mut().unlock();
287b3fcc67fSJonathan Roelofs #endif
288fc88dbd2SHoward Hinnant         return nullptr;
289fc88dbd2SHoward Hinnant     }
290f554add5SHoward Hinnant     while (p->__c_ != __c)
291f554add5SHoward Hinnant     {
292f554add5SHoward Hinnant         p = p->__next_;
293fc88dbd2SHoward Hinnant         if (p == nullptr)
294fc88dbd2SHoward Hinnant         {
295b3fcc67fSJonathan Roelofs #ifndef _LIBCPP_HAS_NO_THREADS
296fc88dbd2SHoward Hinnant             mut().unlock();
297b3fcc67fSJonathan Roelofs #endif
298fc88dbd2SHoward Hinnant             return nullptr;
299fc88dbd2SHoward Hinnant         }
300f554add5SHoward Hinnant     }
301f554add5SHoward Hinnant     return p;
302f554add5SHoward Hinnant }
303f554add5SHoward Hinnant 
304920b56caSHoward Hinnant __c_node*
305920b56caSHoward Hinnant __libcpp_db::__find_c(void* __c) const
306920b56caSHoward Hinnant {
307c206366fSHoward Hinnant     size_t hc = hash<void*>()(__c) % static_cast<size_t>(__cend_ - __cbeg_);
308920b56caSHoward Hinnant     __c_node* p = __cbeg_[hc];
309920b56caSHoward Hinnant     _LIBCPP_ASSERT(p != nullptr, "debug mode internal logic error __find_c A");
310920b56caSHoward Hinnant     while (p->__c_ != __c)
311920b56caSHoward Hinnant     {
312920b56caSHoward Hinnant         p = p->__next_;
313920b56caSHoward Hinnant         _LIBCPP_ASSERT(p != nullptr, "debug mode internal logic error __find_c B");
314920b56caSHoward Hinnant     }
315920b56caSHoward Hinnant     return p;
316920b56caSHoward Hinnant }
317920b56caSHoward Hinnant 
318f554add5SHoward Hinnant void
319f554add5SHoward Hinnant __libcpp_db::unlock() const
320f554add5SHoward Hinnant {
321b3fcc67fSJonathan Roelofs #ifndef _LIBCPP_HAS_NO_THREADS
322f554add5SHoward Hinnant     mut().unlock();
323b3fcc67fSJonathan Roelofs #endif
324f554add5SHoward Hinnant }
325f554add5SHoward Hinnant 
326f554add5SHoward Hinnant void
327f554add5SHoward Hinnant __libcpp_db::__erase_c(void* __c)
328f554add5SHoward Hinnant {
329b3fcc67fSJonathan Roelofs #ifndef _LIBCPP_HAS_NO_THREADS
330f554add5SHoward Hinnant     WLock _(mut());
331b3fcc67fSJonathan Roelofs #endif
332fc88dbd2SHoward Hinnant     if (__cend_ != __cbeg_)
333fc88dbd2SHoward Hinnant     {
334c206366fSHoward Hinnant         size_t hc = hash<void*>()(__c) % static_cast<size_t>(__cend_ - __cbeg_);
335f554add5SHoward Hinnant         __c_node* p = __cbeg_[hc];
336fc88dbd2SHoward Hinnant         if (p == nullptr)
337fc88dbd2SHoward Hinnant             return;
338f554add5SHoward Hinnant         __c_node* q = nullptr;
339f554add5SHoward Hinnant         _LIBCPP_ASSERT(p != nullptr, "debug mode internal logic error __erase_c A");
340f554add5SHoward Hinnant         while (p->__c_ != __c)
341f554add5SHoward Hinnant         {
342f554add5SHoward Hinnant             q = p;
343f554add5SHoward Hinnant             p = p->__next_;
344fc88dbd2SHoward Hinnant             if (p == nullptr)
345fc88dbd2SHoward Hinnant                 return;
346f554add5SHoward Hinnant             _LIBCPP_ASSERT(p != nullptr, "debug mode internal logic error __erase_c B");
347f554add5SHoward Hinnant         }
348f554add5SHoward Hinnant         if (q == nullptr)
349f554add5SHoward Hinnant             __cbeg_[hc] = p->__next_;
350f554add5SHoward Hinnant         else
351f554add5SHoward Hinnant             q->__next_ = p->__next_;
352f554add5SHoward Hinnant         while (p->end_ != p->beg_)
353f554add5SHoward Hinnant         {
354f554add5SHoward Hinnant             --p->end_;
355f554add5SHoward Hinnant             (*p->end_)->__c_ = nullptr;
356f554add5SHoward Hinnant         }
357f554add5SHoward Hinnant         free(p->beg_);
358f554add5SHoward Hinnant         free(p);
359f554add5SHoward Hinnant         --__csz_;
360f554add5SHoward Hinnant     }
361fc88dbd2SHoward Hinnant }
362f554add5SHoward Hinnant 
363f554add5SHoward Hinnant void
364f554add5SHoward Hinnant __libcpp_db::__iterator_copy(void* __i, const void* __i0)
365f554add5SHoward Hinnant {
366b3fcc67fSJonathan Roelofs #ifndef _LIBCPP_HAS_NO_THREADS
367f554add5SHoward Hinnant     WLock _(mut());
368b3fcc67fSJonathan Roelofs #endif
369f554add5SHoward Hinnant     __i_node* i = __find_iterator(__i);
370f554add5SHoward Hinnant     __i_node* i0 = __find_iterator(__i0);
371f554add5SHoward Hinnant     __c_node* c0 = i0 != nullptr ? i0->__c_ : nullptr;
372f7509231SHoward Hinnant     if (i == nullptr && i0 != nullptr)
373f554add5SHoward Hinnant         i = __insert_iterator(__i);
374f554add5SHoward Hinnant     __c_node* c = i != nullptr ? i->__c_ : nullptr;
375f554add5SHoward Hinnant     if (c != c0)
376f554add5SHoward Hinnant     {
377f554add5SHoward Hinnant         if (c != nullptr)
378f554add5SHoward Hinnant             c->__remove(i);
379f554add5SHoward Hinnant         if (i != nullptr)
380f554add5SHoward Hinnant         {
381f554add5SHoward Hinnant             i->__c_ = nullptr;
382f554add5SHoward Hinnant             if (c0 != nullptr)
383f554add5SHoward Hinnant             {
384f554add5SHoward Hinnant                 i->__c_ = c0;
385f554add5SHoward Hinnant                 i->__c_->__add(i);
386f554add5SHoward Hinnant             }
387f554add5SHoward Hinnant         }
388f554add5SHoward Hinnant     }
389f554add5SHoward Hinnant }
390f554add5SHoward Hinnant 
391f554add5SHoward Hinnant bool
392f554add5SHoward Hinnant __libcpp_db::__dereferenceable(const void* __i) const
393f554add5SHoward Hinnant {
394b3fcc67fSJonathan Roelofs #ifndef _LIBCPP_HAS_NO_THREADS
395f554add5SHoward Hinnant     RLock _(mut());
396b3fcc67fSJonathan Roelofs #endif
397f554add5SHoward Hinnant     __i_node* i = __find_iterator(__i);
398f554add5SHoward Hinnant     return i != nullptr && i->__c_ != nullptr && i->__c_->__dereferenceable(__i);
399f554add5SHoward Hinnant }
400f554add5SHoward Hinnant 
401f554add5SHoward Hinnant bool
402f554add5SHoward Hinnant __libcpp_db::__decrementable(const void* __i) const
403f554add5SHoward Hinnant {
404b3fcc67fSJonathan Roelofs #ifndef _LIBCPP_HAS_NO_THREADS
405f554add5SHoward Hinnant     RLock _(mut());
406b3fcc67fSJonathan Roelofs #endif
407f554add5SHoward Hinnant     __i_node* i = __find_iterator(__i);
408f554add5SHoward Hinnant     return i != nullptr && i->__c_ != nullptr && i->__c_->__decrementable(__i);
409f554add5SHoward Hinnant }
410f554add5SHoward Hinnant 
411f554add5SHoward Hinnant bool
412f554add5SHoward Hinnant __libcpp_db::__addable(const void* __i, ptrdiff_t __n) const
413f554add5SHoward Hinnant {
414b3fcc67fSJonathan Roelofs #ifndef _LIBCPP_HAS_NO_THREADS
415f554add5SHoward Hinnant     RLock _(mut());
416b3fcc67fSJonathan Roelofs #endif
417f554add5SHoward Hinnant     __i_node* i = __find_iterator(__i);
418f554add5SHoward Hinnant     return i != nullptr && i->__c_ != nullptr && i->__c_->__addable(__i, __n);
419f554add5SHoward Hinnant }
420f554add5SHoward Hinnant 
421f554add5SHoward Hinnant bool
422f554add5SHoward Hinnant __libcpp_db::__subscriptable(const void* __i, ptrdiff_t __n) const
423f554add5SHoward Hinnant {
424b3fcc67fSJonathan Roelofs #ifndef _LIBCPP_HAS_NO_THREADS
425f554add5SHoward Hinnant     RLock _(mut());
426b3fcc67fSJonathan Roelofs #endif
427f554add5SHoward Hinnant     __i_node* i = __find_iterator(__i);
428f554add5SHoward Hinnant     return i != nullptr && i->__c_ != nullptr && i->__c_->__subscriptable(__i, __n);
429f554add5SHoward Hinnant }
430f554add5SHoward Hinnant 
431f554add5SHoward Hinnant bool
43242a3046eSHoward Hinnant __libcpp_db::__less_than_comparable(const void* __i, const void* __j) const
433f554add5SHoward Hinnant {
434b3fcc67fSJonathan Roelofs #ifndef _LIBCPP_HAS_NO_THREADS
435f554add5SHoward Hinnant     RLock _(mut());
436b3fcc67fSJonathan Roelofs #endif
437f554add5SHoward Hinnant     __i_node* i = __find_iterator(__i);
438f554add5SHoward Hinnant     __i_node* j = __find_iterator(__j);
439f554add5SHoward Hinnant     __c_node* ci = i != nullptr ? i->__c_ : nullptr;
440f554add5SHoward Hinnant     __c_node* cj = j != nullptr ? j->__c_ : nullptr;
441bbc6893bSArthur O'Dwyer     return ci == cj;
442f554add5SHoward Hinnant }
443f554add5SHoward Hinnant 
444f554add5SHoward Hinnant void
445f554add5SHoward Hinnant __libcpp_db::swap(void* c1, void* c2)
446f554add5SHoward Hinnant {
447b3fcc67fSJonathan Roelofs #ifndef _LIBCPP_HAS_NO_THREADS
448f554add5SHoward Hinnant     WLock _(mut());
449b3fcc67fSJonathan Roelofs #endif
450c206366fSHoward Hinnant     size_t hc = hash<void*>()(c1) % static_cast<size_t>(__cend_ - __cbeg_);
451f554add5SHoward Hinnant     __c_node* p1 = __cbeg_[hc];
452f554add5SHoward Hinnant     _LIBCPP_ASSERT(p1 != nullptr, "debug mode internal logic error swap A");
453f554add5SHoward Hinnant     while (p1->__c_ != c1)
454f554add5SHoward Hinnant     {
455f554add5SHoward Hinnant         p1 = p1->__next_;
456f554add5SHoward Hinnant         _LIBCPP_ASSERT(p1 != nullptr, "debug mode internal logic error swap B");
457f554add5SHoward Hinnant     }
458c206366fSHoward Hinnant     hc = hash<void*>()(c2) % static_cast<size_t>(__cend_ - __cbeg_);
459f554add5SHoward Hinnant     __c_node* p2 = __cbeg_[hc];
460f554add5SHoward Hinnant     _LIBCPP_ASSERT(p2 != nullptr, "debug mode internal logic error swap C");
461f554add5SHoward Hinnant     while (p2->__c_ != c2)
462f554add5SHoward Hinnant     {
463f554add5SHoward Hinnant         p2 = p2->__next_;
464f554add5SHoward Hinnant         _LIBCPP_ASSERT(p2 != nullptr, "debug mode internal logic error swap D");
465f554add5SHoward Hinnant     }
466f554add5SHoward Hinnant     std::swap(p1->beg_, p2->beg_);
467f554add5SHoward Hinnant     std::swap(p1->end_, p2->end_);
468f554add5SHoward Hinnant     std::swap(p1->cap_, p2->cap_);
469f554add5SHoward Hinnant     for (__i_node** p = p1->beg_; p != p1->end_; ++p)
470f554add5SHoward Hinnant         (*p)->__c_ = p1;
471f554add5SHoward Hinnant     for (__i_node** p = p2->beg_; p != p2->end_; ++p)
472f554add5SHoward Hinnant         (*p)->__c_ = p2;
473f554add5SHoward Hinnant }
474f554add5SHoward Hinnant 
475c36bfc49SHoward Hinnant void
476c36bfc49SHoward Hinnant __libcpp_db::__insert_i(void* __i)
477c36bfc49SHoward Hinnant {
478b3fcc67fSJonathan Roelofs #ifndef _LIBCPP_HAS_NO_THREADS
479c36bfc49SHoward Hinnant     WLock _(mut());
480b3fcc67fSJonathan Roelofs #endif
481c36bfc49SHoward Hinnant     __insert_iterator(__i);
482c36bfc49SHoward Hinnant }
483c36bfc49SHoward Hinnant 
484920b56caSHoward Hinnant void
485920b56caSHoward Hinnant __c_node::__add(__i_node* i)
486920b56caSHoward Hinnant {
487920b56caSHoward Hinnant     if (end_ == cap_)
488920b56caSHoward Hinnant     {
489c206366fSHoward Hinnant         size_t nc = 2*static_cast<size_t>(cap_ - beg_);
490920b56caSHoward Hinnant         if (nc == 0)
491920b56caSHoward Hinnant             nc = 1;
49285ad6c99SJoerg Sonnenberger         __i_node** beg =
49385ad6c99SJoerg Sonnenberger            static_cast<__i_node**>(malloc(nc * sizeof(__i_node*)));
494920b56caSHoward Hinnant         if (beg == nullptr)
495d437fa5cSMarshall Clow             __throw_bad_alloc();
496d437fa5cSMarshall Clow 
497920b56caSHoward Hinnant         if (nc > 1)
498920b56caSHoward Hinnant             memcpy(beg, beg_, nc/2*sizeof(__i_node*));
499920b56caSHoward Hinnant         free(beg_);
500920b56caSHoward Hinnant         beg_ = beg;
501920b56caSHoward Hinnant         end_ = beg_ + nc/2;
502920b56caSHoward Hinnant         cap_ = beg_ + nc;
503920b56caSHoward Hinnant     }
504920b56caSHoward Hinnant     *end_++ = i;
505920b56caSHoward Hinnant }
506920b56caSHoward Hinnant 
507f554add5SHoward Hinnant // private api
508f554add5SHoward Hinnant 
509f554add5SHoward Hinnant _LIBCPP_HIDDEN
510f554add5SHoward Hinnant __i_node*
511f554add5SHoward Hinnant __libcpp_db::__insert_iterator(void* __i)
512f554add5SHoward Hinnant {
513c206366fSHoward Hinnant     if (__isz_ + 1 > static_cast<size_t>(__iend_ - __ibeg_))
514f554add5SHoward Hinnant     {
515c206366fSHoward Hinnant         size_t nc = __next_prime(2*static_cast<size_t>(__iend_ - __ibeg_) + 1);
516cb843f5bSLouis Dionne         __i_node** ibeg = static_cast<__i_node**>(calloc(nc, sizeof(__i_node*)));
517f554add5SHoward Hinnant         if (ibeg == nullptr)
518d437fa5cSMarshall Clow             __throw_bad_alloc();
519d437fa5cSMarshall Clow 
520f554add5SHoward Hinnant         for (__i_node** p = __ibeg_; p != __iend_; ++p)
521f554add5SHoward Hinnant         {
522f554add5SHoward Hinnant             __i_node* q = *p;
523f554add5SHoward Hinnant             while (q != nullptr)
524f554add5SHoward Hinnant             {
525f554add5SHoward Hinnant                 size_t h = hash<void*>()(q->__i_) % nc;
526f554add5SHoward Hinnant                 __i_node* r = q->__next_;
527f554add5SHoward Hinnant                 q->__next_ = ibeg[h];
528f554add5SHoward Hinnant                 ibeg[h] = q;
529f554add5SHoward Hinnant                 q = r;
530f554add5SHoward Hinnant             }
531f554add5SHoward Hinnant         }
532f554add5SHoward Hinnant         free(__ibeg_);
533f554add5SHoward Hinnant         __ibeg_ = ibeg;
534f554add5SHoward Hinnant         __iend_ = __ibeg_ + nc;
535f554add5SHoward Hinnant     }
536c206366fSHoward Hinnant     size_t hi = hash<void*>()(__i) % static_cast<size_t>(__iend_ - __ibeg_);
537f554add5SHoward Hinnant     __i_node* p = __ibeg_[hi];
53885ad6c99SJoerg Sonnenberger     __i_node* r = __ibeg_[hi] =
53985ad6c99SJoerg Sonnenberger       static_cast<__i_node*>(malloc(sizeof(__i_node)));
540f554add5SHoward Hinnant     if (r == nullptr)
541d437fa5cSMarshall Clow         __throw_bad_alloc();
542d437fa5cSMarshall Clow 
543f554add5SHoward Hinnant     ::new(r) __i_node(__i, p, nullptr);
544f554add5SHoward Hinnant     ++__isz_;
545f554add5SHoward Hinnant     return r;
546f554add5SHoward Hinnant }
547f554add5SHoward Hinnant 
548f554add5SHoward Hinnant _LIBCPP_HIDDEN
549f554add5SHoward Hinnant __i_node*
550f554add5SHoward Hinnant __libcpp_db::__find_iterator(const void* __i) const
551f554add5SHoward Hinnant {
552f554add5SHoward Hinnant     __i_node* r = nullptr;
553f554add5SHoward Hinnant     if (__ibeg_ != __iend_)
554f554add5SHoward Hinnant     {
555c206366fSHoward Hinnant         size_t h = hash<const void*>()(__i) % static_cast<size_t>(__iend_ - __ibeg_);
556f554add5SHoward Hinnant         for (__i_node* nd = __ibeg_[h]; nd != nullptr; nd = nd->__next_)
557f554add5SHoward Hinnant         {
558f554add5SHoward Hinnant             if (nd->__i_ == __i)
559f554add5SHoward Hinnant             {
560f554add5SHoward Hinnant                 r = nd;
561f554add5SHoward Hinnant                 break;
562f554add5SHoward Hinnant             }
563f554add5SHoward Hinnant         }
564f554add5SHoward Hinnant     }
565f554add5SHoward Hinnant     return r;
566f554add5SHoward Hinnant }
567f554add5SHoward Hinnant 
568f554add5SHoward Hinnant _LIBCPP_HIDDEN
569f554add5SHoward Hinnant void
570f554add5SHoward Hinnant __c_node::__remove(__i_node* p)
571f554add5SHoward Hinnant {
572f554add5SHoward Hinnant     __i_node** r = find(beg_, end_, p);
573f554add5SHoward Hinnant     _LIBCPP_ASSERT(r != end_, "debug mode internal logic error __c_node::__remove");
574f554add5SHoward Hinnant     if (--end_ != r)
575c206366fSHoward Hinnant         memmove(r, r+1, static_cast<size_t>(end_ - r)*sizeof(__i_node*));
576f554add5SHoward Hinnant }
577f554add5SHoward Hinnant 
578f554add5SHoward Hinnant _LIBCPP_END_NAMESPACE_STD
579