mirror of
https://github.com/alliedmodders/amxmodx.git
synced 2024-12-25 14:25:38 +03:00
Implementation of journaling
This commit is contained in:
parent
aa8beace98
commit
abbb2f2cc2
@ -23,7 +23,7 @@ HashTable::htNode *HashTable::Retrieve(const char *key)
|
|||||||
return _FindNode(key);
|
return _FindNode(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Adds an entry into the hash table
|
//Adds an entry into the hash table with current time
|
||||||
void HashTable::Store(const char *key, const char *value, bool temporary)
|
void HashTable::Store(const char *key, const char *value, bool temporary)
|
||||||
{
|
{
|
||||||
time_t stamp = 0;
|
time_t stamp = 0;
|
||||||
@ -34,6 +34,22 @@ void HashTable::Store(const char *key, const char *value, bool temporary)
|
|||||||
_Insert(key, value, stamp);
|
_Insert(key, value, stamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Adds an entry into the hash table with preset time
|
||||||
|
void HashTable::Store(const char *key, const char *value, time_t stamp)
|
||||||
|
{
|
||||||
|
_Insert(key, value, stamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Erases a key
|
||||||
|
void HashTable::EraseKey(const char *key)
|
||||||
|
{
|
||||||
|
HashTable::htNodeSet *set = _FindNodeSet(key);
|
||||||
|
HashTable::htNode *node = _FindNode(key, false);
|
||||||
|
|
||||||
|
if (set && node)
|
||||||
|
_Unlink(set, node);
|
||||||
|
}
|
||||||
|
|
||||||
//Deletes all keys between the two times.
|
//Deletes all keys between the two times.
|
||||||
// 0 specifies "match all"
|
// 0 specifies "match all"
|
||||||
//All specifies whether permanent keys (time_t = 0) are erased
|
//All specifies whether permanent keys (time_t = 0) are erased
|
||||||
@ -106,7 +122,20 @@ void HashTable::Clear()
|
|||||||
|
|
||||||
bool HashTable::KeyExists(const char *key)
|
bool HashTable::KeyExists(const char *key)
|
||||||
{
|
{
|
||||||
return _FindNode(key, false);
|
return (_FindNode(key, false) != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t HashTable::UsedHashes()
|
||||||
|
{
|
||||||
|
size_t num = 0;
|
||||||
|
|
||||||
|
for (uint32_t i=0; i<HT_SIZE; i++)
|
||||||
|
{
|
||||||
|
if (m_Table[i])
|
||||||
|
num++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return num;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////
|
////////////////////
|
||||||
|
@ -34,15 +34,19 @@ public: //STRUCTORS
|
|||||||
public: //PRE-DEF
|
public: //PRE-DEF
|
||||||
class iterator;
|
class iterator;
|
||||||
struct htNode;
|
struct htNode;
|
||||||
|
friend class Vault;
|
||||||
private: //PRE-DEF
|
private: //PRE-DEF
|
||||||
struct htNodeSet;
|
struct htNodeSet;
|
||||||
public: //PUBLIC FUNCTIONS
|
public: //PUBLIC FUNCTIONS
|
||||||
void Store(const char *key, const char *value, bool temporary=true);
|
void Store(const char *key, const char *value, bool temporary=true);
|
||||||
|
void Store(const char *key, const char *value, time_t stamp);
|
||||||
htNode *Retrieve(const char *key);
|
htNode *Retrieve(const char *key);
|
||||||
iterator Enumerate();
|
iterator Enumerate();
|
||||||
size_t Prune(time_t begin, time_t end, bool all=false);
|
size_t Prune(time_t begin, time_t end, bool all=false);
|
||||||
void Clear();
|
void Clear();
|
||||||
bool KeyExists(const char *key);
|
bool KeyExists(const char *key);
|
||||||
|
size_t UsedHashes();
|
||||||
|
void EraseKey(const char *key);
|
||||||
public: //PUBLIC CLASSES
|
public: //PUBLIC CLASSES
|
||||||
class iterator
|
class iterator
|
||||||
{
|
{
|
||||||
|
328
dlls/nvault/journal.cpp
Executable file
328
dlls/nvault/journal.cpp
Executable file
@ -0,0 +1,328 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include "journal.h"
|
||||||
|
#include "sdk/CVector.h"
|
||||||
|
|
||||||
|
struct j_info
|
||||||
|
{
|
||||||
|
int id;
|
||||||
|
Vault *vault;
|
||||||
|
};
|
||||||
|
|
||||||
|
Journal::Journal(const char *file)
|
||||||
|
{
|
||||||
|
m_File.assign(file);
|
||||||
|
m_Fp = NULL;
|
||||||
|
m_LastId = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define rd(v,s) if (fread(&v, sizeof(s), 1, m_Fp) != 1) { \
|
||||||
|
fclose(m_Fp); \
|
||||||
|
m_Fp = NULL; \
|
||||||
|
goto _error; }
|
||||||
|
#define rds(v,l) if (fread(v, sizeof(char), l, m_Fp) != l) { \
|
||||||
|
fclose(m_Fp); \
|
||||||
|
m_Fp = NULL; \
|
||||||
|
goto _error; } else { \
|
||||||
|
v[l] = '\0'; }
|
||||||
|
|
||||||
|
bool Journal::Replay(size_t &files, size_t &ops)
|
||||||
|
{
|
||||||
|
m_Fp = fopen(m_File.c_str(), "rb");
|
||||||
|
|
||||||
|
files = 0;
|
||||||
|
ops = 0;
|
||||||
|
|
||||||
|
if (!m_Fp)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
//this must come before the first jump...
|
||||||
|
CVector<j_info *> table;
|
||||||
|
uint32_t magic;
|
||||||
|
|
||||||
|
rd(magic, uint32_t);
|
||||||
|
if (magic != JOURNAL_MAGIC)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
j_info *j;
|
||||||
|
uint8_t op, klen;
|
||||||
|
uint16_t vlen;
|
||||||
|
uint32_t id;
|
||||||
|
size_t i;
|
||||||
|
char *key=NULL, *val=NULL;
|
||||||
|
while (!feof(m_Fp))
|
||||||
|
{
|
||||||
|
if (fread(&op, sizeof(uint8_t), 1, m_Fp) != 1)
|
||||||
|
{
|
||||||
|
if (feof(m_Fp))
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
goto _error;
|
||||||
|
}
|
||||||
|
switch (op)
|
||||||
|
{
|
||||||
|
case Journal_Nop:
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Journal_Name:
|
||||||
|
{
|
||||||
|
rd(id, uint32_t);
|
||||||
|
rd(klen, uint8_t);
|
||||||
|
key = new char[klen+1];
|
||||||
|
rds(key, klen);
|
||||||
|
j = new j_info;
|
||||||
|
j->id = id;
|
||||||
|
j->vault = new Vault(key);
|
||||||
|
j->vault->ReadFromFile();
|
||||||
|
table.push_back(j);
|
||||||
|
files++;
|
||||||
|
delete [] key;
|
||||||
|
key = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Journal_Store:
|
||||||
|
{
|
||||||
|
//Stores key/val (id,time,klen,vlen,[],[])
|
||||||
|
uint32_t stamp;
|
||||||
|
rd(id, uint32_t);
|
||||||
|
rd(stamp, uint32_t);
|
||||||
|
rd(klen, uint8_t);
|
||||||
|
rd(vlen, uint16_t);
|
||||||
|
key = new char[klen+1];
|
||||||
|
val = new char[vlen+1];
|
||||||
|
rds(key, klen);
|
||||||
|
rds(val, vlen);
|
||||||
|
for (i=0; i<table.size(); i++)
|
||||||
|
{
|
||||||
|
if (table.at(i)->id == id)
|
||||||
|
{
|
||||||
|
table.at(i)->vault->Store(key, val, (time_t)stamp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete [] key;
|
||||||
|
delete [] val;
|
||||||
|
key = NULL;
|
||||||
|
val = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Journal_Erase:
|
||||||
|
{
|
||||||
|
//Erases key (id,klen,[])
|
||||||
|
rd(id, uint32_t);
|
||||||
|
rd(klen, uint8_t);
|
||||||
|
key = new char[klen+1];
|
||||||
|
rds(key, klen);
|
||||||
|
for (i=0; i<table.size(); i++)
|
||||||
|
{
|
||||||
|
if (table.at(i)->id == id)
|
||||||
|
{
|
||||||
|
table.at(i)->vault->EraseKey(key);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete [] key;
|
||||||
|
key = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Journal_Clear:
|
||||||
|
{
|
||||||
|
//Clears (id)
|
||||||
|
rd(id, uint32_t);
|
||||||
|
for (i=0; i<table.size(); i++)
|
||||||
|
{
|
||||||
|
if (table.at(i)->id == id)
|
||||||
|
{
|
||||||
|
table.at(i)->vault->Clear();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Journal_Prune:
|
||||||
|
{
|
||||||
|
//Prunes (id,t1,t2,all)
|
||||||
|
rd(id, uint32_t);
|
||||||
|
uint32_t begin, end;
|
||||||
|
uint8_t all;
|
||||||
|
rd(begin, uint32_t);
|
||||||
|
rd(end, uint32_t);
|
||||||
|
rd(all, uint8_t);
|
||||||
|
for (i=0; i<table.size(); i++)
|
||||||
|
{
|
||||||
|
if (table.at(i)->id == id)
|
||||||
|
{
|
||||||
|
table.at(i)->vault->Prune((time_t)begin, (time_t)end, all?true:false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
goto _error;
|
||||||
|
}
|
||||||
|
} //end while
|
||||||
|
ops++;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32_t i=0; i<table.size(); i++)
|
||||||
|
{
|
||||||
|
j = table.at(i);
|
||||||
|
j->vault->WriteToFile();
|
||||||
|
delete j->vault;
|
||||||
|
delete j;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(m_Fp);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
_error:
|
||||||
|
for (uint32_t i=0; i<table.size(); i++)
|
||||||
|
{
|
||||||
|
j = table.at(i);
|
||||||
|
j->vault->WriteToFile();
|
||||||
|
delete j->vault;
|
||||||
|
delete j;
|
||||||
|
}
|
||||||
|
if (key)
|
||||||
|
{
|
||||||
|
delete [] key;
|
||||||
|
key = NULL;
|
||||||
|
}
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
delete [] val;
|
||||||
|
val = NULL;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Journal::ClearJournal()
|
||||||
|
{
|
||||||
|
m_Fp = fopen(m_File.c_str(), "wb");
|
||||||
|
|
||||||
|
if (m_Fp)
|
||||||
|
{
|
||||||
|
fclose(m_Fp);
|
||||||
|
m_Fp = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Journal::StartJournal()
|
||||||
|
{
|
||||||
|
m_Fp = fopen(m_File.c_str(), "wb");
|
||||||
|
|
||||||
|
if (!m_Fp)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
uint32_t magic = JOURNAL_MAGIC;
|
||||||
|
|
||||||
|
fwrite(&magic, sizeof(uint32_t), 1, m_Fp);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Journal::EndJournal()
|
||||||
|
{
|
||||||
|
if (m_Fp)
|
||||||
|
{
|
||||||
|
fclose(m_Fp);
|
||||||
|
m_Fp = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Stores key/val (id,time,klen,vlen,[],[]
|
||||||
|
void Journal::Store(const char *name, const char *key, const char *val, time_t stamp)
|
||||||
|
{
|
||||||
|
uint32_t time32 = (uint32_t)stamp;
|
||||||
|
uint16_t vlen = (uint16_t)strlen(val);
|
||||||
|
uint8_t klen = (uint8_t)strlen(key);
|
||||||
|
|
||||||
|
BeginOp(name, Journal_Store);
|
||||||
|
WriteInt(time32);
|
||||||
|
WriteByte(klen);
|
||||||
|
WriteShort(vlen);
|
||||||
|
WriteString(key);
|
||||||
|
WriteString(val);
|
||||||
|
EndOp();
|
||||||
|
}
|
||||||
|
|
||||||
|
//Erases key (id,klen,[])
|
||||||
|
void Journal::Erase(const char *name, const char *key)
|
||||||
|
{
|
||||||
|
uint8_t klen = (uint8_t)strlen(key);
|
||||||
|
|
||||||
|
BeginOp(name, Journal_Erase);
|
||||||
|
WriteByte(klen);
|
||||||
|
WriteString(key);
|
||||||
|
EndOp();
|
||||||
|
}
|
||||||
|
|
||||||
|
//Clears (id)
|
||||||
|
void Journal::Clear(const char *name)
|
||||||
|
{
|
||||||
|
BeginOp(name, Journal_Clear);
|
||||||
|
EndOp();
|
||||||
|
}
|
||||||
|
|
||||||
|
//Prunes (id,t1,t2,all)
|
||||||
|
void Journal::Prune(const char *name, time_t begin, time_t end, bool all)
|
||||||
|
{
|
||||||
|
uint32_t begin32 = (uint32_t)begin;
|
||||||
|
uint32_t end32 = (uint32_t)end;
|
||||||
|
uint8_t all8 = (uint8_t)all;
|
||||||
|
|
||||||
|
BeginOp(name, Journal_Prune);
|
||||||
|
WriteInt(begin32);
|
||||||
|
WriteInt(end32);
|
||||||
|
WriteByte(all8);
|
||||||
|
EndOp();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Journal::BeginOp(const char *name, JournalOp jop)
|
||||||
|
{
|
||||||
|
uint32_t id;
|
||||||
|
|
||||||
|
if (!m_Names.KeyExists(name))
|
||||||
|
{
|
||||||
|
char name_buf[12];
|
||||||
|
id = ++m_LastId;
|
||||||
|
sprintf(name_buf, "%d", id);
|
||||||
|
m_Names.Store(name, name_buf, false);
|
||||||
|
WriteByte(Journal_Name);
|
||||||
|
WriteInt(id);
|
||||||
|
WriteByte(strlen(name));
|
||||||
|
WriteString(name);
|
||||||
|
} else {
|
||||||
|
id = atoi(m_Names.Retrieve(name)->val.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
WriteByte(jop);
|
||||||
|
WriteInt(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Journal::WriteByte(uint8_t num)
|
||||||
|
{
|
||||||
|
fwrite(&num, sizeof(uint8_t), 1, m_Fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Journal::WriteShort(uint16_t num)
|
||||||
|
{
|
||||||
|
fwrite(&num, sizeof(uint16_t), 1, m_Fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Journal::WriteInt(uint32_t num)
|
||||||
|
{
|
||||||
|
fwrite(&num, sizeof(uint32_t), 1, m_Fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Journal::WriteString(const char *str)
|
||||||
|
{
|
||||||
|
fwrite(str, sizeof(char), strlen(str), m_Fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Journal::EndOp()
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
46
dlls/nvault/journal.h
Executable file
46
dlls/nvault/journal.h
Executable file
@ -0,0 +1,46 @@
|
|||||||
|
#ifndef _INCLUDE_JOURNAL_H
|
||||||
|
#define _INCLUDE_JOURNAL_H
|
||||||
|
|
||||||
|
#include "nvault.h"
|
||||||
|
|
||||||
|
#define JOURNAL_MAGIC 0x6E564A4C
|
||||||
|
|
||||||
|
class Journal
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum JournalOp
|
||||||
|
{
|
||||||
|
Journal_Nop, //Nothing
|
||||||
|
Journal_Name, //Maps name to Id (id,len,[])
|
||||||
|
Journal_Store, //Stores key/val (id,time,klen,vlen,[],[])
|
||||||
|
Journal_Erase, //Erases key (id,klen,[])
|
||||||
|
Journal_Clear, //Clears (id)
|
||||||
|
Journal_Prune //Prunes (id,t1,t2,all)
|
||||||
|
};
|
||||||
|
public:
|
||||||
|
Journal(const char *file);
|
||||||
|
public:
|
||||||
|
bool Replay(size_t &files, size_t &ops);
|
||||||
|
void ClearJournal();
|
||||||
|
bool StartJournal();
|
||||||
|
void EndJournal();
|
||||||
|
public:
|
||||||
|
void Store(const char *name, const char *key, const char *val, time_t stamp);
|
||||||
|
void Erase(const char *name, const char *key);
|
||||||
|
void Clear(const char *name);
|
||||||
|
void Prune(const char *name, time_t begin, time_t end, bool all);
|
||||||
|
private:
|
||||||
|
void BeginOp(const char *name, JournalOp jop);
|
||||||
|
void WriteByte(uint8_t num);
|
||||||
|
void WriteShort(uint16_t num);
|
||||||
|
void WriteInt(uint32_t num);
|
||||||
|
void WriteString(const char *str);
|
||||||
|
size_t EndOp();
|
||||||
|
private:
|
||||||
|
String m_File;
|
||||||
|
FILE *m_Fp;
|
||||||
|
HashTable m_Names;
|
||||||
|
uint32_t m_LastId;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //_INCLUDE_JOURNAL_H
|
@ -1,2 +1,206 @@
|
|||||||
#include "nvault.h"
|
#include "nvault.h"
|
||||||
|
|
||||||
|
Vault::Vault(const char *name)
|
||||||
|
{
|
||||||
|
m_File.assign(name);
|
||||||
|
m_Vault = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vault::~Vault()
|
||||||
|
{
|
||||||
|
if (m_Vault)
|
||||||
|
{
|
||||||
|
delete m_Vault;
|
||||||
|
m_Vault = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Vault::Clear()
|
||||||
|
{
|
||||||
|
if (m_Vault)
|
||||||
|
m_Vault->Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Vault::EraseKey(const char *key)
|
||||||
|
{
|
||||||
|
if (m_Vault)
|
||||||
|
m_Vault->EraseKey(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
HashTable::htNode *Vault::Find(const char *key)
|
||||||
|
{
|
||||||
|
if (m_Vault)
|
||||||
|
return m_Vault->Retrieve(key);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Vault::KeyExists(const char *key)
|
||||||
|
{
|
||||||
|
if (m_Vault)
|
||||||
|
return m_Vault->KeyExists(key);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Vault::Prune(time_t begin, time_t end, bool all)
|
||||||
|
{
|
||||||
|
if (m_Vault)
|
||||||
|
return m_Vault->Prune(begin, end, all);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Vault::Store(const char *key, const char *value, bool temporary)
|
||||||
|
{
|
||||||
|
if (m_Vault)
|
||||||
|
m_Vault->Store(key, value, temporary);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Vault::Store(const char *key, const char *value, time_t stamp)
|
||||||
|
{
|
||||||
|
if (m_Vault)
|
||||||
|
m_Vault->Store(key, value, stamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define wr(v,s) fwrite(&v, sizeof(s), 1, fp)
|
||||||
|
|
||||||
|
bool Vault::WriteToFile()
|
||||||
|
{
|
||||||
|
FILE *fp = fopen(m_File.c_str(), "wb");
|
||||||
|
|
||||||
|
if (!fp)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
uint32_t hashes = m_Vault->UsedHashes();
|
||||||
|
|
||||||
|
_WriteHeaders(fp, hashes);
|
||||||
|
|
||||||
|
HashTable::htNode *node;
|
||||||
|
uint32_t keys, stamp;
|
||||||
|
uint16_t vChars;
|
||||||
|
uint8_t kChars;
|
||||||
|
for (uint32_t i=0; i<HT_SIZE; i++)
|
||||||
|
{
|
||||||
|
if (m_Vault->m_Table[i])
|
||||||
|
{
|
||||||
|
keys = 0;
|
||||||
|
node = m_Vault->m_Table[i]->head;;
|
||||||
|
while (node != NULL)
|
||||||
|
{
|
||||||
|
keys++;
|
||||||
|
node = node->next;
|
||||||
|
}
|
||||||
|
wr(i, uint32_t);
|
||||||
|
wr(keys, uint32_t);
|
||||||
|
node = m_Vault->m_Table[i]->head;
|
||||||
|
while (node != NULL)
|
||||||
|
{
|
||||||
|
stamp = (uint32_t)(node->stamp);
|
||||||
|
wr(stamp, uint32_t);
|
||||||
|
kChars = (uint8_t)(node->key.size());
|
||||||
|
vChars = (uint16_t)(node->val.size());
|
||||||
|
wr(kChars, uint8_t);
|
||||||
|
wr(vChars, uint16_t);
|
||||||
|
fwrite(node->key.c_str(), sizeof(char), kChars, fp);
|
||||||
|
fwrite(node->val.c_str(), sizeof(char), vChars, fp);
|
||||||
|
node = node->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define rd(v,s) if (fread(&v, sizeof(s), 1, fp) != 1) { \
|
||||||
|
fclose(fp); \
|
||||||
|
return Vault_ReadFail; }
|
||||||
|
|
||||||
|
Vault::VaultError Vault::ReadFromFile()
|
||||||
|
{
|
||||||
|
FILE *fp = fopen(m_File.c_str(), "rb");
|
||||||
|
|
||||||
|
if (!fp)
|
||||||
|
{
|
||||||
|
fp = fopen(m_File.c_str(), "wb");
|
||||||
|
if (!fp)
|
||||||
|
return Vault_ReadFail;
|
||||||
|
_WriteHeaders(fp, 0);
|
||||||
|
fclose(fp);
|
||||||
|
m_Vault = new HashTable();
|
||||||
|
return Vault_Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t magic, keysize, hashes;
|
||||||
|
uint8_t timesize;
|
||||||
|
|
||||||
|
rd(magic, uint32_t);
|
||||||
|
if (magic != VAULT_MAGIC)
|
||||||
|
{
|
||||||
|
fclose(fp);
|
||||||
|
return Vault_BadMagic;
|
||||||
|
}
|
||||||
|
rd(timesize, uint8_t);
|
||||||
|
rd(keysize, uint32_t);
|
||||||
|
rd(hashes, uint32_t);
|
||||||
|
|
||||||
|
m_Vault = new HashTable();
|
||||||
|
|
||||||
|
uint32_t hash, keys, stamp;
|
||||||
|
uint16_t vChars;
|
||||||
|
uint8_t kChars;
|
||||||
|
char *key, *value;
|
||||||
|
for (uint32_t i=0; i<hashes; i++)
|
||||||
|
{
|
||||||
|
rd(hash, uint32_t);
|
||||||
|
rd(keys, uint32_t);
|
||||||
|
for (uint32_t d=0; d<keys; d++)
|
||||||
|
{
|
||||||
|
rd(stamp, uint32_t);
|
||||||
|
rd(kChars, uint8_t);
|
||||||
|
rd(vChars, uint16_t);
|
||||||
|
key = new char[kChars+1];
|
||||||
|
if (fread(key, sizeof(char), kChars, fp) != kChars)
|
||||||
|
{
|
||||||
|
delete [] key;
|
||||||
|
fclose(fp);
|
||||||
|
return Vault_ReadFail;
|
||||||
|
}
|
||||||
|
value = new char[vChars+1];
|
||||||
|
if (fread(value, sizeof(char), vChars, fp) != vChars)
|
||||||
|
{
|
||||||
|
delete [] key;
|
||||||
|
delete [] value;
|
||||||
|
return Vault_ReadFail;
|
||||||
|
}
|
||||||
|
key[kChars] = '\0';
|
||||||
|
value[vChars] = '\0';
|
||||||
|
m_Vault->Store(key, value, (time_t)stamp);
|
||||||
|
delete [] key;
|
||||||
|
delete [] value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
return Vault_Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////
|
||||||
|
// Private stuff //
|
||||||
|
///////////////////
|
||||||
|
|
||||||
|
void Vault::_WriteHeaders(FILE *fp, uint32_t keys)
|
||||||
|
{
|
||||||
|
uint32_t magic = VAULT_MAGIC;
|
||||||
|
uint32_t keysize = (1<<11);
|
||||||
|
uint8_t timesize = sizeof(time_t);
|
||||||
|
|
||||||
|
fwrite(&magic, sizeof(uint32_t), 1, fp);
|
||||||
|
fwrite(×ize, sizeof(uint8_t), 1, fp);
|
||||||
|
fwrite(&keysize, sizeof(uint32_t), 1, fp);
|
||||||
|
fwrite(&keys, sizeof(uint32_t), 1, fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -4,47 +4,50 @@
|
|||||||
#include "sdk/CString.h"
|
#include "sdk/CString.h"
|
||||||
#include "hash.h"
|
#include "hash.h"
|
||||||
|
|
||||||
class Journal
|
/**
|
||||||
|
* Vault file format:
|
||||||
|
* Headers
|
||||||
|
* uint32_t - nVLT
|
||||||
|
* uint8_t - sizeof(time_t)
|
||||||
|
* uint32_t - key size (will be used in future maybe)
|
||||||
|
* uint32_t - number of hashes stored
|
||||||
|
* Data
|
||||||
|
* uint32_t - key hash
|
||||||
|
* uint32_t - # of keys in this hash
|
||||||
|
* Data
|
||||||
|
* uint32_t - Time
|
||||||
|
* uint8_t - Characters in key
|
||||||
|
* uint16_t - Characters in value
|
||||||
|
* char[] - Key
|
||||||
|
* char[] - Value
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define VAULT_MAGIC 0x6E564C54
|
||||||
|
|
||||||
|
class Vault
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum JournalOp
|
Vault(const char *name);
|
||||||
|
~Vault();
|
||||||
|
enum VaultError
|
||||||
{
|
{
|
||||||
Journal_Store,
|
Vault_Ok=0,
|
||||||
Journal_Erase,
|
Vault_ReadFail,
|
||||||
Journal_Clear,
|
Vault_BadMagic,
|
||||||
Journal_Prune
|
|
||||||
};
|
};
|
||||||
public:
|
|
||||||
Journal(const char *file);
|
|
||||||
public:
|
|
||||||
bool Replay(size_t &files, size_t &ops);
|
|
||||||
void Clear();
|
|
||||||
public:
|
|
||||||
void Begin(const char *name, JournalOp jop);
|
|
||||||
void WriteByte(uint8_t num);
|
|
||||||
void WriteInt(uint32_t num);
|
|
||||||
void WriteTime(time_t n);
|
|
||||||
void WriteString(const char *str);
|
|
||||||
size_t End();
|
|
||||||
private:
|
|
||||||
String m_File;
|
|
||||||
FILE *m_Fp;
|
|
||||||
size_t m_WriteSize;
|
|
||||||
};
|
|
||||||
|
|
||||||
class nVault
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
nVault(const char *name);
|
|
||||||
public:
|
public:
|
||||||
bool WriteToFile();
|
bool WriteToFile();
|
||||||
bool ReadFromFile();
|
VaultError ReadFromFile();
|
||||||
public:
|
public:
|
||||||
void Store(const char *key, const char *value, bool temporary=true);
|
void Store(const char *key, const char *value, bool temporary=true);
|
||||||
|
void Store(const char *key, const char *value, time_t stamp);
|
||||||
size_t Prune(time_t begin, time_t end, bool all=false);
|
size_t Prune(time_t begin, time_t end, bool all=false);
|
||||||
HashTable::htNode *Find(const char *key);
|
HashTable::htNode *Find(const char *key);
|
||||||
bool KeyExists(const char *key);
|
bool KeyExists(const char *key);
|
||||||
void Clear();
|
void Clear();
|
||||||
|
void EraseKey(const char *key);
|
||||||
|
private:
|
||||||
|
void _WriteHeaders(FILE *fp, uint32_t hashes);
|
||||||
private:
|
private:
|
||||||
String m_File;
|
String m_File;
|
||||||
HashTable *m_Vault;
|
HashTable *m_Vault;
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
MinimalRebuild="TRUE"
|
MinimalRebuild="TRUE"
|
||||||
BasicRuntimeChecks="3"
|
BasicRuntimeChecks="3"
|
||||||
RuntimeLibrary="1"
|
RuntimeLibrary="1"
|
||||||
UsePrecompiledHeader="3"
|
UsePrecompiledHeader="0"
|
||||||
WarningLevel="3"
|
WarningLevel="3"
|
||||||
Detect64BitPortabilityProblems="TRUE"
|
Detect64BitPortabilityProblems="TRUE"
|
||||||
DebugInformationFormat="4"/>
|
DebugInformationFormat="4"/>
|
||||||
@ -117,9 +117,24 @@
|
|||||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
|
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
|
||||||
<File
|
<File
|
||||||
RelativePath=".\hash.cpp">
|
RelativePath=".\hash.cpp">
|
||||||
|
<FileConfiguration
|
||||||
|
Name="Debug|Win32">
|
||||||
|
<Tool
|
||||||
|
Name="VCCLCompilerTool"
|
||||||
|
UsePrecompiledHeader="0"/>
|
||||||
|
</FileConfiguration>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\journal.cpp">
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\nvault.cpp">
|
RelativePath=".\nvault.cpp">
|
||||||
|
<FileConfiguration
|
||||||
|
Name="Debug|Win32">
|
||||||
|
<Tool
|
||||||
|
Name="VCCLCompilerTool"
|
||||||
|
Detect64BitPortabilityProblems="FALSE"/>
|
||||||
|
</FileConfiguration>
|
||||||
</File>
|
</File>
|
||||||
</Filter>
|
</Filter>
|
||||||
<Filter
|
<Filter
|
||||||
@ -129,6 +144,9 @@
|
|||||||
<File
|
<File
|
||||||
RelativePath=".\hash.h">
|
RelativePath=".\hash.h">
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\journal.h">
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\nvault.h">
|
RelativePath=".\nvault.h">
|
||||||
</File>
|
</File>
|
||||||
|
444
dlls/nvault/sdk/CVector.h
Executable file
444
dlls/nvault/sdk/CVector.h
Executable file
@ -0,0 +1,444 @@
|
|||||||
|
/* AMX Mod X
|
||||||
|
*
|
||||||
|
* by the AMX Mod X Development Team
|
||||||
|
* originally developed by OLO
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* 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; either version 2 of the License, or (at
|
||||||
|
* your option) any later version.
|
||||||
|
*
|
||||||
|
* 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 for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
* In addition, as a special exception, the author gives permission to
|
||||||
|
* link the code of this program with the Half-Life Game Engine ("HL
|
||||||
|
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||||||
|
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||||||
|
* respects for all of the code used other than the HL Engine and MODs
|
||||||
|
* from Valve. If you modify this file, you may extend this exception
|
||||||
|
* to your version of the file, but you are not obligated to do so. If
|
||||||
|
* you do not wish to do so, delete this exception statement from your
|
||||||
|
* version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __CVECTOR_H__
|
||||||
|
#define __CVECTOR_H__
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
// Vector
|
||||||
|
template <class T> class CVector
|
||||||
|
{
|
||||||
|
bool Grow()
|
||||||
|
{
|
||||||
|
// automatic grow
|
||||||
|
size_t newSize = m_Size * 2;
|
||||||
|
if (newSize == 0)
|
||||||
|
newSize = 8; // a good init value
|
||||||
|
T *newData = new T[newSize];
|
||||||
|
if (!newData)
|
||||||
|
return false;
|
||||||
|
if (m_Data)
|
||||||
|
{
|
||||||
|
memcpy(newData, m_Data, m_Size * sizeof(T));
|
||||||
|
delete [] m_Data;
|
||||||
|
}
|
||||||
|
m_Data = newData;
|
||||||
|
m_Size = newSize;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GrowIfNeeded()
|
||||||
|
{
|
||||||
|
if (m_CurrentUsedSize >= m_Size)
|
||||||
|
return Grow();
|
||||||
|
else
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ChangeSize(size_t size)
|
||||||
|
{
|
||||||
|
// change size
|
||||||
|
if (size == m_Size)
|
||||||
|
return true;
|
||||||
|
T *newData = new T[size];
|
||||||
|
if (!newData)
|
||||||
|
return false;
|
||||||
|
if (m_Data)
|
||||||
|
{
|
||||||
|
memcpy(newData, m_Data, (m_Size < size) ? (m_Size * sizeof(T)) : (size * sizeof(T)));
|
||||||
|
delete [] m_Data;
|
||||||
|
}
|
||||||
|
if (m_Size < size)
|
||||||
|
m_CurrentSize = size;
|
||||||
|
m_Data = newData;
|
||||||
|
m_Size = size;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FreeMemIfPossible()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
protected:
|
||||||
|
T *m_Data;
|
||||||
|
size_t m_Size;
|
||||||
|
size_t m_CurrentUsedSize;
|
||||||
|
size_t m_CurrentSize;
|
||||||
|
public:
|
||||||
|
class iterator
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
T *m_Ptr;
|
||||||
|
public:
|
||||||
|
// constructors / destructors
|
||||||
|
iterator()
|
||||||
|
{
|
||||||
|
m_Ptr = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator(T * ptr)
|
||||||
|
{
|
||||||
|
m_Ptr = ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// member functions
|
||||||
|
T * base()
|
||||||
|
{
|
||||||
|
return m_Ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const T * base() const
|
||||||
|
{
|
||||||
|
return m_Ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// operators
|
||||||
|
T & operator*()
|
||||||
|
{
|
||||||
|
return *m_Ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
T * operator->()
|
||||||
|
{
|
||||||
|
return m_Ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator & operator++() // preincrement
|
||||||
|
{
|
||||||
|
++m_Ptr;
|
||||||
|
return (*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator operator++(int) // postincrement
|
||||||
|
{
|
||||||
|
iterator tmp = *this;
|
||||||
|
++m_Ptr;
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator & operator--() // predecrement
|
||||||
|
{
|
||||||
|
--m_Ptr;
|
||||||
|
return (*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator operator--(int) // postdecrememnt
|
||||||
|
{
|
||||||
|
iterator tmp = *this;
|
||||||
|
--m_Ptr;
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(T * right) const
|
||||||
|
{
|
||||||
|
return (m_Ptr == right);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const iterator & right) const
|
||||||
|
{
|
||||||
|
return (m_Ptr == right.m_Ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(T * right) const
|
||||||
|
{
|
||||||
|
return (m_Ptr != right);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const iterator & right) const
|
||||||
|
{
|
||||||
|
return (m_Ptr != right.m_Ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator & operator+=(size_t offset)
|
||||||
|
{
|
||||||
|
m_Ptr += offset;
|
||||||
|
return (*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator & operator-=(size_t offset)
|
||||||
|
{
|
||||||
|
m_Ptr += offset;
|
||||||
|
return (*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator operator+(size_t offset) const
|
||||||
|
{
|
||||||
|
iterator tmp(*this);
|
||||||
|
tmp.m_Ptr += offset;
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator operator-(size_t offset) const
|
||||||
|
{
|
||||||
|
iterator tmp(*this);
|
||||||
|
tmp.m_Ptr += offset;
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
T & operator[](size_t offset)
|
||||||
|
{
|
||||||
|
return (*(*this + offset));
|
||||||
|
}
|
||||||
|
|
||||||
|
const T & operator[](size_t offset) const
|
||||||
|
{
|
||||||
|
return (*(*this + offset));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator<(const iterator & right) const
|
||||||
|
{
|
||||||
|
return m_Ptr < right.m_Ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator>(const iterator & right) const
|
||||||
|
{
|
||||||
|
return m_Ptr > right.m_Ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator<=(const iterator & right) const
|
||||||
|
{
|
||||||
|
return m_Ptr <= right.m_Ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator>=(const iterator & right) const
|
||||||
|
{
|
||||||
|
return m_Ptr >= right.m_Ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t operator-(const iterator & right) const
|
||||||
|
{
|
||||||
|
return m_Ptr - right.m_Ptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// constructors / destructors
|
||||||
|
CVector<T>()
|
||||||
|
{
|
||||||
|
m_Size = 0;
|
||||||
|
m_CurrentUsedSize = 0;
|
||||||
|
m_Data = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
CVector<T>(const CVector<T> & other)
|
||||||
|
{
|
||||||
|
// copy data
|
||||||
|
m_Data = new T [other.m_Size];
|
||||||
|
m_Size = other.m_Size;
|
||||||
|
m_CurrentUsedSize = other.m_CurrentUsedSize;
|
||||||
|
memcpy(m_Data, other.m_Data, m_CurrentUsedSize * sizeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
~CVector<T>()
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// interface
|
||||||
|
size_t size() const
|
||||||
|
{
|
||||||
|
return m_CurrentUsedSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t capacity() const
|
||||||
|
{
|
||||||
|
return m_Size;
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator begin()
|
||||||
|
{
|
||||||
|
return iterator(m_Data);
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator end()
|
||||||
|
{
|
||||||
|
return iterator(m_Data + m_CurrentUsedSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator iterAt(size_t pos)
|
||||||
|
{
|
||||||
|
if (pos > m_CurrentUsedSize)
|
||||||
|
assert(0);
|
||||||
|
return iterator(m_Data + pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool reserve(size_t newSize)
|
||||||
|
{
|
||||||
|
return ChangeSize(newSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool push_back(const T & elem)
|
||||||
|
{
|
||||||
|
++m_CurrentUsedSize;
|
||||||
|
if (!GrowIfNeeded())
|
||||||
|
{
|
||||||
|
--m_CurrentUsedSize;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_Data[m_CurrentUsedSize - 1] = elem;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pop_back()
|
||||||
|
{
|
||||||
|
--m_CurrentUsedSize;
|
||||||
|
if (m_CurrentUsedSize < 0)
|
||||||
|
m_CurrentUsedSize = 0;
|
||||||
|
// :TODO: free memory sometimes
|
||||||
|
}
|
||||||
|
|
||||||
|
bool resize(size_t newSize)
|
||||||
|
{
|
||||||
|
if (!ChangeSize(newSize))
|
||||||
|
return false;
|
||||||
|
FreeMemIfPossible();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool empty() const
|
||||||
|
{
|
||||||
|
return (m_CurrentUsedSize == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
T & at(size_t pos)
|
||||||
|
{
|
||||||
|
if (pos > m_CurrentUsedSize)
|
||||||
|
{
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
return m_Data[pos];
|
||||||
|
}
|
||||||
|
|
||||||
|
const T & at(size_t pos) const
|
||||||
|
{
|
||||||
|
if (pos > m_CurrentUsedSize)
|
||||||
|
{
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
return m_Data[pos];
|
||||||
|
}
|
||||||
|
|
||||||
|
T & operator[](size_t pos)
|
||||||
|
{
|
||||||
|
return at(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
const T & operator[](size_t pos) const
|
||||||
|
{
|
||||||
|
return at(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
T & front()
|
||||||
|
{
|
||||||
|
if (m_CurrentUsedSize < 1)
|
||||||
|
{
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
return m_Data[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
const T & front() const
|
||||||
|
{
|
||||||
|
if (m_CurrentUsedSize < 1)
|
||||||
|
{
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
return m_Data[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
T & back()
|
||||||
|
{
|
||||||
|
if (m_CurrentUsedSize < 1)
|
||||||
|
{
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
return m_Data[m_CurrentUsedSize - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
const T & back() const
|
||||||
|
{
|
||||||
|
if (m_CurrentUsedSize < 1)
|
||||||
|
{
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
return m_Data[m_CurrentUsedSize - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool insert(iterator where, const T & value)
|
||||||
|
{
|
||||||
|
// we have to insert before
|
||||||
|
// if it is begin, don't decrement
|
||||||
|
if (where != m_Data)
|
||||||
|
--where;
|
||||||
|
// validate iter
|
||||||
|
if (where < m_Data || where >= (m_Data + m_CurrentUsedSize))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
++m_CurrentUsedSize;
|
||||||
|
if (!GrowIfNeeded())
|
||||||
|
{
|
||||||
|
--m_CurrentUsedSize;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
memmove(where.base() + 1, where.base(), m_CurrentUsedSize - (where - m_Data));
|
||||||
|
memcpy(where.base(), &value, sizeof(T));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void erase(iterator where)
|
||||||
|
{
|
||||||
|
// validate iter
|
||||||
|
if (where < m_Data || where >= (m_Data + m_CurrentUsedSize))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (m_CurrentUsedSize > 1)
|
||||||
|
{
|
||||||
|
// move
|
||||||
|
memmove(where.base(), where.base() + 1, m_CurrentUsedSize - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
--m_CurrentUsedSize;
|
||||||
|
// :TODO: free memory sometimes
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
m_Size = 0;
|
||||||
|
m_CurrentUsedSize = 0;
|
||||||
|
delete [] m_Data;
|
||||||
|
m_Data = NULL;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // __CVECTOR_H__
|
||||||
|
|
Loading…
Reference in New Issue
Block a user