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