summaryrefslogtreecommitdiff
path: root/src/shared_string.cc
diff options
context:
space:
mode:
authorMaxime Coste <mawww@kakoune.org>2017-02-22 23:56:52 +0000
committerMaxime Coste <mawww@kakoune.org>2017-02-23 00:03:32 +0000
commitd9abc2a156df03d264ec23c947cf7cf4c5a581ec (patch)
treed0ee6a0f275e37883fe617f7de462255109d22b4 /src/shared_string.cc
parent7a143a7f7cf25bd2ef8b14a13d0bd31d20a12dfc (diff)
Refactor StringData and StringRegistry to remove need for purging
Purging unused strings could get pretty expensive with a lot of interned strings as it requiered iterating on all of them. Use a flag on the refcount of the StringData to see if the string is interned, and notify the StringRegistry in this case. This should improve the speed of editing big files with many words, such as the one described in #1195
Diffstat (limited to 'src/shared_string.cc')
-rw-r--r--src/shared_string.cc44
1 files changed, 29 insertions, 15 deletions
diff --git a/src/shared_string.cc b/src/shared_string.cc
index 9d816a58..6cf270c2 100644
--- a/src/shared_string.cc
+++ b/src/shared_string.cc
@@ -4,29 +4,43 @@
namespace Kakoune
{
-StringDataPtr StringRegistry::intern(StringView str)
+StringDataPtr StringData::create(ArrayView<const StringView> strs)
{
- auto it = m_strings.find(str);
- if (it == m_strings.end())
+ const int len = std::accumulate(strs.begin(), strs.end(), 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<char*>(res + 1);
+ for (auto& str : strs)
{
- auto data = StringData::create(str);
- it = m_strings.emplace(data->strview(), data).first;
+ memcpy(data, str.begin(), (size_t)str.length());
+ data += (int)str.length();
}
- return it->second;
+ *data = 0;
+ return RefPtr<StringData, PtrPolicy>{res};
}
-void StringRegistry::purge_unused()
+StringDataPtr StringData::Registry::intern(StringView str)
{
- for (auto it = m_strings.begin(); it != m_strings.end(); )
- {
- if (it->second->refcount == 1)
- it = m_strings.erase(it);
- else
- ++it;
- }
+ auto it = m_strings.find(str);
+ if (it != m_strings.end())
+ return StringDataPtr{it->second};
+
+ auto data = StringData::create(str);
+ data->refcount |= interned_flag;
+ m_strings.emplace(data->strview(), data.get());
+ return data;
+}
+
+void StringData::Registry::remove(StringView str)
+{
+ auto it = m_strings.find(str);
+ kak_assert(it != m_strings.end());
+ m_strings.erase(it);
}
-void StringRegistry::debug_stats() const
+void StringData::Registry::debug_stats() const
{
write_to_debug_buffer("Shared Strings stats:");
size_t total_refcount = 0;