1*0b57cec5SDimitry Andric //===-------------------------- debug.cpp ---------------------------------===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric 
9*0b57cec5SDimitry Andric #include "__config"
10*0b57cec5SDimitry Andric #include "__debug"
11*0b57cec5SDimitry Andric #include "functional"
12*0b57cec5SDimitry Andric #include "algorithm"
13*0b57cec5SDimitry Andric #include "string"
14*0b57cec5SDimitry Andric #include "cstdio"
15*0b57cec5SDimitry Andric #include "__hash_table"
16*0b57cec5SDimitry Andric #ifndef _LIBCPP_HAS_NO_THREADS
17*0b57cec5SDimitry Andric #include "mutex"
18480093f4SDimitry Andric #if defined(__ELF__) && defined(_LIBCPP_LINK_PTHREAD_LIB)
19*0b57cec5SDimitry Andric #pragma comment(lib, "pthread")
20*0b57cec5SDimitry Andric #endif
21*0b57cec5SDimitry Andric #endif
22*0b57cec5SDimitry Andric 
23*0b57cec5SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD
24*0b57cec5SDimitry Andric 
25*0b57cec5SDimitry Andric std::string __libcpp_debug_info::what() const {
26*0b57cec5SDimitry Andric   string msg = __file_;
27*0b57cec5SDimitry Andric   msg += ":" + to_string(__line_) + ": _LIBCPP_ASSERT '";
28*0b57cec5SDimitry Andric   msg += __pred_;
29*0b57cec5SDimitry Andric   msg += "' failed. ";
30*0b57cec5SDimitry Andric   msg += __msg_;
31*0b57cec5SDimitry Andric   return msg;
32*0b57cec5SDimitry Andric }
33*0b57cec5SDimitry Andric _LIBCPP_NORETURN void __libcpp_abort_debug_function(__libcpp_debug_info const& info) {
34*0b57cec5SDimitry Andric     std::fprintf(stderr, "%s\n", info.what().c_str());
35*0b57cec5SDimitry Andric     std::abort();
36*0b57cec5SDimitry Andric }
37*0b57cec5SDimitry Andric 
38*0b57cec5SDimitry Andric _LIBCPP_SAFE_STATIC __libcpp_debug_function_type
39*0b57cec5SDimitry Andric     __libcpp_debug_function = __libcpp_abort_debug_function;
40*0b57cec5SDimitry Andric 
41*0b57cec5SDimitry Andric bool __libcpp_set_debug_function(__libcpp_debug_function_type __func) {
42*0b57cec5SDimitry Andric   __libcpp_debug_function = __func;
43*0b57cec5SDimitry Andric   return true;
44*0b57cec5SDimitry Andric }
45*0b57cec5SDimitry Andric 
46*0b57cec5SDimitry Andric _LIBCPP_FUNC_VIS
47*0b57cec5SDimitry Andric __libcpp_db*
48*0b57cec5SDimitry Andric __get_db()
49*0b57cec5SDimitry Andric {
50*0b57cec5SDimitry Andric     static _LIBCPP_NO_DESTROY __libcpp_db db;
51*0b57cec5SDimitry Andric     return &db;
52*0b57cec5SDimitry Andric }
53*0b57cec5SDimitry Andric 
54*0b57cec5SDimitry Andric _LIBCPP_FUNC_VIS
55*0b57cec5SDimitry Andric const __libcpp_db*
56*0b57cec5SDimitry Andric __get_const_db()
57*0b57cec5SDimitry Andric {
58*0b57cec5SDimitry Andric     return __get_db();
59*0b57cec5SDimitry Andric }
60*0b57cec5SDimitry Andric 
61*0b57cec5SDimitry Andric namespace
62*0b57cec5SDimitry Andric {
63*0b57cec5SDimitry Andric 
64*0b57cec5SDimitry Andric #ifndef _LIBCPP_HAS_NO_THREADS
65*0b57cec5SDimitry Andric typedef mutex mutex_type;
66*0b57cec5SDimitry Andric typedef lock_guard<mutex_type> WLock;
67*0b57cec5SDimitry Andric typedef lock_guard<mutex_type> RLock;
68*0b57cec5SDimitry Andric 
69*0b57cec5SDimitry Andric mutex_type&
70*0b57cec5SDimitry Andric mut()
71*0b57cec5SDimitry Andric {
72*0b57cec5SDimitry Andric     static _LIBCPP_NO_DESTROY mutex_type m;
73*0b57cec5SDimitry Andric     return m;
74*0b57cec5SDimitry Andric }
75*0b57cec5SDimitry Andric #endif // !_LIBCPP_HAS_NO_THREADS
76*0b57cec5SDimitry Andric 
77*0b57cec5SDimitry Andric }  // unnamed namespace
78*0b57cec5SDimitry Andric 
79*0b57cec5SDimitry Andric __i_node::~__i_node()
80*0b57cec5SDimitry Andric {
81*0b57cec5SDimitry Andric     if (__next_)
82*0b57cec5SDimitry Andric     {
83*0b57cec5SDimitry Andric         __next_->~__i_node();
84*0b57cec5SDimitry Andric         free(__next_);
85*0b57cec5SDimitry Andric     }
86*0b57cec5SDimitry Andric }
87*0b57cec5SDimitry Andric 
88*0b57cec5SDimitry Andric __c_node::~__c_node()
89*0b57cec5SDimitry Andric {
90*0b57cec5SDimitry Andric     free(beg_);
91*0b57cec5SDimitry Andric     if (__next_)
92*0b57cec5SDimitry Andric     {
93*0b57cec5SDimitry Andric         __next_->~__c_node();
94*0b57cec5SDimitry Andric         free(__next_);
95*0b57cec5SDimitry Andric     }
96*0b57cec5SDimitry Andric }
97*0b57cec5SDimitry Andric 
98*0b57cec5SDimitry Andric __libcpp_db::__libcpp_db()
99*0b57cec5SDimitry Andric     : __cbeg_(nullptr),
100*0b57cec5SDimitry Andric       __cend_(nullptr),
101*0b57cec5SDimitry Andric       __csz_(0),
102*0b57cec5SDimitry Andric       __ibeg_(nullptr),
103*0b57cec5SDimitry Andric       __iend_(nullptr),
104*0b57cec5SDimitry Andric       __isz_(0)
105*0b57cec5SDimitry Andric {
106*0b57cec5SDimitry Andric }
107*0b57cec5SDimitry Andric 
108*0b57cec5SDimitry Andric __libcpp_db::~__libcpp_db()
109*0b57cec5SDimitry Andric {
110*0b57cec5SDimitry Andric     if (__cbeg_)
111*0b57cec5SDimitry Andric     {
112*0b57cec5SDimitry Andric         for (__c_node** p = __cbeg_; p != __cend_; ++p)
113*0b57cec5SDimitry Andric         {
114*0b57cec5SDimitry Andric             if (*p != nullptr)
115*0b57cec5SDimitry Andric             {
116*0b57cec5SDimitry Andric                 (*p)->~__c_node();
117*0b57cec5SDimitry Andric                 free(*p);
118*0b57cec5SDimitry Andric             }
119*0b57cec5SDimitry Andric         }
120*0b57cec5SDimitry Andric         free(__cbeg_);
121*0b57cec5SDimitry Andric     }
122*0b57cec5SDimitry Andric     if (__ibeg_)
123*0b57cec5SDimitry Andric     {
124*0b57cec5SDimitry Andric         for (__i_node** p = __ibeg_; p != __iend_; ++p)
125*0b57cec5SDimitry Andric         {
126*0b57cec5SDimitry Andric             if (*p != nullptr)
127*0b57cec5SDimitry Andric             {
128*0b57cec5SDimitry Andric                 (*p)->~__i_node();
129*0b57cec5SDimitry Andric                 free(*p);
130*0b57cec5SDimitry Andric             }
131*0b57cec5SDimitry Andric         }
132*0b57cec5SDimitry Andric         free(__ibeg_);
133*0b57cec5SDimitry Andric     }
134*0b57cec5SDimitry Andric }
135*0b57cec5SDimitry Andric 
136*0b57cec5SDimitry Andric void*
137*0b57cec5SDimitry Andric __libcpp_db::__find_c_from_i(void* __i) const
138*0b57cec5SDimitry Andric {
139*0b57cec5SDimitry Andric #ifndef _LIBCPP_HAS_NO_THREADS
140*0b57cec5SDimitry Andric     RLock _(mut());
141*0b57cec5SDimitry Andric #endif
142*0b57cec5SDimitry Andric     __i_node* i = __find_iterator(__i);
143*0b57cec5SDimitry Andric     _LIBCPP_ASSERT(i != nullptr, "iterator not found in debug database.");
144*0b57cec5SDimitry Andric     return i->__c_ != nullptr ? i->__c_->__c_ : nullptr;
145*0b57cec5SDimitry Andric }
146*0b57cec5SDimitry Andric 
147*0b57cec5SDimitry Andric void
148*0b57cec5SDimitry Andric __libcpp_db::__insert_ic(void* __i, const void* __c)
149*0b57cec5SDimitry Andric {
150*0b57cec5SDimitry Andric #ifndef _LIBCPP_HAS_NO_THREADS
151*0b57cec5SDimitry Andric     WLock _(mut());
152*0b57cec5SDimitry Andric #endif
153*0b57cec5SDimitry Andric     if (__cbeg_ == __cend_)
154*0b57cec5SDimitry Andric         return;
155*0b57cec5SDimitry Andric     size_t hc = hash<const void*>()(__c) % static_cast<size_t>(__cend_ - __cbeg_);
156*0b57cec5SDimitry Andric     __c_node* c = __cbeg_[hc];
157*0b57cec5SDimitry Andric     if (c == nullptr)
158*0b57cec5SDimitry Andric         return;
159*0b57cec5SDimitry Andric     while (c->__c_ != __c)
160*0b57cec5SDimitry Andric     {
161*0b57cec5SDimitry Andric         c = c->__next_;
162*0b57cec5SDimitry Andric         if (c == nullptr)
163*0b57cec5SDimitry Andric             return;
164*0b57cec5SDimitry Andric     }
165*0b57cec5SDimitry Andric     __i_node* i = __insert_iterator(__i);
166*0b57cec5SDimitry Andric     c->__add(i);
167*0b57cec5SDimitry Andric     i->__c_ = c;
168*0b57cec5SDimitry Andric }
169*0b57cec5SDimitry Andric 
170*0b57cec5SDimitry Andric void
171*0b57cec5SDimitry Andric __libcpp_db::__insert_c(void* __c, __libcpp_db::_InsertConstruct *__fn)
172*0b57cec5SDimitry Andric {
173*0b57cec5SDimitry Andric #ifndef _LIBCPP_HAS_NO_THREADS
174*0b57cec5SDimitry Andric     WLock _(mut());
175*0b57cec5SDimitry Andric #endif
176*0b57cec5SDimitry Andric     if (__csz_ + 1 > static_cast<size_t>(__cend_ - __cbeg_))
177*0b57cec5SDimitry Andric     {
178*0b57cec5SDimitry Andric         size_t nc = __next_prime(2*static_cast<size_t>(__cend_ - __cbeg_) + 1);
179*0b57cec5SDimitry Andric         __c_node** cbeg = static_cast<__c_node**>(calloc(nc, sizeof(__c_node*)));
180*0b57cec5SDimitry Andric         if (cbeg == nullptr)
181*0b57cec5SDimitry Andric             __throw_bad_alloc();
182*0b57cec5SDimitry Andric 
183*0b57cec5SDimitry Andric         for (__c_node** p = __cbeg_; p != __cend_; ++p)
184*0b57cec5SDimitry Andric         {
185*0b57cec5SDimitry Andric             __c_node* q = *p;
186*0b57cec5SDimitry Andric             while (q != nullptr)
187*0b57cec5SDimitry Andric             {
188*0b57cec5SDimitry Andric                 size_t h = hash<void*>()(q->__c_) % nc;
189*0b57cec5SDimitry Andric                 __c_node* r = q->__next_;
190*0b57cec5SDimitry Andric                 q->__next_ = cbeg[h];
191*0b57cec5SDimitry Andric                 cbeg[h] = q;
192*0b57cec5SDimitry Andric                 q = r;
193*0b57cec5SDimitry Andric             }
194*0b57cec5SDimitry Andric         }
195*0b57cec5SDimitry Andric         free(__cbeg_);
196*0b57cec5SDimitry Andric         __cbeg_ = cbeg;
197*0b57cec5SDimitry Andric         __cend_ = __cbeg_ + nc;
198*0b57cec5SDimitry Andric     }
199*0b57cec5SDimitry Andric     size_t hc = hash<void*>()(__c) % static_cast<size_t>(__cend_ - __cbeg_);
200*0b57cec5SDimitry Andric     __c_node* p = __cbeg_[hc];
201*0b57cec5SDimitry Andric     void *buf = malloc(sizeof(__c_node));
202*0b57cec5SDimitry Andric     if (buf == nullptr)
203*0b57cec5SDimitry Andric       __throw_bad_alloc();
204*0b57cec5SDimitry Andric     __cbeg_[hc] = __fn(buf, __c, p);
205*0b57cec5SDimitry Andric 
206*0b57cec5SDimitry Andric     ++__csz_;
207*0b57cec5SDimitry Andric }
208*0b57cec5SDimitry Andric 
209*0b57cec5SDimitry Andric void
210*0b57cec5SDimitry Andric __libcpp_db::__erase_i(void* __i)
211*0b57cec5SDimitry Andric {
212*0b57cec5SDimitry Andric #ifndef _LIBCPP_HAS_NO_THREADS
213*0b57cec5SDimitry Andric     WLock _(mut());
214*0b57cec5SDimitry Andric #endif
215*0b57cec5SDimitry Andric     if (__ibeg_ != __iend_)
216*0b57cec5SDimitry Andric     {
217*0b57cec5SDimitry Andric         size_t hi = hash<void*>()(__i) % static_cast<size_t>(__iend_ - __ibeg_);
218*0b57cec5SDimitry Andric         __i_node* p = __ibeg_[hi];
219*0b57cec5SDimitry Andric         if (p != nullptr)
220*0b57cec5SDimitry Andric         {
221*0b57cec5SDimitry Andric             __i_node* q = nullptr;
222*0b57cec5SDimitry Andric             while (p->__i_ != __i)
223*0b57cec5SDimitry Andric             {
224*0b57cec5SDimitry Andric                 q = p;
225*0b57cec5SDimitry Andric                 p = p->__next_;
226*0b57cec5SDimitry Andric                 if (p == nullptr)
227*0b57cec5SDimitry Andric                     return;
228*0b57cec5SDimitry Andric             }
229*0b57cec5SDimitry Andric             if (q == nullptr)
230*0b57cec5SDimitry Andric                 __ibeg_[hi] = p->__next_;
231*0b57cec5SDimitry Andric             else
232*0b57cec5SDimitry Andric                 q->__next_ = p->__next_;
233*0b57cec5SDimitry Andric             __c_node* c = p->__c_;
234*0b57cec5SDimitry Andric             --__isz_;
235*0b57cec5SDimitry Andric             if (c != nullptr)
236*0b57cec5SDimitry Andric                 c->__remove(p);
237*0b57cec5SDimitry Andric             free(p);
238*0b57cec5SDimitry Andric         }
239*0b57cec5SDimitry Andric     }
240*0b57cec5SDimitry Andric }
241*0b57cec5SDimitry Andric 
242*0b57cec5SDimitry Andric void
243*0b57cec5SDimitry Andric __libcpp_db::__invalidate_all(void* __c)
244*0b57cec5SDimitry Andric {
245*0b57cec5SDimitry Andric #ifndef _LIBCPP_HAS_NO_THREADS
246*0b57cec5SDimitry Andric     WLock _(mut());
247*0b57cec5SDimitry Andric #endif
248*0b57cec5SDimitry Andric     if (__cend_ != __cbeg_)
249*0b57cec5SDimitry Andric     {
250*0b57cec5SDimitry Andric         size_t hc = hash<void*>()(__c) % static_cast<size_t>(__cend_ - __cbeg_);
251*0b57cec5SDimitry Andric         __c_node* p = __cbeg_[hc];
252*0b57cec5SDimitry Andric         if (p == nullptr)
253*0b57cec5SDimitry Andric             return;
254*0b57cec5SDimitry Andric         while (p->__c_ != __c)
255*0b57cec5SDimitry Andric         {
256*0b57cec5SDimitry Andric             p = p->__next_;
257*0b57cec5SDimitry Andric             if (p == nullptr)
258*0b57cec5SDimitry Andric                 return;
259*0b57cec5SDimitry Andric         }
260*0b57cec5SDimitry Andric         while (p->end_ != p->beg_)
261*0b57cec5SDimitry Andric         {
262*0b57cec5SDimitry Andric             --p->end_;
263*0b57cec5SDimitry Andric             (*p->end_)->__c_ = nullptr;
264*0b57cec5SDimitry Andric         }
265*0b57cec5SDimitry Andric     }
266*0b57cec5SDimitry Andric }
267*0b57cec5SDimitry Andric 
268*0b57cec5SDimitry Andric __c_node*
269*0b57cec5SDimitry Andric __libcpp_db::__find_c_and_lock(void* __c) const
270*0b57cec5SDimitry Andric {
271*0b57cec5SDimitry Andric #ifndef _LIBCPP_HAS_NO_THREADS
272*0b57cec5SDimitry Andric     mut().lock();
273*0b57cec5SDimitry Andric #endif
274*0b57cec5SDimitry Andric     if (__cend_ == __cbeg_)
275*0b57cec5SDimitry Andric     {
276*0b57cec5SDimitry Andric #ifndef _LIBCPP_HAS_NO_THREADS
277*0b57cec5SDimitry Andric         mut().unlock();
278*0b57cec5SDimitry Andric #endif
279*0b57cec5SDimitry Andric         return nullptr;
280*0b57cec5SDimitry Andric     }
281*0b57cec5SDimitry Andric     size_t hc = hash<void*>()(__c) % static_cast<size_t>(__cend_ - __cbeg_);
282*0b57cec5SDimitry Andric     __c_node* p = __cbeg_[hc];
283*0b57cec5SDimitry Andric     if (p == nullptr)
284*0b57cec5SDimitry Andric     {
285*0b57cec5SDimitry Andric #ifndef _LIBCPP_HAS_NO_THREADS
286*0b57cec5SDimitry Andric         mut().unlock();
287*0b57cec5SDimitry Andric #endif
288*0b57cec5SDimitry Andric         return nullptr;
289*0b57cec5SDimitry Andric     }
290*0b57cec5SDimitry Andric     while (p->__c_ != __c)
291*0b57cec5SDimitry Andric     {
292*0b57cec5SDimitry Andric         p = p->__next_;
293*0b57cec5SDimitry Andric         if (p == nullptr)
294*0b57cec5SDimitry Andric         {
295*0b57cec5SDimitry Andric #ifndef _LIBCPP_HAS_NO_THREADS
296*0b57cec5SDimitry Andric             mut().unlock();
297*0b57cec5SDimitry Andric #endif
298*0b57cec5SDimitry Andric             return nullptr;
299*0b57cec5SDimitry Andric         }
300*0b57cec5SDimitry Andric     }
301*0b57cec5SDimitry Andric     return p;
302*0b57cec5SDimitry Andric }
303*0b57cec5SDimitry Andric 
304*0b57cec5SDimitry Andric __c_node*
305*0b57cec5SDimitry Andric __libcpp_db::__find_c(void* __c) const
306*0b57cec5SDimitry Andric {
307*0b57cec5SDimitry Andric     size_t hc = hash<void*>()(__c) % static_cast<size_t>(__cend_ - __cbeg_);
308*0b57cec5SDimitry Andric     __c_node* p = __cbeg_[hc];
309*0b57cec5SDimitry Andric     _LIBCPP_ASSERT(p != nullptr, "debug mode internal logic error __find_c A");
310*0b57cec5SDimitry Andric     while (p->__c_ != __c)
311*0b57cec5SDimitry Andric     {
312*0b57cec5SDimitry Andric         p = p->__next_;
313*0b57cec5SDimitry Andric         _LIBCPP_ASSERT(p != nullptr, "debug mode internal logic error __find_c B");
314*0b57cec5SDimitry Andric     }
315*0b57cec5SDimitry Andric     return p;
316*0b57cec5SDimitry Andric }
317*0b57cec5SDimitry Andric 
318*0b57cec5SDimitry Andric void
319*0b57cec5SDimitry Andric __libcpp_db::unlock() const
320*0b57cec5SDimitry Andric {
321*0b57cec5SDimitry Andric #ifndef _LIBCPP_HAS_NO_THREADS
322*0b57cec5SDimitry Andric     mut().unlock();
323*0b57cec5SDimitry Andric #endif
324*0b57cec5SDimitry Andric }
325*0b57cec5SDimitry Andric 
326*0b57cec5SDimitry Andric void
327*0b57cec5SDimitry Andric __libcpp_db::__erase_c(void* __c)
328*0b57cec5SDimitry Andric {
329*0b57cec5SDimitry Andric #ifndef _LIBCPP_HAS_NO_THREADS
330*0b57cec5SDimitry Andric     WLock _(mut());
331*0b57cec5SDimitry Andric #endif
332*0b57cec5SDimitry Andric     if (__cend_ != __cbeg_)
333*0b57cec5SDimitry Andric     {
334*0b57cec5SDimitry Andric         size_t hc = hash<void*>()(__c) % static_cast<size_t>(__cend_ - __cbeg_);
335*0b57cec5SDimitry Andric         __c_node* p = __cbeg_[hc];
336*0b57cec5SDimitry Andric         if (p == nullptr)
337*0b57cec5SDimitry Andric             return;
338*0b57cec5SDimitry Andric         __c_node* q = nullptr;
339*0b57cec5SDimitry Andric         _LIBCPP_ASSERT(p != nullptr, "debug mode internal logic error __erase_c A");
340*0b57cec5SDimitry Andric         while (p->__c_ != __c)
341*0b57cec5SDimitry Andric         {
342*0b57cec5SDimitry Andric             q = p;
343*0b57cec5SDimitry Andric             p = p->__next_;
344*0b57cec5SDimitry Andric             if (p == nullptr)
345*0b57cec5SDimitry Andric                 return;
346*0b57cec5SDimitry Andric             _LIBCPP_ASSERT(p != nullptr, "debug mode internal logic error __erase_c B");
347*0b57cec5SDimitry Andric         }
348*0b57cec5SDimitry Andric         if (q == nullptr)
349*0b57cec5SDimitry Andric             __cbeg_[hc] = p->__next_;
350*0b57cec5SDimitry Andric         else
351*0b57cec5SDimitry Andric             q->__next_ = p->__next_;
352*0b57cec5SDimitry Andric         while (p->end_ != p->beg_)
353*0b57cec5SDimitry Andric         {
354*0b57cec5SDimitry Andric             --p->end_;
355*0b57cec5SDimitry Andric             (*p->end_)->__c_ = nullptr;
356*0b57cec5SDimitry Andric         }
357*0b57cec5SDimitry Andric         free(p->beg_);
358*0b57cec5SDimitry Andric         free(p);
359*0b57cec5SDimitry Andric         --__csz_;
360*0b57cec5SDimitry Andric     }
361*0b57cec5SDimitry Andric }
362*0b57cec5SDimitry Andric 
363*0b57cec5SDimitry Andric void
364*0b57cec5SDimitry Andric __libcpp_db::__iterator_copy(void* __i, const void* __i0)
365*0b57cec5SDimitry Andric {
366*0b57cec5SDimitry Andric #ifndef _LIBCPP_HAS_NO_THREADS
367*0b57cec5SDimitry Andric     WLock _(mut());
368*0b57cec5SDimitry Andric #endif
369*0b57cec5SDimitry Andric     __i_node* i = __find_iterator(__i);
370*0b57cec5SDimitry Andric     __i_node* i0 = __find_iterator(__i0);
371*0b57cec5SDimitry Andric     __c_node* c0 = i0 != nullptr ? i0->__c_ : nullptr;
372*0b57cec5SDimitry Andric     if (i == nullptr && i0 != nullptr)
373*0b57cec5SDimitry Andric         i = __insert_iterator(__i);
374*0b57cec5SDimitry Andric     __c_node* c = i != nullptr ? i->__c_ : nullptr;
375*0b57cec5SDimitry Andric     if (c != c0)
376*0b57cec5SDimitry Andric     {
377*0b57cec5SDimitry Andric         if (c != nullptr)
378*0b57cec5SDimitry Andric             c->__remove(i);
379*0b57cec5SDimitry Andric         if (i != nullptr)
380*0b57cec5SDimitry Andric         {
381*0b57cec5SDimitry Andric             i->__c_ = nullptr;
382*0b57cec5SDimitry Andric             if (c0 != nullptr)
383*0b57cec5SDimitry Andric             {
384*0b57cec5SDimitry Andric                 i->__c_ = c0;
385*0b57cec5SDimitry Andric                 i->__c_->__add(i);
386*0b57cec5SDimitry Andric             }
387*0b57cec5SDimitry Andric         }
388*0b57cec5SDimitry Andric     }
389*0b57cec5SDimitry Andric }
390*0b57cec5SDimitry Andric 
391*0b57cec5SDimitry Andric bool
392*0b57cec5SDimitry Andric __libcpp_db::__dereferenceable(const void* __i) const
393*0b57cec5SDimitry Andric {
394*0b57cec5SDimitry Andric #ifndef _LIBCPP_HAS_NO_THREADS
395*0b57cec5SDimitry Andric     RLock _(mut());
396*0b57cec5SDimitry Andric #endif
397*0b57cec5SDimitry Andric     __i_node* i = __find_iterator(__i);
398*0b57cec5SDimitry Andric     return i != nullptr && i->__c_ != nullptr && i->__c_->__dereferenceable(__i);
399*0b57cec5SDimitry Andric }
400*0b57cec5SDimitry Andric 
401*0b57cec5SDimitry Andric bool
402*0b57cec5SDimitry Andric __libcpp_db::__decrementable(const void* __i) const
403*0b57cec5SDimitry Andric {
404*0b57cec5SDimitry Andric #ifndef _LIBCPP_HAS_NO_THREADS
405*0b57cec5SDimitry Andric     RLock _(mut());
406*0b57cec5SDimitry Andric #endif
407*0b57cec5SDimitry Andric     __i_node* i = __find_iterator(__i);
408*0b57cec5SDimitry Andric     return i != nullptr && i->__c_ != nullptr && i->__c_->__decrementable(__i);
409*0b57cec5SDimitry Andric }
410*0b57cec5SDimitry Andric 
411*0b57cec5SDimitry Andric bool
412*0b57cec5SDimitry Andric __libcpp_db::__addable(const void* __i, ptrdiff_t __n) const
413*0b57cec5SDimitry Andric {
414*0b57cec5SDimitry Andric #ifndef _LIBCPP_HAS_NO_THREADS
415*0b57cec5SDimitry Andric     RLock _(mut());
416*0b57cec5SDimitry Andric #endif
417*0b57cec5SDimitry Andric     __i_node* i = __find_iterator(__i);
418*0b57cec5SDimitry Andric     return i != nullptr && i->__c_ != nullptr && i->__c_->__addable(__i, __n);
419*0b57cec5SDimitry Andric }
420*0b57cec5SDimitry Andric 
421*0b57cec5SDimitry Andric bool
422*0b57cec5SDimitry Andric __libcpp_db::__subscriptable(const void* __i, ptrdiff_t __n) const
423*0b57cec5SDimitry Andric {
424*0b57cec5SDimitry Andric #ifndef _LIBCPP_HAS_NO_THREADS
425*0b57cec5SDimitry Andric     RLock _(mut());
426*0b57cec5SDimitry Andric #endif
427*0b57cec5SDimitry Andric     __i_node* i = __find_iterator(__i);
428*0b57cec5SDimitry Andric     return i != nullptr && i->__c_ != nullptr && i->__c_->__subscriptable(__i, __n);
429*0b57cec5SDimitry Andric }
430*0b57cec5SDimitry Andric 
431*0b57cec5SDimitry Andric bool
432*0b57cec5SDimitry Andric __libcpp_db::__less_than_comparable(const void* __i, const void* __j) const
433*0b57cec5SDimitry Andric {
434*0b57cec5SDimitry Andric #ifndef _LIBCPP_HAS_NO_THREADS
435*0b57cec5SDimitry Andric     RLock _(mut());
436*0b57cec5SDimitry Andric #endif
437*0b57cec5SDimitry Andric     __i_node* i = __find_iterator(__i);
438*0b57cec5SDimitry Andric     __i_node* j = __find_iterator(__j);
439*0b57cec5SDimitry Andric     __c_node* ci = i != nullptr ? i->__c_ : nullptr;
440*0b57cec5SDimitry Andric     __c_node* cj = j != nullptr ? j->__c_ : nullptr;
441*0b57cec5SDimitry Andric     return ci != nullptr && ci == cj;
442*0b57cec5SDimitry Andric }
443*0b57cec5SDimitry Andric 
444*0b57cec5SDimitry Andric void
445*0b57cec5SDimitry Andric __libcpp_db::swap(void* c1, void* c2)
446*0b57cec5SDimitry Andric {
447*0b57cec5SDimitry Andric #ifndef _LIBCPP_HAS_NO_THREADS
448*0b57cec5SDimitry Andric     WLock _(mut());
449*0b57cec5SDimitry Andric #endif
450*0b57cec5SDimitry Andric     size_t hc = hash<void*>()(c1) % static_cast<size_t>(__cend_ - __cbeg_);
451*0b57cec5SDimitry Andric     __c_node* p1 = __cbeg_[hc];
452*0b57cec5SDimitry Andric     _LIBCPP_ASSERT(p1 != nullptr, "debug mode internal logic error swap A");
453*0b57cec5SDimitry Andric     while (p1->__c_ != c1)
454*0b57cec5SDimitry Andric     {
455*0b57cec5SDimitry Andric         p1 = p1->__next_;
456*0b57cec5SDimitry Andric         _LIBCPP_ASSERT(p1 != nullptr, "debug mode internal logic error swap B");
457*0b57cec5SDimitry Andric     }
458*0b57cec5SDimitry Andric     hc = hash<void*>()(c2) % static_cast<size_t>(__cend_ - __cbeg_);
459*0b57cec5SDimitry Andric     __c_node* p2 = __cbeg_[hc];
460*0b57cec5SDimitry Andric     _LIBCPP_ASSERT(p2 != nullptr, "debug mode internal logic error swap C");
461*0b57cec5SDimitry Andric     while (p2->__c_ != c2)
462*0b57cec5SDimitry Andric     {
463*0b57cec5SDimitry Andric         p2 = p2->__next_;
464*0b57cec5SDimitry Andric         _LIBCPP_ASSERT(p2 != nullptr, "debug mode internal logic error swap D");
465*0b57cec5SDimitry Andric     }
466*0b57cec5SDimitry Andric     std::swap(p1->beg_, p2->beg_);
467*0b57cec5SDimitry Andric     std::swap(p1->end_, p2->end_);
468*0b57cec5SDimitry Andric     std::swap(p1->cap_, p2->cap_);
469*0b57cec5SDimitry Andric     for (__i_node** p = p1->beg_; p != p1->end_; ++p)
470*0b57cec5SDimitry Andric         (*p)->__c_ = p1;
471*0b57cec5SDimitry Andric     for (__i_node** p = p2->beg_; p != p2->end_; ++p)
472*0b57cec5SDimitry Andric         (*p)->__c_ = p2;
473*0b57cec5SDimitry Andric }
474*0b57cec5SDimitry Andric 
475*0b57cec5SDimitry Andric void
476*0b57cec5SDimitry Andric __libcpp_db::__insert_i(void* __i)
477*0b57cec5SDimitry Andric {
478*0b57cec5SDimitry Andric #ifndef _LIBCPP_HAS_NO_THREADS
479*0b57cec5SDimitry Andric     WLock _(mut());
480*0b57cec5SDimitry Andric #endif
481*0b57cec5SDimitry Andric     __insert_iterator(__i);
482*0b57cec5SDimitry Andric }
483*0b57cec5SDimitry Andric 
484*0b57cec5SDimitry Andric void
485*0b57cec5SDimitry Andric __c_node::__add(__i_node* i)
486*0b57cec5SDimitry Andric {
487*0b57cec5SDimitry Andric     if (end_ == cap_)
488*0b57cec5SDimitry Andric     {
489*0b57cec5SDimitry Andric         size_t nc = 2*static_cast<size_t>(cap_ - beg_);
490*0b57cec5SDimitry Andric         if (nc == 0)
491*0b57cec5SDimitry Andric             nc = 1;
492*0b57cec5SDimitry Andric         __i_node** beg =
493*0b57cec5SDimitry Andric            static_cast<__i_node**>(malloc(nc * sizeof(__i_node*)));
494*0b57cec5SDimitry Andric         if (beg == nullptr)
495*0b57cec5SDimitry Andric             __throw_bad_alloc();
496*0b57cec5SDimitry Andric 
497*0b57cec5SDimitry Andric         if (nc > 1)
498*0b57cec5SDimitry Andric             memcpy(beg, beg_, nc/2*sizeof(__i_node*));
499*0b57cec5SDimitry Andric         free(beg_);
500*0b57cec5SDimitry Andric         beg_ = beg;
501*0b57cec5SDimitry Andric         end_ = beg_ + nc/2;
502*0b57cec5SDimitry Andric         cap_ = beg_ + nc;
503*0b57cec5SDimitry Andric     }
504*0b57cec5SDimitry Andric     *end_++ = i;
505*0b57cec5SDimitry Andric }
506*0b57cec5SDimitry Andric 
507*0b57cec5SDimitry Andric // private api
508*0b57cec5SDimitry Andric 
509*0b57cec5SDimitry Andric _LIBCPP_HIDDEN
510*0b57cec5SDimitry Andric __i_node*
511*0b57cec5SDimitry Andric __libcpp_db::__insert_iterator(void* __i)
512*0b57cec5SDimitry Andric {
513*0b57cec5SDimitry Andric     if (__isz_ + 1 > static_cast<size_t>(__iend_ - __ibeg_))
514*0b57cec5SDimitry Andric     {
515*0b57cec5SDimitry Andric         size_t nc = __next_prime(2*static_cast<size_t>(__iend_ - __ibeg_) + 1);
516*0b57cec5SDimitry Andric         __i_node** ibeg = static_cast<__i_node**>(calloc(nc, sizeof(__i_node*)));
517*0b57cec5SDimitry Andric         if (ibeg == nullptr)
518*0b57cec5SDimitry Andric             __throw_bad_alloc();
519*0b57cec5SDimitry Andric 
520*0b57cec5SDimitry Andric         for (__i_node** p = __ibeg_; p != __iend_; ++p)
521*0b57cec5SDimitry Andric         {
522*0b57cec5SDimitry Andric             __i_node* q = *p;
523*0b57cec5SDimitry Andric             while (q != nullptr)
524*0b57cec5SDimitry Andric             {
525*0b57cec5SDimitry Andric                 size_t h = hash<void*>()(q->__i_) % nc;
526*0b57cec5SDimitry Andric                 __i_node* r = q->__next_;
527*0b57cec5SDimitry Andric                 q->__next_ = ibeg[h];
528*0b57cec5SDimitry Andric                 ibeg[h] = q;
529*0b57cec5SDimitry Andric                 q = r;
530*0b57cec5SDimitry Andric             }
531*0b57cec5SDimitry Andric         }
532*0b57cec5SDimitry Andric         free(__ibeg_);
533*0b57cec5SDimitry Andric         __ibeg_ = ibeg;
534*0b57cec5SDimitry Andric         __iend_ = __ibeg_ + nc;
535*0b57cec5SDimitry Andric     }
536*0b57cec5SDimitry Andric     size_t hi = hash<void*>()(__i) % static_cast<size_t>(__iend_ - __ibeg_);
537*0b57cec5SDimitry Andric     __i_node* p = __ibeg_[hi];
538*0b57cec5SDimitry Andric     __i_node* r = __ibeg_[hi] =
539*0b57cec5SDimitry Andric       static_cast<__i_node*>(malloc(sizeof(__i_node)));
540*0b57cec5SDimitry Andric     if (r == nullptr)
541*0b57cec5SDimitry Andric         __throw_bad_alloc();
542*0b57cec5SDimitry Andric 
543*0b57cec5SDimitry Andric     ::new(r) __i_node(__i, p, nullptr);
544*0b57cec5SDimitry Andric     ++__isz_;
545*0b57cec5SDimitry Andric     return r;
546*0b57cec5SDimitry Andric }
547*0b57cec5SDimitry Andric 
548*0b57cec5SDimitry Andric _LIBCPP_HIDDEN
549*0b57cec5SDimitry Andric __i_node*
550*0b57cec5SDimitry Andric __libcpp_db::__find_iterator(const void* __i) const
551*0b57cec5SDimitry Andric {
552*0b57cec5SDimitry Andric     __i_node* r = nullptr;
553*0b57cec5SDimitry Andric     if (__ibeg_ != __iend_)
554*0b57cec5SDimitry Andric     {
555*0b57cec5SDimitry Andric         size_t h = hash<const void*>()(__i) % static_cast<size_t>(__iend_ - __ibeg_);
556*0b57cec5SDimitry Andric         for (__i_node* nd = __ibeg_[h]; nd != nullptr; nd = nd->__next_)
557*0b57cec5SDimitry Andric         {
558*0b57cec5SDimitry Andric             if (nd->__i_ == __i)
559*0b57cec5SDimitry Andric             {
560*0b57cec5SDimitry Andric                 r = nd;
561*0b57cec5SDimitry Andric                 break;
562*0b57cec5SDimitry Andric             }
563*0b57cec5SDimitry Andric         }
564*0b57cec5SDimitry Andric     }
565*0b57cec5SDimitry Andric     return r;
566*0b57cec5SDimitry Andric }
567*0b57cec5SDimitry Andric 
568*0b57cec5SDimitry Andric _LIBCPP_HIDDEN
569*0b57cec5SDimitry Andric void
570*0b57cec5SDimitry Andric __c_node::__remove(__i_node* p)
571*0b57cec5SDimitry Andric {
572*0b57cec5SDimitry Andric     __i_node** r = find(beg_, end_, p);
573*0b57cec5SDimitry Andric     _LIBCPP_ASSERT(r != end_, "debug mode internal logic error __c_node::__remove");
574*0b57cec5SDimitry Andric     if (--end_ != r)
575*0b57cec5SDimitry Andric         memmove(r, r+1, static_cast<size_t>(end_ - r)*sizeof(__i_node*));
576*0b57cec5SDimitry Andric }
577*0b57cec5SDimitry Andric 
578*0b57cec5SDimitry Andric _LIBCPP_END_NAMESPACE_STD
579