#pragma once
#include <iterator>
#include <memory>
#include "common/copy_constructors.h"
#include "common/data_chunk/sel_vector.h"
#include "common/types/types.h"
#include "common/vector/value_vector.h"
#include <span>
namespace lbug {
namespace catalog {
class TableCatalogEntry;
} namespace transaction {
class Transaction;
}
namespace graph {
struct NativeGraphEntry;
struct GraphRelInfo {
common::table_id_t srcTableID;
common::table_id_t dstTableID;
catalog::TableCatalogEntry* relGroupEntry;
common::oid_t relTableID;
GraphRelInfo(common::table_id_t srcTableID, common::table_id_t dstTableID,
catalog::TableCatalogEntry* relGroupEntry, common::oid_t relTableID)
: srcTableID{srcTableID}, dstTableID{dstTableID}, relGroupEntry{relGroupEntry},
relTableID{relTableID} {}
};
class LBUG_API NbrScanState {
public:
struct Chunk {
friend class NbrScanState;
EXPLICIT_COPY_METHOD(Chunk);
template<class Func>
void forEach(Func&& func) const {
selVector.forEach([&](auto i) { func(nbrNodes, propertyVectors, i); });
}
template<class Func>
void forEachBreakWhenFalse(Func&& func) const {
selVector.forEachBreakWhenFalse([&](auto i) -> bool { return func(nbrNodes, i); });
}
uint64_t size() const { return selVector.getSelSize(); }
private:
Chunk(std::span<const common::nodeID_t> nbrNodes, common::SelectionVector& selVector,
std::span<const std::shared_ptr<common::ValueVector>> propertyVectors);
Chunk(const Chunk& other) noexcept
: nbrNodes{other.nbrNodes}, selVector{other.selVector},
propertyVectors{other.propertyVectors} {}
private:
std::span<const common::nodeID_t> nbrNodes;
common::SelectionVector& selVector;
std::span<const std::shared_ptr<common::ValueVector>> propertyVectors;
};
virtual ~NbrScanState() = default;
virtual Chunk getChunk() = 0;
virtual bool next() = 0;
protected:
static Chunk createChunk(std::span<const common::nodeID_t> nbrNodes,
common::SelectionVector& selVector,
std::span<const std::shared_ptr<common::ValueVector>> propertyVectors) {
return Chunk{nbrNodes, selVector, propertyVectors};
}
};
class VertexScanState {
public:
struct Chunk {
friend class VertexScanState;
size_t size() const { return nodeIDs.size(); }
std::span<const common::nodeID_t> getNodeIDs() const { return nodeIDs; }
template<typename T>
std::span<const T> getProperties(size_t propertyIndex) const {
return std::span(reinterpret_cast<const T*>(propertyVectors[propertyIndex]->getData()),
nodeIDs.size());
}
private:
LBUG_API Chunk(std::span<const common::nodeID_t> nodeIDs,
std::span<const std::shared_ptr<common::ValueVector>> propertyVectors);
private:
std::span<const common::nodeID_t> nodeIDs;
std::span<const std::shared_ptr<common::ValueVector>> propertyVectors;
};
virtual Chunk getChunk() = 0;
virtual bool next() = 0;
virtual ~VertexScanState() = default;
protected:
static Chunk createChunk(std::span<const common::nodeID_t> nodeIDs,
std::span<const std::shared_ptr<common::ValueVector>> propertyVectors) {
return Chunk{nodeIDs, propertyVectors};
}
};
class Graph {
public:
class EdgeIterator {
public:
explicit constexpr EdgeIterator(NbrScanState* scanState) : scanState{scanState} {}
DEFAULT_BOTH_MOVE(EdgeIterator);
EdgeIterator(const EdgeIterator& other) = default;
EdgeIterator() : scanState{nullptr} {}
using difference_type = std::ptrdiff_t;
using value_type = NbrScanState::Chunk;
value_type operator*() const { return scanState->getChunk(); }
EdgeIterator& operator++() {
if (!scanState->next()) {
scanState = nullptr;
}
return *this;
}
void operator++(int) { ++*this; }
bool operator==(const EdgeIterator& other) const {
return scanState == nullptr && other.scanState == nullptr;
}
uint64_t count() const {
uint64_t result = 0;
do {
result += scanState->getChunk().size();
} while (scanState->next());
return result;
}
std::vector<common::nodeID_t> collectNbrNodes() {
std::vector<common::nodeID_t> nbrNodes;
for (const auto chunk : *this) {
nbrNodes.reserve(nbrNodes.size() + chunk.size());
chunk.forEach(
[&](auto neighbors, auto, auto i) { nbrNodes.push_back(neighbors[i]); });
}
return nbrNodes;
}
EdgeIterator& begin() noexcept { return *this; }
static constexpr EdgeIterator end() noexcept { return EdgeIterator(nullptr); }
private:
NbrScanState* scanState;
};
static_assert(std::input_iterator<EdgeIterator>);
Graph() = default;
virtual ~Graph() = default;
virtual NativeGraphEntry* getGraphEntry() = 0;
virtual std::vector<common::table_id_t> getNodeTableIDs() const = 0;
virtual common::table_id_map_t<common::offset_t> getMaxOffsetMap(
transaction::Transaction* transaction) const = 0;
virtual common::offset_t getMaxOffset(transaction::Transaction* transaction,
common::table_id_t id) const = 0;
virtual common::offset_t getNumNodes(transaction::Transaction* transaction) const = 0;
virtual std::vector<GraphRelInfo> getRelInfos(common::table_id_t srcTableID) = 0;
virtual std::unique_ptr<NbrScanState> prepareRelScan(const catalog::TableCatalogEntry& entry,
common::oid_t relTableID, common::table_id_t nbrTableID,
std::vector<std::string> relProperties, bool randomLookup = true) = 0;
virtual EdgeIterator scanFwd(common::nodeID_t nodeID, NbrScanState& state) = 0;
virtual EdgeIterator scanBwd(common::nodeID_t nodeID, NbrScanState& state) = 0;
class VertexIterator {
public:
explicit constexpr VertexIterator(VertexScanState* scanState) : scanState{scanState} {}
DEFAULT_BOTH_MOVE(VertexIterator);
VertexIterator(const VertexIterator& other) = default;
VertexIterator() : scanState{nullptr} {}
using difference_type = std::ptrdiff_t;
using value_type = VertexScanState::Chunk;
value_type operator*() const { return scanState->getChunk(); }
VertexIterator& operator++() {
if (!scanState->next()) {
scanState = nullptr;
}
return *this;
}
void operator++(int) { ++*this; }
bool operator==(const VertexIterator& other) const {
return scanState == nullptr && other.scanState == nullptr;
}
VertexIterator& begin() noexcept { return *this; }
static constexpr VertexIterator end() noexcept { return VertexIterator(nullptr); }
private:
VertexScanState* scanState;
};
static_assert(std::input_iterator<EdgeIterator>);
virtual std::unique_ptr<VertexScanState> prepareVertexScan(
catalog::TableCatalogEntry* tableEntry, const std::vector<std::string>& properties) = 0;
virtual VertexIterator scanVertices(common::offset_t startNodeOffset,
common::offset_t endNodeOffsetExclusive, VertexScanState& scanState) = 0;
template<class TARGET>
const TARGET& constCast() const {
return common::dynamic_cast_checked<const TARGET&>(*this);
}
};
} }