summaryrefslogtreecommitdiff
path: root/llvm/lib/Option/OptTable.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Option/OptTable.cpp')
-rw-r--r--llvm/lib/Option/OptTable.cpp155
1 files changed, 91 insertions, 64 deletions
diff --git a/llvm/lib/Option/OptTable.cpp b/llvm/lib/Option/OptTable.cpp
index 9fdafed39b8b..87e6f1f12364 100644
--- a/llvm/lib/Option/OptTable.cpp
+++ b/llvm/lib/Option/OptTable.cpp
@@ -31,46 +31,55 @@
using namespace llvm;
using namespace llvm::opt;
-namespace llvm::opt {
+namespace {
+struct OptNameLess {
+ const char *StrTable;
+ ArrayRef<unsigned> PrefixesTable;
+
+ explicit OptNameLess(const char *StrTable, ArrayRef<unsigned> PrefixesTable)
+ : StrTable(StrTable), PrefixesTable(PrefixesTable) {}
+
#ifndef NDEBUG
-static inline bool operator<(const OptTable::Info &A, const OptTable::Info &B) {
- if (&A == &B)
- return false;
-
- if (int Cmp = StrCmpOptionName(A.getName(), B.getName()))
- return Cmp < 0;
-
- // Note: we are converting ArrayRef<StringLiteral> to ArrayRef<StringRef>.
- // In general, ArrayRef<SubClass> cannot be safely viewed as ArrayRef<Base>
- // since sizeof(SubClass) may not be same as sizeof(Base). However in this
- // case, sizeof(StringLiteral) is same as sizeof(StringRef), so this
- // conversion is safe.
- static_assert(sizeof(StringRef) == sizeof(StringLiteral));
- ArrayRef<StringRef> APrefixes(A.Prefixes.data(), A.Prefixes.size());
- ArrayRef<StringRef> BPrefixes(B.Prefixes.data(), B.Prefixes.size());
-
- if (int Cmp = StrCmpOptionPrefixes(APrefixes, BPrefixes))
- return Cmp < 0;
-
- // Names are the same, check that classes are in order; exactly one
- // should be joined, and it should succeed the other.
- assert(((A.Kind == Option::JoinedClass) ^ (B.Kind == Option::JoinedClass)) &&
- "Unexpected classes for options with same name.");
- return B.Kind == Option::JoinedClass;
-}
+ inline bool operator()(const OptTable::Info &A,
+ const OptTable::Info &B) const {
+ if (&A == &B)
+ return false;
+
+ if (int Cmp = StrCmpOptionName(A.getName(StrTable, PrefixesTable),
+ B.getName(StrTable, PrefixesTable)))
+ return Cmp < 0;
+
+ SmallVector<StringRef, 8> APrefixes, BPrefixes;
+ A.appendPrefixes(StrTable, PrefixesTable, APrefixes);
+ B.appendPrefixes(StrTable, PrefixesTable, BPrefixes);
+
+ if (int Cmp = StrCmpOptionPrefixes(APrefixes, BPrefixes))
+ return Cmp < 0;
+
+ // Names are the same, check that classes are in order; exactly one
+ // should be joined, and it should succeed the other.
+ assert(
+ ((A.Kind == Option::JoinedClass) ^ (B.Kind == Option::JoinedClass)) &&
+ "Unexpected classes for options with same name.");
+ return B.Kind == Option::JoinedClass;
+ }
#endif
-// Support lower_bound between info and an option name.
-static inline bool operator<(const OptTable::Info &I, StringRef Name) {
- // Do not fallback to case sensitive comparison.
- return StrCmpOptionName(I.getName(), Name, false) < 0;
-}
-} // namespace llvm::opt
+ // Support lower_bound between info and an option name.
+ inline bool operator()(const OptTable::Info &I, StringRef Name) const {
+ // Do not fallback to case sensitive comparison.
+ return StrCmpOptionName(I.getName(StrTable, PrefixesTable), Name, false) <
+ 0;
+ }
+};
+} // namespace
OptSpecifier::OptSpecifier(const Option *Opt) : ID(Opt->getID()) {}
-OptTable::OptTable(ArrayRef<Info> OptionInfos, bool IgnoreCase)
- : OptionInfos(OptionInfos), IgnoreCase(IgnoreCase) {
+OptTable::OptTable(const char *StrTable, ArrayRef<unsigned> PrefixesTable,
+ ArrayRef<Info> OptionInfos, bool IgnoreCase)
+ : StrTable(StrTable), PrefixesTable(PrefixesTable),
+ OptionInfos(OptionInfos), IgnoreCase(IgnoreCase) {
// Explicitly zero initialize the error to work around a bug in array
// value-initialization on MinGW with gcc 4.3.5.
@@ -102,7 +111,7 @@ OptTable::OptTable(ArrayRef<Info> OptionInfos, bool IgnoreCase)
// Check that options are in order.
for (unsigned i = FirstSearchableIndex + 1, e = getNumOptions(); i != e; ++i){
- if (!(getInfo(i) < getInfo(i + 1))) {
+ if (!(OptNameLess(StrTable, PrefixesTable)(getInfo(i), getInfo(i + 1)))) {
getOption(i).dump();
getOption(i + 1).dump();
llvm_unreachable("Options are not in order!");
@@ -115,7 +124,7 @@ void OptTable::buildPrefixChars() {
assert(PrefixChars.empty() && "rebuilding a non-empty prefix char");
// Build prefix chars.
- for (const StringLiteral &Prefix : getPrefixesUnion()) {
+ for (StringRef Prefix : PrefixesUnion) {
for (char C : Prefix)
if (!is_contained(PrefixChars, C))
PrefixChars.push_back(C);
@@ -132,7 +141,7 @@ const Option OptTable::getOption(OptSpecifier Opt) const {
return Option(&getInfo(id), this);
}
-static bool isInput(const ArrayRef<StringLiteral> &Prefixes, StringRef Arg) {
+static bool isInput(const ArrayRef<StringRef> &Prefixes, StringRef Arg) {
if (Arg == "-")
return true;
for (const StringRef &Prefix : Prefixes)
@@ -142,25 +151,32 @@ static bool isInput(const ArrayRef<StringLiteral> &Prefixes, StringRef Arg) {
}
/// \returns Matched size. 0 means no match.
-static unsigned matchOption(const OptTable::Info *I, StringRef Str,
+static unsigned matchOption(const char *StrTable,
+ ArrayRef<unsigned> PrefixesTable,
+ const OptTable::Info *I, StringRef Str,
bool IgnoreCase) {
- for (auto Prefix : I->Prefixes) {
+ StringRef Name = I->getName(StrTable, PrefixesTable);
+ for (unsigned PrefixOffset : I->getPrefixOffsets(PrefixesTable)) {
+ StringRef Prefix = &StrTable[PrefixOffset];
if (Str.starts_with(Prefix)) {
StringRef Rest = Str.substr(Prefix.size());
- bool Matched = IgnoreCase ? Rest.starts_with_insensitive(I->getName())
- : Rest.starts_with(I->getName());
+ bool Matched = IgnoreCase ? Rest.starts_with_insensitive(Name)
+ : Rest.starts_with(Name);
if (Matched)
- return Prefix.size() + StringRef(I->getName()).size();
+ return Prefix.size() + Name.size();
}
}
return 0;
}
// Returns true if one of the Prefixes + In.Names matches Option
-static bool optionMatches(const OptTable::Info &In, StringRef Option) {
- for (auto Prefix : In.Prefixes)
- if (Option.ends_with(In.getName()))
- if (Option.slice(0, Option.size() - In.getName().size()) == Prefix)
+static bool optionMatches(const char *StrTable,
+ ArrayRef<unsigned> PrefixesTable,
+ const OptTable::Info &In, StringRef Option) {
+ StringRef Name = In.getName(StrTable, PrefixesTable);
+ if (Option.consume_back(Name))
+ for (unsigned PrefixOffset : In.getPrefixOffsets(PrefixesTable))
+ if (Option == &StrTable[PrefixOffset])
return true;
return false;
}
@@ -173,7 +189,7 @@ OptTable::suggestValueCompletions(StringRef Option, StringRef Arg) const {
// Search all options and return possible values.
for (size_t I = FirstSearchableIndex, E = OptionInfos.size(); I < E; I++) {
const Info &In = OptionInfos[I];
- if (!In.Values || !optionMatches(In, Option))
+ if (!In.Values || !optionMatches(StrTable, PrefixesTable, In, Option))
continue;
SmallVector<StringRef, 8> Candidates;
@@ -194,15 +210,17 @@ OptTable::findByPrefix(StringRef Cur, Visibility VisibilityMask,
std::vector<std::string> Ret;
for (size_t I = FirstSearchableIndex, E = OptionInfos.size(); I < E; I++) {
const Info &In = OptionInfos[I];
- if (In.Prefixes.empty() || (!In.HelpText && !In.GroupID))
+ if (In.hasNoPrefix() || (!In.HelpText && !In.GroupID))
continue;
if (!(In.Visibility & VisibilityMask))
continue;
if (In.Flags & DisableFlags)
continue;
- for (auto Prefix : In.Prefixes) {
- std::string S = (Prefix + In.getName() + "\t").str();
+ StringRef Name = In.getName(StrTable, PrefixesTable);
+ for (unsigned PrefixOffset : In.getPrefixOffsets(PrefixesTable)) {
+ StringRef Prefix = &StrTable[PrefixOffset];
+ std::string S = (Twine(Prefix) + Name + "\t").str();
if (In.HelpText)
S += In.HelpText;
if (StringRef(S).starts_with(Cur) && S != std::string(Cur) + "\t")
@@ -253,7 +271,7 @@ unsigned OptTable::internalFindNearest(
for (const Info &CandidateInfo :
ArrayRef<Info>(OptionInfos).drop_front(FirstSearchableIndex)) {
- StringRef CandidateName = CandidateInfo.getName();
+ StringRef CandidateName = CandidateInfo.getName(StrTable, PrefixesTable);
// We can eliminate some option prefix/name pairs as candidates right away:
// * Ignore option candidates with empty names, such as "--", or names
@@ -267,7 +285,7 @@ unsigned OptTable::internalFindNearest(
// * Ignore positional argument option candidates (which do not
// have prefixes).
- if (CandidateInfo.Prefixes.empty())
+ if (CandidateInfo.hasNoPrefix())
continue;
// Now check if the candidate ends with a character commonly used when
@@ -286,7 +304,9 @@ unsigned OptTable::internalFindNearest(
// Consider each possible prefix for each candidate to find the most
// appropriate one. For example, if a user asks for "--helm", suggest
// "--help" over "-help".
- for (auto CandidatePrefix : CandidateInfo.Prefixes) {
+ for (unsigned CandidatePrefixOffset :
+ CandidateInfo.getPrefixOffsets(PrefixesTable)) {
+ StringRef CandidatePrefix = &StrTable[CandidatePrefixOffset];
// If Candidate and NormalizedName have more than 'BestDistance'
// characters of difference, no need to compute the edit distance, it's
// going to be greater than BestDistance. Don't bother computing Candidate
@@ -332,19 +352,21 @@ std::unique_ptr<Arg> OptTable::parseOneArgGrouped(InputArgList &Args,
// itself.
const char *CStr = Args.getArgString(Index);
StringRef Str(CStr);
- if (isInput(getPrefixesUnion(), Str))
+ if (isInput(PrefixesUnion, Str))
return std::make_unique<Arg>(getOption(InputOptionID), Str, Index++, CStr);
const Info *End = OptionInfos.data() + OptionInfos.size();
StringRef Name = Str.ltrim(PrefixChars);
const Info *Start =
- std::lower_bound(OptionInfos.data() + FirstSearchableIndex, End, Name);
+ std::lower_bound(OptionInfos.data() + FirstSearchableIndex, End, Name,
+ OptNameLess(StrTable, PrefixesTable));
const Info *Fallback = nullptr;
unsigned Prev = Index;
// Search for the option which matches Str.
for (; Start != End; ++Start) {
- unsigned ArgSize = matchOption(Start, Str, IgnoreCase);
+ unsigned ArgSize =
+ matchOption(StrTable, PrefixesTable, Start, Str, IgnoreCase);
if (!ArgSize)
continue;
@@ -417,7 +439,7 @@ std::unique_ptr<Arg> OptTable::internalParseOneArg(
// Anything that doesn't start with PrefixesUnion is an input, as is '-'
// itself.
- if (isInput(getPrefixesUnion(), Str))
+ if (isInput(PrefixesUnion, Str))
return std::make_unique<Arg>(getOption(InputOptionID), Str, Index++,
Str.data());
@@ -426,7 +448,8 @@ std::unique_ptr<Arg> OptTable::internalParseOneArg(
StringRef Name = Str.ltrim(PrefixChars);
// Search for the first next option which could be a prefix.
- Start = std::lower_bound(Start, End, Name);
+ Start =
+ std::lower_bound(Start, End, Name, OptNameLess(StrTable, PrefixesTable));
// Options are stored in sorted order, with '\0' at the end of the
// alphabet. Since the only options which can accept a string must
@@ -440,7 +463,8 @@ std::unique_ptr<Arg> OptTable::internalParseOneArg(
unsigned ArgSize = 0;
// Scan for first option which is a proper prefix.
for (; Start != End; ++Start)
- if ((ArgSize = matchOption(Start, Str, IgnoreCase)))
+ if ((ArgSize =
+ matchOption(StrTable, PrefixesTable, Start, Str, IgnoreCase)))
break;
if (Start == End)
break;
@@ -763,12 +787,15 @@ void OptTable::internalPrintHelp(
OS.flush();
}
-GenericOptTable::GenericOptTable(ArrayRef<Info> OptionInfos, bool IgnoreCase)
- : OptTable(OptionInfos, IgnoreCase) {
+GenericOptTable::GenericOptTable(const char *StrTable,
+ ArrayRef<unsigned> PrefixesTable,
+ ArrayRef<Info> OptionInfos, bool IgnoreCase)
+ : OptTable(StrTable, PrefixesTable, OptionInfos, IgnoreCase) {
- std::set<StringLiteral> TmpPrefixesUnion;
+ std::set<StringRef> TmpPrefixesUnion;
for (auto const &Info : OptionInfos.drop_front(FirstSearchableIndex))
- TmpPrefixesUnion.insert(Info.Prefixes.begin(), Info.Prefixes.end());
- PrefixesUnionBuffer.append(TmpPrefixesUnion.begin(), TmpPrefixesUnion.end());
+ for (unsigned PrefixOffset : Info.getPrefixOffsets(PrefixesTable))
+ TmpPrefixesUnion.insert(StringRef(&StrTable[PrefixOffset]));
+ PrefixesUnion.append(TmpPrefixesUnion.begin(), TmpPrefixesUnion.end());
buildPrefixChars();
}