Program Listing for File gxf_parameter_adaptor.hpp
↰ Return to documentation for file (include/holoscan/core/executors/gxf/gxf_parameter_adaptor.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_EXECUTORS_GXF_GXF_PARAMETER_ADAPTOR_HPP
#define HOLOSCAN_CORE_EXECUTORS_GXF_GXF_PARAMETER_ADAPTOR_HPP
#include <functional>
#include <memory>
#include <string>
#include <type_traits>
#include <typeindex>
#include <typeinfo>
#include <unordered_map>
#include <vector>
#include "../../common.hpp"
#include "../../arg.hpp"
#include "../../gxf/gxf_condition.hpp"
#include "../../gxf/gxf_resource.hpp"
#include "../../gxf/gxf_utils.hpp"
#include "../../io_spec.hpp"
#include "../../parameter.hpp"
namespace holoscan::gxf {
class GXFParameterAdaptor {
public:
using AdaptFunc =
std::function<gxf_result_t(gxf_context_t context, gxf_uid_t uid, const char* key,
const ArgType& arg_type, const std::any& any_value)>;
inline static AdaptFunc none_param_handler = [](gxf_context_t context, gxf_uid_t uid,
const char* key, const ArgType& arg_type,
const std::any& any_value) {
(void)context;
(void)uid;
(void)key;
(void)arg_type;
(void)any_value;
HOLOSCAN_LOG_ERROR("Unable to handle parameter: {}", key);
return GXF_FAILURE;
};
static GXFParameterAdaptor& get_instance();
static gxf_result_t set_param(gxf_context_t context, gxf_uid_t uid, const char* key,
ParameterWrapper& param_wrap) {
auto& instance = get_instance();
const auto index = std::type_index(param_wrap.type());
const AdaptFunc& func = instance.get_param_handler(index);
if (&func == &none_param_handler) {
HOLOSCAN_LOG_ERROR("Unable to handle parameter: {}", key);
return GXF_FAILURE;
}
return func(context, uid, key, param_wrap.arg_type(), param_wrap.value());
}
template <typename typeT>
static void ensure_type() {
auto& instance = get_instance();
instance.add_param_handler<typeT>();
}
AdaptFunc& get_param_handler(std::type_index index) {
if (function_map_.find(index) == function_map_.end()) {
HOLOSCAN_LOG_WARN("No parameter handler for type '{}' exists", index.name());
return GXFParameterAdaptor::none_param_handler;
}
auto& handler = function_map_[index];
return handler;
}
template <typename typeT>
void add_param_handler(AdaptFunc func) {
function_map_.try_emplace(std::type_index(typeid(typeT)), func);
}
void add_param_handler(std::type_index index, AdaptFunc func) {
function_map_.try_emplace(index, func);
}
template <typename typeT>
void add_param_handler() {
function_map_.try_emplace(
std::type_index(typeid(typeT)),
[](gxf_context_t context,
gxf_uid_t uid,
const char* key,
const ArgType& arg_type,
const std::any& any_value) {
(void)context;
(void)uid;
(void)key;
(void)arg_type;
(void)any_value;
try {
auto& param = *std::any_cast<Parameter<typeT>*>(any_value);
param.set_default_value(); // set default value if not set.
// If the parameter (any_value) is from the native operator
// (which means 'uid == -1'), return here without setting GXF parameter.
if (uid == -1) { return GXF_SUCCESS; }
if (param.has_value()) {
auto& value = param.get();
switch (arg_type.container_type()) {
case ArgContainerType::kNative: {
switch (arg_type.element_type()) {
case ArgElementType::kBoolean: {
if constexpr (std::is_same_v<typeT, bool>) {
return GxfParameterSetBool(context, uid, key, value);
}
break;
}
case ArgElementType::kInt8: {
HOLOSCAN_LOG_ERROR("GXF does not support int8_t parameter for key '{}'", key);
return GXF_FAILURE;
}
case ArgElementType::kUnsigned8: {
// GXF Doesn't support uint8_t parameter so use a workaround with
// GxfParameterSetFromYamlNode.
if constexpr (std::is_same_v<typeT, uint8_t>) {
YAML::Node yaml_node;
// uint8_t is not supported natively by yaml-cpp so push it as a uint32_t
// so that GXF can handle it.
yaml_node.push_back(static_cast<uint32_t>(value));
YAML::Node value_node = yaml_node[0];
return GxfParameterSetFromYamlNode(context, uid, key, &value_node, "");
}
break;
}
case ArgElementType::kInt16: {
// GXF Doesn't support int16_t parameter so use a workaround with
// GxfParameterSetFromYamlNode.
if constexpr (std::is_same_v<typeT, int16_t>) {
YAML::Node yaml_node;
yaml_node.push_back(value);
YAML::Node value_node = yaml_node[0];
return GxfParameterSetFromYamlNode(context, uid, key, &value_node, "");
}
break;
}
case ArgElementType::kUnsigned16: {
if constexpr (std::is_same_v<typeT, uint16_t>) {
return GxfParameterSetUInt16(context, uid, key, value);
}
break;
}
case ArgElementType::kInt32: {
if constexpr (std::is_same_v<typeT, int32_t>) {
return GxfParameterSetInt32(context, uid, key, value);
}
break;
}
case ArgElementType::kUnsigned32: {
if constexpr (std::is_same_v<typeT, uint32_t>) {
return GxfParameterSetUInt32(context, uid, key, value);
}
break;
}
case ArgElementType::kInt64: {
if constexpr (std::is_same_v<typeT, int64_t>) {
return GxfParameterSetInt64(context, uid, key, value);
}
break;
}
case ArgElementType::kUnsigned64: {
if constexpr (std::is_same_v<typeT, uint64_t>) {
return GxfParameterSetUInt64(context, uid, key, value);
}
break;
}
case ArgElementType::kFloat32: {
// GXF Doesn't support float parameter so use a workaround with
// GxfParameterSetFromYamlNode.
if constexpr (std::is_same_v<typeT, float>) {
YAML::Node yaml_node;
yaml_node.push_back(value);
YAML::Node value_node = yaml_node[0];
return GxfParameterSetFromYamlNode(context, uid, key, &value_node, "");
}
break;
}
case ArgElementType::kFloat64: {
if constexpr (std::is_same_v<typeT, double>) {
return GxfParameterSetFloat64(context, uid, key, value);
}
break;
}
case ArgElementType::kString: {
if constexpr (std::is_same_v<typeT, std::string>) {
return GxfParameterSetStr(context, uid, key, value.c_str());
}
break;
}
case ArgElementType::kHandle: {
HOLOSCAN_LOG_ERROR("Unable to set handle parameter for key '{}'", key);
return GXF_FAILURE;
}
case ArgElementType::kYAMLNode: {
HOLOSCAN_LOG_ERROR("Unable to handle ArgElementType::kYAMLNode for key '{}'",
key);
return GXF_FAILURE;
}
case ArgElementType::kIOSpec: {
if constexpr (std::is_same_v<typeT, holoscan::IOSpec*>) {
if (value) {
auto gxf_resource =
std::dynamic_pointer_cast<GXFResource>(value->resource());
gxf_uid_t cid = gxf_resource->gxf_cid();
return GxfParameterSetHandle(context, uid, key, cid);
} else {
// If the IOSpec is null, do not set the parameter.
return GXF_SUCCESS;
}
}
break;
}
case ArgElementType::kResource: {
if constexpr (std::is_same_v<
typename holoscan::type_info<typeT>::element_type,
std::shared_ptr<Resource>> &&
holoscan::type_info<typeT>::dimension == 0) {
// Set the handle parameter only if the resource is valid.
if (value) {
auto gxf_resource = std::dynamic_pointer_cast<GXFResource>(value);
// Initialize GXF component if it is not already initialized.
if (gxf_resource->gxf_context() == nullptr) {
gxf_resource->gxf_eid(gxf::get_component_eid(
context, uid)); // set Entity ID of the component
gxf_resource->initialize();
}
return GxfParameterSetHandle(context, uid, key, gxf_resource->gxf_cid());
} else {
HOLOSCAN_LOG_TRACE(
"Resource is null for key '{}'. Not setting parameter.", key);
return GXF_SUCCESS;
}
}
HOLOSCAN_LOG_ERROR("Unable to handle ArgElementType::kResource for key '{}'",
key);
break;
}
case ArgElementType::kCondition: {
if constexpr (std::is_same_v<
typename holoscan::type_info<typeT>::element_type,
std::shared_ptr<Condition>> &&
holoscan::type_info<typeT>::dimension == 0) {
auto gxf_condition = std::dynamic_pointer_cast<GXFCondition>(value);
if (value) {
// Initialize GXF component if it is not already initialized.
if (gxf_condition->gxf_context() == nullptr) {
gxf_condition->gxf_eid(gxf::get_component_eid(
context, uid)); // set Entity ID of the component
gxf_condition->initialize();
}
return GxfParameterSetHandle(context, uid, key, gxf_condition->gxf_cid());
}
HOLOSCAN_LOG_ERROR(
"Unable to handle ArgElementType::kCondition for key '{}'", key);
}
break;
}
case ArgElementType::kCustom: {
HOLOSCAN_LOG_ERROR("Unable to handle ArgElementType::kCustom for key '{}'",
key);
return GXF_FAILURE;
}
}
break;
}
case ArgContainerType::kVector: {
switch (arg_type.element_type()) {
case ArgElementType::kInt8: {
HOLOSCAN_LOG_ERROR(
"GXF does not support std::vector<int8_t> parameter "
"for key '{}'",
key);
return GXF_FAILURE;
}
case ArgElementType::kUnsigned8: {
// GXF Doesn't support std::vector
parameter so use a workaround with
// GxfParameterSetFromYamlNode.
if constexpr (std::is_same_v<typeT, std::vector<uint8_t>>) {
// Create vector of Handles
YAML::Node yaml_node;
for (auto& item : value) {
// uint8_t is not supported natively by yaml-cpp so push it as a uint32_t
// so that GXF can handle it.
yaml_node.push_back(static_cast<uint32_t>(item));
}
return GxfParameterSetFromYamlNode(context, uid, key, &yaml_node, "");
} else if constexpr (std::is_same_v<typeT,
std::vector<std::vector<uint32_t>>>) {
YAML::Node yaml_node;
for (const std::vector<uint32_t>& vec : value) {
for (uint32_t item : vec) { yaml_node.push_back(item); }
}
return GxfParameterSetFromYamlNode(context, uid, key, &yaml_node, "");
}
break;
}
case ArgElementType::kBoolean:
case ArgElementType::kInt16:
case ArgElementType::kUnsigned16:
case ArgElementType::kInt32:
case ArgElementType::kUnsigned32:
case ArgElementType::kInt64:
case ArgElementType::kUnsigned64:
case ArgElementType::kFloat32:
case ArgElementType::kFloat64:
case ArgElementType::kString: {
// GXF Doesn't support std::vector
parameter so use a workaround with
// GxfParameterSetFromYamlNode.
if constexpr (holoscan::is_one_of_v<
typename holoscan::type_info<typeT>::element_type,
bool,
int16_t,
uint16_t,
int32_t,
uint32_t,
int64_t,
uint64_t,
float,
double,
std::string>) {
if constexpr (holoscan::dimension_of_v<typeT> == 1) {
// Create vector of Handles
YAML::Node yaml_node = YAML::Load("[]"); // Create an empty sequence
for (typename holoscan::type_info<typeT>::element_type item : value) {
yaml_node.push_back(item);
}
return GxfParameterSetFromYamlNode(context, uid, key, &yaml_node, "");
} else if constexpr (holoscan::dimension_of_v<typeT> == 2) {
YAML::Node yaml_node = YAML::Load("[]"); // Create an empty sequence
for (std::vector<typename holoscan::type_info<typeT>::element_type>& vec :
value) {
YAML::Node inner_yaml_node =
YAML::Load("[]"); // Create an empty sequence
for (typename holoscan::type_info<typeT>::element_type item : vec) {
inner_yaml_node.push_back(item);
}
if (inner_yaml_node.size() > 0) {
yaml_node.push_back(inner_yaml_node);
}
}
return GxfParameterSetFromYamlNode(context, uid, key, &yaml_node, "");
}
}
break;
}
case ArgElementType::kHandle: {
HOLOSCAN_LOG_ERROR(
"Unable to handle vector of ArgElementType::kHandle for key '{}'", key);
return GXF_FAILURE;
}
case ArgElementType::kYAMLNode: {
HOLOSCAN_LOG_ERROR(
"Unable to handle vector of ArgElementType::kYAMLNode for key '{}'", key);
return GXF_FAILURE;
}
case ArgElementType::kIOSpec: {
if constexpr (std::is_same_v<typeT, std::vector<holoscan::IOSpec*>>) {
// Create vector of Handles
YAML::Node yaml_node = YAML::Load("[]"); // Create an empty sequence
for (auto& io_spec : value) {
if (io_spec) { // Only consider non-null IOSpecs
auto gxf_resource =
std::dynamic_pointer_cast<GXFResource>(io_spec->resource());
yaml_node.push_back(gxf_resource->gxf_cname());
}
}
return GxfParameterSetFromYamlNode(context, uid, key, &yaml_node, "");
}
HOLOSCAN_LOG_ERROR(
"Unable to handle vector of std::vector<holoscan::IOSpec*>> for key: "
"'{}'",
key);
break;
}
case ArgElementType::kResource: {
if constexpr (std::is_same_v<
typename holoscan::type_info<typeT>::element_type,
std::shared_ptr<Resource>> &&
holoscan::type_info<typeT>::dimension == 1) {
// Create vector of Handles
YAML::Node yaml_node;
for (auto& resource : value) {
auto gxf_resource = std::dynamic_pointer_cast<GXFResource>(resource);
// Push back the resource's gxf_cname only if it is not null.
if (gxf_resource) {
gxf_uid_t resource_cid = gxf_resource->gxf_cid();
std::string full_resource_name =
gxf::get_full_component_name(context, resource_cid);
yaml_node.push_back(full_resource_name.c_str());
} else {
HOLOSCAN_LOG_TRACE(
"Resource item in the vector is null. Skipping it for key '{}'",
key);
}
}
return GxfParameterSetFromYamlNode(context, uid, key, &yaml_node, "");
}
HOLOSCAN_LOG_ERROR(
"Unable to handle vector of ArgElementType::kResource for key '{}'", key);
break;
}
case ArgElementType::kCondition: {
if constexpr (std::is_same_v<
typename holoscan::type_info<typeT>::element_type,
std::shared_ptr<Condition>> &&
holoscan::type_info<typeT>::dimension == 1) {
// Create vector of Handles
YAML::Node yaml_node;
for (auto& condition : value) {
auto gxf_condition = std::dynamic_pointer_cast<GXFCondition>(condition);
// Initialize GXF component if it is not already initialized.
if (gxf_condition->gxf_context() == nullptr) {
gxf_condition->gxf_eid(gxf::get_component_eid(
context, uid)); // set Entity ID of the component
gxf_condition->initialize();
}
gxf_uid_t condition_cid = gxf_condition->gxf_cid();
std::string full_condition_name =
gxf::get_full_component_name(context, condition_cid);
yaml_node.push_back(full_condition_name.c_str());
}
return GxfParameterSetFromYamlNode(context, uid, key, &yaml_node, "");
}
HOLOSCAN_LOG_ERROR(
"Unable to handle vector of ArgElementType::kCondition for key '{}'",
key);
break;
}
case ArgElementType::kCustom: {
HOLOSCAN_LOG_ERROR(
"Unable to handle vector of ArgElementType::kCustom type for key '{}'",
key);
return GXF_FAILURE;
}
}
break;
}
case ArgContainerType::kArray: {
HOLOSCAN_LOG_ERROR("Unable to handle ArgContainerType::kArray type for key '{}'",
key);
break;
}
}
}
HOLOSCAN_LOG_WARN(
"Unable to get argument for key '{}' with type '{}'", key, typeid(typeT).name());
} catch (const std::bad_any_cast& e) {
HOLOSCAN_LOG_ERROR("Bad any cast exception: {}", e.what());
}
return GXF_FAILURE;
});
}
private:
GXFParameterAdaptor() {
add_param_handler<bool>();
add_param_handler<int8_t>();
add_param_handler<int16_t>();
add_param_handler<int32_t>();
add_param_handler<int64_t>();
add_param_handler<uint8_t>();
add_param_handler<uint16_t>();
add_param_handler<uint32_t>();
add_param_handler<uint64_t>();
add_param_handler<float>();
add_param_handler<double>();
add_param_handler<std::string>();
add_param_handler<std::vector<bool>>();
add_param_handler<std::vector<int8_t>>();
add_param_handler<std::vector<int16_t>>();
add_param_handler<std::vector<int32_t>>();
add_param_handler<std::vector<int64_t>>();
add_param_handler<std::vector<uint8_t>>();
add_param_handler<std::vector<uint16_t>>();
add_param_handler<std::vector<uint32_t>>();
add_param_handler<std::vector<uint64_t>>();
add_param_handler<std::vector<float>>();
add_param_handler<std::vector<double>>();
add_param_handler<std::vector<std::string>>();
add_param_handler<std::vector<std::vector<bool>>>();
add_param_handler<std::vector<std::vector<int8_t>>>();
add_param_handler<std::vector<std::vector<int16_t>>>();
add_param_handler<std::vector<std::vector<int32_t>>>();
add_param_handler<std::vector<std::vector<int64_t>>>();
add_param_handler<std::vector<std::vector<uint8_t>>>();
add_param_handler<std::vector<std::vector<uint16_t>>>();
add_param_handler<std::vector<std::vector<uint32_t>>>();
add_param_handler<std::vector<std::vector<uint64_t>>>();
add_param_handler<std::vector<std::vector<float>>>();
add_param_handler<std::vector<std::vector<double>>>();
add_param_handler<std::vector<std::vector<std::string>>>();
add_param_handler<holoscan::IOSpec*>();
add_param_handler<std::vector<holoscan::IOSpec*>>();
add_param_handler<std::shared_ptr<Resource>>();
add_param_handler<std::vector<std::shared_ptr<Resource>>>();
add_param_handler<std::shared_ptr<Condition>>();
add_param_handler<std::vector<std::shared_ptr<Condition>>>();
}
std::unordered_map<std::type_index, AdaptFunc> function_map_;
};
} // namespace holoscan::gxf
#endif/* HOLOSCAN_CORE_EXECUTORS_GXF_GXF_PARAMETER_ADAPTOR_HPP */