summaryrefslogtreecommitdiff
path: root/current/sources/cxx-stl/llvm-libc++abi/src/include/refstring.h
blob: 5905b5c9327bad1ec14fc3c267b88ec5291a0e45 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
//===------------------------ __refstring ---------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

// FIXME: This file is copied from libcxx/src/include/refstring.h. Instead of
// duplicating the file in libc++abi we should require that the libc++ sources
// are available when building libc++abi.

#ifndef _LIBCPPABI_REFSTRING_H
#define _LIBCPPABI_REFSTRING_H

#include <__config>
#include <stdexcept>
#include <cstddef>
#include <cstring>
#ifdef __APPLE__
#include <dlfcn.h>
#include <mach-o/dyld.h>
#endif
#include "atomic_support.h"

_LIBCPP_BEGIN_NAMESPACE_STD

namespace __refstring_imp { namespace {
typedef int count_t;

struct _Rep_base {
    std::size_t len;
    std::size_t cap;
    count_t     count;
};

inline _Rep_base* rep_from_data(const char *data_) noexcept {
    char *data = const_cast<char *>(data_);
    return reinterpret_cast<_Rep_base *>(data - sizeof(_Rep_base));
}

inline char * data_from_rep(_Rep_base *rep) noexcept {
    char *data = reinterpret_cast<char *>(rep);
    return data + sizeof(*rep);
}

#if defined(__APPLE__)
inline
const char* compute_gcc_empty_string_storage() _NOEXCEPT
{
    void* handle = dlopen("/usr/lib/libstdc++.6.dylib", RTLD_NOLOAD);
    if (handle == nullptr)
        return nullptr;
    void* sym = dlsym(handle, "_ZNSs4_Rep20_S_empty_rep_storageE");
    if (sym == nullptr)
        return nullptr;
    return data_from_rep(reinterpret_cast<_Rep_base *>(sym));
}

inline
const char*
get_gcc_empty_string_storage() _NOEXCEPT
{
    static const char* p = compute_gcc_empty_string_storage();
    return p;
}
#endif

}} // namespace __refstring_imp

using namespace __refstring_imp;

inline
__libcpp_refstring::__libcpp_refstring(const char* msg) {
    std::size_t len = strlen(msg);
    _Rep_base* rep = static_cast<_Rep_base *>(::operator new(sizeof(*rep) + len + 1));
    rep->len = len;
    rep->cap = len;
    rep->count = 0;
    char *data = data_from_rep(rep);
    std::memcpy(data, msg, len + 1);
    __imp_ = data;
}

inline
__libcpp_refstring::__libcpp_refstring(const __libcpp_refstring &s) _NOEXCEPT
    : __imp_(s.__imp_)
{
    if (__uses_refcount())
        __libcpp_atomic_add(&rep_from_data(__imp_)->count, 1);
}

inline
__libcpp_refstring& __libcpp_refstring::operator=(__libcpp_refstring const& s) _NOEXCEPT {
    bool adjust_old_count = __uses_refcount();
    struct _Rep_base *old_rep = rep_from_data(__imp_);
    __imp_ = s.__imp_;
    if (__uses_refcount())
        __libcpp_atomic_add(&rep_from_data(__imp_)->count, 1);
    if (adjust_old_count)
    {
        if (__libcpp_atomic_add(&old_rep->count, count_t(-1)) < 0)
        {
            ::operator delete(old_rep);
        }
    }
    return *this;
}

inline
__libcpp_refstring::~__libcpp_refstring() {
    if (__uses_refcount()) {
        _Rep_base* rep = rep_from_data(__imp_);
        if (__libcpp_atomic_add(&rep->count, count_t(-1)) < 0) {
            ::operator delete(rep);
        }
    }
}

inline
bool __libcpp_refstring::__uses_refcount() const {
#ifdef __APPLE__
    return __imp_ != get_gcc_empty_string_storage();
#else
    return true;
#endif
}

_LIBCPP_END_NAMESPACE_STD

#endif //_LIBCPPABI_REFSTRING_H