summaryrefslogtreecommitdiffstats
path: root/contrib/libc++/include/__refstring
blob: 6866bf1b9736e5fc59ad2fcd8f82b6490901e6e2 (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
132
133
134
135
136
137
138
139
//===------------------------ __refstring ---------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#ifndef _LIBCPP___REFSTRING
#define _LIBCPP___REFSTRING

#include <__config>
#include <cstddef>
#include <cstring>
#if __APPLE__
#include <dlfcn.h>
#include <mach-o/dyld.h>
#endif

_LIBCPP_BEGIN_NAMESPACE_STD

class _LIBCPP_HIDDEN __libcpp_refstring
{
private:
    const char* str_;

    typedef int count_t;

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

    static
    _Rep_base*
    rep_from_data(const char *data_) _NOEXCEPT
    {
        char *data = const_cast<char *>(data_);
        return reinterpret_cast<_Rep_base *>(data - sizeof(_Rep_base));
    }
    static
    char *
    data_from_rep(_Rep_base *rep) _NOEXCEPT
    {
        char *data = reinterpret_cast<char *>(rep);
        return data + sizeof(*rep);
    }

#if __APPLE__
    static
    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));
    }

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

    bool
    uses_refcount() const
    {
        return str_ != get_gcc_empty_string_storage();
    }
#else
    bool
    uses_refcount() const
    {
        return true;
    }
#endif

public:
    explicit __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);
        str_ = data;
    }

    __libcpp_refstring(const __libcpp_refstring& s) _NOEXCEPT : str_(s.str_)
    {
        if (uses_refcount())
            __sync_add_and_fetch(&rep_from_data(str_)->count, 1);
    }

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

    ~__libcpp_refstring()
    {
        if (uses_refcount())
        {
            _Rep_base* rep = rep_from_data(str_);
            if (__sync_add_and_fetch(&rep->count, count_t(-1)) < 0)
            {
                ::operator delete(rep);
            }
        }
    }

    const char* c_str() const _NOEXCEPT {return str_;}
};

_LIBCPP_END_NAMESPACE_STD

#endif //_LIBCPP___REFSTRING
OpenPOWER on IntegriCloud