<commit_before>/* Copyright (C) 2014 INRA
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include "io.hpp"
#include "model.hpp"
#include "utils.hpp"
#include <fstream>
#include <functional>
#include <stack>
#include <stdexcept>
#include <string>
#include <unordered_map>
#include <cstring>
#include <expat.h>
#include <iostream>

namespace {

    struct str_compare
    {
        bool operator()(const char* lhs, const char* rhs) const noexcept
        {
            return std::strcmp(lhs, rhs) == 0;
        }
    };

    struct str_hash
    {
        size_t operator()(const char* str) const noexcept
        {
            size_t hash = 0;
            int c;

            while ((c = *str++) != '\0')
                hash = c + (hash << 6) + (hash << 16) - hash;

            return hash;
        }
    };

    struct dexi_reader
    {
        dexi_reader(std::istream& is, efyj::dexi& dex) noexcept
            : is(is), dex(dex)
        {
        }

        void read(std::size_t buffer_size)
        {
            XML_Parser parser = XML_ParserCreate(NULL);
            efyj::scope_exit parser_free([&parser]() {XML_ParserFree(parser);});

            parser_data data(parser, dex);

            XML_SetElementHandler(parser, dexi_reader::start_element,
                                  dexi_reader::end_element);
            XML_SetCharacterDataHandler(parser, dexi_reader::character_data);
            XML_SetUserData(parser, reinterpret_cast <void*>(&data));

            while (is.good() and not is.eof()) {
                char *buffer = (char*)XML_GetBuffer(parser, buffer_size);
                if (not buffer)
                    throw std::bad_alloc();

                is.read(buffer, buffer_size);

                if (not ::XML_ParseBuffer(parser, is.gcount(), is.eof()))
                    throw efyj::xml_parse_error(
                        data.error_message,
                        XML_GetCurrentLineNumber(parser),
                        XML_GetCurrentColumnNumber(parser),
                        XML_GetErrorCode(parser));
            }
        }

    private:
        std::istream& is;
        efyj::dexi& dex;

        enum class stack_identifier {
            DEXi, LINE, OPTION, SETTINGS, REPORTS, ATTRIBUTE, NAME, DESCRIPTION,
            SCALE, ORDER, SCALEVALUE, GROUP, FUNCTION, LOW, ENTERED, CONSIST
        };

        std::string stack_identifier_to_str(stack_identifier id)
        {
            switch (id) {
            case stack_identifier::DEXi:
                return "DEXi";
            case stack_identifier::LINE:
                return "LINE";
            case stack_identifier::OPTION:
                return "OPTION";
            case stack_identifier::SETTINGS:
                return "SETTINGS";
            case stack_identifier::REPORTS:
                return "REPORTS";
            case stack_identifier::ATTRIBUTE:
                return "ATTRIBUTE";
            case stack_identifier::NAME:
                return "NAME";
            case stack_identifier::DESCRIPTION:
                return "DESCRIPTION";
            case stack_identifier::SCALE:
                return "SCALE";
            case stack_identifier::ORDER:
                return "ORDER";
            case stack_identifier::SCALEVALUE:
                return "SCALEVALUE";
            case stack_identifier::GROUP:
                return "GROUP";
            case stack_identifier::FUNCTION:
                return "FUNCTION";
            case stack_identifier::LOW:
                return "LOW";
            case stack_identifier::ENTERED:
                return "ENTERED";
            case stack_identifier::CONSIST:
                return "CONSIST";
            }

            throw std::logic_error("Remove a stupid GCC 4.8 warning");
        }

        static stack_identifier str_to_stack_identifier(const char* name)
        {
            static const std::unordered_map <const char*, stack_identifier,
                         str_hash, str_compare> stack_identifier_map(
                             {{"DEXi", stack_identifier::DEXi},<commit_msg>io: remove useless function<commit_after>/* Copyright (C) 2014 INRA
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include "io.hpp"
#include "model.hpp"
#include "utils.hpp"
#include <fstream>
#include <functional>
#include <stack>
#include <stdexcept>
#include <string>
#include <unordered_map>
#include <cstring>
#include <expat.h>
#include <iostream>

namespace {

    struct str_compare
    {
        bool operator()(const char* lhs, const char* rhs) const noexcept
        {
            return std::strcmp(lhs, rhs) == 0;
        }
    };

    struct str_hash
    {
        size_t operator()(const char* str) const noexcept
        {
            size_t hash = 0;
            int c;

            while ((c = *str++) != '\0')
                hash = c + (hash << 6) + (hash << 16) - hash;

            return hash;
        }
    };

    struct dexi_reader
    {
        dexi_reader(std::istream& is, efyj::dexi& dex) noexcept
            : is(is), dex(dex)
        {
        }

        void read(std::size_t buffer_size)
        {
            XML_Parser parser = XML_ParserCreate(NULL);
            efyj::scope_exit parser_free([&parser]() {XML_ParserFree(parser);});

            parser_data data(parser, dex);

            XML_SetElementHandler(parser, dexi_reader::start_element,
                                  dexi_reader::end_element);
            XML_SetCharacterDataHandler(parser, dexi_reader::character_data);
            XML_SetUserData(parser, reinterpret_cast <void*>(&data));

            while (is.good() and not is.eof()) {
                char *buffer = (char*)XML_GetBuffer(parser, buffer_size);
                if (not buffer)
                    throw std::bad_alloc();

                is.read(buffer, buffer_size);

                if (not ::XML_ParseBuffer(parser, is.gcount(), is.eof()))
                    throw efyj::xml_parse_error(
                        data.error_message,
                        XML_GetCurrentLineNumber(parser),
                        XML_GetCurrentColumnNumber(parser),
                        XML_GetErrorCode(parser));
            }
        }

    private:
        std::istream& is;
        efyj::dexi& dex;

        enum class stack_identifier {
            DEXi, LINE, OPTION, SETTINGS, REPORTS, ATTRIBUTE, NAME, DESCRIPTION,
            SCALE, ORDER, SCALEVALUE, GROUP, FUNCTION, LOW, ENTERED, CONSIST
        };

        static stack_identifier str_to_stack_identifier(const char* name)
        {
            static const std::unordered_map <const char*, stack_identifier,
                         str_hash, str_compare> stack_identifier_map(
                             {{"DEXi", stack_identifier::DEXi},
{'fraction_non_alphanumeric': 0.09058956916099774, 'fraction_numerical': 0.002494331065759637, 'mean_word_length': 2.111463844797178, 'pattern_counts': {'":': 0, '<': 33, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 2}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1123535', 'n_tokens_mistral': 2440, 'n_tokens_neox': 2306, 'n_words': 736}