mariadb/storage/oqgraph/graphcore.cc
Daniel Black 1815719a5b oqgraph: remove clang warnings
-Wdeprecated-copy-with-user-provided-copy was causing a few errors on
things that where defined in a way that was implicit. By removing code
it now compiles without warnings.

tested with fc38 / clang-16
2023-09-08 10:50:15 +01:00

1216 lines
34 KiB
C++

/* Copyright (C) 2007-2013 Arjen G Lentz & Antony T Curtis for Open Query
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
/* ======================================================================
Open Query Graph Computation Engine, based on a concept by Arjen Lentz
v3 implementation by Antony Curtis, Arjen Lentz, Andrew McDonnell
For more information, documentation, support, enhancement engineering,
see http://openquery.com/graph or contact graph@openquery.com
======================================================================
*/
#include <string.h>
#include <cstdlib>
#include "graphcore-graph.h"
#include <set>
#include <stack>
#include <boost/property_map/property_map.hpp>
#include <boost/graph/breadth_first_search.hpp>
#include <boost/graph/dijkstra_shortest_paths.hpp>
#include <boost/graph/iteration_macros.hpp>
#include <boost/graph/reverse_graph.hpp>
#include <boost/graph/graph_utility.hpp>
#include "graphcore.h"
#include <boost/unordered_map.hpp>
#include <boost/version.hpp>
using namespace open_query;
using namespace boost;
static const row empty_row = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
extern "C" const char* const oqgraph_boost_version= BOOST_LIB_VERSION;
namespace open_query
{
typedef graph_traits<Graph>::vertex_descriptor Vertex;
typedef graph_traits<Graph>::edge_descriptor Edge;
typedef std::list<std::pair<Vertex,optional<EdgeWeight> > > shortest_path_list;
typedef shortest_path_list::iterator shortest_path_iterator;
template<typename ID, typename IDMap>
class id_equals_t
{
public:
id_equals_t(ID id, IDMap map)
: m_id(id), m_map(map)
{ }
template<typename V>
bool operator()(V u) const
{
return m_map[u] == m_id;
}
private:
ID m_id;
IDMap m_map;
};
template<typename ID, typename IDMap>
inline id_equals_t<ID,IDMap>
id_equals(ID id, IDMap idmap)
{
return id_equals_t<ID,IDMap>(id, idmap);
}
template<typename T, typename Graph>
class target_equals_t
{
public:
target_equals_t(T target, Graph &g)
: m_target(target), m_g(g)
{ }
template<typename V>
bool operator()(V u) const
{
return target(u, m_g) == m_target;
}
private:
T m_target;
Graph &m_g;
};
template<typename T, typename Graph>
inline target_equals_t<T,Graph>
target_equals(T target, Graph &g)
{
return target_equals_t<T,Graph>(target, g);
}
template<typename T, typename Graph>
class source_equals_t
{
public:
source_equals_t(T source, Graph &g)
: m_source(source), m_g(g)
{ }
template<typename V>
bool operator()(V u) const
{
return source(u, m_g) == m_source;
}
private:
T m_source;
Graph &m_g;
};
template<typename T, typename Graph>
inline source_equals_t<T,Graph>
source_equals(T source, Graph &g)
{
return source_equals_t<T,Graph>(source, g);
}
struct reference
{
int m_flags;
int m_sequence;
Vertex m_vertex;
Edge m_edge;
EdgeWeight m_weight;
enum
{
HAVE_SEQUENCE = 1,
HAVE_WEIGHT = 2,
HAVE_EDGE = 4,
};
inline reference()
: m_flags(0), m_sequence(0),
m_vertex(graph_traits<Graph>::null_vertex()),
m_edge(), m_weight(0)
{ }
inline reference(int s, Edge e)
: m_flags(HAVE_SEQUENCE | HAVE_EDGE), m_sequence(s),
m_vertex(graph_traits<Graph>::null_vertex()),
m_edge(e), m_weight(0)
{ }
inline reference(int s, Vertex v, const optional<Edge> &e,
const optional<EdgeWeight> &w)
: m_flags(HAVE_SEQUENCE | (w ? HAVE_WEIGHT : 0) | (e ? HAVE_EDGE : 0)),
m_sequence(s), m_vertex(v),
m_edge(), m_weight(0)
{
if (w) m_weight= *w;
if (e) m_edge= *e;
}
inline reference(int s, Vertex v, Edge e, EdgeWeight w)
: m_flags(HAVE_SEQUENCE | HAVE_WEIGHT | HAVE_EDGE),
m_sequence(s), m_vertex(v), m_edge(e), m_weight(w)
{ }
inline reference(int s, Vertex v, EdgeWeight w)
: m_flags(HAVE_SEQUENCE | HAVE_WEIGHT),
m_sequence(s), m_vertex(v), m_edge(), m_weight(w)
{ }
inline reference(int s, Vertex v)
: m_flags(HAVE_SEQUENCE), m_sequence(s), m_vertex(v), m_edge(),
m_weight(0)
{ }
optional<int> sequence() const
{
if (m_flags & HAVE_SEQUENCE)
{
return m_sequence;
}
return optional<int>();
}
optional<Vertex> vertex() const
{
if (m_vertex != graph_traits<Graph>::null_vertex())
return m_vertex;
return optional<Vertex>();
}
optional<Edge> edge() const
{
if (m_flags & HAVE_EDGE)
return m_edge;
return optional<Edge>();
};
optional<EdgeWeight> weight() const
{
if (m_flags & HAVE_WEIGHT)
return m_weight;
return optional<EdgeWeight>();
}
};
}
namespace open_query {
class GRAPHCORE_INTERNAL oqgraph_share
{
public:
Graph g;
optional<Vertex> find_vertex(VertexID id) const;
optional<Edge> find_edge(Vertex, Vertex) const;
inline oqgraph_share(
TABLE* table,
Field* origid,
Field* destid,
Field* weight) throw()
: g(table, origid, destid, weight)
{ }
inline ~oqgraph_share()
{ }
};
class GRAPHCORE_INTERNAL oqgraph_cursor
{
public:
oqgraph_share *const share;
inline oqgraph_cursor(oqgraph_share *arg)
: share(arg)
{ }
virtual ~oqgraph_cursor()
{ }
virtual int fetch_row(const row &, row&) = 0;
virtual int fetch_row(const row &, row&, const reference&) = 0;
virtual void current(reference& ref) const = 0;
};
}
namespace open_query {
class GRAPHCORE_INTERNAL stack_cursor : public oqgraph_cursor
{
private:
optional<EdgeWeight> no_weight;
public:
int sequence;
std::stack<reference> results;
reference last;
inline stack_cursor(oqgraph_share *arg)
: oqgraph_cursor(arg), no_weight(), sequence(0), results(), last()
{ }
int fetch_row(const row &, row&);
int fetch_row(const row &, row&, const reference&);
void current(reference& ref) const
{
ref= last;
}
};
class GRAPHCORE_INTERNAL vertices_cursor : public oqgraph_cursor
{
typedef graph_traits<Graph>::vertex_iterator vertex_iterator;
size_t position;
reference last;
public:
inline vertices_cursor(oqgraph_share *arg)
: oqgraph_cursor(arg), position(0)
{ }
int fetch_row(const row &, row&);
int fetch_row(const row &, row&, const reference&);
void current(reference& ref) const
{
ref= last;
}
};
class GRAPHCORE_INTERNAL edges_cursor : public oqgraph_cursor
{
typedef graph_traits<Graph>::edge_iterator edge_iterator;
typedef edge_iterator::difference_type edge_difference;
edge_difference position;
reference last;
public:
inline edges_cursor(oqgraph_share *arg)
: oqgraph_cursor(arg), position(0), last()
{ }
int fetch_row(const row &, row&);
int fetch_row(const row &, row&, const reference&);
void current(reference& ref) const
{
ref= last;
}
};
template <typename P, typename D>
struct GRAPHCORE_INTERNAL oqgraph_visit_leaves
: public base_visitor< oqgraph_visit_leaves<P,D> >
{
typedef on_finish_vertex event_filter;
oqgraph_visit_leaves(const P& p, const D& d,
stack_cursor *cursor)
: seq(0), m_cursor(*cursor), m_p(p), m_d(d)
{ assert(cursor); }
template<class T, class Graph>
void operator()(T u, Graph &g)
{
typename graph_traits<Graph>::out_edge_iterator ei, ei_end;
boost::tuples::tie(ei, ei_end) = out_edges(u, g);
if (ei == ei_end)
{
m_cursor.results.push(reference(++seq, u, m_d[ u ]));
}
}
private:
int seq;
stack_cursor &m_cursor;
P m_p;
D m_d;
};
template <typename P, typename D>
oqgraph_visit_leaves<P,D>
make_oqgraph_visit_leaves(const P& p, const D& d, stack_cursor *cursor)
{ return oqgraph_visit_leaves<P,D>(p, d, cursor); }
template <typename P, typename D>
struct GRAPHCORE_INTERNAL oqgraph_visit_dist
: public base_visitor< oqgraph_visit_dist<P,D> >
{
typedef on_finish_vertex event_filter;
oqgraph_visit_dist(const P& p, const D& d,
stack_cursor *cursor)
: seq(0), m_cursor(*cursor), m_p(p), m_d(d)
{ assert(cursor); }
template<class T, class Graph>
void operator()(T u, Graph &g)
{
m_cursor.results.push(reference(++seq, u, m_d[ u ]));
}
private:
int seq;
stack_cursor &m_cursor;
P m_p;
D m_d;
};
template <typename P, typename D>
oqgraph_visit_dist<P,D>
make_oqgraph_visit_dist(const P& p, const D& d, stack_cursor *cursor)
{ return oqgraph_visit_dist<P,D>(p, d, cursor); }
template<bool record_weight, typename goal_filter, typename P>
struct GRAPHCORE_INTERNAL oqgraph_goal
: public base_visitor<oqgraph_goal<record_weight,goal_filter,P> >
{
typedef goal_filter event_filter;
oqgraph_goal(const Vertex& goal, const P& p,
stack_cursor *cursor)
: m_goal(goal), m_cursor(*cursor), m_p(p)
{ assert(cursor); }
template<class T, class Graph>
void operator()(T u, Graph &g)
{
if (u == m_goal)
{
int seq= 0;
for (Vertex q, v= u;; v = q, seq++)
if ((q= m_p[ v ]) == v)
break;
for (Vertex v= u;; u= v)
{
optional<Edge> edge;
optional<EdgeWeight> weight;
v= m_p[ u ];
if (record_weight && u != v)
{
typename graph_traits<Graph>::out_edge_iterator ei, ei_end;
for (boost::tuples::tie(ei, ei_end)= out_edges(v, g); ei != ei_end; ++ei)
{
if (target(*ei, g) == u)
{
edge= *ei;
weight= get(boost::edge_weight, g, *ei);
break;
}
}
}
else if (u != v)
weight= 1;
m_cursor.results.push(reference(seq--, u, edge, weight));
if (u == v)
break;
}
throw this;
}
}
private:
Vertex m_goal;
stack_cursor &m_cursor;
P m_p;
};
template<bool record_weight, typename goal_filter, typename P>
oqgraph_goal<record_weight, goal_filter, P>
make_oqgraph_goal(const Vertex& goal, const P& p, stack_cursor *cursor)
{ return oqgraph_goal<record_weight, goal_filter, P>(goal, p, cursor); }
}
namespace open_query
{
inline oqgraph::oqgraph(oqgraph_share *arg) throw()
: share(arg), cursor(0), lastRetainedLatch(NULL)
{ }
inline oqgraph::~oqgraph() throw()
{
std::free(lastRetainedLatch);
delete cursor;
}
unsigned oqgraph::edges_count() const throw()
{
return num_edges(share->g);
}
unsigned oqgraph::vertices_count() const throw()
{
return num_vertices(share->g);
}
THD* oqgraph::get_thd() { return share->g.get_table_thd(); }
void oqgraph::set_thd(THD* thd) { share->g.set_table_thd(thd); }
oqgraph* oqgraph::create(oqgraph_share *share) throw()
{
assert(share != NULL);
return new (std::nothrow) oqgraph(share);
}
oqgraph_share* oqgraph::create(
TABLE* table,
Field* origid,
Field* destid,
Field* weight) throw()
{
return new (std::nothrow) oqgraph_share(
table, origid, destid, weight);
}
optional<Edge>
oqgraph_share::find_edge(Vertex orig, Vertex dest) const
{
if (in_degree(dest, g) >= out_degree(orig, g))
{
graph_traits<Graph>::out_edge_iterator ei, ei_end;
tie(ei, ei_end)= out_edges(orig, g);
if ((ei= std::find_if(ei, ei_end, target_equals(dest, g))) != ei_end)
return *ei;
}
else
{
graph_traits<Graph>::in_edge_iterator ei, ei_end;
tie(ei, ei_end)= in_edges(dest, g);
if ((ei= std::find_if(ei, ei_end, source_equals(orig, g))) != ei_end)
return *ei;
}
return optional<Edge>();
}
optional<Vertex>
oqgraph_share::find_vertex(VertexID id) const
{
return oqgraph3::find_vertex(id, g);
}
#if 0
int oqgraph::delete_all() throw()
{
share->g.clear();
return 0;
}
int oqgraph::insert_edge(
VertexID orig_id, VertexID dest_id, EdgeWeight weight, bool replace) throw()
{
optional<Vertex> orig, dest;
optional<Edge> edge;
bool inserted= 0;
if (weight < 0)
return INVALID_WEIGHT;
if (!(orig= share->find_vertex(orig_id)))
{
try
{
orig= add_vertex(VertexInfo(orig_id), share->g);
if (orig == graph_traits<Graph>::null_vertex())
return CANNOT_ADD_VERTEX;
}
catch (...)
{
return CANNOT_ADD_VERTEX;
}
}
if (!(dest= share->find_vertex(dest_id)))
{
try
{
dest= add_vertex(VertexInfo(dest_id), share->g);
if (dest == graph_traits<Graph>::null_vertex())
return CANNOT_ADD_VERTEX;
}
catch (...)
{
return CANNOT_ADD_VERTEX;
}
}
if (!(edge= share->find_edge(*orig, *dest)))
{
try
{
tie(edge, inserted)= add_edge(*orig, *dest, share->g);
if (!inserted)
return CANNOT_ADD_EDGE;
}
catch (...)
{
return CANNOT_ADD_EDGE;
}
}
else
{
if (!replace)
return DUPLICATE_EDGE;
}
share->weightmap[*edge]= weight;
return OK;
}
int oqgraph::delete_edge(current_row_st) throw()
{
reference ref;
if (cursor)
return EDGE_NOT_FOUND;
cursor->current(ref);
optional<Edge> edge;
if (!(edge= ref.edge()))
return EDGE_NOT_FOUND;
Vertex orig= source(*edge, share->g);
Vertex dest= target(*edge, share->g);
remove_edge(*edge, share->g);
if (!degree(orig, share->g))
remove_vertex(orig, share->g);
if (!degree(dest, share->g))
remove_vertex(dest, share->g);
return OK;
}
int oqgraph::modify_edge(current_row_st,
VertexID *orig_id, VertexID *dest_id, EdgeWeight *weight,
bool replace) throw()
{
if (!cursor)
return EDGE_NOT_FOUND;
reference ref;
cursor->current(ref);
optional<Edge> edge;
if (!(edge= ref.edge()))
return EDGE_NOT_FOUND;
if (weight && *weight < 0)
return INVALID_WEIGHT;
optional<Vertex> orig= source(*edge, share->g),
dest= target(*edge, share->g);
bool orig_neq= orig_id ? get(boost::vertex_index, share->g, *orig) != *orig_id : 0;
bool dest_neq= dest_id ? get(boost::vertex_index, share->g, *dest) != *dest_id : 0;
if (orig_neq || dest_neq)
{
optional<Edge> new_edge;
if (orig_neq && !(orig= share->find_vertex(*orig_id)))
{
try
{
orig= add_vertex(VertexInfo(*orig_id), share->g);
if (orig == graph_traits<Graph>::null_vertex())
return CANNOT_ADD_VERTEX;
}
catch (...)
{
return CANNOT_ADD_VERTEX;
}
}
if (dest_neq && !(dest= share->find_vertex(*dest_id)))
{
try
{
dest= add_vertex(VertexInfo(*dest_id), share->g);
if (dest == graph_traits<Graph>::null_vertex())
return CANNOT_ADD_VERTEX;
}
catch (...)
{
return CANNOT_ADD_VERTEX;
}
}
if (!(new_edge= share->find_edge(*orig, *dest)))
{
try
{
bool inserted;
tie(new_edge, inserted)= add_edge(*orig, *dest, share->g);
if (!inserted)
return CANNOT_ADD_EDGE;
}
catch (...)
{
return CANNOT_ADD_EDGE;
}
}
else
{
if (!replace)
return DUPLICATE_EDGE;
}
share->weightmap[*new_edge]= share->weightmap[*edge];
remove_edge(*edge, share->g);
edge= new_edge;
}
if (weight)
share->weightmap[*edge]= *weight;
return OK;
}
int oqgraph::modify_edge(
VertexID orig_id, VertexID dest_id, EdgeWeight weight) throw()
{
optional<Vertex> orig, dest;
optional<Edge> edge;
if (weight < 0)
return INVALID_WEIGHT;
if (!(orig= share->find_vertex(orig_id)))
return EDGE_NOT_FOUND;
if (!(dest= share->find_vertex(dest_id)))
return EDGE_NOT_FOUND;
if (!(edge= share->find_edge(*orig, *dest)))
return EDGE_NOT_FOUND;
share->weightmap[*edge]= weight;
return OK;
}
int oqgraph::delete_edge(VertexID orig_id, VertexID dest_id) throw()
{
optional<Vertex> orig, dest;
optional<Edge> edge;
if (!(orig= share->find_vertex(orig_id)))
return EDGE_NOT_FOUND;
if (!(dest= share->find_vertex(dest_id)))
return EDGE_NOT_FOUND;
if (!(edge= share->find_edge(*orig, *dest)))
return EDGE_NOT_FOUND;
remove_edge(*edge, share->g);
if (!degree(*orig, share->g))
remove_vertex(*orig, share->g);
if (!degree(*dest, share->g))
remove_vertex(*dest, share->g);
return OK;
}
#endif
// THIS IS UGLY - refactor later
// Update the retained latch string value, for later retrieval by
// fetch_row() as a workaround for making sure we return the correct
// string to match the latch='' clause
// (This is a hack for mariadb mysql compatibility)
// IT SHOULD ONLY BE CALLED IMMEIDATELY BEFORE search)(
void oqgraph::retainLatchFieldValue(const char *retainedLatch)
{
// attempting to use std::string broke lots of stuff
// Probably more efficient to use mysql String class, FIXME later
if (lastRetainedLatch) { std::free(lastRetainedLatch); lastRetainedLatch = NULL; }
if (retainedLatch) { lastRetainedLatch = strdup(retainedLatch); }
}
// Because otherwise things can happen and we havent freed a resource since the end of the last query...
void oqgraph::release_cursor() throw() {
if (share->g._cursor) {
// Make sure refs all freed before deleting share->g._cursor
share->g._rnd_cursor = 0;
delete cursor; cursor = 0;
delete share->g._cursor;
share->g._cursor = NULL;
}
row_info= empty_row;
}
int oqgraph::search(int *latch, VertexID *orig_id, VertexID *dest_id) throw()
{
optional<Vertex> orig, dest;
int op= 0, seq= 0;
delete cursor; cursor= 0;
row_info= empty_row;
if ((row_info.latch_indicator= latch)) {
op= ALGORITHM & (row_info.latch= *latch);
row_info.latchStringValue = lastRetainedLatch;
row_info.latchStringValueLen = strlen(lastRetainedLatch);
}
if ((row_info.orig_indicator= orig_id) && (op|= HAVE_ORIG))
orig= share->find_vertex((row_info.orig= *orig_id));
if ((row_info.dest_indicator= dest_id) && (op|= HAVE_DEST))
dest= share->find_vertex((row_info.dest= *dest_id));
//try
//{
switch (op)
{
case NO_SEARCH | HAVE_ORIG | HAVE_DEST:
case NO_SEARCH | HAVE_ORIG:
if ((cursor= new (std::nothrow) stack_cursor(share)) && orig)
{
graph_traits<Graph>::out_edge_iterator ei, ei_end;
for (boost::tuples::tie(ei, ei_end)= out_edges(*orig, share->g); ei != ei_end; ++ei)
{
Vertex v= target(*ei, share->g);
static_cast<stack_cursor*>(cursor)->
results.push(reference(++seq, v, *ei,
get(boost::edge_weight, share->g, *ei)));
}
}
/* fall through */
case NO_SEARCH | HAVE_DEST:
if ((op & HAVE_DEST) &&
(cursor || (cursor= new (std::nothrow) stack_cursor(share))) &&
dest)
{
graph_traits<Graph>::in_edge_iterator ei, ei_end;
for (boost::tuples::tie(ei, ei_end)= in_edges(*dest, share->g); ei != ei_end; ++ei)
{
Vertex v= source(*ei, share->g);
static_cast<stack_cursor*>(cursor)->
results.push(reference(++seq, v, *ei,
get(boost::edge_weight, share->g, *ei)));
}
}
break;
case NO_SEARCH:
cursor= new (std::nothrow) vertices_cursor(share);
break;
case DIJKSTRAS | HAVE_ORIG | HAVE_DEST:
if ((cursor= new (std::nothrow) stack_cursor(share)) && orig && dest)
{
boost::unordered_map<Vertex, Vertex> p;
boost::unordered_map<Vertex, EdgeWeight> d;
p[ *orig ]= *orig;
d[ *orig ] = EdgeWeight();
try
{
dijkstra_shortest_paths_no_init(share->g, *orig,
make_lazy_property_map(p, identity_initializer<Vertex>()),
make_lazy_property_map(d, value_initializer<EdgeWeight>(
(std::numeric_limits<EdgeWeight>::max)())),
get(edge_weight, share->g),
get(vertex_index, share->g),
std::less<EdgeWeight>(),
closed_plus<EdgeWeight>(),
EdgeWeight(),
make_dijkstra_visitor(
make_oqgraph_goal<true, on_finish_vertex>(
*dest,
boost::make_assoc_property_map(p),
static_cast<stack_cursor*>(cursor)
)
),
make_two_bit_judy_map(get(vertex_index, share->g)));
}
catch (...)
{ /* printf("found\n"); */ }
}
break;
case BREADTH_FIRST | HAVE_ORIG | HAVE_DEST:
if ((cursor= new (std::nothrow) stack_cursor(share)) && orig && dest)
{
boost::unordered_map<Vertex, Vertex> p;
boost::queue<Vertex> Q;
p[ *orig ]= *orig;
try
{
breadth_first_visit(share->g, *orig, Q,
make_bfs_visitor(
std::make_pair(
record_predecessors(
boost::make_assoc_property_map(p),
on_tree_edge()
),
make_oqgraph_goal<false, on_discover_vertex>(
*dest, boost::make_assoc_property_map(p),
static_cast<stack_cursor*>(cursor)
)
)
),
make_two_bit_judy_map(get(vertex_index, share->g)));
}
catch (...)
{ /* printf("found\n"); */ }
}
break;
case DIJKSTRAS | HAVE_ORIG:
case BREADTH_FIRST | HAVE_ORIG:
case LEAVES | HAVE_ORIG:
if ((cursor= new (std::nothrow) stack_cursor(share)) && (orig || dest))
{
boost::unordered_map<Vertex, Vertex> p;
boost::unordered_map<Vertex, EdgeWeight> d;
boost::queue<Vertex> Q;
p[ *orig ]= *orig;
d[ *orig ] = EdgeWeight();
switch (ALGORITHM & op)
{
case DIJKSTRAS:
dijkstra_shortest_paths_no_init(share->g, *orig,
make_lazy_property_map(p, identity_initializer<Vertex>()),
make_lazy_property_map(d, value_initializer<EdgeWeight>(
(std::numeric_limits<EdgeWeight>::max)())),
get(edge_weight, share->g),
get(vertex_index, share->g),
std::less<EdgeWeight>(),
closed_plus<EdgeWeight>(),
EdgeWeight(),
make_dijkstra_visitor(
make_oqgraph_visit_dist(
boost::make_assoc_property_map(p),
boost::make_assoc_property_map(d),
static_cast<stack_cursor*>(cursor)
)
),
make_two_bit_judy_map(get(vertex_index, share->g)));
break;
case BREADTH_FIRST:
breadth_first_visit(share->g, *orig, Q,
make_bfs_visitor(
std::make_pair(
record_predecessors(
boost::make_assoc_property_map(p),
on_tree_edge()
),
std::make_pair(
record_distances(
boost::make_assoc_property_map(d),
on_tree_edge()
),
make_oqgraph_visit_dist(
boost::make_assoc_property_map(p),
boost::make_assoc_property_map(d),
static_cast<stack_cursor*>(cursor)
)
))
),
make_two_bit_judy_map(get(vertex_index, share->g)));
break;
case LEAVES:
breadth_first_visit(share->g, *orig, Q,
make_bfs_visitor(
std::make_pair(
record_predecessors(
boost::make_assoc_property_map(p),
on_tree_edge()
),
std::make_pair(
record_distances(
boost::make_assoc_property_map(d),
on_tree_edge()
),
make_oqgraph_visit_leaves(
boost::make_assoc_property_map(p),
boost::make_assoc_property_map(d),
static_cast<stack_cursor*>(cursor)
)
))
),
make_two_bit_judy_map(get(vertex_index, share->g)));
break;
default:
abort();
}
}
break;
case BREADTH_FIRST | HAVE_DEST:
case DIJKSTRAS | HAVE_DEST:
case LEAVES | HAVE_DEST:
if ((cursor= new (std::nothrow) stack_cursor(share)) && (orig || dest))
{
boost::unordered_map<Vertex, Vertex> p;
boost::unordered_map<Vertex, EdgeWeight> d;
boost::queue<Vertex> Q;
const reverse_graph<Graph> r(share->g);
p[ *dest ]= *dest;
d[ *dest ] = EdgeWeight();
switch (ALGORITHM & op)
{
case DIJKSTRAS:
dijkstra_shortest_paths_no_init(r, *dest,
make_lazy_property_map(p, identity_initializer<Vertex>()),
make_lazy_property_map(d, value_initializer<EdgeWeight>(
(std::numeric_limits<EdgeWeight>::max)())),
get(edge_weight, r),
get(vertex_index, r),
std::less<EdgeWeight>(),
closed_plus<EdgeWeight>(),
EdgeWeight(),
make_dijkstra_visitor(
make_oqgraph_visit_dist(
boost::make_assoc_property_map(p),
boost::make_assoc_property_map(d),
static_cast<stack_cursor*>(cursor)
)
),
make_two_bit_judy_map(get(vertex_index, r)));
break;
case BREADTH_FIRST:
breadth_first_visit(r, *dest, Q,
make_bfs_visitor(
std::make_pair(
record_predecessors(
boost::make_assoc_property_map(p),
on_tree_edge()
),
std::make_pair(
record_distances(
boost::make_assoc_property_map(d),
on_tree_edge()
),
make_oqgraph_visit_dist(
boost::make_assoc_property_map(p),
boost::make_assoc_property_map(d),
static_cast<stack_cursor*>(cursor)
)
))
),
make_two_bit_judy_map(get(vertex_index, r)));
break;
case LEAVES:
breadth_first_visit(r, *dest, Q,
make_bfs_visitor(
std::make_pair(
record_predecessors(
boost::make_assoc_property_map(p),
on_tree_edge()
),
std::make_pair(
record_distances(
boost::make_assoc_property_map(d),
on_tree_edge()
),
make_oqgraph_visit_leaves(
boost::make_assoc_property_map(p),
boost::make_assoc_property_map(d),
static_cast<stack_cursor*>(cursor)
)
))
),
make_two_bit_judy_map(get(vertex_index, r)));
break;
default:
abort();
}
}
break;
default:
break;
}
return 0;
//}
//catch (...)
//{
// return MISC_FAIL;
//}
}
int oqgraph::fetch_row(row& result) throw()
{
if (!cursor)
return NO_MORE_DATA;
return cursor->fetch_row(row_info, result);
}
int oqgraph::fetch_row(row& result, const void* ref_ptr) throw()
{
const reference &ref= *(const reference*) ref_ptr;
if (!cursor)
return NO_MORE_DATA;
return cursor->fetch_row(row_info, result, ref);
}
void oqgraph::row_ref(void *ref_ptr) throw()
{
reference &ref= *(reference*) ref_ptr;
if (cursor)
cursor->current(ref);
else
// Beware: internally this eventually causes a swap by intrusive_ptr, so ref must be initialised to sane on all cases
ref = reference();
}
void oqgraph::init_row_ref(void *ref_ptr) throw()
{
// Placement new will cause a constructor to be called avoiding the assignment operator of intrusive_ptr
// This doesnt allocate any memory, assumes ref_ptr is the correct size(!)
new (ref_ptr) reference();
}
int oqgraph::random(bool scan) throw()
{
if (scan || !cursor)
{
delete cursor; cursor= 0;
if (!(cursor= new (std::nothrow) edges_cursor(share)))
return MISC_FAIL;
}
row_info= empty_row;
return OK;
}
void oqgraph::free(oqgraph *graph) throw()
{
delete graph;
}
void oqgraph::free(oqgraph_share *graph) throw()
{
delete graph;
}
const size_t oqgraph::sizeof_ref= sizeof(reference);
}
int stack_cursor::fetch_row(const row &row_info, row &result)
{
if (!results.empty())
{
if (int res= fetch_row(row_info, result, results.top()))
return res;
results.pop();
return oqgraph::OK;
}
else
{
last= reference();
return oqgraph::NO_MORE_DATA;
}
}
int stack_cursor::fetch_row(const row &row_info, row &result,
const reference &ref)
{
last= ref;
if (last.vertex())
{
optional<int> seq;
optional<EdgeWeight> w;
optional<Vertex> v;
result= row_info;
if ((result.seq_indicator= static_cast<bool>(seq= last.sequence())))
result.seq= *seq;
if ((result.link_indicator= static_cast<bool>(v= last.vertex())))
result.link= get(boost::vertex_index, share->g, *v);
if ((result.weight_indicator= static_cast<bool>(w= last.weight())))
result.weight= *w;
return oqgraph::OK;
}
else
return oqgraph::NO_MORE_DATA;
}
int vertices_cursor::fetch_row(const row &row_info, row &result)
{
vertex_iterator it, end;
reference ref;
size_t count= position;
for (tie(it, end)= vertices(share->g); count && it != end; ++it, --count)
;
if (it != end)
ref= reference(position+1, *it);
if (int res= fetch_row(row_info, result, ref))
return res;
position++;
return oqgraph::OK;
}
int vertices_cursor::fetch_row(const row &row_info, row &result,
const reference &ref)
{
last= ref;
optional<Vertex> v= last.vertex();
result= row_info;
if (v)
{
result.link_indicator= 1;
result.link= get(boost::vertex_index, share->g, *v);
#ifdef DISPLAY_VERTEX_INFO
result.seq_indicator= 1;
if ((result.seq= degree(*v, share->g)))
{
EdgeWeight weight= 0;
graph_traits<Graph>::in_edge_iterator iei, iei_end;
for (tie(iei, iei_end)= in_edges(*v, share->g); iei != iei_end; ++iei)
weight+= get(boost::edge_weight, share->g, *iei);
graph_traits<Graph>::out_edge_iterator oei, oei_end;
for (tie(oei, oei_end)= out_edges(*v, share->g); oei != oei_end; ++oei)
weight+= get(boost::edge_weight, share->g, *oei);
result.weight_indicator= 1;
result.weight= weight / result.seq;
}
#endif
return oqgraph::OK;
}
else
return oqgraph::NO_MORE_DATA;
}
int edges_cursor::fetch_row(const row &row_info, row &result)
{
edge_iterator it, end;
reference ref;
tie(it, end)= edges(share->g);
it+= position;
if (it != end)
ref= reference(position+1, *it);
if (int res= fetch_row(row_info, result, ref))
return res;
++position;
return oqgraph::OK;
}
int edges_cursor::fetch_row(const row &row_info, row &result,
const reference &ref)
{
optional<Edge> edge;
if ((edge= (last= ref).edge()))
{
result= row_info;
result.orig_indicator= result.dest_indicator= result.weight_indicator= 1;
oqgraph3::vertex_id orig = get(boost::vertex_index, share->g, source( *edge, share->g ) );
oqgraph3::vertex_id dest = get(boost::vertex_index, share->g, target( *edge, share->g ) );
// bug 796647c - may be symptomatic of a bigger problem with representation
// but origid and destid can be -1 indicating no such record, NULL? but oqgraph3::vertex_id
// seems to resolve to VertexID (unsigned) in row
// in any case we should check for errors (-1) in origid... because all edges have at least one vertex by definition
if (orig == (oqgraph3::vertex_id)-1 && dest == (oqgraph3::vertex_id)-1) {
// Select * from graph; -- when backing store is empty (bug MDEV-5891)
return oqgraph::NO_MORE_DATA;
}
// assert( ! ((size_t)orig == (size_t)-1 && (size_t)dest == (size_t)-1));
// indicates we havent handle a HA_ERR_RECORD_DELETED somewhere
result.orig= orig;
result.dest= dest;
result.weight= get(boost::edge_weight, share->g, *edge);
return oqgraph::OK;
}
return oqgraph::NO_MORE_DATA;
}
namespace boost {
GRAPHCORE_INTERNAL void throw_exception(std::exception const&)
{
abort();
}
}