<commit_before>#include "string.hh"

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

#include <cstdio>

namespace Kakoune
{

String::Data::Data(const char* data, size_t size, size_t capacity)
{
    if (capacity > Short::capacity)
    {
        if (capacity & 1)
            ++capacity;

        kak_assert(capacity < Long::max_capacity);
        l.ptr = Alloc{}.allocate(capacity+1);
        l.size = size;
        l.capacity = capacity;

        if (data != nullptr)
            memcpy(l.ptr, data, size);
        l.ptr[size] = 0;
    }
    else
        set_short(data, size);
}

String::Data::Data(Data&& other) noexcept
{
    if (other.is_long())
    {
        l = other.l;
        other.set_empty();
    }
    else
        s = other.s;
}

String::Data& String::Data::operator=(const Data& other)
{
    const size_t new_size = other.size();
    reserve<false>(new_size);
    memcpy(data(), other.data(), new_size+1);
    set_size(new_size);

    return *this;
}

String::Data& String::Data::operator=(Data&& other) noexcept
{
    release();

    if (other.is_long())
    {
        l = other.l;
        other.set_empty();
    }
    else
        s = other.s;

    return *this;
}

template<bool copy>
void String::Data::reserve(size_t new_capacity)
{<commit_msg>Fix String::Data copying/moving from self<commit_after>#include "string.hh"

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

#include <cstdio>

namespace Kakoune
{

String::Data::Data(const char* data, size_t size, size_t capacity)
{
    if (capacity > Short::capacity)
    {
        if (capacity & 1)
            ++capacity;

        kak_assert(capacity < Long::max_capacity);
        l.ptr = Alloc{}.allocate(capacity+1);
        l.size = size;
        l.capacity = capacity;

        if (data != nullptr)
            memcpy(l.ptr, data, size);
        l.ptr[size] = 0;
    }
    else
        set_short(data, size);
}

String::Data::Data(Data&& other) noexcept
{
    if (other.is_long())
    {
        l = other.l;
        other.set_empty();
    }
    else
        s = other.s;
}

String::Data& String::Data::operator=(const Data& other)
{
    if (&other == this)
        return *this;

    const size_t new_size = other.size();
    reserve<false>(new_size);
    memcpy(data(), other.data(), new_size+1);
    set_size(new_size);

    return *this;
}

String::Data& String::Data::operator=(Data&& other) noexcept
{
    if (&other == this)
        return *this;

    release();

    if (other.is_long())
    {
        l = other.l;
        other.set_empty();
    }
    else
        s = other.s;

    return *this;
}

template<bool copy>
void String::Data::reserve(size_t new_capacity)
{
{'fraction_non_alphanumeric': 0.15264684554024655, 'fraction_numerical': 0.0036258158085569255, 'mean_word_length': 2.5462724935732646, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 11, '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': '7168966', 'n_tokens_mistral': 971, 'n_tokens_neox': 950, 'n_words': 200}