Program Listing for File ExecutableBase.h

Return to documentation for file (include/mola_kernel/interfaces/ExecutableBase.h)

/* -------------------------------------------------------------------------
 *   A Modular Optimization framework for Localization and mApping  (MOLA)
 * Copyright (C) 2018-2025 Jose Luis Blanco, University of Almeria
 * See LICENSE for license information.
 * ------------------------------------------------------------------------- */
#pragma once

#include <mola_kernel/Yaml.h>
#include <mrpt/containers/yaml.h>
#include <mrpt/rtti/CObject.h>
#include <mrpt/system/COutputLogger.h>
#include <mrpt/system/CTimeLogger.h>
#include <mrpt/version.h>

#include <any>
#include <functional>
#include <memory>
#include <mutex>
#include <optional>
#include <string>
#include <vector>

namespace mola
{
using Profiler            = mrpt::system::CTimeLogger;
using ProfilerEntry       = mrpt::system::CTimeLoggerEntry;
using ProfilerSaverAtDtor = mrpt::system::CTimeLoggerSaveAtDtor;

class ExecutableBase : public mrpt::system::COutputLogger,  // for logging
                       public mrpt::rtti::CObject,  // RTTI helpers
                       std::enable_shared_from_this<ExecutableBase>
{
  // This macro defines `Ptr=shared_ptr<T>`, among other types and methods.
#if MRPT_VERSION < 0x020e00
  DEFINE_VIRTUAL_MRPT_OBJECT(ExecutableBase)
#else
  DEFINE_VIRTUAL_MRPT_OBJECT(ExecutableBase, mola)
#endif

 public:
  ExecutableBase();
  virtual ~ExecutableBase();

  // Delete copy constructor and copy assignment operator
  ExecutableBase(const ExecutableBase&)            = delete;
  ExecutableBase& operator=(const ExecutableBase&) = delete;

  // Define move constructor and move assignment operator
  ExecutableBase(ExecutableBase&&) noexcept            = delete;
  ExecutableBase& operator=(ExecutableBase&&) noexcept = delete;

  static Ptr Factory(const std::string& classname);

  Ptr getAsPtr() { return shared_from_this(); }

  virtual void initialize(const Yaml& cfg) = 0;

  virtual void spinOnce() = 0;

  virtual int launchOrderPriority() const { return 50; }

  virtual void onQuit() {}

  virtual void onParameterUpdate([[maybe_unused]] const mrpt::containers::yaml& names_values) {}

  std::function<Ptr(const std::string&)> nameServer_;

  template <class Interface>
  std::vector<Ptr> findService() const;

  void        setModuleInstanceName(const std::string& s);
  std::string getModuleInstanceName() const;
 protected:
  void exposeParameters(const mrpt::containers::yaml& names_values);

 public:
  mrpt::containers::yaml getModuleParameters() const;

  void changeParameters(const mrpt::containers::yaml& names_values);

  std::optional<ProfilerSaverAtDtor> profiler_dtor_save_stats_;

  Profiler profiler_{false};

  [[nodiscard]] bool requestedShutdown() const
  {
    auto lck = mrpt::lockHelper(requested_system_shutdown_mtx_);
    return requested_system_shutdown_;
  }

  struct DiagnosticsOutput
  {
    DiagnosticsOutput() = default;

    mrpt::Clock::time_point timestamp;
    std::string             label;
    std::any                value;
  };

  [[nodiscard]] auto module_move_out_diagnostics_messages() -> std::vector<DiagnosticsOutput>;

 protected:
  void requestShutdown()
  {
    auto lck                   = mrpt::lockHelper(requested_system_shutdown_mtx_);
    requested_system_shutdown_ = true;
  }

  void module_publish_diagnostics(const DiagnosticsOutput& msg);

  [[nodiscard]] bool module_is_time_to_publish_diagnostics() const;

  double module_diagnostics_period_sec_ = 1.0;

 private:
  std::string module_instance_name{"unnamed"};
  bool        requested_system_shutdown_ = false;
  std::mutex  requested_system_shutdown_mtx_;

  std::mutex             module_params_mtx_;
  mrpt::containers::yaml module_params_;

  std::mutex                     module_diagnostics_out_queue_mtx_;
  std::vector<DiagnosticsOutput> module_diagnostics_out_queue_;
  double                         module_diagnostics_last_clockwall_stamp_ = 0;
};

// Impl:
template <class Interface>
std::vector<ExecutableBase::Ptr> ExecutableBase::findService() const
{
  std::vector<ExecutableBase::Ptr> ret;
  if (!nameServer_) return ret;
  for (size_t idx = 0;; ++idx)
  {
    using namespace std::string_literals;
    const auto req = "["s + std::to_string(idx);
    auto       mod = nameServer_(req);
    if (!mod) break;  // end of list of modules
    if (std::dynamic_pointer_cast<Interface>(mod)) ret.emplace_back(std::move(mod));
  }
  return ret;
}

#define MOLA_REGISTER_MODULE(_classname) mrpt::rtti::registerClass(CLASS_ID(_classname))

}  // namespace mola