flex/engines/graph_db/runtime/common/rt_any.h (1,036 lines of code) (raw):
/** Copyright 2020 Alibaba Group Holding Limited.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef RUNTIME_COMMON_RT_ANY_H_
#define RUNTIME_COMMON_RT_ANY_H_
#include "flex/proto_generated_gie/results.pb.h"
#include "flex/proto_generated_gie/type.pb.h"
#include "flex/engines/graph_db/runtime/common/graph_interface.h"
#include "flex/engines/graph_db/runtime/common/types.h"
#include "flex/utils/app_utils.h"
namespace gs {
namespace runtime {
class CObject {
public:
virtual ~CObject() = default;
};
using Arena = std::vector<std::unique_ptr<CObject>>;
struct ArenaRef : public CObject {
ArenaRef(const std::shared_ptr<Arena>& arena) : arena_(arena) {}
std::shared_ptr<Arena> arena_;
};
class VertexRecord {
public:
bool operator<(const VertexRecord& v) const {
if (label_ == v.label_) {
return vid_ < v.vid_;
} else {
return label_ < v.label_;
}
}
bool operator==(const VertexRecord& v) const {
return label_ == v.label_ && vid_ == v.vid_;
}
label_t label() const { return label_; }
vid_t vid() const { return vid_; }
label_t label_;
vid_t vid_;
};
struct VertexRecordHash {
std::size_t operator()(const VertexRecord& v) const {
return std::hash<vid_t>()(v.vid_) ^ std::hash<label_t>()(v.label_);
}
std::size_t operator()(const std::pair<VertexRecord, VertexRecord>& v) const {
return std::hash<vid_t>()(v.first.vid_) ^
std::hash<label_t>()(v.first.label_) ^
std::hash<vid_t>()(v.second.vid_) ^
std::hash<label_t>()(v.second.label_);
}
};
struct Relation {
label_t label;
vid_t src;
vid_t dst;
bool operator<(const Relation& r) const {
return std::tie(label, src, dst) < std::tie(r.label, r.src, r.dst);
}
bool operator==(const Relation& r) const {
return std::tie(label, src, dst) == std::tie(r.label, r.src, r.dst);
}
VertexRecord start_node() const { return {label, src}; }
VertexRecord end_node() const { return {label, dst}; }
};
class PathImpl : public CObject {
public:
static std::unique_ptr<PathImpl> make_path_impl(label_t label, vid_t v) {
auto new_path = std::make_unique<PathImpl>();
new_path->path_.push_back({label, v});
return new_path;
}
static std::unique_ptr<PathImpl> make_path_impl(
label_t label, label_t edge_label, std::vector<vid_t>& path_ids) {
auto new_path = std::make_unique<PathImpl>();
for (auto id : path_ids) {
new_path->path_.push_back({label, id});
}
new_path->edge_labels_.push_back(edge_label);
return new_path;
}
static std::unique_ptr<PathImpl> make_path_impl(
const std::vector<label_t>& edge_labels,
const std::vector<VertexRecord>& path) {
auto new_path = std::make_unique<PathImpl>();
new_path->path_ = path;
new_path->edge_labels_ = edge_labels;
return new_path;
}
std::unique_ptr<PathImpl> expand(label_t edge_label, label_t label,
vid_t v) const {
auto new_path = std::make_unique<PathImpl>();
new_path->path_ = path_;
new_path->edge_labels_.emplace_back(edge_label);
new_path->path_.push_back({label, v});
return new_path;
}
std::string to_string() const {
std::string str;
for (size_t i = 0; i < path_.size(); ++i) {
str += "(" + std::to_string(static_cast<int>(path_[i].label_)) + ", " +
std::to_string(path_[i].vid_) + ")";
if (i != path_.size() - 1) {
str += "->";
}
}
return str;
}
VertexRecord get_end() const { return path_.back(); }
VertexRecord get_start() const { return path_.front(); }
bool operator<(const PathImpl& p) const { return path_ < p.path_; }
bool operator==(const PathImpl& p) const { return path_ == p.path_; }
std::vector<VertexRecord> path_;
std::vector<label_t> edge_labels_;
};
class Path {
public:
Path() = default;
Path(PathImpl* impl) : impl_(impl) {}
std::string to_string() const { return impl_->to_string(); }
int32_t len() const { return impl_->path_.size(); }
VertexRecord get_end() const { return impl_->get_end(); }
std::vector<Relation> relationships() const {
std::vector<Relation> relations;
for (size_t i = 0; i < impl_->path_.size() - 1; ++i) {
Relation r;
r.label = impl_->path_[i].label_;
r.src = impl_->path_[i].vid_;
r.dst = impl_->path_[i + 1].vid_;
relations.push_back(r);
}
return relations;
}
std::vector<VertexRecord> nodes() { return impl_->path_; }
std::vector<label_t> edge_labels() const { return impl_->edge_labels_; }
VertexRecord get_start() const { return impl_->get_start(); }
bool operator<(const Path& p) const { return *impl_ < *(p.impl_); }
bool operator==(const Path& p) const { return *(impl_) == *(p.impl_); }
PathImpl* impl_;
};
class RTAny;
enum class RTAnyType;
class ListImplBase : public CObject {
public:
virtual ~ListImplBase() = default;
virtual bool operator<(const ListImplBase& p) const = 0;
virtual bool operator==(const ListImplBase& p) const = 0;
virtual size_t size() const = 0;
virtual RTAnyType type() const = 0;
virtual RTAny get(size_t idx) const = 0;
};
template <typename T>
class ListImpl;
class List {
public:
List() = default;
List(ListImplBase* impl) : impl_(impl) {}
bool operator<(const List& p) const { return *impl_ < *(p.impl_); }
bool operator==(const List& p) const { return *(impl_) == *(p.impl_); }
size_t size() const { return impl_->size(); }
RTAny get(size_t idx) const;
RTAnyType elem_type() const;
ListImplBase* impl_;
};
class SetImplBase : public CObject {
public:
virtual ~SetImplBase() = default;
virtual bool operator<(const SetImplBase& p) const = 0;
virtual bool operator==(const SetImplBase& p) const = 0;
virtual size_t size() const = 0;
virtual std::vector<RTAny> values() const = 0;
virtual void insert(const RTAny& val) = 0;
virtual bool exists(const RTAny& val) const = 0;
virtual RTAnyType type() const = 0;
};
template <typename T>
class SetImpl;
class Set {
public:
Set() = default;
Set(SetImplBase* impl) : impl_(impl) {}
void insert(const RTAny& val) { impl_->insert(val); }
bool operator<(const Set& p) const { return *impl_ < *(p.impl_); }
bool operator==(const Set& p) const { return *(impl_) == *(p.impl_); }
bool exists(const RTAny& val) const { return impl_->exists(val); }
std::vector<RTAny> values() const { return impl_->values(); }
RTAnyType elem_type() const;
size_t size() const { return impl_->size(); }
SetImplBase* impl_;
};
class TupleImplBase : public CObject {
public:
virtual ~TupleImplBase() = default;
virtual bool operator<(const TupleImplBase& p) const = 0;
virtual bool operator==(const TupleImplBase& p) const = 0;
virtual size_t size() const = 0;
virtual RTAny get(size_t idx) const = 0;
};
template <typename... Args>
class TupleImpl : public TupleImplBase {
public:
TupleImpl() = default;
~TupleImpl() = default;
TupleImpl(Args&&... args) : values(std::forward<Args>(args)...) {}
TupleImpl(std::tuple<Args...>&& args) : values(std::move(args)) {}
bool operator<(const TupleImplBase& p) const override {
return values < dynamic_cast<const TupleImpl<Args...>&>(p).values;
}
bool operator==(const TupleImplBase& p) const override {
return values == dynamic_cast<const TupleImpl<Args...>&>(p).values;
}
RTAny get(size_t idx) const override;
size_t size() const override {
return std::tuple_size_v<std::tuple<Args...>>;
}
std::tuple<Args...> values;
};
template <>
class TupleImpl<RTAny> : public TupleImplBase {
public:
TupleImpl() = default;
~TupleImpl() = default;
TupleImpl(std::vector<RTAny>&& val) : values(std::move(val)) {}
bool operator<(const TupleImplBase& p) const override {
return values < dynamic_cast<const TupleImpl<RTAny>&>(p).values;
}
bool operator==(const TupleImplBase& p) const override {
return values == dynamic_cast<const TupleImpl<RTAny>&>(p).values;
}
size_t size() const override { return values.size(); }
RTAny get(size_t idx) const override;
std::vector<RTAny> values;
};
class Tuple {
public:
template <typename... Args>
static std::unique_ptr<TupleImplBase> make_tuple_impl(
std::tuple<Args...>&& args) {
return std::make_unique<TupleImpl<Args...>>(std::move(args));
}
static std::unique_ptr<TupleImplBase> make_generic_tuple_impl(
std::vector<RTAny>&& args) {
return std::make_unique<TupleImpl<RTAny>>(std::move(args));
}
Tuple() = default;
Tuple(TupleImplBase* impl) : impl_(impl) {}
bool operator<(const Tuple& p) const { return *impl_ < *(p.impl_); }
bool operator==(const Tuple& p) const { return *impl_ == *(p.impl_); }
size_t size() const { return impl_->size(); }
RTAny get(size_t idx) const;
TupleImplBase* impl_;
};
class MapImpl : public CObject {
public:
static std::unique_ptr<MapImpl> make_map_impl(
const std::vector<RTAny>& keys, const std::vector<RTAny>& values) {
auto new_map = std::make_unique<MapImpl>();
new_map->keys = keys;
new_map->values = values;
return new_map;
}
size_t size() const { return keys.size(); }
bool operator<(const MapImpl& p) const {
return std::tie(keys, values) < std::tie(p.keys, p.values);
}
bool operator==(const MapImpl& p) const {
return std::tie(keys, values) == std::tie(p.keys, p.values);
}
std::vector<RTAny> keys;
std::vector<RTAny> values;
};
class StringImpl : public CObject {
public:
std::string_view str_view() const {
return std::string_view(str.data(), str.size());
}
static std::unique_ptr<StringImpl> make_string_impl(const std::string& str) {
auto new_str = std::make_unique<StringImpl>();
new_str->str = str;
return new_str;
}
std::string str;
};
enum class RTAnyType {
kVertex,
kEdge,
kI64Value,
kU64Value,
kI32Value,
kF64Value,
kBoolValue,
kStringValue,
kUnknown,
kDate32,
kTimestamp,
kPath,
kNull,
kTuple,
kList,
kMap,
kRelation,
kSet,
kEmpty,
kRecordView,
};
PropertyType rt_type_to_property_type(RTAnyType type);
class Map {
public:
static Map make_map(MapImpl* impl) {
Map m;
m.map_ = impl;
return m;
}
std::pair<const std::vector<RTAny>, const std::vector<RTAny>> key_vals()
const {
return std::make_pair(map_->keys, map_->values);
}
bool operator<(const Map& p) const { return *map_ < *(p.map_); }
bool operator==(const Map& p) const { return *map_ == *(p.map_); }
MapImpl* map_;
};
struct pod_string_view {
const char* data_;
size_t size_;
pod_string_view() = default;
pod_string_view(const pod_string_view& other) = default;
pod_string_view(const char* data) : data_(data), size_(strlen(data_)) {}
pod_string_view(const char* data, size_t size) : data_(data), size_(size) {}
pod_string_view(const std::string& str)
: data_(str.data()), size_(str.size()) {}
pod_string_view(const std::string_view& str)
: data_(str.data()), size_(str.size()) {}
const char* data() const { return data_; }
size_t size() const { return size_; }
std::string to_string() const { return std::string(data_, size_); }
};
// only for pod type
struct EdgeData {
// PropertyType type;
template <typename T>
T as() const {
if constexpr (std::is_same_v<T, int32_t>) {
return value.i32_val;
} else if constexpr (std::is_same_v<T, int64_t>) {
return value.i64_val;
} else if constexpr (std::is_same_v<T, uint64_t>) {
return value.u64_val;
} else if constexpr (std::is_same_v<T, double>) {
return value.f64_val;
} else if constexpr (std::is_same_v<T, bool>) {
return value.b_val;
} else if constexpr (std::is_same_v<T, std::string_view>) {
return std::string_view(value.str_val.data(), value.str_val.size());
} else if constexpr (std::is_same_v<T, grape::EmptyType>) {
return grape::EmptyType();
} else if constexpr (std::is_same_v<T, Date>) {
return Date(value.i64_val);
} else if constexpr (std::is_same_v<T, RecordView>) {
return value.record_view;
} else {
LOG(FATAL) << "not support for " << typeid(T).name();
}
}
template <typename T>
explicit EdgeData(T val) {
if constexpr (std::is_same_v<T, int32_t>) {
type = RTAnyType::kI32Value;
value.i32_val = val;
} else if constexpr (std::is_same_v<T, int64_t>) {
type = RTAnyType::kI64Value;
value.i64_val = val;
} else if constexpr (std::is_same_v<T, uint64_t>) {
type = RTAnyType::kU64Value;
value.u64_val = val;
} else if constexpr (std::is_same_v<T, double>) {
type = RTAnyType::kF64Value;
value.f64_val = val;
} else if constexpr (std::is_same_v<T, bool>) {
type = RTAnyType::kBoolValue;
value.b_val = val;
} else if constexpr (std::is_same_v<T, std::string_view>) {
type = RTAnyType::kStringValue;
value.str_val = val;
} else if constexpr (std::is_same_v<T, grape::EmptyType>) {
type = RTAnyType::kEmpty;
} else if constexpr (std::is_same_v<T, Date>) {
type = RTAnyType::kTimestamp;
value.date_val = val;
} else if constexpr (std::is_same_v<T, RecordView>) {
type = RTAnyType::kRecordView;
value.record_view = val;
} else {
LOG(FATAL) << "not support for " << typeid(T).name();
}
}
std::string to_string() const {
if (type == RTAnyType::kI32Value) {
return std::to_string(value.i32_val);
} else if (type == RTAnyType::kI64Value) {
return std::to_string(value.i64_val);
} else if (type == RTAnyType::kStringValue) {
return std::string(value.str_val.data(), value.str_val.size());
return value.str_val.to_string();
} else if (type == RTAnyType::kNull) {
return "NULL";
} else if (type == RTAnyType::kF64Value) {
return std::to_string(value.f64_val);
} else if (type == RTAnyType::kBoolValue) {
return value.b_val ? "true" : "false";
} else if (type == RTAnyType::kDate32) {
return value.day_val.to_string();
} else if (type == RTAnyType::kTimestamp) {
return std::to_string(value.date_val.milli_second);
} else if (type == RTAnyType::kEmpty) {
return "";
} else if (type == RTAnyType::kRecordView) {
return value.record_view.to_string();
} else {
LOG(FATAL) << "Unexpected property type: " << static_cast<int>(type);
return "";
}
}
EdgeData() = default;
EdgeData(const Any& any) {
switch (any.type.type_enum) {
case impl::PropertyTypeImpl::kInt64:
type = RTAnyType::kI64Value;
value.i64_val = any.value.l;
break;
case impl::PropertyTypeImpl::kInt32:
type = RTAnyType::kI32Value;
value.i32_val = any.value.i;
break;
case impl::PropertyTypeImpl::kStringView:
type = RTAnyType::kStringValue;
value.str_val = any.value.s;
break;
case impl::PropertyTypeImpl::kDouble:
type = RTAnyType::kF64Value;
value.f64_val = any.value.db;
break;
case impl::PropertyTypeImpl::kBool:
type = RTAnyType::kBoolValue;
value.b_val = any.value.b;
break;
case impl::PropertyTypeImpl::kEmpty:
type = RTAnyType::kEmpty;
break;
case impl::PropertyTypeImpl::kDate:
type = RTAnyType::kTimestamp;
value.date_val = any.value.d;
break;
case impl::PropertyTypeImpl::kRecordView:
type = RTAnyType::kRecordView;
value.record_view = any.value.record_view;
break;
default:
LOG(FATAL) << "Unexpected property type: "
<< static_cast<int>(any.type.type_enum);
}
}
bool operator<(const EdgeData& e) const {
if (type == RTAnyType::kI64Value) {
return value.i64_val < e.value.i64_val;
} else if (type == RTAnyType::kI32Value) {
return value.i32_val < e.value.i32_val;
} else if (type == RTAnyType::kF64Value) {
return value.f64_val < e.value.f64_val;
} else if (type == RTAnyType::kBoolValue) {
return value.b_val < e.value.b_val;
} else if (type == RTAnyType::kStringValue) {
return std::string_view(value.str_val.data(), value.str_val.size()) <
std::string_view(e.value.str_val.data(), e.value.str_val.size());
} else if (type == RTAnyType::kTimestamp) {
return value.date_val < e.value.date_val;
} else {
return false;
}
}
bool operator==(const EdgeData& e) const {
if (type == RTAnyType::kI64Value) {
return value.i64_val == e.value.i64_val;
} else if (type == RTAnyType::kI32Value) {
return value.i32_val == e.value.i32_val;
} else if (type == RTAnyType::kF64Value) {
return value.f64_val == e.value.f64_val;
} else if (type == RTAnyType::kBoolValue) {
return value.b_val == e.value.b_val;
} else if (type == RTAnyType::kStringValue) {
return std::string_view(value.str_val.data(), value.str_val.size()) ==
std::string_view(e.value.str_val.data(), e.value.str_val.size());
} else if (type == RTAnyType::kDate32) {
return value.day_val == e.value.day_val;
} else if (type == RTAnyType::kTimestamp) {
return value.date_val == e.value.date_val;
} else if (type == RTAnyType::kRecordView) {
return value.record_view == e.value.record_view;
} else {
return false;
}
}
RTAnyType type;
union {
int32_t i32_val;
int64_t i64_val;
uint64_t u64_val;
double f64_val;
bool b_val;
pod_string_view str_val;
Date date_val;
Day day_val;
RecordView record_view;
// todo: make recordview as a pod type
// RecordView record;
} value;
};
class EdgeRecord {
public:
bool operator<(const EdgeRecord& e) const {
return std::tie(src_, dst_, label_triplet_, prop_, dir_) <
std::tie(e.src_, e.dst_, e.label_triplet_, prop_, dir_);
}
bool operator==(const EdgeRecord& e) const {
return std::tie(src_, dst_, label_triplet_, prop_, dir_) ==
std::tie(e.src_, e.dst_, e.label_triplet_, prop_, dir_);
}
vid_t src() const { return src_; }
vid_t dst() const { return dst_; }
LabelTriplet label_triplet() const { return label_triplet_; }
EdgeData prop() const { return prop_; }
Direction dir() const { return dir_; }
LabelTriplet label_triplet_;
vid_t src_, dst_;
EdgeData prop_;
Direction dir_;
};
inline RTAnyType parse_from_ir_data_type(const ::common::IrDataType& dt) {
switch (dt.type_case()) {
case ::common::IrDataType::TypeCase::kDataType: {
const ::common::DataType ddt = dt.data_type();
switch (ddt.item_case()) {
case ::common::DataType::kPrimitiveType: {
const ::common::PrimitiveType pt = ddt.primitive_type();
switch (pt) {
case ::common::PrimitiveType::DT_SIGNED_INT32:
return RTAnyType::kI32Value;
case ::common::PrimitiveType::DT_SIGNED_INT64:
return RTAnyType::kI64Value;
case ::common::PrimitiveType::DT_DOUBLE:
return RTAnyType::kF64Value;
case ::common::PrimitiveType::DT_BOOL:
return RTAnyType::kBoolValue;
case ::common::PrimitiveType::DT_ANY:
return RTAnyType::kUnknown;
default:
LOG(FATAL) << "unrecognized primitive type - " << pt;
break;
}
}
case ::common::DataType::kString:
return RTAnyType::kStringValue;
case ::common::DataType::kTemporal: {
if (ddt.temporal().item_case() == ::common::Temporal::kDate32) {
return RTAnyType::kDate32;
} else if (ddt.temporal().item_case() == ::common::Temporal::kTimestamp) {
return RTAnyType::kTimestamp;
} else {
LOG(FATAL) << "unrecognized temporal type - "
<< ddt.temporal().DebugString();
}
}
case ::common::DataType::kArray:
return RTAnyType::kList;
default:
LOG(FATAL) << "unrecognized data type - " << ddt.DebugString();
break;
}
} break;
case ::common::IrDataType::TypeCase::kGraphType: {
const ::common::GraphDataType gdt = dt.graph_type();
switch (gdt.element_opt()) {
case ::common::GraphDataType_GraphElementOpt::
GraphDataType_GraphElementOpt_VERTEX:
return RTAnyType::kVertex;
case ::common::GraphDataType_GraphElementOpt::
GraphDataType_GraphElementOpt_EDGE:
return RTAnyType::kEdge;
default:
LOG(FATAL) << "unrecognized graph data type";
break;
}
} break;
default:
break;
}
return RTAnyType::kUnknown;
}
union RTAnyValue {
// TODO delete it later
RTAnyValue() {}
~RTAnyValue() {}
VertexRecord vertex;
EdgeRecord edge;
Relation relation;
int64_t i64_val;
uint64_t u64_val;
int i32_val;
double f64_val;
Day day;
Date date;
std::string_view str_val;
Path p;
Tuple t;
List list;
Map map;
Set set;
bool b_val;
};
class RTAny {
public:
RTAny();
RTAny(RTAnyType type);
RTAny(const Any& val);
Any to_any() const;
RTAny(const EdgeData& val);
RTAny(const RTAny& rhs);
RTAny(const Path& p);
~RTAny() = default;
bool is_null() const { return type_ == RTAnyType::kNull; }
int numerical_cmp(const RTAny& other) const;
RTAny& operator=(const RTAny& rhs);
static RTAny from_vertex(label_t l, vid_t v);
static RTAny from_vertex(VertexRecord v);
static RTAny from_edge(const EdgeRecord& v);
static RTAny from_relation(const Relation& r);
static RTAny from_bool(bool v);
static RTAny from_int64(int64_t v);
static RTAny from_uint64(uint64_t v);
static RTAny from_int32(int v);
static RTAny from_string(const std::string& str);
static RTAny from_string(const std::string_view& str);
static RTAny from_date32(Day v);
static RTAny from_timestamp(Date v);
static RTAny from_tuple(const Tuple& tuple);
static RTAny from_list(const List& list);
static RTAny from_double(double v);
static RTAny from_map(const Map& m);
static RTAny from_set(const Set& s);
bool as_bool() const;
int as_int32() const;
int64_t as_int64() const;
uint64_t as_uint64() const;
Day as_date32() const;
Date as_timestamp() const;
double as_double() const;
VertexRecord as_vertex() const;
const EdgeRecord& as_edge() const;
std::string_view as_string() const;
Path as_path() const;
Tuple as_tuple() const;
List as_list() const;
Map as_map() const;
Set as_set() const;
Relation as_relation() const;
bool operator<(const RTAny& other) const;
bool operator==(const RTAny& other) const;
RTAny operator+(const RTAny& other) const;
RTAny operator-(const RTAny& other) const;
RTAny operator/(const RTAny& other) const;
RTAny operator%(const RTAny& other) const;
void sink(const GraphReadInterface& graph, int id,
results::Column* column) const;
template <typename GraphInterface>
void sink(const GraphInterface& graph, Encoder& encoder) const {
if (type_ == RTAnyType::kList) {
encoder.put_int(value_.list.size());
for (size_t i = 0; i < value_.list.size(); ++i) {
value_.list.get(i).sink(graph, encoder);
}
} else if (type_ == RTAnyType::kTuple) {
for (size_t i = 0; i < value_.t.size(); ++i) {
value_.t.get(i).sink(graph, encoder);
}
} else if (type_ == RTAnyType::kStringValue) {
encoder.put_string_view(value_.str_val);
} else if (type_ == RTAnyType::kI64Value) {
encoder.put_long(value_.i64_val);
} else if (type_ == RTAnyType::kDate32) {
encoder.put_long(value_.day.to_timestamp());
} else if (type_ == RTAnyType::kTimestamp) {
encoder.put_long(value_.date.milli_second);
} else if (type_ == RTAnyType::kI32Value) {
encoder.put_int(value_.i32_val);
} else if (type_ == RTAnyType::kF64Value) {
int64_t long_value;
std::memcpy(&long_value, &value_.f64_val, sizeof(long_value));
encoder.put_long(long_value);
} else if (type_ == RTAnyType::kBoolValue) {
encoder.put_byte(value_.b_val ? static_cast<uint8_t>(1)
: static_cast<uint8_t>(0));
} else if (type_ == RTAnyType::kSet) {
encoder.put_int(value_.set.size());
auto value = value_.set.values();
for (const auto& val : value) {
val.sink(graph, encoder);
}
} else if (type_ == RTAnyType::kVertex) {
encoder.put_byte(value_.vertex.label_);
encoder.put_int(value_.vertex.vid_);
} else {
LOG(FATAL) << "not support for " << static_cast<int>(type_);
}
}
void encode_sig(RTAnyType type, Encoder& encoder) const;
std::string to_string() const;
RTAnyType type() const;
private:
void sink_impl(common::Value* collection) const;
RTAnyType type_;
RTAnyValue value_;
};
template <typename T>
struct TypedConverter {};
template <>
struct TypedConverter<bool> {
static RTAnyType type() { return RTAnyType::kBoolValue; }
static bool to_typed(const RTAny& val) { return val.as_bool(); }
static RTAny from_typed(bool val) { return RTAny::from_bool(val); }
static const std::string name() { return "bool"; }
};
template <>
struct TypedConverter<int32_t> {
static RTAnyType type() { return RTAnyType::kI32Value; }
static int32_t to_typed(const RTAny& val) { return val.as_int32(); }
static RTAny from_typed(int val) { return RTAny::from_int32(val); }
static const std::string name() { return "int"; }
static int32_t typed_from_string(const std::string& str) {
return std::stoi(str);
}
};
template <>
struct TypedConverter<std::string_view> {
static RTAnyType type() { return RTAnyType::kStringValue; }
static std::string_view to_typed(const RTAny& val) { return val.as_string(); }
static RTAny from_typed(const std::string_view& val) {
return RTAny::from_string(val);
}
static const std::string name() { return "string_view"; }
static std::string_view typed_from_string(const std::string& str) {
return std::string_view(str.data(), str.size());
}
};
template <>
struct TypedConverter<uint64_t> {
static RTAnyType type() { return RTAnyType::kU64Value; }
static uint64_t to_typed(const RTAny& val) { return val.as_uint64(); }
static RTAny from_typed(uint64_t val) { return RTAny::from_uint64(val); }
static const std::string name() { return "uint64"; }
};
template <>
struct TypedConverter<int64_t> {
static RTAnyType type() { return RTAnyType::kI64Value; }
static int64_t to_typed(const RTAny& val) { return val.as_int64(); }
static RTAny from_typed(int64_t val) { return RTAny::from_int64(val); }
static const std::string name() { return "int64"; }
static int64_t typed_from_string(const std::string& str) {
return std::stoll(str);
}
};
template <>
struct TypedConverter<double> {
static RTAnyType type() { return RTAnyType::kF64Value; }
static double to_typed(const RTAny& val) { return val.as_double(); }
static RTAny from_typed(double val) { return RTAny::from_double(val); }
static double typed_from_string(const std::string& str) {
return std::stod(str);
}
static const std::string name() { return "double"; }
};
template <>
struct TypedConverter<Day> {
static RTAnyType type() { return RTAnyType::kDate32; }
static Day to_typed(const RTAny& val) { return val.as_date32(); }
static RTAny from_typed(Day val) { return RTAny::from_date32(val); }
static const std::string name() { return "day"; }
static Day typed_from_string(const std::string& str) {
int64_t val = std::stoll(str);
return Day(val);
}
};
template <>
struct TypedConverter<Date> {
static RTAnyType type() { return RTAnyType::kTimestamp; }
static Date to_typed(const RTAny& val) { return val.as_timestamp(); }
static RTAny from_typed(Date val) { return RTAny::from_timestamp(val); }
static const std::string name() { return "date"; }
static Date typed_from_string(const std::string& str) {
int64_t val = std::stoll(str);
return Date(val);
}
};
template <>
struct TypedConverter<Tuple> {
static RTAnyType type() { return RTAnyType::kTuple; }
static Tuple to_typed(const RTAny& val) { return val.as_tuple(); }
static RTAny from_typed(Tuple val) {
return RTAny::from_tuple(std::move(val));
}
static const std::string name() { return "tuple"; }
};
template <>
struct TypedConverter<Map> {
static RTAnyType type() { return RTAnyType::kMap; }
static Map to_typed(const RTAny& val) { return val.as_map(); }
static RTAny from_typed(Map val) { return RTAny::from_map(val); }
static const std::string name() { return "map"; }
};
template <>
struct TypedConverter<Set> {
static RTAnyType type() { return RTAnyType::kSet; }
static Set to_typed(const RTAny& val) { return val.as_set(); }
static RTAny from_typed(Set val) { return RTAny::from_set(val); }
static const std::string name() { return "set"; }
};
template <>
struct TypedConverter<Relation> {
static RTAnyType type() { return RTAnyType::kRelation; }
static Relation to_typed(const RTAny& val) { return val.as_relation(); }
static RTAny from_typed(const Relation& val) {
return RTAny::from_relation(val);
}
static const std::string name() { return "relation"; }
};
template <>
struct TypedConverter<VertexRecord> {
static RTAnyType type() { return RTAnyType::kVertex; }
static VertexRecord to_typed(const RTAny& val) { return val.as_vertex(); }
static RTAny from_typed(VertexRecord val) { return RTAny::from_vertex(val); }
static const std::string name() { return "vertex"; }
};
template <typename... Args>
RTAny TupleImpl<Args...>::get(size_t idx) const {
if constexpr (sizeof...(Args) == 2) {
if (idx == 0) {
return TypedConverter<std::tuple_element_t<0, std::tuple<Args...>>>::
from_typed(std::get<0>(values));
} else if (idx == 1) {
return TypedConverter<std::tuple_element_t<1, std::tuple<Args...>>>::
from_typed(std::get<1>(values));
} else {
return RTAny(RTAnyType::kNull);
}
} else if constexpr (sizeof...(Args) == 3) {
if (idx == 0) {
return TypedConverter<std::tuple_element_t<0, std::tuple<Args...>>>::
from_typed(std::get<0>(values));
} else if (idx == 1) {
return TypedConverter<std::tuple_element_t<1, std::tuple<Args...>>>::
from_typed(std::get<1>(values));
} else if (idx == 2) {
return TypedConverter<std::tuple_element_t<2, std::tuple<Args...>>>::
from_typed(std::get<2>(values));
} else {
return RTAny(RTAnyType::kNull);
}
} else {
return RTAny(RTAnyType::kNull);
}
}
template <typename T>
class ListImpl : ListImplBase {
public:
ListImpl() = default;
static std::unique_ptr<ListImplBase> make_list_impl(std::vector<T>&& vals) {
auto new_list = new ListImpl<T>();
new_list->list_ = std::move(vals);
new_list->is_valid_.resize(new_list->list_.size(), true);
return std::unique_ptr<ListImplBase>(static_cast<ListImplBase*>(new_list));
}
bool operator<(const ListImplBase& p) const override {
return list_ < (dynamic_cast<const ListImpl<T>&>(p)).list_;
}
bool operator==(const ListImplBase& p) const override {
return list_ == (dynamic_cast<const ListImpl<T>&>(p)).list_;
}
size_t size() const override { return list_.size(); }
RTAnyType type() const override { return TypedConverter<T>::type(); }
RTAny get(size_t idx) const override {
if (is_valid_[idx]) {
return TypedConverter<T>::from_typed(list_[idx]);
} else {
return RTAny(RTAnyType::kNull);
}
}
std::vector<T> list_;
std::vector<bool> is_valid_;
};
template <typename T>
class SetImpl : public SetImplBase {
public:
SetImpl() = default;
~SetImpl() {}
static std::unique_ptr<SetImplBase> make_set_impl(std::set<T>&& vals) {
auto new_set = new SetImpl<T>();
new_set->set_ = std::move(vals);
return std::unique_ptr<SetImplBase>(static_cast<SetImplBase*>(new_set));
}
RTAnyType type() const override { return TypedConverter<T>::type(); }
bool exists(const RTAny& val) const override {
return set_.find(TypedConverter<T>::to_typed(val)) != set_.end();
}
bool exists(const T& val) const { return set_.find(val) != set_.end(); }
bool operator<(const SetImplBase& p) const override {
return set_ < (dynamic_cast<const SetImpl<T>&>(p)).set_;
}
bool operator==(const SetImplBase& p) const override {
return set_ == (dynamic_cast<const SetImpl<T>&>(p)).set_;
}
void insert(const RTAny& val) override {
set_.insert(TypedConverter<T>::to_typed(val));
}
void insert(const T& val) { set_.insert(val); }
size_t size() const override { return set_.size(); }
std::vector<RTAny> values() const override {
std::vector<RTAny> res;
for (const auto& v : set_) {
res.push_back(TypedConverter<T>::from_typed(v));
}
return res;
}
std::set<T> set_;
};
template <>
class SetImpl<VertexRecord> : public SetImplBase {
public:
SetImpl() = default;
~SetImpl() {}
static std::unique_ptr<SetImplBase> make_set_impl(
std::set<VertexRecord>&& vals) {
auto new_set = new SetImpl<VertexRecord>();
for (auto& v : vals) {
new_set->set_.insert((1ll * v.vid_) << 8 | v.label_);
}
return std::unique_ptr<SetImplBase>(static_cast<SetImplBase*>(new_set));
}
std::vector<RTAny> values() const override {
std::vector<RTAny> res;
for (auto& v : set_) {
res.push_back(RTAny::from_vertex(VertexRecord{
static_cast<label_t>(v & 0xff), static_cast<vid_t>(v >> 8)}));
}
return res;
}
RTAnyType type() const override { return RTAnyType::kVertex; }
bool exists(const RTAny& val) const override {
auto v = TypedConverter<VertexRecord>::to_typed(val);
return set_.find((1ll * v.vid_) << 8 | v.label_) != set_.end();
}
bool exists(VertexRecord val) const {
return set_.find((1ll * val.vid_) << 8 | val.label_) != set_.end();
}
bool operator<(const SetImplBase& p) const override {
LOG(ERROR) << "not support for set of pair";
return set_.size() <
(dynamic_cast<const SetImpl<VertexRecord>&>(p)).set_.size();
}
bool operator==(const SetImplBase& p) const override {
return set_ == (dynamic_cast<const SetImpl<VertexRecord>&>(p)).set_;
}
void insert(const RTAny& val) override {
insert(TypedConverter<VertexRecord>::to_typed(val));
}
void insert(VertexRecord val) {
set_.insert((1ll * val.vid_) << 8 | val.label_);
}
size_t size() const override { return set_.size(); }
std::unordered_set<int64_t> set_;
};
class EdgePropVecBase {
public:
static std::shared_ptr<EdgePropVecBase> make_edge_prop_vec(PropertyType type);
virtual ~EdgePropVecBase() = default;
virtual size_t size() const = 0;
virtual void resize(size_t size) = 0;
virtual void reserve(size_t size) = 0;
virtual void clear() = 0;
virtual EdgeData get(size_t idx) const = 0;
virtual PropertyType type() const = 0;
virtual void set_any(size_t idx, EdgePropVecBase* other,
size_t other_idx) = 0;
};
template <typename T>
class EdgePropVec : public EdgePropVecBase {
public:
~EdgePropVec() {}
void push_back(const T& val) { prop_data_.push_back(val); }
void emplace_back(T&& val) { prop_data_.emplace_back(std::move(val)); }
size_t size() const override { return prop_data_.size(); }
EdgeData get(size_t idx) const override { return EdgeData(prop_data_[idx]); }
T get_view(size_t idx) const { return prop_data_[idx]; }
void resize(size_t size) override { prop_data_.resize(size); }
void clear() override { prop_data_.clear(); }
void reserve(size_t size) override { prop_data_.reserve(size); }
T operator[](size_t idx) const { return prop_data_[idx]; }
void set(size_t idx, const T& val) {
if (prop_data_.size() <= idx) {
prop_data_.resize(idx + 1);
}
prop_data_[idx] = val;
}
PropertyType type() const override { return AnyConverter<T>::type(); }
void set_any(size_t idx, EdgePropVecBase* other, size_t other_idx) override {
assert(dynamic_cast<EdgePropVec<T>*>(other) != nullptr);
set(idx, dynamic_cast<EdgePropVec<T>*>(other)->get_view(other_idx));
}
private:
std::vector<T> prop_data_;
};
template <>
class EdgePropVec<grape::EmptyType> : public EdgePropVecBase {
public:
EdgePropVec() : size_(0) {}
~EdgePropVec() {}
void push_back(const grape::EmptyType& val) { size_++; }
void emplace_back(grape::EmptyType&& val) { size_++; }
size_t size() const override { return size_; }
EdgeData get(size_t idx) const override {
return EdgeData(grape::EmptyType());
}
grape::EmptyType get_view(size_t idx) const { return grape::EmptyType(); }
void resize(size_t size) override { size_ = size; }
void clear() override {}
void reserve(size_t size) override {}
grape::EmptyType operator[](size_t idx) const { return grape::EmptyType(); }
void set(size_t idx, const grape::EmptyType& val) {}
PropertyType type() const override { return PropertyType::kEmpty; }
void set_any(size_t idx, EdgePropVecBase* other, size_t other_idx) override {}
size_t size_;
};
template <typename T>
using is_view_type =
std::disjunction<std::is_same<T, List>, std::is_same<T, Tuple>,
std::is_same<T, Map>, std::is_same<T, Set>,
std::is_same<T, std::string_view>, std::is_same<T, Path>>;
} // namespace runtime
} // namespace gs
#endif // RUNTIME_COMMON_RT_ANY_H_