Path: blob/main/contrib/llvm-project/libcxx/src/include/refstring.h
35231 views
//===----------------------------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#ifndef _LIBCPP_REFSTRING_H9#define _LIBCPP_REFSTRING_H1011#include "atomic_support.h"12#include <__config>13#include <cstddef>14#include <cstring>15#include <stdexcept>1617// MacOS and iOS used to ship with libstdc++, and still support old applications18// linking against libstdc++. The libc++ and libstdc++ exceptions are supposed19// to be ABI compatible, such that they can be thrown from one library and caught20// in the other.21//22// For that reason, we must look for libstdc++ in the same process and if found,23// check the string stored in the exception object to see if it is the GCC empty24// string singleton before manipulating the reference count. This is done so that25// if an exception is created with a zero-length string in libstdc++, libc++abi26// won't try to delete the memory.27#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) || defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__)28# define _LIBCPP_CHECK_FOR_GCC_EMPTY_STRING_STORAGE29# include <dlfcn.h>30# include <mach-o/dyld.h>31#endif3233_LIBCPP_BEGIN_NAMESPACE_STD3435namespace __refstring_imp {36namespace {37typedef int count_t;3839struct _Rep_base {40std::size_t len;41std::size_t cap;42count_t count;43};4445inline _Rep_base* rep_from_data(const char* data_) noexcept {46char* data = const_cast<char*>(data_);47return reinterpret_cast<_Rep_base*>(data - sizeof(_Rep_base));48}4950inline char* data_from_rep(_Rep_base* rep) noexcept {51char* data = reinterpret_cast<char*>(rep);52return data + sizeof(*rep);53}5455#if defined(_LIBCPP_CHECK_FOR_GCC_EMPTY_STRING_STORAGE)56inline const char* compute_gcc_empty_string_storage() noexcept {57void* handle = dlopen("/usr/lib/libstdc++.6.dylib", RTLD_NOLOAD);58if (handle == nullptr)59return nullptr;60void* sym = dlsym(handle, "_ZNSs4_Rep20_S_empty_rep_storageE");61if (sym == nullptr)62return nullptr;63return data_from_rep(reinterpret_cast<_Rep_base*>(sym));64}6566inline const char* get_gcc_empty_string_storage() noexcept {67static const char* p = compute_gcc_empty_string_storage();68return p;69}70#endif7172} // namespace73} // namespace __refstring_imp7475using namespace __refstring_imp;7677inline __libcpp_refstring::__libcpp_refstring(const char* msg) {78std::size_t len = strlen(msg);79_Rep_base* rep = static_cast<_Rep_base*>(::operator new(sizeof(*rep) + len + 1));80rep->len = len;81rep->cap = len;82rep->count = 0;83char* data = data_from_rep(rep);84std::memcpy(data, msg, len + 1);85__imp_ = data;86}8788inline __libcpp_refstring::__libcpp_refstring(const __libcpp_refstring& s) noexcept : __imp_(s.__imp_) {89if (__uses_refcount())90__libcpp_atomic_add(&rep_from_data(__imp_)->count, 1);91}9293inline __libcpp_refstring& __libcpp_refstring::operator=(__libcpp_refstring const& s) noexcept {94bool adjust_old_count = __uses_refcount();95struct _Rep_base* old_rep = rep_from_data(__imp_);96__imp_ = s.__imp_;97if (__uses_refcount())98__libcpp_atomic_add(&rep_from_data(__imp_)->count, 1);99if (adjust_old_count) {100if (__libcpp_atomic_add(&old_rep->count, count_t(-1)) < 0) {101::operator delete(old_rep);102}103}104return *this;105}106107inline __libcpp_refstring::~__libcpp_refstring() {108if (__uses_refcount()) {109_Rep_base* rep = rep_from_data(__imp_);110if (__libcpp_atomic_add(&rep->count, count_t(-1)) < 0) {111::operator delete(rep);112}113}114}115116inline bool __libcpp_refstring::__uses_refcount() const {117#if defined(_LIBCPP_CHECK_FOR_GCC_EMPTY_STRING_STORAGE)118return __imp_ != get_gcc_empty_string_storage();119#else120return true;121#endif122}123124_LIBCPP_END_NAMESPACE_STD125126#endif //_LIBCPP_REFSTRING_H127128129