Replace std::shared_ptr with homemade, intrusive, ref_ptr
That saves a lot of memory as sizeof(SharedString) is now one pointer less.
This commit is contained in:
parent
ef26b77aa7
commit
9b057896d4
65
src/ref_ptr.hh
Normal file
65
src/ref_ptr.hh
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
#ifndef ref_ptr_hh_INCLUDED
|
||||||
|
#define ref_ptr_hh_INCLUDED
|
||||||
|
|
||||||
|
namespace Kakoune
|
||||||
|
{
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct ref_ptr
|
||||||
|
{
|
||||||
|
ref_ptr() = default;
|
||||||
|
ref_ptr(T* ptr) : m_ptr(ptr) { acquire(); }
|
||||||
|
~ref_ptr() { release(); }
|
||||||
|
ref_ptr(const ref_ptr& other) : m_ptr(other.m_ptr) { acquire(); }
|
||||||
|
ref_ptr(ref_ptr&& other) : m_ptr(other.m_ptr) { other.m_ptr = nullptr; }
|
||||||
|
|
||||||
|
ref_ptr& operator=(const ref_ptr& other)
|
||||||
|
{
|
||||||
|
release();
|
||||||
|
m_ptr = other.m_ptr;
|
||||||
|
acquire();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
ref_ptr& operator=(ref_ptr&& other)
|
||||||
|
{
|
||||||
|
release();
|
||||||
|
m_ptr = other.m_ptr;
|
||||||
|
other.m_ptr = nullptr;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
T* operator->() const { return m_ptr; }
|
||||||
|
T& operator*() const { return *m_ptr; }
|
||||||
|
|
||||||
|
T* get() const { return m_ptr; }
|
||||||
|
|
||||||
|
explicit operator bool() { return m_ptr; }
|
||||||
|
|
||||||
|
friend bool operator==(const ref_ptr& lhs, const ref_ptr& rhs)
|
||||||
|
{
|
||||||
|
return lhs.m_ptr == rhs.m_ptr;
|
||||||
|
}
|
||||||
|
friend bool operator!=(const ref_ptr& lhs, const ref_ptr& rhs)
|
||||||
|
{
|
||||||
|
return lhs.m_ptr != rhs.m_ptr;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
T* m_ptr = nullptr;
|
||||||
|
|
||||||
|
void acquire()
|
||||||
|
{
|
||||||
|
if (m_ptr)
|
||||||
|
inc_ref_count(m_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void release()
|
||||||
|
{
|
||||||
|
if (m_ptr)
|
||||||
|
dec_ref_count(m_ptr);
|
||||||
|
m_ptr = nullptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // ref_ptr_hh_INCLUDED
|
|
@ -10,16 +10,16 @@ SharedString StringRegistry::intern(StringView str)
|
||||||
if (it == m_strings.end())
|
if (it == m_strings.end())
|
||||||
{
|
{
|
||||||
SharedString shared_str = str;
|
SharedString shared_str = str;
|
||||||
it = m_strings.emplace(StringView{shared_str}, shared_str.m_storage).first;
|
it = m_strings.emplace(shared_str, shared_str.m_storage).first;
|
||||||
}
|
}
|
||||||
return {*it->second, it->second};
|
return {it->second->strview(), it->second};
|
||||||
}
|
}
|
||||||
|
|
||||||
void StringRegistry::purge_unused()
|
void StringRegistry::purge_unused()
|
||||||
{
|
{
|
||||||
for (auto it = m_strings.begin(); it != m_strings.end(); )
|
for (auto it = m_strings.begin(); it != m_strings.end(); )
|
||||||
{
|
{
|
||||||
if (it->second.unique())
|
if (it->second->refcount == 1)
|
||||||
it = m_strings.erase(it);
|
it = m_strings.erase(it);
|
||||||
else
|
else
|
||||||
++it;
|
++it;
|
||||||
|
@ -28,15 +28,14 @@ void StringRegistry::purge_unused()
|
||||||
|
|
||||||
void StringRegistry::debug_stats() const
|
void StringRegistry::debug_stats() const
|
||||||
{
|
{
|
||||||
|
|
||||||
write_debug("Shared Strings stats:");
|
write_debug("Shared Strings stats:");
|
||||||
size_t total_refcount = 0;
|
size_t total_refcount = 0;
|
||||||
size_t total_size = 0;
|
size_t total_size = 0;
|
||||||
size_t count = m_strings.size();
|
size_t count = m_strings.size();
|
||||||
for (auto& st : m_strings)
|
for (auto& st : m_strings)
|
||||||
{
|
{
|
||||||
total_refcount += st.second.use_count() - 1;
|
total_refcount += st.second->refcount - 1;
|
||||||
total_size += (int)st.second->length();
|
total_size += (int)st.second->content.size();
|
||||||
}
|
}
|
||||||
write_debug(" data size: " + to_string(total_size) + ", mean: " + to_string((float)total_size/count));
|
write_debug(" data size: " + to_string(total_size) + ", mean: " + to_string((float)total_size/count));
|
||||||
write_debug(" refcounts: " + to_string(total_refcount) + ", mean: " + to_string((float)total_refcount/count));
|
write_debug(" refcounts: " + to_string(total_refcount) + ", mean: " + to_string((float)total_refcount/count));
|
||||||
|
|
|
@ -2,26 +2,40 @@
|
||||||
#define shared_string_hh_INCLUDED
|
#define shared_string_hh_INCLUDED
|
||||||
|
|
||||||
#include "string.hh"
|
#include "string.hh"
|
||||||
|
#include "ref_ptr.hh"
|
||||||
#include "utils.hh"
|
#include "utils.hh"
|
||||||
#include "unordered_map.hh"
|
#include "unordered_map.hh"
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
namespace Kakoune
|
namespace Kakoune
|
||||||
{
|
{
|
||||||
|
|
||||||
class SharedString : public StringView
|
class SharedString : public StringView
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using Storage = std::basic_string<char, std::char_traits<char>,
|
struct Storage
|
||||||
Allocator<char, MemoryDomain::SharedString>>;
|
{
|
||||||
|
int refcount = 0;
|
||||||
|
Vector<char, MemoryDomain::SharedString> content;
|
||||||
|
|
||||||
|
Storage(StringView str)
|
||||||
|
{
|
||||||
|
content.reserve((int)str.length() + 1);
|
||||||
|
content.assign(str.begin(), str.end());
|
||||||
|
content.push_back('\0');
|
||||||
|
}
|
||||||
|
StringView strview() const { return {&content.front(), &content.back()}; }
|
||||||
|
|
||||||
|
friend void inc_ref_count(Storage* s) { ++s->refcount; }
|
||||||
|
friend void dec_ref_count(Storage* s) { if (--s->refcount == 0) delete s; }
|
||||||
|
};
|
||||||
|
|
||||||
SharedString() = default;
|
SharedString() = default;
|
||||||
SharedString(StringView str)
|
SharedString(StringView str)
|
||||||
{
|
{
|
||||||
if (not str.empty())
|
if (not str.empty())
|
||||||
{
|
{
|
||||||
m_storage = std::make_shared<Storage>(str.begin(), str.end());
|
m_storage = new Storage{str};
|
||||||
StringView::operator=(*m_storage);
|
StringView::operator=(m_storage->strview());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
struct NoCopy{};
|
struct NoCopy{};
|
||||||
|
@ -39,11 +53,11 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SharedString(StringView str, std::shared_ptr<Storage> storage)
|
SharedString(StringView str, ref_ptr<Storage> storage)
|
||||||
: StringView{str}, m_storage(std::move(storage)) {}
|
: StringView{str}, m_storage(std::move(storage)) {}
|
||||||
|
|
||||||
friend class StringRegistry;
|
friend class StringRegistry;
|
||||||
std::shared_ptr<Storage> m_storage;
|
ref_ptr<Storage> m_storage;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline size_t hash_value(const SharedString& str)
|
inline size_t hash_value(const SharedString& str)
|
||||||
|
@ -59,7 +73,7 @@ public:
|
||||||
void purge_unused();
|
void purge_unused();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
UnorderedMap<StringView, std::shared_ptr<SharedString::Storage>, MemoryDomain::SharedString> m_strings;
|
UnorderedMap<StringView, ref_ptr<SharedString::Storage>, MemoryDomain::SharedString> m_strings;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline SharedString intern(StringView str)
|
inline SharedString intern(StringView str)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user