summaryrefslogtreecommitdiffstats
path: root/lldb/source/Core/ConstString.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Core/ConstString.cpp')
-rw-r--r--lldb/source/Core/ConstString.cpp480
1 files changed, 480 insertions, 0 deletions
diff --git a/lldb/source/Core/ConstString.cpp b/lldb/source/Core/ConstString.cpp
new file mode 100644
index 00000000000..c2d09c76461
--- /dev/null
+++ b/lldb/source/Core/ConstString.cpp
@@ -0,0 +1,480 @@
+//===-- 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)
+ {
+ Mutex::Locker locker (m_mutex);
+ llvm::StringRef string_ref (cstr);
+ llvm::StringMapEntry<uint32_t>& entry = m_string_map.GetOrCreateValue (string_ref);
+ const char *ccstr = entry.getKeyData();
+ llvm::StringMapEntry<uint32_t>&reconstituted_entry = GetStringMapEntryFromKeyData (ccstr);
+ assert (&entry == &reconstituted_entry);
+ return ccstr;
+ }
+ 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);
+ const char *ccstr = entry.getKeyData();
+ llvm::StringMapEntry<uint32_t>&reconstituted_entry = GetStringMapEntryFromKeyData (ccstr);
+ assert (&entry == &reconstituted_entry);
+ return ccstr;
+ }
+ return NULL;
+ }
+
+ const char *
+ GetConstTrimmedCStringWithLength (const char *cstr, int cstr_len)
+ {
+ if (cstr)
+ {
+ Mutex::Locker locker (m_mutex);
+ int actual_cstr_len = strlen (cstr);
+ llvm::StringRef string_ref (cstr, std::min<int>(actual_cstr_len, cstr_len));
+ llvm::StringMapEntry<uint32_t>& entry = m_string_map.GetOrCreateValue (string_ref);
+ const char *ccstr = entry.getKeyData();
+ llvm::StringMapEntry<uint32_t>&reconstituted_entry = GetStringMapEntryFromKeyData (ccstr);
+ assert (&entry == &reconstituted_entry);
+ return ccstr;
+ }
+ 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 ()
+{
+}
+
+//----------------------------------------------------------------------
+// Convert to pointer operator. This allows code to check any
+// ConstString objects to see if they contain anything (not empty)
+// valid using code such as:
+//
+// ConstString str(...);
+// if (str)
+// { ...
+//----------------------------------------------------------------------
+ConstString::operator void*() const
+{
+ return IsEmpty() ? NULL : const_cast<ConstString*>(this);
+}
+
+//----------------------------------------------------------------------
+// Assignment operator
+//
+// Assigns the string in this object with the value from "rhs"
+// and increments the reference count of that string.
+//
+// The previously contained string will be get its reference count
+// decremented and removed from the string pool if its reference
+// count reaches zero.
+//----------------------------------------------------------------------
+const ConstString&
+ConstString::operator=(const ConstString& rhs)
+{
+ m_string = rhs.m_string;
+ return *this;
+}
+
+//----------------------------------------------------------------------
+// Equal to operator
+//
+// Returns true if this string is equal to that in "rhs". This is
+// very fast as it results in a pointer comparison since all strings
+// are in a uniqued and reference counted string pool.
+//------------------------------------------------------------------
+bool
+ConstString::operator == (const ConstString& rhs) const
+{
+ // We can do a pointer compare to compare these strings since they
+ // must come from the same pool in order to be equal.
+ return m_string == rhs.m_string;
+}
+
+bool
+ConstString::operator != (const ConstString& rhs) const
+{
+ return m_string != rhs.m_string;
+}
+
+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;
+}
+
+//----------------------------------------------------------------------
+// Get the value of the contained string as a NULL terminated C
+// string value. Return "fail_value" if the string is empty.
+//----------------------------------------------------------------------
+const char *
+ConstString::AsCString(const char *fail_value) const
+{
+ if (m_string == NULL)
+ return fail_value;
+ return m_string;
+}
+
+const char *
+ConstString::GetCString () const
+{
+ return m_string;
+}
+
+size_t
+ConstString::GetLength () const
+{
+ return StringPool().GetConstCStringLength (m_string);
+}
+
+
+//----------------------------------------------------------------------
+// Clear any contained string and reset the value to the an empty
+// string value.
+//
+// The previously contained string will be get its reference count
+// decremented and removed from the string pool if its reference
+// count reaches zero.
+//----------------------------------------------------------------------
+void
+ConstString::Clear ()
+{
+ m_string = NULL;
+}
+
+//----------------------------------------------------------------------
+// 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);
+}
+
+//----------------------------------------------------------------------
+// Returns true if the contained string is empty.
+//----------------------------------------------------------------------
+bool
+ConstString::IsEmpty() const
+{
+ return m_string == NULL || m_string[0] == '\0';
+}
+
+//----------------------------------------------------------------------
+// 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();
+}
OpenPOWER on IntegriCloud