<commit_before>#include "xchainer/op_node.h"

#include <algorithm>
#include <cassert>
#include <functional>
#include <memory>
#include <tuple>
#include <utility>
#include <vector>

#include "xchainer/array_node.h"
#include "xchainer/backward.h"
#include "xchainer/graph.h"

namespace xchainer {
namespace internal {

OpNodeBackwardEntry::OpNodeBackwardEntry(
        OpNode& op_node, std::vector<nonstd::optional<size_t>> next_array_node_indices, BackwardFunction backward_func)
    : op_node_{op_node}, next_array_node_indices_{std::move(next_array_node_indices)}, backward_func_{std::move(backward_func)} {}

std::vector<std::shared_ptr<ArrayNode>> OpNodeBackwardEntry::GetNextArrayNodes() const {
    std::vector<std::shared_ptr<ArrayNode>> array_nodes;
    array_nodes.reserve(next_array_node_indices_.size());
    for (nonstd::optional<size_t> index : next_array_node_indices_) {
        if (index.has_value()) {
            array_nodes.emplace_back(gsl::at(op_node_.next_array_nodes(), *index));
        } else {
            array_nodes.emplace_back(nullptr);
        }
    }
    return array_nodes;
}

void OpNodeBackwardEntry::AddExoticNextArrayNode(std::tuple<GraphId, std::vector<std::shared_ptr<ArrayNode>>> next_array_nodes) {
    assert(std::get<0>(next_array_nodes) != op_node_.graph_id());
    exotic_next_array_nodes_.emplace_back(std::move(next_array_nodes));
}

}  // namespace internal

OpNode::OpNode(
        std::string name,
        GraphId graph_id,
        std::vector<std::weak_ptr<ArrayNode>> prev_array_nodes,
        std::vector<internal::ArrayProps> prev_array_props)
    : name_{std::move(name)},
      graph_id_{std::move(graph_id)},
      prev_array_nodes_{std::move(prev_array_nodes)},
      prev_array_props_{std::move(prev_array_props)} {
    assert(prev_array_props_.size() == prev_array_nodes_.size());
    AssertConsistency();
}

void OpNode::AssertConsistency() const {
#ifndef NDEBUG
    // No pair of entries may have the same graph ID.
    assert(std::all_of(outer_graphs_prev_array_nodes_.begin(), outer_graphs_prev_array_nodes_.end(), [this](const auto& tup1) {
        return std::all_of(outer_graphs_prev_array_nodes_.begin(), outer_graphs_prev_array_nodes_.end(), [&tup1](const auto& tup2) {
            return &tup1 == &tup2 || std::get<0>(tup1) != std::get<0>(tup2);
        });
    }));

    // Corresponding previous array nodes across graphs (corresponding to the same output array) should have the same array body, if it's
    // alive.
    size_t n_prev = prev_node_count();
    for (size_t i_prev = 0; i_prev < n_prev; ++i_prev) {
        nonstd::optional<internal::ArrayBody*> prev_array_body{};
        for (const auto& tup : outer_graphs_prev_array_nodes_) {
            const std::vector<std::shared_ptr<ArrayNode>>& vec = std::get<1>(tup);
            const std::shared_ptr<ArrayNode>& prev_array_node = vec[i_prev];
            std::shared_ptr<internal::ArrayBody> body = prev_array_node->GetBody();
            if (!prev_array_body.has_value()) {
                prev_array_body = body.get();
            } else {
                assert(*prev_array_body == body.get());
            }
        }
    }
#endif  // NDEBUG
}

std::vector<std::shared_ptr<ArrayNode>>& OpNode::next_array_nodes() {
    assert(std::all_of(next_array_nodes_.begin(), next_array_nodes_.end(), [this](const std::shared_ptr<ArrayNode>& arr_node) {
        return arr_node != nullptr;
    }));
    assert(std::all_of(next_array_nodes_.begin(), next_array_nodes_.end(), [this](const std::shared_ptr<ArrayNode>& arr_node) {
        return arr_node->graph_id() == graph_id_;
    }));
    return next_array_nodes_;<commit_msg>Avoid unncecessary temporary variable<commit_after>#include "xchainer/op_node.h"

#include <algorithm>
#include <cassert>
#include <functional>
#include <memory>
#include <tuple>
#include <utility>
#include <vector>

#include "xchainer/array_node.h"
#include "xchainer/backward.h"
#include "xchainer/graph.h"

namespace xchainer {
namespace internal {

OpNodeBackwardEntry::OpNodeBackwardEntry(
        OpNode& op_node, std::vector<nonstd::optional<size_t>> next_array_node_indices, BackwardFunction backward_func)
    : op_node_{op_node}, next_array_node_indices_{std::move(next_array_node_indices)}, backward_func_{std::move(backward_func)} {}

std::vector<std::shared_ptr<ArrayNode>> OpNodeBackwardEntry::GetNextArrayNodes() const {
    std::vector<std::shared_ptr<ArrayNode>> array_nodes;
    array_nodes.reserve(next_array_node_indices_.size());
    for (nonstd::optional<size_t> index : next_array_node_indices_) {
        if (index.has_value()) {
            array_nodes.emplace_back(gsl::at(op_node_.next_array_nodes(), *index));
        } else {
            array_nodes.emplace_back(nullptr);
        }
    }
    return array_nodes;
}

void OpNodeBackwardEntry::AddExoticNextArrayNode(std::tuple<GraphId, std::vector<std::shared_ptr<ArrayNode>>> next_array_nodes) {
    assert(std::get<0>(next_array_nodes) != op_node_.graph_id());
    exotic_next_array_nodes_.emplace_back(std::move(next_array_nodes));
}

}  // namespace internal

OpNode::OpNode(
        std::string name,
        GraphId graph_id,
        std::vector<std::weak_ptr<ArrayNode>> prev_array_nodes,
        std::vector<internal::ArrayProps> prev_array_props)
    : name_{std::move(name)},
      graph_id_{std::move(graph_id)},
      prev_array_nodes_{std::move(prev_array_nodes)},
      prev_array_props_{std::move(prev_array_props)} {
    assert(prev_array_props_.size() == prev_array_nodes_.size());
    AssertConsistency();
}

void OpNode::AssertConsistency() const {
#ifndef NDEBUG
    // No pair of entries may have the same graph ID.
    assert(std::all_of(outer_graphs_prev_array_nodes_.begin(), outer_graphs_prev_array_nodes_.end(), [this](const auto& tup1) {
        return std::all_of(outer_graphs_prev_array_nodes_.begin(), outer_graphs_prev_array_nodes_.end(), [&tup1](const auto& tup2) {
            return &tup1 == &tup2 || std::get<0>(tup1) != std::get<0>(tup2);
        });
    }));

    // Corresponding previous array nodes across graphs (corresponding to the same output array) should have the same array body, if it's
    // alive.
    for (size_t i_prev = 0; i_prev < prev_node_count(); ++i_prev) {
        nonstd::optional<internal::ArrayBody*> prev_array_body{};
        for (const auto& tup : outer_graphs_prev_array_nodes_) {
            const std::vector<std::shared_ptr<ArrayNode>>& vec = std::get<1>(tup);
            const std::shared_ptr<ArrayNode>& prev_array_node = vec[i_prev];
            std::shared_ptr<internal::ArrayBody> body = prev_array_node->GetBody();
            if (!prev_array_body.has_value()) {
                prev_array_body = body.get();
            } else {
                assert(*prev_array_body == body.get());
            }
        }
    }
#endif  // NDEBUG
}

std::vector<std::shared_ptr<ArrayNode>>& OpNode::next_array_nodes() {
    assert(std::all_of(next_array_nodes_.begin(), next_array_nodes_.end(), [this](const std::shared_ptr<ArrayNode>& arr_node) {
        return arr_node != nullptr;
    }));
    assert(std::all_of(next_array_nodes_.begin(), next_array_nodes_.end(), [this](const std::shared_ptr<ArrayNode>& arr_node) {
        return arr_node->graph_id() == graph_id_;
    }));
    return next_array_nodes_;
{'fraction_non_alphanumeric': 0.13988502600602246, 'fraction_numerical': 0.0032849712565015056, 'mean_word_length': 4.420623145400594, 'pattern_counts': {'":': 0, '<': 71, '<?xml version=': 0, '>': 73, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4077928', 'n_tokens_mistral': 2432, 'n_tokens_neox': 2410, 'n_words': 375}