From: Gabriel Corona Date: Mon, 11 Apr 2016 11:55:45 +0000 (+0200) Subject: simgrid::config::flag, a more declarative way to describe CLI flags X-Git-Tag: v3_13~97^2~18 X-Git-Url: http://info.iut-bm.univ-fcomte.fr/pub/gitweb/simgrid.git/commitdiff_plain/ebc5f7ed172f242031fc644120ce45f690b619bc?ds=sidebyside simgrid::config::flag, a more declarative way to describe CLI flags I got rid of xbt_cfg_cpy() in the process which was not used. If we want to support it, we can: * either provide a "copy" callback; * or (better) use reference counts on the callback. --- diff --git a/include/xbt/config.h b/include/xbt/config.h index a9e4c70181..4061014295 100644 --- a/include/xbt/config.h +++ b/include/xbt/config.h @@ -131,10 +131,11 @@ struct xbt_boolean_couple { }; /** \brief Callback types. They get the name of the modified entry, and the position of the changed value */ -typedef void (*xbt_cfg_cb_t) (const char *); +typedef void (*xbt_cfg_cb_t) (const char * name); +typedef void (*xbt_cfg_cb_ext_t)(const char * name, void* cb_data); +typedef void (*xbt_cfg_cb_free_t)(void* cb_data); XBT_PUBLIC(xbt_cfg_t) xbt_cfg_new(void); -XBT_PUBLIC(void) xbt_cfg_cpy(xbt_cfg_t tocopy, /* OUT */xbt_cfg_t * whereto); XBT_PUBLIC(void) xbt_cfg_free(xbt_cfg_t * cfg); XBT_PUBLIC(void) xbt_cfg_dump(const char *name, const char *indent, xbt_cfg_t cfg); @@ -154,6 +155,10 @@ XBT_PUBLIC(void) xbt_cfg_register_boolean(const char *name, const char*default_v XBT_PUBLIC(void) xbt_cfg_register_alias(const char *newname, const char *oldname); XBT_PUBLIC(void) xbt_cfg_register_str(xbt_cfg_t * cfg, const char *entry); +XBT_PUBLIC(void) xbt_cfg_register_ext( + const char *name, const char *desc, e_xbt_cfgelm_type_t type, + xbt_cfg_cb_ext_t cb, void* data, xbt_cfg_cb_free_t data_free); + XBT_PUBLIC(void) xbt_cfg_aliases(void); XBT_PUBLIC(void) xbt_cfg_help(void); XBT_PUBLIC(e_xbt_cfgelm_type_t) xbt_cfg_get_type(xbt_cfg_t cfg, const char *name); diff --git a/include/xbt/config.hpp b/include/xbt/config.hpp new file mode 100644 index 0000000000..f87f525c38 --- /dev/null +++ b/include/xbt/config.hpp @@ -0,0 +1,194 @@ +/* Copyright (c) 2016. The SimGrid Team. + * All rights reserved. */ + +/* This program is free software; you can redistribute it and/or modify it + * under the terms of the license (GNU LGPL) which comes with this package. */ + +#ifndef _XBT_CONFIG_HPP_ +#define _XBT_CONFIG_HPP_ + +#include +#include +#include + +#include +#include + +namespace simgrid { +namespace config { + +/** Get the base type of a e_xbt_cfgelm_type_t + * + * * `type` is the type used in the config framework to store + * the values of this type; + * + * * `get()` is used to get such a value from the configuration. + */ +template +struct base_type; +template<> struct base_type { + typedef bool type; + static inline bool get(const char* name) + { + return xbt_cfg_get_boolean(name) ? true : false; + } +}; +template<> struct base_type { + typedef int type; + static inline int get(const char* name) + { + return xbt_cfg_get_int(name); + } +}; +template<> struct base_type { + typedef double type; + static inline double get(const char* name) + { + return xbt_cfg_get_double(name); + } +}; +template<> struct base_type { + typedef std::string type; + static inline std::string get(const char* name) + { + char* value = xbt_cfg_get_string(name); + return value != nullptr ? value : ""; + } +}; + +/** Associate the e_xbt_cfgelm_type_t to use for a given type */ +template +struct cfgelm_type : public std::integral_constant::value ? xbt_cfgelm_boolean : + std::is_integral::value ? xbt_cfgelm_int : + std::is_floating_point::value ? xbt_cfgelm_double : + xbt_cfgelm_string> +{}; + +/** Get a value of a given type from the configuration */ +template inline +T get(const char* name) +{ + return T(base_type::value>::get(name)); +} +template inline +T get(std::string const& name) +{ + return T(base_type::value>::get(name.c_str())); +} + +inline void setDefault(const char* name, int value) +{ + xbt_cfg_setdefault_int(name, value); +} +inline void setDefault(const char* name, double value) +{ + xbt_cfg_setdefault_double(name, value); +} +inline void setDefault(const char* name, const char* value) +{ + xbt_cfg_setdefault_string(name, value); +} +inline void setDefault(const char* name, std::string const& value) +{ + xbt_cfg_setdefault_string(name, value.c_str()); +} +inline void setDefault(const char* name, bool value) +{ + xbt_cfg_setdefault_boolean(name, value ? "yes" : "no"); +} + +/** Set the default value of a given configuration option */ +template inline +void setDefault(const char* name, T value) +{ + setDefault(name, base_type::value>::type(value)); +} + +// Register: + +/** Register a configuration flag + * + * @param name name of the option + * @param description Description of the option + * @param type config storage type for the option + * @param callback called with the option name (expected to use `simgrid::config::get`) + */ +XBT_PUBLIC(void) registerConfig(const char* name, const char* description, + e_xbt_cfgelm_type_t type, + std::function callback); + +/** Bind a variable to configuration flag + * + * @param value Bound variable + * @param name Flag name + * @param description Option description + */ +template +void declareFlag(T& value, const char* name, const char* description) +{ + registerConfig(name, description, cfgelm_type::value, + [&value](const char* name) { + value = simgrid::config::get(name); + }); + setDefault(name, value); +} + +/** Bind a variable to configuration flag + * + * @param value Bound variable + * @param name Flag name + * @param description Option description + * @f Callback (called with the option name) providing the value + */ +template +void declareFlag(T& value, const char* name, const char* description, F f) +{ + registerConfig(name, description, cfgelm_type::value, + [&value,f](const char* name) { + value = f(name); + }); + setDefault(name, value); +} + +/** A variable bound to a CLI option + * + *

