text: // Copyright (C) 2018-2022 Intel Corporation
  // SPDX-License-Identifier: Apache-2.0
  //
  
  #pragma once
  
  #include <memory>
  #include <string>
  #include <vector>
  #include <map>
  #include <unordered_map>
  #include <queue>
  #include <sstream>
  #include <fstream>
  
  #include <ie_common.h>
  #include <cpp_interfaces/impl/ie_executable_network_thread_safe_default.hpp>
  #include <threading/ie_executor_manager.hpp>
  
  #include <vpu/graph_transformer.hpp>
  
  #include "myriad_executor.h"
  #include "myriad_infer_request.h"
  #include "myriad_async_infer_request.h"
  #include "cpp_interfaces/interface/ie_iplugin_internal.hpp"
  #include "ie_icore.hpp"
  
  namespace vpu {
  namespace MyriadPlugin {
  
  class ExecutableNetwork : public ie::ExecutableNetworkThreadSafeDefault {
  public:
      typedef std::shared_ptr<ExecutableNetwork> Ptr;
  
      ExecutableNetwork(const InferenceEngine::CNNNetwork& network, std::shared_ptr<IMvnc> mvnc, std::vector<DevicePtr> &devicePool,
                        const PluginConfiguration& configuration, const std::shared_ptr<ie::ICore> core);
  
      ExecutableNetwork(std::istream& strm, std::shared_ptr<IMvnc> mvnc, std::vector<DevicePtr> &devicePool, const PluginConfiguration& configuration,
                        const std::shared_ptr<ie::ICore> core);
  
      ExecutableNetwork(const std::string &blobFilename, std::shared_ptr<IMvnc> mvnc, std::vector<DevicePtr> &devicePool,
                        const PluginConfiguration& configuration, const std::shared_ptr<ie::ICore> core);
  
      virtual ~ExecutableNetwork() {
          try {
              if (_device != nullptr) {
                  _executor->deallocateGraph(_device, _graphDesc);
              }
          }
          catch (...) {
              std::cerr << "ERROR ~ExecutableNetwork():\n"
                        << "Some errors occurred during the calling of the deallocateGraph() method";
          }
      }
  
      ie::IInferRequestInternal::Ptr CreateInferRequestImpl(ie::InputsDataMap networkInputs,
                                                            ie::OutputsDataMap networkOutputs) override {
          if (!_isNetworkConstant && (_device == nullptr || !_device->isBooted())) {
              IE_THROW() << "Can not create infer request: there is no available devices with platform ";
          }
  
          return std::make_shared<MyriadInferRequest>(_graphDesc, networkInputs, networkOutputs,
                                                      _inputInfo, _outputInfo,
                                                      _graphMetaData.stagesMeta, _config, _log, _executor,
                                                      _constDatas, _isNetworkConstant);
      }
  
      ie::IInferRequestInternal::Ptr CreateInferRequest() override {
          if (!_isNetworkConstant && (_device == nullptr || !_device->isBooted())) {
              IE_THROW() << "Can not create infer request: there is no available devices with platform ";
          }
          std::shared_ptr<MyriadInferRequest> syncRequestImpl;
          if (this->_plugin) {
              const auto& core = _plugin->GetCore();
              if (core && core->isNewAPI())
                  syncRequestImpl = std::make_shared<MyriadInferRequest>(_graphDesc, _parameters, _results,
                                                                         _inputInfo, _outputInfo,
                                                                         _graphMetaData.stagesMeta, _config, _log,
                                                                         _executor, _constDatas, _isNetworkConstant);
          }
          if (!syncRequestImpl)
              syncRequestImpl = std::make_shared<MyriadInferRequest>(_graphDesc, _networkInputs, _networkOutputs,
                                                                     _inputInfo, _outputInfo,
                                                                     _graphMetaData.stagesMeta, _config, _log,
                                                                     _executor, _constDatas, _isNetworkConstant);
          syncRequestImpl->setPointerToExecutableNetworkInternal(shared_from_this());
          auto taskExecutorGetResult = getNextTaskExecutor();
          return std::make_shared<MyriadAsyncInferRequest>(
                  syncRequestImpl, _taskExecutor, _callbackExecutor, taskExecutorGetResult);
      }
  
      void Export(std::ostream& model) override {
          model.write(_graphBlob.data(), _graphBlob.size());
      }
  
      void Export(const std::string &modelFileName) override {
          std::ofstream modelFile(modelFileName, std::ios::out | std::ios::binary);
  
          if (modelFile.is_open()) {
              Export(modelFile);
          } else {
              IE_THROW() << "The " << modelFileName << " file can not be opened for export";
          }
      }
  
      ie::Parameter GetMetric(const std::string &name) const override;
      InferenceEngine::Parameter GetConfig(const std::string &name) const override;
  
      std::shared_ptr<ngraph::Function> GetExecGraphInfo() override;
  
      void Import(std::istream& strm, std::vector<DevicePtr> &devicePool, const PluginConfiguration& configuration);
  
  private:
      Logger::Ptr _log;
      MyriadExecutorPtr _executor;
      std::vector<char> _graphBlob;
      GraphDesc _graphDesc;
      DevicePtr _device;
      GraphMetaInfo _graphMetaData;
      PluginConfiguration _config;
      bool _isNetworkConstant = false;
      const std::shared_ptr<ie::ICore> _core = nullptr;
      int _actualNumExecutors = 0;
      std::vector<std::string> _supportedMetrics;
      std::map<std::string, ie::Blob::Ptr> _constDatas;
  
      DataInfo _inputInfo;
      DataInfo _outputInfo;
  
      const size_t _maxTaskExecutorGetResultCount = 1;
      std::queue<std::string> _taskExecutorGetResultIds;
  
      ExecutableNetwork(std::shared_ptr<IMvnc> mvnc,
          const PluginConfiguration& config,
          const std::shared_ptr<ie::ICore> core);
  
      ie::ITaskExecutor::Ptr getNextTaskExecutor() {
          std::string id = _taskExecutorGetResultIds.front();
  
          _taskExecutorGetResultIds.pop();
          _taskExecutorGetResultIds.push(id);
  
          ie::ITaskExecutor::Ptr taskExecutor = ie::executorManager()->getExecutor(id);
  
          return taskExecutor;
      }
  
      void openDevice(std::vector<DevicePtr>& devicePool);
  };
  
  }  // namespace MyriadPlugin
  }  // namespace vpu
  