stringcache: add a simple bulk string cache
This commit is contained in:
parent
5c3df6cd4c
commit
d099a159fb
@ -520,6 +520,8 @@ list (
|
|||||||
stream.hpp
|
stream.hpp
|
||||||
string.cpp
|
string.cpp
|
||||||
string.hpp
|
string.hpp
|
||||||
|
stringcache.cpp
|
||||||
|
stringcache.hpp
|
||||||
stringid.cpp
|
stringid.cpp
|
||||||
stringid.hpp
|
stringid.hpp
|
||||||
strongdef.cpp
|
strongdef.cpp
|
||||||
@ -734,6 +736,7 @@ if (TESTS)
|
|||||||
stream
|
stream
|
||||||
string
|
string
|
||||||
stringid
|
stringid
|
||||||
|
stringcache
|
||||||
strongdef
|
strongdef
|
||||||
thread/condition_variable
|
thread/condition_variable
|
||||||
thread/event
|
thread/event
|
||||||
|
68
stringcache.cpp
Normal file
68
stringcache.cpp
Normal 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
45
stringcache.hpp
Normal 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
40
test/stringcache.cpp
Normal 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 ();
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user