linear_disk_cache.h 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. // Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #pragma once
  5. #include <fstream>
  6. #include "common/common_types.h"
  7. // defined in Version.cpp
  8. extern const char* scm_rev_git_str;
  9. // On disk format:
  10. // header{
  11. // u32 'DCAC';
  12. // u32 version; // svn_rev
  13. // u16 sizeof(key_type);
  14. // u16 sizeof(value_type);
  15. //}
  16. // key_value_pair{
  17. // u32 value_size;
  18. // key_type key;
  19. // value_type[value_size] value;
  20. //}
  21. template <typename K, typename V>
  22. class LinearDiskCacheReader {
  23. public:
  24. virtual void Read(const K& key, const V* value, u32 value_size) = 0;
  25. };
  26. // Dead simple unsorted key-value store with append functionality.
  27. // No random read functionality, all reading is done in OpenAndRead.
  28. // Keys and values can contain any characters, including \0.
  29. //
  30. // Suitable for caching generated shader bytecode between executions.
  31. // Not tuned for extreme performance but should be reasonably fast.
  32. // Does not support keys or values larger than 2GB, which should be reasonable.
  33. // Keys must have non-zero length; values can have zero length.
  34. // K and V are some POD type
  35. // K : the key type
  36. // V : value array type
  37. template <typename K, typename V>
  38. class LinearDiskCache {
  39. public:
  40. // return number of read entries
  41. u32 OpenAndRead(const char* filename, LinearDiskCacheReader<K, V>& reader) {
  42. using std::ios_base;
  43. // close any currently opened file
  44. Close();
  45. m_num_entries = 0;
  46. // try opening for reading/writing
  47. OpenFStream(m_file, filename, ios_base::in | ios_base::out | ios_base::binary);
  48. m_file.seekg(0, std::ios::end);
  49. std::fstream::pos_type end_pos = m_file.tellg();
  50. m_file.seekg(0, std::ios::beg);
  51. std::fstream::pos_type start_pos = m_file.tellg();
  52. std::streamoff file_size = end_pos - start_pos;
  53. if (m_file.is_open() && ValidateHeader()) {
  54. // good header, read some key/value pairs
  55. K key;
  56. V* value = nullptr;
  57. u32 value_size;
  58. u32 entry_number;
  59. std::fstream::pos_type last_pos = m_file.tellg();
  60. while (Read(&value_size)) {
  61. std::streamoff next_extent =
  62. (last_pos - start_pos) + sizeof(value_size) + value_size;
  63. if (next_extent > file_size)
  64. break;
  65. delete[] value;
  66. value = new V[value_size];
  67. // read key/value and pass to reader
  68. if (Read(&key) && Read(value, value_size) && Read(&entry_number) &&
  69. entry_number == m_num_entries + 1) {
  70. reader.Read(key, value, value_size);
  71. } else {
  72. break;
  73. }
  74. m_num_entries++;
  75. last_pos = m_file.tellg();
  76. }
  77. m_file.seekp(last_pos);
  78. m_file.clear();
  79. delete[] value;
  80. return m_num_entries;
  81. }
  82. // failed to open file for reading or bad header
  83. // close and recreate file
  84. Close();
  85. m_file.open(filename, ios_base::out | ios_base::trunc | ios_base::binary);
  86. WriteHeader();
  87. return 0;
  88. }
  89. void Sync() {
  90. m_file.flush();
  91. }
  92. void Close() {
  93. if (m_file.is_open())
  94. m_file.close();
  95. // clear any error flags
  96. m_file.clear();
  97. }
  98. // Appends a key-value pair to the store.
  99. void Append(const K& key, const V* value, u32 value_size) {
  100. // TODO: Should do a check that we don't already have "key"? (I think each caller does that
  101. // already.)
  102. Write(&value_size);
  103. Write(&key);
  104. Write(value, value_size);
  105. m_num_entries++;
  106. Write(&m_num_entries);
  107. }
  108. private:
  109. void WriteHeader() {
  110. Write(&m_header);
  111. }
  112. bool ValidateHeader() {
  113. char file_header[sizeof(Header)];
  114. return (Read(file_header, sizeof(Header)) &&
  115. !memcmp((const char*)&m_header, file_header, sizeof(Header)));
  116. }
  117. template <typename D>
  118. bool Write(const D* data, u32 count = 1) {
  119. return m_file.write((const char*)data, count * sizeof(D)).good();
  120. }
  121. template <typename D>
  122. bool Read(const D* data, u32 count = 1) {
  123. return m_file.read((char*)data, count * sizeof(D)).good();
  124. }
  125. struct Header {
  126. Header() : id(*(u32*)"DCAC"), key_t_size(sizeof(K)), value_t_size(sizeof(V)) {
  127. memcpy(ver, scm_rev_git_str, 40);
  128. }
  129. const u32 id;
  130. const u16 key_t_size, value_t_size;
  131. char ver[40];
  132. } m_header;
  133. std::fstream m_file;
  134. u32 m_num_entries;
  135. };