<commit_before>#pragma once

#include <boost/config.hpp>

#include "blackhole/attribute.hpp"
#include "blackhole/detail/string/formatting/formatter.hpp"
#include "blackhole/detail/util/unique.hpp"
#include "blackhole/repository/factory/traits.hpp"
#include "blackhole/sink/files/backend.hpp"
#include "blackhole/sink/files/config.hpp"
#include "blackhole/sink/files/flusher.hpp"
#include "blackhole/sink/files/rotation.hpp"
#include "blackhole/sink/files/writer.hpp"
#include "blackhole/sink/thread.hpp"

namespace blackhole {

namespace sink {

template<class Backend, class Rotator>
class file_handler_t {
    Backend m_backend;
    files::writer_t<Backend> writer;
    files::flusher_t<Backend> flusher;
    Rotator rotator;
public:
    file_handler_t(const std::string& path, const files::config_t<Rotator>& config) :
        m_backend(path),
        writer(m_backend),
        flusher(config.autoflush, m_backend),
        rotator(config.rotation, m_backend)
    {}

    void handle(const std::string& message) {
        writer.write(message);
        flusher.flush();
        if (rotator.necessary(message)) {
            rotator.rotate();
        }
    }

    const Backend& backend() {
        return m_backend;
    }
};

template<class Backend>
class file_handler_t<Backend, null_rotator_t> {
    Backend m_backend;
    files::writer_t<Backend> writer;
    files::flusher_t<Backend> flusher;
public:
    file_handler_t(const std::string& path, const files::config_t<null_rotator_t>& config) :
        m_backend(path),
        writer(m_backend),
        flusher(config.autoflush, m_backend)
    {}

    void handle(const std::string& message) {
        writer.write(message);
        flusher.flush();
    }

    const Backend& backend() {
        return m_backend;
    }
};

struct substitute_attribute_t {
    const attribute::set_view_t& attributes;

    void operator()(stickystream_t& stream, const std::string& placeholder) const {
        if (auto attribute = attributes.find(placeholder)) {
            stream << attribute->value;
        } else {
            stream.rdbuf()->storage()->append(placeholder);
        }
    }
};

template<class Backend = files::boost_backend_t, class Rotator = null_rotator_t>
class files_t {
    typedef file_handler_t<Backend, Rotator> handler_type;
    typedef std::unordered_map<std::string, std::shared_ptr<handler_type>> handlers_type;

    files::config_t<Rotator> config;
    handlers_type m_handlers;
    aux::formatter_t formatter;
<commit_msg>[Code Clean] Providing template types outside.<commit_after>#pragma once

#include <boost/config.hpp>

#include "blackhole/attribute.hpp"
#include "blackhole/detail/string/formatting/formatter.hpp"
#include "blackhole/detail/util/unique.hpp"
#include "blackhole/repository/factory/traits.hpp"
#include "blackhole/sink/files/backend.hpp"
#include "blackhole/sink/files/config.hpp"
#include "blackhole/sink/files/flusher.hpp"
#include "blackhole/sink/files/rotation.hpp"
#include "blackhole/sink/files/writer.hpp"
#include "blackhole/sink/thread.hpp"

namespace blackhole {

namespace sink {

template<class Backend, class Rotator>
class file_handler_t {
public:
    typedef Backend backend_type;
    typedef Rotator rotator_type;
    typedef files::config_t<rotator_type> config_type;

private:
    backend_type backend_;
    files::writer_t<backend_type> writer;
    files::flusher_t<backend_type> flusher;
    rotator_type rotator;

public:
    file_handler_t(const std::string& path, const config_type& config) :
        backend_(path),
        writer(backend_),
        flusher(config.autoflush, backend_),
        rotator(config.rotation, backend_)
    {}

    void handle(const std::string& message) {
        writer.write(message);
        flusher.flush();
        if (rotator.necessary(message)) {
            rotator.rotate();
        }
    }

    const backend_type& backend() {
        return backend_;
    }
};

template<class Backend>
class file_handler_t<Backend, null_rotator_t> {
public:
    typedef Backend backend_type;
    typedef null_rotator_t rotator_type;
    typedef files::config_t<rotator_type> config_type;

private:
    backend_type backend_;
    files::writer_t<backend_type> writer;
    files::flusher_t<backend_type> flusher;

public:
    file_handler_t(const std::string& path, const config_type& config) :
        backend_(path),
        writer(backend_),
        flusher(config.autoflush, backend_)
    {}

    void handle(const std::string& message) {
        writer.write(message);
        flusher.flush();
    }

    const backend_type& backend() {
        return backend_;
    }
};

struct substitute_attribute_t {
    const attribute::set_view_t& attributes;

    void operator()(stickystream_t& stream, const std::string& placeholder) const {
        if (auto attribute = attributes.find(placeholder)) {
            stream << attribute->value;
        } else {
            stream.rdbuf()->storage()->append(placeholder);
        }
    }
};

template<class Backend = files::boost_backend_t, class Rotator = null_rotator_t>
class files_t {
    typedef file_handler_t<Backend, Rotator> handler_type;
    typedef std::unordered_map<std::string, std::shared_ptr<handler_type>> handlers_type;

    files::config_t<Rotator> config;
    handlers_type m_handlers;
    aux::formatter_t formatter;

{'fraction_non_alphanumeric': 0.11582504223765722, 'fraction_numerical': 0.0, 'mean_word_length': 3.744434550311665, 'pattern_counts': {'":': 0, '<': 37, '<?xml version=': 0, '>': 39, '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': '4012383', 'n_tokens_mistral': 1686, 'n_tokens_neox': 1688, 'n_words': 315}