blob: 4fc1d6e3743d8a71e010679c482fa054a140933f [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 GAR_GRAPH_H_
#define GAR_GRAPH_H_
#include <any>
#include <limits>
#include <map>
#include <memory>
#include <string>
#include <utility>
#include <variant>
#include <vector>
#include "gar/graph_info.h"
#include "gar/reader/arrow_chunk_reader.h"
#include "gar/util/adj_list_type.h"
#include "gar/util/filesystem.h"
#include "gar/util/reader_util.h"
#include "gar/util/util.h"
// forward declarations
namespace arrow {
class ChunkedArray;
class Array;
} // namespace arrow
namespace graphar {
/**
* @brief Vertex contains information of certain vertex.
*/
class Vertex {
public:
/**
* Initialize the Vertex.
*
* @param id The vertex id.
* @param readers A set of readers for reading the vertex properties.
*/
explicit Vertex(
IdType id,
std::vector<VertexPropertyArrowChunkReader>& readers); // NOLINT
/**
* @brief Get the id of the vertex.
*
* @return The id of the vertex.
*/
inline IdType id() const noexcept { return id_; }
/**
* @brief Get the property value of the vertex.
*
* @param property The property name.
* @return Result: The property value or error.
*/
template <typename T>
Result<T> property(const std::string& property) const;
private:
IdType id_;
std::map<std::string, std::any> properties_;
std::map<std::string, std::shared_ptr<arrow::Array>> list_properties_;
};
/**
* @brief Edge contains information of certain edge.
*/
class Edge {
public:
/**
* Initialize the Edge.
*
* @param adj_list_reader The reader for reading the adjList.
* @param property_readers A set of readers for reading the edge properties.
*/
explicit Edge(AdjListArrowChunkReader& adj_list_reader, // NOLINT
std::vector<AdjListPropertyArrowChunkReader>&
property_readers); // NOLINT
/**
* @brief Get source id of the edge.
*
* @return The id of the source vertex.
*/
inline IdType source() const noexcept { return src_id_; }
/**
* @brief Get destination id of the edge.
*
* @return The id of the destination vertex.
*/
inline IdType destination() const noexcept { return dst_id_; }
/**
* @brief Get the property value of the edge.
*
* @param property The property name.
* @return Result: The property value or error.
*/
template <typename T>
Result<T> property(const std::string& property) const;
private:
IdType src_id_, dst_id_;
std::map<std::string, std::any> properties_;
std::map<std::string, std::shared_ptr<arrow::Array>> list_properties_;
};
/**
* @brief The iterator for traversing a type of vertices.
*
*/
class VertexIter {
public:
/**
* Initialize the iterator.
*
* @param vertex_info The vertex info that describes the vertex type.
* @param prefix The absolute prefix.
* @param offset The current offset of the readers.
*/
explicit VertexIter(const std::shared_ptr<VertexInfo>& vertex_info,
const std::string& prefix, IdType offset) noexcept {
for (const auto& pg : vertex_info->GetPropertyGroups()) {
readers_.emplace_back(vertex_info, pg, prefix);
}
cur_offset_ = offset;
}
/** Copy constructor. */
VertexIter(const VertexIter& other)
: readers_(other.readers_), cur_offset_(other.cur_offset_) {}
/** Construct and return the vertex of the current offset. */
Vertex operator*() noexcept {
for (auto& reader : readers_) {
reader.seek(cur_offset_);
}
return Vertex(cur_offset_, readers_);
}
/** Get the vertex id of the current offset. */
IdType id() { return cur_offset_; }
/** Get the value for a property of the current vertex. */
template <typename T>
Result<T> property(const std::string& property) noexcept {
std::shared_ptr<arrow::ChunkedArray> column(nullptr);
for (auto& reader : readers_) {
reader.seek(cur_offset_);
GAR_ASSIGN_OR_RAISE(auto chunk_table, reader.GetChunk());
column = util::GetArrowColumnByName(chunk_table, property);
if (column != nullptr) {
break;
}
}
if (column != nullptr) {
auto array = util::GetArrowArrayByChunkIndex(column, 0);
GAR_ASSIGN_OR_RAISE(auto data, util::GetArrowArrayData(array));
return util::ValueGetter<T>::Value(data, 0);
}
return Status::KeyError("Property with name ", property,
" does not exist in the vertex.");
}
/** The prefix increment operator. */
VertexIter& operator++() noexcept {
++cur_offset_;
return *this;
}
/** The postfix increment operator. */
VertexIter operator++(int) {
VertexIter ret(*this);
++cur_offset_;
return ret;
}
/** The add operator. */
VertexIter operator+(IdType offset) {
VertexIter ret(*this);
ret.cur_offset_ += offset;
return ret;
}
/** The add-assign operator. */
VertexIter& operator+=(IdType offset) {
cur_offset_ += offset;
return *this;
}
/** The equality operator. */
bool operator==(const VertexIter& rhs) const noexcept {
return cur_offset_ == rhs.cur_offset_;
}
/** The inequality operator. */
bool operator!=(const VertexIter& rhs) const noexcept {
return cur_offset_ != rhs.cur_offset_;
}
private:
std::vector<VertexPropertyArrowChunkReader> readers_;
IdType cur_offset_;
};
/**
* @brief VerticesCollection is designed for reading a collection of vertices.
*
*/
class VerticesCollection {
public:
/**
* @brief Initialize the VerticesCollection.
*
* @param vertex_info The vertex info that describes the vertex type.
* @param prefix The absolute prefix.
*/
explicit VerticesCollection(const std::shared_ptr<VertexInfo>& vertex_info,
const std::string& prefix)
: vertex_info_(std::move(vertex_info)), prefix_(prefix) {
// get the vertex num
std::string base_dir;
GAR_ASSIGN_OR_RAISE_ERROR(auto fs,
FileSystemFromUriOrPath(prefix, &base_dir));
GAR_ASSIGN_OR_RAISE_ERROR(auto file_path,
vertex_info->GetVerticesNumFilePath());
std::string vertex_num_path = base_dir + file_path;
GAR_ASSIGN_OR_RAISE_ERROR(vertex_num_,
fs->ReadFileToValue<IdType>(vertex_num_path));
}
/** The iterator pointing to the first vertex. */
VertexIter begin() noexcept { return VertexIter(vertex_info_, prefix_, 0); }
/** The iterator pointing to the past-the-end element. */
VertexIter end() noexcept {
return VertexIter(vertex_info_, prefix_, vertex_num_);
}
/** The iterator pointing to the vertex with specific id. */
VertexIter find(IdType id) { return VertexIter(vertex_info_, prefix_, id); }
/** Get the number of vertices in the collection. */
size_t size() const noexcept { return vertex_num_; }
/**
* @brief Construct a VerticesCollection from graph info and vertex label.
*
* @param graph_info The graph info.
* @param label The vertex label.
*/
static Result<std::shared_ptr<VerticesCollection>> Make(
const std::shared_ptr<GraphInfo>& graph_info, const std::string& label) {
auto vertex_info = graph_info->GetVertexInfo(label);
if (!vertex_info) {
return Status::KeyError("The vertex ", label, " doesn't exist.");
}
return std::make_shared<VerticesCollection>(vertex_info,
graph_info->GetPrefix());
}
private:
std::shared_ptr<VertexInfo> vertex_info_;
std::string prefix_;
IdType vertex_num_;
};
/**
* @brief The iterator for traversing a type of edges.
*
*/
class EdgeIter {
public:
/**
* Initialize the iterator.
*
* @param edge_info The edge info that describes the edge type.
* @param prefix The absolute prefix.
* @param adj_list_type The type of adjList.
* @param global_chunk_index The global index of the current edge chunk.
* @param offset The current offset in the current edge chunk.
* @param chunk_begin The index of the first chunk.
* @param chunk_end The index of the last chunk.
* @param index_converter The converter for transforming the edge chunk
* indices.
*/
explicit EdgeIter(const std::shared_ptr<EdgeInfo>& edge_info,
const std::string& prefix, AdjListType adj_list_type,
IdType global_chunk_index, IdType offset,
IdType chunk_begin, IdType chunk_end,
std::shared_ptr<util::IndexConverter> index_converter)
: adj_list_reader_(edge_info, adj_list_type, prefix),
global_chunk_index_(global_chunk_index),
cur_offset_(offset),
chunk_size_(edge_info->GetChunkSize()),
src_chunk_size_(edge_info->GetSrcChunkSize()),
dst_chunk_size_(edge_info->GetDstChunkSize()),
num_row_of_chunk_(0),
chunk_begin_(chunk_begin),
chunk_end_(chunk_end),
adj_list_type_(adj_list_type),
index_converter_(index_converter) {
vertex_chunk_index_ =
index_converter->GlobalChunkIndexToIndexPair(global_chunk_index).first;
adj_list_reader_.seek_chunk_index(vertex_chunk_index_);
const auto& property_groups = edge_info->GetPropertyGroups();
for (const auto& pg : property_groups) {
property_readers_.emplace_back(edge_info, pg, adj_list_type, prefix),
property_readers_.back().seek_chunk_index(vertex_chunk_index_);
}
if (adj_list_type == AdjListType::ordered_by_source ||
adj_list_type == AdjListType::ordered_by_dest) {
offset_reader_ = std::make_shared<AdjListOffsetArrowChunkReader>(
edge_info, adj_list_type, prefix);
}
}
/** Copy constructor. */
EdgeIter(const EdgeIter& other)
: adj_list_reader_(other.adj_list_reader_),
offset_reader_(other.offset_reader_),
property_readers_(other.property_readers_),
global_chunk_index_(other.global_chunk_index_),
vertex_chunk_index_(other.vertex_chunk_index_),
cur_offset_(other.cur_offset_),
chunk_size_(other.chunk_size_),
src_chunk_size_(other.src_chunk_size_),
dst_chunk_size_(other.dst_chunk_size_),
num_row_of_chunk_(other.num_row_of_chunk_),
chunk_begin_(other.chunk_begin_),
chunk_end_(other.chunk_end_),
adj_list_type_(other.adj_list_type_),
index_converter_(other.index_converter_) {}
/** Construct and return the edge of the current offset. */
Edge operator*() {
adj_list_reader_.seek(cur_offset_);
for (auto& reader : property_readers_) {
reader.seek(cur_offset_);
}
return Edge(adj_list_reader_, property_readers_);
}
/** Get the source vertex id for the current edge. */
IdType source();
/** Get the destination vertex id for the current edge. */
IdType destination();
/** Get the value of a property for the current edge. */
template <typename T>
Result<T> property(const std::string& property) noexcept {
std::shared_ptr<arrow::ChunkedArray> column(nullptr);
for (auto& reader : property_readers_) {
reader.seek(cur_offset_);
GAR_ASSIGN_OR_RAISE(auto chunk_table, reader.GetChunk());
column = util::GetArrowColumnByName(chunk_table, property);
if (column != nullptr) {
break;
}
}
if (column != nullptr) {
auto array = util::GetArrowArrayByChunkIndex(column, 0);
GAR_ASSIGN_OR_RAISE(auto data, util::GetArrowArrayData(array));
return util::ValueGetter<T>::Value(data, 0);
}
return Status::KeyError("Property with name ", property,
" does not exist in the edge.");
}
/** The prefix increment operator. */
EdgeIter& operator++() {
if (num_row_of_chunk_ == 0) {
adj_list_reader_.seek(cur_offset_);
GAR_ASSIGN_OR_RAISE_ERROR(num_row_of_chunk_,
adj_list_reader_.GetRowNumOfChunk());
}
auto st = adj_list_reader_.seek(++cur_offset_);
if (st.ok() && num_row_of_chunk_ != chunk_size_) {
// check the row offset is overflow
auto row_offset = cur_offset_ % chunk_size_;
if (row_offset >= num_row_of_chunk_) {
cur_offset_ = (cur_offset_ / chunk_size_ + 1) * chunk_size_;
adj_list_reader_.seek(cur_offset_);
st =
Status::KeyError("The row offset is overflow, move to next chunk.");
}
}
if (st.ok() && num_row_of_chunk_ == chunk_size_ &&
cur_offset_ % chunk_size_ == 0) {
GAR_ASSIGN_OR_RAISE_ERROR(num_row_of_chunk_,
adj_list_reader_.GetRowNumOfChunk());
++global_chunk_index_;
}
if (st.IsKeyError()) {
st = adj_list_reader_.next_chunk();
++global_chunk_index_;
++vertex_chunk_index_;
if (!st.IsIndexError()) {
GAR_ASSIGN_OR_RAISE_ERROR(num_row_of_chunk_,
adj_list_reader_.GetRowNumOfChunk());
for (auto& reader : property_readers_) {
reader.next_chunk();
}
}
cur_offset_ = 0;
adj_list_reader_.seek(cur_offset_);
}
return *this;
}
/** The postfix increment operator. */
EdgeIter operator++(int) {
EdgeIter ret(*this);
this->operator++();
return ret;
}
/** The copy assignment operator. */
EdgeIter operator=(const EdgeIter& other) {
adj_list_reader_ = other.adj_list_reader_;
offset_reader_ = other.offset_reader_;
property_readers_ = other.property_readers_;
global_chunk_index_ = other.global_chunk_index_;
vertex_chunk_index_ = other.vertex_chunk_index_;
cur_offset_ = other.cur_offset_;
chunk_size_ = other.chunk_size_;
src_chunk_size_ = other.src_chunk_size_;
dst_chunk_size_ = other.dst_chunk_size_;
num_row_of_chunk_ = other.num_row_of_chunk_;
chunk_begin_ = other.chunk_begin_;
chunk_end_ = other.chunk_end_;
adj_list_type_ = other.adj_list_type_;
index_converter_ = other.index_converter_;
return *this;
}
/** The equality operator. */
bool operator==(const EdgeIter& rhs) const noexcept {
return global_chunk_index_ == rhs.global_chunk_index_ &&
cur_offset_ == rhs.cur_offset_ &&
adj_list_type_ == rhs.adj_list_type_;
}
/** The inequality operator. */
bool operator!=(const EdgeIter& rhs) const noexcept {
return global_chunk_index_ != rhs.global_chunk_index_ ||
cur_offset_ != rhs.cur_offset_ ||
adj_list_type_ != rhs.adj_list_type_;
}
/** Get the global index of the current edge chunk. */
IdType global_chunk_index() const { return global_chunk_index_; }
/** Get the current offset in the current chunk. */
IdType cur_offset() const { return cur_offset_; }
/**
* Let the input iterator to point to the first out-going edge of the
* vertex with specific id after the current position of the iterator.
*
* @param from The input iterator.
* @param id The vertex id.
* @return If such edge is found or not.
*/
bool first_src(const EdgeIter& from, IdType id);
/**
* Let the input iterator to point to the first incoming edge of the
* vertex with specific id after the current position of the iterator.
*
* @param from The input iterator.
* @param id The vertex id.
* @return If such edge is found or not.
*/
bool first_dst(const EdgeIter& from, IdType id);
/** Let the iterator to point to the begin. */
void to_begin() {
global_chunk_index_ = chunk_begin_;
cur_offset_ = 0;
vertex_chunk_index_ =
index_converter_->GlobalChunkIndexToIndexPair(global_chunk_index_)
.first;
refresh();
}
/** Check if the current position is the end. */
bool is_end() const { return global_chunk_index_ >= chunk_end_; }
/** Point to the next edge with the same source, return false if not found. */
bool next_src() {
if (is_end())
return false;
IdType id = this->source();
IdType pre_vertex_chunk_index = vertex_chunk_index_;
if (adj_list_type_ == AdjListType::ordered_by_source) {
this->operator++();
if (is_end() || this->source() != id)
return false;
else
return true;
}
this->operator++();
while (!is_end()) {
if (this->source() == id) {
return true;
}
if (adj_list_type_ == AdjListType::unordered_by_source) {
if (vertex_chunk_index_ > pre_vertex_chunk_index)
return false;
}
this->operator++();
}
return false;
}
/**
* Point to the next edge with the same destination, return false if not
* found.
*/
bool next_dst() {
if (is_end())
return false;
IdType id = this->destination();
IdType pre_vertex_chunk_index = vertex_chunk_index_;
if (adj_list_type_ == AdjListType::ordered_by_dest) {
this->operator++();
if (is_end() || this->destination() != id)
return false;
else
return true;
}
this->operator++();
while (!is_end()) {
if (this->destination() == id) {
return true;
}
if (adj_list_type_ == AdjListType::unordered_by_dest) {
if (vertex_chunk_index_ > pre_vertex_chunk_index)
return false;
}
this->operator++();
}
return false;
}
/**
* Point to the next edge with the specific source, return false if not
* found.
*/
bool next_src(IdType id) {
if (is_end())
return false;
this->operator++();
return this->first_src(*this, id);
}
/**
* Point to the next edge with the specific destination, return false if
* not found.
*/
bool next_dst(IdType id) {
if (is_end())
return false;
this->operator++();
return this->first_dst(*this, id);
}
private:
// Refresh the readers to point to the current position.
void refresh() {
adj_list_reader_.seek_chunk_index(vertex_chunk_index_);
adj_list_reader_.seek(cur_offset_);
for (auto& reader : property_readers_) {
reader.seek_chunk_index(vertex_chunk_index_);
}
GAR_ASSIGN_OR_RAISE_ERROR(num_row_of_chunk_,
adj_list_reader_.GetRowNumOfChunk());
}
private:
AdjListArrowChunkReader adj_list_reader_;
std::shared_ptr<AdjListOffsetArrowChunkReader> offset_reader_;
std::vector<AdjListPropertyArrowChunkReader> property_readers_;
IdType global_chunk_index_;
IdType vertex_chunk_index_;
IdType cur_offset_;
IdType chunk_size_;
IdType src_chunk_size_;
IdType dst_chunk_size_;
IdType num_row_of_chunk_;
IdType chunk_begin_, chunk_end_;
AdjListType adj_list_type_;
std::shared_ptr<util::IndexConverter> index_converter_;
friend class OBSEdgeCollection;
friend class OBDEdgesCollection;
friend class UBSEdgesCollection;
friend class UBDEdgesCollection;
};
/**
* @brief EdgesCollection is designed for reading a collection of edges.
*/
class EdgesCollection {
public:
virtual ~EdgesCollection() {}
/** The iterator pointing to the first edge. */
virtual EdgeIter begin() {
if (begin_ == nullptr) {
EdgeIter iter(edge_info_, prefix_, adj_list_type_, chunk_begin_, 0,
chunk_begin_, chunk_end_, index_converter_);
begin_ = std::make_shared<EdgeIter>(iter);
}
return *begin_;
}
/** The iterator pointing to the past-the-end element. */
virtual EdgeIter end() {
if (end_ == nullptr) {
EdgeIter iter(edge_info_, prefix_, adj_list_type_, chunk_end_, 0,
chunk_begin_, chunk_end_, index_converter_);
end_ = std::make_shared<EdgeIter>(iter);
}
return *end_;
}
/** Get the number of edges in the collection. */
virtual size_t size() const noexcept { return edge_num_; }
/**
* Construct and return the iterator pointing to the first out-going edge of
* the vertex with specific id after the input iterator.
*
* @param id The vertex id.
* @param from The input iterator.
* @return The new constructed iterator.
*/
virtual EdgeIter find_src(IdType id, const EdgeIter& from) = 0;
/**
* Construct and return the iterator pointing to the first incoming edge of
* the vertex with specific id after the input iterator.
*
* @param id The vertex id.
* @param from The input iterator.
* @return The new constructed iterator.
*/
virtual EdgeIter find_dst(IdType id, const EdgeIter& from) = 0;
/**
* @brief Construct an EdgesCollection from graph info and edge label.
*
* @param graph_info The graph info.
* @param src_label The source vertex label.
* @param edge_label The edge label.
* @param dst_label The destination vertex label.
* @param adj_list_type The type of adjList.
* @param vertex_chunk_begin The index of the begin vertex chunk, default 0.
* @param vertex_chunk_end The index of the end vertex chunk (not included),
* default max.
*/
static Result<std::shared_ptr<EdgesCollection>> Make(
const std::shared_ptr<GraphInfo>& graph_info,
const std::string& src_label, const std::string& edge_label,
const std::string& dst_label, AdjListType adj_list_type,
const IdType vertex_chunk_begin = 0,
const IdType vertex_chunk_end =
std::numeric_limits<int64_t>::max()) noexcept;
protected:
/**
* @brief Initialize the EdgesCollection with a range of chunks.
*
* @param edge_info The edge info that describes the edge type.
* @param prefix The absolute prefix.
* @param vertex_chunk_begin The index of the begin vertex chunk.
* @param vertex_chunk_end The index of the end vertex chunk (not included).
* @param adj_list_type The type of adjList.
*/
explicit EdgesCollection(const std::shared_ptr<EdgeInfo>& edge_info,
const std::string& prefix, IdType vertex_chunk_begin,
IdType vertex_chunk_end, AdjListType adj_list_type)
: edge_info_(std::move(edge_info)),
prefix_(prefix),
adj_list_type_(adj_list_type) {
GAR_ASSIGN_OR_RAISE_ERROR(
auto vertex_chunk_num,
util::GetVertexChunkNum(prefix_, edge_info_, adj_list_type_));
std::vector<IdType> edge_chunk_nums(vertex_chunk_num, 0);
if (vertex_chunk_end == std::numeric_limits<int64_t>::max()) {
vertex_chunk_end = vertex_chunk_num;
}
chunk_begin_ = 0;
chunk_end_ = 0;
edge_num_ = 0;
for (IdType i = 0; i < vertex_chunk_num; ++i) {
GAR_ASSIGN_OR_RAISE_ERROR(
edge_chunk_nums[i],
util::GetEdgeChunkNum(prefix, edge_info, adj_list_type_, i));
if (i < vertex_chunk_begin) {
chunk_begin_ += edge_chunk_nums[i];
chunk_end_ += edge_chunk_nums[i];
}
if (i >= vertex_chunk_begin && i < vertex_chunk_end) {
chunk_end_ += edge_chunk_nums[i];
GAR_ASSIGN_OR_RAISE_ERROR(
auto chunk_edge_num_,
util::GetEdgeNum(prefix, edge_info, adj_list_type_, i));
edge_num_ += chunk_edge_num_;
}
}
index_converter_ =
std::make_shared<util::IndexConverter>(std::move(edge_chunk_nums));
}
std::shared_ptr<EdgeInfo> edge_info_;
std::string prefix_;
AdjListType adj_list_type_;
IdType chunk_begin_, chunk_end_;
std::shared_ptr<util::IndexConverter> index_converter_;
std::shared_ptr<EdgeIter> begin_, end_;
IdType edge_num_;
};
/**
* @brief Ordered By Source EdgesCollection implementation.
*
*/
class OBSEdgeCollection : public EdgesCollection {
using Base = EdgesCollection;
public:
/**
* @brief Initialize the OBSEdgeCollection with a range of chunks.
*
* @param edge_info The edge info that describes the edge type.
* @param prefix The absolute prefix.
* @param vertex_chunk_begin The index of the begin vertex chunk.
* @param vertex_chunk_end The index of the end vertex chunk (not included).
*/
explicit OBSEdgeCollection(
const std::shared_ptr<EdgeInfo>& edge_info, const std::string& prefix,
IdType vertex_chunk_begin = 0,
IdType vertex_chunk_end = std::numeric_limits<int64_t>::max())
: Base(edge_info, prefix, vertex_chunk_begin, vertex_chunk_end,
AdjListType::ordered_by_source) {}
/**
* Construct and return the iterator pointing to the first out-going edge of
* the vertex with specific id after the input iterator.
*
* @param id The vertex id.
* @param from The input iterator.
* @return The new constructed iterator.
*/
EdgeIter find_src(IdType id, const EdgeIter& from) override {
auto result =
util::GetAdjListOffsetOfVertex(edge_info_, prefix_, adj_list_type_, id);
if (!result.status().ok()) {
return this->end();
}
auto begin_offset = result.value().first;
auto end_offset = result.value().second;
if (begin_offset >= end_offset) {
return this->end();
}
auto begin_global_chunk_index =
index_converter_->IndexPairToGlobalChunkIndex(
id / edge_info_->GetSrcChunkSize(),
begin_offset / edge_info_->GetChunkSize());
auto end_global_chunk_index = index_converter_->IndexPairToGlobalChunkIndex(
id / edge_info_->GetSrcChunkSize(),
end_offset / edge_info_->GetChunkSize());
if (begin_global_chunk_index > from.global_chunk_index_) {
return EdgeIter(edge_info_, prefix_, adj_list_type_,
begin_global_chunk_index, begin_offset, chunk_begin_,
chunk_end_, index_converter_);
} else if (end_global_chunk_index < from.global_chunk_index_) {
return this->end();
} else {
if (begin_offset > from.cur_offset_) {
return EdgeIter(edge_info_, prefix_, adj_list_type_,
begin_global_chunk_index, begin_offset, chunk_begin_,
chunk_end_, index_converter_);
} else if (end_offset <= from.cur_offset_) {
return this->end();
} else {
return EdgeIter(edge_info_, prefix_, adj_list_type_,
from.global_chunk_index_, from.cur_offset_,
chunk_begin_, chunk_end_, index_converter_);
}
}
return this->end();
}
/**
* Construct and return the iterator pointing to the first incoming edge of
* the vertex with specific id after the input iterator.
*
* @param id The vertex id.
* @param from The input iterator.
* @return The new constructed iterator.
*/
EdgeIter find_dst(IdType id, const EdgeIter& from) override {
EdgeIter iter(from);
auto end = this->end();
while (iter != end) {
auto edge = *iter;
if (edge.destination() == id) {
break;
}
++iter;
}
return iter;
}
};
/**
* @brief Ordered By Destination EdgesCollection implementation.
*/
class OBDEdgesCollection : public EdgesCollection {
using Base = EdgesCollection;
public:
/**
* @brief Initialize the OBDEdgesCollection with a range of chunks.
*
* @param edge_info The edge info that describes the edge type.
* @param prefix The absolute prefix.
* @param vertex_chunk_begin The index of the begin vertex chunk.
* @param vertex_chunk_end The index of the end vertex chunk (not included).
*/
explicit OBDEdgesCollection(
const std::shared_ptr<EdgeInfo>& edge_info, const std::string& prefix,
IdType vertex_chunk_begin = 0,
IdType vertex_chunk_end = std::numeric_limits<int64_t>::max())
: Base(edge_info, prefix, vertex_chunk_begin, vertex_chunk_end,
AdjListType::ordered_by_dest) {}
/**
* Construct and return the iterator pointing to the first out-going edge of
* the vertex with specific id after the input iterator.
*
* @param id The vertex id.
* @param from The input iterator.
* @return The new constructed iterator.
*/
EdgeIter find_src(IdType id, const EdgeIter& from) override {
EdgeIter iter(from);
auto end = this->end();
while (iter != end) {
auto edge = *iter;
if (edge.source() == id) {
break;
}
++iter;
}
return iter;
}
/**
* Construct and return the iterator pointing to the first incoming edge of
* the vertex with specific id after the input iterator.
*
* @param id The vertex id.
* @param from The input iterator.
* @return The new constructed iterator.
*/
EdgeIter find_dst(IdType id, const EdgeIter& from) override {
auto result =
util::GetAdjListOffsetOfVertex(edge_info_, prefix_, adj_list_type_, id);
if (!result.status().ok()) {
return this->end();
}
auto begin_offset = result.value().first;
auto end_offset = result.value().second;
if (begin_offset >= end_offset) {
return this->end();
}
auto begin_global_chunk_index =
index_converter_->IndexPairToGlobalChunkIndex(
id / edge_info_->GetDstChunkSize(),
begin_offset / edge_info_->GetChunkSize());
auto end_global_chunk_index = index_converter_->IndexPairToGlobalChunkIndex(
id / edge_info_->GetDstChunkSize(),
end_offset / edge_info_->GetChunkSize());
if (begin_global_chunk_index > from.global_chunk_index_) {
return EdgeIter(edge_info_, prefix_, adj_list_type_,
begin_global_chunk_index, begin_offset, chunk_begin_,
chunk_end_, index_converter_);
} else if (end_global_chunk_index < from.global_chunk_index_) {
return this->end();
} else {
if (begin_offset >= from.cur_offset_) {
return EdgeIter(edge_info_, prefix_, adj_list_type_,
begin_global_chunk_index, begin_offset, chunk_begin_,
chunk_end_, index_converter_);
} else if (end_offset <= from.cur_offset_) {
return this->end();
} else {
return EdgeIter(edge_info_, prefix_, adj_list_type_,
from.global_chunk_index_, from.cur_offset_,
chunk_begin_, chunk_end_, index_converter_);
}
}
return this->end();
}
};
/**
* @brief Unordered By Source EdgesCollection implementation.
*/
class UBSEdgesCollection : public EdgesCollection {
using Base = EdgesCollection;
public:
/**
* @brief Initialize the EdgesCollection with a range of chunks.
*
* @param edge_info The edge info that describes the edge type.
* @param prefix The absolute prefix.
* @param vertex_chunk_begin The index of the begin vertex chunk.
* @param vertex_chunk_end The index of the end vertex chunk (not included).
*/
explicit UBSEdgesCollection(
const std::shared_ptr<EdgeInfo>& edge_info, const std::string& prefix,
IdType vertex_chunk_begin = 0,
IdType vertex_chunk_end = std::numeric_limits<int64_t>::max())
: Base(edge_info, prefix, vertex_chunk_begin, vertex_chunk_end,
AdjListType::unordered_by_source) {}
/**
* Construct and return the iterator pointing to the first out-going edge of
* the vertex with specific id after the input iterator.
*
* @param id The vertex id.
* @param from The input iterator.
* @return The new constructed iterator.
*/
EdgeIter find_src(IdType id, const EdgeIter& from) override {
EdgeIter iter(from);
auto end = this->end();
while (iter != end) {
auto edge = *iter;
if (edge.source() == id) {
break;
}
++iter;
}
return iter;
}
/**
* Construct and return the iterator pointing to the first incoming edge of
* the vertex with specific id after the input iterator.
*
* @param id The vertex id.
* @param from The input iterator.
* @return The new constructed iterator.
*/
EdgeIter find_dst(IdType id, const EdgeIter& from) override {
EdgeIter iter(from);
auto end = this->end();
while (iter != end) {
auto edge = *iter;
if (edge.destination() == id) {
break;
}
++iter;
}
return iter;
}
};
/**
* @brief Unordered By Destination EdgesCollection implementation.
*/
class UBDEdgesCollection : public EdgesCollection {
using Base = EdgesCollection;
public:
/**
* @brief Initialize the EdgesCollection with a range of chunks.
*
* @param edge_info The edge info that describes the edge type.
* @param prefix The absolute prefix.
* @param vertex_chunk_begin The index of the begin vertex chunk.
* @param vertex_chunk_end The index of the end vertex chunk (not included).
*/
explicit UBDEdgesCollection(
const std::shared_ptr<EdgeInfo>& edge_info, const std::string& prefix,
IdType vertex_chunk_begin = 0,
IdType vertex_chunk_end = std::numeric_limits<int64_t>::max())
: Base(edge_info, prefix, vertex_chunk_begin, vertex_chunk_end,
AdjListType::unordered_by_dest) {}
/**
* Construct and return the iterator pointing to the first out-going edge of
* the vertex with specific id after the input iterator.
*
* @param id The vertex id.
* @param from The input iterator.
* @return The new constructed iterator.
*/
EdgeIter find_src(IdType id, const EdgeIter& from) override {
EdgeIter iter(from);
auto end = this->end();
while (iter != end) {
auto edge = *iter;
if (edge.source() == id) {
break;
}
++iter;
}
return iter;
}
/**
* Construct and return the iterator pointing to the first incoming edge of
* the vertex with specific id after the input iterator.
*
* @param id The vertex id.
* @param from The input iterator.
* @return The new constructed iterator.
*/
EdgeIter find_dst(IdType id, const EdgeIter& from) override {
EdgeIter iter(from);
auto end = this->end();
while (iter != end) {
auto edge = *iter;
if (edge.destination() == id) {
break;
}
++iter;
}
return iter;
}
};
} // namespace graphar
#endif // GAR_GRAPH_H_