forked from OSchip/llvm-project
343 lines
10 KiB
C++
343 lines
10 KiB
C++
//===-- ConstString.cpp -----------------------------------------*- C++ -*-===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
#include "lldb/Core/ConstString.h"
|
|
#include "lldb/Core/Stream.h"
|
|
#include "lldb/Host/Mutex.h"
|
|
#include "llvm/ADT/StringMap.h"
|
|
|
|
using namespace lldb_private;
|
|
|
|
|
|
class Pool
|
|
{
|
|
public:
|
|
typedef const char * StringPoolValueType;
|
|
typedef llvm::StringMap<StringPoolValueType, llvm::BumpPtrAllocator> StringPool;
|
|
typedef llvm::StringMapEntry<StringPoolValueType> StringPoolEntryType;
|
|
|
|
//------------------------------------------------------------------
|
|
// Default constructor
|
|
//
|
|
// Initialize the member variables and create the empty string.
|
|
//------------------------------------------------------------------
|
|
Pool () :
|
|
m_mutex (Mutex::eMutexTypeRecursive),
|
|
m_string_map ()
|
|
{
|
|
}
|
|
|
|
//------------------------------------------------------------------
|
|
// Destructor
|
|
//------------------------------------------------------------------
|
|
~Pool ()
|
|
{
|
|
}
|
|
|
|
|
|
static StringPoolEntryType &
|
|
GetStringMapEntryFromKeyData (const char *keyData)
|
|
{
|
|
char *ptr = const_cast<char*>(keyData) - sizeof (StringPoolEntryType);
|
|
return *reinterpret_cast<StringPoolEntryType*>(ptr);
|
|
}
|
|
|
|
size_t
|
|
GetConstCStringLength (const char *ccstr) const
|
|
{
|
|
if (ccstr)
|
|
{
|
|
const StringPoolEntryType&entry = GetStringMapEntryFromKeyData (ccstr);
|
|
return entry.getKey().size();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
StringPoolValueType
|
|
GetMangledCounterpart (const char *ccstr) const
|
|
{
|
|
if (ccstr)
|
|
return GetStringMapEntryFromKeyData (ccstr).getValue();
|
|
return 0;
|
|
}
|
|
|
|
bool
|
|
SetMangledCounterparts (const char *key_ccstr, const char *value_ccstr)
|
|
{
|
|
if (key_ccstr && value_ccstr)
|
|
{
|
|
GetStringMapEntryFromKeyData (key_ccstr).setValue(value_ccstr);
|
|
GetStringMapEntryFromKeyData (value_ccstr).setValue(key_ccstr);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
const char *
|
|
GetConstCString (const char *cstr)
|
|
{
|
|
if (cstr)
|
|
return GetConstCStringWithLength (cstr, strlen (cstr));
|
|
return NULL;
|
|
}
|
|
|
|
const char *
|
|
GetConstCStringWithLength (const char *cstr, size_t cstr_len)
|
|
{
|
|
if (cstr)
|
|
{
|
|
Mutex::Locker locker (m_mutex);
|
|
llvm::StringRef string_ref (cstr, cstr_len);
|
|
StringPoolEntryType& entry = m_string_map.GetOrCreateValue (string_ref, (StringPoolValueType)NULL);
|
|
return entry.getKeyData();
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
const char *
|
|
GetConstCStringWithStringRef (const llvm::StringRef &string_ref)
|
|
{
|
|
if (string_ref.data())
|
|
{
|
|
Mutex::Locker locker (m_mutex);
|
|
StringPoolEntryType& entry = m_string_map.GetOrCreateValue (string_ref, (StringPoolValueType)NULL);
|
|
return entry.getKeyData();
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
const char *
|
|
GetConstCStringAndSetMangledCounterPart (const char *demangled_cstr, const char *mangled_ccstr)
|
|
{
|
|
if (demangled_cstr)
|
|
{
|
|
Mutex::Locker locker (m_mutex);
|
|
// Make string pool entry with the mangled counterpart already set
|
|
StringPoolEntryType& entry = m_string_map.GetOrCreateValue (llvm::StringRef (demangled_cstr), mangled_ccstr);
|
|
|
|
// Extract the const version of the demangled_cstr
|
|
const char *demangled_ccstr = entry.getKeyData();
|
|
// Now assign the demangled const string as the counterpart of the
|
|
// mangled const string...
|
|
GetStringMapEntryFromKeyData (mangled_ccstr).setValue(demangled_ccstr);
|
|
// Return the constant demangled C string
|
|
return demangled_ccstr;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
const char *
|
|
GetConstTrimmedCStringWithLength (const char *cstr, size_t cstr_len)
|
|
{
|
|
if (cstr)
|
|
{
|
|
const size_t trimmed_len = std::min<size_t> (strlen (cstr), cstr_len);
|
|
return GetConstCStringWithLength (cstr, trimmed_len);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
//------------------------------------------------------------------
|
|
// Return the size in bytes that this object and any items in its
|
|
// collection of uniqued strings + data count values takes in
|
|
// memory.
|
|
//------------------------------------------------------------------
|
|
size_t
|
|
MemorySize() const
|
|
{
|
|
Mutex::Locker locker (m_mutex);
|
|
size_t mem_size = sizeof(Pool);
|
|
const_iterator end = m_string_map.end();
|
|
for (const_iterator pos = m_string_map.begin(); pos != end; ++pos)
|
|
{
|
|
mem_size += sizeof(StringPoolEntryType) + pos->getKey().size();
|
|
}
|
|
return mem_size;
|
|
}
|
|
|
|
protected:
|
|
//------------------------------------------------------------------
|
|
// Typedefs
|
|
//------------------------------------------------------------------
|
|
typedef StringPool::iterator iterator;
|
|
typedef StringPool::const_iterator const_iterator;
|
|
|
|
//------------------------------------------------------------------
|
|
// Member variables
|
|
//------------------------------------------------------------------
|
|
mutable Mutex m_mutex;
|
|
StringPool m_string_map;
|
|
};
|
|
|
|
//----------------------------------------------------------------------
|
|
// Frameworks and dylibs aren't supposed to have global C++
|
|
// initializers so we hide the string pool in a static function so
|
|
// that it will get initialized on the first call to this static
|
|
// function.
|
|
//
|
|
// Note, for now we make the string pool a pointer to the pool, because
|
|
// we can't guarantee that some objects won't get destroyed after the
|
|
// global destructor chain is run, and trying to make sure no destructors
|
|
// touch ConstStrings is difficult. So we leak the pool instead.
|
|
//
|
|
// FIXME: If we are going to keep it this way we should come up with some
|
|
// abstraction to "pthread_once" so we don't have to check the pointer
|
|
// every time.
|
|
//----------------------------------------------------------------------
|
|
static Pool &
|
|
StringPool()
|
|
{
|
|
static Mutex g_pool_initialization_mutex;
|
|
static Pool *g_string_pool = NULL;
|
|
|
|
if (g_string_pool == NULL)
|
|
{
|
|
Mutex::Locker initialization_locker(g_pool_initialization_mutex);
|
|
if (g_string_pool == NULL)
|
|
{
|
|
g_string_pool = new Pool();
|
|
}
|
|
}
|
|
|
|
return *g_string_pool;
|
|
}
|
|
|
|
ConstString::ConstString (const char *cstr) :
|
|
m_string (StringPool().GetConstCString (cstr))
|
|
{
|
|
}
|
|
|
|
ConstString::ConstString (const char *cstr, size_t cstr_len) :
|
|
m_string (StringPool().GetConstCStringWithLength (cstr, cstr_len))
|
|
{
|
|
}
|
|
|
|
ConstString::ConstString (const llvm::StringRef &s) :
|
|
m_string (StringPool().GetConstCStringWithLength (s.data(), s.size()))
|
|
{
|
|
}
|
|
|
|
bool
|
|
ConstString::operator < (const ConstString& rhs) const
|
|
{
|
|
if (m_string == rhs.m_string)
|
|
return false;
|
|
|
|
llvm::StringRef lhs_string_ref (m_string, StringPool().GetConstCStringLength (m_string));
|
|
llvm::StringRef rhs_string_ref (rhs.m_string, StringPool().GetConstCStringLength (rhs.m_string));
|
|
|
|
// If both have valid C strings, then return the comparison
|
|
if (lhs_string_ref.data() && rhs_string_ref.data())
|
|
return lhs_string_ref < rhs_string_ref;
|
|
|
|
// Else one of them was NULL, so if LHS is NULL then it is less than
|
|
return lhs_string_ref.data() == NULL;
|
|
}
|
|
|
|
Stream&
|
|
lldb_private::operator << (Stream& s, const ConstString& str)
|
|
{
|
|
const char *cstr = str.GetCString();
|
|
if (cstr)
|
|
s << cstr;
|
|
|
|
return s;
|
|
}
|
|
|
|
size_t
|
|
ConstString::GetLength () const
|
|
{
|
|
return StringPool().GetConstCStringLength (m_string);
|
|
}
|
|
|
|
int
|
|
ConstString::Compare (const ConstString& lhs, const ConstString& rhs)
|
|
{
|
|
// If the iterators are the same, this is the same string
|
|
const char *lhs_cstr = lhs.m_string;
|
|
const char *rhs_cstr = rhs.m_string;
|
|
if (lhs_cstr == rhs_cstr)
|
|
return 0;
|
|
if (lhs_cstr && rhs_cstr)
|
|
{
|
|
llvm::StringRef lhs_string_ref (lhs_cstr, StringPool().GetConstCStringLength (lhs_cstr));
|
|
llvm::StringRef rhs_string_ref (rhs_cstr, StringPool().GetConstCStringLength (rhs_cstr));
|
|
return lhs_string_ref.compare(rhs_string_ref);
|
|
}
|
|
|
|
if (lhs_cstr)
|
|
return +1; // LHS isn't NULL but RHS is
|
|
else
|
|
return -1; // LHS is NULL but RHS isn't
|
|
}
|
|
|
|
void
|
|
ConstString::Dump(Stream *s, const char *fail_value) const
|
|
{
|
|
if (s)
|
|
{
|
|
const char *cstr = AsCString (fail_value);
|
|
if (cstr)
|
|
s->PutCString (cstr);
|
|
}
|
|
}
|
|
|
|
void
|
|
ConstString::DumpDebug(Stream *s) const
|
|
{
|
|
const char *cstr = GetCString ();
|
|
size_t cstr_len = GetLength();
|
|
// Only print the parens if we have a non-NULL string
|
|
const char *parens = cstr ? "\"" : "";
|
|
s->Printf("%*p: ConstString, string = %s%s%s, length = %" PRIu64, (int)sizeof(void*) * 2, this, parens, cstr, parens, (uint64_t)cstr_len);
|
|
}
|
|
|
|
void
|
|
ConstString::SetCString (const char *cstr)
|
|
{
|
|
m_string = StringPool().GetConstCString (cstr);
|
|
}
|
|
|
|
void
|
|
ConstString::SetString (const llvm::StringRef &s)
|
|
{
|
|
m_string = StringPool().GetConstCStringWithLength (s.data(), s.size());
|
|
}
|
|
|
|
void
|
|
ConstString::SetCStringWithMangledCounterpart (const char *demangled, const ConstString &mangled)
|
|
{
|
|
m_string = StringPool().GetConstCStringAndSetMangledCounterPart (demangled, mangled.m_string);
|
|
}
|
|
|
|
bool
|
|
ConstString::GetMangledCounterpart (ConstString &counterpart) const
|
|
{
|
|
counterpart.m_string = StringPool().GetMangledCounterpart(m_string);
|
|
return (bool)counterpart;
|
|
}
|
|
|
|
void
|
|
ConstString::SetCStringWithLength (const char *cstr, size_t cstr_len)
|
|
{
|
|
m_string = StringPool().GetConstCStringWithLength(cstr, cstr_len);
|
|
}
|
|
|
|
void
|
|
ConstString::SetTrimmedCStringWithLength (const char *cstr, size_t cstr_len)
|
|
{
|
|
m_string = StringPool().GetConstTrimmedCStringWithLength (cstr, cstr_len);
|
|
}
|
|
|
|
size_t
|
|
ConstString::StaticMemorySize()
|
|
{
|
|
// Get the size of the static string pool
|
|
return StringPool().MemorySize();
|
|
}
|