Program Listing for File io_context.hpp
↰ Return to documentation for file (include/holoscan/core/io_context.hpp
)
/*
* SPDX-FileCopyrightText: Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef HOLOSCAN_CORE_IO_CONTEXT_HPP
#define HOLOSCAN_CORE_IO_CONTEXT_HPP
#include <any>
#include <memory>
#include <string>
#include <typeinfo>
#include <unordered_map>
#include <utility>
#include <vector>
#include <gxf/core/expected.hpp>
#include "./common.hpp"
#include "./gxf/entity.hpp"
#include "./message.hpp"
#include "./operator.hpp"
#include "./type_traits.hpp"
namespace holoscan {
class InputContext {
public:
InputContext(Operator* op, std::unordered_map<std::string, std::unique_ptr<IOSpec>>& inputs)
: op_(op), inputs_(inputs) {}
explicit InputContext(Operator* op) : op_(op), inputs_(op->spec()->inputs()) {}
Operator* op() const { return op_; }
std::unordered_map<std::string, std::unique_ptr<IOSpec>>& inputs() const { return inputs_; }
template <typename DataT, typename = std::enable_if_t<
!holoscan::is_vector_v<DataT> &&
!holoscan::is_one_of_v<DataT, holoscan::gxf::Entity, std::any>>>
std::shared_ptr<DataT> receive(const char* name = nullptr) {
auto value = receive_impl(name);
try {
return std::any_cast<std::shared_ptr<DataT>>(value);
} catch (const std::bad_any_cast& e) {
HOLOSCAN_LOG_ERROR(
"Unable to cast the received data to the specified type (std::shared_ptr<"
"DataT>): {}",
e.what());
return nullptr;
}
}
template <typename DataT,
typename = std::enable_if_t<holoscan::is_one_of_v<DataT, holoscan::gxf::Entity>>>
DataT receive(const char* name) {
auto value = receive_impl(name);
try {
return std::any_cast<holoscan::gxf::Entity>(value);
} catch (const std::bad_any_cast& e) {
throw std::runtime_error(
fmt::format("Unable to cast the received data to the specified type (holoscan::gxf::"
"Entity): {}",
e.what()));
}
}
template <typename DataT, typename = std::enable_if_t<holoscan::is_one_of_v<DataT, std::any>>>
std::any receive(const char* name) {
auto value = receive_impl(name);
return value;
}
template <typename DataT,
typename = std::enable_if_t<
holoscan::is_vector_v<DataT> &&
!holoscan::is_one_of_v<typename holoscan::type_info<DataT>::element_type,
holoscan::gxf::Entity, std::any>>>
std::vector<std::shared_ptr<typename holoscan::type_info<DataT>::element_type>> receive(
const char* name) {
using DataT_ElementT = typename holoscan::type_info<DataT>::element_type;
std::vector<std::shared_ptr<DataT_ElementT>> input_vector;
auto& params = op_->spec()->params();
auto it = params.find(std::string(name));
if (it == params.end()) {
HOLOSCAN_LOG_ERROR(
"Unable to find input parameter with type 'std::vector<IOSpec*>' and name '{}'", name);
return input_vector;
}
auto& param_wrapper = it->second;
auto& arg_type = param_wrapper.arg_type();
if ((arg_type.element_type() != ArgElementType::kIOSpec) ||
(arg_type.container_type() != ArgContainerType::kVector)) {
HOLOSCAN_LOG_ERROR("Input parameter with name {} is not of type 'std::vector<IOSpec*>'",
name);
return input_vector;
}
std::any& any_param = param_wrapper.value();
// Note that the type of any_param is Parameter
*, not Parameter
.
auto& param = *std::any_cast<Parameter<std::vector<IOSpec*>>*>(any_param);
int num_inputs = param.get().size();
input_vector.reserve(num_inputs);
for (int index = 0; index < num_inputs; ++index) {
// Check if the input name points to the parameter name of the operator,
// and the parameter type is 'std::vector
'.
// In other words, find if there is a receiver with a specific label
// ('
:
'. e.g, 'receivers:0') to return an object with
// 'std::vector
' type.
auto value = receive_impl(fmt::format("{}:{}", name, index).c_str(), true);
try {
auto casted_value = std::any_cast<std::shared_ptr<DataT_ElementT>>(value);
input_vector.push_back(std::move(casted_value));
} catch (const std::bad_any_cast& e) {
HOLOSCAN_LOG_ERROR(
"Unable to receive input (std::vector<std::shared_ptr<DataT>>) with name "
"'{}:{}' ({}). Skipping adding to the vector.",
name,
index,
e.what());
}
}
return input_vector;
}
template <typename DataT,
typename = std::enable_if_t<
holoscan::is_vector_v<DataT> &&
holoscan::is_one_of_v<typename holoscan::type_info<DataT>::element_type,
holoscan::gxf::Entity>>>
std::vector<holoscan::gxf::Entity> receive(const char* name) {
std::vector<holoscan::gxf::Entity> input_vector;
auto& params = op_->spec()->params();
auto it = params.find(std::string(name));
if (it == params.end()) {
HOLOSCAN_LOG_ERROR(
"Unable to find input parameter with type 'std::vector<IOSpec*>' and name '{}'", name);
return input_vector;
}
auto& param_wrapper = it->second;
auto& arg_type = param_wrapper.arg_type();
if ((arg_type.element_type() != ArgElementType::kIOSpec) ||
(arg_type.container_type() != ArgContainerType::kVector)) {
HOLOSCAN_LOG_ERROR("Input parameter with name {} is not of type 'std::vector<IOSpec*>'",
name);
return input_vector;
}
std::any& any_param = param_wrapper.value();
// Note that the type of any_param is Parameter
*, not Parameter
.
auto& param = *std::any_cast<Parameter<std::vector<IOSpec*>>*>(any_param);
int num_inputs = param.get().size();
input_vector.reserve(num_inputs);
for (int index = 0; index < num_inputs; ++index) {
// Check if the input name points to the parameter name of the operator,
// and the parameter type is 'std::vector
'.
// In other words, find if there is a receiver with a specific label
// ('
:
'. e.g, 'receivers:0') to return an object with
// 'std::vector
' type.
auto value = receive_impl(fmt::format("{}:{}", name, index).c_str(), true);
try {
auto casted_value = std::any_cast<holoscan::gxf::Entity>(value);
input_vector.push_back(std::move(casted_value));
} catch (const std::bad_any_cast& e) {
HOLOSCAN_LOG_ERROR(
"Unable to receive input (std::vector<holoscan::gxf::Entity>) "
"with name "
"'{}:{}' ({}). Skipping adding to the vector.",
name,
index,
e.what());
}
}
return input_vector;
}
template <typename DataT,
typename = std::enable_if_t<
holoscan::is_vector_v<DataT> &&
holoscan::is_one_of_v<typename holoscan::type_info<DataT>::element_type, std::any>>>
std::vector<std::any> receive(const char* name) {
std::vector<std::any> input_vector;
auto& params = op_->spec()->params();
auto it = params.find(std::string(name));
if (it == params.end()) {
HOLOSCAN_LOG_ERROR(
"Unable to find input parameter with type 'std::vector<IOSpec*>' and name '{}'", name);
return input_vector;
}
auto& param_wrapper = it->second;
auto& arg_type = param_wrapper.arg_type();
if ((arg_type.element_type() != ArgElementType::kIOSpec) ||
(arg_type.container_type() != ArgContainerType::kVector)) {
HOLOSCAN_LOG_ERROR("Input parameter with name {} is not of type 'std::vector<IOSpec*>'",
name);
return input_vector;
}
std::any& any_param = param_wrapper.value();
// Note that the type of any_param is Parameter
*, not Parameter
.
auto& param = *std::any_cast<Parameter<std::vector<IOSpec*>>*>(any_param);
int num_inputs = param.get().size();
input_vector.reserve(num_inputs);
for (int index = 0; index < num_inputs; ++index) {
// Check if the input name points to the parameter name of the operator,
// and the parameter type is 'std::vector
'.
// In other words, find if there is a receiver with a specific label
// ('
:
'. e.g, 'receivers:0') to return an object with
// 'std::vector
' type.
auto value = receive_impl(fmt::format("{}:{}", name, index).c_str(), true);
input_vector.push_back(std::move(value));
}
return input_vector;
}
protected:
virtual std::any receive_impl(const char* name = nullptr, bool no_error_message = false) {
(void)name;
(void)no_error_message;
return nullptr;
}
Operator* op_ = nullptr;
std::unordered_map<std::string, std::unique_ptr<IOSpec>>& inputs_;
};
class OutputContext {
public:
OutputContext(Operator* op, std::unordered_map<std::string, std::unique_ptr<IOSpec>>& outputs)
: op_(op), outputs_(outputs) {}
Operator* op() const { return op_; }
std::unordered_map<std::string, std::unique_ptr<IOSpec>>& outputs() const { return outputs_; }
explicit OutputContext(Operator* op) : op_(op), outputs_(op->spec()->outputs()) {}
enum class OutputType {
kSharedPointer,
kGXFEntity,
};
template <typename DataT>
void emit(std::shared_ptr<DataT>& data, const char* name = nullptr) {
emit_impl(data, name);
}
template <typename DataT,
typename = std::enable_if_t<std::is_same_v<holoscan::gxf::Entity, std::decay_t<DataT>>>>
void emit(DataT& data, const char* name = nullptr) {
emit_impl(data, name, OutputType::kGXFEntity);
}
protected:
virtual void emit_impl(std::any data, const char* name = nullptr,
OutputType out_type = OutputType::kSharedPointer) {
(void)data;
(void)name;
(void)out_type;
}
Operator* op_ = nullptr;
std::unordered_map<std::string, std::unique_ptr<IOSpec>>& outputs_;
};
} // namespace holoscan
#endif/* HOLOSCAN_CORE_IO_CONTEXT_HPP */