Implementation of journaling

This commit is contained in:
David Anderson 2005-04-03 02:01:42 +00:00
parent aa8beace98
commit abbb2f2cc2
8 changed files with 1108 additions and 32 deletions

View File

@ -23,7 +23,7 @@ HashTable::htNode *HashTable::Retrieve(const char *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)
{
time_t stamp = 0;
@ -34,6 +34,22 @@ void HashTable::Store(const char *key, const char *value, bool temporary)
_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.
// 0 specifies "match all"
//All specifies whether permanent keys (time_t = 0) are erased
@ -106,7 +122,20 @@ void HashTable::Clear()
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;
}
////////////////////

View File

@ -34,15 +34,19 @@ public: //STRUCTORS
public: //PRE-DEF
class iterator;
struct htNode;
friend class Vault;
private: //PRE-DEF
struct htNodeSet;
public: //PUBLIC FUNCTIONS
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);
iterator Enumerate();
size_t Prune(time_t begin, time_t end, bool all=false);
void Clear();
bool KeyExists(const char *key);
size_t UsedHashes();
void EraseKey(const char *key);
public: //PUBLIC CLASSES
class iterator
{

328
dlls/nvault/journal.cpp Executable file
View 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
View 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

View File

@ -1,2 +1,206 @@
#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(&timesize, sizeof(uint8_t), 1, fp);
fwrite(&keysize, sizeof(uint32_t), 1, fp);
fwrite(&keys, sizeof(uint32_t), 1, fp);
}

View File

@ -4,47 +4,50 @@
#include "sdk/CString.h"
#include "hash.h"
class Journal
{
public:
enum JournalOp
{
Journal_Store,
Journal_Erase,
Journal_Clear,
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;
};
/**
* 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
*/
class nVault
#define VAULT_MAGIC 0x6E564C54
class Vault
{
public:
nVault(const char *name);
Vault(const char *name);
~Vault();
enum VaultError
{
Vault_Ok=0,
Vault_ReadFail,
Vault_BadMagic,
};
public:
bool WriteToFile();
bool ReadFromFile();
VaultError ReadFromFile();
public:
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);
HashTable::htNode *Find(const char *key);
bool KeyExists(const char *key);
void Clear();
void EraseKey(const char *key);
private:
void _WriteHeaders(FILE *fp, uint32_t hashes);
private:
String m_File;
HashTable *m_Vault;

View File

@ -23,7 +23,7 @@
MinimalRebuild="TRUE"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
UsePrecompiledHeader="3"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="4"/>
@ -117,9 +117,24 @@
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
<File
RelativePath=".\hash.cpp">
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"/>
</FileConfiguration>
</File>
<File
RelativePath=".\journal.cpp">
</File>
<File
RelativePath=".\nvault.cpp">
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCLCompilerTool"
Detect64BitPortabilityProblems="FALSE"/>
</FileConfiguration>
</File>
</Filter>
<Filter
@ -129,6 +144,9 @@
<File
RelativePath=".\hash.h">
</File>
<File
RelativePath=".\journal.h">
</File>
<File
RelativePath=".\nvault.h">
</File>

444
dlls/nvault/sdk/CVector.h Executable file
View 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__