summaryrefslogtreecommitdiff
path: root/src/common/linear_disk_cache.h
diff options
context:
space:
mode:
authorGravatar bunnei2014-04-08 19:25:03 -0400
committerGravatar bunnei2014-04-08 19:25:03 -0400
commit63e46abdb8764bc97e91bae862c8d461e61b1965 (patch)
treee73f4aa25d7b4015a265e7bbfb6004dab7561027 /src/common/linear_disk_cache.h
parentfixed some license headers that I missed (diff)
downloadyuzu-63e46abdb8764bc97e91bae862c8d461e61b1965.tar.gz
yuzu-63e46abdb8764bc97e91bae862c8d461e61b1965.tar.xz
yuzu-63e46abdb8764bc97e91bae862c8d461e61b1965.zip
got rid of 'src' folders in each sub-project
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 @@
1// Copyright 2013 Dolphin Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5
6#ifndef _LINEAR_DISKCACHE
7#define _LINEAR_DISKCACHE
8
9#include "common.h"
10#include <fstream>
11
12// defined in Version.cpp
13extern const char *scm_rev_git_str;
14
15// On disk format:
16//header{
17// u32 'DCAC';
18// u32 version; // svn_rev
19// u16 sizeof(key_type);
20// u16 sizeof(value_type);
21//}
22
23//key_value_pair{
24// u32 value_size;
25// key_type key;
26// value_type[value_size] value;
27//}
28
29template <typename K, typename V>
30class LinearDiskCacheReader
31{
32public:
33 virtual void Read(const K &key, const V *value, u32 value_size) = 0;
34};
35
36// Dead simple unsorted key-value store with append functionality.
37// No random read functionality, all reading is done in OpenAndRead.
38// Keys and values can contain any characters, including \0.
39//
40// Suitable for caching generated shader bytecode between executions.
41// Not tuned for extreme performance but should be reasonably fast.
42// Does not support keys or values larger than 2GB, which should be reasonable.
43// Keys must have non-zero length; values can have zero length.
44
45// K and V are some POD type
46// K : the key type
47// V : value array type
48template <typename K, typename V>
49class LinearDiskCache
50{
51public:
52 // return number of read entries
53 u32 OpenAndRead(const char *filename, LinearDiskCacheReader<K, V> &reader)
54 {
55 using std::ios_base;
56
57 // close any currently opened file
58 Close();
59 m_num_entries = 0;
60
61 // try opening for reading/writing
62 OpenFStream(m_file, filename, ios_base::in | ios_base::out | ios_base::binary);
63
64 m_file.seekg(0, std::ios::end);
65 std::fstream::pos_type end_pos = m_file.tellg();
66 m_file.seekg(0, std::ios::beg);
67 std::fstream::pos_type start_pos = m_file.tellg();
68 std::streamoff file_size = end_pos - start_pos;
69
70 if (m_file.is_open() && ValidateHeader())
71 {
72 // good header, read some key/value pairs
73 K key;
74
75 V *value = NULL;
76 u32 value_size;
77 u32 entry_number;
78
79 std::fstream::pos_type last_pos = m_file.tellg();
80
81 while (Read(&value_size))
82 {
83 std::streamoff next_extent = (last_pos - start_pos) + sizeof(value_size) + value_size;
84 if (next_extent > file_size)
85 break;
86
87 delete[] value;
88 value = new V[value_size];
89
90 // read key/value and pass to reader
91 if (Read(&key) &&
92 Read(value, value_size) &&
93 Read(&entry_number) &&
94 entry_number == m_num_entries+1)
95 {
96 reader.Read(key, value, value_size);
97 }
98 else
99 {
100 break;
101 }
102
103 m_num_entries++;
104 last_pos = m_file.tellg();
105 }
106 m_file.seekp(last_pos);
107 m_file.clear();
108
109 delete[] value;
110 return m_num_entries;
111 }
112
113 // failed to open file for reading or bad header
114 // close and recreate file
115 Close();
116 m_file.open(filename, ios_base::out | ios_base::trunc | ios_base::binary);
117 WriteHeader();
118 return 0;
119 }
120
121 void Sync()
122 {
123 m_file.flush();
124 }
125
126 void Close()
127 {
128 if (m_file.is_open())
129 m_file.close();
130 // clear any error flags
131 m_file.clear();
132 }
133
134 // Appends a key-value pair to the store.
135 void Append(const K &key, const V *value, u32 value_size)
136 {
137 // TODO: Should do a check that we don't already have "key"? (I think each caller does that already.)
138 Write(&value_size);
139 Write(&key);
140 Write(value, value_size);
141 m_num_entries++;
142 Write(&m_num_entries);
143 }
144
145private:
146 void WriteHeader()
147 {
148 Write(&m_header);
149 }
150
151 bool ValidateHeader()
152 {
153 char file_header[sizeof(Header)];
154
155 return (Read(file_header, sizeof(Header))
156 && !memcmp((const char*)&m_header, file_header, sizeof(Header)));
157 }
158
159 template <typename D>
160 bool Write(const D *data, u32 count = 1)
161 {
162 return m_file.write((const char*)data, count * sizeof(D)).good();
163 }
164
165 template <typename D>
166 bool Read(const D *data, u32 count = 1)
167 {
168 return m_file.read((char*)data, count * sizeof(D)).good();
169 }
170
171 struct Header
172 {
173 Header()
174 : id(*(u32*)"DCAC")
175 , key_t_size(sizeof(K))
176 , value_t_size(sizeof(V))
177 {
178 memcpy(ver, scm_rev_git_str, 40);
179 }
180
181 const u32 id;
182 const u16 key_t_size, value_t_size;
183 char ver[40];
184
185 } m_header;
186
187 std::fstream m_file;
188 u32 m_num_entries;
189};
190
191#endif // _LINEAR_DISKCACHE