Files
jeanlemotan 8297b0b45f First
2024-07-02 18:06:33 +02:00

129 lines
3.2 KiB
C++

#pragma once
#include "tl/detail/prologue.h"
#include <EASTL/vector.h>
#include <EASTL/array.h>
#include <EASTL/unique_ptr.h>
#include <atomic>
#include <shared_mutex>
#include "tl/plain_crash.h"
//disable the 'strdup' warning
#if defined(_MSC_VER)
# pragma warning( disable : 4996 )
#endif
#ifndef _SCL_SECURE_NO_WARNINGS
# define _SCL_SECURE_NO_WARNINGS
#endif
namespace tl
{
namespace detail
{
class string_db;
}
TL_API detail::string_db*& get_shared_string_db_instance_ptr() noexcept;
}
namespace tl
{
class string;
namespace detail
{
struct TL_API string_cell
{
friend class string_db_map;
using length_t = uint32_t; //uint32_t was chosen to avoid the cell to gain 4 bytes in 64 bit configs. We'll never have strings bigger than 4 billion chars (for the foreseeable future)
using hash_t = uint32_t;
length_t length;
hash_t hash; //hash for key
std::atomic_int counter;
// uint32_t padding;
//this increments the ref_count and returns true IF the cell was not resurrected. So true means the cell was alive before the increment
void inc_ref_counter() noexcept { counter.fetch_add(1, std::memory_order_relaxed); }
//this decrements the ref_count and returns true if the cell is still alive
bool dec_ref_counter() noexcept { const int oldRef = counter.fetch_sub(1, std::memory_order_relaxed); TL_PLAIN_ASSERT(oldRef > 0); return oldRef == 1; }
};
static_assert(sizeof(string_cell) % sizeof(uint32_t) == 0);
class TL_API string_db_map
{
public:
using cell_t = string_cell;
string_db_map() noexcept;
~string_db_map() noexcept;
//this returns a new or existing cell with the string in the argument
cell_t* find(cell_t::hash_t hash, cell_t::length_t length, const char* string) noexcept;
cell_t* find_or_add(cell_t::hash_t hash, cell_t::length_t length, const char* string) noexcept;
cell_t* allocate_cell(const char* string, cell_t::length_t length, cell_t::hash_t hash) noexcept;
void free_cell(cell_t* cell) noexcept;
void mark_cell_as_unused(cell_t& cell) noexcept;
void lock() noexcept { m_mutex.lock(); }
void unlock() noexcept { m_mutex.unlock(); }
private:
std::mutex m_mutex;
uint32_t m_hashmap_size = 0;
uint32_t m_hashmap_size_mask = m_hashmap_size - 1;
eastl::vector<cell_t*> m_buckets;
std::atomic_int m_used_cell_count = { 0 };
void rehash(uint32_t new_size) noexcept;
//size_t m_garbage_size = 0;
};
class TL_API string_db
{
public:
string_db() noexcept;
~string_db() noexcept;
using cell_t = string_cell;
static string_db*& get_instance_ptr() noexcept;
static string_db& get_instance() noexcept;
static void free_instance() noexcept;
void internalize(const char* str_start, const char* str_end, cell_t*& dst_cell) noexcept;
void internalize(const char* str, cell_t*& dst_cell) noexcept;
void append_internalize(cell_t& src_cell, const char* str, size_t str_size, cell_t*& dst_cell) noexcept;
void free_cell(cell_t& cell) noexcept;
private:
string_db_map m_map;
};
inline string_db*& string_db::get_instance_ptr() noexcept
{
static string_db*& s_instance = get_shared_string_db_instance_ptr();
return s_instance;
}
inline string_db& string_db::get_instance() noexcept
{
string_db* db = get_instance_ptr();
if (!db)
TL_PLAIN_CRASH("String DB was deleted");
return *db;
}
}
}