packages feed

hasquant-0.8.0.0: cbits/qlCallback.hpp

#ifndef HASQUANT_CALLBACK_HPP
#define HASQUANT_CALLBACK_HPP

#include <exception>
#include <memory>
#include <string>
#include <utility>
#include <vector>

namespace hasquant { class Callback; }
using QlCallback = std::shared_ptr<hasquant::Callback>;
#include "qlCallback.h"

struct QlError {
  explicit QlError(std::string text) : message(std::move(text)) {}
  ~QlError() { if (exception) releaseException(exception); }
  QlError(const QlError&) = delete;
  QlError& operator=(const QlError&) = delete;
  std::string message;
  std::string call, requiredVersion, linkedVersion;
  void* exception = nullptr;
  QlReleaseStable releaseException = nullptr;
};

void qlSetError(QlError** slot, const char* message);
void qlUnsupportedVersion(QlError** slot, const char* call, const char* required);
// False after reporting call as unsupported when a QuantLib <= 1.43 receives a non-default 1.44 argument.
bool ql144Default(QlError** slot, const char* call, bool isDefault);

class QlCallScope {
public:
  explicit QlCallScope(QlError** slot) noexcept;
  ~QlCallScope();
  QlCallScope(const QlCallScope&) = delete;
  QlCallScope& operator=(const QlCallScope&) = delete;
  // Deletes an object once the outermost native call on this thread returns, or at once outside one.
  static void deleteAfterCall(void* object, void (*destroy)(void*)) noexcept;
  QlError** slot;
private:
  QlCallScope* previous_;
  std::vector<std::pair<void*, void (*)(void*)>> deferred_;
};

namespace hasquant {
  class Callback {
  public:
    Callback(QlCallbackFun fn, QlReleaseStable releaseStable)
      : fn_(fn), releaseStable_(releaseStable) {}
    ~Callback() { if (releaseFun_) releaseFun_(reinterpret_cast<void (*)(void)>(fn_)); }
    Callback(const Callback&) = delete;
    Callback& operator=(const Callback&) = delete;
    void adopt(QlReleaseFun release) noexcept { releaseFun_ = release; }
    void invoke(const QlCallbackArgs& args) const;
    double scalar(double x, double y = 0.0) const {
      double result = 0.0;
      invoke(QlCallbackArgs{x, y, 0.0, nullptr, &result, 0, 0});
      return result;
    }
    double array(const double* input, unsigned size, double time = 0.0) const {
      double result = 0.0;
      invoke(QlCallbackArgs{0.0, time, 0.0, input, &result, size, 0});
      return result;
    }
  private:
    QlCallbackFun fn_;
    QlReleaseStable releaseStable_;
    QlReleaseFun releaseFun_ = nullptr;
  };
  // A finalizer run by a callback's GC must not delete an object that the interrupted call uses.
  template <class T> struct DeleteAfterCall {
    void operator()(T* object) const noexcept {
      QlCallScope::deleteAfterCall(object, [](void* p) { delete static_cast<T*>(p); });
    }
  };
  struct UnaryCallback {
    QlCallback owner;
    double operator()(double x) const { return owner->scalar(x); }
  };
  struct BinaryCallback {
    QlCallback owner;
    double operator()(double x, double y) const { return owner->scalar(x, y); }
  };
}
#endif