<commit_before>// From vmdconio.h
#define VMDCON_WARN      2
#define VMDCON_ERROR     3

extern "C" {
    #include <vmdplugin.h>
    #include <molfile_plugin.h>
}

#include <cassert>
#include <array>
#include <string>
#include <vector>
#include <unordered_map>

#include "chemfiles/File.hpp"
#include "chemfiles/Format.hpp"
#include "chemfiles/Atom.hpp"
#include "chemfiles/Frame.hpp"
#include "chemfiles/Residue.hpp"
#include "chemfiles/Topology.hpp"

#include "chemfiles/types.hpp"
#include "chemfiles/warnings.hpp"
#include "chemfiles/error_fmt.hpp"
#include "chemfiles/external/span.hpp"
#include "chemfiles/external/optional.hpp"

#include "chemfiles/formats/Molfile.hpp"

using namespace chemfiles;

/******************************************************************************/
#define PLUGINS_DATA(FORMAT, PLUGIN, READER, VELOCITIES)                       \
    extern "C" int PLUGIN##_register(void*, vmdplugin_register_cb); /*NOLINT*/ \
    extern "C" int PLUGIN##_fini(void); /*NOLINT*/                             \
    extern "C" int PLUGIN##_init(void); /*NOLINT*/                             \
    template <> struct MolfilePluginData<FORMAT> {                             \
        int init() { return PLUGIN##_init(); }                                 \
        int registration(void* data, vmdplugin_register_cb callback) {         \
            return PLUGIN##_register(data, callback);                          \
        }                                                                      \
        int fini() { return PLUGIN##_fini(); }                                 \
        std::string format() const {return #FORMAT;}                           \
        std::string plugin_name() const {return #PLUGIN;}                      \
        std::string reader() const {return #READER;}                           \
        bool have_velocities() const {return VELOCITIES;}                     \
    }

namespace chemfiles {
    PLUGINS_DATA(DCD,               dcdplugin,          dcd,            false);
    PLUGINS_DATA(TRJ,               gromacsplugin,      trj,            false);
    PLUGINS_DATA(LAMMPS,            lammpsplugin,       lammpstrj,      true);
    PLUGINS_DATA(MOLDEN,            moldenplugin,       molden,         false);
}

#undef PLUGINS_FUNCTIONS
/******************************************************************************/

template <MolfileFormat F> static int register_plugin(void* user_data, vmdplugin_t* vmd_plugin) {
    auto user_plugin = static_cast<molfile_plugin_t**>(user_data);
    assert(std::string(MOLFILE_PLUGIN_TYPE) == std::string(vmd_plugin->type));

    auto plugin = reinterpret_cast<molfile_plugin_t*>(vmd_plugin);
    // When this callback is called multiple times with more than one plugin,
    // only register the one whe want
    if (MolfilePluginData<F>().reader() == plugin->name) {
        *user_plugin = plugin;
    }

    return VMDPLUGIN_SUCCESS;
}

static int molfiles_to_chemfiles_warning(int level, const char* message) {
    if (level == VMDCON_ERROR || level == VMDCON_WARN) {
        send_warning(message);
    }
    return 0;
}

/******************************************************************************/

template <MolfileFormat F>
Molfile<F>::Molfile(std::string path, File::Mode mode, File::Compression compression)
    : path_(std::move(path)), plugin_handle_(nullptr), data_(nullptr), natoms_(0) {
    if (mode != File::READ) {
        throw format_error(
            "molfiles based format {} is only available in read mode", plugin_data_.format()
        );
    }

    if (compression != File::DEFAULT) {
        throw format_error(
            "molfiles based format {} do not support compression", plugin_data_.format()
        );
    }

    if (plugin_data_.init()) {
        throw format_error(
            "could not initialize the {} plugin", plugin_data_.format()
        );
    }

    if (plugin_data_.registration(&plugin_handle_, register_plugin<F>)) {
        throw format_error(
            "could not register the {} plugin", plugin_data_.format()
        );
    }

    // Check the ABI version of the plugin
    assert(plugin_handle_->abiversion == vmdplugin_ABIVERSION);
    // Redirect console output to chemfiles warnings
    plugin_handle_->cons_fputs = molfiles_to_chemfiles_warning;

    // Check that needed functions are here
    if (plugin_handle_->open_file_read == nullptr ||
        (plugin_handle_->read_next_timestep == nullptr && plugin_handle_->read_timestep == nullptr ) ||
        (plugin_handle_->close_file_read == nullptr )) {
        throw format_error(
            "the {} plugin does not have read capacities", plugin_data_.format()
        );
    }

    data_ = plugin_handle_->open_file_read(
        path_.c_str(), plugin_handle_->name, &natoms_
    );

    if (data_ == nullptr) {
        throw format_error(
            "could not open the file at '{}' with {} plugin", path_, plugin_data_.format()
        );
    }

    read_topology();
}

template <MolfileFormat F> Molfile<F>::~Molfile() {
    if (data_) {
        plugin_handle_->close_file_read(data_);
    }
    plugin_data_.fini();
}

template <MolfileFormat F> int Molfile<F>::read_next_timestep(molfile_timestep_t* timestep) {
    if (plugin_handle_->read_next_timestep != nullptr) {
        // This function is provided by classical molecular simulation format.
        return plugin_handle_->read_next_timestep(data_, natoms_, timestep);
    } else if (plugin_handle_->read_timestep != nullptr) {
        // This function is provided by quantum molecular simulation format.
        return plugin_handle_->read_timestep(
            data_, natoms_, timestep, nullptr, nullptr
        );
    } else {
        throw format_error(
            "both read_next_timestep and read_timestep are missing in this "
            "plugin. This is a bug"
        );
    }
}

template <MolfileFormat F> void Molfile<F>::read(Frame& frame) {
    std::vector<float> coords(3 * static_cast<size_t>(natoms_));
    std::vector<float> velocities(0);

    molfile_timestep_t timestep{nullptr, nullptr, 0, 0, 0, 0, 0, 0, 0};
    timestep.coords = coords.data();
    if (plugin_data_.have_velocities()) {
        velocities.resize(3 * static_cast<size_t>(natoms_));
        timestep.velocities = velocities.data();
    }

    int status = read_next_timestep(&timestep);
    if (status != MOLFILE_SUCCESS) {
        throw format_error(
            "error while reading the file at '{}' with {} plugin",
            path_, plugin_data_.format()
        );
    }

    if (topology_) {
        frame.resize(topology_->size());
        frame.set_topology(*topology_);
    }
    molfile_to_frame(timestep, frame);

    frames_.emplace_back(std::move(frame.clone()));
}

template <MolfileFormat F> void Molfile<F>::read_step(size_t step, Frame& frame) {
    while (step >= frames_.size()) {
        Frame new_frame;
        this->read(new_frame);
    }
    frame = frames_.at(step).clone();
}

template <MolfileFormat F> size_t Molfile<F>::nsteps() {
    if (plugin_handle_->read_next_timestep == nullptr) {
        // FIXME: this is hacky, but the molden plugin does not respect a NULL
        // argument for molfile_timestep_t, so for now we are only able to read
        // a sinle step from all the QM format plugins.
        return 1;
    }
    size_t n = 0;
    int status = MOLFILE_SUCCESS;
    while (true) {
        status = read_next_timestep(nullptr);
        if (status == MOLFILE_SUCCESS) {
            n++;
        } else {
            break;
        }
    }
    // We need to close and re-open the file
    plugin_handle_->close_file_read(data_);
    int unused = 0;
    data_ = plugin_handle_->open_file_read(path_.c_str(), plugin_handle_->name, &unused);<commit_msg>Do not std::move temporary object<commit_after>// From vmdconio.h
#define VMDCON_WARN      2
#define VMDCON_ERROR     3

extern "C" {
    #include <vmdplugin.h>
    #include <molfile_plugin.h>
}

#include <cassert>
#include <array>
#include <string>
#include <vector>
#include <unordered_map>

#include "chemfiles/File.hpp"
#include "chemfiles/Format.hpp"
#include "chemfiles/Atom.hpp"
#include "chemfiles/Frame.hpp"
#include "chemfiles/Residue.hpp"
#include "chemfiles/Topology.hpp"

#include "chemfiles/types.hpp"
#include "chemfiles/warnings.hpp"
#include "chemfiles/error_fmt.hpp"
#include "chemfiles/external/span.hpp"
#include "chemfiles/external/optional.hpp"

#include "chemfiles/formats/Molfile.hpp"

using namespace chemfiles;

/******************************************************************************/
#define PLUGINS_DATA(FORMAT, PLUGIN, READER, VELOCITIES)                       \
    extern "C" int PLUGIN##_register(void*, vmdplugin_register_cb); /*NOLINT*/ \
    extern "C" int PLUGIN##_fini(void); /*NOLINT*/                             \
    extern "C" int PLUGIN##_init(void); /*NOLINT*/                             \
    template <> struct MolfilePluginData<FORMAT> {                             \
        int init() { return PLUGIN##_init(); }                                 \
        int registration(void* data, vmdplugin_register_cb callback) {         \
            return PLUGIN##_register(data, callback);                          \
        }                                                                      \
        int fini() { return PLUGIN##_fini(); }                                 \
        std::string format() const {return #FORMAT;}                           \
        std::string plugin_name() const {return #PLUGIN;}                      \
        std::string reader() const {return #READER;}                           \
        bool have_velocities() const {return VELOCITIES;}                     \
    }

namespace chemfiles {
    PLUGINS_DATA(DCD,               dcdplugin,          dcd,            false);
    PLUGINS_DATA(TRJ,               gromacsplugin,      trj,            false);
    PLUGINS_DATA(LAMMPS,            lammpsplugin,       lammpstrj,      true);
    PLUGINS_DATA(MOLDEN,            moldenplugin,       molden,         false);
}

#undef PLUGINS_FUNCTIONS
/******************************************************************************/

template <MolfileFormat F> static int register_plugin(void* user_data, vmdplugin_t* vmd_plugin) {
    auto user_plugin = static_cast<molfile_plugin_t**>(user_data);
    assert(std::string(MOLFILE_PLUGIN_TYPE) == std::string(vmd_plugin->type));

    auto plugin = reinterpret_cast<molfile_plugin_t*>(vmd_plugin);
    // When this callback is called multiple times with more than one plugin,
    // only register the one whe want
    if (MolfilePluginData<F>().reader() == plugin->name) {
        *user_plugin = plugin;
    }

    return VMDPLUGIN_SUCCESS;
}

static int molfiles_to_chemfiles_warning(int level, const char* message) {
    if (level == VMDCON_ERROR || level == VMDCON_WARN) {
        send_warning(message);
    }
    return 0;
}

/******************************************************************************/

template <MolfileFormat F>
Molfile<F>::Molfile(std::string path, File::Mode mode, File::Compression compression)
    : path_(std::move(path)), plugin_handle_(nullptr), data_(nullptr), natoms_(0) {
    if (mode != File::READ) {
        throw format_error(
            "molfiles based format {} is only available in read mode", plugin_data_.format()
        );
    }

    if (compression != File::DEFAULT) {
        throw format_error(
            "molfiles based format {} do not support compression", plugin_data_.format()
        );
    }

    if (plugin_data_.init()) {
        throw format_error(
            "could not initialize the {} plugin", plugin_data_.format()
        );
    }

    if (plugin_data_.registration(&plugin_handle_, register_plugin<F>)) {
        throw format_error(
            "could not register the {} plugin", plugin_data_.format()
        );
    }

    // Check the ABI version of the plugin
    assert(plugin_handle_->abiversion == vmdplugin_ABIVERSION);
    // Redirect console output to chemfiles warnings
    plugin_handle_->cons_fputs = molfiles_to_chemfiles_warning;

    // Check that needed functions are here
    if (plugin_handle_->open_file_read == nullptr ||
        (plugin_handle_->read_next_timestep == nullptr && plugin_handle_->read_timestep == nullptr ) ||
        (plugin_handle_->close_file_read == nullptr )) {
        throw format_error(
            "the {} plugin does not have read capacities", plugin_data_.format()
        );
    }

    data_ = plugin_handle_->open_file_read(
        path_.c_str(), plugin_handle_->name, &natoms_
    );

    if (data_ == nullptr) {
        throw format_error(
            "could not open the file at '{}' with {} plugin", path_, plugin_data_.format()
        );
    }

    read_topology();
}

template <MolfileFormat F> Molfile<F>::~Molfile() {
    if (data_) {
        plugin_handle_->close_file_read(data_);
    }
    plugin_data_.fini();
}

template <MolfileFormat F> int Molfile<F>::read_next_timestep(molfile_timestep_t* timestep) {
    if (plugin_handle_->read_next_timestep != nullptr) {
        // This function is provided by classical molecular simulation format.
        return plugin_handle_->read_next_timestep(data_, natoms_, timestep);
    } else if (plugin_handle_->read_timestep != nullptr) {
        // This function is provided by quantum molecular simulation format.
        return plugin_handle_->read_timestep(
            data_, natoms_, timestep, nullptr, nullptr
        );
    } else {
        throw format_error(
            "both read_next_timestep and read_timestep are missing in this "
            "plugin. This is a bug"
        );
    }
}

template <MolfileFormat F> void Molfile<F>::read(Frame& frame) {
    std::vector<float> coords(3 * static_cast<size_t>(natoms_));
    std::vector<float> velocities(0);

    molfile_timestep_t timestep{nullptr, nullptr, 0, 0, 0, 0, 0, 0, 0};
    timestep.coords = coords.data();
    if (plugin_data_.have_velocities()) {
        velocities.resize(3 * static_cast<size_t>(natoms_));
        timestep.velocities = velocities.data();
    }

    int status = read_next_timestep(&timestep);
    if (status != MOLFILE_SUCCESS) {
        throw format_error(
            "error while reading the file at '{}' with {} plugin",
            path_, plugin_data_.format()
        );
    }

    if (topology_) {
        frame.resize(topology_->size());
        frame.set_topology(*topology_);
    }
    molfile_to_frame(timestep, frame);

    frames_.emplace_back(frame.clone());
}

template <MolfileFormat F> void Molfile<F>::read_step(size_t step, Frame& frame) {
    while (step >= frames_.size()) {
        Frame new_frame;
        this->read(new_frame);
    }
    frame = frames_.at(step).clone();
}

template <MolfileFormat F> size_t Molfile<F>::nsteps() {
    if (plugin_handle_->read_next_timestep == nullptr) {
        // FIXME: this is hacky, but the molden plugin does not respect a NULL
        // argument for molfile_timestep_t, so for now we are only able to read
        // a sinle step from all the QM format plugins.
        return 1;
    }
    size_t n = 0;
    int status = MOLFILE_SUCCESS;
    while (true) {
        status = read_next_timestep(nullptr);
        if (status == MOLFILE_SUCCESS) {
            n++;
        } else {
            break;
        }
    }
    // We need to close and re-open the file
    plugin_handle_->close_file_read(data_);
    int unused = 0;
    data_ = plugin_handle_->open_file_read(path_.c_str(), plugin_handle_->name, &unused);
{'fraction_non_alphanumeric': 0.14152340480329664, 'fraction_numerical': 0.0021891700470027687, 'mean_word_length': 2.5340159271899885, 'pattern_counts': {'":': 0, '<': 63, '<?xml version=': 0, '>': 107, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 10, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2848074', 'n_tokens_mistral': 4691, 'n_tokens_neox': 4616, 'n_words': 1055}