<commit_before>#include <string>
#include <vector>
#include <list>
#include <algorithm>
#include <map>
#include <fstream>
#include <iostream>
#include <stdexcept>

#include <filesystem>

#include <mntent.h>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
#include <string.h>

#include <fmt/format.h>
#include <fmt/ostream.h>

#include "utils.h"
#include "cgroup.h"

using std::string;
using std::vector;
using std::list;
using std::map;
using std::ifstream;
using std::ofstream;
namespace fs = std::filesystem;
using fmt::format;

map<string, vector<fs::path>> cgroup_mnt;

static bool IsEmpty(const string &str)
{
    auto f = [](unsigned char const c) { return std::isspace(c); };
    return std::all_of(str.begin(), str.end(), f);
}
CgroupInfo::CgroupInfo(const string &controller, const string &group)
    : Controller(controller), Group(group)
{
    if (IsEmpty(controller))
    {
        throw std::invalid_argument("Controller name cannot be empty!");
    }
    else if (IsEmpty(group))
    {
        throw std::invalid_argument("Group name cannot be empty!");
    }
}

// This piece of code is copied from libcgroup but translated to C++. C++ is very great.
bool InitializeCgroup()
{
    cgroup_mnt.clear();
    char buf[4 * FILENAME_MAX];

    ifstream proc_cgroup("/proc/cgroups");
    // The first line is ignored.
    proc_cgroup.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

    vector<string> controllers;
    string subsys_name;
    int hierarchy, num_cgroups, enabled;
    while (proc_cgroup >> subsys_name >> hierarchy >> num_cgroups >> enabled)
    {
        controllers.push_back(string(subsys_name));
    }

    FILE *proc_mount = CHECKNULL(fopen("/proc/mounts", "re"));
    mntent *temp_ent = new mntent, *ent;
    while ((ent = getmntent_r(proc_mount, temp_ent,
                              buf,
                              sizeof(buf))) != NULL)
    {
        if (strcmp(ent->mnt_type, "cgroup"))
            continue;

        for (auto iter = controllers.begin(); iter != controllers.end(); iter++)
        {
            char *mntopt = hasmntopt(ent, iter->c_str());
            if (!mntopt)
                continue;

            cgroup_mnt[*iter].push_back(fs::path(string(ent->mnt_dir)));
        }
    }
    delete temp_ent;

    // TODO: implement RAII here. `throw` will cause file descriptor leak for now.
    if (proc_mount)
        fclose(proc_mount);

    return cgroup_mnt.size() != 0;
}
<commit_msg>Replace delete and fclose with RAII<commit_after>#include <string>
#include <vector>
#include <list>
#include <algorithm>
#include <map>
#include <fstream>
#include <iostream>
#include <stdexcept>

#include <filesystem>

#include <mntent.h>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
#include <string.h>

#include <fmt/format.h>
#include <fmt/ostream.h>

#include "utils.h"
#include "cgroup.h"

using std::string;
using std::vector;
using std::list;
using std::map;
using std::ifstream;
using std::ofstream;
namespace fs = std::filesystem;
using fmt::format;

map<string, vector<fs::path>> cgroup_mnt;

static bool IsEmpty(const string &str)
{
    auto f = [](unsigned char const c) { return std::isspace(c); };
    return std::all_of(str.begin(), str.end(), f);
}
CgroupInfo::CgroupInfo(const string &controller, const string &group)
    : Controller(controller), Group(group)
{
    if (IsEmpty(controller))
    {
        throw std::invalid_argument("Controller name cannot be empty!");
    }
    else if (IsEmpty(group))
    {
        throw std::invalid_argument("Group name cannot be empty!");
    }
}

// This piece of code is copied from libcgroup but translated to C++. C++ is very great.
bool InitializeCgroup()
{
    cgroup_mnt.clear();
    char buf[4 * FILENAME_MAX];

    ifstream proc_cgroup("/proc/cgroups");
    // The first line is ignored.
    proc_cgroup.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

    vector<string> controllers;
    string subsys_name;
    int hierarchy, num_cgroups, enabled;
    while (proc_cgroup >> subsys_name >> hierarchy >> num_cgroups >> enabled)
    {
        controllers.push_back(string(subsys_name));
    }

    std::unique_ptr<FILE, decltype(fclose) *> proc_mount(CHECKNULL(fopen("/proc/mounts", "re")), fclose);
    std::unique_ptr<mntent> temp_ent = std::make_unique<mntent>();
    mntent *ent;
    while ((ent = getmntent_r(proc_mount.get(), temp_ent.get(),
                              buf,
                              sizeof(buf))) != NULL)
    {
        if (strcmp(ent->mnt_type, "cgroup"))
            continue;

        for (auto iter = controllers.begin(); iter != controllers.end(); iter++)
        {
            char *mntopt = hasmntopt(ent, iter->c_str());
            if (!mntopt)
                continue;

            cgroup_mnt[*iter].push_back(fs::path(string(ent->mnt_dir)));
        }
    }

    return cgroup_mnt.size() != 0;
}

{'fraction_non_alphanumeric': 0.14868447889047523, 'fraction_numerical': 0.0008158270446665307, 'mean_word_length': 3.2275862068965515, 'pattern_counts': {'":': 0, '<': 46, '<?xml version=': 0, '>': 68, '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': '7272598', 'n_tokens_mistral': 1638, 'n_tokens_neox': 1608, 'n_words': 391}