+// Splits |text| into two parts by the |separator| where the first part will be
+// returned updated in |first| and the second part will be returned as |second|.
+// This function returns false if there is more than one |separator| in |first|.
+// If there is no |separator| presented in |first|, this function will not
+// modify |first| and |second|. It's used for splitting the |enable_features|
+// flag into feature name, field trial name and feature parameters.
+bool SplitIntoTwo(StringPiece text,
+ StringPiece separator,
+ StringPiece* first,
+ std::string* second) {
+ std::vector<StringPiece> parts =
+ SplitStringPiece(text, separator, TRIM_WHITESPACE, SPLIT_WANT_ALL);
+ if (parts.size() == 2) {
+ *second = std::string(parts[1]);
+ } else if (parts.size() > 2) {
+ DLOG(ERROR) << "Only one '" << separator
+ << "' is allowed but got: " << *first;
+ return false;
+ }
+ *first = parts[0];
+ return true;
+}
+
+// Checks and parses the |enable_features| flag and sets
+// |parsed_enable_features| to be a comma-separated list of features,
+// |force_fieldtrials| to be a comma-separated list of field trials that each
+// feature want to associate with and |force_fieldtrial_params| to be the field
+// trial parameters for each field trial.
+// Returns true if |enable_features| is parsable, otherwise false.
+bool ParseEnableFeatures(const std::string& enable_features,
+ std::string* parsed_enable_features,
+ std::string* force_fieldtrials,
+ std::string* force_fieldtrial_params) {
+ std::vector<std::string> enable_features_list;
+ std::vector<std::string> force_fieldtrials_list;
+ std::vector<std::string> force_fieldtrial_params_list;
+ for (const auto& enable_feature :
+ FeatureList::SplitFeatureListString(enable_features)) {
+ std::string feature_name;
+ std::string study;
+ std::string group;
+ std::string feature_params;
+ if (!FeatureList::ParseEnableFeatureString(
+ enable_feature, &feature_name, &study, &group, &feature_params)) {
+ return false;
+ }
+
+ // If feature params were set but group and study weren't, associate the
+ // feature and its feature params to a synthetic field trial as the
+ // feature params only make sense when it's combined with a field trial.
+ if (!feature_params.empty()) {
+ force_fieldtrials_list.push_back(study + "/" + group);
+ force_fieldtrial_params_list.push_back(study + "." + group + ":" +
+ feature_params);
+ }
+ enable_features_list.push_back(
+ study.empty() ? feature_name : (feature_name + "<" + study));
+ }
+
+ *parsed_enable_features = JoinString(enable_features_list, ",");
+ // Field trial separator is currently a slash. See
+ // |kPersistentStringSeparator| in base/metrics/field_trial.cc.
+ *force_fieldtrials = JoinString(force_fieldtrials_list, "/");
+ *force_fieldtrial_params = JoinString(force_fieldtrial_params_list, ",");
+ return true;
+}
+
+std::pair<FeatureList::OverrideState, uint16_t> UnpackFeatureCache(
+ uint32_t packed_cache_value) {
+ return std::make_pair(
+ static_cast<FeatureList::OverrideState>(packed_cache_value >> 24),
+ packed_cache_value & 0xFFFF);
+}
+
+uint32_t PackFeatureCache(FeatureList::OverrideState override_state,
+ uint32_t caching_context) {
+ return (static_cast<uint32_t>(override_state) << 24) |
+ (caching_context & 0xFFFF);