ov::Any can get value from stored string (#10131)

* Any value can fromm inner string

* Fixed review coment

* strict str to value conversion

* fix format
This commit is contained in:
Anton Pankratov 2022-02-04 20:41:37 +03:00 committed by GitHub
parent 1abc6e2a16
commit 69b118ed7b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 351 additions and 86 deletions

View File

@ -60,18 +60,17 @@ class OPENVINO_API Any {
constexpr static const auto value = std::is_same<std::true_type, decltype(test<T>(nullptr))>::value;
};
template <class T>
struct Istreamable {
template <class U>
static auto test(U*) -> decltype(std::declval<std::istream&>() >> std::declval<U&>(), std::true_type()) {
return {};
}
template <typename>
static auto test(...) -> std::false_type {
return {};
}
constexpr static const auto value = std::is_same<std::true_type, decltype(test<T>(nullptr))>::value;
};
template <class U>
static typename std::enable_if<Ostreamable<U>::value && !std::is_same<bool, U>::value>::type print_impl(
std::ostream& os,
const U& value) {
os << value;
}
static void print_impl(std::ostream& os, const bool& b);
template <class U>
static typename std::enable_if<!Ostreamable<U>::value>::type print_impl(std::ostream&, const U&) {}
template <typename T>
struct EqualityComparable {
@ -106,6 +105,17 @@ class OPENVINO_API Any {
constexpr static const bool value = sizeof(test<std::vector<T...>>(nullptr)) == sizeof(char);
};
template <class U>
static typename std::enable_if<EqualityComparable<U>::value, bool>::type equal_impl(const U& rhs, const U& lhs) {
return rhs == lhs;
}
template <class U>
[[noreturn]] static typename std::enable_if<!EqualityComparable<U>::value, bool>::type equal_impl(const U&,
const U&) {
throw ov::Exception{"Could not compare types without equality operator"};
}
template <typename T>
struct HasBaseMemberType {
template <class U>
@ -157,6 +167,42 @@ class OPENVINO_API Any {
constexpr static const auto value = std::is_same<std::true_type, decltype(test<T>(nullptr))>::value;
};
template <class T>
struct Istreamable {
template <class U>
static auto test(U*) -> decltype(std::declval<std::istream&>() >> std::declval<U&>(), std::true_type()) {
return {};
}
template <typename>
static auto test(...) -> std::false_type {
return {};
}
constexpr static const auto value = std::is_same<std::true_type, decltype(test<T>(nullptr))>::value;
};
template <class U>
static typename std::enable_if<Istreamable<U>::value && !std::is_same<bool, U>::value>::type read_impl(
std::istream& is,
U& value) {
is >> value;
}
static void read_impl(std::istream& is, bool& value);
static void read_impl(std::istream& is, int& value);
static void read_impl(std::istream& is, long& value);
static void read_impl(std::istream& is, long long& value);
static void read_impl(std::istream& is, unsigned& value);
static void read_impl(std::istream& is, unsigned long& value);
static void read_impl(std::istream& is, unsigned long long& value);
static void read_impl(std::istream& is, float& value);
static void read_impl(std::istream& is, double& value);
static void read_impl(std::istream& is, long double& value);
template <class U>
static typename std::enable_if<!Istreamable<U>::value>::type read_impl(std::istream&, U&) {
throw ov::Exception{"Could read type without std::istream& operator>>(std::istream&, T) defined"};
}
/**
* @brief Base API of erased type
*/
@ -253,17 +299,6 @@ class OPENVINO_API Any {
return std::make_shared<Impl<T>>(this->runtime_attribute);
}
template <class U>
static typename std::enable_if<EqualityComparable<U>::value, bool>::type equal_impl(const U& rhs,
const U& lhs) {
return rhs == lhs;
}
template <class U>
[[noreturn]] static typename std::enable_if<!EqualityComparable<U>::value, bool>::type equal_impl(const U&,
const U&) {
throw ov::Exception{"Could not compare types without equality operator"};
}
bool equal(const Base& rhs) const override {
if (rhs.is<T>()) {
return equal_impl(this->runtime_attribute, rhs.as<T>());
@ -317,17 +352,6 @@ class OPENVINO_API Any {
return base_type_info_impl<T>();
}
template <class U>
static typename std::enable_if<EqualityComparable<U>::value, bool>::type equal_impl(const U& rhs,
const U& lhs) {
return rhs == lhs;
}
template <class U>
[[noreturn]] static typename std::enable_if<!EqualityComparable<U>::value, bool>::type equal_impl(const U&,
const U&) {
throw ov::Exception{"Could not compare types without equality operator"};
}
bool equal(const Base& rhs) const override {
if (rhs.is<T>()) {
return equal_impl(this->value, rhs.as<T>());
@ -335,28 +359,10 @@ class OPENVINO_API Any {
return false;
}
template <class U>
static typename std::enable_if<Ostreamable<U>::value>::type print_impl(std::ostream& os, const U& value) {
os << value;
}
template <class U>
static typename std::enable_if<!Ostreamable<U>::value>::type print_impl(std::ostream&, const U&) {}
void print(std::ostream& os) const override {
print_impl(os, value);
}
template <class U>
static typename std::enable_if<Istreamable<U>::value>::type read_impl(std::istream& is, U& value) {
is >> value;
}
template <class U>
static typename std::enable_if<!Istreamable<U>::value>::type read_impl(std::istream&, U&) {
throw ov::Exception{"Could print type without std::istream& operator>>(std::istream&, T) defined"};
}
void read(std::istream& is) override {
read_impl(is, value);
}
@ -376,7 +382,9 @@ class OPENVINO_API Any {
void impl_check() const;
mutable Base::Ptr _runtime_attribute_impl;
mutable Base::Ptr _temp_impl;
mutable std::string _str;
Base::Ptr _impl;
@ -486,8 +494,8 @@ public:
template <typename T>
typename std::enable_if<std::is_convertible<T, std::shared_ptr<RuntimeAttribute>>::value, T>::type&& as() && {
if (_impl == nullptr) {
_runtime_attribute_impl = std::make_shared<Impl<decay_t<T>>>(T{});
return _runtime_attribute_impl->as<T>();
_temp_impl = std::make_shared<Impl<decay_t<T>>>(T{});
return _temp_impl->as<T>();
} else {
if (_impl->type_info() == typeid(decay_t<T>)) {
return std::move(*static_cast<decay_t<T>*>(_impl->addressof()));
@ -507,8 +515,8 @@ public:
static_cast<std::string>(T::element_type::get_type_info_static())};
}
vptr = std::static_pointer_cast<typename T::element_type>(runtime_attribute);
_runtime_attribute_impl = std::make_shared<Impl<decay_t<T>>>(vptr);
return _runtime_attribute_impl->as<T>();
_temp_impl = std::make_shared<Impl<decay_t<T>>>(vptr);
return _temp_impl->as<T>();
}
}
}
@ -521,8 +529,8 @@ public:
template <class T>
typename std::enable_if<std::is_convertible<T, std::shared_ptr<RuntimeAttribute>>::value, T>::type& as() & {
if (_impl == nullptr) {
_runtime_attribute_impl = std::make_shared<Impl<decay_t<T>>>(T{});
return _runtime_attribute_impl->as<T>();
_temp_impl = std::make_shared<Impl<decay_t<T>>>(T{});
return _temp_impl->as<T>();
} else {
if (_impl->type_info() == typeid(decay_t<T>)) {
return *static_cast<decay_t<T>*>(_impl->addressof());
@ -542,8 +550,8 @@ public:
static_cast<std::string>(T::element_type::get_type_info_static())};
}
vptr = std::static_pointer_cast<typename T::element_type>(runtime_attribute);
_runtime_attribute_impl = std::make_shared<Impl<decay_t<T>>>(vptr);
return _runtime_attribute_impl->as<T>();
_temp_impl = std::make_shared<Impl<decay_t<T>>>(vptr);
return _temp_impl->as<T>();
}
}
}
@ -557,8 +565,8 @@ public:
const typename std::enable_if<std::is_convertible<T, std::shared_ptr<RuntimeAttribute>>::value, T>::type& as()
const& {
if (_impl == nullptr) {
_runtime_attribute_impl = std::make_shared<Impl<decay_t<T>>>(T{});
return _runtime_attribute_impl->as<T>();
_temp_impl = std::make_shared<Impl<decay_t<T>>>(T{});
return _temp_impl->as<T>();
} else {
if (_impl->type_info() == typeid(decay_t<T>)) {
return *static_cast<const decay_t<T>*>(_impl->addressof());
@ -578,8 +586,8 @@ public:
static_cast<std::string>(T::element_type::get_type_info_static())};
}
vptr = std::static_pointer_cast<typename T::element_type>(runtime_attribute);
_runtime_attribute_impl = std::make_shared<Impl<decay_t<T>>>(vptr);
return _runtime_attribute_impl->as<T>();
_temp_impl = std::make_shared<Impl<decay_t<T>>>(vptr);
return _temp_impl->as<T>();
}
}
}
@ -590,7 +598,85 @@ public:
* @return casted object
*/
template <typename T>
typename std::enable_if<!std::is_convertible<T, std::shared_ptr<RuntimeAttribute>>::value, T>::type&& as() && {
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,
T>::type&&
as() && {
impl_check();
if (_impl->type_info() == typeid(std::string)) {
_temp_impl = std::make_shared<Impl<decay_t<T>>>();
std::stringstream strm{as<std::string>()};
_temp_impl->read(strm);
return std::move(*static_cast<decay_t<T>*>(_temp_impl->addressof()));
}
_impl->type_check(typeid(decay_t<T>));
return std::move(*static_cast<decay_t<T>*>(_impl->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,
T>::type&
as() & {
impl_check();
if (_impl->type_info() == typeid(decay_t<T>)) {
return *static_cast<decay_t<T>*>(_impl->addressof());
} else if (_impl->type_info() == typeid(std::string)) {
_temp_impl = std::make_shared<Impl<decay_t<T>>>();
std::stringstream strm{as<std::string>()};
_temp_impl->read(strm);
return *static_cast<decay_t<T>*>(_temp_impl->addressof());
}
for (const auto& type_index : _impl->base_type_info()) {
if (type_index == typeid(decay_t<T>)) {
return *static_cast<decay_t<T>*>(_impl->addressof());
}
}
throw ov::Exception{std::string{"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>
const 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,
T>::type&
as() const& {
impl_check();
if (_impl->type_info() == typeid(decay_t<T>)) {
return *static_cast<const decay_t<T>*>(_impl->addressof());
} else if (_impl->type_info() == typeid(std::string)) {
_temp_impl = std::make_shared<Impl<decay_t<T>>>();
std::stringstream strm{as<std::string>()};
_temp_impl->read(strm);
return *static_cast<const decay_t<T>*>(_temp_impl->addressof());
}
for (const auto& type_index : _impl->base_type_info()) {
if (type_index == typeid(decay_t<T>)) {
return *static_cast<const decay_t<T>*>(_impl->addressof());
}
}
throw ov::Exception{std::string{"Bad cast from: "} + _impl->type_info().name() + " to: " + typeid(T).name()};
}
/**
* Dynamic cast to specified type
* @tparam T type
* @return casted object
*/
template <typename 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,
T>::type&&
as() && {
impl_check();
_impl->type_check(typeid(decay_t<T>));
return std::move(*static_cast<decay_t<T>*>(_impl->addressof()));
@ -602,7 +688,10 @@ public:
* @return casted object
*/
template <class T>
typename std::enable_if<!std::is_convertible<T, std::shared_ptr<RuntimeAttribute>>::value, T>::type& as() & {
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,
T>::type&
as() & {
impl_check();
if (_impl->type_info() == typeid(decay_t<T>)) {
return *static_cast<decay_t<T>*>(_impl->addressof());
@ -621,8 +710,10 @@ public:
* @return casted object
*/
template <class T>
const typename std::enable_if<!std::is_convertible<T, std::shared_ptr<RuntimeAttribute>>::value, T>::type& as()
const& {
const 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,
T>::type&
as() const& {
impl_check();
if (_impl->type_info() == typeid(decay_t<T>)) {
return *static_cast<const decay_t<T>*>(_impl->addressof());
@ -635,6 +726,60 @@ public:
throw ov::Exception{std::string{"Bad cast from: "} + _impl->type_info().name() + " to: " + typeid(T).name()};
}
/**
* Dynamic cast to specified type
* @tparam T type
* @return casted object
*/
template <typename T>
typename std::enable_if<std::is_same<T, std::string>::value, T>::type&& as() && {
impl_check();
if (_impl->type_info() == typeid(decay_t<T>)) {
return std::move(*static_cast<decay_t<T>*>(_impl->addressof()));
} else {
std::stringstream strm;
print(strm);
_str = strm.str();
return std::move(_str);
}
}
/**
* Dynamic cast to specified type
* @tparam T type
* @return casted object
*/
template <class T>
typename std::enable_if<std::is_same<T, std::string>::value, T>::type& as() & {
impl_check();
if (_impl->type_info() == typeid(decay_t<T>)) {
return *static_cast<decay_t<T>*>(_impl->addressof());
} else {
std::stringstream strm;
print(strm);
_str = strm.str();
return _str;
}
}
/**
* Dynamic cast to specified type
* @tparam T type
* @return casted object
*/
template <class T>
const typename std::enable_if<std::is_same<T, std::string>::value, T>::type& as() const& {
impl_check();
if (_impl->type_info() == typeid(decay_t<T>)) {
return *static_cast<const decay_t<T>*>(_impl->addressof());
} else {
std::stringstream strm;
print(strm);
_str = strm.str();
return _str;
}
}
/**
* @brief Converts to specified type
* @tparam T type
@ -802,4 +947,4 @@ std::shared_ptr<T> static_pointer_cast(const ::ov::Any& any) {
return any.as<std::shared_ptr<T>>();
}
} // namespace std
} // namespace std

View File

@ -4,6 +4,8 @@
#include "openvino/core/any.hpp"
#include <string>
namespace ov {
void Any::Base::type_check(const std::type_info& type_info_) const {
@ -41,7 +43,7 @@ bool Any::Base::visit_attributes(AttributeVisitor& visitor) const {
}
Any::~Any() {
_runtime_attribute_impl = {};
_temp_impl = {};
_impl = {};
}
@ -52,7 +54,9 @@ Any::Any(const char* str) : Any(std::string{str}) {}
Any::Any(const std::nullptr_t) : Any() {}
void Any::impl_check() const {
OPENVINO_ASSERT(_impl != nullptr, "Any was not initialized.");
if (_impl == nullptr) {
OPENVINO_UNREACHABLE("Any was not initialized.");
}
}
const std::type_info& Any::type_info() const {
@ -101,4 +105,85 @@ Any::Base* Any::operator->() {
const Any::Base* Any::operator->() const {
return _impl.get();
}
void Any::read_impl(std::istream& is, bool& value) {
std::string str;
is >> str;
if (str == "YES") {
value = true;
} else if (str == "NO") {
value = false;
} else {
OPENVINO_UNREACHABLE("Could not convert to bool from string " + str);
}
}
template <typename F>
static auto stream_to(std::istream& is, F&& f) -> decltype(f(std::declval<const std::string&>())) {
std::string str;
is >> str;
try {
return f(str);
} catch (std::exception& e) {
OPENVINO_UNREACHABLE(std::string{"Could not convert to: "} +
typeid(decltype(f(std::declval<const std::string&>()))).name() + " from string " + str +
": " + e.what());
}
}
void Any::read_impl(std::istream& is, int& value) {
value = stream_to(is, [](const std::string& str) {
return std::stoi(str);
});
}
void Any::read_impl(std::istream& is, long& value) {
value = stream_to(is, [](const std::string& str) {
return std::stol(str);
});
}
void Any::read_impl(std::istream& is, long long& value) {
value = stream_to(is, [](const std::string& str) {
return std::stoll(str);
});
}
void Any::read_impl(std::istream& is, unsigned& value) {
value = stream_to(is, [](const std::string& str) {
auto ul = std::stoul(str);
if (ul > std::numeric_limits<unsigned>::max()) {
throw std::out_of_range{"Out of range"};
}
return static_cast<unsigned>(ul);
});
}
void Any::read_impl(std::istream& is, unsigned long& value) {
value = stream_to(is, [](const std::string& str) {
return std::stoul(str);
});
}
void Any::read_impl(std::istream& is, unsigned long long& value) {
value = stream_to(is, [](const std::string& str) {
return std::stoull(str);
});
}
void Any::read_impl(std::istream& is, float& value) {
value = stream_to(is, [](const std::string& str) {
return std::stof(str);
});
}
void Any::read_impl(std::istream& is, double& value) {
value = stream_to(is, [](const std::string& str) {
return std::stod(str);
});
}
void Any::read_impl(std::istream& is, long double& value) {
value = stream_to(is, [](const std::string& str) {
return std::stold(str);
});
}
void Any::print_impl(std::ostream& os, const bool& b) {
os << (b ? "YES" : "NO");
}
} // namespace ov

View File

@ -133,20 +133,6 @@ TEST_F(AnyTests, AnyAsStringInLine) {
ASSERT_EQ("test", test);
}
TEST_F(AnyTests, IntAnyAsString) {
Any p = 4;
ASSERT_TRUE(p.is<int>());
ASSERT_FALSE(p.is<std::string>());
ASSERT_THROW(std::string test = p.as<std::string>(), ov::Exception);
}
TEST_F(AnyTests, StringAnyAsInt) {
Any p = "4";
ASSERT_FALSE(p.is<int>());
ASSERT_TRUE(p.is<std::string>());
ASSERT_THROW((void)p.as<int>(), ov::Exception);
}
TEST_F(AnyTests, AnyAsInts) {
std::vector<int> ref = {1, 2, 3, 4, 5};
Any p = ref;
@ -511,3 +497,52 @@ TEST_F(AnyTests, accessUsingWrongBaseReference) {
ASSERT_NO_THROW(p.as<WrongDerived>());
ASSERT_THROW(p.as<WrongBase>(), ov::Exception);
}
TEST_F(AnyTests, ToString) {
Any p = 42;
ASSERT_TRUE(p.is<int>());
ASSERT_EQ("42", p.as<std::string>());
}
TEST_F(AnyTests, FromString) {
Any p = "42";
ASSERT_TRUE(p.is<std::string>());
ASSERT_EQ(42, p.as<int>());
}
TEST_F(AnyTests, BoolToString) {
{
Any p = true;
ASSERT_TRUE(p.is<bool>());
ASSERT_EQ("YES", p.as<std::string>());
}
{
Any p = false;
ASSERT_TRUE(p.is<bool>());
ASSERT_EQ("NO", p.as<std::string>());
}
}
TEST_F(AnyTests, BoolFromString) {
{
Any p = "YES";
ASSERT_TRUE(p.is<std::string>());
ASSERT_EQ(true, p.as<bool>());
}
{
Any p = "NO";
ASSERT_TRUE(p.is<std::string>());
ASSERT_EQ(false, p.as<bool>());
}
{
Any p = "Some";
ASSERT_TRUE(p.is<std::string>());
ASSERT_THROW(p.as<bool>(), ov::Exception);
}
}
TEST_F(AnyTests, NotIntFromStringThrow) {
Any p = "not42";
ASSERT_TRUE(p.is<std::string>());
ASSERT_THROW(p.as<int>(), ov::Exception);
}