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

Side by Side Diff: base/metrics/feature_list.h

Issue 1278403003: Initial implementation of FeatureList in base/. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: More comments addressed. Created 5 years, 3 months 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 #ifndef BASE_METRICS_FEATURE_LIST_H_
6 #define BASE_METRICS_FEATURE_LIST_H_
7
8 #include <map>
9 #include <string>
10
11 #include "base/base_export.h"
12 #include "base/basictypes.h"
13 #include "base/containers/scoped_ptr_map.h"
14 #include "base/gtest_prod_util.h"
15 #include "base/synchronization/lock.h"
16
17 namespace base {
18
19 // The Feature struct is used to define the default state for a feature. See
20 // comment below for more details. There must only ever be one struct instance
21 // for a given feature name - generally defined as a global variable or a file
Ilya Sherman 2015/09/01 03:55:26 nit: Might be worth emphasizing that the global va
Alexei Svitkine (slow) 2015/09/01 15:53:44 Done.
22 // static.
23 struct BASE_EXPORT Feature {
24 // The name of the feature. This should be unique to each feature and is used
25 // for enabling/disabling features via command line flags and experiments.
26 const char* const name;
27
28 // The default state (i.e. enabled or disabled) for this feature.
29 const bool default_state;
Ilya Sherman 2015/09/01 03:55:26 Let's use an enum rather than a bool. "default_st
Alexei Svitkine (slow) 2015/09/01 15:53:44 Done.
30 };
31
32 // The FeatureList class is used to determine whether a given feature is on or
33 // off. It provides an authoritative answer, taking into account command-line
34 // overrides and experimental control.
35 //
36 // The basic use case is for any feature that can be toggled (e.g. through
37 // command-line or an experiment) to have a defined Feature struct, e.g.:
38 //
39 // struct base::Feature kMyGreatFeature {
40 // "MyGreatFeature", true
41 // };
42 //
43 // Then, client code that wishes to query the state of the feature would check:
44 //
45 // if (base::FeatureList::IsEnabled(kMyGreatFeature)) {
46 // // Feature code goes here.
47 // }
48 //
49 // Behind the scenes, the above call would take into account any command-line
50 // flags to enable or disable the feature, any experiments that may control it
51 // and finally its default state (in that order of priority), to determine
52 // whether the feature is on.
53 //
54 // Features can be explicitly forced on or off by specifying a list of comma
Ilya Sherman 2015/09/01 03:55:25 nit: s/comma/comma-
Alexei Svitkine (slow) 2015/09/01 15:53:43 Done.
55 // separated feature names via the following command-line flags:
56 //
57 // --enable-features=Feature5,Feature7
58 // --disable-features=Feature1,Feature2,Feature3
59 //
60 // After initial initialization (which should be done single-threaded), the
Ilya Sherman 2015/09/01 03:55:25 nit: "initial initialization" reads a little weird
Alexei Svitkine (slow) 2015/09/01 15:53:44 Done.
61 // FeatureList API is thread safe.
62 //
63 // Note: This class is a singleton, but does not use base/memory/singleton.h in
64 // order to have control over its initialization sequence. Specifically, the
65 // intended use is to create an instance of this class and fully initialize it,
66 // before setting it as the singleton for a process, via SetInstance().
67 class BASE_EXPORT FeatureList {
68 public:
69 FeatureList();
70 ~FeatureList();
71
72 // Initializes feature overrides via command-line flags |enable_features| and
73 // |disable_features|, each of which is a comma-separated list of features to
74 // enable or disable, respectively. If a feature appears on both lists, then
75 // it will be disabled. Must only be invoked during initialization phase
Ilya Sherman 2015/09/01 03:55:25 nit: "during initialization phase" -> "during the
Alexei Svitkine (slow) 2015/09/01 15:53:44 Done.
76 // (before FinalizeInitialization() has been called).
77 void InitializeFromCommandLine(const std::string& enable_features,
78 const std::string& disable_features);
79
80 // Finalizes the initialization state of the FeatureList instance, so that no
81 // further overrides can be registered. For the singleton feature list, this
82 // gets called when it is registered via SetInstance().
83 void FinalizeInitialization();
Ilya Sherman 2015/09/01 03:55:25 nit: Can this method be private?
Alexei Svitkine (slow) 2015/09/01 15:53:43 Done.
84
85 // Returns whether the given |feature| is enabled. This is member function is
Ilya Sherman 2015/09/01 03:55:26 nit: "This is" -> "This"
Alexei Svitkine (slow) 2015/09/01 15:53:44 Done.
86 // normally called through the static IsEnabled() function, which corresponds
87 // to GeInstance()->IsFeatureEnabled(). Must only be called on a FeatureList
88 // that has been fully initialized (FinalizeInitialization() called).
89 bool IsFeatureEnabled(const Feature& feature);
Ilya Sherman 2015/09/01 03:55:25 I agree with Rob that it's probably sensible to ma
Alexei Svitkine (slow) 2015/09/01 15:53:44 Done. See my other comment for my original reasoni
90
91 // Returns whether the given |feature| is enabled. Must only be called after
92 // the singleton instance has been registered via SetInstance(). Additionally,
93 // a feature with a given name must only have a single corresponding Feature
94 // struct, which is checked for in debug builds.
Ilya Sherman 2015/09/01 03:55:26 nit: Below, you write this as "builds with DCHECKs
Alexei Svitkine (slow) 2015/09/01 15:53:44 Done.
95 static bool IsEnabled(const Feature& feature);
96
97 // Returns the singleton instance of FeatureList. Will return null until an
98 // instance is registered via SetInstance().
99 static FeatureList* GetInstance();
100
101 // Registers the given |instance| to be the singleton feature list for this
102 // process. This should only be called once and |instance| must not be null.
103 static void SetInstance(scoped_ptr<FeatureList> instance);
104
105 // Clears the previously-registered singleton instance for tests.
106 static void ClearInstanceForTesting();
107
108 private:
109 FRIEND_TEST_ALL_PREFIXES(FeatureListTest, CheckFeatureIdentity);
Ilya Sherman 2015/09/01 03:55:25 Please use a mechanism that exposes a more narrow
Alexei Svitkine (slow) 2015/09/01 15:53:44 It seems like that would result in more boilerplat
Ilya Sherman 2015/09/01 20:17:16 I think it's generally nice to clearly distinguish
110
111 // Registers an override for feature |feature_name|. The override specifies
112 // whether the feature should be on or off (via |overridden_state|), which
113 // will take precedence over the feature's default state.
114 void RegisterOverride(const std::string& feature_name, bool overriden_state);
115
116 // Checks whether |feature| has the same address as any previously seen
Ilya Sherman 2015/09/01 03:55:26 This comment is a little bit confusing/misleading.
Alexei Svitkine (slow) 2015/09/01 15:53:43 Done.
117 // Feature structs with the same name. Used only from DCHECKs and tests.
Ilya Sherman 2015/09/01 03:55:25 The semantics of the return value are probably wor
Alexei Svitkine (slow) 2015/09/01 15:53:44 Done.
118 bool CheckFeatureIdentity(const Feature& feature);
119
120 struct OverrideEntry {
121 // The overridden enable (on/off) state of the feature.
122 bool overriden_state;
Ilya Sherman 2015/09/01 03:55:26 nit: I think it would be much nicer, for readabili
Ilya Sherman 2015/09/01 03:55:26 nit: "riden" -> "ridden" (applies throughout)
Alexei Svitkine (slow) 2015/09/01 15:53:43 Done.
Alexei Svitkine (slow) 2015/09/01 15:53:44 Done.
123
124 // TODO(asvitkine): Expand this as more support is added.
125
126 explicit OverrideEntry(bool overriden_state);
127 };
128 // Map from feature name to an OverrideEntry struct for the feature, if it
129 // exists. A ScopedPtrMap<> is used because OverrideEntry will later expand
130 // to hold additional non-copyable fields.
Ilya Sherman 2015/09/01 03:55:25 nit: I would personally prefer to use a regular ma
Alexei Svitkine (slow) 2015/09/01 15:53:43 Done.
131 ScopedPtrMap<std::string, scoped_ptr<OverrideEntry>> overrides_;
132
133 // Locked map that keeps track of seen features, to ensure a single feature is
134 // only defined once. This verification is only done in builds with DCHECKs
135 // enabled.
136 Lock feature_identity_tracker_lock_;
137 std::map<std::string, const Feature*> feature_identity_tracker_;
138
139 // Whether this object has been fully initialized. This gets set to true as a
140 // result of FinalizeInitialization().
141 bool initialized_;
142
143 DISALLOW_COPY_AND_ASSIGN(FeatureList);
144 };
145
146 } // namespace base
147
148 #endif // BASE_METRICS_FEATURE_LIST_H_
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698