<commit_before>#include "string.hh"

#include "exception.hh"
#include "containers.hh"
#include "utf8_iterator.hh"
#include "unit_tests.hh"

#include <cstdio>

namespace Kakoune
{

Vector<String> split(StringView str, char separator, char escape)
{
    Vector<String> res;
    auto it = str.begin();
    while (it != str.end())
    {
        res.emplace_back();
        String& element = res.back();
        while (it != str.end())
        {
            auto c = *it;
            if (c == escape and it + 1 != str.end() and *(it+1) == separator)
            {
                element += separator;
                it += 2;
            }
            else if (c == separator)
            {
                ++it;
                break;
            }
            else
            {
                element += c;
                ++it;
            }
        }
    }
    return res;
}

Vector<StringView> split(StringView str, char separator)
{
    Vector<StringView> res;
    auto beg = str.begin();
    for (auto it = beg; it != str.end(); ++it)
    {
        if (*it == separator)
        {
            res.emplace_back(beg, it);
            beg = it + 1;
        }
    }
    res.emplace_back(beg, str.end());
    return res;
}

String escape(StringView str, StringView characters, char escape)
{
    String res;
    res.reserve(str.length());
    for (auto& c : str)
    {
        if (contains(characters, c))
            res += escape;
        res += c;
    }
    return res;
}

String unescape(StringView str, StringView characters, char escape)
{
    String res;
    res.reserve(str.length());
    for (auto& c : str)
    {
        if (contains(characters, c) and not res.empty() and res.back() == escape)
            res.back() = c;
        else
            res += c;
    }
    return res;
}

String indent(StringView str, StringView indent)
{
    String res;
    res.reserve(str.length());
    bool was_eol = true;
    for (ByteCount i = 0; i < str.length(); ++i)
    {
        if (was_eol)
            res += indent;
        res += str[i];
        was_eol = is_eol(str[i]);
    }
    return res;
}

Optional<int> str_to_int_ifp(StringView str)
{
    unsigned int res = 0;
    bool negative = false;
    for (auto it = str.begin(), end = str.end(); it != end; ++it)
    {
        const char c = *it;
        if (it == str.begin() and c == '-')
            negative = true;
        else if (c >= '0' and c <= '9')
            res = res * 10 + c - '0';
        else
            return {};
    }
    return negative ? -(int)res : (int)res;
}

int str_to_int(StringView str)
{
    if (auto val = str_to_int_ifp(str))
        return *val;
    throw str + " is not a number";
}

InplaceString<16> to_string(int val)
{<commit_msg>Fix wrong exception type in str_to_int<commit_after>#include "string.hh"

#include "exception.hh"
#include "containers.hh"
#include "utf8_iterator.hh"
#include "unit_tests.hh"

#include <cstdio>

namespace Kakoune
{

Vector<String> split(StringView str, char separator, char escape)
{
    Vector<String> res;
    auto it = str.begin();
    while (it != str.end())
    {
        res.emplace_back();
        String& element = res.back();
        while (it != str.end())
        {
            auto c = *it;
            if (c == escape and it + 1 != str.end() and *(it+1) == separator)
            {
                element += separator;
                it += 2;
            }
            else if (c == separator)
            {
                ++it;
                break;
            }
            else
            {
                element += c;
                ++it;
            }
        }
    }
    return res;
}

Vector<StringView> split(StringView str, char separator)
{
    Vector<StringView> res;
    auto beg = str.begin();
    for (auto it = beg; it != str.end(); ++it)
    {
        if (*it == separator)
        {
            res.emplace_back(beg, it);
            beg = it + 1;
        }
    }
    res.emplace_back(beg, str.end());
    return res;
}

String escape(StringView str, StringView characters, char escape)
{
    String res;
    res.reserve(str.length());
    for (auto& c : str)
    {
        if (contains(characters, c))
            res += escape;
        res += c;
    }
    return res;
}

String unescape(StringView str, StringView characters, char escape)
{
    String res;
    res.reserve(str.length());
    for (auto& c : str)
    {
        if (contains(characters, c) and not res.empty() and res.back() == escape)
            res.back() = c;
        else
            res += c;
    }
    return res;
}

String indent(StringView str, StringView indent)
{
    String res;
    res.reserve(str.length());
    bool was_eol = true;
    for (ByteCount i = 0; i < str.length(); ++i)
    {
        if (was_eol)
            res += indent;
        res += str[i];
        was_eol = is_eol(str[i]);
    }
    return res;
}

Optional<int> str_to_int_ifp(StringView str)
{
    unsigned int res = 0;
    bool negative = false;
    for (auto it = str.begin(), end = str.end(); it != end; ++it)
    {
        const char c = *it;
        if (it == str.begin() and c == '-')
            negative = true;
        else if (c >= '0' and c <= '9')
            res = res * 10 + c - '0';
        else
            return {};
    }
    return negative ? -(int)res : (int)res;
}

int str_to_int(StringView str)
{
    if (auto val = str_to_int_ifp(str))
        return *val;
    throw runtime_error{str + " is not a number"};
}

InplaceString<16> to_string(int val)
{
{'fraction_non_alphanumeric': 0.13994169096209913, 'fraction_numerical': 0.00510204081632653, 'mean_word_length': 1.6854207436399218, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 19, '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': '5580262', 'n_tokens_mistral': 1841, 'n_tokens_neox': 1791, 'n_words': 487}