September 25, 2007
Straightforward SettingsRuntime Constants
When settings are this easy, you can get carried away. In fact, a lot of the application constants can become runtime constants (that is, be read as settings). This brings flexibility up a gear—which is great! Imagine doing profiling—you go through the .ini file, change a few values, see how the application behaves. Tuning your app will become a lot less painful.
One thing to remember is that when using a runtime constant, use the const_ function, instead of setting. You'll have a few advantages:
Note that you can use forced get when using const_. Listing Four shows you how to use the constants.
int r = const_("user.retries");
std::string welcome = const_("app.welcome_msg");
int max_users = const_("app.max_users");
int def_size =
const_<int>("w.def_width") * const_<int>("w.def_height");
Listing Four
The Dot Makes a Point
The setting names contain dots in them. This is intentional. First of all, it delimits scope of the setting: "chart.window.width" tells you that it's a setting related to the "chart" module, it's about its window, and it's about the window's width.
More than that, the dots can specify the actual storage destination: be it a file, a read-only file, the registry, some web site, etc. Based on the name of the setting (as you'll see below), the library will select where it reads or writes the setting.
The predefined storage classes are file_storage and registry_storage, but you can extend the library, by adding your own storage classes.
Note that for a setting, its type must be IOstream friendly (have operator<< defined, in order to be read, and operator>> defined, in order to be written). As a bonus, I allow for automatic conversions between strings of different types (from std::string to std::wstring, and vice versa).
The storage class will always deal with the setting values as strings. However, for each setting it deals with, it will also know its original type, thus, it can optimize the storage. For instance, the registry storage class will keep integers as DWORDs in the registry. See Listing 5.
struct setting_storage
{
...
virtual void get_setting(
const std::string &name, std::string &val,
const std::type_info&) const = 0;
virtual void set_setting(
const std::string &name, const std::string &val,
const std::type_info& ) = 0;
...
};
struct registry_setting_storage : setting_storage {
...
virtual void set_setting(
const std::string &name, const std::string &val,
const std::type_info& t) {
if ( t == typeid(int) || t == typeid(long) ||
t == typeid(short) || ...)
write_to_registry_as_DWORD(name, val);
else
write_to_registry_as_SZ_string(name,val);
}
};
Listing Five
As a side note, the file_storage class has an option to save the settings at a certain interval (on a dedicated thread). file_storage also allows you to have comments, as shown in Listing 6.
# when connecting to server, # and it fails, how many times should we try again? app.retry_count=10 # when delete dummy temporary files, at what period should we do it? app.del_temp_files_ms=5000
Listing Six
|
|
||||||||||||||||||||||||||||||
|
|
|
|