1 | // |
2 | // Copyright 2019 The Abseil Authors. |
3 | // |
4 | // Licensed under the Apache License, Version 2.0 (the "License"); |
5 | // you may not use this file except in compliance with the License. |
6 | // You may obtain a copy of the License at |
7 | // |
8 | // https://www.apache.org/licenses/LICENSE-2.0 |
9 | // |
10 | // Unless required by applicable law or agreed to in writing, software |
11 | // distributed under the License is distributed on an "AS IS" BASIS, |
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | // See the License for the specific language governing permissions and |
14 | // limitations under the License. |
15 | |
16 | #ifndef ABSL_FLAGS_INTERNAL_REGISTRY_H_ |
17 | #define ABSL_FLAGS_INTERNAL_REGISTRY_H_ |
18 | |
19 | #include <functional> |
20 | #include <map> |
21 | #include <string> |
22 | |
23 | #include "absl/base/macros.h" |
24 | #include "absl/flags/internal/commandlineflag.h" |
25 | |
26 | // -------------------------------------------------------------------- |
27 | // Global flags registry API. |
28 | |
29 | namespace absl { |
30 | namespace flags_internal { |
31 | |
32 | // CommandLineFlagInfo holds all information for a flag. |
33 | struct CommandLineFlagInfo { |
34 | std::string name; // the name of the flag |
35 | std::string type; // DO NOT use. Use flag->IsOfType<T>() instead. |
36 | std::string description; // the "help text" associated with the flag |
37 | std::string current_value; // the current value, as a std::string |
38 | std::string default_value; // the default value, as a std::string |
39 | std::string filename; // 'cleaned' version of filename holding the flag |
40 | bool has_validator_fn; // true if RegisterFlagValidator called on this flag |
41 | |
42 | bool is_default; // true if the flag has the default value and |
43 | // has not been set explicitly from the cmdline |
44 | // or via SetCommandLineOption. |
45 | |
46 | // nullptr for ABSL_FLAG. A pointer to the flag's current value |
47 | // otherwise. E.g., for DEFINE_int32(foo, ...), flag_ptr will be |
48 | // &FLAGS_foo. |
49 | const void* flag_ptr; |
50 | }; |
51 | |
52 | //----------------------------------------------------------------------------- |
53 | |
54 | void FillCommandLineFlagInfo(CommandLineFlag* flag, |
55 | CommandLineFlagInfo* result); |
56 | |
57 | //----------------------------------------------------------------------------- |
58 | |
59 | CommandLineFlag* FindCommandLineFlag(absl::string_view name); |
60 | CommandLineFlag* FindCommandLineV1Flag(const void* flag_ptr); |
61 | CommandLineFlag* FindRetiredFlag(absl::string_view name); |
62 | |
63 | // Executes specified visitor for each non-retired flag in the registry. |
64 | // Requires the caller hold the registry lock. |
65 | void ForEachFlagUnlocked(std::function<void(CommandLineFlag*)> visitor); |
66 | // Executes specified visitor for each non-retired flag in the registry. While |
67 | // callback are executed, the registry is locked and can't be changed. |
68 | void ForEachFlag(std::function<void(CommandLineFlag*)> visitor); |
69 | |
70 | //----------------------------------------------------------------------------- |
71 | |
72 | // Store the list of all flags in *OUTPUT, sorted by file. |
73 | void GetAllFlags(std::vector<CommandLineFlagInfo>* OUTPUT); |
74 | |
75 | //----------------------------------------------------------------------------- |
76 | |
77 | bool RegisterCommandLineFlag(CommandLineFlag*, const void* ptr = nullptr); |
78 | |
79 | //----------------------------------------------------------------------------- |
80 | // Retired registrations: |
81 | // |
82 | // Retired flag registrations are treated specially. A 'retired' flag is |
83 | // provided only for compatibility with automated invocations that still |
84 | // name it. A 'retired' flag: |
85 | // - is not bound to a C++ FLAGS_ reference. |
86 | // - has a type and a value, but that value is intentionally inaccessible. |
87 | // - does not appear in --help messages. |
88 | // - is fully supported by _all_ flag parsing routines. |
89 | // - consumes args normally, and complains about type mismatches in its |
90 | // argument. |
91 | // - emits a complaint but does not die (e.g. LOG(ERROR)) if it is |
92 | // accessed by name through the flags API for parsing or otherwise. |
93 | // |
94 | // The registrations for a flag happen in an unspecified order as the |
95 | // initializers for the namespace-scope objects of a program are run. |
96 | // Any number of weak registrations for a flag can weakly define the flag. |
97 | // One non-weak registration will upgrade the flag from weak to non-weak. |
98 | // Further weak registrations of a non-weak flag are ignored. |
99 | // |
100 | // This mechanism is designed to support moving dead flags into a |
101 | // 'graveyard' library. An example migration: |
102 | // |
103 | // 0: Remove references to this FLAGS_flagname in the C++ codebase. |
104 | // 1: Register as 'retired' in old_lib. |
105 | // 2: Make old_lib depend on graveyard. |
106 | // 3: Add a redundant 'retired' registration to graveyard. |
107 | // 4: Remove the old_lib 'retired' registration. |
108 | // 5: Eventually delete the graveyard registration entirely. |
109 | // |
110 | // Returns bool to enable use in namespace-scope initializers. |
111 | // For example: |
112 | // |
113 | // static const bool dummy = base::RetiredFlag<int32_t>("myflag"); |
114 | // |
115 | // Or to declare several at once: |
116 | // |
117 | // static bool dummies[] = { |
118 | // base::RetiredFlag<std::string>("some_string_flag"), |
119 | // base::RetiredFlag<double>("some_double_flag"), |
120 | // base::RetiredFlag<int32_t>("some_int32_flag") |
121 | // }; |
122 | |
123 | // Retire flag with name "name" and type indicated by ops. |
124 | bool Retire(FlagOpFn ops, FlagMarshallingOpFn marshalling_ops, |
125 | const char* name); |
126 | |
127 | // Registered a retired flag with name 'flag_name' and type 'T'. |
128 | template <typename T> |
129 | inline bool RetiredFlag(const char* flag_name) { |
130 | return flags_internal::Retire(flags_internal::FlagOps<T>, |
131 | flags_internal::FlagMarshallingOps<T>, |
132 | flag_name); |
133 | } |
134 | |
135 | // If the flag is retired, returns true and indicates in |*type_is_bool| |
136 | // whether the type of the retired flag is a bool. |
137 | // Only to be called by code that needs to explicitly ignore retired flags. |
138 | bool IsRetiredFlag(absl::string_view name, bool* type_is_bool); |
139 | |
140 | //----------------------------------------------------------------------------- |
141 | // Saves the states (value, default value, whether the user has set |
142 | // the flag, registered validators, etc) of all flags, and restores |
143 | // them when the FlagSaver is destroyed. |
144 | // |
145 | // This class is thread-safe. However, its destructor writes to |
146 | // exactly the set of flags that have changed value during its |
147 | // lifetime, so concurrent _direct_ access to those flags |
148 | // (i.e. FLAGS_foo instead of {Get,Set}CommandLineOption()) is unsafe. |
149 | |
150 | class FlagSaver { |
151 | public: |
152 | FlagSaver(); |
153 | ~FlagSaver(); |
154 | |
155 | FlagSaver(const FlagSaver&) = delete; |
156 | void operator=(const FlagSaver&) = delete; |
157 | |
158 | // Prevents saver from restoring the saved state of flags. |
159 | void Ignore(); |
160 | |
161 | private: |
162 | class FlagSaverImpl* impl_; // we use pimpl here to keep API steady |
163 | }; |
164 | |
165 | } // namespace flags_internal |
166 | } // namespace absl |
167 | |
168 | #endif // ABSL_FLAGS_INTERNAL_REGISTRY_H_ |
169 | |