Browse Source

event: Support lambdas as tasks via new FunctionAsyncTask

This is intended to replace GenericAsyncTask.
rdb 4 years ago
parent
commit
4af5bc9e6d

+ 2 - 0
panda/src/event/CMakeLists.txt

@@ -9,6 +9,7 @@ set(P3EVENT_HEADERS
   config_event.h
   config_event.h
   buttonEvent.I buttonEvent.h
   buttonEvent.I buttonEvent.h
   buttonEventList.I buttonEventList.h
   buttonEventList.I buttonEventList.h
+  functionAsyncTask.h functionAsyncTask.I
   genericAsyncTask.h genericAsyncTask.I
   genericAsyncTask.h genericAsyncTask.I
   pointerEvent.I pointerEvent.h
   pointerEvent.I pointerEvent.h
   pointerEventList.I pointerEventList.h
   pointerEventList.I pointerEventList.h
@@ -28,6 +29,7 @@ set(P3EVENT_SOURCES
   asyncTaskSequence.cxx
   asyncTaskSequence.cxx
   buttonEvent.cxx
   buttonEvent.cxx
   buttonEventList.cxx
   buttonEventList.cxx
+  functionAsyncTask.cxx
   genericAsyncTask.cxx
   genericAsyncTask.cxx
   pointerEvent.cxx
   pointerEvent.cxx
   pointerEventList.cxx
   pointerEventList.cxx

+ 13 - 0
panda/src/event/asyncTaskManager.I

@@ -32,6 +32,19 @@ get_clock() {
   return _clock;
   return _clock;
 }
 }
 
 
+#ifndef CPPPARSER
+/**
+ * Adds a new task which calls the indicated function to the task manager.
+ * Returns the newly created FunctionAsyncTask object.
+ */
+INLINE AsyncTask *AsyncTaskManager::
+add(const std::string &name, FunctionAsyncTask::TaskFunction function) {
+  AsyncTask *task = new FunctionAsyncTask(name, std::move(function));
+  add(task);
+  return task;
+}
+#endif
+
 /**
 /**
  * Returns the number of tasks that are currently active or sleeping within
  * Returns the number of tasks that are currently active or sleeping within
  * the task manager.
  * the task manager.

+ 4 - 0
panda/src/event/asyncTaskManager.h

@@ -30,6 +30,7 @@
 #include "clockObject.h"
 #include "clockObject.h"
 #include "ordered_vector.h"
 #include "ordered_vector.h"
 #include "indirectCompareNames.h"
 #include "indirectCompareNames.h"
+#include "functionAsyncTask.h"
 
 
 /**
 /**
  * A class to manage a loose queue of isolated tasks, which can be performed
  * A class to manage a loose queue of isolated tasks, which can be performed
@@ -64,6 +65,9 @@ PUBLISHED:
   BLOCKING bool remove_task_chain(const std::string &name);
   BLOCKING bool remove_task_chain(const std::string &name);
 
 
   void add(AsyncTask *task);
   void add(AsyncTask *task);
+#ifndef CPPPARSER
+  INLINE AsyncTask *add(const std::string &name, FunctionAsyncTask::TaskFunction function);
+#endif
   bool has_task(AsyncTask *task) const;
   bool has_task(AsyncTask *task) const;
 
 
   AsyncTask *find_task(const std::string &name) const;
   AsyncTask *find_task(const std::string &name) const;

+ 2 - 0
panda/src/event/config_event.cxx

@@ -22,6 +22,7 @@
 #include "event.h"
 #include "event.h"
 #include "eventHandler.h"
 #include "eventHandler.h"
 #include "eventParameter.h"
 #include "eventParameter.h"
+#include "functionAsyncTask.h"
 #include "genericAsyncTask.h"
 #include "genericAsyncTask.h"
 #include "pointerEventList.h"
 #include "pointerEventList.h"
 
 
@@ -49,6 +50,7 @@ ConfigureFn(config_event) {
   EventHandler::init_type();
   EventHandler::init_type();
   EventStoreInt::init_type("EventStoreInt");
   EventStoreInt::init_type("EventStoreInt");
   EventStoreDouble::init_type("EventStoreDouble");
   EventStoreDouble::init_type("EventStoreDouble");
+  FunctionAsyncTask::init_type();
   GenericAsyncTask::init_type();
   GenericAsyncTask::init_type();
 
 
   ButtonEventList::register_with_read_factory();
   ButtonEventList::register_with_read_factory();

+ 83 - 0
panda/src/event/functionAsyncTask.I

@@ -0,0 +1,83 @@
+/**
+ * PANDA 3D SOFTWARE
+ * Copyright (c) Carnegie Mellon University.  All rights reserved.
+ *
+ * All use of this software is subject to the terms of the revised BSD
+ * license.  You should have received a copy of this license along
+ * with this source code in a file named "LICENSE."
+ *
+ * @file functionAsyncTask.I
+ * @author rdb
+ * @date 2021-11-29
+ */
+
+/**
+ *
+ */
+INLINE FunctionAsyncTask::
+FunctionAsyncTask(const std::string &name) :
+  AsyncTask(name)
+{
+}
+
+/**
+ *
+ */
+INLINE FunctionAsyncTask::
+FunctionAsyncTask(const std::string &name, FunctionAsyncTask::TaskFunction function) :
+  AsyncTask(name),
+  _function(std::move(function))
+{
+}
+
+/**
+ * Replaces the function that is called when the task runs.
+ */
+INLINE void FunctionAsyncTask::
+set_function(TaskFunction function) {
+  _function = std::move(function);
+}
+
+/**
+ * Returns the function that is called when the task runs.
+ */
+INLINE const FunctionAsyncTask::TaskFunction &FunctionAsyncTask::
+get_function() const {
+  return _function;
+}
+
+/**
+ * Replaces the function that is called when the task begins.  This is an
+ * optional function.
+ */
+INLINE void FunctionAsyncTask::
+set_upon_birth(BirthFunction upon_birth) {
+  _upon_birth = std::move(upon_birth);
+}
+
+/**
+ * Returns the function that is called when the task begins, or NULL if the
+ * function is not defined.
+ */
+INLINE const FunctionAsyncTask::BirthFunction &FunctionAsyncTask::
+get_upon_birth() const {
+  return _upon_birth;
+}
+
+/**
+ * Replaces the function that is called when the task ends.  This is an
+ * optional function.
+ */
+INLINE void FunctionAsyncTask::
+set_upon_death(FunctionAsyncTask::DeathFunction upon_death) {
+  _upon_death = upon_death;
+}
+
+/**
+ * Returns the function that is called when the task ends, or NULL if the
+ * function is not defined.
+ */
+INLINE const FunctionAsyncTask::DeathFunction &FunctionAsyncTask::
+get_upon_death() const {
+  return _upon_death;
+}

+ 81 - 0
panda/src/event/functionAsyncTask.cxx

@@ -0,0 +1,81 @@
+/**
+ * PANDA 3D SOFTWARE
+ * Copyright (c) Carnegie Mellon University.  All rights reserved.
+ *
+ * All use of this software is subject to the terms of the revised BSD
+ * license.  You should have received a copy of this license along
+ * with this source code in a file named "LICENSE."
+ *
+ * @file functionAsyncTask.cxx
+ * @author rdb
+ * @date 2021-11-29
+ */
+
+#include "functionAsyncTask.h"
+#include "pnotify.h"
+
+#ifndef CPPPARSER
+
+TypeHandle FunctionAsyncTask::_type_handle;
+
+/**
+ * Override this function to return true if the task can be successfully
+ * executed, false if it cannot.  Mainly intended as a sanity check when
+ * attempting to add the task to a task manager.
+ *
+ * This function is called with the lock held.
+ */
+bool FunctionAsyncTask::
+is_runnable() {
+  return !!_function;
+}
+
+/**
+ * Override this function to do something useful for the task.
+ *
+ * This function is called with the lock *not* held.
+ */
+AsyncTask::DoneStatus FunctionAsyncTask::
+do_task() {
+  nassertr(_function, DS_interrupt);
+  return _function(this);
+}
+
+/**
+ * Override this function to do something useful when the task has been added
+ * to the active queue.
+ *
+ * This function is called with the lock *not* held.
+ */
+void FunctionAsyncTask::
+upon_birth(AsyncTaskManager *manager) {
+  AsyncTask::upon_birth(manager);
+
+  if (_upon_birth) {
+    _upon_birth(this);
+  }
+}
+
+/**
+ * Override this function to do something useful when the task has been
+ * removed from the active queue.  The parameter clean_exit is true if the
+ * task has been removed because it exited normally (returning DS_done), or
+ * false if it was removed for some other reason (e.g.
+ * AsyncTaskManager::remove()).  By the time this method is called, _manager
+ * has been cleared, so the parameter manager indicates the original
+ * AsyncTaskManager that owned this task.
+ *
+ * The normal behavior is to throw the done_event only if clean_exit is true.
+ *
+ * This function is called with the lock *not* held.
+ */
+void FunctionAsyncTask::
+upon_death(AsyncTaskManager *manager, bool clean_exit) {
+  AsyncTask::upon_death(manager, clean_exit);
+
+  if (_upon_death) {
+    _upon_death(this, clean_exit);
+  }
+}
+
+#endif  // CPPPARSER

+ 83 - 0
panda/src/event/functionAsyncTask.h

@@ -0,0 +1,83 @@
+/**
+ * PANDA 3D SOFTWARE
+ * Copyright (c) Carnegie Mellon University.  All rights reserved.
+ *
+ * All use of this software is subject to the terms of the revised BSD
+ * license.  You should have received a copy of this license along
+ * with this source code in a file named "LICENSE."
+ *
+ * @file functionAsyncTask.h
+ * @author rdb
+ * @date 2021-11-29
+ */
+
+#ifndef FUNCTIONASYNCTASK_H
+#define FUNCTIONASYNCTASK_H
+
+#include "pandabase.h"
+
+#include "asyncTask.h"
+
+#ifndef CPPPARSER
+#include <functional>
+
+/**
+ * Associates a generic std::function (eg. a lambda) with an AsyncTask object.
+ * You can use this when you want to create an AsyncTask without having to
+ * subclass.
+ *
+ * @since 1.11.0
+ */
+class EXPCL_PANDA_EVENT FunctionAsyncTask final : public AsyncTask {
+public:
+  typedef std::function<DoneStatus (FunctionAsyncTask *task)> TaskFunction;
+  typedef std::function<void (FunctionAsyncTask *task)> BirthFunction;
+  typedef std::function<void (FunctionAsyncTask *task, bool clean_exit)> DeathFunction;
+
+  INLINE FunctionAsyncTask(const std::string &name = std::string());
+  INLINE FunctionAsyncTask(const std::string &name, TaskFunction function);
+  ALLOC_DELETED_CHAIN(FunctionAsyncTask);
+
+  INLINE void set_function(TaskFunction function);
+  INLINE const TaskFunction &get_function() const;
+
+  INLINE void set_upon_birth(BirthFunction function);
+  INLINE const BirthFunction &get_upon_birth() const;
+
+  INLINE void set_upon_death(DeathFunction function);
+  INLINE const DeathFunction &get_upon_death() const;
+
+protected:
+  virtual bool is_runnable() override;
+  virtual DoneStatus do_task() override;
+  virtual void upon_birth(AsyncTaskManager *manager) override;
+  virtual void upon_death(AsyncTaskManager *manager, bool clean_exit) override;
+
+private:
+  TaskFunction _function;
+  BirthFunction _upon_birth;
+  DeathFunction _upon_death;
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    AsyncTask::init_type();
+    register_type(_type_handle, "FunctionAsyncTask",
+                  AsyncTask::get_class_type());
+  }
+  virtual TypeHandle get_type() const override {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() override {init_type(); return get_class_type();}
+
+private:
+  static TypeHandle _type_handle;
+};
+
+#include "functionAsyncTask.I"
+
+#endif  // CPPPARSER
+
+#endif

+ 2 - 0
panda/src/event/genericAsyncTask.h

@@ -22,6 +22,8 @@
  * Associates a generic C-style function pointer with an AsyncTask object.
  * Associates a generic C-style function pointer with an AsyncTask object.
  * You can use this when you want to create an AsyncTask without having to
  * You can use this when you want to create an AsyncTask without having to
  * subclass.
  * subclass.
+ *
+ * @deprecated See FunctionAsyncTask instead, which is more powerful.
  */
  */
 class EXPCL_PANDA_EVENT GenericAsyncTask : public AsyncTask {
 class EXPCL_PANDA_EVENT GenericAsyncTask : public AsyncTask {
 public:
 public:

+ 1 - 0
panda/src/event/p3event_composite1.cxx

@@ -7,6 +7,7 @@
 #include "asyncTaskSequence.cxx"
 #include "asyncTaskSequence.cxx"
 #include "buttonEvent.cxx"
 #include "buttonEvent.cxx"
 #include "buttonEventList.cxx"
 #include "buttonEventList.cxx"
+#include "functionAsyncTask.cxx"
 #include "genericAsyncTask.cxx"
 #include "genericAsyncTask.cxx"
 #include "pointerEvent.cxx"
 #include "pointerEvent.cxx"
 #include "pointerEventList.cxx"
 #include "pointerEventList.cxx"

+ 6 - 15
panda/src/framework/windowFramework.cxx

@@ -1429,8 +1429,11 @@ create_anim_controls() {
   setup_shuttle_button("4", 2, st_play_button);
   setup_shuttle_button("4", 2, st_play_button);
   setup_shuttle_button(":", 3, st_forward_button);
   setup_shuttle_button(":", 3, st_forward_button);
 
 
-  _update_anim_controls_task = new GenericAsyncTask("controls", st_update_anim_controls, (void *)this);
-  _panda_framework->get_task_mgr().add(_update_anim_controls_task);
+  AsyncTaskManager &task_mgr = _panda_framework->get_task_mgr();
+  _update_anim_controls_task = task_mgr.add("controls", [this](AsyncTask *task) {
+    update_anim_controls();
+    return AsyncTask::DS_cont;
+  });
 }
 }
 
 
 /**
 /**
@@ -1443,7 +1446,7 @@ destroy_anim_controls() {
 
 
     _panda_framework->get_event_handler().remove_hooks_with((void *)this);
     _panda_framework->get_event_handler().remove_hooks_with((void *)this);
     if (_update_anim_controls_task != nullptr) {
     if (_update_anim_controls_task != nullptr) {
-      _panda_framework->get_task_mgr().remove(_update_anim_controls_task);
+      _update_anim_controls_task->remove();
       _update_anim_controls_task.clear();
       _update_anim_controls_task.clear();
     }
     }
   }
   }
@@ -1559,18 +1562,6 @@ forward_button() {
   control->pose(control->get_frame() + 1);
   control->pose(control->get_frame() + 1);
 }
 }
 
 
-
-/**
- * The static task function.
- */
-AsyncTask::DoneStatus WindowFramework::
-st_update_anim_controls(GenericAsyncTask *, void *data) {
-  WindowFramework *self = (WindowFramework *)data;
-  self->update_anim_controls();
-  return AsyncTask::DS_cont;
-}
-
-
 /**
 /**
  * The static event handler function.
  * The static event handler function.
  */
  */

+ 1 - 3
panda/src/framework/windowFramework.h

@@ -154,8 +154,6 @@ private:
   void play_button();
   void play_button();
   void forward_button();
   void forward_button();
 
 
-  static AsyncTask::DoneStatus st_update_anim_controls(GenericAsyncTask *task, void *data);
-
   static void st_back_button(const Event *, void *data);
   static void st_back_button(const Event *, void *data);
   static void st_pause_button(const Event *, void *data);
   static void st_pause_button(const Event *, void *data);
   static void st_play_button(const Event *, void *data);
   static void st_play_button(const Event *, void *data);
@@ -183,7 +181,7 @@ private:
   PT(PGSliderBar) _anim_slider;
   PT(PGSliderBar) _anim_slider;
   PT(PGSliderBar) _play_rate_slider;
   PT(PGSliderBar) _play_rate_slider;
   PT(TextNode) _frame_number;
   PT(TextNode) _frame_number;
-  PT(GenericAsyncTask) _update_anim_controls_task;
+  PT(AsyncTask) _update_anim_controls_task;
 
 
   NodePath _mouse;
   NodePath _mouse;
   NodePath _button_thrower;
   NodePath _button_thrower;