diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/common/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/common/chunk_file.h | 623 | ||||
| -rw-r--r-- | src/common/linear_disk_cache.h | 167 |
3 files changed, 0 insertions, 792 deletions
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 32cb85de0..f49a31612 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt | |||
| @@ -31,7 +31,6 @@ add_library(common STATIC | |||
| 31 | bit_set.h | 31 | bit_set.h |
| 32 | break_points.cpp | 32 | break_points.cpp |
| 33 | break_points.h | 33 | break_points.h |
| 34 | chunk_file.h | ||
| 35 | cityhash.cpp | 34 | cityhash.cpp |
| 36 | cityhash.h | 35 | cityhash.h |
| 37 | color.h | 36 | color.h |
| @@ -41,7 +40,6 @@ add_library(common STATIC | |||
| 41 | file_util.cpp | 40 | file_util.cpp |
| 42 | file_util.h | 41 | file_util.h |
| 43 | hash.h | 42 | hash.h |
| 44 | linear_disk_cache.h | ||
| 45 | logging/backend.cpp | 43 | logging/backend.cpp |
| 46 | logging/backend.h | 44 | logging/backend.h |
| 47 | logging/filter.cpp | 45 | logging/filter.cpp |
diff --git a/src/common/chunk_file.h b/src/common/chunk_file.h deleted file mode 100644 index 972ef9039..000000000 --- a/src/common/chunk_file.h +++ /dev/null | |||
| @@ -1,623 +0,0 @@ | |||
| 1 | // Copyright (C) 2003 Dolphin Project. | ||
| 2 | |||
| 3 | // This program is free software: you can redistribute it and/or modify | ||
| 4 | // it under the terms of the GNU General Public License as published by | ||
| 5 | // the Free Software Foundation, version 2.0 or later versions. | ||
| 6 | |||
| 7 | // This program is distributed in the hope that it will be useful, | ||
| 8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 10 | // GNU General Public License 2.0 for more details. | ||
| 11 | |||
| 12 | // A copy of the GPL 2.0 should have been included with the program. | ||
| 13 | // If not, see http://www.gnu.org/licenses/ | ||
| 14 | |||
| 15 | // Official SVN repository and contact information can be found at | ||
| 16 | // http://code.google.com/p/dolphin-emu/ | ||
| 17 | |||
| 18 | #pragma once | ||
| 19 | |||
| 20 | // Extremely simple serialization framework. | ||
| 21 | |||
| 22 | // (mis)-features: | ||
| 23 | // + Super fast | ||
| 24 | // + Very simple | ||
| 25 | // + Same code is used for serialization and deserializaition (in most cases) | ||
| 26 | // - Zero backwards/forwards compatibility | ||
| 27 | // - Serialization code for anything complex has to be manually written. | ||
| 28 | |||
| 29 | #include <cstring> | ||
| 30 | #include <deque> | ||
| 31 | #include <list> | ||
| 32 | #include <map> | ||
| 33 | #include <set> | ||
| 34 | #include <string> | ||
| 35 | #include <type_traits> | ||
| 36 | #include <utility> | ||
| 37 | #include <vector> | ||
| 38 | #include "common/assert.h" | ||
| 39 | #include "common/common_types.h" | ||
| 40 | #include "common/logging/log.h" | ||
| 41 | |||
| 42 | template <class T> | ||
| 43 | struct LinkedListItem : public T { | ||
| 44 | LinkedListItem<T>* next; | ||
| 45 | }; | ||
| 46 | |||
| 47 | class PointerWrap; | ||
| 48 | |||
| 49 | class PointerWrapSection { | ||
| 50 | public: | ||
| 51 | PointerWrapSection(PointerWrap& p, int ver, const char* title) | ||
| 52 | : p_(p), ver_(ver), title_(title) {} | ||
| 53 | ~PointerWrapSection(); | ||
| 54 | |||
| 55 | bool operator==(const int& v) const { | ||
| 56 | return ver_ == v; | ||
| 57 | } | ||
| 58 | bool operator!=(const int& v) const { | ||
| 59 | return ver_ != v; | ||
| 60 | } | ||
| 61 | bool operator<=(const int& v) const { | ||
| 62 | return ver_ <= v; | ||
| 63 | } | ||
| 64 | bool operator>=(const int& v) const { | ||
| 65 | return ver_ >= v; | ||
| 66 | } | ||
| 67 | bool operator<(const int& v) const { | ||
| 68 | return ver_ < v; | ||
| 69 | } | ||
| 70 | bool operator>(const int& v) const { | ||
| 71 | return ver_ > v; | ||
| 72 | } | ||
| 73 | |||
| 74 | operator bool() const { | ||
| 75 | return ver_ > 0; | ||
| 76 | } | ||
| 77 | |||
| 78 | private: | ||
| 79 | PointerWrap& p_; | ||
| 80 | int ver_; | ||
| 81 | const char* title_; | ||
| 82 | }; | ||
| 83 | |||
| 84 | // Wrapper class | ||
| 85 | class PointerWrap { | ||
| 86 | // This makes it a compile error if you forget to define DoState() on non-POD. | ||
| 87 | // Which also can be a problem, for example struct tm is non-POD on linux, for whatever reason... | ||
| 88 | #ifdef _MSC_VER | ||
| 89 | template <typename T, bool isPOD = std::is_pod<T>::value, | ||
| 90 | bool isPointer = std::is_pointer<T>::value> | ||
| 91 | #else | ||
| 92 | template <typename T, bool isPOD = __is_pod(T), bool isPointer = std::is_pointer<T>::value> | ||
| 93 | #endif | ||
| 94 | struct DoHelper { | ||
| 95 | static void DoArray(PointerWrap* p, T* x, int count) { | ||
| 96 | for (int i = 0; i < count; ++i) | ||
| 97 | p->Do(x[i]); | ||
| 98 | } | ||
| 99 | |||
| 100 | static void Do(PointerWrap* p, T& x) { | ||
| 101 | p->DoClass(x); | ||
| 102 | } | ||
| 103 | }; | ||
| 104 | |||
| 105 | template <typename T> | ||
| 106 | struct DoHelper<T, true, false> { | ||
| 107 | static void DoArray(PointerWrap* p, T* x, int count) { | ||
| 108 | p->DoVoid((void*)x, sizeof(T) * count); | ||
| 109 | } | ||
| 110 | |||
| 111 | static void Do(PointerWrap* p, T& x) { | ||
| 112 | p->DoVoid((void*)&x, sizeof(x)); | ||
| 113 | } | ||
| 114 | }; | ||
| 115 | |||
| 116 | public: | ||
| 117 | enum Mode { | ||
| 118 | MODE_READ = 1, // load | ||
| 119 | MODE_WRITE, // save | ||
| 120 | MODE_MEASURE, // calculate size | ||
| 121 | MODE_VERIFY, // compare | ||
| 122 | }; | ||
| 123 | |||
| 124 | enum Error { | ||
| 125 | ERROR_NONE = 0, | ||
| 126 | ERROR_WARNING = 1, | ||
| 127 | ERROR_FAILURE = 2, | ||
| 128 | }; | ||
| 129 | |||
| 130 | u8** ptr; | ||
| 131 | Mode mode; | ||
| 132 | Error error; | ||
| 133 | |||
| 134 | public: | ||
| 135 | PointerWrap(u8** ptr_, Mode mode_) : ptr(ptr_), mode(mode_), error(ERROR_NONE) {} | ||
| 136 | PointerWrap(unsigned char** ptr_, int mode_) | ||
| 137 | : ptr((u8**)ptr_), mode((Mode)mode_), error(ERROR_NONE) {} | ||
| 138 | |||
| 139 | PointerWrapSection Section(const char* title, int ver) { | ||
| 140 | return Section(title, ver, ver); | ||
| 141 | } | ||
| 142 | |||
| 143 | // The returned object can be compared against the version that was loaded. | ||
| 144 | // This can be used to support versions as old as minVer. | ||
| 145 | // Version = 0 means the section was not found. | ||
| 146 | PointerWrapSection Section(const char* title, int minVer, int ver) { | ||
| 147 | char marker[16] = {0}; | ||
| 148 | int foundVersion = ver; | ||
| 149 | |||
| 150 | strncpy(marker, title, sizeof(marker)); | ||
| 151 | if (!ExpectVoid(marker, sizeof(marker))) { | ||
| 152 | // Might be before we added name markers for safety. | ||
| 153 | if (foundVersion == 1 && ExpectVoid(&foundVersion, sizeof(foundVersion))) | ||
| 154 | DoMarker(title); | ||
| 155 | // Wasn't found, but maybe we can still load the state. | ||
| 156 | else | ||
| 157 | foundVersion = 0; | ||
| 158 | } else | ||
| 159 | Do(foundVersion); | ||
| 160 | |||
| 161 | if (error == ERROR_FAILURE || foundVersion < minVer || foundVersion > ver) { | ||
| 162 | LOG_ERROR(Common, "Savestate failure: wrong version %d found for %s", foundVersion, | ||
| 163 | title); | ||
| 164 | SetError(ERROR_FAILURE); | ||
| 165 | return PointerWrapSection(*this, -1, title); | ||
| 166 | } | ||
| 167 | return PointerWrapSection(*this, foundVersion, title); | ||
| 168 | } | ||
| 169 | |||
| 170 | void SetMode(Mode mode_) { | ||
| 171 | mode = mode_; | ||
| 172 | } | ||
| 173 | Mode GetMode() const { | ||
| 174 | return mode; | ||
| 175 | } | ||
| 176 | u8** GetPPtr() { | ||
| 177 | return ptr; | ||
| 178 | } | ||
| 179 | void SetError(Error error_) { | ||
| 180 | if (error < error_) | ||
| 181 | error = error_; | ||
| 182 | if (error > ERROR_WARNING) | ||
| 183 | mode = PointerWrap::MODE_MEASURE; | ||
| 184 | } | ||
| 185 | |||
| 186 | bool ExpectVoid(void* data, int size) { | ||
| 187 | switch (mode) { | ||
| 188 | case MODE_READ: | ||
| 189 | if (memcmp(data, *ptr, size) != 0) | ||
| 190 | return false; | ||
| 191 | break; | ||
| 192 | case MODE_WRITE: | ||
| 193 | memcpy(*ptr, data, size); | ||
| 194 | break; | ||
| 195 | case MODE_MEASURE: | ||
| 196 | break; // MODE_MEASURE - don't need to do anything | ||
| 197 | case MODE_VERIFY: | ||
| 198 | for (int i = 0; i < size; i++) { | ||
| 199 | DEBUG_ASSERT_MSG( | ||
| 200 | ((u8*)data)[i] == (*ptr)[i], | ||
| 201 | "Savestate verification failure: %d (0x%X) (at %p) != %d (0x%X) (at %p).\n", | ||
| 202 | ((u8*)data)[i], ((u8*)data)[i], &((u8*)data)[i], (*ptr)[i], (*ptr)[i], | ||
| 203 | &(*ptr)[i]); | ||
| 204 | } | ||
| 205 | break; | ||
| 206 | default: | ||
| 207 | break; // throw an error? | ||
| 208 | } | ||
| 209 | (*ptr) += size; | ||
| 210 | return true; | ||
| 211 | } | ||
| 212 | |||
| 213 | void DoVoid(void* data, int size) { | ||
| 214 | switch (mode) { | ||
| 215 | case MODE_READ: | ||
| 216 | memcpy(data, *ptr, size); | ||
| 217 | break; | ||
| 218 | case MODE_WRITE: | ||
| 219 | memcpy(*ptr, data, size); | ||
| 220 | break; | ||
| 221 | case MODE_MEASURE: | ||
| 222 | break; // MODE_MEASURE - don't need to do anything | ||
| 223 | case MODE_VERIFY: | ||
| 224 | for (int i = 0; i < size; i++) { | ||
| 225 | DEBUG_ASSERT_MSG( | ||
| 226 | ((u8*)data)[i] == (*ptr)[i], | ||
| 227 | "Savestate verification failure: %d (0x%X) (at %p) != %d (0x%X) (at %p).\n", | ||
| 228 | ((u8*)data)[i], ((u8*)data)[i], &((u8*)data)[i], (*ptr)[i], (*ptr)[i], | ||
| 229 | &(*ptr)[i]); | ||
| 230 | } | ||
| 231 | break; | ||
| 232 | default: | ||
| 233 | break; // throw an error? | ||
| 234 | } | ||
| 235 | (*ptr) += size; | ||
| 236 | } | ||
| 237 | |||
| 238 | template <class K, class T> | ||
| 239 | void Do(std::map<K, T*>& x) { | ||
| 240 | if (mode == MODE_READ) { | ||
| 241 | for (auto it = x.begin(), end = x.end(); it != end; ++it) { | ||
| 242 | if (it->second != nullptr) | ||
| 243 | delete it->second; | ||
| 244 | } | ||
| 245 | } | ||
| 246 | T* dv = nullptr; | ||
| 247 | DoMap(x, dv); | ||
| 248 | } | ||
| 249 | |||
| 250 | template <class K, class T> | ||
| 251 | void Do(std::map<K, T>& x) { | ||
| 252 | T dv = T(); | ||
| 253 | DoMap(x, dv); | ||
| 254 | } | ||
| 255 | |||
| 256 | template <class K, class T> | ||
| 257 | void DoMap(std::map<K, T>& x, T& default_val) { | ||
| 258 | unsigned int number = (unsigned int)x.size(); | ||
| 259 | Do(number); | ||
| 260 | switch (mode) { | ||
| 261 | case MODE_READ: { | ||
| 262 | x.clear(); | ||
| 263 | while (number > 0) { | ||
| 264 | K first = K(); | ||
| 265 | Do(first); | ||
| 266 | T second = default_val; | ||
| 267 | Do(second); | ||
| 268 | x[first] = second; | ||
| 269 | --number; | ||
| 270 | } | ||
| 271 | } break; | ||
| 272 | case MODE_WRITE: | ||
| 273 | case MODE_MEASURE: | ||
| 274 | case MODE_VERIFY: { | ||
| 275 | typename std::map<K, T>::iterator itr = x.begin(); | ||
| 276 | while (number > 0) { | ||
| 277 | K first = itr->first; | ||
| 278 | Do(first); | ||
| 279 | Do(itr->second); | ||
| 280 | --number; | ||
| 281 | ++itr; | ||
| 282 | } | ||
| 283 | } break; | ||
| 284 | } | ||
| 285 | } | ||
| 286 | |||
| 287 | template <class K, class T> | ||
| 288 | void Do(std::multimap<K, T*>& x) { | ||
| 289 | if (mode == MODE_READ) { | ||
| 290 | for (auto it = x.begin(), end = x.end(); it != end; ++it) { | ||
| 291 | if (it->second != nullptr) | ||
| 292 | delete it->second; | ||
| 293 | } | ||
| 294 | } | ||
| 295 | T* dv = nullptr; | ||
| 296 | DoMultimap(x, dv); | ||
| 297 | } | ||
| 298 | |||
| 299 | template <class K, class T> | ||
| 300 | void Do(std::multimap<K, T>& x) { | ||
| 301 | T dv = T(); | ||
| 302 | DoMultimap(x, dv); | ||
| 303 | } | ||
| 304 | |||
| 305 | template <class K, class T> | ||
| 306 | void DoMultimap(std::multimap<K, T>& x, T& default_val) { | ||
| 307 | unsigned int number = (unsigned int)x.size(); | ||
| 308 | Do(number); | ||
| 309 | switch (mode) { | ||
| 310 | case MODE_READ: { | ||
| 311 | x.clear(); | ||
| 312 | while (number > 0) { | ||
| 313 | K first = K(); | ||
| 314 | Do(first); | ||
| 315 | T second = default_val; | ||
| 316 | Do(second); | ||
| 317 | x.insert(std::make_pair(first, second)); | ||
| 318 | --number; | ||
| 319 | } | ||
| 320 | } break; | ||
| 321 | case MODE_WRITE: | ||
| 322 | case MODE_MEASURE: | ||
| 323 | case MODE_VERIFY: { | ||
| 324 | typename std::multimap<K, T>::iterator itr = x.begin(); | ||
| 325 | while (number > 0) { | ||
| 326 | Do(itr->first); | ||
| 327 | Do(itr->second); | ||
| 328 | --number; | ||
| 329 | ++itr; | ||
| 330 | } | ||
| 331 | } break; | ||
| 332 | } | ||
| 333 | } | ||
| 334 | |||
| 335 | // Store vectors. | ||
| 336 | template <class T> | ||
| 337 | void Do(std::vector<T*>& x) { | ||
| 338 | T* dv = nullptr; | ||
| 339 | DoVector(x, dv); | ||
| 340 | } | ||
| 341 | |||
| 342 | template <class T> | ||
| 343 | void Do(std::vector<T>& x) { | ||
| 344 | T dv = T(); | ||
| 345 | DoVector(x, dv); | ||
| 346 | } | ||
| 347 | |||
| 348 | template <class T> | ||
| 349 | void DoPOD(std::vector<T>& x) { | ||
| 350 | T dv = T(); | ||
| 351 | DoVectorPOD(x, dv); | ||
| 352 | } | ||
| 353 | |||
| 354 | template <class T> | ||
| 355 | void Do(std::vector<T>& x, T& default_val) { | ||
| 356 | DoVector(x, default_val); | ||
| 357 | } | ||
| 358 | |||
| 359 | template <class T> | ||
| 360 | void DoVector(std::vector<T>& x, T& default_val) { | ||
| 361 | u32 vec_size = (u32)x.size(); | ||
| 362 | Do(vec_size); | ||
| 363 | x.resize(vec_size, default_val); | ||
| 364 | if (vec_size > 0) | ||
| 365 | DoArray(&x[0], vec_size); | ||
| 366 | } | ||
| 367 | |||
| 368 | template <class T> | ||
| 369 | void DoVectorPOD(std::vector<T>& x, T& default_val) { | ||
| 370 | u32 vec_size = (u32)x.size(); | ||
| 371 | Do(vec_size); | ||
| 372 | x.resize(vec_size, default_val); | ||
| 373 | if (vec_size > 0) | ||
| 374 | DoArray(&x[0], vec_size); | ||
| 375 | } | ||
| 376 | |||
| 377 | // Store deques. | ||
| 378 | template <class T> | ||
| 379 | void Do(std::deque<T*>& x) { | ||
| 380 | T* dv = nullptr; | ||
| 381 | DoDeque(x, dv); | ||
| 382 | } | ||
| 383 | |||
| 384 | template <class T> | ||
| 385 | void Do(std::deque<T>& x) { | ||
| 386 | T dv = T(); | ||
| 387 | DoDeque(x, dv); | ||
| 388 | } | ||
| 389 | |||
| 390 | template <class T> | ||
| 391 | void DoDeque(std::deque<T>& x, T& default_val) { | ||
| 392 | u32 deq_size = (u32)x.size(); | ||
| 393 | Do(deq_size); | ||
| 394 | x.resize(deq_size, default_val); | ||
| 395 | u32 i; | ||
| 396 | for (i = 0; i < deq_size; i++) | ||
| 397 | Do(x[i]); | ||
| 398 | } | ||
| 399 | |||
| 400 | // Store STL lists. | ||
| 401 | template <class T> | ||
| 402 | void Do(std::list<T*>& x) { | ||
| 403 | T* dv = nullptr; | ||
| 404 | Do(x, dv); | ||
| 405 | } | ||
| 406 | |||
| 407 | template <class T> | ||
| 408 | void Do(std::list<T>& x) { | ||
| 409 | T dv = T(); | ||
| 410 | DoList(x, dv); | ||
| 411 | } | ||
| 412 | |||
| 413 | template <class T> | ||
| 414 | void Do(std::list<T>& x, T& default_val) { | ||
| 415 | DoList(x, default_val); | ||
| 416 | } | ||
| 417 | |||
| 418 | template <class T> | ||
| 419 | void DoList(std::list<T>& x, T& default_val) { | ||
| 420 | u32 list_size = (u32)x.size(); | ||
| 421 | Do(list_size); | ||
| 422 | x.resize(list_size, default_val); | ||
| 423 | |||
| 424 | typename std::list<T>::iterator itr, end; | ||
| 425 | for (itr = x.begin(), end = x.end(); itr != end; ++itr) | ||
| 426 | Do(*itr); | ||
| 427 | } | ||
| 428 | |||
| 429 | // Store STL sets. | ||
| 430 | template <class T> | ||
| 431 | void Do(std::set<T*>& x) { | ||
| 432 | if (mode == MODE_READ) { | ||
| 433 | for (auto it = x.begin(), end = x.end(); it != end; ++it) { | ||
| 434 | if (*it != nullptr) | ||
| 435 | delete *it; | ||
| 436 | } | ||
| 437 | } | ||
| 438 | DoSet(x); | ||
| 439 | } | ||
| 440 | |||
| 441 | template <class T> | ||
| 442 | void Do(std::set<T>& x) { | ||
| 443 | DoSet(x); | ||
| 444 | } | ||
| 445 | |||
| 446 | template <class T> | ||
| 447 | void DoSet(std::set<T>& x) { | ||
| 448 | unsigned int number = (unsigned int)x.size(); | ||
| 449 | Do(number); | ||
| 450 | |||
| 451 | switch (mode) { | ||
| 452 | case MODE_READ: { | ||
| 453 | x.clear(); | ||
| 454 | while (number-- > 0) { | ||
| 455 | T it = T(); | ||
| 456 | Do(it); | ||
| 457 | x.insert(it); | ||
| 458 | } | ||
| 459 | } break; | ||
| 460 | case MODE_WRITE: | ||
| 461 | case MODE_MEASURE: | ||
| 462 | case MODE_VERIFY: { | ||
| 463 | typename std::set<T>::iterator itr = x.begin(); | ||
| 464 | while (number-- > 0) | ||
| 465 | Do(*itr++); | ||
| 466 | } break; | ||
| 467 | |||
| 468 | default: | ||
| 469 | LOG_ERROR(Common, "Savestate error: invalid mode %d.", mode); | ||
| 470 | } | ||
| 471 | } | ||
| 472 | |||
| 473 | // Store strings. | ||
| 474 | void Do(std::string& x) { | ||
| 475 | int stringLen = (int)x.length() + 1; | ||
| 476 | Do(stringLen); | ||
| 477 | |||
| 478 | switch (mode) { | ||
| 479 | case MODE_READ: | ||
| 480 | x = (char*)*ptr; | ||
| 481 | break; | ||
| 482 | case MODE_WRITE: | ||
| 483 | memcpy(*ptr, x.c_str(), stringLen); | ||
| 484 | break; | ||
| 485 | case MODE_MEASURE: | ||
| 486 | break; | ||
| 487 | case MODE_VERIFY: | ||
| 488 | DEBUG_ASSERT_MSG((x == (char*)*ptr), | ||
| 489 | "Savestate verification failure: \"%s\" != \"%s\" (at %p).\n", | ||
| 490 | x.c_str(), (char*)*ptr, ptr); | ||
| 491 | break; | ||
| 492 | } | ||
| 493 | (*ptr) += stringLen; | ||
| 494 | } | ||
| 495 | |||
| 496 | void Do(std::wstring& x) { | ||
| 497 | int stringLen = sizeof(wchar_t) * ((int)x.length() + 1); | ||
| 498 | Do(stringLen); | ||
| 499 | |||
| 500 | switch (mode) { | ||
| 501 | case MODE_READ: | ||
| 502 | x = (wchar_t*)*ptr; | ||
| 503 | break; | ||
| 504 | case MODE_WRITE: | ||
| 505 | memcpy(*ptr, x.c_str(), stringLen); | ||
| 506 | break; | ||
| 507 | case MODE_MEASURE: | ||
| 508 | break; | ||
| 509 | case MODE_VERIFY: | ||
| 510 | DEBUG_ASSERT_MSG((x == (wchar_t*)*ptr), | ||
| 511 | "Savestate verification failure: \"%ls\" != \"%ls\" (at %p).\n", | ||
| 512 | x.c_str(), (wchar_t*)*ptr, ptr); | ||
| 513 | break; | ||
| 514 | } | ||
| 515 | (*ptr) += stringLen; | ||
| 516 | } | ||
| 517 | |||
| 518 | template <class T> | ||
| 519 | void DoClass(T& x) { | ||
| 520 | x.DoState(*this); | ||
| 521 | } | ||
| 522 | |||
| 523 | template <class T> | ||
| 524 | void DoClass(T*& x) { | ||
| 525 | if (mode == MODE_READ) { | ||
| 526 | if (x != nullptr) | ||
| 527 | delete x; | ||
| 528 | x = new T(); | ||
| 529 | } | ||
| 530 | x->DoState(*this); | ||
| 531 | } | ||
| 532 | |||
| 533 | template <class T> | ||
| 534 | void DoArray(T* x, int count) { | ||
| 535 | DoHelper<T>::DoArray(this, x, count); | ||
| 536 | } | ||
| 537 | |||
| 538 | template <class T> | ||
| 539 | void Do(T& x) { | ||
| 540 | DoHelper<T>::Do(this, x); | ||
| 541 | } | ||
| 542 | |||
| 543 | template <class T> | ||
| 544 | void DoPOD(T& x) { | ||
| 545 | DoHelper<T>::Do(this, x); | ||
| 546 | } | ||
| 547 | |||
| 548 | template <class T> | ||
| 549 | void DoPointer(T*& x, T* const base) { | ||
| 550 | // pointers can be more than 2^31 apart, but you're using this function wrong if you need | ||
| 551 | // that much range | ||
| 552 | s32 offset = x - base; | ||
| 553 | Do(offset); | ||
| 554 | if (mode == MODE_READ) | ||
| 555 | x = base + offset; | ||
| 556 | } | ||
| 557 | |||
| 558 | template <class T, LinkedListItem<T>* (*TNew)(), void (*TFree)(LinkedListItem<T>*), | ||
| 559 | void (*TDo)(PointerWrap&, T*)> | ||
| 560 | void DoLinkedList(LinkedListItem<T>*& list_start, LinkedListItem<T>** list_end = nullptr) { | ||
| 561 | LinkedListItem<T>* list_cur = list_start; | ||
| 562 | LinkedListItem<T>* prev = nullptr; | ||
| 563 | |||
| 564 | while (true) { | ||
| 565 | u8 shouldExist = (list_cur ? 1 : 0); | ||
| 566 | Do(shouldExist); | ||
| 567 | if (shouldExist == 1) { | ||
| 568 | LinkedListItem<T>* cur = list_cur ? list_cur : TNew(); | ||
| 569 | TDo(*this, (T*)cur); | ||
| 570 | if (!list_cur) { | ||
| 571 | if (mode == MODE_READ) { | ||
| 572 | cur->next = nullptr; | ||
| 573 | list_cur = cur; | ||
| 574 | if (prev) | ||
| 575 | prev->next = cur; | ||
| 576 | else | ||
| 577 | list_start = cur; | ||
| 578 | } else { | ||
| 579 | TFree(cur); | ||
| 580 | continue; | ||
| 581 | } | ||
| 582 | } | ||
| 583 | } else { | ||
| 584 | if (mode == MODE_READ) { | ||
| 585 | if (prev) | ||
| 586 | prev->next = nullptr; | ||
| 587 | if (list_end) | ||
| 588 | *list_end = prev; | ||
| 589 | if (list_cur) { | ||
| 590 | if (list_start == list_cur) | ||
| 591 | list_start = nullptr; | ||
| 592 | do { | ||
| 593 | LinkedListItem<T>* next = list_cur->next; | ||
| 594 | TFree(list_cur); | ||
| 595 | list_cur = next; | ||
| 596 | } while (list_cur); | ||
| 597 | } | ||
| 598 | } | ||
| 599 | break; | ||
| 600 | } | ||
| 601 | prev = list_cur; | ||
| 602 | list_cur = list_cur->next; | ||
| 603 | } | ||
| 604 | } | ||
| 605 | |||
| 606 | void DoMarker(const char* prevName, u32 arbitraryNumber = 0x42) { | ||
| 607 | u32 cookie = arbitraryNumber; | ||
| 608 | Do(cookie); | ||
| 609 | if (mode == PointerWrap::MODE_READ && cookie != arbitraryNumber) { | ||
| 610 | LOG_ERROR(Common, | ||
| 611 | "After \"%s\", found %d (0x%X) instead of save marker %d (0x%X). " | ||
| 612 | "Aborting savestate load...", | ||
| 613 | prevName, cookie, cookie, arbitraryNumber, arbitraryNumber); | ||
| 614 | SetError(ERROR_FAILURE); | ||
| 615 | } | ||
| 616 | } | ||
| 617 | }; | ||
| 618 | |||
| 619 | inline PointerWrapSection::~PointerWrapSection() { | ||
| 620 | if (ver_ > 0) { | ||
| 621 | p_.DoMarker(title_); | ||
| 622 | } | ||
| 623 | } | ||
diff --git a/src/common/linear_disk_cache.h b/src/common/linear_disk_cache.h deleted file mode 100644 index 94c695163..000000000 --- a/src/common/linear_disk_cache.h +++ /dev/null | |||
| @@ -1,167 +0,0 @@ | |||
| 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 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <fstream> | ||
| 8 | #include "common/common_types.h" | ||
| 9 | |||
| 10 | // defined in Version.cpp | ||
| 11 | extern const char* scm_rev_git_str; | ||
| 12 | |||
| 13 | // On disk format: | ||
| 14 | // header{ | ||
| 15 | // u32 'DCAC'; | ||
| 16 | // u32 version; // svn_rev | ||
| 17 | // u16 sizeof(key_type); | ||
| 18 | // u16 sizeof(value_type); | ||
| 19 | //} | ||
| 20 | |||
| 21 | // key_value_pair{ | ||
| 22 | // u32 value_size; | ||
| 23 | // key_type key; | ||
| 24 | // value_type[value_size] value; | ||
| 25 | //} | ||
| 26 | |||
| 27 | template <typename K, typename V> | ||
| 28 | class LinearDiskCacheReader { | ||
| 29 | public: | ||
| 30 | virtual void Read(const K& key, const V* value, u32 value_size) = 0; | ||
| 31 | }; | ||
| 32 | |||
| 33 | // Dead simple unsorted key-value store with append functionality. | ||
| 34 | // No random read functionality, all reading is done in OpenAndRead. | ||
| 35 | // Keys and values can contain any characters, including \0. | ||
| 36 | // | ||
| 37 | // Suitable for caching generated shader bytecode between executions. | ||
| 38 | // Not tuned for extreme performance but should be reasonably fast. | ||
| 39 | // Does not support keys or values larger than 2GB, which should be reasonable. | ||
| 40 | // Keys must have non-zero length; values can have zero length. | ||
| 41 | |||
| 42 | // K and V are some POD type | ||
| 43 | // K : the key type | ||
| 44 | // V : value array type | ||
| 45 | template <typename K, typename V> | ||
| 46 | class LinearDiskCache { | ||
| 47 | public: | ||
| 48 | // return number of read entries | ||
| 49 | u32 OpenAndRead(const char* filename, LinearDiskCacheReader<K, V>& reader) { | ||
| 50 | using std::ios_base; | ||
| 51 | |||
| 52 | // close any currently opened file | ||
| 53 | Close(); | ||
| 54 | m_num_entries = 0; | ||
| 55 | |||
| 56 | // try opening for reading/writing | ||
| 57 | OpenFStream(m_file, filename, ios_base::in | ios_base::out | ios_base::binary); | ||
| 58 | |||
| 59 | m_file.seekg(0, std::ios::end); | ||
| 60 | std::fstream::pos_type end_pos = m_file.tellg(); | ||
| 61 | m_file.seekg(0, std::ios::beg); | ||
| 62 | std::fstream::pos_type start_pos = m_file.tellg(); | ||
| 63 | std::streamoff file_size = end_pos - start_pos; | ||
| 64 | |||
| 65 | if (m_file.is_open() && ValidateHeader()) { | ||
| 66 | // good header, read some key/value pairs | ||
| 67 | K key; | ||
| 68 | |||
| 69 | V* value = nullptr; | ||
| 70 | u32 value_size; | ||
| 71 | u32 entry_number; | ||
| 72 | |||
| 73 | std::fstream::pos_type last_pos = m_file.tellg(); | ||
| 74 | |||
| 75 | while (Read(&value_size)) { | ||
| 76 | std::streamoff next_extent = | ||
| 77 | (last_pos - start_pos) + sizeof(value_size) + value_size; | ||
| 78 | if (next_extent > file_size) | ||
| 79 | break; | ||
| 80 | |||
| 81 | delete[] value; | ||
| 82 | value = new V[value_size]; | ||
| 83 | |||
| 84 | // read key/value and pass to reader | ||
| 85 | if (Read(&key) && Read(value, value_size) && Read(&entry_number) && | ||
| 86 | entry_number == m_num_entries + 1) { | ||
| 87 | reader.Read(key, value, value_size); | ||
| 88 | } else { | ||
| 89 | break; | ||
| 90 | } | ||
| 91 | |||
| 92 | m_num_entries++; | ||
| 93 | last_pos = m_file.tellg(); | ||
| 94 | } | ||
| 95 | m_file.seekp(last_pos); | ||
| 96 | m_file.clear(); | ||
| 97 | |||
| 98 | delete[] value; | ||
| 99 | return m_num_entries; | ||
| 100 | } | ||
| 101 | |||
| 102 | // failed to open file for reading or bad header | ||
| 103 | // close and recreate file | ||
| 104 | Close(); | ||
| 105 | m_file.open(filename, ios_base::out | ios_base::trunc | ios_base::binary); | ||
| 106 | WriteHeader(); | ||
| 107 | return 0; | ||
| 108 | } | ||
| 109 | |||
| 110 | void Sync() { | ||
| 111 | m_file.flush(); | ||
| 112 | } | ||
| 113 | |||
| 114 | void Close() { | ||
| 115 | if (m_file.is_open()) | ||
| 116 | m_file.close(); | ||
| 117 | // clear any error flags | ||
| 118 | m_file.clear(); | ||
| 119 | } | ||
| 120 | |||
| 121 | // Appends a key-value pair to the store. | ||
| 122 | void Append(const K& key, const V* value, u32 value_size) { | ||
| 123 | // TODO: Should do a check that we don't already have "key"? (I think each caller does that | ||
| 124 | // already.) | ||
| 125 | Write(&value_size); | ||
| 126 | Write(&key); | ||
| 127 | Write(value, value_size); | ||
| 128 | m_num_entries++; | ||
| 129 | Write(&m_num_entries); | ||
| 130 | } | ||
| 131 | |||
| 132 | private: | ||
| 133 | void WriteHeader() { | ||
| 134 | Write(&m_header); | ||
| 135 | } | ||
| 136 | |||
| 137 | bool ValidateHeader() { | ||
| 138 | char file_header[sizeof(Header)]; | ||
| 139 | |||
| 140 | return (Read(file_header, sizeof(Header)) && | ||
| 141 | !memcmp((const char*)&m_header, file_header, sizeof(Header))); | ||
| 142 | } | ||
| 143 | |||
| 144 | template <typename D> | ||
| 145 | bool Write(const D* data, u32 count = 1) { | ||
| 146 | return m_file.write((const char*)data, count * sizeof(D)).good(); | ||
| 147 | } | ||
| 148 | |||
| 149 | template <typename D> | ||
| 150 | bool Read(const D* data, u32 count = 1) { | ||
| 151 | return m_file.read((char*)data, count * sizeof(D)).good(); | ||
| 152 | } | ||
| 153 | |||
| 154 | struct Header { | ||
| 155 | Header() : id(*(u32*)"DCAC"), key_t_size(sizeof(K)), value_t_size(sizeof(V)) { | ||
| 156 | memcpy(ver, scm_rev_git_str, 40); | ||
| 157 | } | ||
| 158 | |||
| 159 | const u32 id; | ||
| 160 | const u16 key_t_size, value_t_size; | ||
| 161 | char ver[40]; | ||
| 162 | |||
| 163 | } m_header; | ||
| 164 | |||
| 165 | std::fstream m_file; | ||
| 166 | u32 m_num_entries; | ||
| 167 | }; | ||