mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-24 06:39:46 -06:00
Made LinearDiskCache a template class. Keys are now some POD type (fixed size). Eliminates casting and key size checking.
git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@6420 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
@ -701,10 +701,6 @@
|
||||
RelativePath=".\Src\IniFile.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\LinearDiskCache.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\LinearDiskCache.h"
|
||||
>
|
||||
|
@ -1,172 +0,0 @@
|
||||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "LinearDiskCache.h"
|
||||
|
||||
static const char ID[4] = {'D', 'C', 'A', 'C'};
|
||||
|
||||
// Update this to the current SVN revision every time you change shader generation code.
|
||||
// We don't automatically get this from SVN_REV because that would mean regenerating the
|
||||
// shader cache for every revision, graphics-related or not, which is simply annoying.
|
||||
const int version = 6306;
|
||||
|
||||
LinearDiskCache::LinearDiskCache()
|
||||
: file_(NULL), num_entries_(0) {
|
||||
}
|
||||
|
||||
void LinearDiskCache::WriteHeader() {
|
||||
fwrite(ID, 4, 1, file_);
|
||||
fwrite(&version, 4, 1, file_);
|
||||
}
|
||||
|
||||
bool LinearDiskCache::ValidateHeader() {
|
||||
char header_id[4];
|
||||
int header_version;
|
||||
fread(&header_id, 4, 1, file_);
|
||||
fread(&header_version, 4, 1, file_);
|
||||
if (memcmp(header_id, ID, 4) != 0)
|
||||
return false;
|
||||
if (header_version != version)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
int LinearDiskCache::OpenAndRead(const char *filename, LinearDiskCacheReader *reader) {
|
||||
if (file_)
|
||||
{
|
||||
ERROR_LOG(VIDEO, "LinearDiskCache trying to open an alredy opened cache");
|
||||
return 0;
|
||||
}
|
||||
int items_read_count = 0;
|
||||
file_ = fopen(filename, "rb");
|
||||
int file_size = 0;
|
||||
if (file_) {
|
||||
fseek(file_, 0, SEEK_END);
|
||||
file_size = (int)ftell(file_);
|
||||
}
|
||||
|
||||
bool file_corrupt = false;
|
||||
if (file_size == 0) {
|
||||
if (file_)
|
||||
fclose(file_);
|
||||
// Reopen for writing.
|
||||
file_ = fopen(filename, "wb");
|
||||
// Cache empty, let's initialize a header.
|
||||
WriteHeader();
|
||||
num_entries_ = 0;
|
||||
} else {
|
||||
// file_ must be != 0 here.
|
||||
// Back to the start we go.
|
||||
fseek(file_, 0, SEEK_SET);
|
||||
// Check that the file is valid
|
||||
if (!ValidateHeader()) {
|
||||
// Not valid - delete the file and start over.
|
||||
fclose(file_);
|
||||
unlink(filename);
|
||||
|
||||
// PanicAlert("LinearDiskCache file header broken.");
|
||||
|
||||
file_ = fopen(filename, "wb");
|
||||
WriteHeader();
|
||||
num_entries_ = 0;
|
||||
} else {
|
||||
// Valid - blow through it.
|
||||
// We're past the header already thanks to ValidateHeader.
|
||||
while (!feof(file_)) {
|
||||
int key_size, value_size;
|
||||
size_t key_size_size = fread(&key_size, 1, sizeof(key_size), file_);
|
||||
size_t value_size_size = fread(&value_size, 1, sizeof(value_size), file_);
|
||||
if (key_size_size == 0 && value_size_size == 0) {
|
||||
// I guess feof isn't doing it's job - we're at the end.
|
||||
break;
|
||||
}
|
||||
if (key_size <= 0 || value_size < 0 || key_size_size != 4 || value_size_size != 4) {
|
||||
// PanicAlert("Disk cache file %s corrupted/truncated! ks: %i vs %i kss %i vss %i", filename,
|
||||
// key_size, value_size, key_size_size, value_size_size);
|
||||
file_corrupt = true;
|
||||
break;
|
||||
}
|
||||
u8 *key = new u8[key_size];
|
||||
u8 *value = new u8[value_size];
|
||||
int actual_key_size = (int)fread(key, 1, key_size, file_);
|
||||
int actual_value_size = (int)fread(value, 1, value_size, file_);
|
||||
if (actual_key_size != key_size || actual_value_size != value_size) {
|
||||
// PanicAlert("Disk cache file %s corrupted/truncated! ks: %i actual ks: %i vs: %i actual vs: %i", filename,
|
||||
// key_size, actual_key_size, value_size, actual_value_size);
|
||||
file_corrupt = true;
|
||||
} else {
|
||||
reader->Read(key, key_size, value, value_size);
|
||||
items_read_count++;
|
||||
}
|
||||
delete [] key;
|
||||
delete [] value;
|
||||
}
|
||||
fclose(file_);
|
||||
// Done reading.
|
||||
|
||||
// Reopen file for append.
|
||||
// At this point, ftell() will be at the end of the file,
|
||||
// which happens to be exactly what we want.
|
||||
file_ = fopen(filename, "ab");
|
||||
fseek(file_, 0, SEEK_END);
|
||||
}
|
||||
}
|
||||
|
||||
if (file_corrupt) {
|
||||
// Restore sanity, start over.
|
||||
fclose(file_);
|
||||
unlink(filename);
|
||||
|
||||
file_ = fopen(filename, "wb+");
|
||||
WriteHeader();
|
||||
}
|
||||
|
||||
return items_read_count;
|
||||
}
|
||||
|
||||
void LinearDiskCache::Append(
|
||||
const u8 *key, int key_size, const u8 *value, int value_size) {
|
||||
// Should do a check that we don't already have "key"?
|
||||
fwrite(&key_size, 1, sizeof(key_size), file_);
|
||||
fwrite(&value_size, 1, sizeof(value_size), file_);
|
||||
fwrite(key, 1, key_size, file_);
|
||||
fwrite(value, 1, value_size, file_);
|
||||
}
|
||||
|
||||
void LinearDiskCache::Sync() {
|
||||
if (file_)
|
||||
{
|
||||
fflush(file_);
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR_LOG(VIDEO, "LinearDiskCache trying to sync closed cache");
|
||||
}
|
||||
}
|
||||
|
||||
void LinearDiskCache::Close() {
|
||||
if (file_)
|
||||
{
|
||||
fclose(file_);
|
||||
file_ = 0;
|
||||
num_entries_ = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR_LOG(VIDEO, "LinearDiskCache trying to close an alredy closed cache");
|
||||
}
|
||||
}
|
@ -19,21 +19,35 @@
|
||||
#define _LINEAR_DISKCACHE
|
||||
|
||||
#include "Common.h"
|
||||
#include <fstream>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
// Update this to the current SVN revision every time you change shader generation code.
|
||||
// We don't automatically get this from SVN_REV because that would mean regenerating the
|
||||
// shader cache for every revision, graphics-related or not, which is simply annoying.
|
||||
enum
|
||||
{
|
||||
LINEAR_DISKCACHE_VER = 6420
|
||||
};
|
||||
|
||||
// On disk format:
|
||||
// uint32 'DCAC'
|
||||
// uint32 version; // svn_rev
|
||||
// uint32 key_length;
|
||||
// uint32 value_length;
|
||||
// .... key;
|
||||
// .... value;
|
||||
//header{
|
||||
// u32 'DCAC';
|
||||
// u32 version; // svn_rev
|
||||
// u16 sizeof(key_type);
|
||||
// u16 sizeof(value_type);
|
||||
//}
|
||||
|
||||
class LinearDiskCacheReader {
|
||||
//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 u8 *key, int key_size, const u8 *value, int value_size) = 0;
|
||||
virtual void Read(const K &key, const V *value, u32 value_size) = 0;
|
||||
};
|
||||
|
||||
// Dead simple unsorted key-value store with append functionality.
|
||||
@ -44,24 +58,123 @@ public:
|
||||
// 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.
|
||||
class LinearDiskCache {
|
||||
public:
|
||||
LinearDiskCache();
|
||||
|
||||
// Returns the number of items read from the cache.
|
||||
int OpenAndRead(const char *filename, LinearDiskCacheReader *reader);
|
||||
void Close();
|
||||
void Sync();
|
||||
// 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();
|
||||
|
||||
// try opening for reading/writing
|
||||
m_file.open(filename, ios_base::in | ios_base::out | ios_base::binary);
|
||||
|
||||
if (m_file.is_open() && ValidateHeader())
|
||||
{
|
||||
// good header, read some key/value pairs
|
||||
u32 num_entries = 0;
|
||||
K key;
|
||||
|
||||
V *value = NULL;
|
||||
u32 value_size;
|
||||
|
||||
while (Read(&value_size))
|
||||
{
|
||||
delete[] value;
|
||||
value = new V[value_size];
|
||||
|
||||
// read key/value and pass to reader
|
||||
if (Read(&key) && Read(value, value_size))
|
||||
reader.Read(key, value, value_size);
|
||||
else
|
||||
break;
|
||||
|
||||
++num_entries;
|
||||
}
|
||||
|
||||
delete[] value;
|
||||
return 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 u8 *key, int key_size, const u8 *value, int value_size);
|
||||
void Append(const K &key, const V *value, u32 value_size)
|
||||
{
|
||||
// TODO: Should do a check that we don't already have "key"?
|
||||
Write(&value_size);
|
||||
Write(&key);
|
||||
Write(value, value_size);
|
||||
}
|
||||
|
||||
private:
|
||||
void WriteHeader();
|
||||
bool ValidateHeader();
|
||||
void WriteHeader()
|
||||
{
|
||||
Write(&m_header);
|
||||
}
|
||||
|
||||
FILE *file_;
|
||||
int num_entries_;
|
||||
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")
|
||||
, ver(LINEAR_DISKCACHE_VER)
|
||||
, key_t_size(sizeof(K))
|
||||
, value_t_size(sizeof(V))
|
||||
{}
|
||||
|
||||
const u32 id, ver;
|
||||
const u16 key_t_size, value_t_size;
|
||||
|
||||
} m_header;
|
||||
|
||||
std::fstream m_file;
|
||||
};
|
||||
|
||||
#endif // _LINEAR_DISKCACHE
|
||||
|
Reference in New Issue
Block a user