114cf0368Sopenharmony_ci/*
214cf0368Sopenharmony_ci * Copyright (c) 2023 Huawei Device Co., Ltd.
314cf0368Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
414cf0368Sopenharmony_ci * you may not use this file except in compliance with the License.
514cf0368Sopenharmony_ci * You may obtain a copy of the License at
614cf0368Sopenharmony_ci *
714cf0368Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
814cf0368Sopenharmony_ci *
914cf0368Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
1014cf0368Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
1114cf0368Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1214cf0368Sopenharmony_ci * See the License for the specific language governing permissions and
1314cf0368Sopenharmony_ci * limitations under the License.
1414cf0368Sopenharmony_ci */
1514cf0368Sopenharmony_ci#define LOG_TAG "Graph"
1614cf0368Sopenharmony_ci#include "graph.h"
1714cf0368Sopenharmony_ci#include "logger.h"
1814cf0368Sopenharmony_cinamespace OHOS {
1914cf0368Sopenharmony_cinamespace UDMF {
2014cf0368Sopenharmony_ciGraph::Graph(uint32_t vertexNum, const std::map<std::string, uint32_t> &typeIdIndex)
2114cf0368Sopenharmony_ci    : vertexNum_(vertexNum), typeIdIndex_(typeIdIndex)
2214cf0368Sopenharmony_ci{
2314cf0368Sopenharmony_ci    for (uint32_t node = 0; node < vertexNum_; node++) {
2414cf0368Sopenharmony_ci        adjList_.push_back({node, nullptr});
2514cf0368Sopenharmony_ci    }
2614cf0368Sopenharmony_ci    visited_.resize(vertexNum_);
2714cf0368Sopenharmony_ci    fill(visited_.begin(), visited_.end(), 0);
2814cf0368Sopenharmony_ci}
2914cf0368Sopenharmony_ci
3014cf0368Sopenharmony_ciGraph::~Graph()
3114cf0368Sopenharmony_ci{
3214cf0368Sopenharmony_ci    for (const auto &vertexNode : adjList_) {
3314cf0368Sopenharmony_ci        EdgeNode *edge = vertexNode.firstEdge;
3414cf0368Sopenharmony_ci        while (edge != nullptr) {
3514cf0368Sopenharmony_ci            EdgeNode *nextEdge = edge->next;
3614cf0368Sopenharmony_ci            delete edge;
3714cf0368Sopenharmony_ci            edge = nextEdge;
3814cf0368Sopenharmony_ci        }
3914cf0368Sopenharmony_ci    }
4014cf0368Sopenharmony_ci}
4114cf0368Sopenharmony_ci
4214cf0368Sopenharmony_civoid Graph::AddEdge(const std::string &startNode, const std::string &endNode)
4314cf0368Sopenharmony_ci{
4414cf0368Sopenharmony_ci    int32_t start = GetIndex(startNode);
4514cf0368Sopenharmony_ci    int32_t end = GetIndex(endNode);
4614cf0368Sopenharmony_ci    if (start < 0 || end < 0) {
4714cf0368Sopenharmony_ci        LOG_WARN(UDMF_CLIENT, "abnormal edge, startNode:%{public}s, endNode:%{public}s. ",
4814cf0368Sopenharmony_ci                 startNode.c_str(), endNode.c_str());
4914cf0368Sopenharmony_ci        return;
5014cf0368Sopenharmony_ci    }
5114cf0368Sopenharmony_ci    AddEdge(start, end);
5214cf0368Sopenharmony_ci}
5314cf0368Sopenharmony_ci
5414cf0368Sopenharmony_civoid Graph::AddEdge(uint32_t start, uint32_t end)
5514cf0368Sopenharmony_ci{
5614cf0368Sopenharmony_ci    EdgeNode *edge = new EdgeNode;  // add new edge
5714cf0368Sopenharmony_ci    edge->adjIndex = end;
5814cf0368Sopenharmony_ci    edge->next = adjList_[start].firstEdge;
5914cf0368Sopenharmony_ci    adjList_[start].firstEdge = edge;
6014cf0368Sopenharmony_ci}
6114cf0368Sopenharmony_ci
6214cf0368Sopenharmony_cibool Graph::Dfs(uint32_t startNode, Action action, bool isInit)
6314cf0368Sopenharmony_ci{
6414cf0368Sopenharmony_ci    if (isInit) {
6514cf0368Sopenharmony_ci        visited_.resize(vertexNum_);
6614cf0368Sopenharmony_ci        fill(visited_.begin(), visited_.end(), 0);
6714cf0368Sopenharmony_ci    }
6814cf0368Sopenharmony_ci    std::stack<uint32_t> nodes;
6914cf0368Sopenharmony_ci    EdgeNode *edge = nullptr;
7014cf0368Sopenharmony_ci    visited_[startNode] = 1;
7114cf0368Sopenharmony_ci    nodes.push(startNode);
7214cf0368Sopenharmony_ci    if (action(adjList_[startNode].value)) {
7314cf0368Sopenharmony_ci        return true;
7414cf0368Sopenharmony_ci    }
7514cf0368Sopenharmony_ci    while (!nodes.empty()) {
7614cf0368Sopenharmony_ci        edge = adjList_[nodes.top()].firstEdge;
7714cf0368Sopenharmony_ci        while (edge) {
7814cf0368Sopenharmony_ci            if (visited_[edge->adjIndex] == 0) {
7914cf0368Sopenharmony_ci                visited_[edge->adjIndex] = 1;
8014cf0368Sopenharmony_ci                nodes.push(edge->adjIndex);
8114cf0368Sopenharmony_ci                if (action(adjList_[edge->adjIndex].value)) {
8214cf0368Sopenharmony_ci                    return true;
8314cf0368Sopenharmony_ci                }
8414cf0368Sopenharmony_ci                edge = adjList_[edge->adjIndex].firstEdge;
8514cf0368Sopenharmony_ci            } else if (visited_[edge->adjIndex] == 1) {
8614cf0368Sopenharmony_ci                return false;
8714cf0368Sopenharmony_ci            } else {
8814cf0368Sopenharmony_ci                edge = edge->next;
8914cf0368Sopenharmony_ci            }
9014cf0368Sopenharmony_ci        }
9114cf0368Sopenharmony_ci        visited_[nodes.top()] = 2;  // 2: all edge of the adj is visited.
9214cf0368Sopenharmony_ci        nodes.pop();
9314cf0368Sopenharmony_ci    }
9414cf0368Sopenharmony_ci    return true;
9514cf0368Sopenharmony_ci}
9614cf0368Sopenharmony_ci
9714cf0368Sopenharmony_cibool Graph::DfsUnconnectedGraph(Action action)
9814cf0368Sopenharmony_ci{
9914cf0368Sopenharmony_ci    visited_.resize(vertexNum_);
10014cf0368Sopenharmony_ci    fill(visited_.begin(), visited_.end(), 0);
10114cf0368Sopenharmony_ci    for (uint32_t node = 0; node < vertexNum_; node++) {
10214cf0368Sopenharmony_ci        if (!visited_[node]) {
10314cf0368Sopenharmony_ci            if (!Dfs(node, action, false)) {
10414cf0368Sopenharmony_ci                return false;
10514cf0368Sopenharmony_ci            }
10614cf0368Sopenharmony_ci        }
10714cf0368Sopenharmony_ci    }
10814cf0368Sopenharmony_ci    return true;
10914cf0368Sopenharmony_ci}
11014cf0368Sopenharmony_ci
11114cf0368Sopenharmony_cibool Graph::IsValidType(const std::string &node)
11214cf0368Sopenharmony_ci{
11314cf0368Sopenharmony_ci    if (typeIdIndex_.find(node) == typeIdIndex_.end()) {
11414cf0368Sopenharmony_ci        LOG_ERROR(UDMF_CLIENT, "invalid typeId. typeId:%{public}s ", node.c_str());
11514cf0368Sopenharmony_ci        return false;
11614cf0368Sopenharmony_ci    }
11714cf0368Sopenharmony_ci    return true;
11814cf0368Sopenharmony_ci}
11914cf0368Sopenharmony_ci
12014cf0368Sopenharmony_ciint32_t Graph::GetIndex(const std::string &node)
12114cf0368Sopenharmony_ci{
12214cf0368Sopenharmony_ci    auto idx = typeIdIndex_.find(node);
12314cf0368Sopenharmony_ci    if (idx == typeIdIndex_.end()) {
12414cf0368Sopenharmony_ci        return -1;
12514cf0368Sopenharmony_ci    }
12614cf0368Sopenharmony_ci    return idx->second;
12714cf0368Sopenharmony_ci}
12814cf0368Sopenharmony_ci
12914cf0368Sopenharmony_cibool Graph::IsDAG()
13014cf0368Sopenharmony_ci{
13114cf0368Sopenharmony_ci    return DfsUnconnectedGraph([&](uint32_t currNode) -> bool { return false; });
13214cf0368Sopenharmony_ci}
13314cf0368Sopenharmony_ci} // namespace UDMF
13414cf0368Sopenharmony_ci} // namespace OHOS
135