llvm.org GIT mirror llvm / 3f8a26f
[Support] Promote cl::StringSaver to a separate utility This class is generally useful. In breaking it out, the primary change is that it has been made non-virtual. It seems like being abstract led to there being 3 different (2 in llvm + 1 in clang) concrete implementations which disagreed about the ownership of the saved strings (see the manual call to free() in the unittest StrDupSaver; yes this is different from the CommandLine.cpp StrDupSaver which owns the stored strings; which is different from Clang's StringSetSaver which just holds a reference to a std::set<std::string> which owns the strings). I've identified 2 other places in the codebase that are open-coding this pattern: memcpy(Alloc.Allocate<char>(strlen(S)+1), S, strlen(S)+1) I'll be switching them over. They are * llvm::sys::Process::GetArgumentVector * The StringAllocator member of YAMLIO's Input class This also will allow simplifying Clang's driver.cpp quite a bit. Let me know if there are any other places that could benefit from StringSaver. I'm also thinking of adding a saveStringRef member for getting a stable StringRef. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@215784 91177308-0d34-0410-b5e6-96231b3b80d8 Sean Silva 6 years ago
4 changed file(s) with 43 addition(s) and 45 deletion(s). Raw diff Collapse all Expand all
2323 #include "llvm/ADT/StringMap.h"
2424 #include "llvm/ADT/Twine.h"
2525 #include "llvm/Support/Compiler.h"
26 #include "llvm/Support/StringSaver.h"
2627 #include
2728 #include
2829 #include
17711772 // Standalone command line processing utilities.
17721773 //
17731774
1774 /// \brief Saves strings in the inheritor's stable storage and returns a stable
1775 /// raw character pointer.
1776 class StringSaver {
1777 virtual void anchor();
1778 public:
1779 virtual const char *SaveString(const char *Str) = 0;
1780 virtual ~StringSaver() {}; // Pacify -Wnon-virtual-dtor.
1781 };
1782
17831775 /// \brief Tokenizes a command line that can contain escapes and quotes.
17841776 //
17851777 /// The quoting rules match those used by GCC and other tools that use
0 //===- llvm/Support/StringSaver.h - Stable storage for strings --*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #ifndef LLVM_SUPPORT_STRINGSAVER_H
10 #define LLVM_SUPPORT_STRINGSAVER_H
11
12 #include "llvm/Support/Allocator.h"
13 #include
14
15 namespace llvm {
16
17 /// \brief Saves strings in stable storage that it owns.
18 class StringSaver {
19 BumpPtrAllocator Alloc;
20
21 public:
22 const char *saveCStr(const char *CStr) {
23 auto Len = std::strlen(CStr) + 1; // Don't forget the NUL!
24 char *Buf = Alloc.Allocate(Len);
25 std::memcpy(Buf, CStr, Len);
26 return Buf;
27 }
28 };
29
30 } // end namespace llvm
31
32 #endif
7575 void parser::anchor() {}
7676 void parser::anchor() {}
7777 void parser::anchor() {}
78 void StringSaver::anchor() {}
7978
8079 //===----------------------------------------------------------------------===//
8180
508507 // End the token if this is whitespace.
509508 if (isWhitespace(Src[I])) {
510509 if (!Token.empty())
511 NewArgv.push_back(Saver.SaveString(Token.c_str()));
510 NewArgv.push_back(Saver.saveCStr(Token.c_str()));
512511 Token.clear();
513512 continue;
514513 }
519518
520519 // Append the last token after hitting EOF with no whitespace.
521520 if (!Token.empty())
522 NewArgv.push_back(Saver.SaveString(Token.c_str()));
521 NewArgv.push_back(Saver.saveCStr(Token.c_str()));
523522 }
524523
525524 /// Backslashes are interpreted in a rather complicated way in the Windows-style
592591 if (State == UNQUOTED) {
593592 // Whitespace means the end of the token.
594593 if (isWhitespace(Src[I])) {
595 NewArgv.push_back(Saver.SaveString(Token.c_str()));
594 NewArgv.push_back(Saver.saveCStr(Token.c_str()));
596595 Token.clear();
597596 State = INIT;
598597 continue;
624623 }
625624 // Append the last token after hitting EOF with no whitespace.
626625 if (!Token.empty())
627 NewArgv.push_back(Saver.SaveString(Token.c_str()));
626 NewArgv.push_back(Saver.saveCStr(Token.c_str()));
628627 }
629628
630629 static bool ExpandResponseFile(const char *FName, StringSaver &Saver,
690689 return AllExpanded;
691690 }
692691
693 namespace {
694 class StrDupSaver : public StringSaver {
695 std::vector Dups;
696 public:
697 ~StrDupSaver() {
698 for (std::vector::iterator I = Dups.begin(), E = Dups.end();
699 I != E; ++I) {
700 char *Dup = *I;
701 free(Dup);
702 }
703 }
704 const char *SaveString(const char *Str) override {
705 char *Dup = strdup(Str);
706 Dups.push_back(Dup);
707 return Dup;
708 }
709 };
710 }
711
712692 /// ParseEnvironmentOptions - An alternative entry point to the
713693 /// CommandLine library, which allows you to read the program's name
714694 /// from the caller (as PROGNAME) and its command-line arguments from
728708 // Get program's "name", which we wouldn't know without the caller
729709 // telling us.
730710 SmallVector newArgv;
731 StrDupSaver Saver;
732 newArgv.push_back(Saver.SaveString(progName));
711 StringSaver Saver;
712 newArgv.push_back(Saver.saveCStr(progName));
733713
734714 // Parse the value of the environment variable into a "command line"
735715 // and hand it off to ParseCommandLineOptions().
753733 SmallVector newArgv;
754734 for (int i = 0; i != argc; ++i)
755735 newArgv.push_back(argv[i]);
756 StrDupSaver Saver;
736 StringSaver Saver;
757737 ExpandResponseFiles(Saver, TokenizeGNUCommandLine, newArgv);
758738 argv = &newArgv[0];
759739 argc = static_cast(newArgv.size());
145145 "Category.";
146146 }
147147
148 class StrDupSaver : public cl::StringSaver {
149 const char *SaveString(const char *Str) override {
150 return strdup(Str);
151 }
152 };
153
154 typedef void ParserFunction(StringRef Source, llvm::cl::StringSaver &Saver,
148 typedef void ParserFunction(StringRef Source, StringSaver &Saver,
155149 SmallVectorImpl &NewArgv);
156150
157151
158152 void testCommandLineTokenizer(ParserFunction *parse, const char *Input,
159153 const char *const Output[], size_t OutputSize) {
160154 SmallVector Actual;
161 StrDupSaver Saver;
155 StringSaver Saver;
162156 parse(Input, Saver, Actual);
163157 EXPECT_EQ(OutputSize, Actual.size());
164158 for (unsigned I = 0, E = Actual.size(); I != E; ++I) {
165159 if (I < OutputSize)
166160 EXPECT_STREQ(Output[I], Actual[I]);
167 free(const_cast(Actual[I]));
168161 }
169162 }
170163