<commit_before>#pragma once
// TODO: move implementation to impl header
#include <type_traits>
#include <functional>
#include <vector>
#include <ostream>
#include <cstdint>
#include <stdexcept>
#include <algorithm>


struct edge_base_t
{
    int start, stop;

    edge_base_t(const std::initializer_list<int> &e)
    {
        if (e.size() != 2)
            throw std::logic_error("edge_base_t needs exactly two arguments.");

        auto it = e.begin();
        start = *it;
        ++it;
        stop = *it;;
    }
};

inline bool operator==(const edge_base_t &lhs, const edge_base_t &rhs)
{
    return lhs.start == rhs.start and lhs.stop == rhs.stop;
}

inline std::ostream& operator<<(std::ostream &os, const edge_base_t &e)
{
    os << e.start << " --> " << e.stop;
    return os;
}

/* TODO: what about the container type for edges? */
template<
    class Edge = edge_base_t,
    typename = std::is_base_of<edge_base_t, Edge>
>
class Graph
{
public:
    using edge_t = Edge;

    Graph(size_t n)
        : E(n)
        , num_of_edges_(0)
    {
    }

    void remove_vertex(int v)
    {
        num_of_edges_ -= E[v].size();
        E[v].clear();

        for (int i = 0; i < size(); i++)
        {
            auto it = std::remove_if(E[i].begin(), E[i].end(), [v](const edge_t &e) { return e.stop == v; });

            num_of_edges_ -= std::distance(it, E[i].end());
            E[i].erase(it, E[i].end());
        }
    }

    void for_each_edge(std::function<void(edge_t*)> f)
    {
        for (auto &edges_ : E)
            for (auto &e : edges_)
                f(&e);
    }

    std::vector<edge_t> edges()
    {
        std::vector<edge_t> result;
        for_each_edge([&result] (edge_t *e) { result.push_back(*e); });
        return result;
    }

    size_t size() const
    {
        return E.size();
    }

    size_t num_of_edges() const
    {
        return num_of_edges_;
    }

    void add_edge(edge_t e)
    {
        E[e.start].push_back(e);
        num_of_edges_++;
    }


    void remove_edge(edge_base_t e)
    {
        remove_edge(e.start, e.stop);<commit_msg>added a const version of Graph::for_each_edge<commit_after>#pragma once
// TODO: move implementation to impl header
#include <type_traits>
#include <functional>
#include <vector>
#include <ostream>
#include <cstdint>
#include <stdexcept>
#include <algorithm>


struct edge_base_t
{
    int start, stop;

    edge_base_t(const std::initializer_list<int> &e)
    {
        if (e.size() != 2)
            throw std::logic_error("edge_base_t needs exactly two arguments.");

        auto it = e.begin();
        start = *it;
        ++it;
        stop = *it;;
    }
};

inline bool operator==(const edge_base_t &lhs, const edge_base_t &rhs)
{
    return lhs.start == rhs.start and lhs.stop == rhs.stop;
}

inline std::ostream& operator<<(std::ostream &os, const edge_base_t &e)
{
    os << e.start << " --> " << e.stop;
    return os;
}

/* TODO: what about the container type for edges? */
template<
    class Edge = edge_base_t,
    typename = std::is_base_of<edge_base_t, Edge>
>
class Graph
{
public:
    using edge_t = Edge;

    Graph(size_t n)
        : E(n)
        , num_of_edges_(0)
    {
    }

    void remove_vertex(int v)
    {
        num_of_edges_ -= E[v].size();
        E[v].clear();

        for (int i = 0; i < size(); i++)
        {
            auto it = std::remove_if(E[i].begin(), E[i].end(), [v](const edge_t &e) { return e.stop == v; });

            num_of_edges_ -= std::distance(it, E[i].end());
            E[i].erase(it, E[i].end());
        }
    }

    void for_each_edge(std::function<void(edge_t*)> f)
    {
        for (auto &edges_ : E)
            for (auto &e : edges_)
                f(&e);
    }

    void for_each_edge(std::function<void(const edge_t*)> f) const
    {
        for (auto &edges_ : E)
            for (auto &e : edges_)
                f(&e);
    }

    std::vector<edge_t> edges() const
    {
        std::vector<edge_t> result;
        for_each_edge([&result] (const edge_t *e) { result.push_back(*e); });
        return result;
    }

    size_t size() const
    {
        return E.size();
    }

    size_t num_of_edges() const
    {
        return num_of_edges_;
    }

    void add_edge(edge_t e)
    {
        E[e.start].push_back(e);
        num_of_edges_++;
    }


    void remove_edge(edge_base_t e)
    {
        remove_edge(e.start, e.stop);
{'fraction_non_alphanumeric': 0.15194185782421077, 'fraction_numerical': 0.0013627072450601862, 'mean_word_length': 2.1982570806100217, 'pattern_counts': {'":': 0, '<': 48, '<?xml version=': 0, '>': 32, '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': '7435213', 'n_tokens_mistral': 1615, 'n_tokens_neox': 1574, 'n_words': 356}