stringcache: add a simple bulk string cache

This commit is contained in:
Danny Robson 2020-04-23 05:53:40 +10:00
parent 5c3df6cd4c
commit d099a159fb
4 changed files with 156 additions and 0 deletions

View File

@ -520,6 +520,8 @@ list (
stream.hpp
string.cpp
string.hpp
stringcache.cpp
stringcache.hpp
stringid.cpp
stringid.hpp
strongdef.cpp
@ -734,6 +736,7 @@ if (TESTS)
stream
string
stringid
stringcache
strongdef
thread/condition_variable
thread/event

68
stringcache.cpp Normal file
View File

@ -0,0 +1,68 @@
/******************************************************************************
_ _
| | | |
| | ___ | |__ ___
| |/ _ \| '_ \ / _ \
| | (_) | |_) | (_) |
|_|\___/|_.__/ \___/
Copyright:
Danny Robson, 2020
*****************************************************************************/
#include "stringcache.hpp"
#include "cast.hpp"
using cruft::stringcache;
///////////////////////////////////////////////////////////////////////////////
stringcache::id_t
stringcache::add (std::string_view val)
{
auto const required_size = std::ssize (val);
if (m_values.size () > std::numeric_limits<value_type>::max ())
throw std::bad_alloc ();
if (m_store.size () + required_size > std::numeric_limits<value_type>::max ())
throw std::bad_alloc ();
slot_t allocation {
.start = value_type (m_store.size ()),
.length = value_type (required_size),
};
m_store.resize (m_store.size () + allocation.length);
std::copy (
std::begin (val),
std::end (val),
std::begin (m_store) + allocation.start
);
m_values.push_back (allocation);
return id_t (m_values.size () - 1);
}
//-----------------------------------------------------------------------------
stringcache::id_t
stringcache::add (std::string const &val)
{
return add (std::string_view (val));
}
//-----------------------------------------------------------------------------
stringcache::id_t
stringcache::add (char const *val)
{
return add (std::string_view (val));
}
///////////////////////////////////////////////////////////////////////////////
std::string_view
stringcache::operator[] (id_t idx)
{
slot_t const entry = m_values[value_type (idx)];
return std::string_view (m_store.data () + entry.start, entry.length);
}

45
stringcache.hpp Normal file
View File

@ -0,0 +1,45 @@
/******************************************************************************
_ _
| | | |
| | ___ | |__ ___
| |/ _ \| '_ \ / _ \
| | (_) | |_) | (_) |
|_|\___/|_.__/ \___/
Copyright:
Danny Robson, 2020
*****************************************************************************/
#pragma once
#include "./std.hpp"
#include <string>
#include <string_view>
#include <vector>
namespace cruft {
/// Stores strings in a single block of memory where they can be indexed
/// by an integral id, and compacted to save space as required.
class stringcache {
using value_type = i16;
public:
enum id_t : value_type {};
std::string_view operator[] (id_t);
id_t add (std::string_view);
id_t add (std::string const &);
id_t add (char const*);
private:
struct slot_t {
value_type start;
value_type length;
};
std::vector<slot_t> m_values;
std::vector<char> m_store;
};
}

40
test/stringcache.cpp Normal file
View File

@ -0,0 +1,40 @@
#include <cruft/util/tap.hpp>
#include <cruft/util/stringcache.hpp>
#include <cruft/util/iterator/zip.hpp>
int main ()
{
cruft::TAP::logger tap;
{
static constexpr const char* VALUES[] = {
"foo",
"bar",
"qux",
"the",
"quick",
"brown",
"fox",
};
cruft::stringcache cache;
std::vector<cruft::stringcache::id_t> indices;
for (auto const v: VALUES)
indices.push_back (cache.add (v));
bool success = true;
for (auto const [expected, idx]: cruft::iterator::zip (VALUES, indices)) {
auto const actual = cache[idx];
if (actual != expected) {
success = false;
break;
}
}
tap.expect (success, "cache holds values");
}
return tap.status ();
}