1//===-- ConstString.cpp -----------------------------------------*- C++ -*-===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9#include "lldb/Core/ConstString.h"
10#include "lldb/Core/Stream.h"
11#include "lldb/Host/Mutex.h"
12#include "llvm/ADT/StringMap.h"
13
14using namespace lldb_private;
15
16
17class Pool
18{
19public:
20    typedef const char * StringPoolValueType;
21    typedef llvm::StringMap<StringPoolValueType, llvm::BumpPtrAllocator> StringPool;
22    typedef llvm::StringMapEntry<StringPoolValueType> StringPoolEntryType;
23
24    //------------------------------------------------------------------
25    // Default constructor
26    //
27    // Initialize the member variables and create the empty string.
28    //------------------------------------------------------------------
29    Pool () :
30        m_mutex (Mutex::eMutexTypeRecursive),
31        m_string_map ()
32    {
33    }
34
35    //------------------------------------------------------------------
36    // Destructor
37    //------------------------------------------------------------------
38    ~Pool ()
39    {
40    }
41
42
43    static StringPoolEntryType &
44    GetStringMapEntryFromKeyData (const char *keyData)
45    {
46        char *ptr = const_cast<char*>(keyData) - sizeof (StringPoolEntryType);
47        return *reinterpret_cast<StringPoolEntryType*>(ptr);
48    }
49
50    size_t
51    GetConstCStringLength (const char *ccstr) const
52    {
53        if (ccstr)
54        {
55            const StringPoolEntryType&entry = GetStringMapEntryFromKeyData (ccstr);
56            return entry.getKey().size();
57        }
58        return 0;
59    }
60
61    StringPoolValueType
62    GetMangledCounterpart (const char *ccstr) const
63    {
64        if (ccstr)
65            return GetStringMapEntryFromKeyData (ccstr).getValue();
66        return 0;
67    }
68
69    bool
70    SetMangledCounterparts (const char *key_ccstr, const char *value_ccstr)
71    {
72        if (key_ccstr && value_ccstr)
73        {
74            GetStringMapEntryFromKeyData (key_ccstr).setValue(value_ccstr);
75            GetStringMapEntryFromKeyData (value_ccstr).setValue(key_ccstr);
76            return true;
77        }
78        return false;
79    }
80
81    const char *
82    GetConstCString (const char *cstr)
83    {
84        if (cstr)
85            return GetConstCStringWithLength (cstr, strlen (cstr));
86        return NULL;
87    }
88
89    const char *
90    GetConstCStringWithLength (const char *cstr, size_t cstr_len)
91    {
92        if (cstr)
93        {
94            Mutex::Locker locker (m_mutex);
95            llvm::StringRef string_ref (cstr, cstr_len);
96            StringPoolEntryType& entry = m_string_map.GetOrCreateValue (string_ref, (StringPoolValueType)NULL);
97            return entry.getKeyData();
98        }
99        return NULL;
100    }
101
102    const char *
103    GetConstCStringWithStringRef (const llvm::StringRef &string_ref)
104    {
105        if (string_ref.data())
106        {
107            Mutex::Locker locker (m_mutex);
108            StringPoolEntryType& entry = m_string_map.GetOrCreateValue (string_ref, (StringPoolValueType)NULL);
109            return entry.getKeyData();
110        }
111        return NULL;
112    }
113
114    const char *
115    GetConstCStringAndSetMangledCounterPart (const char *demangled_cstr, const char *mangled_ccstr)
116    {
117        if (demangled_cstr)
118        {
119            Mutex::Locker locker (m_mutex);
120            // Make string pool entry with the mangled counterpart already set
121            StringPoolEntryType& entry = m_string_map.GetOrCreateValue (llvm::StringRef (demangled_cstr), mangled_ccstr);
122
123            // Extract the const version of the demangled_cstr
124            const char *demangled_ccstr = entry.getKeyData();
125            // Now assign the demangled const string as the counterpart of the
126            // mangled const string...
127            GetStringMapEntryFromKeyData (mangled_ccstr).setValue(demangled_ccstr);
128            // Return the constant demangled C string
129            return demangled_ccstr;
130        }
131        return NULL;
132    }
133
134    const char *
135    GetConstTrimmedCStringWithLength (const char *cstr, size_t cstr_len)
136    {
137        if (cstr)
138        {
139            const size_t trimmed_len = std::min<size_t> (strlen (cstr), cstr_len);
140            return GetConstCStringWithLength (cstr, trimmed_len);
141        }
142        return NULL;
143    }
144
145    //------------------------------------------------------------------
146    // Return the size in bytes that this object and any items in its
147    // collection of uniqued strings + data count values takes in
148    // memory.
149    //------------------------------------------------------------------
150    size_t
151    MemorySize() const
152    {
153        Mutex::Locker locker (m_mutex);
154        size_t mem_size = sizeof(Pool);
155        const_iterator end = m_string_map.end();
156        for (const_iterator pos = m_string_map.begin(); pos != end; ++pos)
157        {
158            mem_size += sizeof(StringPoolEntryType) + pos->getKey().size();
159        }
160        return mem_size;
161    }
162
163protected:
164    //------------------------------------------------------------------
165    // Typedefs
166    //------------------------------------------------------------------
167    typedef StringPool::iterator iterator;
168    typedef StringPool::const_iterator const_iterator;
169
170    //------------------------------------------------------------------
171    // Member variables
172    //------------------------------------------------------------------
173    mutable Mutex m_mutex;
174    StringPool m_string_map;
175};
176
177//----------------------------------------------------------------------
178// Frameworks and dylibs aren't supposed to have global C++
179// initializers so we hide the string pool in a static function so
180// that it will get initialized on the first call to this static
181// function.
182//
183// Note, for now we make the string pool a pointer to the pool, because
184// we can't guarantee that some objects won't get destroyed after the
185// global destructor chain is run, and trying to make sure no destructors
186// touch ConstStrings is difficult.  So we leak the pool instead.
187//
188// FIXME: If we are going to keep it this way we should come up with some
189// abstraction to "pthread_once" so we don't have to check the pointer
190// every time.
191//----------------------------------------------------------------------
192static Pool &
193StringPool()
194{
195    static Mutex g_pool_initialization_mutex;
196    static Pool *g_string_pool = NULL;
197
198    if (g_string_pool == NULL)
199    {
200        Mutex::Locker initialization_locker(g_pool_initialization_mutex);
201        if (g_string_pool == NULL)
202        {
203            g_string_pool = new Pool();
204        }
205    }
206
207    return *g_string_pool;
208}
209
210ConstString::ConstString (const char *cstr) :
211    m_string (StringPool().GetConstCString (cstr))
212{
213}
214
215ConstString::ConstString (const char *cstr, size_t cstr_len) :
216    m_string (StringPool().GetConstCStringWithLength (cstr, cstr_len))
217{
218}
219
220ConstString::ConstString (const llvm::StringRef &s) :
221    m_string (StringPool().GetConstCStringWithLength (s.data(), s.size()))
222{
223}
224
225bool
226ConstString::operator < (const ConstString& rhs) const
227{
228    if (m_string == rhs.m_string)
229        return false;
230
231    llvm::StringRef lhs_string_ref (m_string, StringPool().GetConstCStringLength (m_string));
232    llvm::StringRef rhs_string_ref (rhs.m_string, StringPool().GetConstCStringLength (rhs.m_string));
233
234    // If both have valid C strings, then return the comparison
235    if (lhs_string_ref.data() && rhs_string_ref.data())
236        return lhs_string_ref < rhs_string_ref;
237
238    // Else one of them was NULL, so if LHS is NULL then it is less than
239    return lhs_string_ref.data() == NULL;
240}
241
242Stream&
243lldb_private::operator << (Stream& s, const ConstString& str)
244{
245    const char *cstr = str.GetCString();
246    if (cstr)
247        s << cstr;
248
249    return s;
250}
251
252size_t
253ConstString::GetLength () const
254{
255    return StringPool().GetConstCStringLength (m_string);
256}
257
258int
259ConstString::Compare (const ConstString& lhs, const ConstString& rhs)
260{
261    // If the iterators are the same, this is the same string
262    register const char *lhs_cstr = lhs.m_string;
263    register const char *rhs_cstr = rhs.m_string;
264    if (lhs_cstr == rhs_cstr)
265        return 0;
266    if (lhs_cstr && rhs_cstr)
267    {
268        llvm::StringRef lhs_string_ref (lhs_cstr, StringPool().GetConstCStringLength (lhs_cstr));
269        llvm::StringRef rhs_string_ref (rhs_cstr, StringPool().GetConstCStringLength (rhs_cstr));
270        return lhs_string_ref.compare(rhs_string_ref);
271    }
272
273    if (lhs_cstr)
274        return +1;  // LHS isn't NULL but RHS is
275    else
276        return -1;  // LHS is NULL but RHS isn't
277}
278
279void
280ConstString::Dump(Stream *s, const char *fail_value) const
281{
282    if (s)
283    {
284        const char *cstr = AsCString (fail_value);
285        if (cstr)
286            s->PutCString (cstr);
287    }
288}
289
290void
291ConstString::DumpDebug(Stream *s) const
292{
293    const char *cstr = GetCString ();
294    size_t cstr_len = GetLength();
295    // Only print the parens if we have a non-NULL string
296    const char *parens = cstr ? "\"" : "";
297    s->Printf("%*p: ConstString, string = %s%s%s, length = %" PRIu64, (int)sizeof(void*) * 2, this, parens, cstr, parens, (uint64_t)cstr_len);
298}
299
300void
301ConstString::SetCString (const char *cstr)
302{
303    m_string = StringPool().GetConstCString (cstr);
304}
305
306void
307ConstString::SetString (const llvm::StringRef &s)
308{
309    m_string = StringPool().GetConstCStringWithLength (s.data(), s.size());
310}
311
312void
313ConstString::SetCStringWithMangledCounterpart (const char *demangled, const ConstString &mangled)
314{
315    m_string = StringPool().GetConstCStringAndSetMangledCounterPart (demangled, mangled.m_string);
316}
317
318bool
319ConstString::GetMangledCounterpart (ConstString &counterpart) const
320{
321    counterpart.m_string = StringPool().GetMangledCounterpart(m_string);
322    return counterpart;
323}
324
325void
326ConstString::SetCStringWithLength (const char *cstr, size_t cstr_len)
327{
328    m_string = StringPool().GetConstCStringWithLength(cstr, cstr_len);
329}
330
331void
332ConstString::SetTrimmedCStringWithLength (const char *cstr, size_t cstr_len)
333{
334    m_string = StringPool().GetConstTrimmedCStringWithLength (cstr, cstr_len);
335}
336
337size_t
338ConstString::StaticMemorySize()
339{
340    // Get the size of the static string pool
341    return StringPool().MemorySize();
342}
343