summaryrefslogtreecommitdiffstats
path: root/src/common/linear_disk_cache.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/linear_disk_cache.h')
-rw-r--r--src/common/linear_disk_cache.h191
1 files changed, 191 insertions, 0 deletions
diff --git a/src/common/linear_disk_cache.h b/src/common/linear_disk_cache.h
new file mode 100644
index 000000000..da5d6b9b4
--- /dev/null
+++ b/src/common/linear_disk_cache.h
@@ -0,0 +1,191 @@
+// Copyright 2013 Dolphin Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+
+#ifndef _LINEAR_DISKCACHE
+#define _LINEAR_DISKCACHE
+
+#include "common.h"
+#include <fstream>
+
+// defined in Version.cpp
+extern const char *scm_rev_git_str;
+
+// On disk format:
+//header{
+// u32 'DCAC';
+// u32 version; // svn_rev
+// u16 sizeof(key_type);
+// u16 sizeof(value_type);
+//}
+
+//key_value_pair{
+// u32 value_size;
+// key_type key;
+// value_type[value_size] value;
+//}
+
+template <typename K, typename V>
+class LinearDiskCacheReader
+{
+public:
+ virtual void Read(const K &key, const V *value, u32 value_size) = 0;
+};
+
+// Dead simple unsorted key-value store with append functionality.
+// No random read functionality, all reading is done in OpenAndRead.
+// Keys and values can contain any characters, including \0.
+//
+// Suitable for caching generated shader bytecode between executions.
+// Not tuned for extreme performance but should be reasonably fast.
+// Does not support keys or values larger than 2GB, which should be reasonable.
+// Keys must have non-zero length; values can have zero length.
+
+// K and V are some POD type
+// K : the key type
+// V : value array type
+template <typename K, typename V>
+class LinearDiskCache
+{
+public:
+ // return number of read entries
+ u32 OpenAndRead(const char *filename, LinearDiskCacheReader<K, V> &reader)
+ {
+ using std::ios_base;
+
+ // close any currently opened file
+ Close();
+ m_num_entries = 0;
+
+ // try opening for reading/writing
+ OpenFStream(m_file, filename, ios_base::in | ios_base::out | ios_base::binary);
+
+ m_file.seekg(0, std::ios::end);
+ std::fstream::pos_type end_pos = m_file.tellg();
+ m_file.seekg(0, std::ios::beg);
+ std::fstream::pos_type start_pos = m_file.tellg();
+ std::streamoff file_size = end_pos - start_pos;
+
+ if (m_file.is_open() && ValidateHeader())
+ {
+ // good header, read some key/value pairs
+ K key;
+
+ V *value = NULL;
+ u32 value_size;
+ u32 entry_number;
+
+ std::fstream::pos_type last_pos = m_file.tellg();
+
+ while (Read(&value_size))
+ {
+ std::streamoff next_extent = (last_pos - start_pos) + sizeof(value_size) + value_size;
+ if (next_extent > file_size)
+ break;
+
+ delete[] value;
+ value = new V[value_size];
+
+ // read key/value and pass to reader
+ if (Read(&key) &&
+ Read(value, value_size) &&
+ Read(&entry_number) &&
+ entry_number == m_num_entries+1)
+ {
+ reader.Read(key, value, value_size);
+ }
+ else
+ {
+ break;
+ }
+
+ m_num_entries++;
+ last_pos = m_file.tellg();
+ }
+ m_file.seekp(last_pos);
+ m_file.clear();
+
+ delete[] value;
+ return m_num_entries;
+ }
+
+ // failed to open file for reading or bad header
+ // close and recreate file
+ Close();
+ m_file.open(filename, ios_base::out | ios_base::trunc | ios_base::binary);
+ WriteHeader();
+ return 0;
+ }
+
+ void Sync()
+ {
+ m_file.flush();
+ }
+
+ void Close()
+ {
+ if (m_file.is_open())
+ m_file.close();
+ // clear any error flags
+ m_file.clear();
+ }
+
+ // Appends a key-value pair to the store.
+ void Append(const K &key, const V *value, u32 value_size)
+ {
+ // TODO: Should do a check that we don't already have "key"? (I think each caller does that already.)
+ Write(&value_size);
+ Write(&key);
+ Write(value, value_size);
+ m_num_entries++;
+ Write(&m_num_entries);
+ }
+
+private:
+ void WriteHeader()
+ {
+ Write(&m_header);
+ }
+
+ bool ValidateHeader()
+ {
+ char file_header[sizeof(Header)];
+
+ return (Read(file_header, sizeof(Header))
+ && !memcmp((const char*)&m_header, file_header, sizeof(Header)));
+ }
+
+ template <typename D>
+ bool Write(const D *data, u32 count = 1)
+ {
+ return m_file.write((const char*)data, count * sizeof(D)).good();
+ }
+
+ template <typename D>
+ bool Read(const D *data, u32 count = 1)
+ {
+ return m_file.read((char*)data, count * sizeof(D)).good();
+ }
+
+ struct Header
+ {
+ Header()
+ : id(*(u32*)"DCAC")
+ , key_t_size(sizeof(K))
+ , value_t_size(sizeof(V))
+ {
+ memcpy(ver, scm_rev_git_str, 40);
+ }
+
+ const u32 id;
+ const u16 key_t_size, value_t_size;
+ char ver[40];
+
+ } m_header;
+
+ std::fstream m_file;
+ u32 m_num_entries;
+};
+
+#endif // _LINEAR_DISKCACHE