Skip to content

Add try_dynamic_cast from rvalue to optionalt #4028

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 5, 2019

Conversation

thomasspriggs
Copy link
Contributor

@thomasspriggs thomasspriggs commented Feb 2, 2019

This pr adds templates for expr_try_dynamic_cast and
type_try_dynamic_cast where the parameter is an rvalue and the return
type is an optionalt. This is implemented by moving the parameter into
the optionalt.

Included are unit tests of the new templates, which show that they
return the types and values expected. As well as tests and a static
assert for the existing overloads which show that they still return a
pointer.

These new templates are useful in the case where we are using the
result of a function, which returns by value but only in the case where
the value can be cast to a given type. For example with the new
overloads the following code can be written -

exprt enig();
void handle_struct_case(const struct_exprt &struct_expr);

void myFunction()
{
  if(const auto my_struct = expr_try_dynamic_cast<struct_exprt>(enig()))
    handle_struct_case(*my_struct);
}

However without the new templates and because the old ones do not bind
to rvalues, an additional temporary variable otherwise would have to be
declared -

void myFunction2()
{
  const exprt enigma = enig();
  if(const auto my_struct = expr_try_dynamic_cast<struct_exprt>(enigma))
    handle_struct_case(*my_struct);
}
  • Each commit message has a non-empty body, explaining why the change was made.
  • Methods or procedures I have added are documented, following the guidelines provided in CODING_STANDARD.md.
  • The feature or user visible behaviour I have added or modified has been documented in the User Guide in doc/cprover-manual/
  • Regression or unit tests are included, or existing tests cover the modified code (in this case I have detailed which ones those are in the commit message).
  • My commit message includes data points confirming performance improvements (if claimed).
  • My PR is restricted to a single feature or bugfix.
  • White-space or formatting changes outside the feature-related changed lines are in commits of their own.

@@ -107,6 +107,32 @@ auto expr_try_dynamic_cast(TExpr &base)
return ret;
}

/// \brief Try to cast a generic exprt to a specific derived class.
/// \tparam T: The type to cast the `base` param to.
/// \tparam TType: The original type to cast from, Must be a exprt rvalue.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit pick: s/Must/must/

@@ -107,6 +107,32 @@ auto expr_try_dynamic_cast(TExpr &base)
return ret;
}

/// \brief Try to cast a generic exprt to a specific derived class.
/// \tparam T: The type to cast the `base` param to.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit pick: I'd use \p base (it will be rendered the same way, but conveys the fact that this is a parameter)

return {};
optionalt<T> ret{static_cast<T &&>(base)};
validate_expr(*ret);
return ret;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It probably doesn't make much of a difference, other than saving one line, but I'd have used:

validate_expr(base);
return std::move(base);

@@ -134,6 +160,31 @@ auto type_try_dynamic_cast(TType &base) ->
return ret;
}

/// \brief Try to cast a generic typet to a specific derived class.
/// \tparam T: The type to cast the `base` param to.
/// \tparam TType: The original type to cast from, Must be a typet rvalue.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All the same comments as above apply...

Copy link
Contributor

@smowton smowton left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, one nitpick

{
typet type = string_type;

THEN("Trying casting a value to a string_typet should yield a non null "
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a value -> a string type throughout?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No. I think the update should be a value -> a typet lvalue, in order to make things clear.

This commit adds templates for `expr_try_dynamic_cast` and
`type_try_dynamic_cast` where the parameter is an rvalue and the return
type is an `optionalt`. This is implemented by moving the parameter into
the `optionalt`.

Included are unit tests of the new templates, which show that they
return the types and values expected. As well as tests and a static
assert for the existing overloads which show that they still return a
pointer.

These new templates are useful in the case where we are using the
result of a function, which returns by value but only in the case where
the value can be cast to a given type. For example with the new
overloads the following code can be written -
```
exprt enig();
void handle_struct_case(const struct_exprt &struct_expr);

void myFunction()
{
  if(const auto my_struct = expr_try_dynamic_cast<struct_exprt>(enig()))
    handle_struct_case(*my_struct);
}
```
However without the new templates and because the old ones do not bind
to rvalues, an additional temporary variable otherwise would have to be
declared -
```
void myFunction2()
{
  const exprt enigma = enig();
  if(const auto my_struct = expr_try_dynamic_cast<struct_exprt>(enigma))
    handle_struct_case(*my_struct);
}
```
Copy link
Contributor

@allredj allredj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✔️
Passed Diffblue compatibility checks (cbmc commit: 52e95a6).
Build URL: https://travis-ci.com/diffblue/test-gen/builds/99777773

@thomasspriggs thomasspriggs merged commit 88ab7d5 into diffblue:develop Feb 5, 2019
@thomasspriggs thomasspriggs deleted the tas/optional_cast branch February 5, 2019 14:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants