From a1b16efdebab120c8dca526702f4ae4791ff228b Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Fri, 6 Apr 2018 15:04:38 +0200 Subject: [PATCH] Move dynamic_unique_cast to Utilities --- doc/news/changes/minor/20180403Bangerth | 5 +- include/deal.II/base/std_cxx11/unique_ptr.h | 67 --------------------- include/deal.II/base/utilities.h | 62 +++++++++++++++++++ source/fe/mapping_q.cc | 13 ++-- tests/base/dynamic_unique_cast.cc | 9 +-- 5 files changed, 73 insertions(+), 83 deletions(-) diff --git a/doc/news/changes/minor/20180403Bangerth b/doc/news/changes/minor/20180403Bangerth index d5828853ea..66e1c17e3f 100644 --- a/doc/news/changes/minor/20180403Bangerth +++ b/doc/news/changes/minor/20180403Bangerth @@ -1,5 +1,4 @@ -New: There is now a function dynamic_unique_cast() that does for -`std::unique_ptr` objects what `dynamic_cast` does for regular -pointers. +New: There is now a function Utilities::dynamic_unique_cast() that does for +`std::unique_ptr` objects what `dynamic_cast` does for regular pointers.
(Wolfgang Bangerth, 2018/04/03) diff --git a/include/deal.II/base/std_cxx11/unique_ptr.h b/include/deal.II/base/std_cxx11/unique_ptr.h index 0182927a3e..d99ad5cc68 100644 --- a/include/deal.II/base/std_cxx11/unique_ptr.h +++ b/include/deal.II/base/std_cxx11/unique_ptr.h @@ -33,71 +33,4 @@ DEAL_II_NAMESPACE_OPEN namespace std_cxx1x = std_cxx11; DEAL_II_NAMESPACE_CLOSE - -DEAL_II_NAMESPACE_OPEN - -/** - * Convert an object of type `std::unique_ptr` to an object of - * type `std::unique_ptr`, where it is assumed that we can cast - * the pointer to `From` to a pointer to `To` using a `dynamic_cast` - * -- in other words, we assume that `From` and `To` are connected - * through a class hierarchy, and that the object pointed to is in - * fact of a type that contains both a `From` and a `To`. An example - * is if either `To` is derived from `From` or the other way around. - * - * The function throws an exception of type `std::bad_cast` if the - * `dynamic_cast` does not succeed. This is the same exception you - * would get if a regular `dynamic_cast` between object types (but not - * pointer types) does not succeed. - * - * An example of how this function works is as follows: - * @code - * class B { ... }; // A base class. Assume that it has virtual - * // functions so that dynamic_cast can work. - * class D : public B { ... }; // A derived class - * - * - * std::unique_ptr create_object (...) {...} // A factory function - * - * void foo (...) - * { - * std::unique_ptr b = create_object (...); - * - * // Assume that we know for some reason that the object above must - * // have created a D object but returned it as a std::unique_ptr. - * // In order to access the D functionality, we need to cast the - * // pointer. Use the equivalent to dynamic_cast: - * std::unique_ptr d = dynamic_unique_cast(std::move(b)); - * - * // If the object really was a D, then 'd' now points to it. Note - * // also that in accordance with the semantics of std::unique_ptr, - * // it was necessary to std::move the 'b' object, and indeed 'b' - * // now no longer points to anything -- ownership has been - * // transferred to 'd'! - * @endcode - * - * @note This function does not try to convert the `Deleter` objects stored - * by `std::unique_ptr` objects. The function therefore only works if the - * deleter objects are at their defaults, i.e., if they are of type - * `std::default_delete` and `std::default_delete`. - */ -template -std::unique_ptr -dynamic_unique_cast (std::unique_ptr &&p) -{ - // Let's see if we can cast from 'From' to 'To'. If so, do the cast, - // and then release the pointer from the old - // owner - if (To *cast = dynamic_cast(p.get())) - { - std::unique_ptr result(cast); - p.release(); - return result; - } - else - throw std::bad_cast(); -} - -DEAL_II_NAMESPACE_CLOSE - #endif diff --git a/include/deal.II/base/utilities.h b/include/deal.II/base/utilities.h index 69272ecac9..051662d6ee 100644 --- a/include/deal.II/base/utilities.h +++ b/include/deal.II/base/utilities.h @@ -505,6 +505,68 @@ namespace Utilities void unpack (const std::vector &buffer, T (&unpacked_object)[N]); + /** + * Convert an object of type `std::unique_ptr` to an object of + * type `std::unique_ptr`, where it is assumed that we can cast + * the pointer to `From` to a pointer to `To` using a `dynamic_cast` + * -- in other words, we assume that `From` and `To` are connected + * through a class hierarchy, and that the object pointed to is in + * fact of a type that contains both a `From` and a `To`. An example + * is if either `To` is derived from `From` or the other way around. + * + * The function throws an exception of type `std::bad_cast` if the + * `dynamic_cast` does not succeed. This is the same exception you + * would get if a regular `dynamic_cast` between object types (but not + * pointer types) does not succeed. + * + * An example of how this function works is as follows: + * @code + * class B { ... }; // A base class. Assume that it has virtual + * // functions so that dynamic_cast can work. + * class D : public B { ... }; // A derived class + * + * + * std::unique_ptr create_object (...) {...} // A factory function + * + * void foo (...) + * { + * std::unique_ptr b = create_object (...); + * + * // Assume that we know for some reason that the object above must + * // have created a D object but returned it as a std::unique_ptr. + * // In order to access the D functionality, we need to cast the + * // pointer. Use the equivalent to dynamic_cast: + * std::unique_ptr d = dynamic_unique_cast(std::move(b)); + * + * // If the object really was a D, then 'd' now points to it. Note + * // also that in accordance with the semantics of std::unique_ptr, + * // it was necessary to std::move the 'b' object, and indeed 'b' + * // now no longer points to anything -- ownership has been + * // transferred to 'd'! + * @endcode + * + * @note This function does not try to convert the `Deleter` objects stored + * by `std::unique_ptr` objects. The function therefore only works if the + * deleter objects are at their defaults, i.e., if they are of type + * `std::default_delete` and `std::default_delete`. + */ + template + std::unique_ptr + dynamic_unique_cast (std::unique_ptr &&p) + { + // Let's see if we can cast from 'From' to 'To'. If so, do the cast, + // and then release the pointer from the old + // owner + if (To *cast = dynamic_cast(p.get())) + { + std::unique_ptr result(cast); + p.release(); + return result; + } + else + throw std::bad_cast(); + } + /** * A namespace for utility functions that probe system properties. * diff --git a/source/fe/mapping_q.cc b/source/fe/mapping_q.cc index 9fd1fbc34a..136dc8e7ab 100644 --- a/source/fe/mapping_q.cc +++ b/source/fe/mapping_q.cc @@ -13,7 +13,6 @@ // // --------------------------------------------------------------------- -#include #include #include #include @@ -159,11 +158,11 @@ MappingQ::get_data (const UpdateFlags update_flags, quadrature); if (!use_mapping_q_on_all_cells) - data->mapping_q1_data = dynamic_unique_cast::InternalData> + data->mapping_q1_data = Utilities::dynamic_unique_cast::InternalData> (std::move(q1_mapping->get_data (update_flags, quadrature))); // wait for the task above to finish and use returned value - data->mapping_qp_data = dynamic_unique_cast::InternalData> + data->mapping_qp_data = Utilities::dynamic_unique_cast::InternalData> (std::move(do_get_data.return_value())); return std::move(data); @@ -186,11 +185,11 @@ MappingQ::get_face_data (const UpdateFlags update_flags, quadrature); if (!use_mapping_q_on_all_cells) - data->mapping_q1_data = dynamic_unique_cast::InternalData> + data->mapping_q1_data = Utilities::dynamic_unique_cast::InternalData> (std::move(q1_mapping->get_face_data (update_flags, quadrature))); // wait for the task above to finish and use returned value - data->mapping_qp_data = dynamic_unique_cast::InternalData> + data->mapping_qp_data = Utilities::dynamic_unique_cast::InternalData> (std::move(do_get_data.return_value())); return std::move(data); } @@ -212,11 +211,11 @@ MappingQ::get_subface_data (const UpdateFlags update_flags, quadrature); if (!use_mapping_q_on_all_cells) - data->mapping_q1_data = dynamic_unique_cast::InternalData> + data->mapping_q1_data = Utilities::dynamic_unique_cast::InternalData> (std::move(q1_mapping->get_subface_data (update_flags, quadrature))); // wait for the task above to finish and use returned value - data->mapping_qp_data = dynamic_unique_cast::InternalData> + data->mapping_qp_data = Utilities::dynamic_unique_cast::InternalData> (std::move(do_get_data.return_value())); return std::move(data); } diff --git a/tests/base/dynamic_unique_cast.cc b/tests/base/dynamic_unique_cast.cc index 0707a3b983..ad60c83160 100644 --- a/tests/base/dynamic_unique_cast.cc +++ b/tests/base/dynamic_unique_cast.cc @@ -18,9 +18,6 @@ #include "../tests.h" -#include - - class B { public: @@ -36,7 +33,7 @@ void test () std::unique_ptr d = std_cxx14::make_unique(); // See that we can successfully downcast to B - std::unique_ptr b = dynamic_unique_cast(std::move(d)); + std::unique_ptr b = Utilities::dynamic_unique_cast(std::move(d)); // Ownership now rests with b, but it's still a D. Verify this: Assert (d.get() == nullptr, ExcInternalError()); @@ -44,7 +41,7 @@ void test () Assert (dynamic_cast(b.get()) != nullptr, ExcInternalError()); // Check that we can again upcast to D: - std::unique_ptr dd = dynamic_unique_cast(std::move(b)); + std::unique_ptr dd = Utilities::dynamic_unique_cast(std::move(b)); // Ownership now rests with b, but it's still a D. Verify this: Assert (b.get() == nullptr, ExcInternalError()); @@ -62,7 +59,7 @@ void invalid_test () // Check that we can indeed not upcast to D: try { - std::unique_ptr dd = dynamic_unique_cast(std::move(b)); + std::unique_ptr dd = Utilities::dynamic_unique_cast(std::move(b)); } catch (const std::bad_cast &) { -- 2.39.5