stim::cache_interface struct

Interface for enabling runtime caching of computationally-expensive resources.

Example

A thread-safe implementation which reads and writes cache information directly to the current working directory using std::fstreams:

#include <fstream>
#include <map>
#include <memory>
#include <mutex>
#include <stim/stim.h>

class fstream_cache final : public stim::cache_interface
{
  private:
    std::map<uintptr_t, std::unique_ptr<std::ifstream>> readers;
    std::mutex mx_readers;

    std::map<uintptr_t, std::unique_ptr<std::ofstream>> writers;
    std::mutex mx_writers;

    using lock_type = std::unique_lock<std::mutex>;

  public:
    size_t read_begin(uintptr_t thread_id, stim::string_view key) noexcept override
    {
        std::unique_ptr<std::ifstream> reader;
        try
        {
            reader.reset(new std::ifstream{ key.data(), std::ios::binary | std::ios::ate });
        }
        catch (...)
        {}
        if (!reader || !(*reader))
            return static_cast<size_t>(-1); // indicates error

        const auto size = reader->tellg();
        if (size <= 0)
            return {};
        reader->seekg(0);

        {
            const auto lock = lock_type{ mx_readers };
            readers.emplace(thread_id, std::move(reader));
        }

        return static_cast<size_t>(size);
    }

    bool read_chunk(uintptr_t thread_id, stim::buffer_view chunk) noexcept override
    {
        std::ifstream* reader = nullptr;
        {
            const auto lock = lock_type{ mx_readers };
            reader          = readers.find(thread_id)->second.get();
        }

        reader->read(static_cast<char*>(chunk.data()),
                     static_cast<std::streamsize>(chunk.size()));
        return static_cast<bool>(*reader);
    }

    void read_end(uintptr_t thread_id, bool error) noexcept override
    {
        const auto lock = lock_type{ mx_readers };
        readers.erase(thread_id);

        if (error)
        {
            // delete corrupt files or other diagnostics
        }
    }

    bool write_begin(uintptr_t thread_id, stim::string_view key) noexcept override
    {
        std::unique_ptr<std::ofstream> writer;
        try
        {
            writer.reset(new std::ofstream{ key.data(), std::ios::binary });
        }
        catch (...)
        {}
        if (!writer || !(*writer))
            return false;

        {
            const auto lock = lock_type{ mx_writers };
            writers.emplace(thread_id, std::move(writer));
        }

        return true;
    }

    bool write_chunk(uintptr_t thread_id, stim::const_buffer_view chunk) noexcept override
    {
        std::ofstream* writer = nullptr;
        {
            const auto lock = lock_type{ mx_writers };
            writer          = writers.find(thread_id)->second.get();
        }

        writer->write(static_cast<const char*>(chunk.data()),
                      static_cast<std::streamsize>(chunk.size()));
        return static_cast<bool>(*writer);
    }

    void write_end(uintptr_t thread_id, bool error) noexcept override
    {
        const auto lock = lock_type{ mx_writers };
        writers.erase(thread_id);

        if (error)
        {
            // delete partially-written files or other cleanup
        }
    }
};

Reading

auto read_begin(uintptr_t thread_id, string_view key) -> size_t pure virtual noexcept
Starts a cache read operation.
auto read_chunk(uintptr_t thread_id, buffer_view chunk) -> bool pure virtual noexcept
Reads a chunk of data.
void read_end(uintptr_t thread_id, bool error) pure virtual noexcept
Ends a cache read operation.

Writing

auto write_begin(uintptr_t thread_id, string_view key) -> bool pure virtual noexcept
Starts a cache write operation.
auto write_chunk(uintptr_t thread_id, const_buffer_view chunk) -> bool pure virtual noexcept
Writes a chunk of data.
void write_end(uintptr_t thread_id, bool error) pure virtual noexcept
Ends a cache write operation.

Function documentation

size_t stim::cache_interface::read_begin(uintptr_t thread_id, string_view key) pure virtual noexcept

Starts a cache read operation.

Parameters
thread_id An identifier for the calling thread.
key The cached asset key.
Returns The total number of bytes to be read (may be zero), or (size_t)-1 if an error occurred.

bool stim::cache_interface::read_chunk(uintptr_t thread_id, buffer_view chunk) pure virtual noexcept

Reads a chunk of data.

Parameters
thread_id An identifier for the calling thread.
chunk The destination buffer for the chunk read operation.
Returns True if the read operation succeeded, or false if an error occurred.

void stim::cache_interface::read_end(uintptr_t thread_id, bool error) pure virtual noexcept

Ends a cache read operation.

Parameters
thread_id An identifier for the calling thread.
error Indicates if the cache data was not fully read due to error.

bool stim::cache_interface::write_begin(uintptr_t thread_id, string_view key) pure virtual noexcept

Starts a cache write operation.

Parameters
thread_id An identifier for the calling thread.
key The cached asset key.
Returns True if the write operation was started successfully, or false if an error occurred.

bool stim::cache_interface::write_chunk(uintptr_t thread_id, const_buffer_view chunk) pure virtual noexcept

Writes a chunk of data.

Parameters
thread_id An identifier for the calling thread.
chunk The source buffer for the chunk write operation.
Returns True if the write operation succeeded, or false if an error occurred.

void stim::cache_interface::write_end(uintptr_t thread_id, bool error) pure virtual noexcept

Ends a cache write operation.

Parameters
thread_id An identifier for the calling thread.
error Indicates if the cache data was not fully written due to error.