// Copyright (C) 2018-2025 Intel Corporation // SPDX-License-Identifier: Apache-2.0 // /** * @brief A header file for the Any class * @file openvino/runtime/any.hpp */ #pragma once #include #include #include #include #include #include #include #include #include "openvino/core/attribute_visitor.hpp" #include "openvino/core/except.hpp" #include "openvino/core/runtime_attribute.hpp" namespace ov { class Plugin; /** @cond INTERNAL */ class Any; using AnyMap = std::map; namespace util { OPENVINO_API bool equal(std::type_index lhs, std::type_index rhs); template struct Read; template struct Readable { template static auto test(U*) -> decltype(std::declval>()(std::declval(), std::declval()), std::true_type()) { return {}; } template static auto test(...) -> std::false_type { return {}; } constexpr static const auto value = std::is_same(nullptr))>::value; }; template struct Istreamable { template static auto test(U*) -> decltype(std::declval() >> std::declval(), std::true_type()) { return {}; } template static auto test(...) -> std::false_type { return {}; } constexpr static const auto value = std::is_same(nullptr))>::value; }; template <> struct OPENVINO_API Read { void operator()(std::istream& is, bool& value) const; }; template <> struct OPENVINO_API Read { void operator()(std::istream& is, Any& any) const; }; template <> struct OPENVINO_API Read { void operator()(std::istream& is, int& value) const; }; template <> struct OPENVINO_API Read { void operator()(std::istream& is, long& value) const; }; template <> struct OPENVINO_API Read { void operator()(std::istream& is, long long& value) const; }; template <> struct OPENVINO_API Read { void operator()(std::istream& is, unsigned& value) const; }; template <> struct OPENVINO_API Read { void operator()(std::istream& is, unsigned long& value) const; }; template <> struct OPENVINO_API Read { void operator()(std::istream& is, unsigned long long& value) const; }; template <> struct OPENVINO_API Read { void operator()(std::istream& is, float& value) const; }; template <> struct OPENVINO_API Read { void operator()(std::istream& is, double& value) const; }; template <> struct OPENVINO_API Read { void operator()(std::istream& is, long double& value) const; }; template <> struct OPENVINO_API Read> { void operator()(std::istream& is, std::tuple& tuple) const; }; template <> struct OPENVINO_API Read> { void operator()(std::istream& is, std::tuple& tuple) const; }; template <> struct OPENVINO_API Read { void operator()(std::istream& is, AnyMap& map) const; }; template auto from_string(const std::string& str) -> const typename std::enable_if::value, T>::type& { return str; } template auto from_string(const std::string& val) -> typename std::enable_if::value && !std::is_same::value, T>::type { std::stringstream ss(val); T value; Read{}(ss, value); return value; } template auto from_string(const std::string& val) -> typename std::enable_if::value && Istreamable::value && !std::is_same::value, T>::type { std::stringstream ss(val); T value; ss >> value; return value; } template struct ValueTyped { template static auto test(U*) -> decltype(std::declval(), std::true_type()) { return {}; } template static auto test(...) -> std::false_type { return {}; } constexpr static const auto value = std::is_same(nullptr))>::value; }; template ::value && Readable::value, bool>::type = true> typename T::value_type from_string(const std::string& val, const T&) { std::stringstream ss(val); typename T::value_type value; Read{}(ss, value); return value; } template ::value && !Readable::value && Istreamable::value, bool>::type = true> typename T::value_type from_string(const std::string& val, const T&) { std::stringstream ss(val); typename T::value_type value; ss >> value; return value; } template auto from_string(const std::string& val) -> typename std::enable_if::value && !Istreamable::value && !std::is_same::value, T>::type { OPENVINO_THROW("Could read type without std::istream& operator>>(std::istream&, T)", " defined or ov::util::Read class specialization, T: ", typeid(T).name()); } template struct Read, typename std::enable_if::value>::type> { void operator()(std::istream& is, std::vector& vec) const { while (is.good()) { std::string str; is >> str; auto v = from_string(str); vec.push_back(std::move(v)); } } }; template struct Read, typename std::enable_if::value>::type> { void operator()(std::istream& is, std::set& set) const { while (is.good()) { std::string str; is >> str; auto v = from_string(str); set.insert(std::move(v)); } } }; template struct Read< std::map, typename std::enable_if::value && std::is_default_constructible::value>::type> { void operator()(std::istream& is, std::map& map) const { char c; is >> c; OPENVINO_ASSERT(c == '{', "Failed to parse std::map. Starting symbols is not '{', it's ", c); while (c != '}') { std::string key, value; std::getline(is, key, ':'); size_t enclosed_container_level = 0; while (is.good()) { is >> c; if (c == ',') { // delimiter between map's pairs if (enclosed_container_level == 0) // we should interrupt after delimiter break; } if (c == '{' || c == '[') // case of enclosed maps / arrays ++enclosed_container_level; if (c == '}' || c == ']') { if (enclosed_container_level == 0) break; // end of map --enclosed_container_level; } value += c; // accumulate current value } map.emplace(from_string(key), from_string(value)); } OPENVINO_ASSERT(c == '}', "Failed to parse std::map. Ending symbols is not '}', it's ", c); } }; template struct Write; template struct Ostreamable { template static auto test(U*) -> decltype(std::declval() << std::declval(), std::true_type()) { return {}; } template static auto test(...) -> std::false_type { return {}; } constexpr static const auto value = std::is_same(nullptr))>::value; }; template struct Writable { template static auto test(U*) -> decltype(std::declval>()(std::declval(), std::declval()), std::true_type()) { return {}; } template static auto test(...) -> std::false_type { return {}; } constexpr static const auto value = std::is_same(nullptr))>::value; }; template <> struct OPENVINO_API Write { void operator()(std::ostream& is, const bool& b) const; }; template <> struct OPENVINO_API Write { void operator()(std::ostream& is, const Any& any) const; }; template <> struct OPENVINO_API Write> { void operator()(std::ostream& os, const std::tuple& tuple) const; }; template <> struct OPENVINO_API Write> { void operator()(std::ostream& os, const std::tuple& tuple) const; }; template auto to_string(const T& str) -> const typename std::enable_if::value, T>::type& { return str; } template auto to_string(const T& value) -> typename std::enable_if::value && !std::is_same::value, std::string>::type { std::stringstream ss; Write{}(ss, value); return ss.str(); } template auto to_string(const T& value) -> typename std::enable_if::value && Ostreamable::value && !std::is_same::value, std::string>::type { std::stringstream ss; ss << value; return ss.str(); } template auto to_string(const T&) -> typename std::enable_if::value && !Ostreamable::value && !std::is_same::value, std::string>::type { OPENVINO_THROW("Could convert to string from type without std::ostream& operator>>(std::ostream&, const T&)", " defined or ov::util::Write class specialization, T: ", typeid(T).name()); } template struct Write> { void operator()(std::ostream& os, const std::vector& vec) const { if (!vec.empty()) { std::size_t i = 0; for (auto&& v : vec) { os << to_string(v); if (i < (vec.size() - 1)) os << ' '; ++i; } } } }; template struct Write> { void operator()(std::ostream& os, const std::set& set) const { if (!set.empty()) { std::size_t i = 0; for (auto&& v : set) { os << to_string(v); if (i < (set.size() - 1)) os << ' '; ++i; } } } }; template struct Write> { void operator()(std::ostream& os, const std::map& map) const { if (!map.empty()) { std::size_t i = 0; os << '{'; for (auto&& v : map) { os << to_string(v.first) << ':' << to_string(v.second); if (i < (map.size() - 1)) os << ','; ++i; } os << '}'; } } }; } // namespace util /** @endcond */ class Node; class RuntimeAttribute; class CompiledModel; namespace proxy { class CompiledModel; } class RemoteContext; class RemoteTensor; /** * @brief This class represents an object to work with different types */ class OPENVINO_API Any { std::shared_ptr _so; template using decay_t = typename std::decay::type; template struct EqualityComparable { static void* conv(bool); template static char test(decltype(conv(std::declval() == std::declval()))); template static long test(...); constexpr static const bool value = sizeof(test(nullptr)) == sizeof(char); }; template struct EqualityComparable> { static void* conv(bool); template static char test(decltype(conv(std::declval() == std::declval() && std::declval() == std::declval()))); template static long test(...); constexpr static const bool value = sizeof(test>(nullptr)) == sizeof(char); }; template struct EqualityComparable> { static void* conv(bool); template static char test(decltype(conv(std::declval() == std::declval()))); template static long test(...); constexpr static const bool value = sizeof(test>(nullptr)) == sizeof(char); }; template static typename std::enable_if::value, bool>::type equal_impl(const U& rhs, const U& lhs) { return rhs == lhs; } template [[noreturn]] static typename std::enable_if::value, bool>::type equal_impl(const U&, const U&) { OPENVINO_THROW("Could not compare types without equality operator"); } template struct HasBaseMemberType { template static auto test(U*) -> decltype(std::is_class::value, std::true_type()) { return {}; } template static auto test(...) -> std::false_type { return {}; } constexpr static const auto value = std::is_same(nullptr))>::value; }; template struct TupleToTypeIndex; template struct TupleToTypeIndex> { static std::vector get() { return {typeid(Args)...}; } }; class OPENVINO_API Base : public std::enable_shared_from_this { public: void type_check(const std::type_info&) const; using Ptr = std::shared_ptr; virtual const std::type_info& type_info() const = 0; virtual std::vector base_type_info() const = 0; bool is_base_type_info(const std::type_info& type_info) const; virtual const void* addressof() const = 0; void* addressof() { return const_cast(const_cast(this)->addressof()); } virtual Base::Ptr copy() const = 0; virtual bool equal(const Base& rhs) const = 0; virtual void print(std::ostream& os) const = 0; virtual void read(std::istream& os) = 0; void read_to(Base& other) const; virtual const DiscreteTypeInfo& get_type_info() const = 0; virtual std::shared_ptr as_runtime_attribute() const; virtual bool is_copyable() const; virtual Any init(const std::shared_ptr& node); virtual Any merge(const std::vector>& nodes); virtual std::string to_string(); virtual bool visit_attributes(AttributeVisitor&); bool visit_attributes(AttributeVisitor&) const; std::string to_string() const; bool is(const std::type_info& other) const; bool is_signed_integral() const; bool is_unsigned_integral() const; bool is_floating_point() const; template bool is() const { return is(typeid(decay_t)); } template T& as() & { return *static_cast*>(addressof()); } template const T& as() const& { return *static_cast*>(addressof()); } template T convert() const; protected: template [[noreturn]] U convert_impl() const; template U convert_impl() const; virtual ~Base(); }; template struct Impl; template struct Impl>::value>::type> : public Base { const DiscreteTypeInfo& get_type_info() const override { return static_cast(runtime_attribute.get())->get_type_info(); } std::shared_ptr as_runtime_attribute() const override { return std::static_pointer_cast(runtime_attribute); } bool is_copyable() const override { return static_cast(runtime_attribute.get())->is_copyable(); } Any init(const std::shared_ptr& node) override { return static_cast(runtime_attribute.get())->init(node); } Any merge(const std::vector>& nodes) override { return static_cast(runtime_attribute.get())->merge(nodes); } std::string to_string() override { return static_cast(runtime_attribute.get())->to_string(); } bool visit_attributes(AttributeVisitor& visitor) override { return static_cast(runtime_attribute.get())->visit_attributes(visitor); } Impl(const T& runtime_attribute) : runtime_attribute{runtime_attribute} {} const std::type_info& type_info() const override { return typeid(T); } std::vector base_type_info() const override { return {typeid(std::shared_ptr)}; } const void* addressof() const override { return std::addressof(runtime_attribute); } Base::Ptr copy() const override { return std::make_shared>(this->runtime_attribute); } bool equal(const Base& rhs) const override { if (rhs.is()) { return equal_impl(this->runtime_attribute, rhs.as()); } return false; } void print(std::ostream& os) const override { os << runtime_attribute->to_string(); } void read(std::istream&) override { OPENVINO_THROW("Pointer to runtime attribute is not readable from std::istream"); } T runtime_attribute; }; template struct Impl>::value>::type> : public Base { OPENVINO_RTTI(typeid(T).name()); template Impl(Args&&... args) : value(std::forward(args)...) {} const std::type_info& type_info() const override { return typeid(T); } const void* addressof() const override { return std::addressof(value); } Base::Ptr copy() const override { return std::make_shared>(this->value); } template static std::vector base_type_info_impl( typename std::enable_if::value, std::true_type>::type = {}) { return TupleToTypeIndex::get(); } template static std::vector base_type_info_impl( typename std::enable_if::value, std::false_type>::type = {}) { return {typeid(T)}; } std::vector base_type_info() const override { return base_type_info_impl(); } bool equal(const Base& rhs) const override { if (rhs.is()) { return equal_impl(this->value, rhs.as()); } return false; } template static typename std::enable_if::value>::type print_impl(std::ostream& os, const U& value) { util::Write{}(os, value); } template static typename std::enable_if::value && util::Ostreamable::value>::type print_impl( std::ostream& os, const U& value) { os << value; } template static typename std::enable_if::value && !util::Ostreamable::value>::type print_impl( std::ostream&, const U&) {} void print(std::ostream& os) const override { print_impl(os, value); } template static typename std::enable_if::value>::type read_impl(std::istream& is, U& value) { util::Read{}(is, value); } template static typename std::enable_if::value && util::Istreamable::value>::type read_impl( std::istream& is, U& value) { is >> value; } template static typename std::enable_if::value && !util::Istreamable::value>::type read_impl( std::istream&, U&) { OPENVINO_THROW("Could read type without std::istream& operator>>(std::istream&, T)", " defined or ov::util::Read class specialization, T: ", typeid(T).name()); } void read(std::istream& is) override { read_impl(is, value); } T value; }; // Generic if there is no specialization for T. template T& as_impl(...) { impl_check(); if (is()) { return _impl->as(); } OPENVINO_THROW("Bad as from: ", _impl->type_info().name(), " to: ", typeid(T).name()); } template ::value>::type* = nullptr> T& as_impl(int) { if (_impl != nullptr) { if (_impl->is()) { return _impl->as(); } else { _temp = std::make_shared>(); _impl->read_to(*_temp); return _temp->as(); } } else { _temp = std::make_shared>(); return _temp->as(); } } template < class T, typename std::enable_if>::value>::type* = nullptr> T& as_impl(int) { if (_impl == nullptr) { _temp = std::make_shared>>(T{}); return _temp->as(); } else { if (_impl->is()) { return _impl->as(); } else { auto runtime_attribute = _impl->as_runtime_attribute(); if (runtime_attribute == nullptr) { OPENVINO_THROW("Any does not contains pointer to runtime_attribute. It contains ", _impl->type_info().name()); } auto vptr = ov::as_type_ptr(runtime_attribute); if (vptr == nullptr && T::element_type::get_type_info_static() != runtime_attribute->get_type_info() && T::element_type::get_type_info_static() != RuntimeAttribute::get_type_info_static()) { OPENVINO_THROW("Could not as Any runtime_attribute to ", typeid(T).name(), " from ", _impl->type_info().name(), "; from ", static_cast(runtime_attribute->get_type_info()), " to ", static_cast(T::element_type::get_type_info_static())); } _temp = std::make_shared>>( std::static_pointer_cast(runtime_attribute)); return _temp->as(); } } } template ::value && !std::is_same::type, bool>::value>::type* = nullptr> T& as_impl(int); template ::value || util::Readable::value) && !std::is_same::value && (!std::is_arithmetic::value || std::is_same::type, bool>::value)>::type* = nullptr> T& as_impl(int) { impl_check(); if (is()) { return _impl->as(); } else if (_impl->is()) { _temp = std::make_shared>>(); _impl->read_to(*_temp); return _temp->as(); } OPENVINO_THROW("Bad as from: ", _impl->type_info().name(), " to: ", typeid(T).name()); } friend class ::ov::RuntimeAttribute; friend class ::ov::CompiledModel; friend class ::ov::proxy::CompiledModel; friend class ::ov::RemoteContext; friend class ::ov::RemoteTensor; friend class ::ov::Plugin; Any(const Any& other, const std::shared_ptr& so); void impl_check() const; mutable Base::Ptr _temp; Base::Ptr _impl; public: /// @brief Default constructor Any() = default; /// @brief Copy constructor /// @param other other Any object Any(const Any& other); /// @brief Copy assignment operator /// @param other other Any object /// @return reference to the current object Any& operator=(const Any& other); /// @brief Default move constructor /// @param other other Any object Any(Any&& other) = default; /// @brief Default move assignment operator /// @param other other Any object /// @return reference to the current object Any& operator=(Any&& other) = default; /** * @brief Destructor preserves unloading order of implementation object and reference to library */ ~Any(); /** * @brief Constructor creates any with object * * @tparam T Any type * @param value object */ template , Any>::value && !std::is_abstract>::value && !std::is_convertible, Base::Ptr>::value, bool>::type = true> Any(T&& value) : _impl{std::make_shared>>(std::forward(value))} {} /** * @brief Constructor creates string any from char * * * @param str char array */ Any(const char* str); /** * @brief Empty constructor * */ Any(const std::nullptr_t); /** * @brief Inplace value construction function * * @tparam T Any type * @tparam Args pack of parameter types passed to T constructor * @param args pack of parameters passed to T constructor */ template static Any make(Args&&... args) { Any any; any._impl = std::make_shared>>(std::forward(args)...); return any; } /** * Returns type info * @return type info */ const std::type_info& type_info() const; /** * Checks that any contains a value * @return false if any contains a value else false */ bool empty() const; /** * @brief Check that stored type can be casted to specified type. * If internal type supports Base * @tparam T Type of value * @return true if type of value is correct. Return false if any is empty */ template bool is() const { return _impl && (_impl->is() || _impl->is_base_type_info(typeid(decay_t))); } /** * Dynamic as to specified type * @tparam T type * @return reference to caster object */ template T& as() { return as_impl(int{}); } /** * Dynamic as to specified type * @tparam T type * @return const reference to caster object */ template const T& as() const { return const_cast(this)->as(); } /** * @brief The comparison operator for the Any * * @param other object to compare * @return true if objects are equal */ bool operator==(const Any& other) const; /** * @brief The comparison operator for the Any * * @param other object to compare * @return true if objects are equal */ bool operator==(const std::nullptr_t&) const; /** * @brief The comparison operator for the Any * * @param other object to compare * @return true if objects aren't equal */ bool operator!=(const Any& other) const; /** * @brief Prints underlying object to the given output stream. * Uses operator<< if it is defined, leaves stream unchanged otherwise. * In case of empty any or nullptr stream immediately returns. * * @param stream Output stream object will be printed to. */ void print(std::ostream& stream) const; /** * @brief Read into underlying object from the given input stream. * Uses operator>> if it is defined, leaves stream unchanged otherwise. * In case of empty any or nullptr stream immediately returns. * * @param stream Output stream object will be printed to. */ void read(std::istream& stream); /** * @brief Returns address to internal value if any is not empty and `nullptr` instead * @return address to internal stored value */ void* addressof(); /** * @brief Returns address to internal value if any is not empty and `nullptr` instead * @return address to internal stored value */ const void* addressof() const; }; using RTMap = AnyMap; using AnyVector = std::vector; /** @cond INTERNAL */ inline static void PrintTo(const Any& any, std::ostream* os) { any.print(*os); } /** @endcond */ template <> OPENVINO_API unsigned long long Any::Base::convert() const; template <> OPENVINO_API long long Any::Base::convert() const; template <> OPENVINO_API double Any::Base::convert() const; template ::value && !std::is_same::type, bool>::value>::type*> T& Any::as_impl(int) { impl_check(); if (is()) { return _impl->as(); } else if (util::Readable::value && _impl->is()) { _temp = std::make_shared>>(); _impl->read_to(*_temp); return _temp->as(); } else if (_impl->is_signed_integral()) { auto value = _impl->convert(); _temp = std::make_shared>>(static_cast(value)); return _temp->as(); } else if (_impl->is_unsigned_integral()) { auto value = _impl->convert(); _temp = std::make_shared>>(static_cast(value)); return _temp->as(); } else if (_impl->is_floating_point()) { auto value = _impl->convert(); _temp = std::make_shared>>(static_cast(value)); return _temp->as(); } OPENVINO_THROW("Bad as from: ", _impl->type_info().name(), " to: ", typeid(T).name()); } } // namespace ov