diff options
Diffstat (limited to 'llvm/lib/Option/OptTable.cpp')
| -rw-r--r-- | llvm/lib/Option/OptTable.cpp | 155 |
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(); } |
