2014-10-01 01:20:12 +02:00
|
|
|
#ifndef interned_string_hh_INCLUDED
|
|
|
|
#define interned_string_hh_INCLUDED
|
|
|
|
|
|
|
|
#include "string.hh"
|
|
|
|
#include "utils.hh"
|
2014-12-16 19:57:19 +01:00
|
|
|
#include "unordered_map.hh"
|
2015-01-07 20:29:31 +01:00
|
|
|
#include "vector.hh"
|
2014-10-01 01:20:12 +02:00
|
|
|
|
|
|
|
namespace Kakoune
|
|
|
|
{
|
|
|
|
|
|
|
|
class InternedString;
|
|
|
|
|
|
|
|
class StringRegistry : public Singleton<StringRegistry>
|
|
|
|
{
|
2015-01-13 14:48:16 +01:00
|
|
|
public:
|
|
|
|
void debug_stats() const;
|
2014-10-01 01:20:12 +02:00
|
|
|
private:
|
|
|
|
friend class InternedString;
|
|
|
|
|
|
|
|
InternedString acquire(StringView str);
|
2014-10-05 11:20:50 +02:00
|
|
|
void acquire(size_t slot);
|
2014-10-28 21:01:27 +01:00
|
|
|
void release(size_t slot) noexcept;
|
2014-10-01 01:20:12 +02:00
|
|
|
|
2015-01-11 20:28:03 +01:00
|
|
|
UnorderedMap<StringView, size_t, MemoryDomain::InternedString> m_slot_map;
|
2015-01-07 20:29:31 +01:00
|
|
|
Vector<size_t, MemoryDomain::InternedString> m_free_slots;
|
|
|
|
struct DataAndRefCount
|
|
|
|
{
|
|
|
|
Vector<char, MemoryDomain::InternedString> data;
|
|
|
|
int refcount;
|
|
|
|
};
|
|
|
|
Vector<DataAndRefCount, MemoryDomain::InternedString> m_storage;
|
2014-10-01 01:20:12 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
class InternedString : public StringView
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
InternedString() = default;
|
|
|
|
|
2014-10-23 14:53:04 +02:00
|
|
|
InternedString(const InternedString& str) : InternedString(str, str.m_slot)
|
|
|
|
{
|
|
|
|
if (m_slot != -1)
|
|
|
|
StringRegistry::instance().acquire(m_slot);
|
|
|
|
}
|
2014-10-01 01:20:12 +02:00
|
|
|
|
2014-10-28 20:44:00 +01:00
|
|
|
InternedString(InternedString&& str) noexcept : StringView(str)
|
2014-10-01 01:20:12 +02:00
|
|
|
{
|
2014-10-05 11:20:50 +02:00
|
|
|
m_slot = str.m_slot;
|
|
|
|
str.m_slot = -1;
|
2014-10-01 01:20:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
InternedString(const char* str) : StringView() { acquire_ifn(str); }
|
|
|
|
InternedString(StringView str) : StringView() { acquire_ifn(str); }
|
|
|
|
|
|
|
|
InternedString& operator=(const InternedString& str)
|
|
|
|
{
|
2014-10-28 21:01:55 +01:00
|
|
|
if (str.data() == data() and str.length() == length())
|
2014-10-01 01:20:12 +02:00
|
|
|
return *this;
|
2014-10-05 11:20:50 +02:00
|
|
|
static_cast<StringView&>(*this) = str;
|
|
|
|
if (str.m_slot != m_slot)
|
|
|
|
{
|
|
|
|
release_ifn();
|
|
|
|
m_slot = str.m_slot;
|
|
|
|
if (str.m_slot != -1)
|
|
|
|
StringRegistry::instance().acquire(str.m_slot);
|
|
|
|
}
|
|
|
|
|
2014-10-01 01:20:12 +02:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2014-10-28 21:01:27 +01:00
|
|
|
InternedString& operator=(InternedString&& str) noexcept
|
2014-10-01 01:20:12 +02:00
|
|
|
{
|
2014-10-28 21:01:27 +01:00
|
|
|
release_ifn();
|
|
|
|
|
2014-10-01 01:20:12 +02:00
|
|
|
static_cast<StringView&>(*this) = str;
|
2014-10-05 11:20:50 +02:00
|
|
|
m_slot = str.m_slot;
|
|
|
|
str.m_slot = -1;
|
2014-10-01 01:20:12 +02:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
~InternedString()
|
|
|
|
{
|
|
|
|
release_ifn();
|
|
|
|
}
|
|
|
|
|
2014-10-07 10:15:32 +02:00
|
|
|
InternedString acquire_substr(ByteCount from, ByteCount length = INT_MAX) const
|
|
|
|
{
|
|
|
|
if (m_slot == -1)
|
|
|
|
return InternedString{};
|
|
|
|
StringRegistry::instance().acquire(m_slot);
|
|
|
|
return InternedString{StringView::substr(from, length), m_slot};
|
|
|
|
}
|
|
|
|
InternedString acquire_substr(CharCount from, CharCount length = INT_MAX) const
|
|
|
|
{
|
|
|
|
if (m_slot == -1)
|
|
|
|
return InternedString{};
|
|
|
|
StringRegistry::instance().acquire(m_slot);
|
|
|
|
return InternedString{StringView::substr(from, length), m_slot};
|
|
|
|
}
|
|
|
|
|
2014-10-01 01:20:12 +02:00
|
|
|
private:
|
|
|
|
friend class StringRegistry;
|
|
|
|
|
2014-10-05 11:20:50 +02:00
|
|
|
InternedString(StringView str, size_t slot)
|
|
|
|
: StringView(str), m_slot(slot) {}
|
2014-10-01 01:20:12 +02:00
|
|
|
|
|
|
|
void acquire_ifn(StringView str)
|
|
|
|
{
|
|
|
|
if (str.empty())
|
2014-10-05 11:20:50 +02:00
|
|
|
{
|
2014-10-01 01:20:12 +02:00
|
|
|
static_cast<StringView&>(*this) = StringView{};
|
2014-10-05 11:20:50 +02:00
|
|
|
m_slot = -1;
|
|
|
|
}
|
2014-10-01 01:20:12 +02:00
|
|
|
else
|
|
|
|
*this = StringRegistry::instance().acquire(str);
|
|
|
|
}
|
|
|
|
|
2014-10-28 21:01:27 +01:00
|
|
|
void release_ifn() noexcept
|
2014-10-01 01:20:12 +02:00
|
|
|
{
|
2014-10-05 11:20:50 +02:00
|
|
|
if (m_slot != -1)
|
|
|
|
StringRegistry::instance().release(m_slot);
|
2014-10-01 01:20:12 +02:00
|
|
|
}
|
2014-10-05 11:20:50 +02:00
|
|
|
|
|
|
|
size_t m_slot = -1;
|
2014-10-01 01:20:12 +02:00
|
|
|
};
|
|
|
|
|
2014-12-16 19:57:19 +01:00
|
|
|
inline size_t hash_value(const Kakoune::InternedString& str)
|
|
|
|
{
|
|
|
|
return hash_data(str.data(), (int)str.length());
|
2014-10-01 01:20:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif // interned_string_hh_INCLUDED
|