diff --git a/src/buffer.cc b/src/buffer.cc index 7054e6b8..9c38605a 100644 --- a/src/buffer.cc +++ b/src/buffer.cc @@ -430,14 +430,14 @@ BufferRange Buffer::do_insert(BufferCoord pos, StringView content) if (content[i] == '\n') { StringView line = content.substr(start, i + 1 - start); - new_lines.push_back(start == 0 ? StringData::create({prefix, line}) : StringData::create({line})); + new_lines.push_back(start == 0 ? StringData::create(prefix, line) : StringData::create(line)); start = i + 1; } } if (start == 0) - new_lines.push_back(StringData::create({prefix, content, suffix})); + new_lines.push_back(StringData::create(prefix, content, suffix)); else if (start != content.length() or not suffix.empty()) - new_lines.push_back(StringData::create({content.substr(start), suffix})); + new_lines.push_back(StringData::create(content.substr(start), suffix)); auto line_it = m_lines.begin() + (int)pos.line; auto new_lines_it = new_lines.begin(); @@ -466,7 +466,7 @@ BufferCoord Buffer::do_erase(BufferCoord begin, BufferCoord end) StringView prefix = m_lines[begin.line].substr(0, begin.column); StringView suffix = end.line == line_count() ? StringView{} : m_lines[end.line].substr(end.column); - auto new_line = (not prefix.empty() or not suffix.empty()) ? StringData::create({prefix, suffix}) : StringDataPtr{}; + auto new_line = (not prefix.empty() or not suffix.empty()) ? StringData::create(prefix, suffix) : StringDataPtr{}; m_lines.erase(m_lines.begin() + (int)begin.line, m_lines.begin() + (int)end.line); m_changes.push_back({ Change::Erase, begin, end }); @@ -691,7 +691,7 @@ String Buffer::debug_description() const UnitTest test_buffer{[]() { - auto make_lines = [](auto&&... lines) { return BufferLines{StringData::create({lines})...}; }; + auto make_lines = [](auto&&... lines) { return BufferLines{StringData::create(lines)...}; }; Buffer empty_buffer("empty", Buffer::Flags::None, make_lines("\n")); @@ -738,7 +738,7 @@ UnitTest test_buffer{[]() UnitTest test_undo{[]() { - auto make_lines = [](auto&&... lines) { return BufferLines{StringData::create({lines})...}; }; + auto make_lines = [](auto&&... lines) { return BufferLines{StringData::create(lines)...}; }; Buffer buffer("test", Buffer::Flags::None, make_lines("allo ?\n", "mais que fais la police\n", " hein ?\n", " youpi\n")); auto pos = buffer.end_coord(); diff --git a/src/buffer_manager.cc b/src/buffer_manager.cc index 32d03fc1..22ccf366 100644 --- a/src/buffer_manager.cc +++ b/src/buffer_manager.cc @@ -83,8 +83,8 @@ Buffer& BufferManager::get_first_buffer() { if (all_of(m_buffers, [](auto& b) { return (b->flags() & Buffer::Flags::Debug); })) create_buffer("*scratch*", Buffer::Flags::None, - {StringData::create({"*** this is a *scratch* buffer which won't be automatically saved ***\n"}), - StringData::create({"*** use it for notes or open a file buffer with the :edit command ***\n"})}, + {StringData::create("*** this is a *scratch* buffer which won't be automatically saved ***\n"), + StringData::create("*** use it for notes or open a file buffer with the :edit command ***\n")}, ByteOrderMark::None, EolFormat::Lf, {InvalidTime, {}, {}}); return *m_buffers.back(); diff --git a/src/buffer_utils.cc b/src/buffer_utils.cc index 996f6be5..effb7cc7 100644 --- a/src/buffer_utils.cc +++ b/src/buffer_utils.cc @@ -97,12 +97,12 @@ static BufferLines parse_lines(const char* pos, const char* end, EolFormat eolfo if ((eol - pos) >= std::numeric_limits::max()) throw runtime_error("line is too long"); - lines.emplace_back(StringData::create({{pos, eol - (eolformat == EolFormat::Crlf and eol != end ? 1 : 0)}, "\n"})); + lines.emplace_back(StringData::create(StringView{pos, eol - (eolformat == EolFormat::Crlf and eol != end ? 1 : 0)}, "\n")); pos = eol + 1; } if (lines.empty()) - lines.emplace_back(StringData::create({"\n"})); + lines.emplace_back(StringData::create("\n")); return lines; } @@ -179,12 +179,12 @@ Buffer* create_fifo_buffer(String name, int fd, Buffer::Flags flags, bool scroll { buffer->flags() |= Buffer::Flags::NoUndo | flags; buffer->values().clear(); - buffer->reload({StringData::create({"\n"})}, ByteOrderMark::None, EolFormat::Lf, {InvalidTime, {}, {}}); + buffer->reload({StringData::create("\n")}, ByteOrderMark::None, EolFormat::Lf, {InvalidTime, {}, {}}); } else buffer = buffer_manager.create_buffer( std::move(name), flags | Buffer::Flags::Fifo | Buffer::Flags::NoUndo, - {StringData::create({"\n"})}, ByteOrderMark::None, EolFormat::Lf, {InvalidTime, {}, {}}); + {StringData::create("\n")}, ByteOrderMark::None, EolFormat::Lf, {InvalidTime, {}, {}}); struct FifoWatcher : FDWatcher { diff --git a/src/line_modification.cc b/src/line_modification.cc index 5b5f523d..49cadf62 100644 --- a/src/line_modification.cc +++ b/src/line_modification.cc @@ -196,7 +196,7 @@ void LineRangeSet::remove_range(LineRange range) UnitTest test_line_modifications{[]() { - auto make_lines = [](auto&&... lines) { return BufferLines{StringData::create({lines})...}; }; + auto make_lines = [](auto&&... lines) { return BufferLines{StringData::create(lines)...}; }; { Buffer buffer("test", Buffer::Flags::None, make_lines("line 1\n", "line 2\n")); diff --git a/src/shared_string.cc b/src/shared_string.cc index 862277bd..f88008b1 100644 --- a/src/shared_string.cc +++ b/src/shared_string.cc @@ -1,30 +1,9 @@ #include "shared_string.hh" #include "buffer_utils.hh" -#include - namespace Kakoune { -StringDataPtr StringData::create(ArrayView strs) -{ - const int len = accumulate(strs, 0, [](int l, StringView s) { - return l + (int)s.length(); - }); - void* ptr = StringData::operator new(sizeof(StringData) + len + 1); - auto* res = new (ptr) StringData(len); - auto* data = reinterpret_cast(res + 1); - for (auto& str : strs) - { - if (str.length() == 0) // memccpy(..., nullptr, 0) is UB - continue; - memcpy(data, str.begin(), (size_t)str.length()); - data += (int)str.length(); - } - *data = 0; - return RefPtr{res}; -} - StringDataPtr StringData::Registry::intern(StringView str, size_t hash) { kak_assert(hash_value(str) == hash); diff --git a/src/shared_string.hh b/src/shared_string.hh index 17bb72d8..bb06c7fc 100644 --- a/src/shared_string.hh +++ b/src/shared_string.hh @@ -7,6 +7,7 @@ #include "hash_map.hh" #include +#include namespace Kakoune { @@ -32,12 +33,11 @@ private: static void inc_ref(StringData* r, void*) noexcept { ++r->refcount; } static void dec_ref(StringData* r, void*) noexcept { - if ((--r->refcount & refcount_mask) == 0) - { - if (r->refcount & interned_flag) - Registry::instance().remove(r->strview()); - StringData::operator delete(r, sizeof(StringData) + r->length + 1); - } + if ((--r->refcount & refcount_mask) > 0) + return; + if (r->refcount & interned_flag) + Registry::instance().remove(r->strview()); + StringData::operator delete(r, sizeof(StringData) + r->length + 1); } static void ptr_moved(StringData*, void*, void*) noexcept {} }; @@ -57,7 +57,23 @@ public: HashMap m_strings; }; - static Ptr create(ArrayView strs); + static Ptr create(ConvertibleTo auto&&... strs) + { + const int len = ((int)StringView{strs}.length() + ...); + void* ptr = StringData::operator new(sizeof(StringData) + len + 1); + auto* res = new (ptr) StringData(len); + auto* data = reinterpret_cast(res + 1); + auto append = [&](StringView str) { + if (str.empty()) // memccpy(..., nullptr, 0) is UB + return; + memcpy(data, str.begin(), (size_t)str.length()); + data += (int)str.length(); + }; + (append(strs), ...); + *data = 0; + return RefPtr{res}; + } + }; using StringDataPtr = StringData::Ptr; diff --git a/src/word_db.cc b/src/word_db.cc index 498d6a41..755304ca 100644 --- a/src/word_db.cc +++ b/src/word_db.cc @@ -223,7 +223,7 @@ UnitTest test_word_db{[]() }); }; - auto make_lines = [](auto&&... lines) { return BufferLines{StringData::create({lines})...}; }; + auto make_lines = [](auto&&... lines) { return BufferLines{StringData::create(lines)...}; }; Buffer buffer("test", Buffer::Flags::None, make_lines("tchou mutch\n", "tchou kanaky tchou\n", "\n", "tchaa tchaa\n", "allo\n"));