370 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			370 lines
		
	
	
		
			13 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;
 | 
						|
 | 
						|
 | 
						|
//----------------------------------------------------------------------
 | 
						|
// 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();
 | 
						|
}
 |