ConstString.cpp revision fb2d05b85d8185f06d97d2c5444652fa74c246c3
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, int 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, int cstr_len) 136 { 137 if (cstr) 138 { 139 int trimmed_len = std::min<int> (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 = %llu", (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