Пример использования:
Вот такая вот база данных:
struct my_record
{
int x;
int y;
my_record(): x(0),y(0) {}
};
tool::table<my_record> db;
db.open("c:/test.db",true);
db[0].x = 10;
db[0].y = 10;
db[1].x = 20;
db[1].y = 20;
...
db.close();
Собственно persistent flat table
namespace tool {
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
template<class RECORD>
class table
{
bool read_only;
HANDLE hfile;
HANDLE hmap;
RECORD* data;
unsigned int total_records;
public:
table(): hfile(0),hmap(0),data(0),total_records(0), read_only(true) {}
virtual ~table() { close(); }
bool open(const char *path, bool to_write = false);
void close();
unsigned int total() { return total_records; }
void total(unsigned int numrecs)
{
assert(numrecs <= total_records);
total_records = numrecs;
}
const RECORD& operator[](int idx) const
{
assert(idx < total_records);
return data[idx];
}
RECORD& operator[](int idx)
{
assert(!read_only);
if(idx >= total_records)
{
RECORD nullrec;
while(idx >= total_records)
data[total_records++] = nullrec;
}
return data[idx];
}
};
template <class RECORD>
inline bool
table<RECORD>::open(const char *path, bool to_write)
{
read_only = !to_write;
hfile = INVALID_HANDLE_VALUE;
hmap = INVALID_HANDLE_VALUE;
data = 0;
size_t length = 0;
hfile = CreateFile(path, GENERIC_READ | (read_only? 0: GENERIC_WRITE), FILE_SHARE_READ | (read_only? 0: FILE_SHARE_WRITE), NULL,
read_only?OPEN_EXISTING:CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
if (hfile != INVALID_HANDLE_VALUE)
{
length = GetFileSize(hfile, 0);
hmap = CreateFileMapping(hfile, NULL, read_only? PAGE_READONLY : PAGE_READWRITE, 0, read_only?0:0x10000000, NULL);
}
else
{
DWORD erno = GetLastError();
printf("ERROR: memory map file open <%s> failed with %x\n",path, erno);
return false;
}
if (hfile != INVALID_HANDLE_VALUE && hmap == NULL)
{
close();
return false;
}
else
{
if (hmap != NULL)
data = (RECORD *) MapViewOfFile(hmap, read_only? FILE_MAP_READ : FILE_MAP_WRITE, 0, 0, 0);
if(data == 0)
{
DWORD erno = GetLastError();
printf("ERROR: map file %x\n", erno);
close();
return false;
}
}
total_records = length / sizeof(RECORD);
return true;
}
template <class RECORD>
inline void
table<RECORD>::close()
{
if (hfile && hmap && data) {
if(!read_only)
if (!FlushViewOfFile(data, total_records * sizeof(RECORD)) )
{
printf("Could not flush memory to disk.\n");
}
UnmapViewOfFile(data);
data = 0;
}
if (hmap) {
CloseHandle(hmap);
hmap = 0;
}
if (hfile != INVALID_HANDLE_VALUE)
{
if(!read_only)
{
SetFilePointer(hfile,total_records * sizeof(RECORD),0,FILE_BEGIN);
SetEndOfFile(hfile);
}
CloseHandle(hfile);
hfile = 0;
}
}
}