#ifndef GRAPH_UTILS_ATTRIBUTE_VALUE_HPP
#define GRAPH_UTILS_ATTRIBUTE_VALUE_HPP
#include <memory>
#include <stdexcept>
#include <string>
#include <utility>
#include <vector>
#include "graph/interface/c_types_map.hpp"
#include "graph/utils/json.hpp"
namespace dnnl {
namespace impl {
namespace graph {
namespace dnnl_impl {
class fusion_info_t;
} } } }
namespace dnnl {
namespace impl {
namespace graph {
namespace utils {
template <typename value_type>
struct attribute_value_traits_t;
template <>
struct attribute_value_traits_t<int64_t> {
static attribute_kind_t constexpr kind = attribute_kind::i;
};
template <>
struct attribute_value_traits_t<std::vector<int64_t>> {
static attribute_kind_t constexpr kind = attribute_kind::is;
};
template <>
struct attribute_value_traits_t<float> {
static attribute_kind_t constexpr kind = attribute_kind::f;
};
template <>
struct attribute_value_traits_t<std::vector<float>> {
static attribute_kind_t constexpr kind = attribute_kind::fs;
};
template <>
struct attribute_value_traits_t<std::string> {
static attribute_kind_t constexpr kind = attribute_kind::s;
};
template <>
struct attribute_value_traits_t<bool> {
static attribute_kind_t constexpr kind = attribute_kind::b;
};
template <>
struct attribute_value_traits_t<dnnl::impl::graph::dnnl_impl::fusion_info_t> {
static attribute_kind_t constexpr kind = attribute_kind::fusion_info;
};
template <typename value_type>
using base_value_type = typename std::remove_cv<
typename std::remove_reference<value_type>::type>::type;
template <typename value_type>
constexpr attribute_kind_t get_attribute_kind() {
static_assert(std::is_same<float, value_type>::value
|| std::is_same<int64_t, value_type>::value
|| std::is_same<std::vector<float>, value_type>::value
|| std::is_same<std::vector<int64_t>, value_type>::value
|| std::is_same<std::string, value_type>::value
|| std::is_same<bool, value_type>::value
|| std::is_same<dnnl::impl::graph::dnnl_impl::fusion_info_t,
value_type>::value,
"value_type should be one of int64_t, float, string, "
"bool, vector<float>, vector<int64_t> or fusion_info_t class "
"type.");
return attribute_value_traits_t<base_value_type<value_type>>::kind;
}
template <typename value_type>
class attribute_value_cell_imp_t;
class attribute_value_cell_t {
protected:
template <typename value_type>
using imp_class = attribute_value_cell_imp_t<base_value_type<value_type>>;
public:
virtual ~attribute_value_cell_t() = default;
virtual attribute_kind_t get_kind() const = 0;
virtual std::unique_ptr<attribute_value_cell_t> duplicate() const = 0;
virtual bool operator==(const attribute_value_cell_t &other) const = 0;
template <typename value_type>
attribute_value_cell_t &operator=(value_type &&value) {
if (get_kind() == get_attribute_kind<value_type>()) {
static_cast<imp_class<value_type> &>(*this).set(
std::forward<value_type>(value));
return *this;
} else {
throw std::runtime_error(
"Attempt to set attribute to invalid type.\n");
}
}
template <typename value_type>
value_type &get() {
if (get_kind() == get_attribute_kind<value_type>()) {
return static_cast<imp_class<value_type> &>(*this).get();
} else {
throw std::runtime_error(
"Attempt to get attribute using invalid type.\n");
}
}
template <typename value_type>
const value_type &get() const {
if (get_kind() == get_attribute_kind<value_type>()) {
return static_cast<imp_class<value_type> &>(*this).get();
} else {
throw std::runtime_error(
"Attempt to get attribute using invalid type.\n");
}
}
};
template <typename value_type>
class attribute_value_cell_imp_t : public attribute_value_cell_t {
public:
attribute_value_cell_imp_t(const value_type &value) : value_(value) {}
attribute_value_cell_imp_t(value_type &&value) : value_(std::move(value)) {}
attribute_kind_t get_kind() const override {
return get_attribute_kind<value_type>();
}
std::unique_ptr<attribute_value_cell_t> duplicate() const override {
return std::unique_ptr<attribute_value_cell_t>(
new attribute_value_cell_imp_t<value_type>(value_));
}
bool operator==(const attribute_value_cell_t &other) const override {
return (other.get_kind() == get_kind())
&& static_cast<const attribute_value_cell_imp_t<value_type> &>(
other)
.value_
== value_;
}
void set(const value_type &value) { value_ = value; }
void set(value_type &&value) { value_ = std::move(value); }
value_type &get() { return value_; }
const value_type &get() const { return value_; }
protected:
value_type value_;
};
class attribute_value_t {
public:
attribute_value_t() = default;
template <typename value_type>
attribute_value_t(const value_type &value)
: value_cell_(new attribute_value_cell_imp_t<value_type>(value)) {}
attribute_value_t(attribute_value_t &&orig)
: value_cell_(std::move(orig.value_cell_)) {}
attribute_value_t(const attribute_value_t &orig) {
if (orig.value_cell_) {
this->value_cell_ = orig.value_cell_->duplicate();
}
}
status_t save(dnnl::impl::graph::utils::json::json_writer_t *writer) const {
writer->begin_object();
if (check_type<bool>()) {
writer->write_keyvalue("type", std::string("bool"));
writer->write_keyvalue("value", get<bool>());
} else if (check_type<int64_t>()) {
writer->write_keyvalue("type", std::string("s64"));
writer->write_keyvalue("value", get<int64_t>());
} else if (check_type<float>()) {
writer->write_keyvalue("type", std::string("f32"));
writer->write_keyvalue("value", get<float>());
} else if (check_type<std::vector<float>>()) {
writer->write_keyvalue("type", std::string("f32[]"));
writer->write_keyvalue("value", get<std::vector<float>>());
} else if (check_type<std::vector<int64_t>>()) {
writer->write_keyvalue("type", std::string("s64[]"));
writer->write_keyvalue("value", get<std::vector<int64_t>>());
} else if (check_type<std::string>()) {
writer->write_keyvalue("type", std::string("string"));
writer->write_keyvalue("value", get<std::string>());
} else {
}
writer->end_object();
return graph::status::success;
}
template <typename value_type>
attribute_value_t &operator=(value_type &&value) {
*value_cell_ = std::forward<value_type>(value);
return *this;
}
attribute_value_t &operator=(attribute_value_t &&orig) {
value_cell_ = std::move(orig.value_cell_);
return *this;
}
attribute_value_t &operator=(const attribute_value_t &orig) {
if (&orig != this && orig.value_cell_) {
this->value_cell_ = orig.value_cell_->duplicate();
}
return *this;
}
bool operator==(const attribute_value_t &value) const {
return *value_cell_ == *value.value_cell_;
}
bool operator!=(const attribute_value_t &value) const {
return !operator==(value);
}
attribute_kind_t get_kind() const { return value_cell_->get_kind(); }
template <typename value_type>
bool check_type() const {
return value_cell_->get_kind() == get_attribute_kind<value_type>();
}
template <typename value_type>
value_type &get() const {
return value_cell_->get<value_type>();
}
private:
std::unique_ptr<attribute_value_cell_t> value_cell_;
};
inline std::ostream &operator<<(
std::ostream &ss, const attribute_value_t &val) {
switch (val.get_kind()) {
case attribute_kind::i: ss << val.get<int64_t>(); break;
case attribute_kind::is: {
const auto &vec = val.get<std::vector<int64_t>>();
ss << "[";
for (size_t i = 0; i < vec.size(); ++i) {
ss << vec[i];
if (i != vec.size() - 1) ss << ", ";
}
ss << "]";
break;
}
case attribute_kind::f: ss << val.get<float>(); break;
case attribute_kind::fs: {
const auto &vec = val.get<std::vector<float>>();
ss << "[";
for (size_t i = 0; i < vec.size(); ++i) {
ss << vec[i];
if (i != vec.size() - 1) ss << ", ";
}
ss << "]";
break;
}
case attribute_kind::s: ss << val.get<std::string>(); break;
case attribute_kind::b:
ss << (val.get<bool>() ? "true" : "false");
break;
default: ss << "unknown attribute type";
}
return ss;
}
} } } }
#endif