llvm.org GIT mirror llvm / 4130c91
[CommandLine] Remove OptionCategory and SubCommand caches from the Option class. Summary: This change processes `OptionCategory`s and `SubCommand`s as they are seen instead of caching them in the Option class and processing them later. Doing so simplifies the work needed to be done by the Global parser and significantly reduces the size of the Option class to a mere 64 bytes. Removing the `OptionCategory` cache saved 24 bytes, and removing the `SubCommand` cache saved an additional 48 bytes, for a total of a 72 byte reduction. Reviewers: beanz, zturner, MaskRay, serge-sans-paille Reviewed By: serge-sans-paille Subscribers: serge-sans-paille, tstellar, zturner, hiraditya, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D62105 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@364134 91177308-0d34-0410-b5e6-96231b3b80d8 Don Hinton 3 months ago
3 changed file(s) with 125 addition(s) and 102 deletion(s). Raw diff Collapse all Expand all
200200
201201 StringRef getName() const { return Name; }
202202 StringRef getDescription() const { return Description; }
203
204 SmallPtrSet
203205 };
204206
205207 // The general Option Category (used as default category).
282284 StringRef ArgStr; // The argument string itself (ex: "help", "o")
283285 StringRef HelpStr; // The descriptive text message for -help
284286 StringRef ValueStr; // String describing what the value of this option is
285 SmallVector
286 Categories; // The Categories this option belongs to
287 SmallPtrSet Subs; // The subcommands this option belongs to.
287
288 // Return the set of OptionCategories that this Option belongs to.
289 SmallPtrSet getCategories() const;
290
291 // Return the set of SubCommands that this Option belongs to.
292 SmallPtrSet getSubCommands() const;
288293
289294 inline enum NumOccurrencesFlag getNumOccurrencesFlag() const {
290295 return (enum NumOccurrencesFlag)Occurrences;
314319
315320 bool isConsumeAfter() const {
316321 return getNumOccurrencesFlag() == cl::ConsumeAfter;
317 }
318
319 bool isInAllSubCommands() const {
320 return any_of(Subs, [](const SubCommand *SC) {
321 return SC == &*AllSubCommands;
322 });
323322 }
324323
325324 //-------------------------------------------------------------------------===
335334 void setMiscFlag(enum MiscFlags M) { Misc |= M; }
336335 void setPosition(unsigned pos) { Position = pos; }
337336 void addCategory(OptionCategory &C);
338 void addSubCommand(SubCommand &S) { Subs.insert(&S); }
339337
340338 protected:
341339 explicit Option(enum NumOccurrencesFlag OccurrencesFlag,
342340 enum OptionHidden Hidden)
343341 : NumOccurrences(0), Occurrences(OccurrencesFlag), Value(0),
344342 HiddenFlag(Hidden), Formatting(NormalFormatting), Misc(0),
345 FullyInitialized(false), Position(0), AdditionalVals(0) {
346 Categories.push_back(&GeneralCategory);
347 }
343 FullyInitialized(false), Position(0), AdditionalVals(0) {}
348344
349345 inline void setNumAdditionalVals(unsigned n) { AdditionalVals = n; }
350346
353349
354350 // addArgument - Register this argument with the commandline system.
355351 //
356 void addArgument();
352 virtual void addArgument(SubCommand &SC);
353
354 // addArgument - Only called in done() method to add default
355 // TopLevelSubCommand.
356 void addArgument() {
357 if (!FullyInitialized)
358 addArgument(*TopLevelSubCommand);
359 }
357360
358361 /// Unregisters this option from the CommandLine system.
359362 ///
464467
465468 sub(SubCommand &S) : Sub(S) {}
466469
467 template void apply(Opt &O) const { O.addSubCommand(Sub); }
470 template void apply(Opt &O) const { O.addArgument(Sub); }
468471 };
469472
470473 //===----------------------------------------------------------------------===//
17711774 error("cl::alias must have argument name specified!");
17721775 if (!AliasFor)
17731776 error("cl::alias must have an cl::aliasopt(option) specified!");
1774 if (!Subs.empty())
1775 error("cl::alias must not have cl::sub(), aliased option's cl::sub() will be used!");
1776 Subs = AliasFor->Subs;
1777 Categories = AliasFor->Categories;
1778 addArgument();
1777 for(OptionCategory *Cat: AliasFor->getCategories())
1778 addCategory(*Cat);
1779 for(SubCommand *SC: AliasFor->getSubCommands())
1780 Option::addArgument(*SC);
17791781 }
17801782
17811783 public:
17881790 error("cl::alias must only have one cl::aliasopt(...) specified!");
17891791 AliasFor = &O;
17901792 }
1793
1794 // Does nothing when called via apply. Aliases call Option::addArgument
1795 // directly in the done() method to actually add the option..
1796 void addArgument(SubCommand &SC) override {}
17911797
17921798 template
17931799 explicit alias(const Mods &... Ms)
141141 // This collects Options added with the cl::DefaultOption flag. Since they can
142142 // be overridden, they are not added to the appropriate SubCommands until
143143 // ParseCommandLineOptions actually runs.
144 SmallVector<Option*, 4> DefaultOptions;
144 SmallVector<std::pair, 4> DefaultOptions;
145145
146146 // This collects the different option categories that have been registered.
147147 SmallPtrSet RegisteredOptionCategories;
181181 }
182182
183183 void addLiteralOption(Option &Opt, StringRef Name) {
184 if (Opt.Subs.empty())
185 addLiteralOption(Opt, &*TopLevelSubCommand, Name);
186 else {
187 for (auto SC : Opt.Subs)
188 addLiteralOption(Opt, SC, Name);
189 }
190 }
191
192 void addOption(Option *O, SubCommand *SC) {
184 for(SubCommand *SC: Opt.getSubCommands())
185 addLiteralOption(Opt, SC, Name);
186 }
187
188 void addOption(Option *O, SubCommand *SC, bool ProcessDefaultOptions = false) {
189 if (!ProcessDefaultOptions && O->isDefaultOption()) {
190 DefaultOptions.push_back(std::make_pair(O, SC));
191 return;
192 }
193
193194 bool HadErrors = false;
194195 if (O->hasArgStr()) {
195196 // If it's a DefaultOption, check to make sure it isn't already there.
231232 for (const auto &Sub : RegisteredSubCommands) {
232233 if (SC == Sub)
233234 continue;
234 addOption(O, Sub);
235 }
236 }
237 }
238
239 void addOption(Option *O, bool ProcessDefaultOption = false) {
240 if (!ProcessDefaultOption && O->isDefaultOption()) {
241 DefaultOptions.push_back(O);
242 return;
243 }
244
245 if (O->Subs.empty()) {
246 addOption(O, &*TopLevelSubCommand);
247 } else {
248 for (auto SC : O->Subs)
249 addOption(O, SC);
235 addOption(O, Sub, ProcessDefaultOptions);
236 }
237 }
238 }
239
240 void addDefaultOptions() {
241 for (std::pair
242 addOption(DO.first, DO.second, true);
250243 }
251244 }
252245
284277 }
285278
286279 void removeOption(Option *O) {
287 if (O->Subs.empty())
288 removeOption(O, &*TopLevelSubCommand);
289 else {
290 if (O->isInAllSubCommands()) {
291 for (auto SC : RegisteredSubCommands)
292 removeOption(O, SC);
293 } else {
294 for (auto SC : O->Subs)
295 removeOption(O, SC);
296 }
297 }
280 for (auto SC : RegisteredSubCommands)
281 removeOption(O, SC);
298282 }
299283
300284 bool hasOptions(const SubCommand &Sub) const {
323307 }
324308
325309 void updateArgStr(Option *O, StringRef NewName) {
326 if (O->Subs.empty())
327 updateArgStr(O, NewName, &*TopLevelSubCommand);
328 else {
329 if (O->isInAllSubCommands()) {
330 for (auto SC : RegisteredSubCommands)
331 updateArgStr(O, NewName, SC);
332 } else {
333 for (auto SC : O->Subs)
334 updateArgStr(O, NewName, SC);
335 }
336 }
310 for (auto SC : RegisteredSubCommands)
311 updateArgStr(O, NewName, SC);
337312 }
338313
339314 void printOptionValues();
426401 GlobalParser->MoreHelp.push_back(Help);
427402 }
428403
429 void Option::addArgument() {
430 GlobalParser->addOption(this);
404 void Option::addArgument(SubCommand &SC) {
405 GlobalParser->addOption(this, &SC);
431406 FullyInitialized = true;
432407 }
433408
434409 void Option::removeArgument() { GlobalParser->removeOption(this); }
410
411 SmallPtrSet Option::getCategories() const {
412 SmallPtrSet Cats;
413 for (OptionCategory *C: GlobalParser->RegisteredOptionCategories) {
414 if (C->MemberOptions.find(this) != C->MemberOptions.end())
415 Cats.insert(C);
416 }
417 if (Cats.empty())
418 Cats.insert(&GeneralCategory);
419 return Cats;
420 }
421
422 SmallPtrSet Option::getSubCommands() const {
423 // This can happen for enums and literal options.
424 if (ArgStr.empty())
425 return SmallPtrSet{&*TopLevelSubCommand};
426
427 SmallPtrSet Subs;
428 for (SubCommand *SC : GlobalParser->getRegisteredSubcommands()) {
429 auto I = SC->OptionsMap.find(ArgStr);
430 if (I != SC->OptionsMap.end() && I->getValue() == this)
431 Subs.insert(SC);
432 }
433 return Subs;
434 }
435435
436436 void Option::setArgStr(StringRef S) {
437437 if (FullyInitialized)
443443 }
444444
445445 void Option::addCategory(OptionCategory &C) {
446 assert(!Categories.empty() && "Categories cannot be empty.");
447 // Maintain backward compatibility by replacing the default GeneralCategory
448 // if it's still set. Otherwise, just add the new one. The GeneralCategory
449 // must be explicitly added if you want multiple categories that include it.
450 if (&C != &GeneralCategory && Categories[0] == &GeneralCategory)
451 Categories[0] = &C;
452 else if (find(Categories, &C) == Categories.end())
453 Categories.push_back(&C);
446 C.MemberOptions.insert(this);
454447 }
455448
456449 void Option::reset() {
13011294 auto &SinkOpts = ChosenSubCommand->SinkOpts;
13021295 auto &OptionsMap = ChosenSubCommand->OptionsMap;
13031296
1304 for (auto O: DefaultOptions) {
1305 addOption(O, true);
1306 }
1297 addDefaultOptions();
13071298
13081299 if (ConsumeAfterOpt) {
13091300 assert(PositionalOpts.size() > 0 &&
22032194 // options within categories will also be alphabetically sorted.
22042195 for (size_t I = 0, E = Opts.size(); I != E; ++I) {
22052196 Option *Opt = Opts[I].second;
2206 for (auto &Cat : Opt->Categories) {
2197 for (auto *Cat : Opt->getCategories()) {
22072198 assert(CategorizedOptions.count(Cat) > 0 &&
22082199 "Option has an unregistered category");
22092200 CategorizedOptions[Cat].push_back(Opt);
24642455
24652456 void cl::HideUnrelatedOptions(cl::OptionCategory &Category, SubCommand &Sub) {
24662457 for (auto &I : Sub.OptionsMap) {
2467 for (auto &Cat : I.second->Categories) {
2458 for (OptionCategory *Cat : I.second->getCategories()) {
24682459 if (Cat != &Category &&
24692460 Cat != &GenericCategory)
24702461 I.second->setHiddenFlag(cl::ReallyHidden);
24752466 void cl::HideUnrelatedOptions(ArrayRef Categories,
24762467 SubCommand &Sub) {
24772468 for (auto &I : Sub.OptionsMap) {
2478 for (auto &Cat : I.second->Categories) {
2469 for (OptionCategory *Cat : I.second->getCategories()) {
24792470 if (find(Categories, Cat) == Categories.end() && Cat != &GenericCategory)
24802471 I.second->setHiddenFlag(cl::ReallyHidden);
24812472 }
9494 cl::Option *Retrieved = Map["test-option"];
9595 ASSERT_EQ(&TestOption, Retrieved) << "Retrieved wrong option.";
9696
97 ASSERT_NE(Retrieved->Categories.end(),
98 find_if(Retrieved->Categories,
97 ASSERT_NE(Retrieved->getCategories().end(),
98 find_if(Retrieved->getCategories(),
9999 [&](const llvm::cl::OptionCategory *Cat) {
100100 return Cat == &cl::GeneralCategory;
101101 }))
102102 << "Incorrect default option category.";
103103
104104 Retrieved->addCategory(TestCategory);
105 ASSERT_NE(Retrieved->Categories.end(),
106 find_if(Retrieved->Categories,
105 ASSERT_NE(Retrieved->getCategories().end(),
106 find_if(Retrieved->getCategories(),
107107 [&](const llvm::cl::OptionCategory *Cat) {
108108 return Cat == &TestCategory;
109109 }))
159159 TEST(CommandLineTest, UseOptionCategory) {
160160 StackOption TestOption2("test-option", cl::cat(TestCategory));
161161
162 ASSERT_NE(TestOption2.Categories.end(),
163 find_if(TestOption2.Categories,
162 ASSERT_NE(TestOption2.getCategories().end(),
163 find_if(TestOption2.getCategories(),
164164 [&](const llvm::cl::OptionCategory *Cat) {
165165 return Cat == &TestCategory;
166166 }))
171171 StackOption TestOption2("test-option2", cl::cat(TestCategory),
172172 cl::cat(cl::GeneralCategory),
173173 cl::cat(cl::GeneralCategory));
174 auto TestOption2Categories = TestOption2.getCategories();
174175
175176 // Make sure cl::GeneralCategory wasn't added twice.
176 ASSERT_EQ(TestOption2.Categories.size(), 2U);
177
178 ASSERT_NE(TestOption2.Categories.end(),
179 find_if(TestOption2.Categories,
177 ASSERT_EQ(TestOption2Categories.size(), 2U);
178
179 ASSERT_NE(TestOption2Categories.end(),
180 find_if(TestOption2Categories,
180181 [&](const llvm::cl::OptionCategory *Cat) {
181182 return Cat == &TestCategory;
182183 }))
183184 << "Failed to assign Option Category.";
184 ASSERT_NE(TestOption2.Categories.end(),
185 find_if(TestOption2.Categories,
185 ASSERT_NE(TestOption2Categories.end(),
186 find_if(TestOption2Categories,
186187 [&](const llvm::cl::OptionCategory *Cat) {
187188 return Cat == &cl::GeneralCategory;
188189 }))
191192 cl::OptionCategory AnotherCategory("Additional test Options", "Description");
192193 StackOption TestOption("test-option", cl::cat(TestCategory),
193194 cl::cat(AnotherCategory));
194 ASSERT_EQ(TestOption.Categories.end(),
195 find_if(TestOption.Categories,
195 auto TestOptionCategories = TestOption.getCategories();
196 ASSERT_EQ(TestOptionCategories.end(),
197 find_if(TestOptionCategories,
196198 [&](const llvm::cl::OptionCategory *Cat) {
197199 return Cat == &cl::GeneralCategory;
198200 }))
199201 << "Failed to remove General Category.";
200 ASSERT_NE(TestOption.Categories.end(),
201 find_if(TestOption.Categories,
202 ASSERT_NE(TestOptionCategories.end(),
203 find_if(TestOptionCategories,
202204 [&](const llvm::cl::OptionCategory *Cat) {
203205 return Cat == &TestCategory;
204206 }))
205207 << "Failed to assign Option Category.";
206 ASSERT_NE(TestOption.Categories.end(),
207 find_if(TestOption.Categories,
208 ASSERT_NE(TestOptionCategories.end(),
209 find_if(TestOptionCategories,
208210 [&](const llvm::cl::OptionCategory *Cat) {
209211 return Cat == &AnotherCategory;
210212 }))
375377 const char *opts2[] = { "-tool", "-o", "x" };
376378 testAliasRequired(array_lengthof(opts1), opts1);
377379 testAliasRequired(array_lengthof(opts2), opts2);
380 }
381
382 TEST(CommandLineTest, AliasWithSubCommand) {
383 StackSubCommand SC1("sc1", "Subcommand 1");
384 StackOption Option1("option", cl::value_desc("output file"),
385 cl::init("-"), cl::desc("Option"),
386 cl::sub(SC1));
387 StackOption Alias1("o", llvm::cl::aliasopt(Option1),
388 cl::desc("Alias for --option"),
389 cl::sub(SC1));
390 }
391
392 TEST(CommandLineTest, AliasWithMultipleSubCommandsWithSameOption) {
393 StackSubCommand SC1("sc1", "Subcommand 1");
394 StackOption Option1("option", cl::value_desc("output file"),
395 cl::init("-"), cl::desc("Option"),
396 cl::sub(SC1));
397 StackSubCommand SC2("sc2", "Subcommand 2");
398 StackOption Option2("option", cl::value_desc("output file"),
399 cl::init("-"), cl::desc("Option"),
400 cl::sub(SC2));
401
402 StackOption Alias1("o", llvm::cl::aliasopt(Option1),
403 cl::desc("Alias for --option"));
378404 }
379405
380406 TEST(CommandLineTest, HideUnrelatedOptions) {