1//===------------------------ __refstring ---------------------------------===//
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// FIXME: This file is copied from libcxx/src/include/refstring.h. Instead of
10// duplicating the file in libc++abi we should require that the libc++ sources
11// are available when building libc++abi.
12
13#ifndef _LIBCPPABI_REFSTRING_H
14#define _LIBCPPABI_REFSTRING_H
15
16#include <__config>
17#include <stdexcept>
18#include <cstddef>
19#include <cstring>
20#ifdef __APPLE__
21#include <dlfcn.h>
22#include <mach-o/dyld.h>
23#endif
24#include "atomic_support.h"
25
26_LIBCPP_BEGIN_NAMESPACE_STD
27
28namespace __refstring_imp { namespace {
29typedef int count_t;
30
31struct _Rep_base {
32 std::size_t len;
33 std::size_t cap;
34 count_t count;
35};
36
37inline _Rep_base* rep_from_data(const char *data_) noexcept {
38 char *data = const_cast<char *>(data_);
39 return reinterpret_cast<_Rep_base *>(data - sizeof(_Rep_base));
40}
41
42inline char * data_from_rep(_Rep_base *rep) noexcept {
43 char *data = reinterpret_cast<char *>(rep);
44 return data + sizeof(*rep);
45}
46
47#if defined(__APPLE__)
48inline
49const char* compute_gcc_empty_string_storage() _NOEXCEPT
50{
51 void* handle = dlopen("/usr/lib/libstdc++.6.dylib", RTLD_NOLOAD);
52 if (handle == nullptr)
53 return nullptr;
54 void* sym = dlsym(handle, "_ZNSs4_Rep20_S_empty_rep_storageE");
55 if (sym == nullptr)
56 return nullptr;
57 return data_from_rep(reinterpret_cast<_Rep_base *>(sym));
58}
59
60inline
61const char*
62get_gcc_empty_string_storage() _NOEXCEPT
63{
64 static const char* p = compute_gcc_empty_string_storage();
65 return p;
66}
67#endif
68
69}} // namespace __refstring_imp
70
71using namespace __refstring_imp;
72
73inline
74__libcpp_refstring::__libcpp_refstring(const char* msg) {
75 std::size_t len = strlen(msg);
76 _Rep_base* rep = static_cast<_Rep_base *>(::operator new(sizeof(*rep) + len + 1));
77 rep->len = len;
78 rep->cap = len;
79 rep->count = 0;
80 char *data = data_from_rep(rep);
81 std::memcpy(data, msg, len + 1);
82 __imp_ = data;
83}
84
85inline
86__libcpp_refstring::__libcpp_refstring(const __libcpp_refstring &s) _NOEXCEPT
87 : __imp_(s.__imp_)
88{
89 if (__uses_refcount())
90 __libcpp_atomic_add(&rep_from_data(__imp_)->count, 1);
91}
92
93inline
94__libcpp_refstring& __libcpp_refstring::operator=(__libcpp_refstring const& s) _NOEXCEPT {
95 bool adjust_old_count = __uses_refcount();
96 struct _Rep_base *old_rep = rep_from_data(__imp_);
97 __imp_ = s.__imp_;
98 if (__uses_refcount())
99 __libcpp_atomic_add(&rep_from_data(__imp_)->count, 1);
100 if (adjust_old_count)
101 {
102 if (__libcpp_atomic_add(&old_rep->count, count_t(-1)) < 0)
103 {
104 ::operator delete(old_rep);
105 }
106 }
107 return *this;
108}
109
110inline
111__libcpp_refstring::~__libcpp_refstring() {
112 if (__uses_refcount()) {
113 _Rep_base* rep = rep_from_data(__imp_);
114 if (__libcpp_atomic_add(&rep->count, count_t(-1)) < 0) {
115 ::operator delete(rep);
116 }
117 }
118}
119
120inline
121bool __libcpp_refstring::__uses_refcount() const {
122#ifdef __APPLE__
123 return __imp_ != get_gcc_empty_string_storage();
124#else
125 return true;
126#endif
127}
128
129_LIBCPP_END_NAMESPACE_STD
130
131#endif //_LIBCPPABI_REFSTRING_H
132