* Copyright (c) 2025 Huawei Technologies Co., Ltd.
* This program is free software, you can redistribute it and/or modify it under the terms and conditions of
* CANN Open Software License Agreement Version 2.0 (the "License").
* Please refer to the License for details. You may not use this file except in compliance with the License.
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
* See LICENSE in the root of the software repository for the full text of the License.
*/
#ifndef EXECUTE_GRAPH_ANY_VALUE_H
#define EXECUTE_GRAPH_ANY_VALUE_H
#include <functional>
#include <memory>
#include <vector>
#include "graph/types.h"
#include "graph/type_id.h"
#include "graph/ge_error_codes.h"
#include "graph/def_types.h"
namespace ge {
class ComputeGraph;
using GeTensorPtr = std::shared_ptr<GeTensor>;
using ComputeGraphPtr = std::shared_ptr<ComputeGraph>;
class AnyValue {
public:
using INT = int64_t;
using FLOAT = float;
using BOOL = bool;
using STR = std::string;
using TENSOR = GeTensorPtr;
using TENSOR_DESC = GeTensorDesc;
using GRAPH = ComputeGraphPtr;
using BYTES = Buffer;
using NAMED_ATTRS = ge::NamedAttrs;
using DATA_TYPE = ge::DataType;
using LIST_INT = std::vector<INT>;
using LIST_FLOAT = std::vector<FLOAT>;
using LIST_BOOL = std::vector<BOOL>;
using LIST_STR = std::vector<STR>;
using LIST_TENSOR = std::vector<TENSOR>;
using LIST_TENSOR_DESC = std::vector<TENSOR_DESC>;
using LIST_GRAPH = std::vector<GRAPH>;
using LIST_BYTES = std::vector<BYTES>;
using LIST_NAMED_ATTRS = std::vector<NAMED_ATTRS>;
using LIST_DATA_TYPE = std::vector<DATA_TYPE>;
using LIST_LIST_INT = std::vector<std::vector<int64_t>>;
using LIST_LIST_FLOAT = std::vector<std::vector<float>>;
using NamedAttrs = ge::NamedAttrs;
enum ValueType {
VT_NONE = 0,
VT_STRING = 1,
VT_FLOAT = 2,
VT_BOOL = 3,
VT_INT = 4,
VT_TENSOR_DESC = 5,
VT_TENSOR = 6,
VT_BYTES = 7,
VT_GRAPH = 8,
VT_NAMED_ATTRS = 9,
VT_LIST_LIST_INT = 10,
VT_DATA_TYPE = 11,
VT_LIST_LIST_FLOAT = 12,
VT_LIST_BASE = 1000,
VT_LIST_STRING = static_cast<int32_t>(VT_LIST_BASE) + static_cast<int32_t>(VT_STRING),
VT_LIST_FLOAT = static_cast<int32_t>(VT_LIST_BASE) + static_cast<int32_t>(VT_FLOAT),
VT_LIST_BOOL = static_cast<int32_t>(VT_LIST_BASE) + static_cast<int32_t>(VT_BOOL),
VT_LIST_INT = static_cast<int32_t>(VT_LIST_BASE) + static_cast<int32_t>(VT_INT),
VT_LIST_TENSOR_DESC = static_cast<int32_t>(VT_LIST_BASE) + static_cast<int32_t>(VT_TENSOR_DESC),
VT_LIST_TENSOR = static_cast<int32_t>(VT_LIST_BASE) + static_cast<int32_t>(VT_TENSOR),
VT_LIST_BYTES = static_cast<int32_t>(VT_LIST_BASE) + static_cast<int32_t>(VT_BYTES),
VT_LIST_GRAPH = static_cast<int32_t>(VT_LIST_BASE) + static_cast<int32_t>(VT_GRAPH),
VT_LIST_NAMED_ATTRS = static_cast<int32_t>(VT_LIST_BASE) + static_cast<int32_t>(VT_NAMED_ATTRS),
VT_LIST_DATA_TYPE = static_cast<int32_t>(VT_LIST_BASE) + static_cast<int32_t>(VT_DATA_TYPE),
};
AnyValue() = default;
AnyValue(AnyValue &&other) noexcept;
AnyValue(const AnyValue &other) {
if (!other.IsEmpty()) {
other.operate_(OperateType::kOpClone, &other, this);
}
}
AnyValue &operator=(AnyValue &&other) noexcept;
AnyValue &operator=(const AnyValue &other);
~AnyValue() noexcept {
Clear();
}
template <class T>
static AnyValue CreateFrom(T &&value) {
AnyValue av;
av.InnerSet(std::forward<T>(value));
return av;
}
template <typename T>
static AnyValue CreateFrom(const T &value) {
AnyValue av;
av.InnerSet(value);
return av;
}
template <class T>
graphStatus SetValue(T &&value) {
Clear();
InnerSet(std::forward<T>(value));
return GRAPH_SUCCESS;
}
template <typename T>
graphStatus SetValue(const T &value) {
Clear();
InnerSet(value);
return GRAPH_SUCCESS;
}
template <typename T>
graphStatus SetValue(std::initializer_list<T> values) {
Clear();
InnerSet(std::vector<T>(std::move(values)));
return GRAPH_SUCCESS;
}
template <typename T>
graphStatus GetValue(T &value) const {
auto *const p = Get<T>();
if (p == nullptr) {
return GRAPH_FAILED;
}
value = *p;
return GRAPH_SUCCESS;
}
template <class T>
const T *Get() const {
if (!SameType<T>()) {
return nullptr;
}
if (IsEmpty()) {
return nullptr;
}
return PtrToPtr<const void, const T>(GetAddr());
}
template <class T>
T *MutableGet();
template <class T>
bool SameType() const noexcept {
if (operate_ == nullptr) {
return false;
}
TypeId tid = kInvalidTypeId;
operate_(OperateType::kGetTypeId, this, &tid);
return tid == GetTypeId<T>();
}
void Swap(AnyValue &other) noexcept;
void Clear() noexcept {
if (operate_ == nullptr) {
return;
}
operate_(OperateType::kOpClear, nullptr, this);
}
bool IsEmpty() const noexcept {
return operate_ == nullptr;
}
ValueType GetValueType() const noexcept;
TypeId GetValueTypeId() const noexcept;
AnyValue Copy() const;
private:
template <typename T>
void InnerSet(T &&value) {
using PureT = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
using Inline = std::integral_constant<bool, sizeof(PureT) <= sizeof(holder_)>;
using Operations = typename std::conditional<Inline{}, AnyValue::InlineOperations<PureT>,
AnyValue::AllocateOperations<PureT>>::type;
Operations::Construct(std::forward<T>(value), this);
}
const void *GetAddr() const;
enum class OperateType : uint32_t { kOpClear, kOpGetAddr, kOpClone, kOpMove, kGetTypeId, kOperateTypeEnd };
template <typename T>
class InlineOperations {
public:
static void Operate(const OperateType ot, const AnyValue *const av, void *const out);
static void Construct(const T &value, AnyValue *const av);
static void Construct(T &&value, AnyValue *const av);
};
template <typename T>
class AllocateOperations {
public:
static void Operate(const OperateType ot, const AnyValue *const av, void *const out);
static void Construct(const T &value, AnyValue *const av);
static void Construct(T &&value, AnyValue *const av);
};
using ValueBuf = std::aligned_storage<sizeof(void *)>::type;
using ValueHolder = union {
void *pointer;
std::aligned_storage<sizeof(void *)>::type inline_buf;
};
ValueHolder holder_ = {nullptr};
void (*operate_)(OperateType ot, const AnyValue *av, void *out){nullptr};
};
using GeAttrValue = AnyValue;
template <typename T>
void AnyValue::AllocateOperations<T>::Construct(const T &value, AnyValue *const av) {
av->holder_.pointer = new (std::nothrow) T(value);
av->operate_ = AnyValue::AllocateOperations<T>::Operate;
}
template <typename T>
void AnyValue::AllocateOperations<T>::Construct(T &&value, AnyValue *const av) {
av->holder_.pointer = ::new (std::nothrow) T(std::forward<T>(value));
av->operate_ = AnyValue::AllocateOperations<T>::Operate;
}
template <typename T>
void AnyValue::AllocateOperations<T>::Operate(const AnyValue::OperateType ot, const AnyValue *const av,
void *const out) {
switch (ot) {
case OperateType::kOpClear: {
auto *const av_p = PtrToPtr<void, AnyValue>(out);
delete PtrToPtr<void, T>(av_p->holder_.pointer);
av_p->holder_.pointer = nullptr;
av_p->operate_ = nullptr;
break;
}
case OperateType::kOpGetAddr:
*PtrToPtr<void, void *>(out) = const_cast<void *>(av->holder_.pointer);
break;
case OperateType::kOpClone:
PtrToPtr<void, AnyValue>(out)->holder_.pointer =
new (std::nothrow) T(*PtrToPtr<const void, const T>(av->holder_.pointer));
PtrToPtr<void, AnyValue>(out)->operate_ = av->operate_;
break;
case OperateType::kOpMove: {
auto *const av_p = PtrToPtr<void, AnyValue>(out);
av_p->holder_.pointer = av->holder_.pointer;
av_p->operate_ = av->operate_;
const_cast<AnyValue *>(av)->holder_.pointer = nullptr;
break;
}
case OperateType::kGetTypeId:
*PtrToPtr<void, TypeId>(out) = GetTypeId<T>();
break;
default:
break;
}
}
template <typename T>
void AnyValue::InlineOperations<T>::Construct(const T &value, AnyValue *const av) {
(void)::new (&(av->holder_.inline_buf)) T(value);
av->operate_ = AnyValue::InlineOperations<T>::Operate;
}
template <typename T>
void AnyValue::InlineOperations<T>::Construct(T &&value, AnyValue *const av) {
Construct(value, av);
}
template <typename T>
void AnyValue::InlineOperations<T>::Operate(const AnyValue::OperateType ot, const AnyValue *const av, void *const out) {
switch (ot) {
case OperateType::kOpClear: {
auto *const av_p = PtrToPtr<void, AnyValue>(out);
PtrToPtr<std::aligned_storage<sizeof(void *)>::type, T>(&av_p->holder_.inline_buf)->~T();
av_p->operate_ = nullptr;
break;
}
case OperateType::kOpGetAddr:
*PtrToPtr<void, void *>(out) = const_cast<void *>(PtrToPtr<const ValueBuf, const void>(&av->holder_.inline_buf));
break;
case OperateType::kOpClone: {
auto *const av_p = PtrToPtr<void, AnyValue>(out);
(void)new (&av_p->holder_.inline_buf)
T(*PtrToPtr<const std::aligned_storage<sizeof(void *)>::type, const T>(&av->holder_.inline_buf));
av_p->operate_ = av->operate_;
break;
}
case OperateType::kOpMove: {
auto *const av_p = PtrToPtr<void, AnyValue>(out);
auto *const moved_t_p = const_cast<T *>(PtrToPtr<const ValueBuf, const T>(&av->holder_.inline_buf));
(void)new (&av_p->holder_.inline_buf) T(std::move(*moved_t_p));
av_p->operate_ = av->operate_;
break;
}
case OperateType::kGetTypeId:
*PtrToPtr<void, TypeId>(out) = GetTypeId<T>();
break;
default:
break;
}
}
template <class T>
auto AnyValue::MutableGet() -> T * {
if (!SameType<T>()) {
return nullptr;
}
if (IsEmpty()) {
return nullptr;
}
void *addr = nullptr;
operate_(OperateType::kOpGetAddr, this, &addr);
return PtrToPtr<void, T>(addr);
}
}
#endif