__refstring revision 278724
1213288Sdavidxu//===------------------------ __refstring ---------------------------------===//
2213288Sdavidxu//
3213288Sdavidxu//                     The LLVM Compiler Infrastructure
4213288Sdavidxu//
5213288Sdavidxu// This file is dual licensed under the MIT and the University of Illinois Open
6213288Sdavidxu// Source Licenses. See LICENSE.TXT for details.
7213288Sdavidxu//
8213288Sdavidxu//===----------------------------------------------------------------------===//
9213288Sdavidxu
10213288Sdavidxu#ifndef _LIBCPP___REFSTRING
11213288Sdavidxu#define _LIBCPP___REFSTRING
12213288Sdavidxu
13213288Sdavidxu#include <__config>
14213288Sdavidxu#include <cstddef>
15213288Sdavidxu#include <cstring>
16213288Sdavidxu#if __APPLE__
17213288Sdavidxu#include <dlfcn.h>
18213288Sdavidxu#include <mach-o/dyld.h>
19213288Sdavidxu#endif
20213288Sdavidxu
21213288Sdavidxu_LIBCPP_BEGIN_NAMESPACE_STD
22213288Sdavidxu
23213288Sdavidxuclass _LIBCPP_HIDDEN __libcpp_refstring
24213288Sdavidxu{
25213288Sdavidxuprivate:
26213288Sdavidxu    const char* str_;
27213288Sdavidxu
28213288Sdavidxu    typedef int count_t;
29213288Sdavidxu
30213288Sdavidxu    struct _Rep_base
31213289Sdavidxu    {
32213289Sdavidxu        std::size_t len;
33213288Sdavidxu        std::size_t cap;
34213288Sdavidxu        count_t     count;
35213288Sdavidxu    };
36213288Sdavidxu
37213288Sdavidxu    static
38213288Sdavidxu    _Rep_base*
39213288Sdavidxu    rep_from_data(const char *data_) _NOEXCEPT
40213288Sdavidxu    {
41213288Sdavidxu        char *data = const_cast<char *>(data_);
42213288Sdavidxu        return reinterpret_cast<_Rep_base *>(data - sizeof(_Rep_base));
43213288Sdavidxu    }
44213288Sdavidxu    static
45213288Sdavidxu    char *
46213288Sdavidxu    data_from_rep(_Rep_base *rep) _NOEXCEPT
47213288Sdavidxu    {
48213288Sdavidxu        char *data = reinterpret_cast<char *>(rep);
49213288Sdavidxu        return data + sizeof(*rep);
50213288Sdavidxu    }
51213288Sdavidxu
52213288Sdavidxu#if __APPLE__
53213288Sdavidxu    static
54213288Sdavidxu    const char*
55213288Sdavidxu    compute_gcc_empty_string_storage() _NOEXCEPT
56213288Sdavidxu    {
57213288Sdavidxu        void* handle = dlopen("/usr/lib/libstdc++.6.dylib", RTLD_NOLOAD);
58213288Sdavidxu        if (handle == nullptr)
59213288Sdavidxu            return nullptr;
60213288Sdavidxu        void* sym = dlsym(handle, "_ZNSs4_Rep20_S_empty_rep_storageE");
61213288Sdavidxu        if (sym == nullptr)
62213288Sdavidxu            return nullptr;
63213288Sdavidxu        return data_from_rep(reinterpret_cast<_Rep_base *>(sym));
64213288Sdavidxu    }
65213288Sdavidxu
66213288Sdavidxu    static
67213288Sdavidxu    const char*
68213288Sdavidxu    get_gcc_empty_string_storage() _NOEXCEPT
69213290Sdavidxu    {
70213288Sdavidxu        static const char* p = compute_gcc_empty_string_storage();
71213288Sdavidxu        return p;
72213288Sdavidxu    }
73213288Sdavidxu
74213288Sdavidxu    bool
75213288Sdavidxu    uses_refcount() const
76213288Sdavidxu    {
77213288Sdavidxu        return str_ != get_gcc_empty_string_storage();
78213288Sdavidxu    }
79213288Sdavidxu#else
80213288Sdavidxu    bool
81213289Sdavidxu    uses_refcount() const
82213288Sdavidxu    {
83213288Sdavidxu        return true;
84213288Sdavidxu    }
85213288Sdavidxu#endif
86213288Sdavidxu
87213288Sdavidxupublic:
88213288Sdavidxu    explicit __libcpp_refstring(const char* msg) {
89213288Sdavidxu        std::size_t len = strlen(msg);
90213288Sdavidxu        _Rep_base* rep = static_cast<_Rep_base *>(::operator new(sizeof(*rep) + len + 1));
91213288Sdavidxu        rep->len = len;
92213288Sdavidxu        rep->cap = len;
93213288Sdavidxu        rep->count = 0;
94213288Sdavidxu        char *data = data_from_rep(rep);
95213288Sdavidxu        std::memcpy(data, msg, len + 1);
96213288Sdavidxu        str_ = data;
97213288Sdavidxu    }
98213288Sdavidxu
99213288Sdavidxu    __libcpp_refstring(const __libcpp_refstring& s) _NOEXCEPT : str_(s.str_)
100213289Sdavidxu    {
101213288Sdavidxu        if (uses_refcount())
102213288Sdavidxu            __sync_add_and_fetch(&rep_from_data(str_)->count, 1);
103213288Sdavidxu    }
104213288Sdavidxu
105213288Sdavidxu    __libcpp_refstring& operator=(const __libcpp_refstring& s) _NOEXCEPT
106213288Sdavidxu    {
107213288Sdavidxu        bool adjust_old_count = uses_refcount();
108213288Sdavidxu        struct _Rep_base *old_rep = rep_from_data(str_);
109213288Sdavidxu        str_ = s.str_;
110213288Sdavidxu        if (uses_refcount())
111213288Sdavidxu            __sync_add_and_fetch(&rep_from_data(str_)->count, 1);
112213288Sdavidxu        if (adjust_old_count)
113213288Sdavidxu        {
114213288Sdavidxu            if (__sync_add_and_fetch(&old_rep->count, count_t(-1)) < 0)
115213288Sdavidxu            {
116213288Sdavidxu                ::operator delete(old_rep);
117213288Sdavidxu            }
118213288Sdavidxu        }
119213288Sdavidxu        return *this;
120213288Sdavidxu    }
121213288Sdavidxu
122213288Sdavidxu    ~__libcpp_refstring()
123213288Sdavidxu    {
124213288Sdavidxu        if (uses_refcount())
125213288Sdavidxu        {
126213288Sdavidxu            _Rep_base* rep = rep_from_data(str_);
127213288Sdavidxu            if (__sync_add_and_fetch(&rep->count, count_t(-1)) < 0)
128213288Sdavidxu            {
129213288Sdavidxu                ::operator delete(rep);
130213288Sdavidxu            }
131213288Sdavidxu        }
132213288Sdavidxu    }
133213288Sdavidxu
134213288Sdavidxu    const char* c_str() const _NOEXCEPT {return str_;}
135213288Sdavidxu};
136213288Sdavidxu
137213288Sdavidxu_LIBCPP_END_NAMESPACE_STD
138213288Sdavidxu
139213288Sdavidxu#endif //_LIBCPP___REFSTRING
140213288Sdavidxu