Skip to content

Commit

Permalink
allow virtual configs to be templated to set optional value before co…
Browse files Browse the repository at this point in the history
…nstructing (#37)
  • Loading branch information
nathanhhughes authored Nov 25, 2024
1 parent 83595cb commit e435b99
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 8 deletions.
17 changes: 9 additions & 8 deletions config_utilities/include/config_utilities/virtual_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,9 @@ namespace config {
* class.
*
* @tparam BaseT The base class of the object that should be created from the config.
* @tparam BaseT Whether or not the virtual config is optional when constructed (useful for maps and vectors of configs)
*/
template <class BaseT>
template <class BaseT, bool OptionalByDefault = false>
class VirtualConfig {
public:
VirtualConfig() = default;
Expand Down Expand Up @@ -184,25 +185,25 @@ class VirtualConfig {
}

private:
template <typename T>
friend void declare_config(VirtualConfig<T>&);
template <typename T, bool Opt>
friend void declare_config(VirtualConfig<T, Opt>&);
friend struct internal::Visitor;

bool optional_ = false;
bool optional_ = OptionalByDefault;
std::unique_ptr<internal::ConfigWrapper> config_;
};

namespace internal {

// Declare virtual config types.
template <typename T>
struct is_virtual_config<VirtualConfig<T>> : std::true_type {};
template <typename T, bool Opt>
struct is_virtual_config<VirtualConfig<T, Opt>> : std::true_type {};

} // namespace internal

// Declare the Virtual Config a config, so it can be handled like any other object.
template <typename BaseT>
void declare_config(VirtualConfig<BaseT>& config) {
template <typename BaseT, bool Opt>
void declare_config(VirtualConfig<BaseT, Opt>& config) {
auto data = internal::Visitor::visitVirtualConfig(config.isSet(), config.optional_, config.getType());

// underlying derived type is not required if the config is optional, or if the config has been
Expand Down
36 changes: 36 additions & 0 deletions config_utilities/test/tests/virtual_config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,27 @@ void declare_config(ObjectWithBase::Config& config) {
config::field(config.base_config, "base_config", false);
}

struct ObjectWithOptionalConfigs {
struct Config {
std::vector<VirtualConfig<Base2, true>> modules;
} const config;

explicit ObjectWithOptionalConfigs(const Config& config) : config(config::checkValid(config)) {
for (const auto& base_config : config.modules) {
if (base_config) {
valid.emplace_back(base_config.create());
}
}
}

std::vector<std::unique_ptr<Base2>> valid;
};

void declare_config(ObjectWithOptionalConfigs::Config& config) {
config::name("ObjectWithOptionalConfigs");
config::field(config.modules, "modules");
}

TEST(VirtualConfig, isSet) {
Settings().restoreDefaults();

Expand Down Expand Up @@ -348,4 +369,19 @@ TEST(VirtualConfig, getUnderlying) {
EXPECT_TRUE(config.getUnderlying<Derived2A::Config>());
}

TEST(VirtualConfig, optionalByDefault) {
Settings().restoreDefaults();

const std::string yaml_str = R"""(modules:
- {type: testing}
- {a: 5, b: 6}
- {type: Derived2}
)""";

const auto node = YAML::Load(yaml_str);
const auto config = config::fromYaml<ObjectWithOptionalConfigs::Config>(node);
const ObjectWithOptionalConfigs object(config);
EXPECT_EQ(object.valid.size(), 1u);
}

} // namespace config::test

0 comments on commit e435b99

Please sign in to comment.