Home | History | Annotate | Download | only in Core
      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     //------------------------------------------------------------------
     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 
    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 &
    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 
    210 ConstString::ConstString (const char *cstr) :
    211     m_string (StringPool().GetConstCString (cstr))
    212 {
    213 }
    214 
    215 ConstString::ConstString (const char *cstr, size_t cstr_len) :
    216     m_string (StringPool().GetConstCStringWithLength (cstr, cstr_len))
    217 {
    218 }
    219 
    220 ConstString::ConstString (const llvm::StringRef &s) :
    221     m_string (StringPool().GetConstCStringWithLength (s.data(), s.size()))
    222 {
    223 }
    224 
    225 bool
    226 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&
    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
    253 ConstString::GetLength () const
    254 {
    255     return StringPool().GetConstCStringLength (m_string);
    256 }
    257 
    258 int
    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
    280 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
    291 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
    301 ConstString::SetCString (const char *cstr)
    302 {
    303     m_string = StringPool().GetConstCString (cstr);
    304 }
    305 
    306 void
    307 ConstString::SetString (const llvm::StringRef &s)
    308 {
    309     m_string = StringPool().GetConstCStringWithLength (s.data(), s.size());
    310 }
    311 
    312 void
    313 ConstString::SetCStringWithMangledCounterpart (const char *demangled, const ConstString &mangled)
    314 {
    315     m_string = StringPool().GetConstCStringAndSetMangledCounterPart (demangled, mangled.m_string);
    316 }
    317 
    318 bool
    319 ConstString::GetMangledCounterpart (ConstString &counterpart) const
    320 {
    321     counterpart.m_string = StringPool().GetMangledCounterpart(m_string);
    322     return counterpart;
    323 }
    324 
    325 void
    326 ConstString::SetCStringWithLength (const char *cstr, size_t cstr_len)
    327 {
    328     m_string = StringPool().GetConstCStringWithLength(cstr, cstr_len);
    329 }
    330 
    331 void
    332 ConstString::SetTrimmedCStringWithLength (const char *cstr, size_t cstr_len)
    333 {
    334     m_string = StringPool().GetConstTrimmedCStringWithLength (cstr, cstr_len);
    335 }
    336 
    337 size_t
    338 ConstString::StaticMemorySize()
    339 {
    340     // Get the size of the static string pool
    341     return StringPool().MemorySize();
    342 }
    343