diff --git a/src/core/include/openvino/core/any.hpp b/src/core/include/openvino/core/any.hpp
index 9badb007d526b9..e002756d361f1f 100644
--- a/src/core/include/openvino/core/any.hpp
+++ b/src/core/include/openvino/core/any.hpp
@@ -485,6 +485,7 @@ class OPENVINO_API Any {
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());
@@ -506,6 +507,9 @@ class OPENVINO_API Any {
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 {
@@ -514,17 +518,24 @@ class OPENVINO_API Any {
template
T& as() & {
- type_check(typeid(decay_t));
return *static_cast*>(addressof());
}
template
const T& as() const& {
- type_check(typeid(decay_t));
return *static_cast*>(addressof());
}
+ template
+ T convert() const;
+
protected:
+ template
+ [[noreturn]] U convert_impl() const;
+
+ template
+ U convert_impl() const;
+
virtual ~Base() = default;
};
@@ -685,6 +696,92 @@ class OPENVINO_API Any {
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 = std::dynamic_pointer_cast(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;
@@ -704,11 +801,11 @@ class OPENVINO_API Any {
/// @brief Default constructor
Any() = default;
- /// @brief Сopy constructor
+ /// @brief Copy constructor
/// @param other other Any object
Any(const Any& other);
- /// @brief Сopy assignment operator
+ /// @brief Copy assignment operator
/// @param other other Any object
/// @return reference to the current object
Any& operator=(const Any& other);
@@ -756,8 +853,8 @@ class OPENVINO_API Any {
* @brief Inplace value construction function
*
* @tparam T Any type
- * @tparam Args pack of paramter types passed to T constructor
- * @param args pack of paramters passed to T constructor
+ * @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) {
@@ -786,130 +883,21 @@ class OPENVINO_API Any {
*/
template
bool is() const {
- if (_impl != nullptr) {
- if (_impl->is(typeid(decay_t))) {
- return true;
- }
- for (const auto& type_index : _impl->base_type_info()) {
- if (util::equal(type_index, typeid(decay_t))) {
- return true;
- }
- }
- }
- return false;
- }
-
- /**
- * Dynamic cast to specified type
- * @tparam T type
- * @return casted object
- */
- template
- typename std::enable_if>::value, T>::type& as() {
- if (_impl == nullptr) {
- _temp = std::make_shared>>(T{});
- return *static_cast*>(_temp->addressof());
- } else {
- if (_impl->is(typeid(decay_t))) {
- return *static_cast*>(_impl->addressof());
- } 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 = std::dynamic_pointer_cast(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 cast 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 *static_cast*>(_temp->addressof());
- }
- }
- }
-
- /**
- * Dynamic cast to specified type
- * @tparam T type
- * @return casted object
- */
- template
- typename std::enable_if>::value &&
- !std::is_same::value && std::is_default_constructible::value &&
- (util::Istreamable::value || util::Readable::value),
- T>::type&
- as() {
- impl_check();
- if (_impl->is(typeid(decay_t))) {
- return *static_cast*>(_impl->addressof());
- } else if (_impl->is(typeid(std::string))) {
- _temp = std::make_shared>>();
- _impl->read_to(*_temp);
- return *static_cast*>(_temp->addressof());
- }
- for (const auto& type_index : _impl->base_type_info()) {
- if (util::equal(type_index, typeid(decay_t))) {
- return *static_cast*>(_impl->addressof());
- }
- }
- OPENVINO_THROW("Bad cast from: ", _impl->type_info().name(), " to: ", typeid(T).name());
- }
-
- /**
- * Dynamic cast to specified type
- * @tparam T type
- * @return casted object
- */
- template
- typename std::enable_if<
- !std::is_convertible>::value && !std::is_same::value &&
- (!std::is_default_constructible::value || (!util::Istreamable::value && !util::Readable::value)),
- T>::type&
- as() {
- impl_check();
- if (_impl->is(typeid(decay_t))) {
- return *static_cast*>(_impl->addressof());
- }
- for (const auto& type_index : _impl->base_type_info()) {
- if (util::equal(type_index, typeid(decay_t))) {
- return *static_cast*>(_impl->addressof());
- }
- }
- OPENVINO_THROW("Bad cast from: ", _impl->type_info().name(), " to: ", typeid(T).name());
+ return _impl && (_impl->is() || _impl->is_base_type_info(typeid(decay_t)));
}
/**
- * Dynamic cast to specified type
+ * Dynamic as to specified type
* @tparam T type
- * @return casted object
+ * @return reference to caster object
*/
template
- typename std::enable_if::value, T>::type& as() {
- if (_impl != nullptr) {
- if (_impl->is(typeid(decay_t))) {
- return *static_cast*>(_impl->addressof());
- } else {
- _temp = std::make_shared>();
- _impl->read_to(*_temp);
- return *static_cast(_temp->addressof());
- }
- } else {
- _temp = std::make_shared>();
- return *static_cast(_temp->addressof());
- }
+ T& as() {
+ return as_impl(int{});
}
/**
- * Dynamic cast to specified type
+ * Dynamic as to specified type
* @tparam T type
* @return const reference to caster object
*/
@@ -983,4 +971,40 @@ inline static void PrintTo(const Any& any, std::ostream* 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
diff --git a/src/core/src/any.cpp b/src/core/src/any.cpp
index 82dc01c99377fd..346819eced93e5 100644
--- a/src/core/src/any.cpp
+++ b/src/core/src/any.cpp
@@ -6,6 +6,17 @@
#include
#include
+namespace {
+template
+bool contains_type_index(Container&& types, const std::type_info& user_type) {
+ for (auto&& type : types) {
+ if (ov::util::equal(type, user_type)) {
+ return true;
+ }
+ }
+ return false;
+}
+} // namespace
namespace ov {
@@ -68,6 +79,48 @@ void Any::Base::read_to(Base& other) const {
}
}
+bool Any::Base::is_base_type_info(const std::type_info& user_type) const {
+ return contains_type_index(base_type_info(), user_type);
+}
+
+bool Any::Base::is_signed_integral() const {
+ return std::is_signed::value ? contains_type_index(std::initializer_list{typeid(char),
+ typeid(signed char),
+ typeid(short),
+ typeid(int),
+ typeid(long),
+ typeid(long long)},
+ type_info())
+ : contains_type_index(std::initializer_list{typeid(signed char),
+ typeid(short),
+ typeid(int),
+ typeid(long),
+ typeid(long long)},
+ type_info());
+}
+
+bool Any::Base::is_unsigned_integral() const {
+ return std::is_signed::value
+ ? contains_type_index(std::initializer_list{typeid(unsigned char),
+ typeid(unsigned short),
+ typeid(unsigned int),
+ typeid(unsigned long),
+ typeid(unsigned long long)},
+ type_info())
+ : contains_type_index(std::initializer_list{typeid(char),
+ typeid(unsigned char),
+ typeid(unsigned short),
+ typeid(unsigned int),
+ typeid(unsigned long),
+ typeid(unsigned long long)},
+ type_info());
+}
+bool Any::Base::is_floating_point() const {
+ return contains_type_index(
+ std::initializer_list{typeid(float), typeid(double), typeid(long double)},
+ type_info());
+}
+
Any::~Any() {
_temp = {};
_impl = {};
@@ -293,4 +346,42 @@ void Write::operator()(std::ostream& os, const Any& any) const {
}
} // namespace util
+
+template
+[[noreturn]] U Any::Base::convert_impl() const {
+ OPENVINO_THROW("Bad cast from: ", type_info().name(), " to: ", typeid(U).name());
+}
+
+template
+U Any::Base::convert_impl() const {
+ return is() ? static_cast(as()) : convert_impl();
+}
+
+template <>
+long long Any::Base::convert() const {
+ return std::is_signed::value ? convert_impl()
+ : convert_impl();
+}
+
+template <>
+unsigned long long Any::Base::convert() const {
+ return std::is_signed::value ? convert_impl()
+ : convert_impl();
+}
+
+template <>
+double Any::Base::convert() const {
+ return convert_impl();
+}
} // namespace ov
diff --git a/src/core/tests/any.cpp b/src/core/tests/any.cpp
index 3914a617ff2982..33e928d60b872d 100644
--- a/src/core/tests/any.cpp
+++ b/src/core/tests/any.cpp
@@ -11,7 +11,8 @@
#include "common_test_utils/test_assertions.hpp"
#include "openvino/core/runtime_attribute.hpp"
-using namespace ov;
+namespace ov {
+namespace test {
class DestructorTest {
public:
@@ -735,3 +736,70 @@ TEST_F(AnyTests, EmptyStringAsAny) {
ASSERT_EQ(p.as>(), ref_f);
ASSERT_EQ(p.as>(), ref_i);
}
+
+template
+class AnyConversionTest : public AnyTests {};
+
+TYPED_TEST_SUITE_P(AnyConversionTest);
+
+using AnyArithmeticTypes = ::testing::Types;
+
+TYPED_TEST_P(AnyConversionTest, AnyToOtherValue) {
+ const TypeParam test_value{static_cast(23.15f)};
+ const auto a = Any{test_value};
+
+ EXPECT_EQ(a.as(), static_cast(test_value));
+ EXPECT_EQ(a.as(), static_cast(test_value));
+ EXPECT_EQ(a.as(), static_cast(test_value));
+ EXPECT_EQ(a.as(), static_cast(test_value));
+
+ EXPECT_EQ(a.as(), static_cast(test_value));
+ EXPECT_EQ(a.as(), static_cast(test_value));
+ EXPECT_EQ(a.as(), static_cast(test_value));
+ EXPECT_EQ(a.as(), static_cast(test_value));
+ EXPECT_EQ(a.as(), static_cast(test_value));
+
+ EXPECT_EQ(a.as(), static_cast(test_value));
+ EXPECT_EQ(a.as(), static_cast(test_value));
+}
+
+REGISTER_TYPED_TEST_SUITE_P(AnyConversionTest, AnyToOtherValue);
+INSTANTIATE_TYPED_TEST_SUITE_P(InstantiationName, AnyConversionTest, AnyArithmeticTypes);
+
+TEST_F(AnyTests, AnyAsOtherTypeIsIncosisoinet) {
+ // To show member `as` current behaviour.
+ // Maybe there should be two members `as` which return value
+ // and `cast` returns reference if casted type is same as Any underlying type
+ auto a = Any{10};
+
+ auto& a_int = a.as();
+ auto& a_str = a.as();
+
+ EXPECT_EQ(a_int, 10);
+ EXPECT_EQ(a_str, "10");
+
+ a_int = 15;
+ EXPECT_EQ(a_int, 15);
+ // as string ref still has old value
+ EXPECT_EQ(a_str, "10");
+
+ a_str = "30";
+ EXPECT_EQ(a_int, 15);
+ // as string ref has new value but is not in sync what any contains.
+ EXPECT_EQ(a_str, "30");
+}
+
+} // namespace test
+} // namespace ov