diff options
| author | 2014-04-08 19:25:03 -0400 | |
|---|---|---|
| committer | 2014-04-08 19:25:03 -0400 | |
| commit | 63e46abdb8764bc97e91bae862c8d461e61b1965 (patch) | |
| tree | e73f4aa25d7b4015a265e7bbfb6004dab7561027 /src/common/linear_disk_cache.h | |
| parent | fixed some license headers that I missed (diff) | |
| download | yuzu-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.h | 191 |
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 | ||
| 13 | extern 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 | |||
| 29 | template <typename K, typename V> | ||
| 30 | class LinearDiskCacheReader | ||
| 31 | { | ||
| 32 | public: | ||
| 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 | ||
| 48 | template <typename K, typename V> | ||
| 49 | class LinearDiskCache | ||
| 50 | { | ||
| 51 | public: | ||
| 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 | |||
| 145 | private: | ||
| 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 | ||