• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
14 using namespace lldb_private;
15 
16 
17 class Pool
18 {
19 public:
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     //------------------------------------------------------------------
Pool()29     Pool () :
30         m_mutex (Mutex::eMutexTypeRecursive),
31         m_string_map ()
32     {
33     }
34 
35     //------------------------------------------------------------------
36     // Destructor
37     //------------------------------------------------------------------
~Pool()38     ~Pool ()
39     {
40     }
41 
42 
43     static StringPoolEntryType &
GetStringMapEntryFromKeyData(const char * keyData)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
GetConstCStringLength(const char * ccstr) const51     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
GetMangledCounterpart(const char * ccstr) const62     GetMangledCounterpart (const char *ccstr) const
63     {
64         if (ccstr)
65             return GetStringMapEntryFromKeyData (ccstr).getValue();
66         return 0;
67     }
68 
69     bool
SetMangledCounterparts(const char * key_ccstr,const char * value_ccstr)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 *
GetConstCString(const char * cstr)82     GetConstCString (const char *cstr)
83     {
84         if (cstr)
85             return GetConstCStringWithLength (cstr, strlen (cstr));
86         return NULL;
87     }
88 
89     const char *
GetConstCStringWithLength(const char * cstr,size_t cstr_len)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 *
GetConstCStringWithStringRef(const llvm::StringRef & string_ref)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 *
GetConstCStringAndSetMangledCounterPart(const char * demangled_cstr,const char * mangled_ccstr)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 *
GetConstTrimmedCStringWithLength(const char * cstr,size_t cstr_len)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
MemorySize() const151     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 
163 protected:
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 //----------------------------------------------------------------------
192 static Pool &
StringPool()193 StringPool()
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 
ConstString(const char * cstr)210 ConstString::ConstString (const char *cstr) :
211     m_string (StringPool().GetConstCString (cstr))
212 {
213 }
214 
ConstString(const char * cstr,size_t cstr_len)215 ConstString::ConstString (const char *cstr, size_t cstr_len) :
216     m_string (StringPool().GetConstCStringWithLength (cstr, cstr_len))
217 {
218 }
219 
ConstString(const llvm::StringRef & s)220 ConstString::ConstString (const llvm::StringRef &s) :
221     m_string (StringPool().GetConstCStringWithLength (s.data(), s.size()))
222 {
223 }
224 
225 bool
operator <(const ConstString & rhs) const226 ConstString::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 
242 Stream&
operator <<(Stream & s,const ConstString & str)243 lldb_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 
252 size_t
GetLength() const253 ConstString::GetLength () const
254 {
255     return StringPool().GetConstCStringLength (m_string);
256 }
257 
258 int
Compare(const ConstString & lhs,const ConstString & rhs)259 ConstString::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 
279 void
Dump(Stream * s,const char * fail_value) const280 ConstString::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 
290 void
DumpDebug(Stream * s) const291 ConstString::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 
300 void
SetCString(const char * cstr)301 ConstString::SetCString (const char *cstr)
302 {
303     m_string = StringPool().GetConstCString (cstr);
304 }
305 
306 void
SetString(const llvm::StringRef & s)307 ConstString::SetString (const llvm::StringRef &s)
308 {
309     m_string = StringPool().GetConstCStringWithLength (s.data(), s.size());
310 }
311 
312 void
SetCStringWithMangledCounterpart(const char * demangled,const ConstString & mangled)313 ConstString::SetCStringWithMangledCounterpart (const char *demangled, const ConstString &mangled)
314 {
315     m_string = StringPool().GetConstCStringAndSetMangledCounterPart (demangled, mangled.m_string);
316 }
317 
318 bool
GetMangledCounterpart(ConstString & counterpart) const319 ConstString::GetMangledCounterpart (ConstString &counterpart) const
320 {
321     counterpart.m_string = StringPool().GetMangledCounterpart(m_string);
322     return counterpart;
323 }
324 
325 void
SetCStringWithLength(const char * cstr,size_t cstr_len)326 ConstString::SetCStringWithLength (const char *cstr, size_t cstr_len)
327 {
328     m_string = StringPool().GetConstCStringWithLength(cstr, cstr_len);
329 }
330 
331 void
SetTrimmedCStringWithLength(const char * cstr,size_t cstr_len)332 ConstString::SetTrimmedCStringWithLength (const char *cstr, size_t cstr_len)
333 {
334     m_string = StringPool().GetConstTrimmedCStringWithLength (cstr, cstr_len);
335 }
336 
337 size_t
StaticMemorySize()338 ConstString::StaticMemorySize()
339 {
340     // Get the size of the static string pool
341     return StringPool().MemorySize();
342 }
343