2017-09-08 17:29:54 +08:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <utility>
|
|
|
|
#include <vector>
|
|
|
|
|
2017-10-11 19:19:10 +08:00
|
|
|
#include "glog/logging.h"
|
2018-01-12 22:17:04 +08:00
|
|
|
|
2017-09-08 17:29:54 +08:00
|
|
|
#include "mvcc/version_list.hpp"
|
2017-11-14 15:47:50 +08:00
|
|
|
#include "storage/address.hpp"
|
2018-02-15 22:03:30 +08:00
|
|
|
#include "storage/address_types.hpp"
|
2018-01-16 17:09:15 +08:00
|
|
|
#include "storage/types.hpp"
|
2017-09-26 18:51:52 +08:00
|
|
|
#include "utils/algorithm.hpp"
|
2017-09-08 17:29:54 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* A data stucture that holds a number of edges. This implementation assumes
|
|
|
|
* that separate Edges instances are used for incoming and outgoing edges in a
|
2017-11-14 15:47:50 +08:00
|
|
|
* vertex (and consequently that edge Addresses are unique in it).
|
2017-09-08 17:29:54 +08:00
|
|
|
*/
|
|
|
|
class Edges {
|
2018-01-10 19:57:44 +08:00
|
|
|
private:
|
2017-09-08 17:29:54 +08:00
|
|
|
struct Element {
|
2018-02-15 22:03:30 +08:00
|
|
|
storage::VertexAddress vertex;
|
|
|
|
storage::EdgeAddress edge;
|
2018-01-16 17:09:15 +08:00
|
|
|
storage::EdgeType edge_type;
|
2017-09-08 17:29:54 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
/** Custom iterator that takes care of skipping edges when the destination
|
2017-09-26 18:51:52 +08:00
|
|
|
* vertex or edge types are known. */
|
2017-09-08 17:29:54 +08:00
|
|
|
class Iterator {
|
|
|
|
public:
|
|
|
|
/** Ctor that just sets the position. Used for normal iteration (that does
|
|
|
|
* not skip any edges), and for end-iterator creation in both normal and
|
|
|
|
* skipping iteration.
|
|
|
|
*
|
|
|
|
* @param iterator - Iterator in the underlying storage.
|
|
|
|
*/
|
|
|
|
explicit Iterator(std::vector<Element>::const_iterator iterator)
|
|
|
|
: position_(iterator) {}
|
|
|
|
|
2017-09-26 18:51:52 +08:00
|
|
|
/** Ctor used for creating the beginning iterator with known destination
|
2017-09-08 17:29:54 +08:00
|
|
|
* vertex.
|
|
|
|
*
|
|
|
|
* @param iterator - Iterator in the underlying storage.
|
|
|
|
* @param end - End iterator in the underlying storage.
|
2017-11-14 15:47:50 +08:00
|
|
|
* @param vertex - The destination vertex address. If empty the
|
2017-09-27 20:57:41 +08:00
|
|
|
* edges are not filtered on destination.
|
2017-09-26 18:51:52 +08:00
|
|
|
* @param edge_types - The edge types at least one of which must be matched.
|
2017-09-27 20:57:41 +08:00
|
|
|
* If nullptr edges are not filtered on type.
|
2017-09-08 17:29:54 +08:00
|
|
|
*/
|
|
|
|
Iterator(std::vector<Element>::const_iterator position,
|
2018-02-15 22:03:30 +08:00
|
|
|
std::vector<Element>::const_iterator end,
|
|
|
|
storage::VertexAddress vertex,
|
2018-01-16 17:09:15 +08:00
|
|
|
const std::vector<storage::EdgeType> *edge_types)
|
2017-09-27 20:57:41 +08:00
|
|
|
: position_(position),
|
|
|
|
end_(end),
|
|
|
|
vertex_(vertex),
|
|
|
|
edge_types_(edge_types) {
|
2017-09-08 17:29:54 +08:00
|
|
|
update_position();
|
|
|
|
}
|
|
|
|
|
|
|
|
Iterator &operator++() {
|
|
|
|
++position_;
|
|
|
|
update_position();
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
const Element &operator*() const { return *position_; }
|
2018-01-10 19:57:44 +08:00
|
|
|
const Element *operator->() const { return &(*position_); }
|
2017-09-08 17:29:54 +08:00
|
|
|
|
|
|
|
bool operator==(const Iterator &other) const {
|
|
|
|
return position_ == other.position_;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool operator!=(const Iterator &other) const { return !(*this == other); }
|
|
|
|
|
|
|
|
private:
|
|
|
|
std::vector<Element>::const_iterator position_;
|
|
|
|
// end_ is used only in update_position() to limit find.
|
|
|
|
std::vector<Element>::const_iterator end_;
|
|
|
|
|
2017-11-14 15:47:50 +08:00
|
|
|
// Optional predicates. If set they define which edges are skipped by the
|
2017-09-08 17:29:54 +08:00
|
|
|
// iterator. Only one can be not-null in the current implementation.
|
2018-02-15 22:03:30 +08:00
|
|
|
storage::VertexAddress vertex_{nullptr};
|
2017-09-26 18:51:52 +08:00
|
|
|
// For edge types we use a vector pointer because it's optional.
|
2018-01-16 17:09:15 +08:00
|
|
|
const std::vector<storage::EdgeType> *edge_types_ = nullptr;
|
2017-09-08 17:29:54 +08:00
|
|
|
|
|
|
|
/** Helper function that skips edges that don't satisfy the predicate
|
|
|
|
* present in this iterator. */
|
|
|
|
void update_position() {
|
2017-11-14 15:47:50 +08:00
|
|
|
if (vertex_.local()) {
|
2018-02-15 22:03:30 +08:00
|
|
|
position_ = std::find_if(
|
|
|
|
position_, end_,
|
|
|
|
[v = this->vertex_](const Element &e) { return e.vertex == v; });
|
2017-09-27 20:57:41 +08:00
|
|
|
}
|
|
|
|
if (edge_types_) {
|
2017-09-26 18:51:52 +08:00
|
|
|
position_ = std::find_if(position_, end_, [this](const Element &e) {
|
|
|
|
return utils::Contains(*edge_types_, e.edge_type);
|
|
|
|
});
|
2017-09-27 20:57:41 +08:00
|
|
|
}
|
2017-09-08 17:29:54 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
public:
|
|
|
|
/**
|
|
|
|
* Adds an edge to this structure.
|
|
|
|
*
|
2017-09-27 20:57:41 +08:00
|
|
|
* @param vertex - The destination vertex of the edge. That's the one
|
|
|
|
* opposite from the vertex that contains this `Edges` instance.
|
2017-09-08 17:29:54 +08:00
|
|
|
* @param edge - The edge.
|
|
|
|
* @param edge_type - Type of the edge.
|
|
|
|
*/
|
2018-02-15 22:03:30 +08:00
|
|
|
void emplace(storage::VertexAddress vertex, storage::EdgeAddress edge,
|
2018-01-16 17:09:15 +08:00
|
|
|
storage::EdgeType edge_type) {
|
2017-09-08 17:29:54 +08:00
|
|
|
storage_.emplace_back(Element{vertex, edge, edge_type});
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Removes an edge from this structure.
|
|
|
|
*/
|
2018-02-15 22:03:30 +08:00
|
|
|
void RemoveEdge(storage::EdgeAddress edge) {
|
2017-09-08 17:29:54 +08:00
|
|
|
auto found = std::find_if(
|
|
|
|
storage_.begin(), storage_.end(),
|
|
|
|
[edge](const Element &element) { return edge == element.edge; });
|
2017-10-11 19:19:10 +08:00
|
|
|
DCHECK(found != storage_.end()) << "Removing an edge that is not present";
|
2017-09-08 17:29:54 +08:00
|
|
|
*found = std::move(storage_.back());
|
|
|
|
storage_.pop_back();
|
|
|
|
}
|
|
|
|
|
|
|
|
auto size() const { return storage_.size(); }
|
|
|
|
auto begin() const { return Iterator(storage_.begin()); }
|
|
|
|
auto end() const { return Iterator(storage_.end()); }
|
|
|
|
|
|
|
|
/**
|
2017-09-27 20:57:41 +08:00
|
|
|
* Creates a beginning iterator that will skip edges whose destination
|
|
|
|
* vertex is not equal to the given vertex.
|
|
|
|
*
|
2017-11-14 15:47:50 +08:00
|
|
|
* @param vertex - The destination vertex Address. If empty the
|
2017-09-27 20:57:41 +08:00
|
|
|
* edges are not filtered on destination.
|
|
|
|
* @param edge_types - The edge types at least one of which must be matched.
|
|
|
|
* If nullptr edges are not filtered on type.
|
2017-09-08 17:29:54 +08:00
|
|
|
*/
|
2018-02-15 22:03:30 +08:00
|
|
|
auto begin(storage::VertexAddress vertex,
|
2018-01-16 17:09:15 +08:00
|
|
|
const std::vector<storage::EdgeType> *edge_types) const {
|
2017-09-27 20:57:41 +08:00
|
|
|
if (edge_types && edge_types->empty()) edge_types = nullptr;
|
|
|
|
return Iterator(storage_.begin(), storage_.end(), vertex, edge_types);
|
2017-09-08 17:29:54 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
std::vector<Element> storage_;
|
|
|
|
};
|