Skip to content

Commit

Permalink
Expand ov::Any to allow convert numerical values to others (openvinot…
Browse files Browse the repository at this point in the history
…oolkit#27824)

### Details:
- Expand `ov::Any::as` member to allow convert numerical types to others
values.
- Refactor `ov::Any` internals to remove some code duplications and `as`
member has generic implementation, no need explicit condition to enable
it if specialization selection fails.

### Tickets:
 - CVS-157622

---------

Signed-off-by: Pawel Raasz <[email protected]>
Signed-off-by: Raasz, Pawel <[email protected]>
  • Loading branch information
praasz authored Dec 3, 2024
1 parent 5d2317d commit 963b1be
Show file tree
Hide file tree
Showing 3 changed files with 305 additions and 122 deletions.
266 changes: 145 additions & 121 deletions src/core/include/openvino/core/any.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,7 @@ class OPENVINO_API Any {
using Ptr = std::shared_ptr<Base>;
virtual const std::type_info& type_info() const = 0;
virtual std::vector<std::type_index> 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<void*>(const_cast<const Base*>(this)->addressof());
Expand All @@ -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 <class T>
bool is() const {
Expand All @@ -514,17 +518,24 @@ class OPENVINO_API Any {

template <class T>
T& as() & {
type_check(typeid(decay_t<T>));
return *static_cast<decay_t<T>*>(addressof());
}

template <class T>
const T& as() const& {
type_check(typeid(decay_t<T>));
return *static_cast<const decay_t<T>*>(addressof());
}

template <class T>
T convert() const;

protected:
template <class U>
[[noreturn]] U convert_impl() const;

template <class U, class T, class... Others>
U convert_impl() const;

virtual ~Base() = default;
};

Expand Down Expand Up @@ -685,6 +696,92 @@ class OPENVINO_API Any {
T value;
};

// Generic if there is no specialization for T.
template <class T>
T& as_impl(...) {
impl_check();
if (is<T>()) {
return _impl->as<T>();
}

OPENVINO_THROW("Bad as from: ", _impl->type_info().name(), " to: ", typeid(T).name());
}

template <class T, typename std::enable_if<std::is_same<T, std::string>::value>::type* = nullptr>
T& as_impl(int) {
if (_impl != nullptr) {
if (_impl->is<T>()) {
return _impl->as<T>();
} else {
_temp = std::make_shared<Impl<std::string>>();
_impl->read_to(*_temp);
return _temp->as<std::string>();
}
} else {
_temp = std::make_shared<Impl<std::string>>();
return _temp->as<std::string>();
}
}

template <
class T,
typename std::enable_if<std::is_convertible<T, std::shared_ptr<RuntimeAttribute>>::value>::type* = nullptr>
T& as_impl(int) {
if (_impl == nullptr) {
_temp = std::make_shared<Impl<decay_t<T>>>(T{});
return _temp->as<T>();
} else {
if (_impl->is<T>()) {
return _impl->as<T>();
} 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<typename T::element_type>(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<std::string>(runtime_attribute->get_type_info()),
" to ",
static_cast<std::string>(T::element_type::get_type_info_static()));
}
_temp = std::make_shared<Impl<decay_t<T>>>(
std::static_pointer_cast<typename T::element_type>(runtime_attribute));
return _temp->as<T>();
}
}
}

template <class T,
typename std::enable_if<std::is_arithmetic<T>::value &&
!std::is_same<typename std::decay<T>::type, bool>::value>::type* = nullptr>
T& as_impl(int);

template <class T,
typename std::enable_if<
(util::Istreamable<T>::value || util::Readable<T>::value) && !std::is_same<T, std::string>::value &&
(!std::is_arithmetic<T>::value || std::is_same<typename std::decay<T>::type, bool>::value)>::type* =
nullptr>
T& as_impl(int) {
impl_check();

if (is<T>()) {
return _impl->as<T>();
} else if (_impl->is<std::string>()) {
_temp = std::make_shared<Impl<decay_t<T>>>();
_impl->read_to(*_temp);
return _temp->as<T>();
}

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;
Expand All @@ -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);
Expand Down Expand Up @@ -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 <typename T, typename... Args>
static Any make(Args&&... args) {
Expand Down Expand Up @@ -786,130 +883,21 @@ class OPENVINO_API Any {
*/
template <class T>
bool is() const {
if (_impl != nullptr) {
if (_impl->is(typeid(decay_t<T>))) {
return true;
}
for (const auto& type_index : _impl->base_type_info()) {
if (util::equal(type_index, typeid(decay_t<T>))) {
return true;
}
}
}
return false;
}

/**
* Dynamic cast to specified type
* @tparam T type
* @return casted object
*/
template <class T>
typename std::enable_if<std::is_convertible<T, std::shared_ptr<RuntimeAttribute>>::value, T>::type& as() {
if (_impl == nullptr) {
_temp = std::make_shared<Impl<decay_t<T>>>(T{});
return *static_cast<decay_t<T>*>(_temp->addressof());
} else {
if (_impl->is(typeid(decay_t<T>))) {
return *static_cast<decay_t<T>*>(_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<typename T::element_type>(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<std::string>(runtime_attribute->get_type_info()),
" to ",
static_cast<std::string>(T::element_type::get_type_info_static()));
}
_temp = std::make_shared<Impl<decay_t<T>>>(
std::static_pointer_cast<typename T::element_type>(runtime_attribute));
return *static_cast<decay_t<T>*>(_temp->addressof());
}
}
}

/**
* Dynamic cast to specified type
* @tparam T type
* @return casted object
*/
template <class T>
typename std::enable_if<!std::is_convertible<T, std::shared_ptr<RuntimeAttribute>>::value &&
!std::is_same<T, std::string>::value && std::is_default_constructible<T>::value &&
(util::Istreamable<T>::value || util::Readable<T>::value),
T>::type&
as() {
impl_check();
if (_impl->is(typeid(decay_t<T>))) {
return *static_cast<decay_t<T>*>(_impl->addressof());
} else if (_impl->is(typeid(std::string))) {
_temp = std::make_shared<Impl<decay_t<T>>>();
_impl->read_to(*_temp);
return *static_cast<decay_t<T>*>(_temp->addressof());
}
for (const auto& type_index : _impl->base_type_info()) {
if (util::equal(type_index, typeid(decay_t<T>))) {
return *static_cast<decay_t<T>*>(_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 <class T>
typename std::enable_if<
!std::is_convertible<T, std::shared_ptr<RuntimeAttribute>>::value && !std::is_same<T, std::string>::value &&
(!std::is_default_constructible<T>::value || (!util::Istreamable<T>::value && !util::Readable<T>::value)),
T>::type&
as() {
impl_check();
if (_impl->is(typeid(decay_t<T>))) {
return *static_cast<decay_t<T>*>(_impl->addressof());
}
for (const auto& type_index : _impl->base_type_info()) {
if (util::equal(type_index, typeid(decay_t<T>))) {
return *static_cast<decay_t<T>*>(_impl->addressof());
}
}
OPENVINO_THROW("Bad cast from: ", _impl->type_info().name(), " to: ", typeid(T).name());
return _impl && (_impl->is<T>() || _impl->is_base_type_info(typeid(decay_t<T>)));
}

/**
* Dynamic cast to specified type
* Dynamic as to specified type
* @tparam T type
* @return casted object
* @return reference to caster object
*/
template <class T>
typename std::enable_if<std::is_same<T, std::string>::value, T>::type& as() {
if (_impl != nullptr) {
if (_impl->is(typeid(decay_t<T>))) {
return *static_cast<decay_t<T>*>(_impl->addressof());
} else {
_temp = std::make_shared<Impl<std::string>>();
_impl->read_to(*_temp);
return *static_cast<std::string*>(_temp->addressof());
}
} else {
_temp = std::make_shared<Impl<std::string>>();
return *static_cast<std::string*>(_temp->addressof());
}
T& as() {
return as_impl<T>(int{});
}

/**
* Dynamic cast to specified type
* Dynamic as to specified type
* @tparam T type
* @return const reference to caster object
*/
Expand Down Expand Up @@ -983,4 +971,40 @@ inline static void PrintTo(const Any& any, std::ostream* os) {
}
/** @endcond */

template <>
OPENVINO_API unsigned long long Any::Base::convert<unsigned long long>() const;

template <>
OPENVINO_API long long Any::Base::convert<long long>() const;

template <>
OPENVINO_API double Any::Base::convert<double>() const;

template <class T,
typename std::enable_if<std::is_arithmetic<T>::value &&
!std::is_same<typename std::decay<T>::type, bool>::value>::type*>
T& Any::as_impl(int) {
impl_check();
if (is<T>()) {
return _impl->as<T>();
} else if (util::Readable<T>::value && _impl->is<std::string>()) {
_temp = std::make_shared<Impl<decay_t<T>>>();
_impl->read_to(*_temp);
return _temp->as<T>();
} else if (_impl->is_signed_integral()) {
auto value = _impl->convert<long long>();
_temp = std::make_shared<Impl<decay_t<T>>>(static_cast<T>(value));
return _temp->as<T>();
} else if (_impl->is_unsigned_integral()) {
auto value = _impl->convert<unsigned long long>();
_temp = std::make_shared<Impl<decay_t<T>>>(static_cast<T>(value));
return _temp->as<T>();
} else if (_impl->is_floating_point()) {
auto value = _impl->convert<double>();
_temp = std::make_shared<Impl<decay_t<T>>>(static_cast<T>(value));
return _temp->as<T>();
}

OPENVINO_THROW("Bad as from: ", _impl->type_info().name(), " to: ", typeid(T).name());
}
} // namespace ov
Loading

0 comments on commit 963b1be

Please sign in to comment.