+ *  static simgrid::config::flag answer("answer", "Expected answer", 42);
+ *  static simgrid::config::flag name("name", "Ford Prefect", "John Doe");
+ *  static simgrid::config::flag gamma("gamma", "Gamma factor", 1.987);
+ *  
+ */ +template +class flag { + T value_; +public: + + /** Constructor + * + * @param name Flag name + * @param desc Flag description + * @param value Flag initial/default value + */ + flag(const char* name, const char* desc, T value) : value_(value) + { + declareFlag(value_, name, desc); + } + + // No copy: + flag(flag const&) = delete; + flag& operator=(flag const&) = delete; + + // Get the underlying value: + T& get() { return value_; } + T const& get() const { return value_; } + + // Implicit conversion to the underlying type: + operator T&() { return value_; } + operator T const&() const{ return value_; } +}; + +} +} + +#endif diff --git a/src/xbt/config.c b/src/xbt/config.c index 7c3de17497..80b48028e6 100644 --- a/src/xbt/config.c +++ b/src/xbt/config.c @@ -22,7 +22,6 @@ XBT_LOG_NEW_DEFAULT_SUBCATEGORY(xbt_cfg, xbt, "configuration support"); XBT_EXPORT_NO_IMPORT(xbt_cfg_t) simgrid_config = NULL; -static void xbt_cfg_register(xbt_cfg_t * cfg, const char *name, const char *desc, e_xbt_cfgelm_type_t type, xbt_cfg_cb_t cb_set); /* xbt_cfgelm_t: the typedef corresponding to a config variable. */ @@ -37,6 +36,11 @@ typedef struct { /* Callbacks */ xbt_cfg_cb_t cb_set; + /* Advanced callbacks */ + xbt_cfg_cb_ext_t cb_set_ext; + void* cb_set_data; + xbt_cfg_cb_free_t cb_set_free; + /* actual content (could be an union or something) */ xbt_dynar_t content; } s_xbt_cfgelm_t, *xbt_cfgelm_t; @@ -67,27 +71,6 @@ xbt_cfg_t xbt_cfg_new(void) return (xbt_cfg_t) xbt_dict_new_homogeneous(&xbt_cfgelm_free); } -/** \brief Copy an existing configuration set - * - * @param whereto the config set to be created - * @param tocopy the source data - * - * This only copy the registrations, not the actual content - */ -void xbt_cfg_cpy(xbt_cfg_t tocopy, xbt_cfg_t * whereto) -{ - xbt_dict_cursor_t cursor = NULL; - xbt_cfgelm_t variable = NULL; - char *name = NULL; - - XBT_DEBUG("Copy cfg set %p", tocopy); - *whereto = NULL; - xbt_assert(tocopy, "cannot copy NULL config"); - - xbt_dict_foreach((xbt_dict_t) tocopy, cursor, name, variable) - xbt_cfg_register(whereto, name, variable->desc, variable->type, variable->cb_set); -} - /** @brief Destructor */ void xbt_cfg_free(xbt_cfg_t * cfg) { @@ -120,7 +103,7 @@ void xbt_cfg_dump(const char *name, const char *indent, xbt_cfg_t cfg) printf("%s %s:", indent, key); size = xbt_dynar_length(variable->content); - printf ("%s. Actual size=%d. postset=%p, List of values:\n", + printf ("%s. Actual size=%d. postset=%p\n", xbt_cfgelm_type_name[variable->type], size, variable->cb_set); switch (variable->type) { @@ -174,6 +157,8 @@ void xbt_cfgelm_free(void *data) XBT_DEBUG("Frees cfgelm %p", c); if (!c) return; + if (c->cb_set_free) + c->cb_set_free(c->cb_set_data); xbt_free(c->desc); if (c->type != xbt_cfgelm_alias) xbt_dynar_free(&(c->content)); @@ -189,7 +174,10 @@ void xbt_cfgelm_free(void *data) * @param type the type of the config element * @param cb_set callback function called when a value is set */ -static void xbt_cfg_register(xbt_cfg_t * cfg, const char *name, const char *desc, e_xbt_cfgelm_type_t type, xbt_cfg_cb_t cb_set) +static void xbt_cfg_register( + xbt_cfg_t * cfg, const char *name, const char *desc, e_xbt_cfgelm_type_t type, + xbt_cfg_cb_t cb_set, + xbt_cfg_cb_ext_t cb_set_ext, void* cb_set_data, xbt_cfg_cb_free_t cb_set_free) { if (*cfg == NULL) *cfg = xbt_cfg_new(); @@ -207,6 +195,9 @@ static void xbt_cfg_register(xbt_cfg_t * cfg, const char *name, const char *desc res->desc = xbt_strdup(desc); res->type = type; res->cb_set = cb_set; + res->cb_set_ext = cb_set_ext; + res->cb_set_data = cb_set_data; + res->cb_set_free = cb_set_free; res->isdefault = 1; switch (type) { @@ -229,23 +220,40 @@ static void xbt_cfg_register(xbt_cfg_t * cfg, const char *name, const char *desc xbt_dict_set((xbt_dict_t) * cfg, name, res, NULL); } + + void xbt_cfg_register_double(const char *name, double default_value,xbt_cfg_cb_t cb_set, const char *desc){ - xbt_cfg_register(&simgrid_config,name,desc,xbt_cfgelm_double,cb_set); + xbt_cfg_register(&simgrid_config,name,desc,xbt_cfgelm_double,cb_set, NULL, NULL, NULL); xbt_cfg_setdefault_double(name, default_value); } void xbt_cfg_register_int(const char *name, int default_value,xbt_cfg_cb_t cb_set, const char *desc) { - xbt_cfg_register(&simgrid_config,name,desc,xbt_cfgelm_int,cb_set); + xbt_cfg_register(&simgrid_config,name,desc,xbt_cfgelm_int,cb_set, NULL, NULL, NULL); xbt_cfg_setdefault_int(name, default_value); } void xbt_cfg_register_string(const char *name, const char *default_value, xbt_cfg_cb_t cb_set, const char *desc){ - xbt_cfg_register(&simgrid_config,name,desc,xbt_cfgelm_string,cb_set); + xbt_cfg_register(&simgrid_config,name,desc,xbt_cfgelm_string,cb_set, NULL, NULL, NULL); xbt_cfg_setdefault_string(name, default_value); } void xbt_cfg_register_boolean(const char *name, const char*default_value,xbt_cfg_cb_t cb_set, const char *desc){ - xbt_cfg_register(&simgrid_config,name,desc,xbt_cfgelm_boolean,cb_set); + xbt_cfg_register(&simgrid_config,name,desc,xbt_cfgelm_boolean,cb_set, NULL, NULL, NULL); xbt_cfg_setdefault_boolean(name, default_value); } +/** Register a config with an extended callback + * + * @param name Name of the flag + * @param desc Description of the flag + * @param type Type of the flag + * @param cb Extended callback + * @param data Data associated with the callback + * @param data_free Function used to free the callback data (or NULL) + */ +void xbt_cfg_register_ext(const char *name, const char *desc, e_xbt_cfgelm_type_t type, + xbt_cfg_cb_ext_t cb, void* data, xbt_cfg_cb_free_t data_free) +{ + xbt_cfg_register(&simgrid_config, name, desc, type, NULL, cb, data, data_free); +} + void xbt_cfg_register_alias(const char *newname, const char *oldname) { if (simgrid_config == NULL) @@ -296,7 +304,7 @@ void xbt_cfg_register_str(xbt_cfg_t * cfg, const char *entry) xbt_assert(type < xbt_cfgelm_type_count, "Invalid type in config element descriptor: %s; Should be one of 'string', 'int' or 'double'.", entry); - xbt_cfg_register(cfg, entrycpy, NULL, type, NULL); + xbt_cfg_register(cfg, entrycpy, NULL, type, NULL, NULL, NULL, NULL); free(entrycpy); /* strdup'ed by dict mechanism, but cannot be const */ } @@ -696,6 +704,8 @@ void xbt_cfg_set_int(const char *name, int val) if (variable->cb_set) variable->cb_set(name); + if (variable->cb_set_ext) + variable->cb_set_ext(name, variable->cb_set_data); variable->isdefault = 0; } @@ -712,6 +722,8 @@ void xbt_cfg_set_double(const char *name, double val) if (variable->cb_set) variable->cb_set(name); + if (variable->cb_set_ext) + variable->cb_set_ext(name, variable->cb_set_data); variable->isdefault = 0; } @@ -736,6 +748,8 @@ void xbt_cfg_set_string(const char *name, const char *val) if (variable->cb_set) variable->cb_set(name); + if (variable->cb_set_ext) + variable->cb_set_ext(name, variable->cb_set_data); variable->isdefault = 0; } @@ -764,6 +778,8 @@ void xbt_cfg_set_boolean(const char *name, const char *val) if (variable->cb_set) variable->cb_set(name); + if (variable->cb_set_ext) + variable->cb_set_ext(name, variable->cb_set_data); variable->isdefault = 0; } diff --git a/src/xbt/config.cpp b/src/xbt/config.cpp new file mode 100644 index 0000000000..964343c37d --- /dev/null +++ b/src/xbt/config.cpp @@ -0,0 +1,37 @@ +/* Copyright (c) 2016. The SimGrid Team. + * All rights reserved. */ + +/* This program is free software; you can redistribute it and/or modify it + * under the terms of the license (GNU LGPL) which comes with this package. */ + +#include +#include + +#include +#include + +namespace simgrid { +namespace config { + +static void callCallback(const char* name, void* data) +{ + (*(std::function*) data)(name); +} + +static void freeCallback(void* data) +{ + delete (std::function*) data; +} + +void registerConfig(const char* name, const char* description, + e_xbt_cfgelm_type_t type, + std::function callback) +{ + std::function* code + = new std::function(std::move(callback)); + xbt_cfg_register_ext(name, description, type, + callCallback, code, freeCallback); +} + +} +} \ No newline at end of file diff --git a/tools/cmake/DefinePackages.cmake b/tools/cmake/DefinePackages.cmake index 74ff5d9996..570528b5d3 100644 --- a/tools/cmake/DefinePackages.cmake +++ b/tools/cmake/DefinePackages.cmake @@ -239,6 +239,7 @@ set(XBT_SRC src/xbt/automaton/automaton.c src/xbt/automaton/automatonparse_promela.c src/xbt/config.c + src/xbt/config.cpp src/xbt/cunit.c src/xbt/dict.c src/xbt/dict_cursor.c @@ -666,6 +667,7 @@ set(headers_to_install include/xbt/automaton.hpp include/xbt/base.h include/xbt/config.h + include/xbt/config.hpp include/xbt/cunit.h include/xbt/dict.h include/xbt/string.hpp