180814287SRaphael Isemann //===-- ConstString.cpp ---------------------------------------------------===//
2bf9a7730SZachary Turner //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6bf9a7730SZachary Turner //
7bf9a7730SZachary Turner //===----------------------------------------------------------------------===//
8bf9a7730SZachary Turner
9bf9a7730SZachary Turner #include "lldb/Utility/ConstString.h"
10bf9a7730SZachary Turner
114479ac15SZachary Turner #include "lldb/Utility/Stream.h"
12bf9a7730SZachary Turner
13bf9a7730SZachary Turner #include "llvm/ADT/StringMap.h"
14672d2c12SJonas Devlieghere #include "llvm/ADT/iterator.h"
15672d2c12SJonas Devlieghere #include "llvm/Support/Allocator.h"
16672d2c12SJonas Devlieghere #include "llvm/Support/DJB.h"
17672d2c12SJonas Devlieghere #include "llvm/Support/FormatProviders.h"
18bf9a7730SZachary Turner #include "llvm/Support/RWMutex.h"
19c5f28e2aSKamil Rytarowski #include "llvm/Support/Threading.h"
204479ac15SZachary Turner
214479ac15SZachary Turner #include <array>
22672d2c12SJonas Devlieghere #include <utility>
234479ac15SZachary Turner
2476e47d48SRaphael Isemann #include <cinttypes>
2576e47d48SRaphael Isemann #include <cstdint>
2676e47d48SRaphael Isemann #include <cstring>
27bf9a7730SZachary Turner
28bf9a7730SZachary Turner using namespace lldb_private;
29bf9a7730SZachary Turner
30bf9a7730SZachary Turner class Pool {
31bf9a7730SZachary Turner public:
32fad012bcSRaphael Isemann /// The default BumpPtrAllocatorImpl slab size.
33fad012bcSRaphael Isemann static const size_t AllocatorSlabSize = 4096;
34fad012bcSRaphael Isemann static const size_t SizeThreshold = AllocatorSlabSize;
35fad012bcSRaphael Isemann /// Every Pool has its own allocator which receives an equal share of
36fad012bcSRaphael Isemann /// the ConstString allocations. This means that when allocating many
37fad012bcSRaphael Isemann /// ConstStrings, every allocator sees only its small share of allocations and
38fad012bcSRaphael Isemann /// assumes LLDB only allocated a small amount of memory so far. In reality
39fad012bcSRaphael Isemann /// LLDB allocated a total memory that is N times as large as what the
40fad012bcSRaphael Isemann /// allocator sees (where N is the number of string pools). This causes that
41fad012bcSRaphael Isemann /// the BumpPtrAllocator continues a long time to allocate memory in small
42fad012bcSRaphael Isemann /// chunks which only makes sense when allocating a small amount of memory
43fad012bcSRaphael Isemann /// (which is true from the perspective of a single allocator). On some
44fad012bcSRaphael Isemann /// systems doing all these small memory allocations causes LLDB to spend
45fad012bcSRaphael Isemann /// a lot of time in malloc, so we need to force all these allocators to
46fad012bcSRaphael Isemann /// behave like one allocator in terms of scaling their memory allocations
47fad012bcSRaphael Isemann /// with increased demand. To do this we set the growth delay for each single
48fad012bcSRaphael Isemann /// allocator to a rate so that our pool of allocators scales their memory
49fad012bcSRaphael Isemann /// allocations similar to a single BumpPtrAllocatorImpl.
50fad012bcSRaphael Isemann ///
51fad012bcSRaphael Isemann /// Currently we have 256 string pools and the normal growth delay of the
52fad012bcSRaphael Isemann /// BumpPtrAllocatorImpl is 128 (i.e., the memory allocation size increases
53fad012bcSRaphael Isemann /// every 128 full chunks), so by changing the delay to 1 we get a
54fad012bcSRaphael Isemann /// total growth delay in our allocator collection of 256/1 = 256. This is
55fad012bcSRaphael Isemann /// still only half as fast as a normal allocator but we can't go any faster
56fad012bcSRaphael Isemann /// without decreasing the number of string pools.
57fad012bcSRaphael Isemann static const size_t AllocatorGrowthDelay = 1;
58fad012bcSRaphael Isemann typedef llvm::BumpPtrAllocatorImpl<llvm::MallocAllocator, AllocatorSlabSize,
59fad012bcSRaphael Isemann SizeThreshold, AllocatorGrowthDelay>
60fad012bcSRaphael Isemann Allocator;
61bf9a7730SZachary Turner typedef const char *StringPoolValueType;
62fad012bcSRaphael Isemann typedef llvm::StringMap<StringPoolValueType, Allocator> StringPool;
63bf9a7730SZachary Turner typedef llvm::StringMapEntry<StringPoolValueType> StringPoolEntryType;
64bf9a7730SZachary Turner
65bf9a7730SZachary Turner static StringPoolEntryType &
GetStringMapEntryFromKeyData(const char * keyData)66bf9a7730SZachary Turner GetStringMapEntryFromKeyData(const char *keyData) {
678070bf0aSPavel Labath return StringPoolEntryType::GetStringMapEntryFromKeyData(keyData);
68bf9a7730SZachary Turner }
69bf9a7730SZachary Turner
GetConstCStringLength(const char * ccstr)708070bf0aSPavel Labath static size_t GetConstCStringLength(const char *ccstr) {
71bf9a7730SZachary Turner if (ccstr != nullptr) {
7205097246SAdrian Prantl // Since the entry is read only, and we derive the entry entirely from
7305097246SAdrian Prantl // the pointer, we don't need the lock.
74bf9a7730SZachary Turner const StringPoolEntryType &entry = GetStringMapEntryFromKeyData(ccstr);
75bf9a7730SZachary Turner return entry.getKey().size();
76bf9a7730SZachary Turner }
77bf9a7730SZachary Turner return 0;
78bf9a7730SZachary Turner }
79bf9a7730SZachary Turner
GetMangledCounterpart(const char * ccstr) const80bf9a7730SZachary Turner StringPoolValueType GetMangledCounterpart(const char *ccstr) const {
81bf9a7730SZachary Turner if (ccstr != nullptr) {
82bf9a7730SZachary Turner const uint8_t h = hash(llvm::StringRef(ccstr));
83bf9a7730SZachary Turner llvm::sys::SmartScopedReader<false> rlock(m_string_pools[h].m_mutex);
84bf9a7730SZachary Turner return GetStringMapEntryFromKeyData(ccstr).getValue();
85bf9a7730SZachary Turner }
86bf9a7730SZachary Turner return nullptr;
87bf9a7730SZachary Turner }
88bf9a7730SZachary Turner
GetConstCString(const char * cstr)89bf9a7730SZachary Turner const char *GetConstCString(const char *cstr) {
90bf9a7730SZachary Turner if (cstr != nullptr)
91bf9a7730SZachary Turner return GetConstCStringWithLength(cstr, strlen(cstr));
92bf9a7730SZachary Turner return nullptr;
93bf9a7730SZachary Turner }
94bf9a7730SZachary Turner
GetConstCStringWithLength(const char * cstr,size_t cstr_len)95bf9a7730SZachary Turner const char *GetConstCStringWithLength(const char *cstr, size_t cstr_len) {
96bf9a7730SZachary Turner if (cstr != nullptr)
97bf9a7730SZachary Turner return GetConstCStringWithStringRef(llvm::StringRef(cstr, cstr_len));
98bf9a7730SZachary Turner return nullptr;
99bf9a7730SZachary Turner }
100bf9a7730SZachary Turner
GetConstCStringWithStringRef(const llvm::StringRef & string_ref)101bf9a7730SZachary Turner const char *GetConstCStringWithStringRef(const llvm::StringRef &string_ref) {
102bf9a7730SZachary Turner if (string_ref.data()) {
103bf9a7730SZachary Turner const uint8_t h = hash(string_ref);
104bf9a7730SZachary Turner
105bf9a7730SZachary Turner {
106bf9a7730SZachary Turner llvm::sys::SmartScopedReader<false> rlock(m_string_pools[h].m_mutex);
107bf9a7730SZachary Turner auto it = m_string_pools[h].m_string_map.find(string_ref);
108bf9a7730SZachary Turner if (it != m_string_pools[h].m_string_map.end())
109bf9a7730SZachary Turner return it->getKeyData();
110bf9a7730SZachary Turner }
111bf9a7730SZachary Turner
112bf9a7730SZachary Turner llvm::sys::SmartScopedWriter<false> wlock(m_string_pools[h].m_mutex);
113bf9a7730SZachary Turner StringPoolEntryType &entry =
114bf9a7730SZachary Turner *m_string_pools[h]
115bf9a7730SZachary Turner .m_string_map.insert(std::make_pair(string_ref, nullptr))
116bf9a7730SZachary Turner .first;
117bf9a7730SZachary Turner return entry.getKeyData();
118bf9a7730SZachary Turner }
119bf9a7730SZachary Turner return nullptr;
120bf9a7730SZachary Turner }
121bf9a7730SZachary Turner
122bf9a7730SZachary Turner const char *
GetConstCStringAndSetMangledCounterPart(llvm::StringRef demangled,const char * mangled_ccstr)12319a357adSPavel Labath GetConstCStringAndSetMangledCounterPart(llvm::StringRef demangled,
124bf9a7730SZachary Turner const char *mangled_ccstr) {
125bf9a7730SZachary Turner const char *demangled_ccstr = nullptr;
126bf9a7730SZachary Turner
127bf9a7730SZachary Turner {
12819a357adSPavel Labath const uint8_t h = hash(demangled);
129bf9a7730SZachary Turner llvm::sys::SmartScopedWriter<false> wlock(m_string_pools[h].m_mutex);
130bf9a7730SZachary Turner
1312397a2b6SStefan Granitz // Make or update string pool entry with the mangled counterpart
1322397a2b6SStefan Granitz StringPool &map = m_string_pools[h].m_string_map;
1332397a2b6SStefan Granitz StringPoolEntryType &entry = *map.try_emplace(demangled).first;
1342397a2b6SStefan Granitz
1352397a2b6SStefan Granitz entry.second = mangled_ccstr;
136bf9a7730SZachary Turner
137bf9a7730SZachary Turner // Extract the const version of the demangled_cstr
138bf9a7730SZachary Turner demangled_ccstr = entry.getKeyData();
139bf9a7730SZachary Turner }
140bf9a7730SZachary Turner
141bf9a7730SZachary Turner {
142bf9a7730SZachary Turner // Now assign the demangled const string as the counterpart of the
143bf9a7730SZachary Turner // mangled const string...
144bf9a7730SZachary Turner const uint8_t h = hash(llvm::StringRef(mangled_ccstr));
145bf9a7730SZachary Turner llvm::sys::SmartScopedWriter<false> wlock(m_string_pools[h].m_mutex);
146bf9a7730SZachary Turner GetStringMapEntryFromKeyData(mangled_ccstr).setValue(demangled_ccstr);
147bf9a7730SZachary Turner }
148bf9a7730SZachary Turner
149bf9a7730SZachary Turner // Return the constant demangled C string
150bf9a7730SZachary Turner return demangled_ccstr;
151bf9a7730SZachary Turner }
152bf9a7730SZachary Turner
GetConstTrimmedCStringWithLength(const char * cstr,size_t cstr_len)153bf9a7730SZachary Turner const char *GetConstTrimmedCStringWithLength(const char *cstr,
154bf9a7730SZachary Turner size_t cstr_len) {
155bf9a7730SZachary Turner if (cstr != nullptr) {
156bb3609e4SJan Kratochvil const size_t trimmed_len = strnlen(cstr, cstr_len);
157bf9a7730SZachary Turner return GetConstCStringWithLength(cstr, trimmed_len);
158bf9a7730SZachary Turner }
159bf9a7730SZachary Turner return nullptr;
160bf9a7730SZachary Turner }
161bf9a7730SZachary Turner
GetMemoryStats() const162*cd8122b2SJonas Devlieghere ConstString::MemoryStats GetMemoryStats() const {
163*cd8122b2SJonas Devlieghere ConstString::MemoryStats stats;
164*cd8122b2SJonas Devlieghere for (const auto &pool : m_string_pools) {
165*cd8122b2SJonas Devlieghere llvm::sys::SmartScopedReader<false> rlock(pool.m_mutex);
166*cd8122b2SJonas Devlieghere const Allocator &alloc = pool.m_string_map.getAllocator();
167*cd8122b2SJonas Devlieghere stats.bytes_total += alloc.getTotalMemory();
168*cd8122b2SJonas Devlieghere stats.bytes_used += alloc.getBytesAllocated();
169*cd8122b2SJonas Devlieghere }
170*cd8122b2SJonas Devlieghere return stats;
171*cd8122b2SJonas Devlieghere }
172*cd8122b2SJonas Devlieghere
173bf9a7730SZachary Turner protected:
hash(const llvm::StringRef & s) const174bf9a7730SZachary Turner uint8_t hash(const llvm::StringRef &s) const {
175560ce2c7SJonas Devlieghere uint32_t h = llvm::djbHash(s);
176bf9a7730SZachary Turner return ((h >> 24) ^ (h >> 16) ^ (h >> 8) ^ h) & 0xff;
177bf9a7730SZachary Turner }
178bf9a7730SZachary Turner
179bf9a7730SZachary Turner struct PoolEntry {
180bf9a7730SZachary Turner mutable llvm::sys::SmartRWMutex<false> m_mutex;
181755420c0SRaphael Isemann StringPool m_string_map;
182bf9a7730SZachary Turner };
183bf9a7730SZachary Turner
184bf9a7730SZachary Turner std::array<PoolEntry, 256> m_string_pools;
185bf9a7730SZachary Turner };
186bf9a7730SZachary Turner
18705097246SAdrian Prantl // Frameworks and dylibs aren't supposed to have global C++ initializers so we
18805097246SAdrian Prantl // hide the string pool in a static function so that it will get initialized on
18905097246SAdrian Prantl // the first call to this static function.
190bf9a7730SZachary Turner //
19105097246SAdrian Prantl // Note, for now we make the string pool a pointer to the pool, because we
19205097246SAdrian Prantl // can't guarantee that some objects won't get destroyed after the global
19305097246SAdrian Prantl // destructor chain is run, and trying to make sure no destructors touch
19405097246SAdrian Prantl // ConstStrings is difficult. So we leak the pool instead.
StringPool()195bf9a7730SZachary Turner static Pool &StringPool() {
196c5f28e2aSKamil Rytarowski static llvm::once_flag g_pool_initialization_flag;
197bf9a7730SZachary Turner static Pool *g_string_pool = nullptr;
198bf9a7730SZachary Turner
199c5f28e2aSKamil Rytarowski llvm::call_once(g_pool_initialization_flag,
200bf9a7730SZachary Turner []() { g_string_pool = new Pool(); });
201bf9a7730SZachary Turner
202bf9a7730SZachary Turner return *g_string_pool;
203bf9a7730SZachary Turner }
204bf9a7730SZachary Turner
ConstString(const char * cstr)205bf9a7730SZachary Turner ConstString::ConstString(const char *cstr)
206bf9a7730SZachary Turner : m_string(StringPool().GetConstCString(cstr)) {}
207bf9a7730SZachary Turner
ConstString(const char * cstr,size_t cstr_len)208bf9a7730SZachary Turner ConstString::ConstString(const char *cstr, size_t cstr_len)
209bf9a7730SZachary Turner : m_string(StringPool().GetConstCStringWithLength(cstr, cstr_len)) {}
210bf9a7730SZachary Turner
ConstString(const llvm::StringRef & s)211bf9a7730SZachary Turner ConstString::ConstString(const llvm::StringRef &s)
21212886f04SRaphael Isemann : m_string(StringPool().GetConstCStringWithStringRef(s)) {}
213bf9a7730SZachary Turner
operator <(ConstString rhs) const214ccdb5b4bSJonas Devlieghere bool ConstString::operator<(ConstString rhs) const {
215bf9a7730SZachary Turner if (m_string == rhs.m_string)
216bf9a7730SZachary Turner return false;
217bf9a7730SZachary Turner
2188070bf0aSPavel Labath llvm::StringRef lhs_string_ref(GetStringRef());
2198070bf0aSPavel Labath llvm::StringRef rhs_string_ref(rhs.GetStringRef());
220bf9a7730SZachary Turner
221bf9a7730SZachary Turner // If both have valid C strings, then return the comparison
222bf9a7730SZachary Turner if (lhs_string_ref.data() && rhs_string_ref.data())
223bf9a7730SZachary Turner return lhs_string_ref < rhs_string_ref;
224bf9a7730SZachary Turner
225bf9a7730SZachary Turner // Else one of them was nullptr, so if LHS is nullptr then it is less than
226bf9a7730SZachary Turner return lhs_string_ref.data() == nullptr;
227bf9a7730SZachary Turner }
228bf9a7730SZachary Turner
operator <<(Stream & s,ConstString str)229ccdb5b4bSJonas Devlieghere Stream &lldb_private::operator<<(Stream &s, ConstString str) {
230bf9a7730SZachary Turner const char *cstr = str.GetCString();
231bf9a7730SZachary Turner if (cstr != nullptr)
232bf9a7730SZachary Turner s << cstr;
233bf9a7730SZachary Turner
234bf9a7730SZachary Turner return s;
235bf9a7730SZachary Turner }
236bf9a7730SZachary Turner
GetLength() const237bf9a7730SZachary Turner size_t ConstString::GetLength() const {
2388070bf0aSPavel Labath return Pool::GetConstCStringLength(m_string);
239bf9a7730SZachary Turner }
240bf9a7730SZachary Turner
Equals(ConstString lhs,ConstString rhs,const bool case_sensitive)241ccdb5b4bSJonas Devlieghere bool ConstString::Equals(ConstString lhs, ConstString rhs,
242bf9a7730SZachary Turner const bool case_sensitive) {
243bf9a7730SZachary Turner if (lhs.m_string == rhs.m_string)
244bf9a7730SZachary Turner return true;
245bf9a7730SZachary Turner
246bf9a7730SZachary Turner // Since the pointers weren't equal, and identical ConstStrings always have
24705097246SAdrian Prantl // identical pointers, the result must be false for case sensitive equality
24805097246SAdrian Prantl // test.
249bf9a7730SZachary Turner if (case_sensitive)
250bf9a7730SZachary Turner return false;
251bf9a7730SZachary Turner
252bf9a7730SZachary Turner // perform case insensitive equality test
2538070bf0aSPavel Labath llvm::StringRef lhs_string_ref(lhs.GetStringRef());
2548070bf0aSPavel Labath llvm::StringRef rhs_string_ref(rhs.GetStringRef());
255e50f9c41SMartin Storsjö return lhs_string_ref.equals_insensitive(rhs_string_ref);
256bf9a7730SZachary Turner }
257bf9a7730SZachary Turner
Compare(ConstString lhs,ConstString rhs,const bool case_sensitive)258ccdb5b4bSJonas Devlieghere int ConstString::Compare(ConstString lhs, ConstString rhs,
259bf9a7730SZachary Turner const bool case_sensitive) {
260bf9a7730SZachary Turner // If the iterators are the same, this is the same string
261bf9a7730SZachary Turner const char *lhs_cstr = lhs.m_string;
262bf9a7730SZachary Turner const char *rhs_cstr = rhs.m_string;
263bf9a7730SZachary Turner if (lhs_cstr == rhs_cstr)
264bf9a7730SZachary Turner return 0;
265bf9a7730SZachary Turner if (lhs_cstr && rhs_cstr) {
2668070bf0aSPavel Labath llvm::StringRef lhs_string_ref(lhs.GetStringRef());
2678070bf0aSPavel Labath llvm::StringRef rhs_string_ref(rhs.GetStringRef());
268bf9a7730SZachary Turner
269bf9a7730SZachary Turner if (case_sensitive) {
270bf9a7730SZachary Turner return lhs_string_ref.compare(rhs_string_ref);
271bf9a7730SZachary Turner } else {
272e50f9c41SMartin Storsjö return lhs_string_ref.compare_insensitive(rhs_string_ref);
273bf9a7730SZachary Turner }
274bf9a7730SZachary Turner }
275bf9a7730SZachary Turner
276bf9a7730SZachary Turner if (lhs_cstr)
277bf9a7730SZachary Turner return +1; // LHS isn't nullptr but RHS is
278bf9a7730SZachary Turner else
279bf9a7730SZachary Turner return -1; // LHS is nullptr but RHS isn't
280bf9a7730SZachary Turner }
281bf9a7730SZachary Turner
Dump(Stream * s,const char * fail_value) const282bf9a7730SZachary Turner void ConstString::Dump(Stream *s, const char *fail_value) const {
283bf9a7730SZachary Turner if (s != nullptr) {
284bf9a7730SZachary Turner const char *cstr = AsCString(fail_value);
285bf9a7730SZachary Turner if (cstr != nullptr)
286bf9a7730SZachary Turner s->PutCString(cstr);
287bf9a7730SZachary Turner }
288bf9a7730SZachary Turner }
289bf9a7730SZachary Turner
DumpDebug(Stream * s) const290bf9a7730SZachary Turner void ConstString::DumpDebug(Stream *s) const {
291bf9a7730SZachary Turner const char *cstr = GetCString();
292bf9a7730SZachary Turner size_t cstr_len = GetLength();
293bf9a7730SZachary Turner // Only print the parens if we have a non-nullptr string
294bf9a7730SZachary Turner const char *parens = cstr ? "\"" : "";
295bf9a7730SZachary Turner s->Printf("%*p: ConstString, string = %s%s%s, length = %" PRIu64,
296bf9a7730SZachary Turner static_cast<int>(sizeof(void *) * 2),
297bf9a7730SZachary Turner static_cast<const void *>(this), parens, cstr, parens,
298bf9a7730SZachary Turner static_cast<uint64_t>(cstr_len));
299bf9a7730SZachary Turner }
300bf9a7730SZachary Turner
SetCString(const char * cstr)301bf9a7730SZachary Turner void ConstString::SetCString(const char *cstr) {
302bf9a7730SZachary Turner m_string = StringPool().GetConstCString(cstr);
303bf9a7730SZachary Turner }
304bf9a7730SZachary Turner
SetString(const llvm::StringRef & s)305bf9a7730SZachary Turner void ConstString::SetString(const llvm::StringRef &s) {
306bf9a7730SZachary Turner m_string = StringPool().GetConstCStringWithLength(s.data(), s.size());
307bf9a7730SZachary Turner }
308bf9a7730SZachary Turner
SetStringWithMangledCounterpart(llvm::StringRef demangled,ConstString mangled)30919a357adSPavel Labath void ConstString::SetStringWithMangledCounterpart(llvm::StringRef demangled,
310ccdb5b4bSJonas Devlieghere ConstString mangled) {
311bf9a7730SZachary Turner m_string = StringPool().GetConstCStringAndSetMangledCounterPart(
312bf9a7730SZachary Turner demangled, mangled.m_string);
313bf9a7730SZachary Turner }
314bf9a7730SZachary Turner
GetMangledCounterpart(ConstString & counterpart) const315bf9a7730SZachary Turner bool ConstString::GetMangledCounterpart(ConstString &counterpart) const {
316bf9a7730SZachary Turner counterpart.m_string = StringPool().GetMangledCounterpart(m_string);
317bf9a7730SZachary Turner return (bool)counterpart;
318bf9a7730SZachary Turner }
319bf9a7730SZachary Turner
SetCStringWithLength(const char * cstr,size_t cstr_len)320bf9a7730SZachary Turner void ConstString::SetCStringWithLength(const char *cstr, size_t cstr_len) {
321bf9a7730SZachary Turner m_string = StringPool().GetConstCStringWithLength(cstr, cstr_len);
322bf9a7730SZachary Turner }
323bf9a7730SZachary Turner
SetTrimmedCStringWithLength(const char * cstr,size_t cstr_len)324bf9a7730SZachary Turner void ConstString::SetTrimmedCStringWithLength(const char *cstr,
325bf9a7730SZachary Turner size_t cstr_len) {
326bf9a7730SZachary Turner m_string = StringPool().GetConstTrimmedCStringWithLength(cstr, cstr_len);
327bf9a7730SZachary Turner }
328bf9a7730SZachary Turner
GetMemoryStats()329*cd8122b2SJonas Devlieghere ConstString::MemoryStats ConstString::GetMemoryStats() {
330*cd8122b2SJonas Devlieghere return StringPool().GetMemoryStats();
331*cd8122b2SJonas Devlieghere }
332*cd8122b2SJonas Devlieghere
format(const ConstString & CS,llvm::raw_ostream & OS,llvm::StringRef Options)3333b7e1981SPavel Labath void llvm::format_provider<ConstString>::format(const ConstString &CS,
3343b7e1981SPavel Labath llvm::raw_ostream &OS,
3353b7e1981SPavel Labath llvm::StringRef Options) {
336642bc15dSRaphael Isemann format_provider<StringRef>::format(CS.GetStringRef(), OS, Options);
3373b7e1981SPavel Labath }
338bc9b6b33SJonas Devlieghere
output(const ConstString & Val,void *,raw_ostream & Out)339bc9b6b33SJonas Devlieghere void llvm::yaml::ScalarTraits<ConstString>::output(const ConstString &Val,
340bc9b6b33SJonas Devlieghere void *, raw_ostream &Out) {
341bc9b6b33SJonas Devlieghere Out << Val.GetStringRef();
342bc9b6b33SJonas Devlieghere }
343bc9b6b33SJonas Devlieghere
344bc9b6b33SJonas Devlieghere llvm::StringRef
input(llvm::StringRef Scalar,void *,ConstString & Val)345bc9b6b33SJonas Devlieghere llvm::yaml::ScalarTraits<ConstString>::input(llvm::StringRef Scalar, void *,
346bc9b6b33SJonas Devlieghere ConstString &Val) {
347bc9b6b33SJonas Devlieghere Val = ConstString(Scalar);
348bc9b6b33SJonas Devlieghere return {};
349bc9b6b33SJonas Devlieghere }
350