// Copyright 2019 Google LLC.
// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.

#include "modules/skplaintexteditor/include/stringslice.h"

#include <algorithm>
#include <cassert>
#include <cstdlib>
#include <cstring>

using namespace SkPlainTextEditor;

void StringSlice::FreeWrapper::operator()(void* t) { std::free(t); }

StringSlice::StringSlice(StringSlice&& that)
    : fPtr(std::move(that.fPtr))
    , fLength(that.fLength)
    , fCapacity(that.fCapacity)
{
    that.fLength = 0;
    that.fCapacity = 0;
}

StringSlice& StringSlice::operator=(StringSlice&& that) {
    if (this != &that) {
        this->~StringSlice();
        new (this)StringSlice(std::move(that));
    }
    return *this;
}

StringSlice& StringSlice::operator=(const StringSlice& that) {
    if (this != &that) {
        fLength = 0;
        if (that.size() > 0) {
            this->insert(0, that.begin(), that.size());
        }
    }
    return *this;
}

void StringSlice::insert(std::size_t offset, const char* text, std::size_t length) {
    if (length) {
        offset = std::min(fLength, offset);
        this->reserve(fLength + length);
        char* s = fPtr.get();
        assert(s);
        if (offset != fLength) {
            std::memmove(s + offset + length, s + offset, fLength - offset);
        }
        if (text) {
            std::memcpy(s + offset, text, length);
        } else {
            std::memset(s + offset, 0, length);
        }
        fLength += length;
    }
}

void StringSlice::remove(std::size_t offset, std::size_t length) {
    if (length && offset < fLength) {
        length = std::min(length, fLength - offset);
        assert(length > 0);
        assert(length + offset <= fLength);
        if (length + offset < fLength) {
            char* s = fPtr.get();
            assert(s);
            std::memmove(s + offset, s + offset + length, fLength - (length + offset));
        }
        fLength -= length;
    }
}

void StringSlice::realloc(std::size_t size) {
    // round up to multiple of (1 << kBits) bytes
    static constexpr unsigned kBits = 4;
    fCapacity = size ? (((size - 1) >> kBits) + 1) << kBits : 0;
    assert(fCapacity % (1u << kBits) == 0);
    assert(fCapacity >= size);
    fPtr.reset((char*)std::realloc(fPtr.release(), fCapacity));
    assert(fCapacity >= fLength);
}
