-
Notifications
You must be signed in to change notification settings - Fork 1
Home
Welcome to the ConfigurationReader wiki!
In order to use the configuration reader, you'll first need a Lua file with the appropriate variables. This file can have any extension you'd like as long as it obeys Lua formatting. For example:
testString = "This is a string!"
tree = {
stree = {
number = 42;
};
};
Additionally, you'll need to create a header file of your choosing that defines the variables the configuration reader is responsible for reading and updating. You should #include "reader.h"
at the top of this header file. Within your header file you can then use the macros to declare variables of the correct type with the name you'd like them to have and their location in the Lua tree.
The macros take the format CONFIG_TYPE(name, key)
where name
is plaintext that is the name you will use to refer to the variable elsewhere in your program and key
is the location of your parameter in the Lua file as a string. The supported types are as follows:
- Integer -
CONFIG_INT(name, key)
- Unsigned Integer -
CONFIG_UINT(name, key)
- Double -
CONFIG_DOUBLE(name, key)
- Float -
CONFIG_FLOAT(name, key)
- String -
CONFIG_STRING(name, key)
- Eigen::Vector2f -
CONFIG_VECTOR2F(name, key)
So for the above file, you could import testString
by adding CONFIG_STRING(someString, "testString")
to your header file. You can add these macros in any namespace you'd like and the variables will be created in that namespace. Just keep in mind that the macros themselves are defined in the configuration_reader
namespace.
If the key has more than one subtree, you should include all of them in the key
string separated by .
's. For example CFG_INT(someNum, "tree.stree.number")
For an example file, please see my_vars.h
.
To retrieve the value of a specific parameter simply use the global variable that has been created for you. The variable will have the name you specified in the macro CONFIG_TYPE(name, key)
with the characters CFG_
appended to it. Below you can see a small code snippet that puts it all together. Additional detail can be found in the example main.cpp
file.
// In my_vars.h
#include "reader.h"
CFG_STRING(someString, "testString");
// In your main.cc
#include "my_vars.h"
int main(){
std::vector<string> files;
files.push_back("myfile.cfg");
configuration_reader::CreateDaemon(files); // Spawns a new thread to read in the values in the background
// You can do something else here and the thread will continue to watch and update the value of CONFIG_someString
std::cout << configuration_reader::CFG_someString << std::endl; // Will print the value of testString from the lua file
configuration_reader::Stop(); // To end the daemon thread
return 0;
}
The Configuration Reader program consists of a variety of parts, each of which will have their own section. Here we'll list them and provide a brief description.
-
config_interface
- Each file specified in the config_types folder is a class that stores the variable of the specified type. All of them inherit from theconfig_interface
class which ensures that each child type contains functions to retrieve it's key and type. -
lua_script
- Thelua_script.cc
andlua_script.h
files contain a binding between the Lua intrepreter and C++. -
reader
- Thereader.cc
andreader.h
files contain the implementation of the configuration reader functions. -
main
- This file contains an example usage of the configuration reader -
config.lua
- Theconfig.lua
andconfig2.lua
files are example files used for testing the program with the examplemain.cc
file.
The reader.h
and reader.cc
files contain the main logic of the configuration reader program. A short description of each function is listed below:
reader.h
-
const std::string kDefaultFileName
- A constant that stores the default file to be read in if none is provided. Example behavior that utilizes this constant can be see in themain.cc
file. -
CONFIG_TYPE(name, key)
- All of the macros of the formCONFIG_TYPE(name, key)
are used to initialize a configuration variable. Thename
argument is for the name that you wish to use to access the variable within the program. It is expanded into a variable name of the typeCFG_name
. Thekey
is the full path to the variable within the lua file. For usage details, see the importing parameters section.
reader.cc
-
const type& InitType(std::string key)
- All the functions of the generic signatureInitType
take in akey
as a string (from the macros defined inreader.h
) and create an entry in the globalunordered_map
that corresponds to the key, with a pointer to a newConfigInterface
object as the value. The function then reads in the value from the Lua file and returns a const reference to the privatevalue
data within the child class of theConfigInterface
. -
void LuaRead(const std::vector<std::string>& files)
- TheLuaRead()
function takes in a list of file names as a vector of strings and imports them into a new Lua state using theLuaScript
constructor. It then loops through the keys in theunordered_map
and uses theGetType()
function to dynamically determine the correct type of each value. Depending on the type, the function will cast theConfigInterface
pointer returned from theunordered_map
and call the correctSetVal()
function (which loads in the proper value from the Lua state). -
void HelpText()
- A simple function that returns text on how to use the program from the command line. See an example that uses the function in themain.cc
file. -
void InitDaemon(const std::vector<std::string>& files)
- TheInitDaemon()
function contains all the logic for a background thread that calls theLuaRead()
every time any of the files passed in as arguments have are modified with anIN_MODIFY
event from the inotify API. The function loops indefinitely until the program is ended. -
void CreateDaemon(const std::vector<std::string>& files)
- TheCreateDaemon()
function spawns and detaches a new daemon thread that executes theInitDaemon()
function in the background.
The configuration_interface class is a parent type for all the other configuration types. It contains the following functions & data:
-
enum ConfigType
- TheConfigType
enum is used as a "runtime" typecheck in theLuaRead()
function (which is in the filereader.cc
). It allows for the pointers toConfigInterface
objecs to be properly cast to their appropiate types at runtime. -
virtual ConfigType GetType()
- TheGetType()
function returns the type of the object. TheConfigInterface
returns a null type. All the classes that inherit from theConfigInterface
provide their own implementation of this function that returns their specified type. -
std::string GetKey()
- TheGetKey()
function returns a string that corresponds to thekey
used to hash the value in theunordered_map
used by thereader.cc
file. The key is also the full path to the variable in the Lua tables (because it should be a unique identifier for each variable).
The configuration types can all be found in the folder config_types and each class is a wrapper for a specific type that we wish to read in from our Lua file. Every class also inherits from the ConfigInterface
type. Each configuration type has the following functions:
-
ConfigType(std::string key_name)
- A constructor for the type. Takes in a string for the key as a parameter. Sets the protectedstd::string key_
variable tokey_name
. -
ConfigType(std::string key_name, type upper_bound, type lower_bound)
- An overridden constructor for the type. This constructor only exists for numeric types. An upper and lower bound can be supplied and the respective protected data will be initialized. -
Type& GetVal()
- TheGetType()
function returns a reference to theType val_
protected data of the class. -
bool SetVal(LuaScript* script)
- This function calls the appropriate Lua binding functions and sets the value of theType val_
protected variable from the provided Lua state. The function will return false if the value was unable to be read for any reason. If bounds exist, this function will also check that the value retrieved from the Lua state is within those bounds and return false if it is not acceptable.