Files
2026-07-13 12:40:42 +08:00

180 lines
6.4 KiB
C++

// Copyright (c) 2024 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed 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.
#pragma once
#include <list>
#include "paddle/ap/include/adt/adt.h"
#include "paddle/ap/include/graph/node.h"
#include "paddle/ap/include/graph/tags.h"
namespace ap::graph {
template <typename T>
class NodeArena : public std::enable_shared_from_this<NodeArena<T>> {
public:
NodeArena() {}
NodeArena(const NodeArena&) = delete;
NodeArena(NodeArena&&) = delete;
adt::Result<T> At(const tNodeId<size_t>& node_id) const {
if (node_id.value() >= nodes_.size()) {
return adt::errors::IndexError{"node_id out of ranges."};
}
return nodes_.at(node_id.value());
}
template <typename ConstructorT>
const T& New(const ConstructorT& Constructor) {
tNodeId<size_t> node_id{nodes_.size()};
const auto& node = Constructor(Node<T>{node_id, this->shared_from_this()});
return EmplaceBackNode(node);
}
template <typename ConstructorT>
adt::Result<T> TryNew(const ConstructorT& Constructor) {
tNodeId<size_t> node_id{nodes_.size()};
ADT_LET_CONST_REF(node,
Constructor(Node<T>{node_id, this->shared_from_this()}));
return EmplaceBackNode(node);
}
adt::Result<NodeList<T>> DownstreamNodes4SrcNodeId(
const tNodeId<size_t>& src_id) {
if (src_id.value() >= src_node_id2downstream_nodes_.size()) {
return adt::errors::IndexError{"src node_id out of ranges."};
}
return src_node_id2downstream_nodes_.at(src_id.value());
}
adt::Result<NodeList<T>> UpstreamNodes4DstNodeId(
const tNodeId<size_t>& dst_id) {
if (dst_id.value() >= dst_node_id2upstream_nodes_.size()) {
return adt::errors::IndexError{"dst node_id out of ranges."};
}
return dst_node_id2upstream_nodes_.at(dst_id.value());
}
adt::Result<adt::Ok> Connect(
const Node<T>& src_node,
const ValidListTag<std::monostate>& src_downstream_type,
const Node<T>& dst_node,
const ValidListTag<std::monostate>& dst_unstream_type) {
const auto& src_id = src_node.node_id();
if (src_node.node_arena().lock() != this->shared_from_this()) {
return adt::errors::RuntimeError{
"Connection between nodes from different arena is not supported. "};
}
if (src_id.value() >= this->src_node_id2downstream_nodes_.size()) {
return adt::errors::IndexError{
"src_id.value() is out of range "
"this->src_node_id2downstream_nodes_."};
}
const auto& dst_id = dst_node.node_id();
if (dst_node.node_arena().lock() != this->shared_from_this()) {
return adt::errors::RuntimeError{
"Connection between nodes from different arena is not supported. "};
}
if (dst_id.value() >= this->dst_node_id2upstream_nodes_.size()) {
return adt::errors::IndexError{
"src_id.value() is out of range this->dst_node_id2upstream_nodes_."};
}
ADT_LET_CONST_REF(
downstream_nodes_data,
GetNodeListData(&src_node_id2downstream_nodes_[src_id.value()],
src_downstream_type));
downstream_nodes_data->emplace_back(
Node<T>{dst_id, this->shared_from_this()});
ADT_LET_CONST_REF(
upstream_nodes_data,
GetNodeListData(&dst_node_id2upstream_nodes_[dst_id.value()],
dst_unstream_type));
upstream_nodes_data->emplace_back(
Node<T>{src_id, this->shared_from_this()});
return adt::Ok{};
}
const std::vector<T>& nodes() const { return nodes_; }
private:
adt::Result<adt::List<Node<T>>> GetNodeListData(
NodeList<T>* node_list, const ValidListTag<std::monostate>& type) {
using RetDataT = adt::List<Node<T>>;
using RetT = adt::Result<RetDataT>;
if (node_list->template Has<UndefinedTag<RetDataT>>()) {
return type.Match(
[&](const IndexedTag<std::monostate>&) -> RetT {
IndexedTag<RetDataT> data{RetDataT{}};
*node_list = data;
return data.data;
},
[&](const UnindexedTag<std::monostate>&) -> RetT {
UnindexedTag<RetDataT> data{RetDataT{}};
*node_list = data;
return data.data;
});
}
const auto& pattern_match = ::common::Overloaded{
[&](const IndexedTag<RetDataT>& l,
const IndexedTag<std::monostate>&) -> RetT { return l.data; },
[&](const UnindexedTag<RetDataT>& l,
const UnindexedTag<std::monostate>&) -> RetT { return l.data; },
[&](const auto&, const auto&) -> RetT {
return adt::errors::TypeError{"ap graph node list type mismatch."};
}};
return std::visit(pattern_match, node_list->variant(), type.variant());
}
const T& EmplaceBackNode(const T& node) {
nodes_.emplace_back(node);
src_node_id2downstream_nodes_.resize(nodes_.size());
dst_node_id2upstream_nodes_.resize(nodes_.size());
return nodes_.at(nodes_.size() - 1);
}
std::vector<T> nodes_;
std::vector<NodeList<T>> src_node_id2downstream_nodes_;
std::vector<NodeList<T>> dst_node_id2upstream_nodes_;
};
template <typename T>
adt::Result<T> Node<T>::Get() const {
ADT_LET_CONST_REF(arena, adt::WeakPtrLock(this->node_arena()));
return arena->At(this->node_id());
}
template <typename T>
adt::Result<NodeList<T>> Node<T>::DownstreamNodes() const {
ADT_LET_CONST_REF(arena, adt::WeakPtrLock(this->node_arena()));
return arena->DownstreamNodes4SrcNodeId(this->node_id());
}
template <typename T>
adt::Result<NodeList<T>> Node<T>::UpstreamNodes() const {
ADT_LET_CONST_REF(arena, adt::WeakPtrLock(this->node_arena()));
return arena->UpstreamNodes4DstNodeId(this->node_id());
}
template <typename T>
adt::Result<adt::Ok> Node<T>::ConnectTo(
const Node& dst_node,
const ValidListTag<std::monostate>& src_downstream_type,
const ValidListTag<std::monostate>& dst_unstream_type) const {
ADT_LET_CONST_REF(arena, adt::WeakPtrLock(this->node_arena()));
return arena->Connect(
*this, src_downstream_type, dst_node, dst_unstream_type);
}
} // namespace ap::graph