blob: e3b0623502d1579abaec95e430bfded381afdc5f [file] [log] [blame]
//===-- 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;
//----------------------------------------------------------------------
// The global string pool is implemented as a hash_map that maps
// std::string objects to a uint32_t reference count.
//
// In debug builds the value that is stored in the ConstString objects is
// a C string that is owned by one of the std::string objects in the
// hash map. This was done for visibility purposes when debugging as
// gcc was often generating insufficient debug info for the
// iterator objects.
//
// In release builds, the value that is stored in the ConstString objects
// is the iterator into the ConstString::HashMap. This is much faster when
// it comes to modifying the reference count, and removing strings from
// the pool.
//----------------------------------------------------------------------
class Pool
{
public:
//------------------------------------------------------------------
// Default constructor
//
// Initialize the member variables and create the empty string.
//------------------------------------------------------------------
Pool () :
m_mutex (Mutex::eMutexTypeRecursive),
m_string_map ()
{
}
//------------------------------------------------------------------
// Destructor
//------------------------------------------------------------------
~Pool ()
{
}
static llvm::StringMapEntry<uint32_t> &
GetStringMapEntryFromKeyData (const char *keyData)
{
char *ptr = const_cast<char*>(keyData) - sizeof (llvm::StringMapEntry<uint32_t>);
return *reinterpret_cast<llvm::StringMapEntry<uint32_t>*>(ptr);
}
size_t
GetConstCStringLength (const char *ccstr)
{
if (ccstr)
{
llvm::StringMapEntry<uint32_t>&entry = GetStringMapEntryFromKeyData (ccstr);
return entry.getKey().size();
}
return 0;
}
const char *
GetConstCString (const char *cstr)
{
if (cstr)
return GetConstCStringWithLength (cstr, strlen (cstr));
return NULL;
}
const char *
GetConstCStringWithLength (const char *cstr, int cstr_len)
{
if (cstr)
{
Mutex::Locker locker (m_mutex);
llvm::StringRef string_ref (cstr, cstr_len);
llvm::StringMapEntry<uint32_t>& entry = m_string_map.GetOrCreateValue (string_ref);
return entry.getKeyData();
}
return NULL;
}
const char *
GetConstTrimmedCStringWithLength (const char *cstr, int cstr_len)
{
if (cstr)
{
int trimmed_len = std::min<int> (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 + reference 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(llvm::StringMapEntry<uint32_t>) + pos->getKey().size();
}
return mem_size;
}
protected:
//------------------------------------------------------------------
// Typedefs
//------------------------------------------------------------------
typedef llvm::StringMap<uint32_t, llvm::BumpPtrAllocator> StringPool;
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.
//----------------------------------------------------------------------
static Pool &
StringPool()
{
static Pool string_pool;
return string_pool;
}
//----------------------------------------------------------------------
// Default constructor
//
// Initializes the string to an empty string.
//----------------------------------------------------------------------
ConstString::ConstString () :
m_string (NULL)
{
}
//----------------------------------------------------------------------
// Copy constructor
//
// Copies the string value in "rhs" and retains an extra reference
// to the string value in the string pool.
//----------------------------------------------------------------------
ConstString::ConstString (const ConstString& rhs) :
m_string (rhs.m_string)
{
}
//----------------------------------------------------------------------
// Construct with C String value
//
// Constructs this object with a C string by looking to see if the
// C string already exists in the global string pool. If it does
// exist, it retains an extra reference to the string in the string
// pool. If it doesn't exist, it is added to the string pool with
// a reference count of 1.
//----------------------------------------------------------------------
ConstString::ConstString (const char *cstr) :
m_string (StringPool().GetConstCString (cstr))
{
}
//----------------------------------------------------------------------
// Construct with C String value with max length
//
// Constructs this object with a C string with a length. If
// the length of the string is greather than "cstr_len", the
// string length will be truncated. This allows substrings to be
// created without the need to NULL terminate the string as it
// is passed into this function.
//
// If the C string already exists in the global string pool, it
// retains an extra reference to the string in the string
// pool. If it doesn't exist, it is added to the string pool with
// a reference count of 1.
//----------------------------------------------------------------------
ConstString::ConstString (const char *cstr, size_t cstr_len) :
m_string (StringPool().GetConstCStringWithLength (cstr, cstr_len))
{
}
//----------------------------------------------------------------------
// Destructor
//
// Decrements the reference count on the contained string, and if
// the resulting reference count is zero, then the string is removed
// from the string pool. If the reference count is still greater
// than zero, the string will remain in the string pool
//----------------------------------------------------------------------
ConstString::~ConstString ()
{
}
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 the string value "str" to the stream "s"
//----------------------------------------------------------------------
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);
}
//----------------------------------------------------------------------
// Compare two string objects.
//
// Returns:
// -1 if a < b
// 0 if a == b
// 1 if a > b
//----------------------------------------------------------------------
int
ConstString::Compare (const ConstString& lhs, const ConstString& rhs)
{
// If the iterators are the same, this is the same string
register const char *lhs_cstr = lhs.m_string;
register 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
}
//----------------------------------------------------------------------
// Dump the string value to the stream "s". If the contained string
// is empty, print "fail_value" to the stream instead. If
// "fail_value" is NULL, then nothing will be dumped to the
// stream.
//----------------------------------------------------------------------
void
ConstString::Dump(Stream *s, const char *fail_value) const
{
const char *cstr = AsCString (fail_value);
if (cstr)
s->PutCString (cstr);
}
//----------------------------------------------------------------------
// Dump extra debug information to the stream "s".
//----------------------------------------------------------------------
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 = %zu", (int)sizeof(void*) * 2, this, parens, cstr, parens, cstr_len);
}
//----------------------------------------------------------------------
// Set the string value in the object by uniquing the "cstr" string
// value in our global string pool.
//
// If the C string already exists in the global string pool, it
// retains an extra reference to the string in the string
// pool. If it doesn't exist, it is added to the string pool with
// a reference count of 1.
//----------------------------------------------------------------------
void
ConstString::SetCString (const char *cstr)
{
m_string = StringPool().GetConstCString (cstr);
}
//----------------------------------------------------------------------
// Set the string value in the object by uniquing "cstr_len" bytes
// starting at the "cstr" string value in our global string pool.
// If trim is true, then "cstr_len" indicates a maximum length of
// the CString and if the actual length of the string is less, then
// it will be trimmed. If trim is false, then this allows strings
// with NULL characters ('\0') to be added to the string pool.
//
// If the C string already exists in the global string pool, it
// retains an extra reference to the string in the string
// pool. If it doesn't exist, it is added to the string pool with
// a reference count of 1.
//----------------------------------------------------------------------
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);
}
//----------------------------------------------------------------------
// Return the size in bytes that this object takes in memory. The
// resulting size will not include any of the C string values from
// the global string pool (see StaticMemorySize ()).
//----------------------------------------------------------------------
size_t
ConstString::MemorySize() const
{
return sizeof(ConstString);
}
//----------------------------------------------------------------------
// Reports the the size in bytes of all shared C string values,
// containers and reference count values as a byte size for the
// entire string pool.
//----------------------------------------------------------------------
size_t
ConstString::StaticMemorySize()
{
// Get the size of the static string pool
return StringPool().MemorySize();
}