memgraph/src/traversal/path.hpp
florijan 80c266ce21 Traversal added. Only the core, tests and template specialization is on the way
Summary: See above.

Reviewers: buda, dgleich, mislav.bradac

Reviewed By: buda, dgleich, mislav.bradac

Subscribers: pullbot, mislav.bradac, buda, florijan

Differential Revision: https://phabricator.memgraph.io/D67
2017-03-01 16:45:00 +01:00

218 lines
5.5 KiB
C++

//
// Copyright 2017 Memgraph
// Created by Florijan Stamenkovic on 23.02.17.
//
#pragma once
#include <list>
#include <algorithm>
#include <functional>
#include "enums.hpp"
#include "utils/assert.hpp"
/**
* For a documentation of this namespace and it's
* intended usage (namespace specialization) take
* a look at the docs in "templates.hpp".
*/
namespace traversal_template {
/**
* A path containing zero or more vertices. Between
* each two vertices is an edge.
*
* @tparam TVertex
* @tparam TEdge
*/
template<typename TVertex, typename TEdge>
class Path {
public:
Path() {}
size_t Size() const {
return vertices_.size();
}
friend std::ostream &operator<<(std::ostream &stream, const Path &path) {
auto vertices_it = path.vertices_.begin();
auto vertices_end = path.vertices_.end();
auto edges_it = path.edges_.begin();
if (vertices_it != vertices_end)
stream << *vertices_it++;
while (vertices_it != vertices_end)
// current vertex has incoming if it is
if (edges_it->to() == *vertices_it)
stream << "-" << *edges_it++ << "->" << *vertices_it++;
else
stream << "<-" << *edges_it++ << "-" << *vertices_it++;
return stream;
}
bool operator==(const Path &other) const {
return vertices_ == other.vertices_ && edges_ == other.edges_;
}
bool operator!=(const Path &other) const { return !(*this == other); }
/**
* Starts the path. At this moment the Path must be empty.
*
* @return A reference to this same path.
*/
Path &Start(const TVertex &v) {
debug_assert(vertices_.size() == 0, "Can only start iteration on empty path");
vertices_.push_back(v);
return *this;
}
/**
* Checks if the given vertex is contained in this path.
*/
bool Contains(const TVertex &vertex) const {
for (const auto &v : vertices_)
if (v == vertex) return true;
return false;
}
/**
* Checks if the given edge is contained in this path.
*/
bool Contains(const TEdge &edge) const {
for (const auto &e : edges_)
if (e == edge) return true;
return false;
}
/**
* Gets the last Vertex of this path. Fails if the path contains no elements.
*/
const TVertex &Back() const {
debug_assert(vertices_.size() > 0, "Can only get a Vertex on non-empty path");
return vertices_.back();
}
/**
* Appends a traversal to the end of this path.
*
* @param edge The edge along with the traversal happens.
* @param vertex The new vertex to append to the path.
* @param direction The direction along which the traversal happens
* (relative to the currently last vertex in path).
* @return A reference to this same path.
*/
Path &Append(const TEdge &edge, const TVertex &vertex) {
edges_.emplace_back(edge);
vertices_.emplace_back(vertex);
return *this;
}
/**
* Removes the last element from the path. Fails if the path contains no elements.
*/
void PopBack() {
debug_assert(vertices_.size() > 0, "Can only remove a vertex from a non-empty path");
vertices_.pop_back();
if (vertices_.size() > 0)
edges_.pop_back();
}
/**
* Gets the first Vertex of this path. Fails if the path contains no elements.
*/
const TVertex &Front() const {
debug_assert(vertices_.size() > 0, "Can only get a vertex from a non-empty path");
return vertices_.front();
}
/**
* Prepends a traversal to the beginning of this path.
*
* @param edge The edge along with the traversal happens.
* @param vertex The new vertex to prepend to the path.
* @return A reference to this same path.
*/
Path &Prepend(const TEdge &edge, const TVertex &vertex) {
edges_.emplace_front(edge);
vertices_.emplace_front(vertex);
return *this;
}
/**
* Removes the first element from the path. Fails if the path contains no elements.
*/
void PopFront() {
debug_assert(vertices_.size() > 0, "Can only remove a vertex from a non-empty path");
vertices_.pop_front();
if (vertices_.size() > 0)
edges_.pop_front();
}
/**
* Removes all the elements from the path.
*/
void Clear() {
edges_.clear();
vertices_.clear();
}
/**
* Returns all the vertices in this path.
*/
const auto &Vertices() const { return vertices_; }
/**
* Returns all the edges in this path.
*/
const auto &Edges() const { return edges_; }
private:
std::list<TVertex> vertices_;
std::list<TEdge> edges_;
};
/**
* An ordered sequence of Path reference wrappers. Used when
* visiting cartesian products of traversals.
*/
// TODO review: do we like std::list inheritance (and why)?
// alternatively we could do:
// A. using Paths = std::list<std::reference_wrapper<Path>>;
// B. encapsulation
template <typename TVertex, typename TEdge>
class Paths : public std::list<std::reference_wrapper<Path<TVertex, TEdge>>> {
using Path = Path<TVertex, TEdge>;
public:
bool operator==(const Paths<TVertex, TEdge> &other) const {
return std::equal(this->begin(), this->end(), other.begin(),
[](const std::reference_wrapper<Path> &p1,
const std::reference_wrapper<Path> &p2) {
return p1.get() == p2.get();
});
}
bool operator!=(const Paths &other) const { return !(*this == other);}
friend std::ostream &operator<<(std::ostream &stream, const Paths &paths) {
stream << "[";
auto it = paths.begin();
auto end = paths.end();
if (it != end) stream << *it++;
while (it != end) stream << ", " << *it++;
return stream << "]";
}
};
}