]> https://gitweb.dealii.org/ - dealii.git/commitdiff
Mutable bind implementation. 8530/head
authorLuca Heltai <luca.heltai@sissa.it>
Fri, 9 Aug 2019 04:25:27 +0000 (22:25 -0600)
committerLuca Heltai <luca.heltai@sissa.it>
Tue, 27 Aug 2019 07:30:00 +0000 (09:30 +0200)
doc/news/changes/minor/20190808LucaHeltaiMatthiasMaier [new file with mode: 0644]
include/deal.II/base/mutable_bind.h [new file with mode: 0644]
tests/base/mutable_bind_01.cc [new file with mode: 0644]
tests/base/mutable_bind_01.output [new file with mode: 0644]
tests/base/mutable_bind_02.cc [new file with mode: 0644]
tests/base/mutable_bind_02.output [new file with mode: 0644]
tests/base/mutable_bind_03.cc [new file with mode: 0644]
tests/base/mutable_bind_03.output [new file with mode: 0644]
tests/base/mutable_bind_04.cc [new file with mode: 0644]
tests/base/mutable_bind_04.output [new file with mode: 0644]

diff --git a/doc/news/changes/minor/20190808LucaHeltaiMatthiasMaier b/doc/news/changes/minor/20190808LucaHeltaiMatthiasMaier
new file mode 100644 (file)
index 0000000..6b5da92
--- /dev/null
@@ -0,0 +1,3 @@
+New: Added MutableBind class and mutable_bind() method.
+<br>
+(Luca Heltai, Matthias Maier, 2019/08/08)
diff --git a/include/deal.II/base/mutable_bind.h b/include/deal.II/base/mutable_bind.h
new file mode 100644 (file)
index 0000000..eb0824d
--- /dev/null
@@ -0,0 +1,334 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2019 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+#ifndef dealii_base_mutable_bind_h
+#define dealii_base_mutable_bind_h
+
+#include <deal.II/base/config.h>
+
+#include <deal.II/base/patterns.h>
+#include <deal.II/base/std_cxx14/utility.h>
+#include <deal.II/base/std_cxx17/tuple.h>
+
+#include <tuple>
+
+DEAL_II_NAMESPACE_OPEN
+
+namespace Utilities
+{
+  /**
+   * A mutable version of std::bind, that binds all arguments of a function
+   * pointer to a stored tuple, and allows you to update the tuple between
+   * calls.
+   *
+   * An example usage of this class is through the helper function
+   * mutable_bind() that creates a MutableBind object on the fly, based on its
+   * arguments:
+   *
+   * @code
+   * void my_function(const int &a, const double &b);
+   *
+   * auto bound = mutable_bind(my_function, 1, 2.0);
+   *
+   * bound(); // will execute my_function(1, 2.0);
+   *
+   * bound.set_arguments(2, 3.0);
+   * bound(); // will execute my_function(2, 3.0);
+   *
+   * bound.parse_arguments("3: 4.0");
+   * bound(); // will execute my_function(3, 4.0);
+   * @endcode
+   *
+   * The arguments are copied to the tuple, with their reference and const
+   * attributes removed. Only copy constructible objects are allowed as
+   * function arguments. If you need to keep some references around, you may
+   * wrap your function into a std::bind object:
+   *
+   * @code
+   *  void
+   *  example_function(const Point<2> &p,
+   *                   const double &d,
+   *                   const unsigned int i = 3) {
+   *  ...
+   *  };
+   *
+   *  const Point<2> p(1, 2);
+   *
+   *  Utilities::MutableBind<void, double, unsigned int> exp = {
+   *    std::bind(example_function,
+   *              std::cref(p),
+   *              std::placeholders::_1,
+   *              std::placeholders::_2),
+   *    {}};
+   *
+   *  exp.parse_arguments("3.0 : 4");
+   *  exp(); // calls example_function(p, 3.0, 4);
+   * @endcode
+   *
+   * @authors Luca Heltai, Matthias Maier, 2019.
+   */
+  template <typename ReturnType, class... FunctionArgs>
+  class MutableBind
+  {
+  public:
+    /**
+     * An alias to the stored std::tuple type. Only copy constructible
+     * objects are allowed as tuple members.
+     */
+    using TupleType = std::tuple<typename std::remove_cv<
+      typename std::remove_reference<FunctionArgs>::type>::type...>;
+
+    /**
+     * Construct a MutableBind object specifying the function, and
+     * each arguments separately.
+     */
+    template <class FunctionType>
+    MutableBind(FunctionType function, FunctionArgs &&... arguments);
+
+    /**
+     * Construct a MutableBind object specifying the function, and
+     * the arguments as a tuple.
+     */
+    template <class FunctionType>
+    MutableBind(FunctionType function, TupleType &&arguments);
+
+    /**
+     * Construct a MutableBind object specifying only the function. By default,
+     * the arguments are left to their defult constructor values.
+     */
+    template <class FunctionType>
+    MutableBind(FunctionType function);
+
+    /**
+     * Call the original function, passing as arguments the elements of the
+     * tuple of bound arguments.
+     */
+    ReturnType
+    operator()() const;
+
+    /**
+     * Set the arguments to use in @p function, for next time
+     * operator()() is called, using move semantic.
+     */
+    void
+    set_arguments(TupleType &&arguments);
+
+    /**
+     * Set the arguments to use in @p function, for next time
+     * operator()() is called, using move semantic.
+     */
+    void
+    set_arguments(FunctionArgs &&... arguments);
+
+    /**
+     * Parse the arguments to use in @p function from a string, for next time
+     * operator()() is called.
+     *
+     * The conversion is performed using a user supplied Patterns::PatternBase
+     * object. By default, Patterns::Tools::Convert<TupleType>::to_pattern() is
+     * used to determine how to convert from @p value_string to a TupleType
+     * object.
+     *
+     * @param value_string The string to convert from
+     * @param pattern A unique pointer to the pattern to use when performing
+     * the conversion
+     */
+    void
+    parse_arguments(const std::string &                           value_string,
+                    const std::unique_ptr<Patterns::PatternBase> &pattern =
+                      Patterns::Tools::Convert<TupleType>::to_pattern());
+
+  private:
+    /**
+     * An std::function that stores the original function.
+     */
+    const std::function<ReturnType(FunctionArgs...)> function;
+
+    /**
+     * Currently stored arguments. These are forwarded to the function object
+     * above, when calling operator()().
+     */
+    TupleType arguments;
+  };
+
+
+
+  /**
+   * Create a MutableBind object from a function pointer and a list of
+   * arguments.
+   *
+   * An example usage is given by:
+   * @code
+   * void my_function(const int &a, const double &b);
+   *
+   * auto bound = mutable_bind(my_function, 1, 2.0);
+   *
+   * bound(); // will execute my_function(1, 2.0);
+   *
+   * bound.set_arguments(2, 3.0);
+   * bound(); // will execute my_function(2, 3.0);
+   *
+   * bound.parse_arguments("3: 4.0");
+   * bound(); // will execute my_function(3, 4.0);
+   * @endcode
+   *
+   * @authors Luca Heltai, Matthias Maier, 2019.
+   */
+  template <typename ReturnType, class... FunctionArgs>
+  MutableBind<ReturnType, FunctionArgs...>
+  mutable_bind(ReturnType (*function)(FunctionArgs...),
+               typename identity<FunctionArgs>::type &&... arguments);
+
+  /**
+   * Same as above, using a std::function object.
+   */
+  template <typename ReturnType, class... FunctionArgs>
+  MutableBind<ReturnType, FunctionArgs...>
+  mutable_bind(std::function<ReturnType(FunctionArgs...)>,
+               typename identity<FunctionArgs>::type &&... arguments);
+
+  /**
+   * Create a MutableBind object from a function pointer, with uninitialized
+   * arguments.
+   *
+   * Notice that if you do not call one of the MutableBind::set_arguments()
+   * methods, or the MutableBind::parse_arguments() function on the returned
+   * object, then the arguments passed to the function object will be
+   * initialized with the values coming from each of the arguments' default
+   * constructors.
+   */
+  template <typename ReturnType, class... FunctionArgs>
+  MutableBind<ReturnType, FunctionArgs...>
+    mutable_bind(ReturnType (*function)(FunctionArgs...));
+
+  /**
+   * Same as above, using a std::function object.
+   */
+  template <typename ReturnType, class... FunctionArgs>
+  MutableBind<ReturnType, FunctionArgs...>
+    mutable_bind(std::function<ReturnType(FunctionArgs...)>);
+
+
+
+#ifndef DOXYGEN
+  template <typename ReturnType, class... FunctionArgs>
+  template <class FunctionType>
+  MutableBind<ReturnType, FunctionArgs...>::MutableBind(
+    FunctionType function,
+    FunctionArgs &&... arguments)
+    : function(function)
+    , arguments(std::make_tuple(std::move(arguments)...)){};
+
+
+
+  template <typename ReturnType, class... FunctionArgs>
+  template <class FunctionType>
+  MutableBind<ReturnType, FunctionArgs...>::MutableBind(FunctionType function,
+                                                        TupleType && arguments)
+    : function(function)
+    , arguments(std::move(arguments)){};
+
+
+
+  template <typename ReturnType, class... FunctionArgs>
+  template <class FunctionType>
+  MutableBind<ReturnType, FunctionArgs...>::MutableBind(FunctionType function)
+    : function(function){};
+
+
+
+  template <typename ReturnType, class... FunctionArgs>
+  ReturnType
+  MutableBind<ReturnType, FunctionArgs...>::operator()() const
+  {
+    return std_cxx17::apply(function, arguments);
+  }
+
+
+
+  template <typename ReturnType, class... FunctionArgs>
+  void
+  MutableBind<ReturnType, FunctionArgs...>::set_arguments(
+    FunctionArgs &&... args)
+  {
+    arguments = std::make_tuple(std::move(args)...);
+  }
+
+
+
+  template <typename ReturnType, class... FunctionArgs>
+  void
+  MutableBind<ReturnType, FunctionArgs...>::set_arguments(TupleType &&args)
+  {
+    arguments = std::move(args);
+  }
+
+
+
+  template <typename ReturnType, class... FunctionArgs>
+  void
+  MutableBind<ReturnType, FunctionArgs...>::parse_arguments(
+    const std::string &                           value_string,
+    const std::unique_ptr<Patterns::PatternBase> &pattern)
+  {
+    arguments =
+      Patterns::Tools::Convert<TupleType>::to_value(value_string, pattern);
+  }
+
+
+
+  template <typename ReturnType, class... FunctionArgs>
+  MutableBind<ReturnType, FunctionArgs...>
+  mutable_bind(ReturnType (*function)(FunctionArgs...),
+               typename identity<FunctionArgs>::type &&... arguments)
+  {
+    return MutableBind<ReturnType, FunctionArgs...>(function,
+                                                    std::move(arguments)...);
+  };
+
+
+
+  template <typename ReturnType, class... FunctionArgs>
+  MutableBind<ReturnType, FunctionArgs...>
+    mutable_bind(ReturnType (*function)(FunctionArgs...))
+  {
+    return MutableBind<ReturnType, FunctionArgs...>(function);
+  }
+
+
+
+  template <typename ReturnType, class... FunctionArgs>
+  MutableBind<ReturnType, FunctionArgs...>
+  mutable_bind(std::function<ReturnType(FunctionArgs...)> function,
+               typename identity<FunctionArgs>::type &&... arguments)
+  {
+    return MutableBind<ReturnType, FunctionArgs...>(function,
+                                                    std::move(arguments)...);
+  }
+
+
+
+  template <typename ReturnType, class... FunctionArgs>
+  MutableBind<ReturnType, FunctionArgs...>
+  mutable_bind(std::function<ReturnType(FunctionArgs...)> function)
+  {
+    return MutableBind<ReturnType, FunctionArgs...>(function);
+  }
+#endif
+} // namespace Utilities
+
+DEAL_II_NAMESPACE_CLOSE
+
+#endif
diff --git a/tests/base/mutable_bind_01.cc b/tests/base/mutable_bind_01.cc
new file mode 100644 (file)
index 0000000..1c532a2
--- /dev/null
@@ -0,0 +1,51 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2019 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+// test the implementation of the Utilities::mutable_bind function
+
+
+#include <deal.II/base/mutable_bind.h>
+#include <deal.II/base/point.h>
+#include <deal.II/base/std_cxx17/tuple.h>
+
+#include "../tests.h"
+
+void
+example_function(const Point<2> &p, const double &d, const unsigned int i = 3)
+{
+  deallog << "P: " << p << ", d: " << d << ", i: " << i << std::endl;
+}
+
+int
+main()
+{
+  initlog();
+
+  auto exp = Utilities::mutable_bind(example_function);
+  exp();
+
+  exp.set_arguments(std::make_tuple(Point<2>(.5, .5), 2.0, 3));
+  exp();
+
+  exp.parse_arguments("2.0 , 2.0 : 1.0 : 4");
+  exp();
+
+  exp.set_arguments(Point<2>(.3, .3), 2.0, 5);
+  exp();
+
+  auto exp1 =
+    Utilities::mutable_bind(example_function, Point<2>(.8, .8), 4.0, 10);
+  exp1();
+}
diff --git a/tests/base/mutable_bind_01.output b/tests/base/mutable_bind_01.output
new file mode 100644 (file)
index 0000000..3df373e
--- /dev/null
@@ -0,0 +1,6 @@
+
+DEAL::P: 0.00000 0.00000, d: 0.00000, i: 0
+DEAL::P: 0.500000 0.500000, d: 2.00000, i: 3
+DEAL::P: 2.00000 2.00000, d: 1.00000, i: 4
+DEAL::P: 0.300000 0.300000, d: 2.00000, i: 5
+DEAL::P: 0.800000 0.800000, d: 4.00000, i: 10
diff --git a/tests/base/mutable_bind_02.cc b/tests/base/mutable_bind_02.cc
new file mode 100644 (file)
index 0000000..d80e08c
--- /dev/null
@@ -0,0 +1,55 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2019 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+// test the implementation of the Utilities::mutable_bind function. Make
+// sure it works for std::function objects.
+
+#include <deal.II/base/mutable_bind.h>
+#include <deal.II/base/point.h>
+#include <deal.II/base/std_cxx17/tuple.h>
+
+#include "../tests.h"
+
+void
+example_function(const Point<2> &p, const double &d, const unsigned int i = 3)
+{
+  deallog << "P: " << p << ", d: " << d << ", i: " << i << std::endl;
+}
+
+int
+main()
+{
+  initlog();
+
+  Point<2> p(.1, .1);
+
+  std::function<void(const double, const unsigned int)> reduced_function =
+    [&p](const double d, const unsigned int i) { example_function(p, d, i); };
+
+  auto exp = Utilities::mutable_bind(reduced_function);
+  exp();
+
+  exp.set_arguments(std::make_tuple(2.0, 3));
+  exp();
+
+  exp.parse_arguments("1.0 : 4");
+  exp();
+
+  exp.set_arguments(2.0, 5);
+  exp();
+
+  auto exp1 = Utilities::mutable_bind(reduced_function, 4.0, 10);
+  exp1();
+}
diff --git a/tests/base/mutable_bind_02.output b/tests/base/mutable_bind_02.output
new file mode 100644 (file)
index 0000000..5d55d3f
--- /dev/null
@@ -0,0 +1,6 @@
+
+DEAL::P: 0.100000 0.100000, d: 0.00000, i: 0
+DEAL::P: 0.100000 0.100000, d: 2.00000, i: 3
+DEAL::P: 0.100000 0.100000, d: 1.00000, i: 4
+DEAL::P: 0.100000 0.100000, d: 2.00000, i: 5
+DEAL::P: 0.100000 0.100000, d: 4.00000, i: 10
diff --git a/tests/base/mutable_bind_03.cc b/tests/base/mutable_bind_03.cc
new file mode 100644 (file)
index 0000000..4fd542a
--- /dev/null
@@ -0,0 +1,49 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2019 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+// test the implementation of the Utilities::mutable_bind function with
+// std::bind objects
+
+
+#include <deal.II/base/mutable_bind.h>
+#include <deal.II/base/point.h>
+#include <deal.II/base/std_cxx17/tuple.h>
+
+#include "../tests.h"
+
+void
+example_function(const Point<2> &p, const double &d, const unsigned int i = 3)
+{
+  deallog << "P: " << p << ", d: " << d << ", i: " << i << std::endl;
+}
+
+int
+main()
+{
+  initlog(1);
+
+  const Point<2> p(1, 2);
+
+  Utilities::MutableBind<void, double, unsigned int> exp = {
+    std::bind(example_function,
+              std::cref(p),
+              std::placeholders::_1,
+              std::placeholders::_2),
+    {}};
+
+  exp();
+  exp.set_arguments(3.0, 4);
+  exp();
+}
diff --git a/tests/base/mutable_bind_03.output b/tests/base/mutable_bind_03.output
new file mode 100644 (file)
index 0000000..9ff7b20
--- /dev/null
@@ -0,0 +1,3 @@
+
+DEAL::P: 1.00000 2.00000, d: 0.00000, i: 0
+DEAL::P: 1.00000 2.00000, d: 3.00000, i: 4
diff --git a/tests/base/mutable_bind_04.cc b/tests/base/mutable_bind_04.cc
new file mode 100644 (file)
index 0000000..d0aea62
--- /dev/null
@@ -0,0 +1,56 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2019 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+// test the implementation of the Utilities::mutable_bind function with
+// std::bind objects and std::cref
+
+
+#include <deal.II/base/mutable_bind.h>
+#include <deal.II/base/point.h>
+#include <deal.II/base/std_cxx17/tuple.h>
+
+#include "../tests.h"
+
+void
+example_function(const Point<2> &p, const double &d, const unsigned int i = 3)
+{
+  deallog << "P: " << p << ", d: " << d << ", i: " << i << std::endl;
+}
+
+int
+main()
+{
+  initlog(1);
+
+  const Point<2> p(1, 2);
+  const Point<2> p2(2, 3);
+
+  Utilities::MutableBind<void,
+                         std::reference_wrapper<const Point<2>>,
+                         double,
+                         unsigned int>
+    exp(std::bind(example_function,
+                  std::placeholders::_1,
+                  std::placeholders::_2,
+                  std::placeholders::_3),
+        std::cref(p),
+        3.0,
+        4);
+
+  exp.set_arguments(std::cref(p), 3.0, 4);
+  exp(); // executes example_function(p, 3.0, 4);
+  exp.set_arguments(std::cref(p2), 4.0, 5);
+  exp(); // executes example_function(p2, 4.0, 5);
+}
diff --git a/tests/base/mutable_bind_04.output b/tests/base/mutable_bind_04.output
new file mode 100644 (file)
index 0000000..3bab596
--- /dev/null
@@ -0,0 +1,3 @@
+
+DEAL::P: 1.00000 2.00000, d: 3.00000, i: 4
+DEAL::P: 2.00000 3.00000, d: 4.00000, i: 5

In the beginning the Universe was created. This has made a lot of people very angry and has been widely regarded as a bad move.

Douglas Adams


Typeset in Trocchi and Trocchi Bold Sans Serif.