Skip to content

Commit

Permalink
Add an API to reset/unset options and expose it at CLI level (#1640)
Browse files Browse the repository at this point in the history
  • Loading branch information
Yogesh9000 authored Sep 30, 2024
1 parent f7c013c commit ebf5575
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 1 deletion.
11 changes: 10 additions & 1 deletion cmake/f3dOptions.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ function (f3d_generate_options)
list(JOIN _options_string_setter ";\n else " _options_string_setter)
list(JOIN _options_string_getter ";\n else " _options_string_getter)
list(JOIN _options_lister ",\n " _options_lister)
list(JOIN _options_is_optional ";\n else " _options_is_optional)
list(JOIN _options_reset ";\n else " _options_reset)

configure_file(
"${_f3d_generate_options_INPUT_PUBLIC_HEADER}"
Expand Down Expand Up @@ -133,12 +135,17 @@ function(_parse_json_option _top_json)

if(_default_value_error STREQUAL "NOTFOUND")
# Use default_value
string(APPEND _options_struct "${_option_indent} ${_option_actual_type} ${_member_name} = ${_option_default_value_start}${_option_default_value}${_option_default_value_end};\n")
set(_optional_default_value_initialize "${_option_default_value_start}${_option_default_value}${_option_default_value_end}")
string(APPEND _options_struct "${_option_indent} ${_option_actual_type} ${_member_name} = ${_optional_default_value_initialize};\n")
set(_optional_getter "")
list(APPEND _options_is_optional "if (name == \"${_option_name}\") return false")
list(APPEND _options_reset "if (name == \"${_option_name}\") opt.${_option_name} = ${_optional_default_value_initialize}")
else()
# No default_value, it is an std::optional
string(APPEND _options_struct "${_option_indent} std::optional<${_option_actual_type}> ${_member_name};\n")
set(_optional_getter ".value()")
list(APPEND _options_is_optional "if (name == \"${_option_name}\") return true")
list(APPEND _options_reset "if (name == \"${_option_name}\") opt.${_option_name}.reset()")
endif()

list(APPEND _options_setter "if (name == \"${_option_name}\") opt.${_option_name} = std::get<${_option_variant_type}>(value)")
Expand Down Expand Up @@ -168,4 +175,6 @@ function(_parse_json_option _top_json)
set(_options_string_setter ${_options_string_setter} PARENT_SCOPE)
set(_options_string_getter ${_options_string_getter} PARENT_SCOPE)
set(_options_lister ${_options_lister} PARENT_SCOPE)
set(_options_is_optional ${_options_is_optional} PARENT_SCOPE)
set(_options_reset ${_options_reset} PARENT_SCOPE)
endfunction()
25 changes: 25 additions & 0 deletions library/private/options_tools.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,31 @@ std::string getAsString(const options& opt, const std::string& name)
throw options::no_value_exception("Trying to get " + name + " before it was set");
}
}

//----------------------------------------------------------------------------
/**
* Generated method, see `options::isOptional`
*/
bool isOptional(const std::string& name)
{
// clang-format off
${_options_is_optional};
// clang-format on
else throw options::inexistent_exception("Option " + name + " does not exist");
}

//----------------------------------------------------------------------------
/**
* Generated method, see `options::reset`
*/
void reset(options& opt, const std::string& name)
{
// clang-format off
${_options_reset};
// clang-format on
else throw options::inexistent_exception("Option " + name + " does not exist");
}

} // option_tools
} // f3d
#endif // f3d_options_tools_h
18 changes: 18 additions & 0 deletions library/public/options.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,24 @@ public:
*/
std::pair<std::string, unsigned int> getClosestOption(const std::string& option) const;

/**
* Returns true if the option is optional else returns false.
* Throws an options::inexistent_exception if option does not exist.
*/
bool isOptional(const std::string& option) const;

/**
* Resets the option to default value.
* Throws an options::inexistent_exception if option does not exist.
*/
void reset(const std::string& name);

/**
* Unset the option if it is optional else throws options::incompatible_exception.
* Throws an options::inexistent_exception if option does not exist.
*/
void removeValue(const std::string& name);

/**
* Templated parsing method used internally to parse strings.
* Implemented for:
Expand Down
25 changes: 25 additions & 0 deletions library/src/options.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,31 @@ std::pair<std::string, unsigned int> options::getClosestOption(const std::string
return ret;
}

//----------------------------------------------------------------------------
bool options::isOptional(const std::string& option) const
{
return options_tools::isOptional(option);
}

//----------------------------------------------------------------------------
void options::reset(const std::string& name)
{
options_tools::reset(*this, name);
}

//----------------------------------------------------------------------------
void options::removeValue(const std::string& name)
{
if (this->isOptional(name))
{
this->reset(name);
}
else
{
throw options::incompatible_exception("Option " + name + " is not not optional");
}
}

//----------------------------------------------------------------------------
template<typename T>
T options::parse(const std::string& str)
Expand Down
47 changes: 47 additions & 0 deletions library/testing/TestSDKOptions.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -195,5 +195,52 @@ int TestSDKOptions(int argc, char* argv[])
test.expect<f3d::options::no_value_exception>("no_value_exception exception on getAsString",
[&]() { opt.getAsString("scene.animation.time"); });

f3d::options opt6{};

// Test isOptional optional values
test("isOptional with optional value", opt6.isOptional("model.scivis.array_name"));
test("isOptional with optional value", opt6.isOptional("model.scivis.range"));

// Test isOptional non-optional values
test("isOptional with non-optional value", opt6.isOptional("model.scivis.cells") == false);
test("isOptional with non-optional value", opt6.isOptional("model.scivis.enable") == false);

// Test isOptional non-existent options
test.expect<f3d::options::inexistent_exception>(
"isOptional with non-existent option", [&]() { opt6.isOptional("dummy"); });

f3d::options opt7{};

// Test reset non-optional values
opt7.model.color.opacity = 0.5;
opt7.reset("model.color.opacity");
test("reset non-optional values", opt7.model.color.opacity == 1.0);

// Test reset optional values
opt7.model.scivis.array_name = "dummy";
opt7.reset("model.scivis.array_name");
test.expect<f3d::options::no_value_exception>(
"reset non-optional values", [&]() { opt7.get("model.scivis.array_name"); });

// Test reset non-existent option
test.expect<f3d::options::inexistent_exception>(
"reset with non-existent option", [&]() { opt7.reset("dummy"); });

f3d::options opt8{};

// Test removeValue optional values
opt8.model.scivis.array_name = "dummy";
opt8.removeValue("model.scivis.array_name");
test.expect<f3d::options::no_value_exception>(
"removeValue optional values", [&]() { opt8.get("model.scivis.array_name"); });

// Test removeValue non-optional values
test.expect<f3d::options::incompatible_exception>(
"removeValue non-optional values", [&]() { opt8.removeValue("model.scivis.cells"); });

// Test removeValue non-optional values
test.expect<f3d::options::inexistent_exception>(
"removeValue non-existent option", [&]() { opt8.removeValue("dummy"); });

return EXIT_SUCCESS;
}

0 comments on commit ebf5575

Please sign in to comment.