flex/engines/hqps_db/structures/collection.h (1,299 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 ENGINES_HQPS_DS_COLLECTION_H_
#define ENGINES_HQPS_DS_COLLECTION_H_
#include <tuple>
#include <unordered_set>
#include <vector>
#include "flex/engines/hqps_db/core/null_record.h"
#include "flex/engines/hqps_db/core/utils/hqps_utils.h"
#include "flex/engines/hqps_db/core/utils/props.h"
#include "flex/storages/rt_mutable_graph/types.h"
#include "grape/utils/bitset.h"
#include <boost/functional/hash.hpp>
#include "grape/util.h"
namespace gs {
class EmptyCol {
public:
using value_type = grape::EmptyType;
};
// After operator like group, we need to extract the property or the count to
// separate column.
// We use collection to implement this abstraction.
// Currently we may not use it like vertex_set/edge_set, i.e., no dedup, no
// flat, not subset on collection.
template <typename LabelT, typename VID_T, typename... T>
class RowVertexSetImpl;
template <typename LabelT, typename VID_T, typename... T>
class RowVertexSetImplBuilder;
template <typename VID_T, typename LabelT, typename... T>
class TwoLabelVertexSetImpl;
template <typename VID_T, typename LabelT, typename... T>
class TwoLabelVertexSetImplBuilder;
template <typename VID_T, typename LabelT, typename... T>
class GeneralVertexSetBuilder;
// untypedEdgeSet
template <typename VID_T, typename LabelT, typename SUB_GRAPH_T>
class UnTypedEdgeSet;
template <typename T>
class Collection;
template <typename T>
class CollectionBuilder {
public:
static constexpr bool is_row_vertex_set_builder = false;
static constexpr bool is_flat_edge_set_builder = false;
static constexpr bool is_general_edge_set_builder = false;
static constexpr bool is_two_label_set_builder = false;
static constexpr bool is_collection_builder = true;
using result_t = Collection<T>;
CollectionBuilder() {}
// insert tuple at index ind.
void Insert(T&& t) { vec_.emplace_back(std::move(t)); }
void Insert(const T& t) { vec_.push_back(t); }
// ele& data
void Insert(const T& t, const T& t2) { vec_.push_back(t); }
// insert index ele tuple
void Insert(const std::tuple<size_t, T>& t) {
vec_.emplace_back(std::get<1>(t));
}
Collection<T> Build() {
// VLOG(10) << "Finish building counter" << gs::to_string(vec_);
return Collection<T>(std::move(vec_));
}
private:
std::vector<T> vec_;
};
// Building for collection which appears as the key in group by
template <typename T>
class KeyedCollectionBuilder {
public:
static constexpr bool is_row_vertex_set_builder = false;
static constexpr bool is_flat_edge_set_builder = false;
static constexpr bool is_general_edge_set_builder = false;
static constexpr bool is_two_label_set_builder = false;
static constexpr bool is_collection_builder = true;
using result_t = Collection<T>;
KeyedCollectionBuilder() {}
KeyedCollectionBuilder(const Collection<T>& old) { vec_.reserve(old.Size()); }
template <typename LabelT, typename VID_T, typename... TS>
KeyedCollectionBuilder(
const RowVertexSetImpl<LabelT, VID_T, TS...>& row_vertex_set) {
vec_.reserve(row_vertex_set.Size());
}
// insert returning a unique index for the inserted element
int32_t insert(const T& t) {
if (IsNull(t)) {
return -1;
}
if (map_.find(t) == map_.end()) {
map_[t] = vec_.size();
vec_.push_back(t);
return vec_.size() - 1;
} else {
return map_[t];
}
}
int32_t insert(const std::tuple<size_t, T>& t, const T& data) {
return insert(std::get<1>(t));
}
int32_t insert(T&& t) { return insert(t); }
int32_t Insert(const std::tuple<size_t, T>& t) {
return insert(std::get<1>(t));
}
Collection<T> Build() {
// VLOG(10) << "Finish building counter" << gs::to_string(vec_);
return Collection<T>(std::move(vec_));
}
private:
std::unordered_map<T, size_t, boost::hash<T>> map_;
std::vector<T> vec_;
};
template <typename T>
class CollectionIter {
public:
using data_tuple_t = std::tuple<T>;
using inner_iter_t = typename std::vector<T>::const_iterator;
using self_type_t = CollectionIter<T>;
using index_ele_tuple_t = std::tuple<size_t, T>;
CollectionIter(const std::vector<T>& vec, size_t ind)
: vec_(vec), ind_(ind) {}
T GetElement() const { return vec_[ind_]; }
index_ele_tuple_t GetIndexElement() const {
return std::make_tuple(ind_, vec_[ind_]);
}
T GetData() const { return vec_[ind_]; }
inline CollectionIter<T>& operator++() {
++ind_;
return *this;
};
inline bool operator==(const self_type_t& rhs) const {
return ind_ == rhs.ind_;
}
inline bool operator!=(const self_type_t& rhs) const {
return ind_ != rhs.ind_;
}
inline bool operator<(const self_type_t& rhs) const {
return ind_ < rhs.ind_;
}
inline const self_type_t& operator*() const { return *this; }
inline const self_type_t* operator->() const { return this; }
private:
const std::vector<T>& vec_;
size_t ind_;
};
// specialization for T is tuple, and only contains one element.
template <typename T>
class CollectionIter<std::tuple<T>> {
public:
using element_type = std::tuple<T>;
using data_tuple_t = std::tuple<element_type>;
using inner_iter_t = typename std::vector<element_type>::const_iterator;
using self_type_t = CollectionIter<element_type>;
using index_ele_tuple_t = std::tuple<size_t, T>;
CollectionIter(const std::vector<element_type>& vec, size_t ind)
: vec_(vec), ind_(ind) {}
T GetElement() const { return std::get<0>(vec_[ind_]); }
index_ele_tuple_t GetIndexElement() const {
return std::make_tuple(ind_, std::get<0>(vec_[ind_]));
}
T GetData() const { return std::get<0>(vec_[ind_]); }
inline CollectionIter<std::tuple<T>>& operator++() {
++ind_;
return *this;
};
inline bool operator==(const self_type_t& rhs) const {
return ind_ == rhs.ind_;
}
inline bool operator!=(const self_type_t& rhs) const {
return ind_ != rhs.ind_;
}
inline bool operator<(const self_type_t& rhs) const {
return ind_ < rhs.ind_;
}
inline const self_type_t& operator*() const { return *this; }
inline const self_type_t* operator->() const { return this; }
private:
size_t ind_;
const std::vector<element_type>& vec_;
};
template <typename T>
class Collection {
public:
using element_type = T;
using value_type = T;
using iterator = CollectionIter<T>;
using data_tuple_t = typename iterator::data_tuple_t;
using index_ele_tuple_t = typename iterator::index_ele_tuple_t;
using flat_t = Collection<T>;
using self_type_t = Collection<T>;
using EntityValueType = T;
using builder_t = CollectionBuilder<T>;
static constexpr bool is_collection = true;
static constexpr bool is_keyed = false;
static constexpr bool is_multi_label = false;
static constexpr bool is_vertex_set = false;
static constexpr bool is_edge_set = false;
static constexpr bool is_two_label_set = false;
static constexpr bool is_general_set = false;
static constexpr bool is_row_vertex_set = false;
Collection() {}
Collection(size_t cap) { vec_.reserve(cap); }
Collection(std::vector<T>&& vec) : vec_(std::move(vec)) {}
Collection(Collection<T>&& other) : vec_(std::move(other.vec_)) {}
Collection(const Collection<T>& other) : vec_(other.vec_) {}
~Collection() {}
size_t Size() const { return vec_.size(); }
builder_t CreateBuilder() const { return builder_t(); }
// Append empty entries to make length == the give args
void MakeUpTo(size_t dstLen) {
if (dstLen <= vec_.size()) {
return;
}
vec_.resize(dstLen);
}
// For the input offset array, add default value for null entry.
std::pair<Collection<T>, std::vector<offset_t>> apply(
const std::vector<offset_t>& offset) {
size_t new_size = offset.size() - 1;
VLOG(10) << "Extend " << vec_.size() << " to size: " << new_size;
std::vector<T> new_vec;
std::vector<offset_t> new_offset;
new_offset.reserve(new_size + 1);
new_vec.reserve(new_size);
new_offset.emplace_back(0);
for (size_t i = 0; i < new_size; ++i) {
if (offset[i] >= offset[i + 1]) {
new_vec.emplace_back(T());
} else {
for (auto j = offset[i]; j < offset[i + 1]; ++j) {
new_vec.push_back(vec_[j]);
}
}
new_offset.emplace_back(new_vec.size());
}
Collection<T> new_set(std::move(new_vec));
return std::make_pair(std::move(new_set), std::move(new_offset));
}
void Repeat(std::vector<offset_t>& cur_offset,
std::vector<offset_t>& repeat_vec) {
std::vector<T> res;
res.reserve(repeat_vec.back());
CHECK(repeat_vec.size() == cur_offset.size())
<< "repeat vec:" << gs::to_string(repeat_vec)
<< ", cur offset: " << gs::to_string(cur_offset);
for (size_t i = 0; i + 1 < cur_offset.size(); ++i) {
auto times_to_repeat = repeat_vec[i + 1] - repeat_vec[i];
for (size_t j = 0; j < times_to_repeat; ++j) {
for (auto k = cur_offset[i]; k < cur_offset[i + 1]; ++k) {
res.push_back(vec_[k]);
}
}
}
VLOG(10) << "new vids: " << gs::to_string(res);
vec_.swap(res);
}
template <size_t col_ind, typename... index_ele_tuple_t>
auto Flat(std::vector<std::tuple<index_ele_tuple_t...>>& index_ele_tuples) {
std::vector<T> res_vids;
res_vids.reserve(index_ele_tuples.size());
for (auto ele : index_ele_tuples) {
auto& cur = std::get<col_ind>(ele);
//(ind, vid)
auto& ind = std::get<0>(cur);
CHECK(ind < vec_.size());
res_vids.emplace_back(vec_[ind]);
}
return self_type_t(std::move(res_vids));
}
// project my self.
template <int tag_id, int Fs,
typename std::enable_if<Fs == -1>::type* = nullptr>
self_type_t ProjectWithRepeatArray(const std::vector<size_t>& repeat_array,
KeyAlias<tag_id, Fs>& key_alias) const {
std::vector<T> res;
for (size_t i = 0; i < repeat_array.size(); ++i) {
for (size_t j = 0; j < repeat_array[i]; ++j) {
// VLOG(10) << "Project: " << vids_[i];
res.push_back(vec_[i]);
}
}
return self_type_t(std::move(res));
}
void SubSetWithIndices(std::vector<size_t>& indices) {
std::vector<T> res;
res.reserve(indices.size());
for (auto ind : indices) {
res.emplace_back(vec_[ind]);
}
vec_.swap(res);
}
template <typename... PropT>
void fillBuiltinProps(std::vector<std::tuple<PropT...>>& tuples,
PropNameArray<PropT...>& prop_names) {
LOG(WARNING) << " Not implemented";
}
template <typename PropT, typename std::enable_if_t<std::is_same_v<
PropT, grape::EmptyType>>::type* = nullptr>
std::vector<offset_t> Dedup(const PropertySelector<PropT>& prop_selector) {
std::vector<offset_t> offsets;
std::vector<T> new_vec;
std::unordered_map<T, size_t, boost::hash<T>> map;
for (size_t ind = 0; ind < vec_.size(); ++ind) {
offsets.emplace_back(new_vec.size());
auto ret = map.insert({vec_[ind], ind});
if (ret.second == true) {
new_vec.emplace_back(vec_[ind]);
}
}
offsets.emplace_back(new_vec.size());
vec_.swap(new_vec);
return offsets;
}
iterator begin() const { return iterator(vec_, 0); }
iterator end() const { return iterator(vec_, vec_.size()); }
T Get(size_t ind) const { return vec_[ind]; }
const std::vector<T> GetVector() const { return vec_; }
private:
std::vector<T> vec_;
};
template <typename T>
using CollectionOfVec = Collection<std::vector<T>>;
// the tag is used when receiving tuple, and apply aggregate function on tuple.
template <int tag>
class CountBuilder {
public:
CountBuilder() {}
// insert tuple at index ind.
// if the ele_value equal to invalid_value, then do not insert.
template <typename ELE_TUPLE, typename DATA_TUPLE>
bool insert(size_t ind, const ELE_TUPLE& tuple, const DATA_TUPLE& data) {
// just count times.
while (vec_.size() <= ind) {
vec_.emplace_back(0);
}
using cur_ele_tuple = typename gs::tuple_element<tag, ELE_TUPLE>::type;
auto& cur_ele = gs::get_from_tuple<tag>(tuple);
// currently we support vertex ele tuple and edge tuple.
if constexpr (std::tuple_size<cur_ele_tuple>::value == 2) {
auto& ele = std::get<1>(cur_ele);
using vid_t = typename std::tuple_element<1, cur_ele_tuple>::type;
if (ele != NullRecordCreator<vid_t>::GetNull()) {
++vec_[ind];
} else {
VLOG(10) << "ele is null";
}
} else {
++vec_[ind];
}
return true;
}
bool inc_count(size_t ind, int32_t v) {
while (vec_.size() <= ind) {
vec_.emplace_back(0);
}
vec_[ind] += v;
return true;
}
Collection<int64_t> Build() { return Collection<int64_t>(std::move(vec_)); }
private:
std::vector<int64_t> vec_;
};
// Prop Count Builder.
template <int tag, typename PropGetterT>
class PropCountBuilder {
public:
PropCountBuilder(PropGetterT&& prop_getter)
: prop_getter_(std::move(prop_getter)) {}
// insert tuple at index ind.
// if the ele_value equal to invalid_value, then do not insert.
template <typename ELE_TUPLE, typename DATA_TUPLE>
bool insert(size_t ind, const ELE_TUPLE& tuple, const DATA_TUPLE& data) {
// just count times.
while (vec_.size() <= ind) {
vec_.emplace_back(0);
}
auto& cur_ele = gs::get_from_tuple<tag>(tuple);
if (IsNull(cur_ele)) {
return false;
}
// get prop from prop getter
auto props = prop_getter_.get_view(cur_ele);
if (IsNull(props)) {
return false;
}
// get the type of props
using props_t = decltype(props);
if (props != NullRecordCreator<props_t>::GetNull()) {
++vec_[ind];
} else {
VLOG(10) << "ele is null, ind: " << ind
<< "ele:" << gs::to_string(cur_ele);
}
return true;
}
Collection<int64_t> Build() { return Collection<int64_t>(std::move(vec_)); }
private:
std::vector<int64_t> vec_;
PropGetterT prop_getter_;
};
template <int... tag>
class MultiColCountBuilder {
public:
MultiColCountBuilder() {}
// insert tuple at index ind.
// if the ele_value equal to invalid_value, then do not insert.
template <typename ELE_TUPLE, typename DATA_TUPLE>
bool insert(size_t ind, const ELE_TUPLE& tuple, const DATA_TUPLE& data) {
auto cur_ele_tuple =
std::tuple_cat(tuple_slice<1>(gs::get_from_tuple<tag>(tuple))...);
if (IsNull(cur_ele_tuple)) {
return false;
}
while (vec_.size() <= ind) {
vec_.emplace_back(0);
}
using cur_ele_tuple_t =
std::remove_const_t<std::remove_reference_t<decltype(cur_ele_tuple)>>;
// remove the const and reference for each type in cur_ele_tuple_t
using cur_ele_tuple_rm_const_ref_t =
typename ConstRefRemoveHelper<cur_ele_tuple_t>::type;
if (cur_ele_tuple !=
NullRecordCreator<cur_ele_tuple_rm_const_ref_t>::GetNull()) {
++vec_[ind];
} else {
VLOG(10) << "ele is null";
}
return true;
}
Collection<int64_t> Build() { return Collection<int64_t>(std::move(vec_)); }
private:
std::vector<int64_t> vec_;
};
template <int tag_id, typename T, typename Enable = void>
class DistinctCountBuilder;
// Count the distinct edges of UntypedEdgeSet.
// We assume each edge in UnTypeEdgeSet is unique, so just count the index of
// index_ele_tuple_t.
template <int tag_id, typename EDGE_SET_T>
class DistinctCountBuilder<
tag_id, EDGE_SET_T,
typename std::enable_if<(EDGE_SET_T::is_edge_set)>::type> {
public:
using edge_set_t = EDGE_SET_T;
using index_ele_t = typename edge_set_t::index_ele_tuple_t;
DistinctCountBuilder(const edge_set_t& edge_set) {
edges_num_ = edge_set.Size();
}
template <typename ELE_TUPLE_T, typename DATA_TUPLE>
bool insert(size_t ind, const ELE_TUPLE_T& tuple, const DATA_TUPLE& data) {
auto& cur_ind_ele = gs::get_from_tuple<tag_id>(tuple);
if (IsNull(cur_ind_ele)) {
return false;
}
while (vec_.size() <= ind) {
vec_.emplace_back(grape::Bitset(edges_num_));
}
auto& cur_bitset = vec_[ind];
auto cur_ind = std::get<0>(cur_ind_ele);
if (cur_ind < edges_num_) {
cur_bitset.set_bit(cur_ind);
} else {
LOG(FATAL) << "Invalid edge index: " << cur_ind
<< ", edges num: " << edges_num_;
}
return true;
}
Collection<int64_t> Build() {
std::vector<int64_t> res;
res.reserve(vec_.size());
for (auto& bitset : vec_) {
res.emplace_back(bitset.count());
}
return Collection<int64_t>(std::move(res));
}
private:
std::vector<grape::Bitset> vec_;
size_t edges_num_;
};
// count the distinct number of received elements.
template <int tag_id, typename LabelT, typename VID_T, typename... T>
class DistinctCountBuilder<tag_id, RowVertexSetImpl<LabelT, VID_T, T...>> {
public:
DistinctCountBuilder(const std::vector<VID_T>& vertices) {
// find out the range of vertices inside vector, and use a bitset to count
for (auto v : vertices) {
min_v = std::min(min_v, v);
max_v = std::max(max_v, v);
}
range_size = max_v - min_v + 1;
}
template <typename ELE_TUPLE_T, typename DATA_TUPLE>
bool insert(size_t ind, const ELE_TUPLE_T& tuple, const DATA_TUPLE& data) {
auto& cur_ind_ele = gs::get_from_tuple<tag_id>(tuple);
if (IsNull(cur_ind_ele)) {
return false;
}
static_assert(
std::is_same_v<
std::tuple_element_t<1, std::remove_const_t<std::remove_reference_t<
decltype(cur_ind_ele)>>>,
VID_T>,
"Type not match");
while (vec_.size() <= ind) {
vec_.emplace_back(grape::Bitset(range_size));
}
auto& cur_bitset = vec_[ind];
auto cur_v = std::get<1>(cur_ind_ele);
cur_bitset.set_bit(cur_v - min_v);
// VLOG(10) << "tag id: " << tag_id << "insert at ind: " << ind
// << ",value : " << cur_v << ", res: " << cur_bitset.count();
return true;
}
Collection<int64_t> Build() {
std::vector<int64_t> res;
res.reserve(vec_.size());
for (auto& bitset : vec_) {
res.emplace_back(bitset.count());
}
return Collection<int64_t>(std::move(res));
}
private:
std::vector<grape::Bitset> vec_;
VID_T min_v, max_v, range_size;
};
// specialization for DistinctCountBuilder for num_labels=2
template <int tag_id, typename VID_T, typename LabelT, typename... T>
class DistinctCountBuilder<tag_id, TwoLabelVertexSetImpl<VID_T, LabelT, T...>> {
public:
DistinctCountBuilder(const grape::Bitset& bitset,
const std::vector<VID_T>& vids) {
// find out the range of vertices inside vector, and use a bitset to count
for (size_t i = 0; i < vids.size(); ++i) {
auto v = vids[i];
if (bitset.get_bit(i)) {
min_v[0] = std::min(min_v[0], v);
max_v[0] = std::max(max_v[0], v);
} else {
min_v[1] = std::min(min_v[1], v);
max_v[1] = std::max(max_v[1], v);
}
}
range_size[0] = max_v[0] - min_v[0] + 1;
range_size[1] = max_v[1] - min_v[0] + 1;
VLOG(10) << "Min: " << min_v[0] << ", range size: " << range_size[0];
VLOG(10) << "Min: " << min_v[1] << ", range size: " << range_size[1];
}
template <typename ELE_TUPLE_T, typename DATA_TUPLE>
bool insert(size_t ind, const ELE_TUPLE_T& tuple, const DATA_TUPLE& data) {
auto& cur_ind_ele = gs::get_from_tuple<tag_id>(tuple);
if (IsNull(cur_ind_ele)) {
return false;
}
static_assert(
std::is_same_v<
std::tuple_element_t<2, std::remove_const_t<std::remove_reference_t<
decltype(cur_ind_ele)>>>,
VID_T>,
"Type not match");
auto label_ind = std::get<1>(cur_ind_ele);
while (vec_[label_ind].size() <= ind) {
vec_[label_ind].emplace_back(grape::Bitset(range_size[label_ind]));
}
auto& cur_bitset = vec_[label_ind][ind];
auto cur_v = std::get<2>(cur_ind_ele);
cur_bitset.set_bit(cur_v - min_v[label_ind]);
VLOG(10) << "tag id: " << tag_id << "insert at ind: " << ind
<< ",value : " << cur_v << ", res: " << cur_bitset.count();
return true;
}
Collection<int64_t> Build() {
std::vector<int64_t> res;
auto max_ind = std::max(vec_[0].size(), vec_[1].size());
res.resize(max_ind, 0);
for (auto label_ind = 0; label_ind < 2; ++label_ind) {
for (size_t i = 0; i < vec_[label_ind].size(); ++i) {
res[i] += vec_[label_ind][i].count();
}
}
return Collection<int64_t>(std::move(res));
}
private:
std::array<std::vector<grape::Bitset>, 2> vec_;
std::array<VID_T, 2> min_v, max_v, range_size;
};
// specialization for DistinctCountBuilder for num_labels=2
template <int tag_id, typename VID_T, typename LabelT, typename... T>
class DistinctCountBuilder<tag_id, GeneralVertexSet<VID_T, LabelT, T...>> {
public:
DistinctCountBuilder(const std::vector<grape::Bitset>& bitsets,
const std::vector<LabelT>& labels)
: bitset_vec_(bitsets), labels_(labels) {
CHECK(bitset_vec_.size() == labels_.size());
}
template <typename ELE_TUPLE_T, typename DATA_TUPLE>
bool insert(size_t ind, const ELE_TUPLE_T& tuple, const DATA_TUPLE& data) {
auto& cur_ind_ele = gs::get_from_tuple<tag_id>(tuple);
if (IsNull(cur_ind_ele)) {
return false;
}
while (vec_.size() <= ind) {
vec_.emplace_back(std::unordered_set<GlobalId>());
}
auto ele_index = std::get<0>(cur_ind_ele);
int32_t label_ind = -1;
for (size_t i = 0; i < bitset_vec_.size(); ++i) {
if (bitset_vec_[i].get_bit(ele_index)) {
label_ind = i;
break;
}
}
CHECK(label_ind != -1);
auto global_id = GlobalId(labels_[label_ind], std::get<1>(cur_ind_ele));
vec_[ind].insert(global_id);
return true;
}
Collection<int64_t> Build() {
std::vector<int64_t> res;
res.reserve(vec_.size());
for (auto& set : vec_) {
res.emplace_back(set.size());
}
return Collection<int64_t>(std::move(res));
}
private:
std::vector<std::unordered_set<GlobalId>> vec_;
const std::vector<grape::Bitset>& bitset_vec_;
const std::vector<LabelT>& labels_;
};
// DistinctCountBuilder for PathSet
template <int tag_id, typename PATH_SET_T>
class DistinctCountBuilder<
tag_id, PATH_SET_T,
typename std::enable_if<PATH_SET_T::is_path_set>::type> {
public:
using path_set_t = PATH_SET_T;
using index_ele_t = typename path_set_t::index_ele_tuple_t;
DistinctCountBuilder(const path_set_t& path_set) {
paths_num_ = path_set.Size();
LOG(INFO) << "path num: " << paths_num_;
}
template <typename ELE_TUPLE_T, typename DATA_TUPLE>
bool insert(size_t ind, const ELE_TUPLE_T& tuple, const DATA_TUPLE& data) {
auto& cur_ind_ele = gs::get_from_tuple<tag_id>(tuple);
if (IsNull(std::get<1>(cur_ind_ele))) {
return false;
}
while (vec_.size() <= ind) {
vec_.emplace_back(grape::Bitset(paths_num_));
}
auto& cur_bitset = vec_[ind];
auto cur_ind = std::get<0>(cur_ind_ele);
if (cur_ind < paths_num_) {
cur_bitset.set_bit(cur_ind);
} else {
LOG(FATAL) << "Invalid path set index: " << cur_ind
<< ", path set num: " << paths_num_;
}
return true;
}
Collection<int64_t> Build() {
std::vector<int64_t> res;
res.reserve(vec_.size());
for (auto& bitset : vec_) {
res.emplace_back(bitset.count());
}
return Collection<int64_t>(std::move(res));
}
private:
std::vector<grape::Bitset> vec_;
size_t paths_num_;
};
// DistinctCountBuilder for Collection
template <int tag_id, typename T>
class DistinctCountBuilder<tag_id, Collection<T>> {
public:
using set_t = Collection<T>;
using index_ele_t = typename set_t::index_ele_tuple_t;
DistinctCountBuilder(const set_t& set) { record_num_ = set.Size(); }
template <typename ELE_TUPLE_T, typename DATA_TUPLE>
bool insert(size_t ind, const ELE_TUPLE_T& tuple, const DATA_TUPLE& data) {
auto& cur_ind_ele = gs::get_from_tuple<tag_id>(tuple);
if (IsNull(cur_ind_ele)) {
return false;
}
while (vec_.size() <= ind) {
vec_.emplace_back(grape::Bitset(record_num_));
}
auto& cur_bitset = vec_[ind];
auto cur_ind = std::get<0>(cur_ind_ele);
if (cur_ind < record_num_) {
cur_bitset.set_bit(cur_ind);
} else {
LOG(FATAL) << "Invalid path set index: " << cur_ind
<< ", set num: " << record_num_;
}
return true;
}
Collection<int64_t> Build() {
std::vector<int64_t> res;
res.reserve(vec_.size());
for (auto& bitset : vec_) {
res.emplace_back(bitset.count());
}
return Collection<int64_t>(std::move(res));
}
private:
std::vector<grape::Bitset> vec_;
size_t record_num_;
};
// DistinctCountBuilder for multiple sets together
template <typename SET_TUPLE_T, int... TAG_IDs>
class MultiColDistinctCountBuilder;
template <typename... SET_Ts, int... TAG_IDs>
class MultiColDistinctCountBuilder<std::tuple<SET_Ts...>, TAG_IDs...> {
public:
using set_ele_t = std::tuple<typename SET_Ts::element_t...>;
MultiColDistinctCountBuilder() {}
template <typename ELE_TUPLE_T, typename DATA_TUPLE>
bool insert(size_t ind, const ELE_TUPLE_T& tuple, const DATA_TUPLE& data) {
// construct the ref tuple from tuple,with TAG_IDS,
// get element tuple from index_ele_tuple_t
auto cur_ele_tuple =
std::tuple_cat(tuple_slice<1>(gs::get_from_tuple<TAG_IDs>(tuple))...);
if (IsNull(cur_ele_tuple)) {
return false;
}
while (vec_of_set_.size() <= ind) {
vec_of_set_.emplace_back(
std::unordered_set<set_ele_t, boost::hash<set_ele_t>>());
}
auto& cur_set = vec_of_set_[ind];
cur_set.insert(cur_ele_tuple);
VLOG(10) << "tuple: " << gs::to_string(cur_ele_tuple)
<< ",all ele: " << gs::to_string(tuple) << "insert at ind: " << ind
<< ", res: " << cur_set.size();
return true;
}
Collection<int64_t> Build() {
std::vector<int64_t> res;
res.reserve(vec_of_set_.size());
for (auto& set : vec_of_set_) {
res.emplace_back(set.size());
}
return Collection<int64_t>(std::move(res));
}
private:
std::vector<std::unordered_set<set_ele_t, boost::hash<set_ele_t>>>
vec_of_set_;
};
template <typename PropGetterT, int tag_id>
class SumBuilder {
public:
using T = typename PropGetterT::prop_element_t;
SumBuilder(PropGetterT&& prop_getter)
: prop_getter_(std::move(prop_getter)) {}
// insert tuple at index ind.
template <typename IND_ELE_TUPLE, typename DATA_TUPLE>
bool insert(size_t ind, const IND_ELE_TUPLE& tuple, const DATA_TUPLE& data) {
const auto& cur_ind_ele = gs::get_from_tuple<tag_id>(tuple);
if (IsNull(cur_ind_ele)) {
return false;
}
// just count times.
while (vec_.size() <= ind) {
vec_.emplace_back((T) 0);
is_null_.emplace_back(true);
}
// vec_[ind] += std::get<1>(cur_ind_ele);
auto view = prop_getter_.get_view(cur_ind_ele);
if (IsNull(view)) {
return false;
}
vec_[ind] += view;
is_null_[ind] = false;
return true;
}
Collection<T> Build() {
for (size_t i = 0; i < vec_.size(); ++i) {
if (is_null_[i]) {
vec_[i] = NullRecordCreator<T>::GetNull();
}
}
return Collection<T>(std::move(vec_));
}
private:
PropGetterT prop_getter_;
std::vector<T> vec_;
std::vector<bool> is_null_;
};
template <typename GI, typename PropGetterT, int tag_id>
class MinBuilder {
public:
using T = typename PropGetterT::prop_element_t;
MinBuilder(PropGetterT&& prop_getter)
: prop_getter_(std::move(prop_getter)) {}
// insert tuple at index ind.
template <typename IND_ELE_TUPLE, typename DATA_TUPLE>
bool insert(size_t ind, const IND_ELE_TUPLE& tuple, const DATA_TUPLE& data) {
const auto& cur_ind_ele = gs::get_from_tuple<tag_id>(tuple);
if (IsNull(cur_ind_ele)) {
return false;
}
VLOG(10) << "Insert min with ind: " << ind
<< ", value: " << std::get<1>(cur_ind_ele)
<< ", vec size: " << vec_.size();
// just count times.
while (vec_.size() <= ind) {
vec_.emplace_back(std::numeric_limits<T>::max());
}
vec_[ind] = std::min(vec_[ind], prop_getter_.get_view(cur_ind_ele));
return true;
}
Collection<T> Build() {
// iterate over vec_, turn inf to null
for (auto& ele : vec_) {
if (ele == std::numeric_limits<T>::max()) {
ele = NullRecordCreator<T>::GetNull();
}
}
return Collection<T>(std::move(vec_));
}
private:
PropGetterT prop_getter_;
std::vector<T> vec_;
};
template <typename GI, typename PropGetterT, int tag_id>
class MaxBuilder {
public:
using T = typename PropGetterT::prop_element_t;
MaxBuilder(PropGetterT&& prop_getter)
: prop_getter_(std::move(prop_getter)) {}
// insert tuple at index ind.
template <typename IND_ELE_TUPLE, typename DATA_TUPLE_T>
bool insert(size_t ind, const IND_ELE_TUPLE& tuple,
const DATA_TUPLE_T& data) {
const auto& cur_ind_ele = gs::get_from_tuple<tag_id>(tuple);
if (IsNull(cur_ind_ele)) {
return false;
}
// just count times.
while (vec_.size() <= ind) {
vec_.emplace_back(std::numeric_limits<T>::min());
}
vec_[ind] = std::max(vec_[ind], prop_getter_.get_view(cur_ind_ele));
return true;
}
Collection<T> Build() {
// iterate over vec_, turn -inf to inf
for (auto& ele : vec_) {
if (ele == std::numeric_limits<T>::min()) {
ele = NullRecordCreator<T>::GetNull();
}
}
return Collection<T>(std::move(vec_));
}
private:
PropGetterT prop_getter_;
std::vector<T> vec_;
};
template <typename GI, typename SET_T, typename T, int tag_id>
class FirstBuilder;
// FirstBuilder
template <typename GI, typename C_T, int tag_id>
class FirstBuilder<GI, Collection<C_T>, grape::EmptyType, tag_id> {
public:
FirstBuilder(const Collection<C_T>& set, const GI& graph,
PropNameArray<grape::EmptyType> prop_names) {
CHECK(prop_names.size() == 1);
CHECK(prop_names[0] == "none" || prop_names[0] == "None" ||
prop_names[0] == "");
}
template <typename IND_ELE_T, typename DATA_ELE_T>
bool insert(size_t ind, const IND_ELE_T& tuple,
const DATA_ELE_T& data_tuple) {
if (ind < vec_.size()) {
return false;
} else if (ind == vec_.size()) {
vec_.emplace_back(std::get<1>(gs::get_from_tuple<tag_id>(tuple)));
} else {
LOG(FATAL) << "Can not insert with ind: " << ind
<< ", which cur size is : " << vec_.size();
}
return true;
}
Collection<C_T> Build() { return Collection<C_T>(std::move(vec_)); }
private:
std::vector<C_T> vec_;
};
// firstBuilder for vertex set, with data tuple
template <typename GI, typename LabelT, typename VID_T, typename... OLD_T,
int tag_id>
class FirstBuilder<GI, RowVertexSetImpl<LabelT, VID_T, OLD_T...>,
grape::EmptyType, tag_id> {
public:
using set_t = RowVertexSetImpl<LabelT, VID_T, OLD_T...>;
using builder_t = RowVertexSetImplBuilder<LabelT, VID_T, OLD_T...>;
FirstBuilder(const set_t& set, const GI& graph,
PropNameArray<grape::EmptyType> prop_names)
: builder_(set.GetLabel(), set.GetPropNames()) {}
template <typename IND_ELE_T, typename DATA_TUPLE_T>
bool insert(size_t ind, const IND_ELE_T& tuple,
const DATA_TUPLE_T& data_tuple) {
if (ind < builder_.Size()) {
return false;
} else if (ind == builder_.Size()) {
builder_.Insert(tuple, data_tuple);
} else {
LOG(FATAL) << "Can not insert with ind: " << ind
<< ", which cur size is : " << builder_.size();
}
return true;
}
set_t Build() { return builder_.Build(); }
private:
builder_t builder_;
};
template <typename GI, typename LabelT, typename VID_T, int tag_id>
class FirstBuilder<GI, RowVertexSetImpl<LabelT, VID_T, grape::EmptyType>,
grape::EmptyType, tag_id> {
public:
using set_t = RowVertexSetImpl<LabelT, VID_T, grape::EmptyType>;
using builder_t = RowVertexSetImplBuilder<LabelT, VID_T, grape::EmptyType>;
FirstBuilder(const set_t& set, const GI& graph,
PropNameArray<grape::EmptyType> prop_names)
: builder_(set.GetLabel(), set.GetPropNames()) {}
template <typename IND_ELE_T, typename DATA_TUPLE_T>
bool insert(size_t ind, const IND_ELE_T& tuple,
const DATA_TUPLE_T& data_tuple) {
if (ind < builder_.Size()) {
return false;
} else if (ind == builder_.Size()) {
builder_.Insert(tuple);
} else {
LOG(FATAL) << "Can not insert with ind: " << ind
<< ", which cur size is : " << builder_.Size();
}
return true;
}
set_t Build() { return builder_.Build(); }
private:
builder_t builder_;
};
// first builder for two label set
template <typename GI, typename VID_T, typename LabelT, int tag_id>
class FirstBuilder<GI, TwoLabelVertexSetImpl<VID_T, LabelT, grape::EmptyType>,
grape::EmptyType, tag_id> {
public:
using set_t = TwoLabelVertexSetImpl<VID_T, LabelT, grape::EmptyType>;
using builder_t =
TwoLabelVertexSetImplBuilder<VID_T, LabelT, grape::EmptyType>;
FirstBuilder(const set_t& set, const GI& graph,
PropNameArray<grape::EmptyType> prop_names)
: builder_(set.Size(), set.GetLabels()) {}
template <typename IND_ELE_T, typename DATA_TUPLE_T>
bool insert(size_t ind, const IND_ELE_T& tuple,
const DATA_TUPLE_T& data_tuple) {
if (ind < builder_.Size()) {
return false;
} else if (ind == builder_.Size()) {
builder_.Insert(gs::get_from_tuple<tag_id>(tuple));
} else {
LOG(FATAL) << "Can not insert with ind: " << ind
<< ", which cur size is : " << builder_.Size();
}
return true;
}
set_t Build() { return builder_.Build(); }
private:
builder_t builder_;
};
template <typename GI, typename VID_T, typename LabelT, typename... T,
int tag_id>
class FirstBuilder<GI, TwoLabelVertexSetImpl<VID_T, LabelT, T...>,
grape::EmptyType, tag_id> {
public:
using set_t = TwoLabelVertexSetImpl<VID_T, LabelT, T...>;
using builder_t = TwoLabelVertexSetImplBuilder<VID_T, LabelT, T...>;
FirstBuilder(const set_t& set, const GI& graph,
PropNameArray<grape::EmptyType> prop_names)
// we should use a size which indicate the context size
: builder_(set.Size(), set.GetLabels()) {}
template <typename IND_ELE_T, typename DATA_TUPLE_T>
bool insert(size_t ind, const IND_ELE_T& tuple,
const DATA_TUPLE_T& data_tuple) {
if (ind < builder_.Size()) {
return false;
} else if (ind == builder_.Size()) {
builder_.Insert(gs::get_from_tuple<tag_id>(tuple),
gs::get_from_tuple<tag_id>(data_tuple));
} else {
LOG(FATAL) << "Can not insert with ind: " << ind
<< ", which cur size is : " << builder_.Size();
}
return true;
}
set_t Build() { return builder_.Build(); }
private:
builder_t builder_;
};
template <typename GI, typename VID_T, typename LabelT, typename... T,
int tag_id>
class FirstBuilder<GI, GeneralVertexSet<VID_T, LabelT, T...>, grape::EmptyType,
tag_id> {
public:
using set_t = GeneralVertexSet<VID_T, LabelT, T...>;
using builder_t = GeneralVertexSetBuilder<VID_T, LabelT, T...>;
FirstBuilder(const set_t& set, const GI& graph,
PropNameArray<grape::EmptyType> prop_names)
// we should use a size which indicate the context size
: builder_(set.Size(), set.GetLabels()) {}
template <typename IND_ELE_T, typename DATA_TUPLE_T>
bool insert(size_t ind, const IND_ELE_T& tuple,
const DATA_TUPLE_T& data_tuple) {
if (ind < builder_.Size()) {
return false;
} else if (ind == builder_.Size()) {
builder_.Insert(gs::get_from_tuple<tag_id>(tuple),
gs::get_from_tuple<tag_id>(data_tuple));
} else {
LOG(FATAL) << "Can not insert with ind: " << ind
<< ", which cur size is : " << builder_.Size();
}
return true;
}
set_t Build() { return builder_.Build(); }
private:
builder_t builder_;
};
template <typename T, typename GRAPH_INTERFACE, typename SET_T, int tag_id>
class CollectionOfSetBuilder;
template <typename T, typename GRAPH_INTERFACE, typename LabelT, typename VID_T,
typename... OLD_T, int tag_id>
class CollectionOfSetBuilder<
T, GRAPH_INTERFACE, RowVertexSetImpl<LabelT, VID_T, OLD_T...>, tag_id> {
public:
using set_t = RowVertexSetImpl<LabelT, VID_T, OLD_T...>;
using index_ele_t = typename set_t::index_ele_tuple_t;
using set_ele_t = typename set_t::element_t;
using graph_prop_getter_t =
typename GRAPH_INTERFACE::template single_prop_getter_t<T>;
using PROP_GETTER_T =
RowVertexSetPropGetter<tag_id, graph_prop_getter_t,
typename set_t::index_ele_tuple_t>;
CollectionOfSetBuilder(const RowVertexSetImpl<LabelT, VID_T, OLD_T...>& set,
const GRAPH_INTERFACE& graph,
PropNameArray<T> prop_names)
: prop_getter_(
create_prop_getter_impl<tag_id, T>(set, graph, prop_names[0])) {}
// insert tuple at index ind.
template <typename IND_TUPLE>
bool insert(size_t ind, IND_TUPLE& tuple) {
while (vec_.size() <= ind) {
vec_.emplace_back(std::vector<T>());
}
auto cur = gs::get_from_tuple<tag_id>(tuple);
using ele_t = typename set_t::index_ele_tuple_t;
if (NullRecordCreator<ele_t>::GetNull() == cur) {
return false;
}
vec_[ind].emplace_back(prop_getter_.get_view(cur));
return true;
}
template <typename IND_TUPLE, typename DATA_TUPLE>
bool insert(size_t ind, const IND_TUPLE& tuple, const DATA_TUPLE& data) {
while (vec_.size() <= ind) {
vec_.emplace_back(std::vector<T>());
}
auto cur = gs::get_from_tuple<tag_id>(tuple);
using ele_t = typename set_t::index_ele_tuple_t;
if (NullRecordCreator<ele_t>::GetNull() == cur) {
return false;
}
vec_[ind].emplace_back(prop_getter_.get_view(cur));
return true;
}
CollectionOfVec<T> Build() {
// Make it unique.
for (size_t i = 0; i < vec_.size(); ++i) {
sort(vec_[i].begin(), vec_[i].end());
vec_[i].erase(unique(vec_[i].begin(), vec_[i].end()), vec_[i].end());
}
// VLOG(10) << "Finish building counter" << gs::to_string(vec_);
return CollectionOfVec<T>(std::move(vec_));
}
private:
std::vector<std::vector<T>> vec_;
PROP_GETTER_T prop_getter_;
};
// To vector
template <typename T, typename GI, typename SET_T, int tag_id>
class CollectionOfVecBuilder;
template <typename T, typename GI, int tag_id>
class CollectionOfVecBuilder<T, GI, Collection<T>, tag_id> {
public:
CollectionOfVecBuilder(const GI& graph, const Collection<T>& set,
PropNameArray<T> prop_names) {}
// insert tuple at index ind.
template <typename IND_TUPLE>
bool insert(size_t ind, IND_TUPLE& tuple) {
auto cur = std::get<1>(gs::get_from_tuple<tag_id>(tuple));
// just count times.
while (vec_.size() <= ind) {
vec_.emplace_back(std::vector<T>());
}
using input_ele_t = typename std::remove_reference<decltype(cur)>::type;
if (NullRecordCreator<input_ele_t>::GetNull() == cur) {
return false;
}
// emplace the element to vector
vec_[ind].emplace_back(cur);
return true;
}
template <typename IND_TUPLE, typename DATA_TUPLE>
bool insert(size_t ind, const IND_TUPLE& tuple, const DATA_TUPLE& data) {
return insert(ind, tuple);
}
CollectionOfVec<T> Build() { return CollectionOfVec<T>(std::move(vec_)); }
private:
std::vector<std::vector<T>> vec_;
};
// organizing one property of vertex set to vector.
template <typename PropT, typename GRAPH_INTERFACE, typename LabelT,
typename VID_T, typename... VERTEX_SET_TT, int tag_id>
class CollectionOfVecBuilder<PropT, GRAPH_INTERFACE,
RowVertexSetImpl<LabelT, VID_T, VERTEX_SET_TT...>,
tag_id> {
public:
using set_t = RowVertexSetImpl<LabelT, VID_T, VERTEX_SET_TT...>;
using graph_prop_getter_t =
typename GRAPH_INTERFACE::template single_prop_getter_t<PropT>;
using PROP_GETTER_T =
RowVertexSetPropGetter<tag_id, graph_prop_getter_t,
typename set_t::index_ele_tuple_t>;
CollectionOfVecBuilder(const set_t& set, const GRAPH_INTERFACE& graph,
PropNameArray<PropT>& prop_names)
: prop_getter_(create_prop_getter_impl<tag_id, PropT>(set, graph,
prop_names[0])) {}
// insert tuple at index ind.
template <typename IND_TUPLE>
bool insert(size_t ind, IND_TUPLE& tuple) {
auto cur = gs::get_from_tuple<tag_id>(tuple);
// just count times.
while (vec_.size() <= ind) {
vec_.emplace_back(std::vector<PropT>());
}
using input_ele_t = typename std::remove_reference<decltype(cur)>::type;
if (NullRecordCreator<input_ele_t>::GetNull() == cur) {
return false;
}
// emplace the element to vector
vec_[ind].emplace_back(prop_getter_.get_view(cur));
return true;
}
template <typename IND_TUPLE, typename DATA_TUPLE>
bool insert(size_t ind, const IND_TUPLE& tuple, const DATA_TUPLE& data) {
return insert(ind, tuple);
}
CollectionOfVec<PropT> Build() {
return CollectionOfVec<PropT>(std::move(vec_));
}
private:
std::vector<std::vector<PropT>> vec_;
PROP_GETTER_T prop_getter_;
};
template <typename GRAPH_INTERFACE, typename LabelT, typename VID_T,
typename... VERTEX_SET_TT, int tag_id>
class CollectionOfVecBuilder<grape::EmptyType, GRAPH_INTERFACE,
RowVertexSetImpl<LabelT, VID_T, VERTEX_SET_TT...>,
tag_id> {
public:
using set_t = RowVertexSetImpl<LabelT, VID_T, VERTEX_SET_TT...>;
CollectionOfVecBuilder(LabelT label) : label_(label) {}
// insert tuple at index ind.
template <typename IND_TUPLE>
bool insert(size_t ind, IND_TUPLE& tuple) {
auto cur = gs::get_from_tuple<tag_id>(tuple);
// just count times.
while (vec_.size() <= ind) {
vec_.emplace_back(std::vector<GlobalId>());
}
using input_ele_t = typename std::remove_reference<decltype(cur)>::type;
if (NullRecordCreator<input_ele_t>::GetNull() == cur) {
return false;
}
// emplace the element to vector
vec_[ind].emplace_back(GlobalId(label_, cur));
return true;
}
template <typename IND_TUPLE, typename DATA_TUPLE>
bool insert(size_t ind, const IND_TUPLE& tuple, const DATA_TUPLE& data) {
return insert(ind, tuple);
}
CollectionOfVec<GlobalId> Build() {
return CollectionOfVec<GlobalId>(std::move(vec_));
}
private:
LabelT label_;
std::vector<std::vector<GlobalId>> vec_;
};
template <typename GRAPH_INTERFACE, typename LabelT, typename VID_T,
typename... VERTEX_SET_TT, int tag_id>
class CollectionOfVecBuilder<
grape::EmptyType, GRAPH_INTERFACE,
TwoLabelVertexSetImpl<VID_T, LabelT, VERTEX_SET_TT...>, tag_id> {
public:
using set_t = TwoLabelVertexSetImpl<VID_T, LabelT, VERTEX_SET_TT...>;
CollectionOfVecBuilder(std::array<LabelT, 2> labels) : labels_(labels) {}
// insert tuple at index ind.
template <typename IND_TUPLE>
bool insert(size_t ind, IND_TUPLE& tuple) {
auto cur = gs::get_from_tuple<tag_id>(tuple);
// just count times.
while (vec_.size() <= ind) {
vec_.emplace_back(std::vector<GlobalId>());
}
using input_ele_t = typename std::remove_reference<decltype(cur)>::type;
if (NullRecordCreator<input_ele_t>::GetNull() == cur) {
return false;
}
// emplace the element to vector
auto label_ind = std::get<1>(cur);
CHECK(label_ind < 2);
vec_[ind].emplace_back(GlobalId(labels_[label_ind], std::get<2>(cur)));
return true;
}
template <typename IND_TUPLE, typename DATA_TUPLE>
bool insert(size_t ind, const IND_TUPLE& tuple, const DATA_TUPLE& data) {
return insert(ind, tuple);
}
CollectionOfVec<GlobalId> Build() {
return CollectionOfVec<GlobalId>(std::move(vec_));
}
private:
std::array<LabelT, 2> labels_;
std::vector<std::vector<GlobalId>> vec_;
};
template <typename PropT, typename GRAPH_INTERFACE, typename LabelT,
typename VID_T, typename... VERTEX_SET_TT, int tag_id>
class CollectionOfVecBuilder<
PropT, GRAPH_INTERFACE,
TwoLabelVertexSetImpl<VID_T, LabelT, VERTEX_SET_TT...>, tag_id> {
public:
using set_t = TwoLabelVertexSetImpl<VID_T, LabelT, VERTEX_SET_TT...>;
using graph_prop_getter_t =
typename GRAPH_INTERFACE::template single_prop_getter_t<PropT>;
using PROP_GETTER_T =
TwoLabelVertexSetImplPropGetter<tag_id, graph_prop_getter_t,
typename set_t::index_ele_tuple_t>;
CollectionOfVecBuilder(const set_t& set, const GRAPH_INTERFACE& graph,
PropNameArray<PropT>& prop_names)
: prop_getter_(create_prop_getter_impl<tag_id, PropT>(set, graph,
prop_names[0])) {}
// insert tuple at index ind.
template <typename IND_TUPLE>
bool insert(size_t ind, IND_TUPLE& tuple) {
auto cur = gs::get_from_tuple<tag_id>(tuple);
// just count times.
while (vec_.size() <= ind) {
vec_.emplace_back(std::vector<PropT>());
}
using input_ele_t = typename std::remove_reference<decltype(cur)>::type;
if (NullRecordCreator<input_ele_t>::GetNull() == cur) {
return false;
}
// emplace the element to vector
vec_[ind].emplace_back(prop_getter_.get_view(cur));
return true;
}
template <typename IND_TUPLE, typename DATA_TUPLE>
void insert(size_t ind, const IND_TUPLE& tuple, const DATA_TUPLE& data) {
return insert(ind, tuple);
}
CollectionOfVec<PropT> Build() {
return CollectionOfVec<PropT>(std::move(vec_));
}
private:
PROP_GETTER_T prop_getter_;
std::vector<std::vector<PropT>> vec_;
};
// Aggregating for average.
template <typename PropT, typename GRAPH_INTERFACE, typename SET_T, int tag_id>
class AvgBuilder;
template <typename PropT, typename GRAPH_INTERFACE, typename LabelT,
typename VID_T, typename... VERTEX_SET_TT, int tag_id>
class AvgBuilder<PropT, GRAPH_INTERFACE,
TwoLabelVertexSetImpl<VID_T, LabelT, VERTEX_SET_TT...>,
tag_id> {
public:
using set_t = TwoLabelVertexSetImpl<VID_T, LabelT, VERTEX_SET_TT...>;
using index_ele_t = typename set_t::index_ele_tuple_t;
using graph_prop_getter_t =
typename GRAPH_INTERFACE::template single_prop_getter_t<PropT>;
using PROP_GETTER_T =
TwoLabelVertexSetImplPropGetter<tag_id, graph_prop_getter_t,
typename set_t::index_ele_tuple_t>;
AvgBuilder(const set_t& set, const GRAPH_INTERFACE& graph,
PropNameArray<PropT> prop_names)
: prop_getter_(create_prop_getter_impl<tag_id, PropT>(set, graph,
prop_names[0])) {}
template <typename IND_TUPLE, typename DATA_TUPLE>
bool insert(size_t ind, const IND_TUPLE& tuple, const DATA_TUPLE& data) {
while (vec_.size() <= ind) {
vec_.emplace_back(std::pair<size_t, PropT>(0, (PropT) 0));
}
auto cur = gs::get_from_tuple<tag_id>(tuple);
using ele_t = typename set_t::index_ele_tuple_t;
if (NullRecordCreator<ele_t>::GetNull() == cur) {
return false;
}
auto prop = prop_getter_.get_view(cur);
if (IsNull(prop)) {
return false;
}
vec_[ind].first += 1;
vec_[ind].second += prop;
return true;
}
Collection<PropT> Build() {
std::vector<PropT> res;
res.reserve(vec_.size());
for (auto& pair : vec_) {
if (pair.first == 0) {
res.emplace_back(NullRecordCreator<PropT>::GetNull());
} else {
res.emplace_back(pair.second / pair.first);
}
}
return Collection<PropT>(std::move(res));
}
private:
std::vector<std::pair<size_t, PropT>> vec_;
PROP_GETTER_T prop_getter_;
};
template <typename PropT, typename GRAPH_INTERFACE, typename LabelT,
typename VID_T, typename... VERTEX_SET_TT, int tag_id>
class AvgBuilder<PropT, GRAPH_INTERFACE,
RowVertexSetImpl<LabelT, VID_T, VERTEX_SET_TT...>, tag_id> {
public:
using set_t = RowVertexSetImpl<LabelT, VID_T, VERTEX_SET_TT...>;
using index_ele_t = typename set_t::index_ele_tuple_t;
using graph_prop_getter_t =
typename GRAPH_INTERFACE::template single_prop_getter_t<PropT>;
using PROP_GETTER_T =
RowVertexSetPropGetter<tag_id, graph_prop_getter_t,
typename set_t::index_ele_tuple_t>;
AvgBuilder(const set_t& set, const GRAPH_INTERFACE& graph,
PropNameArray<PropT> prop_names)
: prop_getter_(create_prop_getter_impl<tag_id, PropT>(set, graph,
prop_names[0])) {}
template <typename IND_TUPLE, typename DATA_TUPLE>
bool insert(size_t ind, const IND_TUPLE& tuple, const DATA_TUPLE& data) {
while (vec_.size() <= ind) {
vec_.emplace_back(std::pair<size_t, PropT>(0, (PropT) 0));
}
auto cur = gs::get_from_tuple<tag_id>(tuple);
using ele_t = typename set_t::index_ele_tuple_t;
if (NullRecordCreator<ele_t>::GetNull() == cur) {
return false;
}
auto prop = prop_getter_.get_view(cur);
if (IsNull(prop)) {
return false;
}
vec_[ind].first += 1;
vec_[ind].second += prop;
return true;
}
Collection<PropT> Build() {
std::vector<PropT> res;
res.reserve(vec_.size());
for (auto& pair : vec_) {
if (pair.first == 0) {
res.emplace_back(NullRecordCreator<PropT>::GetNull());
} else {
res.emplace_back(pair.second / pair.first);
}
}
return Collection<PropT>(std::move(res));
}
private:
std::vector<std::pair<size_t, PropT>> vec_;
PROP_GETTER_T prop_getter_;
};
} // namespace gs
#endif // ENGINES_HQPS_DS_COLLECTION_H_