xref: /src/contrib/llvm-project/lldb/source/Utility/ConstString.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1cfca06d7SDimitry Andric //===-- ConstString.cpp ---------------------------------------------------===//
2f034231aSEd Maste //
35f29bb8aSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45f29bb8aSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55f29bb8aSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6f034231aSEd Maste //
7f034231aSEd Maste //===----------------------------------------------------------------------===//
8f3fbd1c0SDimitry Andric 
974a628f7SDimitry Andric #include "lldb/Utility/ConstString.h"
10f3fbd1c0SDimitry Andric 
1174a628f7SDimitry Andric #include "lldb/Utility/Stream.h"
12f3fbd1c0SDimitry Andric 
1314f1b3e8SDimitry Andric #include "llvm/ADT/StringMap.h"
1494994d37SDimitry Andric #include "llvm/ADT/iterator.h"
1594994d37SDimitry Andric #include "llvm/Support/Allocator.h"
1694994d37SDimitry Andric #include "llvm/Support/DJB.h"
1794994d37SDimitry Andric #include "llvm/Support/FormatProviders.h"
18e81d9d49SDimitry Andric #include "llvm/Support/RWMutex.h"
1974a628f7SDimitry Andric #include "llvm/Support/Threading.h"
20f034231aSEd Maste 
2174a628f7SDimitry Andric #include <array>
2294994d37SDimitry Andric #include <utility>
2374a628f7SDimitry Andric 
24344a3780SDimitry Andric #include <cinttypes>
25344a3780SDimitry Andric #include <cstdint>
26344a3780SDimitry Andric #include <cstring>
27205afe67SEd Maste 
28f034231aSEd Maste using namespace lldb_private;
29f034231aSEd Maste 
3014f1b3e8SDimitry Andric class Pool {
31f034231aSEd Maste public:
32cfca06d7SDimitry Andric   /// The default BumpPtrAllocatorImpl slab size.
33cfca06d7SDimitry Andric   static const size_t AllocatorSlabSize = 4096;
34cfca06d7SDimitry Andric   static const size_t SizeThreshold = AllocatorSlabSize;
35cfca06d7SDimitry Andric   /// Every Pool has its own allocator which receives an equal share of
36cfca06d7SDimitry Andric   /// the ConstString allocations. This means that when allocating many
37cfca06d7SDimitry Andric   /// ConstStrings, every allocator sees only its small share of allocations and
38cfca06d7SDimitry Andric   /// assumes LLDB only allocated a small amount of memory so far. In reality
39cfca06d7SDimitry Andric   /// LLDB allocated a total memory that is N times as large as what the
40cfca06d7SDimitry Andric   /// allocator sees (where N is the number of string pools). This causes that
41cfca06d7SDimitry Andric   /// the BumpPtrAllocator continues a long time to allocate memory in small
42cfca06d7SDimitry Andric   /// chunks which only makes sense when allocating a small amount of memory
43cfca06d7SDimitry Andric   /// (which is true from the perspective of a single allocator). On some
44cfca06d7SDimitry Andric   /// systems doing all these small memory allocations causes LLDB to spend
45cfca06d7SDimitry Andric   /// a lot of time in malloc, so we need to force all these allocators to
46cfca06d7SDimitry Andric   /// behave like one allocator in terms of scaling their memory allocations
47cfca06d7SDimitry Andric   /// with increased demand. To do this we set the growth delay for each single
48cfca06d7SDimitry Andric   /// allocator to a rate so that our pool of allocators scales their memory
49cfca06d7SDimitry Andric   /// allocations similar to a single BumpPtrAllocatorImpl.
50cfca06d7SDimitry Andric   ///
51cfca06d7SDimitry Andric   /// Currently we have 256 string pools and the normal growth delay of the
52cfca06d7SDimitry Andric   /// BumpPtrAllocatorImpl is 128 (i.e., the memory allocation size increases
53cfca06d7SDimitry Andric   /// every 128 full chunks), so by changing the delay to 1 we get a
54cfca06d7SDimitry Andric   /// total growth delay in our allocator collection of 256/1 = 256. This is
55cfca06d7SDimitry Andric   /// still only half as fast as a normal allocator but we can't go any faster
56cfca06d7SDimitry Andric   /// without decreasing the number of string pools.
57cfca06d7SDimitry Andric   static const size_t AllocatorGrowthDelay = 1;
58cfca06d7SDimitry Andric   typedef llvm::BumpPtrAllocatorImpl<llvm::MallocAllocator, AllocatorSlabSize,
59cfca06d7SDimitry Andric                                      SizeThreshold, AllocatorGrowthDelay>
60cfca06d7SDimitry Andric       Allocator;
61f034231aSEd Maste   typedef const char *StringPoolValueType;
62cfca06d7SDimitry Andric   typedef llvm::StringMap<StringPoolValueType, Allocator> StringPool;
63f034231aSEd Maste   typedef llvm::StringMapEntry<StringPoolValueType> StringPoolEntryType;
64f034231aSEd Maste 
65f034231aSEd Maste   static StringPoolEntryType &
GetStringMapEntryFromKeyData(const char * keyData)6614f1b3e8SDimitry Andric   GetStringMapEntryFromKeyData(const char *keyData) {
67773dd0e6SDimitry Andric     return StringPoolEntryType::GetStringMapEntryFromKeyData(keyData);
68f034231aSEd Maste   }
69f034231aSEd Maste 
GetConstCStringLength(const char * ccstr)70773dd0e6SDimitry Andric   static size_t GetConstCStringLength(const char *ccstr) {
7114f1b3e8SDimitry Andric     if (ccstr != nullptr) {
72f73363f1SDimitry Andric       // Since the entry is read only, and we derive the entry entirely from
73f73363f1SDimitry Andric       // the pointer, we don't need the lock.
74f034231aSEd Maste       const StringPoolEntryType &entry = GetStringMapEntryFromKeyData(ccstr);
75f034231aSEd Maste       return entry.getKey().size();
76f034231aSEd Maste     }
77f034231aSEd Maste     return 0;
78f034231aSEd Maste   }
79f034231aSEd Maste 
GetMangledCounterpart(const char * ccstr)80ac9a064cSDimitry Andric   StringPoolValueType GetMangledCounterpart(const char *ccstr) {
8114f1b3e8SDimitry Andric     if (ccstr != nullptr) {
82ac9a064cSDimitry Andric       const PoolEntry &pool = selectPool(llvm::StringRef(ccstr));
83ac9a064cSDimitry Andric       llvm::sys::SmartScopedReader<false> rlock(pool.m_mutex);
84f034231aSEd Maste       return GetStringMapEntryFromKeyData(ccstr).getValue();
85e81d9d49SDimitry Andric     }
86f3fbd1c0SDimitry Andric     return nullptr;
87f034231aSEd Maste   }
88f034231aSEd Maste 
GetConstCString(const char * cstr)8914f1b3e8SDimitry Andric   const char *GetConstCString(const char *cstr) {
90f3fbd1c0SDimitry Andric     if (cstr != nullptr)
91f034231aSEd Maste       return GetConstCStringWithLength(cstr, strlen(cstr));
92e81d9d49SDimitry Andric     return nullptr;
93f034231aSEd Maste   }
94f034231aSEd Maste 
GetConstCStringWithLength(const char * cstr,size_t cstr_len)9514f1b3e8SDimitry Andric   const char *GetConstCStringWithLength(const char *cstr, size_t cstr_len) {
96f3fbd1c0SDimitry Andric     if (cstr != nullptr)
97e81d9d49SDimitry Andric       return GetConstCStringWithStringRef(llvm::StringRef(cstr, cstr_len));
98e81d9d49SDimitry Andric     return nullptr;
99f034231aSEd Maste   }
100f034231aSEd Maste 
GetConstCStringWithStringRef(llvm::StringRef string_ref)1017fa27ce4SDimitry Andric   const char *GetConstCStringWithStringRef(llvm::StringRef string_ref) {
10214f1b3e8SDimitry Andric     if (string_ref.data()) {
103ac9a064cSDimitry Andric       const uint32_t string_hash = StringPool::hash(string_ref);
104ac9a064cSDimitry Andric       PoolEntry &pool = selectPool(string_hash);
105e81d9d49SDimitry Andric 
106e81d9d49SDimitry Andric       {
107ac9a064cSDimitry Andric         llvm::sys::SmartScopedReader<false> rlock(pool.m_mutex);
108ac9a064cSDimitry Andric         auto it = pool.m_string_map.find(string_ref, string_hash);
109ac9a064cSDimitry Andric         if (it != pool.m_string_map.end())
110e81d9d49SDimitry Andric           return it->getKeyData();
111e81d9d49SDimitry Andric       }
112e81d9d49SDimitry Andric 
113ac9a064cSDimitry Andric       llvm::sys::SmartScopedWriter<false> wlock(pool.m_mutex);
11414f1b3e8SDimitry Andric       StringPoolEntryType &entry =
115ac9a064cSDimitry Andric           *pool.m_string_map
116ac9a064cSDimitry Andric                .insert(std::make_pair(string_ref, nullptr), string_hash)
11714f1b3e8SDimitry Andric                .first;
118f034231aSEd Maste       return entry.getKeyData();
119f034231aSEd Maste     }
120e81d9d49SDimitry Andric     return nullptr;
121f034231aSEd Maste   }
122f034231aSEd Maste 
123f034231aSEd Maste   const char *
GetConstCStringAndSetMangledCounterPart(llvm::StringRef demangled,const char * mangled_ccstr)12494994d37SDimitry Andric   GetConstCStringAndSetMangledCounterPart(llvm::StringRef demangled,
12514f1b3e8SDimitry Andric                                           const char *mangled_ccstr) {
126e81d9d49SDimitry Andric     const char *demangled_ccstr = nullptr;
127e81d9d49SDimitry Andric 
128e81d9d49SDimitry Andric     {
129ac9a064cSDimitry Andric       const uint32_t demangled_hash = StringPool::hash(demangled);
130ac9a064cSDimitry Andric       PoolEntry &pool = selectPool(demangled_hash);
131ac9a064cSDimitry Andric       llvm::sys::SmartScopedWriter<false> wlock(pool.m_mutex);
132e81d9d49SDimitry Andric 
13394994d37SDimitry Andric       // Make or update string pool entry with the mangled counterpart
134ac9a064cSDimitry Andric       StringPool &map = pool.m_string_map;
135ac9a064cSDimitry Andric       StringPoolEntryType &entry =
136ac9a064cSDimitry Andric           *map.try_emplace_with_hash(demangled, demangled_hash).first;
13794994d37SDimitry Andric 
13894994d37SDimitry Andric       entry.second = mangled_ccstr;
139f034231aSEd Maste 
140f034231aSEd Maste       // Extract the const version of the demangled_cstr
141e81d9d49SDimitry Andric       demangled_ccstr = entry.getKeyData();
142e81d9d49SDimitry Andric     }
143e81d9d49SDimitry Andric 
144e81d9d49SDimitry Andric     {
145f034231aSEd Maste       // Now assign the demangled const string as the counterpart of the
146f034231aSEd Maste       // mangled const string...
147ac9a064cSDimitry Andric       PoolEntry &pool = selectPool(llvm::StringRef(mangled_ccstr));
148ac9a064cSDimitry Andric       llvm::sys::SmartScopedWriter<false> wlock(pool.m_mutex);
149f034231aSEd Maste       GetStringMapEntryFromKeyData(mangled_ccstr).setValue(demangled_ccstr);
150e81d9d49SDimitry Andric     }
151e81d9d49SDimitry Andric 
152f034231aSEd Maste     // Return the constant demangled C string
153f034231aSEd Maste     return demangled_ccstr;
154f034231aSEd Maste   }
155f034231aSEd Maste 
GetConstTrimmedCStringWithLength(const char * cstr,size_t cstr_len)15614f1b3e8SDimitry Andric   const char *GetConstTrimmedCStringWithLength(const char *cstr,
15714f1b3e8SDimitry Andric                                                size_t cstr_len) {
15814f1b3e8SDimitry Andric     if (cstr != nullptr) {
1595f29bb8aSDimitry Andric       const size_t trimmed_len = strnlen(cstr, cstr_len);
160f034231aSEd Maste       return GetConstCStringWithLength(cstr, trimmed_len);
161f034231aSEd Maste     }
162e81d9d49SDimitry Andric     return nullptr;
163f034231aSEd Maste   }
164f034231aSEd Maste 
GetMemoryStats() const1656f8fc217SDimitry Andric   ConstString::MemoryStats GetMemoryStats() const {
1666f8fc217SDimitry Andric     ConstString::MemoryStats stats;
16714f1b3e8SDimitry Andric     for (const auto &pool : m_string_pools) {
168e81d9d49SDimitry Andric       llvm::sys::SmartScopedReader<false> rlock(pool.m_mutex);
1696f8fc217SDimitry Andric       const Allocator &alloc = pool.m_string_map.getAllocator();
1706f8fc217SDimitry Andric       stats.bytes_total += alloc.getTotalMemory();
1716f8fc217SDimitry Andric       stats.bytes_used += alloc.getBytesAllocated();
172f034231aSEd Maste     }
1736f8fc217SDimitry Andric     return stats;
174f034231aSEd Maste   }
175f034231aSEd Maste 
176f034231aSEd Maste protected:
17714f1b3e8SDimitry Andric   struct PoolEntry {
178e81d9d49SDimitry Andric     mutable llvm::sys::SmartRWMutex<false> m_mutex;
179f034231aSEd Maste     StringPool m_string_map;
180f034231aSEd Maste   };
181f034231aSEd Maste 
182e81d9d49SDimitry Andric   std::array<PoolEntry, 256> m_string_pools;
183ac9a064cSDimitry Andric 
selectPool(const llvm::StringRef & s)184ac9a064cSDimitry Andric   PoolEntry &selectPool(const llvm::StringRef &s) {
185ac9a064cSDimitry Andric     return selectPool(StringPool::hash(s));
186ac9a064cSDimitry Andric   }
187ac9a064cSDimitry Andric 
selectPool(uint32_t h)188ac9a064cSDimitry Andric   PoolEntry &selectPool(uint32_t h) {
189ac9a064cSDimitry Andric     return m_string_pools[((h >> 24) ^ (h >> 16) ^ (h >> 8) ^ h) & 0xff];
190ac9a064cSDimitry Andric   }
191e81d9d49SDimitry Andric };
192e81d9d49SDimitry Andric 
193f73363f1SDimitry Andric // Frameworks and dylibs aren't supposed to have global C++ initializers so we
194f73363f1SDimitry Andric // hide the string pool in a static function so that it will get initialized on
195f73363f1SDimitry Andric // the first call to this static function.
196f034231aSEd Maste //
197f73363f1SDimitry Andric // Note, for now we make the string pool a pointer to the pool, because we
198f73363f1SDimitry Andric // can't guarantee that some objects won't get destroyed after the global
199f73363f1SDimitry Andric // destructor chain is run, and trying to make sure no destructors touch
200f73363f1SDimitry Andric // ConstStrings is difficult.  So we leak the pool instead.
StringPool()20114f1b3e8SDimitry Andric static Pool &StringPool() {
20274a628f7SDimitry Andric   static llvm::once_flag g_pool_initialization_flag;
203e81d9d49SDimitry Andric   static Pool *g_string_pool = nullptr;
204f034231aSEd Maste 
20574a628f7SDimitry Andric   llvm::call_once(g_pool_initialization_flag,
20614f1b3e8SDimitry Andric                   []() { g_string_pool = new Pool(); });
207f034231aSEd Maste 
208f034231aSEd Maste   return *g_string_pool;
209f034231aSEd Maste }
210f034231aSEd Maste 
ConstString(const char * cstr)21114f1b3e8SDimitry Andric ConstString::ConstString(const char *cstr)
21214f1b3e8SDimitry Andric     : m_string(StringPool().GetConstCString(cstr)) {}
213f034231aSEd Maste 
ConstString(const char * cstr,size_t cstr_len)21414f1b3e8SDimitry Andric ConstString::ConstString(const char *cstr, size_t cstr_len)
21514f1b3e8SDimitry Andric     : m_string(StringPool().GetConstCStringWithLength(cstr, cstr_len)) {}
216f034231aSEd Maste 
ConstString(llvm::StringRef s)2177fa27ce4SDimitry Andric ConstString::ConstString(llvm::StringRef s)
2185f29bb8aSDimitry Andric     : m_string(StringPool().GetConstCStringWithStringRef(s)) {}
219f034231aSEd Maste 
operator <(ConstString rhs) const2205f29bb8aSDimitry Andric bool ConstString::operator<(ConstString rhs) const {
221f034231aSEd Maste   if (m_string == rhs.m_string)
222f034231aSEd Maste     return false;
223f034231aSEd Maste 
224773dd0e6SDimitry Andric   llvm::StringRef lhs_string_ref(GetStringRef());
225773dd0e6SDimitry Andric   llvm::StringRef rhs_string_ref(rhs.GetStringRef());
226f034231aSEd Maste 
227f034231aSEd Maste   // If both have valid C strings, then return the comparison
228f034231aSEd Maste   if (lhs_string_ref.data() && rhs_string_ref.data())
229f034231aSEd Maste     return lhs_string_ref < rhs_string_ref;
230f034231aSEd Maste 
231e81d9d49SDimitry Andric   // Else one of them was nullptr, so if LHS is nullptr then it is less than
232e81d9d49SDimitry Andric   return lhs_string_ref.data() == nullptr;
233f034231aSEd Maste }
234f034231aSEd Maste 
operator <<(Stream & s,ConstString str)2355f29bb8aSDimitry Andric Stream &lldb_private::operator<<(Stream &s, ConstString str) {
236f034231aSEd Maste   const char *cstr = str.GetCString();
237f3fbd1c0SDimitry Andric   if (cstr != nullptr)
238f034231aSEd Maste     s << cstr;
239f034231aSEd Maste 
240f034231aSEd Maste   return s;
241f034231aSEd Maste }
242f034231aSEd Maste 
GetLength() const24314f1b3e8SDimitry Andric size_t ConstString::GetLength() const {
244773dd0e6SDimitry Andric   return Pool::GetConstCStringLength(m_string);
245f034231aSEd Maste }
246f034231aSEd Maste 
Equals(ConstString lhs,ConstString rhs,const bool case_sensitive)2475f29bb8aSDimitry Andric bool ConstString::Equals(ConstString lhs, ConstString rhs,
24814f1b3e8SDimitry Andric                          const bool case_sensitive) {
249f3fbd1c0SDimitry Andric   if (lhs.m_string == rhs.m_string)
250f3fbd1c0SDimitry Andric     return true;
251f3fbd1c0SDimitry Andric 
25214f1b3e8SDimitry Andric   // Since the pointers weren't equal, and identical ConstStrings always have
253f73363f1SDimitry Andric   // identical pointers, the result must be false for case sensitive equality
254f73363f1SDimitry Andric   // test.
255f3fbd1c0SDimitry Andric   if (case_sensitive)
256f3fbd1c0SDimitry Andric     return false;
257f3fbd1c0SDimitry Andric 
258f3fbd1c0SDimitry Andric   // perform case insensitive equality test
259773dd0e6SDimitry Andric   llvm::StringRef lhs_string_ref(lhs.GetStringRef());
260773dd0e6SDimitry Andric   llvm::StringRef rhs_string_ref(rhs.GetStringRef());
261344a3780SDimitry Andric   return lhs_string_ref.equals_insensitive(rhs_string_ref);
262f3fbd1c0SDimitry Andric }
263f3fbd1c0SDimitry Andric 
Compare(ConstString lhs,ConstString rhs,const bool case_sensitive)2645f29bb8aSDimitry Andric int ConstString::Compare(ConstString lhs, ConstString rhs,
26514f1b3e8SDimitry Andric                          const bool case_sensitive) {
266f034231aSEd Maste   // If the iterators are the same, this is the same string
267f21a844fSEd Maste   const char *lhs_cstr = lhs.m_string;
268f21a844fSEd Maste   const char *rhs_cstr = rhs.m_string;
269f034231aSEd Maste   if (lhs_cstr == rhs_cstr)
270f034231aSEd Maste     return 0;
27114f1b3e8SDimitry Andric   if (lhs_cstr && rhs_cstr) {
272773dd0e6SDimitry Andric     llvm::StringRef lhs_string_ref(lhs.GetStringRef());
273773dd0e6SDimitry Andric     llvm::StringRef rhs_string_ref(rhs.GetStringRef());
274f3fbd1c0SDimitry Andric 
27514f1b3e8SDimitry Andric     if (case_sensitive) {
276f034231aSEd Maste       return lhs_string_ref.compare(rhs_string_ref);
27714f1b3e8SDimitry Andric     } else {
278344a3780SDimitry Andric       return lhs_string_ref.compare_insensitive(rhs_string_ref);
279f3fbd1c0SDimitry Andric     }
280f3fbd1c0SDimitry Andric   }
281f034231aSEd Maste 
282f034231aSEd Maste   if (lhs_cstr)
283f3fbd1c0SDimitry Andric     return +1; // LHS isn't nullptr but RHS is
284f034231aSEd Maste   else
285f3fbd1c0SDimitry Andric     return -1; // LHS is nullptr but RHS isn't
286f034231aSEd Maste }
287f034231aSEd Maste 
Dump(Stream * s,const char * fail_value) const28814f1b3e8SDimitry Andric void ConstString::Dump(Stream *s, const char *fail_value) const {
28914f1b3e8SDimitry Andric   if (s != nullptr) {
290f034231aSEd Maste     const char *cstr = AsCString(fail_value);
291f3fbd1c0SDimitry Andric     if (cstr != nullptr)
292f034231aSEd Maste       s->PutCString(cstr);
293f034231aSEd Maste   }
294f034231aSEd Maste }
295f034231aSEd Maste 
DumpDebug(Stream * s) const29614f1b3e8SDimitry Andric void ConstString::DumpDebug(Stream *s) const {
297f034231aSEd Maste   const char *cstr = GetCString();
298f034231aSEd Maste   size_t cstr_len = GetLength();
299f3fbd1c0SDimitry Andric   // Only print the parens if we have a non-nullptr string
300f034231aSEd Maste   const char *parens = cstr ? "\"" : "";
3010cac4ca3SEd Maste   s->Printf("%*p: ConstString, string = %s%s%s, length = %" PRIu64,
3020cac4ca3SEd Maste             static_cast<int>(sizeof(void *) * 2),
3030cac4ca3SEd Maste             static_cast<const void *>(this), parens, cstr, parens,
3040cac4ca3SEd Maste             static_cast<uint64_t>(cstr_len));
305f034231aSEd Maste }
306f034231aSEd Maste 
SetCString(const char * cstr)30714f1b3e8SDimitry Andric void ConstString::SetCString(const char *cstr) {
308f034231aSEd Maste   m_string = StringPool().GetConstCString(cstr);
309f034231aSEd Maste }
310f034231aSEd Maste 
SetString(llvm::StringRef s)3117fa27ce4SDimitry Andric void ConstString::SetString(llvm::StringRef s) {
3127fa27ce4SDimitry Andric   m_string = StringPool().GetConstCStringWithStringRef(s);
313f034231aSEd Maste }
314f034231aSEd Maste 
SetStringWithMangledCounterpart(llvm::StringRef demangled,ConstString mangled)31594994d37SDimitry Andric void ConstString::SetStringWithMangledCounterpart(llvm::StringRef demangled,
3165f29bb8aSDimitry Andric                                                   ConstString mangled) {
31714f1b3e8SDimitry Andric   m_string = StringPool().GetConstCStringAndSetMangledCounterPart(
31814f1b3e8SDimitry Andric       demangled, mangled.m_string);
319f034231aSEd Maste }
320f034231aSEd Maste 
GetMangledCounterpart(ConstString & counterpart) const32114f1b3e8SDimitry Andric bool ConstString::GetMangledCounterpart(ConstString &counterpart) const {
322f034231aSEd Maste   counterpart.m_string = StringPool().GetMangledCounterpart(m_string);
323f21a844fSEd Maste   return (bool)counterpart;
324f034231aSEd Maste }
325f034231aSEd Maste 
SetCStringWithLength(const char * cstr,size_t cstr_len)32614f1b3e8SDimitry Andric void ConstString::SetCStringWithLength(const char *cstr, size_t cstr_len) {
327f034231aSEd Maste   m_string = StringPool().GetConstCStringWithLength(cstr, cstr_len);
328f034231aSEd Maste }
329f034231aSEd Maste 
SetTrimmedCStringWithLength(const char * cstr,size_t cstr_len)33014f1b3e8SDimitry Andric void ConstString::SetTrimmedCStringWithLength(const char *cstr,
33114f1b3e8SDimitry Andric                                               size_t cstr_len) {
332f034231aSEd Maste   m_string = StringPool().GetConstTrimmedCStringWithLength(cstr, cstr_len);
333f034231aSEd Maste }
334f034231aSEd Maste 
GetMemoryStats()3356f8fc217SDimitry Andric ConstString::MemoryStats ConstString::GetMemoryStats() {
3366f8fc217SDimitry Andric   return StringPool().GetMemoryStats();
337f034231aSEd Maste }
33874a628f7SDimitry Andric 
format(const ConstString & CS,llvm::raw_ostream & OS,llvm::StringRef Options)33974a628f7SDimitry Andric void llvm::format_provider<ConstString>::format(const ConstString &CS,
34074a628f7SDimitry Andric                                                 llvm::raw_ostream &OS,
34174a628f7SDimitry Andric                                                 llvm::StringRef Options) {
342cfca06d7SDimitry Andric   format_provider<StringRef>::format(CS.GetStringRef(), OS, Options);
343cfca06d7SDimitry Andric }
344