Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(492)

Side by Side Diff: components/flags_ui/flags_state.cc

Issue 1411453004: Componentize internal class FlagsState in flags_ui component. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@feature_entry
Patch Set: Fix build with gn and typo in gyp file Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "components/flags_ui/flags_state.h"
6
7 #include "base/callback.h"
8 #include "base/feature_list.h"
9 #include "base/logging.h"
10 #include "base/stl_util.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/values.h"
14 #include "build/build_config.h"
15 #include "components/flags_ui/feature_entry.h"
16 #include "components/flags_ui/flags_storage.h"
17 #include "components/flags_ui/flags_ui_switches.h"
18 #include "ui/base/l10n/l10n_util.h"
19
20 namespace flags_ui {
21
22 namespace {
23
24 const struct {
25 unsigned bit;
26 const char* const name;
27 } kBitsToOs[] = {
28 {kOsMac, "Mac"},
29 {kOsWin, "Windows"},
30 {kOsLinux, "Linux"},
31 {kOsCrOS, "Chrome OS"},
32 {kOsAndroid, "Android"},
33 {kOsCrOSOwnerOnly, "Chrome OS (owner only)"},
34 };
35
36 // Convert switch constants to proper CommandLine::StringType strings.
37 base::CommandLine::StringType GetSwitchString(const std::string& flag) {
38 base::CommandLine cmd_line(base::CommandLine::NO_PROGRAM);
39 cmd_line.AppendSwitch(flag);
40 DCHECK_EQ(2U, cmd_line.argv().size());
41 return cmd_line.argv()[1];
42 }
43
44 // Scoops flags from a command line.
45 std::set<base::CommandLine::StringType> ExtractFlagsFromCommandLine(
46 const base::CommandLine& cmdline,
47 const char* extra_flag_sentinel_begin_flag_name,
48 const char* extra_flag_sentinel_end_flag_name) {
49 DCHECK_EQ(!!extra_flag_sentinel_begin_flag_name,
50 !!extra_flag_sentinel_end_flag_name);
51 std::set<base::CommandLine::StringType> flags;
52 // First do the ones between --flag-switches-begin and --flag-switches-end.
53 base::CommandLine::StringVector::const_iterator first =
54 std::find(cmdline.argv().begin(), cmdline.argv().end(),
55 GetSwitchString(switches::kFlagSwitchesBegin));
56 base::CommandLine::StringVector::const_iterator last =
57 std::find(cmdline.argv().begin(), cmdline.argv().end(),
58 GetSwitchString(switches::kFlagSwitchesEnd));
59 if (first != cmdline.argv().end() && last != cmdline.argv().end())
60 flags.insert(first + 1, last);
61 if (extra_flag_sentinel_begin_flag_name &&
62 extra_flag_sentinel_end_flag_name) {
63 // Then add those between the extra sentinels.
64 first = std::find(cmdline.argv().begin(), cmdline.argv().end(),
65 GetSwitchString(extra_flag_sentinel_begin_flag_name));
66 last = std::find(cmdline.argv().begin(), cmdline.argv().end(),
67 GetSwitchString(extra_flag_sentinel_end_flag_name));
68 if (first != cmdline.argv().end() && last != cmdline.argv().end())
69 flags.insert(first + 1, last);
70 }
71 return flags;
72 }
73
74 // Adds a |StringValue| to |list| for each platform where |bitmask| indicates
75 // whether the entry is available on that platform.
76 void AddOsStrings(unsigned bitmask, base::ListValue* list) {
77 for (size_t i = 0; i < arraysize(kBitsToOs); ++i) {
78 if (bitmask & kBitsToOs[i].bit)
79 list->Append(new base::StringValue(kBitsToOs[i].name));
80 }
81 }
82
83 // Adds the internal names for the specified entry to |names|.
84 void AddInternalName(const FeatureEntry& e, std::set<std::string>* names) {
85 switch (e.type) {
86 case FeatureEntry::SINGLE_VALUE:
87 case FeatureEntry::SINGLE_DISABLE_VALUE:
88 names->insert(e.internal_name);
89 break;
90 case FeatureEntry::MULTI_VALUE:
91 case FeatureEntry::ENABLE_DISABLE_VALUE:
92 case FeatureEntry::FEATURE_VALUE:
93 for (int i = 0; i < e.num_choices; ++i)
94 names->insert(e.NameForChoice(i));
95 break;
96 }
97 }
98
99 // Confirms that an entry is valid, used in a DCHECK in
100 // SanitizeList below.
101 bool ValidateFeatureEntry(const FeatureEntry& e) {
102 switch (e.type) {
103 case FeatureEntry::SINGLE_VALUE:
104 case FeatureEntry::SINGLE_DISABLE_VALUE:
105 DCHECK_EQ(0, e.num_choices);
106 DCHECK(!e.choices);
107 return true;
108 case FeatureEntry::MULTI_VALUE:
109 DCHECK_GT(e.num_choices, 0);
110 DCHECK(e.choices);
111 DCHECK(e.choices[0].command_line_switch);
112 DCHECK_EQ('\0', e.choices[0].command_line_switch[0]);
113 return true;
114 case FeatureEntry::ENABLE_DISABLE_VALUE:
115 DCHECK_EQ(3, e.num_choices);
116 DCHECK(!e.choices);
117 DCHECK(e.command_line_switch);
118 DCHECK(e.command_line_value);
119 DCHECK(e.disable_command_line_switch);
120 DCHECK(e.disable_command_line_value);
121 return true;
122 case FeatureEntry::FEATURE_VALUE:
123 DCHECK_EQ(3, e.num_choices);
124 DCHECK(!e.choices);
125 DCHECK(e.feature_name);
126 return true;
127 }
128 NOTREACHED();
129 return false;
130 }
131
132 // Returns true if none of this entry's options have been enabled.
133 bool IsDefaultValue(const FeatureEntry& entry,
134 const std::set<std::string>& enabled_entries) {
135 switch (entry.type) {
136 case FeatureEntry::SINGLE_VALUE:
137 case FeatureEntry::SINGLE_DISABLE_VALUE:
138 return enabled_entries.count(entry.internal_name) == 0;
139 case FeatureEntry::MULTI_VALUE:
140 case FeatureEntry::ENABLE_DISABLE_VALUE:
141 case FeatureEntry::FEATURE_VALUE:
142 for (int i = 0; i < entry.num_choices; ++i) {
143 if (enabled_entries.count(entry.NameForChoice(i)) > 0)
144 return false;
145 }
146 return true;
147 }
148 NOTREACHED();
149 return true;
150 }
151
152 // Returns the Value representing the choice data in the specified entry.
153 base::Value* CreateChoiceData(const FeatureEntry& entry,
154 const std::set<std::string>& enabled_entries) {
155 DCHECK(entry.type == FeatureEntry::MULTI_VALUE ||
156 entry.type == FeatureEntry::ENABLE_DISABLE_VALUE ||
157 entry.type == FeatureEntry::FEATURE_VALUE);
158 base::ListValue* result = new base::ListValue;
159 for (int i = 0; i < entry.num_choices; ++i) {
160 base::DictionaryValue* value = new base::DictionaryValue;
161 const std::string name = entry.NameForChoice(i);
162 value->SetString("internal_name", name);
163 value->SetString("description", entry.DescriptionForChoice(i));
164 value->SetBoolean("selected", enabled_entries.count(name) > 0);
165 result->Append(value);
166 }
167 return result;
168 }
169
170 } // namespace
171
172 // Keeps track of affected switches for each FeatureEntry, based on which
173 // choice is selected for it.
174 struct SwitchEntry {
175 // Corresponding base::Feature to toggle.
176 std::string feature_name;
177
178 // If |feature_name| is not empty, the state (enable/disabled) to set.
179 bool feature_state;
180
181 // The name of the switch to add.
182 std::string switch_name;
183
184 // If |switch_name| is not empty, the value of the switch to set.
185 std::string switch_value;
186
187 SwitchEntry() : feature_state(false) {}
188 };
189
190 FlagsState::FlagsState(const FeatureEntry* feature_entries,
191 size_t num_feature_entries)
192 : feature_entries_(feature_entries),
193 num_feature_entries_(num_feature_entries),
194 needs_restart_(false) {}
195
196 FlagsState::~FlagsState() {}
197
198 void FlagsState::ConvertFlagsToSwitches(
199 flags_ui::FlagsStorage* flags_storage,
200 base::CommandLine* command_line,
201 SentinelsMode sentinels,
202 const char* enable_features_flag_name,
203 const char* disable_features_flag_name) {
204 std::set<std::string> enabled_entries;
205
206 GetSanitizedEnabledFlagsForCurrentPlatform(flags_storage, &enabled_entries);
207
208 std::map<std::string, SwitchEntry> name_to_switch_map;
209 for (size_t i = 0; i < num_feature_entries_; ++i) {
210 const FeatureEntry& e = feature_entries_[i];
211 switch (e.type) {
212 case FeatureEntry::SINGLE_VALUE:
213 case FeatureEntry::SINGLE_DISABLE_VALUE:
214 AddSwitchMapping(e.internal_name, e.command_line_switch,
215 e.command_line_value, &name_to_switch_map);
216 break;
217 case FeatureEntry::MULTI_VALUE:
218 for (int j = 0; j < e.num_choices; ++j) {
219 AddSwitchMapping(e.NameForChoice(j), e.choices[j].command_line_switch,
220 e.choices[j].command_line_value,
221 &name_to_switch_map);
222 }
223 break;
224 case FeatureEntry::ENABLE_DISABLE_VALUE:
225 AddSwitchMapping(e.NameForChoice(0), std::string(), std::string(),
226 &name_to_switch_map);
227 AddSwitchMapping(e.NameForChoice(1), e.command_line_switch,
228 e.command_line_value, &name_to_switch_map);
229 AddSwitchMapping(e.NameForChoice(2), e.disable_command_line_switch,
230 e.disable_command_line_value, &name_to_switch_map);
231 break;
232 case FeatureEntry::FEATURE_VALUE:
233 AddFeatureMapping(e.NameForChoice(0), std::string(), false,
234 &name_to_switch_map);
235 AddFeatureMapping(e.NameForChoice(1), e.feature_name, true,
236 &name_to_switch_map);
237 AddFeatureMapping(e.NameForChoice(2), e.feature_name, false,
238 &name_to_switch_map);
239 break;
240 }
241 }
242
243 AddSwitchesToCommandLine(enabled_entries, name_to_switch_map, sentinels,
244 command_line, enable_features_flag_name,
245 disable_features_flag_name);
246 }
247
248 bool FlagsState::IsRestartNeededToCommitChanges() {
249 return needs_restart_;
250 }
251
252 void FlagsState::SetFeatureEntryEnabled(flags_ui::FlagsStorage* flags_storage,
253 const std::string& internal_name,
254 bool enable) {
255 size_t at_index = internal_name.find(flags_ui::testing::kMultiSeparator);
256 if (at_index != std::string::npos) {
257 DCHECK(enable);
258 // We're being asked to enable a multi-choice entry. Disable the
259 // currently selected choice.
260 DCHECK_NE(at_index, 0u);
261 const std::string entry_name = internal_name.substr(0, at_index);
262 SetFeatureEntryEnabled(flags_storage, entry_name, false);
263
264 // And enable the new choice, if it is not the default first choice.
265 if (internal_name != entry_name + "@0") {
266 std::set<std::string> enabled_entries;
267 GetSanitizedEnabledFlags(flags_storage, &enabled_entries);
268 needs_restart_ |= enabled_entries.insert(internal_name).second;
269 flags_storage->SetFlags(enabled_entries);
270 }
271 return;
272 }
273
274 std::set<std::string> enabled_entries;
275 GetSanitizedEnabledFlags(flags_storage, &enabled_entries);
276
277 const FeatureEntry* e = nullptr;
278 for (size_t i = 0; i < num_feature_entries_; ++i) {
279 if (feature_entries_[i].internal_name == internal_name) {
280 e = feature_entries_ + i;
281 break;
282 }
283 }
284 DCHECK(e);
285
286 if (e->type == FeatureEntry::SINGLE_VALUE) {
287 if (enable)
288 needs_restart_ |= enabled_entries.insert(internal_name).second;
289 else
290 needs_restart_ |= (enabled_entries.erase(internal_name) > 0);
291 } else if (e->type == FeatureEntry::SINGLE_DISABLE_VALUE) {
292 if (!enable)
293 needs_restart_ |= enabled_entries.insert(internal_name).second;
294 else
295 needs_restart_ |= (enabled_entries.erase(internal_name) > 0);
296 } else {
297 if (enable) {
298 // Enable the first choice.
299 needs_restart_ |= enabled_entries.insert(e->NameForChoice(0)).second;
300 } else {
301 // Find the currently enabled choice and disable it.
302 for (int i = 0; i < e->num_choices; ++i) {
303 std::string choice_name = e->NameForChoice(i);
304 if (enabled_entries.find(choice_name) != enabled_entries.end()) {
305 needs_restart_ = true;
306 enabled_entries.erase(choice_name);
307 // Continue on just in case there's a bug and more than one
308 // entry for this choice was enabled.
309 }
310 }
311 }
312 }
313
314 flags_storage->SetFlags(enabled_entries);
315 }
316
317 void FlagsState::RemoveFlagsSwitches(
318 std::map<std::string, base::CommandLine::StringType>* switch_list) {
319 for (const auto& entry : flags_switches_)
320 switch_list->erase(entry.first);
321
322 // If feature entries were added to --enable-features= or --disable-features=
323 // lists, remove them here while preserving existing values.
324 for (const auto& entry : appended_switches_) {
325 const auto& switch_name = entry.first;
326 const auto& switch_added_values = entry.second;
327
328 // The below is either a std::string or a base::string16 based on platform.
329 const auto& existing_value = (*switch_list)[switch_name];
330 #if defined(OS_WIN)
331 const std::string existing_value_utf8 = base::UTF16ToUTF8(existing_value);
332 #else
333 const std::string& existing_value_utf8 = existing_value;
334 #endif
335
336 std::vector<std::string> features =
337 base::FeatureList::SplitFeatureListString(existing_value_utf8);
338 std::vector<std::string> remaining_features;
339 // For any featrue name in |features| that is not in |switch_added_values| -
340 // i.e. it wasn't added by about_flags code, add it to |remaining_features|.
341 for (const std::string& feature : features) {
342 if (!ContainsKey(switch_added_values, feature))
343 remaining_features.push_back(feature);
344 }
345
346 // Either remove the flag entirely if |remaining_features| is empty, or set
347 // the new list.
348 if (remaining_features.empty()) {
349 switch_list->erase(switch_name);
350 } else {
351 std::string switch_value = base::JoinString(remaining_features, ",");
352 #if defined(OS_WIN)
353 (*switch_list)[switch_name] = base::UTF8ToUTF16(switch_value);
354 #else
355 (*switch_list)[switch_name] = switch_value;
356 #endif
357 }
358 }
359 }
360
361 void FlagsState::ResetAllFlags(flags_ui::FlagsStorage* flags_storage) {
362 needs_restart_ = true;
363
364 std::set<std::string> no_entries;
365 flags_storage->SetFlags(no_entries);
366 }
367
368 void FlagsState::Reset() {
369 needs_restart_ = false;
370 flags_switches_.clear();
371 appended_switches_.clear();
372 }
373
374 void FlagsState::GetFlagFeatureEntries(
375 flags_ui::FlagsStorage* flags_storage,
376 FlagAccess access,
377 base::ListValue* supported_entries,
378 base::ListValue* unsupported_entries,
379 base::Callback<bool(const flags_ui::FeatureEntry&)> skip_feature_entry) {
380 std::set<std::string> enabled_entries;
381 GetSanitizedEnabledFlags(flags_storage, &enabled_entries);
382
383 int current_platform = GetCurrentPlatform();
384
385 for (size_t i = 0; i < num_feature_entries_; ++i) {
386 const FeatureEntry& entry = feature_entries_[i];
387 if (skip_feature_entry.Run(entry))
388 continue;
389
390 base::DictionaryValue* data = new base::DictionaryValue();
391 data->SetString("internal_name", entry.internal_name);
392 data->SetString("name", l10n_util::GetStringUTF16(entry.visible_name_id));
393 data->SetString("description",
394 l10n_util::GetStringUTF16(entry.visible_description_id));
395
396 base::ListValue* supported_platforms = new base::ListValue();
397 AddOsStrings(entry.supported_platforms, supported_platforms);
398 data->Set("supported_platforms", supported_platforms);
399 // True if the switch is not currently passed.
400 bool is_default_value = IsDefaultValue(entry, enabled_entries);
401 data->SetBoolean("is_default", is_default_value);
402
403 switch (entry.type) {
404 case FeatureEntry::SINGLE_VALUE:
405 case FeatureEntry::SINGLE_DISABLE_VALUE:
406 data->SetBoolean(
407 "enabled",
408 (!is_default_value && entry.type == FeatureEntry::SINGLE_VALUE) ||
409 (is_default_value &&
410 entry.type == FeatureEntry::SINGLE_DISABLE_VALUE));
411 break;
412 case FeatureEntry::MULTI_VALUE:
413 case FeatureEntry::ENABLE_DISABLE_VALUE:
414 data->Set("choices", CreateChoiceData(entry, enabled_entries));
415 break;
416 default:
417 NOTREACHED();
418 }
419
420 bool supported = (entry.supported_platforms & current_platform) != 0;
421 #if defined(OS_CHROMEOS)
422 if (access == kOwnerAccessToFlags &&
423 (entry.supported_platforms & kOsCrOSOwnerOnly) != 0) {
424 supported = true;
425 }
426 #endif
427 if (supported)
428 supported_entries->Append(data);
429 else
430 unsupported_entries->Append(data);
431 }
432 }
433
434 void FlagsState::AddSwitchMapping(
435 const std::string& key,
436 const std::string& switch_name,
437 const std::string& switch_value,
438 std::map<std::string, SwitchEntry>* name_to_switch_map) {
439 DCHECK(!ContainsKey(*name_to_switch_map, key));
440
441 SwitchEntry* entry = &(*name_to_switch_map)[key];
442 entry->switch_name = switch_name;
443 entry->switch_value = switch_value;
444 }
445
446 void FlagsState::AddFeatureMapping(
447 const std::string& key,
448 const std::string& feature_name,
449 bool feature_state,
450 std::map<std::string, SwitchEntry>* name_to_switch_map) {
451 DCHECK(!ContainsKey(*name_to_switch_map, key));
452
453 SwitchEntry* entry = &(*name_to_switch_map)[key];
454 entry->feature_name = feature_name;
455 entry->feature_state = feature_state;
456 }
457
458 void FlagsState::AddSwitchesToCommandLine(
459 const std::set<std::string>& enabled_entries,
460 const std::map<std::string, SwitchEntry>& name_to_switch_map,
461 SentinelsMode sentinels,
462 base::CommandLine* command_line,
463 const char* enable_features_flag_name,
464 const char* disable_features_flag_name) {
465 std::map<std::string, bool> feature_switches;
466 if (sentinels == kAddSentinels) {
467 command_line->AppendSwitch(switches::kFlagSwitchesBegin);
468 flags_switches_[switches::kFlagSwitchesBegin] = std::string();
469 }
470
471 for (const std::string& entry_name : enabled_entries) {
472 const auto& entry_it = name_to_switch_map.find(entry_name);
473 if (entry_it == name_to_switch_map.end()) {
474 NOTREACHED();
475 continue;
476 }
477
478 const SwitchEntry& entry = entry_it->second;
479 if (!entry.feature_name.empty()) {
480 feature_switches[entry.feature_name] = entry.feature_state;
481 } else if (!entry.switch_name.empty()) {
482 command_line->AppendSwitchASCII(entry.switch_name, entry.switch_value);
483 flags_switches_[entry.switch_name] = entry.switch_value;
484 }
485 // If an entry doesn't match either of the above, then it is likely the
486 // default entry for a FEATURE_VALUE entry. Safe to ignore.
487 }
488
489 if (!feature_switches.empty()) {
490 MergeFeatureCommandLineSwitch(feature_switches, enable_features_flag_name,
491 true, command_line);
492 MergeFeatureCommandLineSwitch(feature_switches, disable_features_flag_name,
493 false, command_line);
494 }
495
496 if (sentinels == kAddSentinels) {
497 command_line->AppendSwitch(switches::kFlagSwitchesEnd);
498 flags_switches_[switches::kFlagSwitchesEnd] = std::string();
499 }
500 }
501
502 void FlagsState::MergeFeatureCommandLineSwitch(
503 const std::map<std::string, bool>& feature_switches,
504 const char* switch_name,
505 bool feature_state,
506 base::CommandLine* command_line) {
507 std::string original_switch_value =
508 command_line->GetSwitchValueASCII(switch_name);
509 std::vector<std::string> features =
510 base::FeatureList::SplitFeatureListString(original_switch_value);
511 // Only add features that don't already exist in the lists.
512 // Note: The ContainsValue() call results in O(n^2) performance, but in
513 // practice n should be very small.
514 for (const auto& entry : feature_switches) {
515 if (entry.second == feature_state &&
516 !ContainsValue(features, entry.first)) {
517 features.push_back(entry.first);
518 appended_switches_[switch_name].insert(entry.first);
519 }
520 }
521 // Update the switch value only if it didn't change. This avoids setting an
522 // empty list or duplicating the same list (since AppendSwitch() adds the
523 // switch to the end but doesn't remove previous ones).
524 std::string switch_value = base::JoinString(features, ",");
525 if (switch_value != original_switch_value)
526 command_line->AppendSwitchASCII(switch_name, switch_value);
527 }
528
529 void FlagsState::SanitizeList(flags_ui::FlagsStorage* flags_storage) {
530 std::set<std::string> known_entries;
531 for (size_t i = 0; i < num_feature_entries_; ++i) {
532 DCHECK(ValidateFeatureEntry(feature_entries_[i]));
533 AddInternalName(feature_entries_[i], &known_entries);
534 }
535
536 std::set<std::string> enabled_entries = flags_storage->GetFlags();
537
538 std::set<std::string> new_enabled_entries =
539 base::STLSetIntersection<std::set<std::string>>(known_entries,
540 enabled_entries);
541
542 if (new_enabled_entries != enabled_entries)
543 flags_storage->SetFlags(new_enabled_entries);
544 }
545
546 void FlagsState::GetSanitizedEnabledFlags(flags_ui::FlagsStorage* flags_storage,
547 std::set<std::string>* result) {
548 SanitizeList(flags_storage);
549 *result = flags_storage->GetFlags();
550 }
551
552 void FlagsState::GetSanitizedEnabledFlagsForCurrentPlatform(
553 flags_ui::FlagsStorage* flags_storage,
554 std::set<std::string>* result) {
555 GetSanitizedEnabledFlags(flags_storage, result);
556
557 // Filter out any entries that aren't enabled on the current platform. We
558 // don't remove these from prefs else syncing to a platform with a different
559 // set of entries would be lossy.
560 std::set<std::string> platform_entries;
561 int current_platform = GetCurrentPlatform();
562 for (size_t i = 0; i < num_feature_entries_; ++i) {
563 const FeatureEntry& entry = feature_entries_[i];
564 if (entry.supported_platforms & current_platform)
565 AddInternalName(entry, &platform_entries);
566 #if defined(OS_CHROMEOS)
567 if (feature_entries[i].supported_platforms & kOsCrOSOwnerOnly)
568 AddInternalName(entry, &platform_entries);
569 #endif
570 }
571
572 std::set<std::string> new_enabled_entries =
573 base::STLSetIntersection<std::set<std::string>>(platform_entries,
574 *result);
575
576 result->swap(new_enabled_entries);
577 }
578
579 int GetCurrentPlatform() {
580 #if defined(OS_MACOSX)
581 return kOsMac;
582 #elif defined(OS_WIN)
583 return kOsWin;
584 #elif defined(OS_CHROMEOS) // Needs to be before the OS_LINUX check.
585 return kOsCrOS;
586 #elif defined(OS_LINUX) || defined(OS_OPENBSD)
587 return kOsLinux;
588 #elif defined(OS_ANDROID)
589 return kOsAndroid;
590 #else
591 #error Unknown platform
592 #endif
593 }
594
595 bool AreSwitchesIdenticalToCurrentCommandLine(
596 const base::CommandLine& new_cmdline,
597 const base::CommandLine& active_cmdline,
598 std::set<base::CommandLine::StringType>* out_difference,
599 const char* extra_flag_sentinel_begin_flag_name,
600 const char* extra_flag_sentinel_end_flag_name) {
601 std::set<base::CommandLine::StringType> new_flags =
602 ExtractFlagsFromCommandLine(new_cmdline,
603 extra_flag_sentinel_begin_flag_name,
604 extra_flag_sentinel_end_flag_name);
605 std::set<base::CommandLine::StringType> active_flags =
606 ExtractFlagsFromCommandLine(active_cmdline,
607 extra_flag_sentinel_begin_flag_name,
608 extra_flag_sentinel_end_flag_name);
609
610 bool result = false;
611 // Needed because std::equal doesn't check if the 2nd set is empty.
612 if (new_flags.size() == active_flags.size()) {
613 result =
614 std::equal(new_flags.begin(), new_flags.end(), active_flags.begin());
615 }
616
617 if (out_difference && !result) {
618 std::set_symmetric_difference(
619 new_flags.begin(), new_flags.end(), active_flags.begin(),
620 active_flags.end(),
621 std::inserter(*out_difference, out_difference->begin()));
622 }
623
624 return result;
625 }
626
627 } // namespace flags_ui
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698