Refactor DqnVHashTable to be simpler

This commit is contained in:
Doyle T 2018-07-24 23:05:08 +10:00
parent 71a1446fe0
commit 34907eeb04
2 changed files with 97 additions and 108 deletions

View File

@ -2843,6 +2843,28 @@ FILE_SCOPE void DqnMemStack_Test()
} }
} }
template <typename T>
T *DqnCatalog<T>::Get(DqnFixedString128 file)
{
Entry *result = this->assetTable.GetOrMake(file.str);
(void)result;
return nullptr;
}
void DqnCatalog_Test()
{
struct TxtFile
{
char *buffer;
int len;
};
DqnCatalog<TxtFile> textCatalog = {};
TxtFile *file = textCatalog.Get("makefile");
(void)file;
}
int main(void) int main(void)
{ {
globalIndent = 1; globalIndent = 1;
@ -2863,6 +2885,7 @@ int main(void)
DqnJson_Test(); DqnJson_Test();
#ifdef DQN_PLATFORM_HEADER #ifdef DQN_PLATFORM_HEADER
DqnCatalog_Test();
DqnVHashTable_Test(); DqnVHashTable_Test();
DqnOS_Test(); DqnOS_Test();
DqnFile_Test(); DqnFile_Test();

182
dqn.h
View File

@ -1935,9 +1935,9 @@ DQN_FILE_SCOPE DqnString DqnString_(DqnMemStack *const stack);
// #DqnFixedString Public API - Fixed sized strings at compile time // #DqnFixedString Public API - Fixed sized strings at compile time
// ================================================================================================= // =================================================================================================
FILE_SCOPE int DqnFixedString__Append(char *dest, int destSize, char const *src, int len = -1); FILE_SCOPE int DqnFixedString__Append (char *dest, int destSize, char const *src, int len = -1);
template <unsigned int MAX> template <int MAX>
struct DqnFixedString struct DqnFixedString
{ {
int len; int len;
@ -1955,69 +1955,32 @@ struct DqnFixedString
DqnFixedString &operator+=(DqnSlice<char> const &other) { this->len += DqnFixedString__Append(this->str + this->len, MAX - this->len, other.data, other.len); return *this; } DqnFixedString &operator+=(DqnSlice<char> const &other) { this->len += DqnFixedString__Append(this->str + this->len, MAX - this->len, other.data, other.len); return *this; }
DqnFixedString &operator+=(DqnFixedString const &other) { this->len += DqnFixedString__Append(this->str + this->len, MAX - this->len, other.str, other.len); return *this; } DqnFixedString &operator+=(DqnFixedString const &other) { this->len += DqnFixedString__Append(this->str + this->len, MAX - this->len, other.str, other.len); return *this; }
DqnFixedString operator+ (char const *other) { DqnFixedString result = *this; result.len += DqnFixedString__Append(result.str + result.len, MAX - result.len, other); return result; } DqnFixedString operator+ (char const *other) { auto result = *this; result.len += DqnFixedString__Append(result.str + result.len, MAX - result.len, other); return result; }
DqnFixedString operator+ (DqnSlice<char const> const &other) { DqnFixedString result = *this; result.len += DqnFixedString__Append(result.str + result.len, MAX - result.len, other.data, other.len); return result; } DqnFixedString operator+ (DqnSlice<char const> const &other) { auto result = *this; result.len += DqnFixedString__Append(result.str + result.len, MAX - result.len, other.data, other.len); return result; }
DqnFixedString operator+ (DqnSlice<char> const &other) { DqnFixedString result = *this; result.len += DqnFixedString__Append(result.str + result.len, MAX - result.len, other.data, other.len); return result; } DqnFixedString operator+ (DqnSlice<char> const &other) { auto result = *this; result.len += DqnFixedString__Append(result.str + result.len, MAX - result.len, other.data, other.len); return result; }
DqnFixedString operator+ (DqnFixedString const &other) { DqnFixedString result = *this; result.len += DqnFixedString__Append(result.str + result.len, MAX - result.len, other.str, other.len); return result; } DqnFixedString operator+ (DqnFixedString const &other) { auto result = *this; result.len += DqnFixedString__Append(result.str + result.len, MAX - result.len, other.str, other.len); return result; }
// Xprintf functions always modifies buffer and null-terminates even with insufficient buffer size. // Xprintf functions always modifies buffer and null-terminates even with insufficient buffer size.
// Asserts on failure if DQN_ASSERT is defined. // Asserts on failure if DQN_ASSERT is defined.
// return: The number of characters copied to the buffer // return: The number of characters copied to the buffer
int Sprintf (char const *fmt, ...); int Sprintf (char const *fmt, ...) { va_list va; va_start(va, fmt); int result = VSprintf (fmt, va); va_end(va); return result; }
int SprintfAppend (char const *fmt, ...); int SprintfAppend (char const *fmt, ...) { va_list va; va_start(va, fmt); int result = VSprintfAppend(fmt, va); va_end(va); return result; }
int VSprintf (char const *fmt, va_list argList); int VSprintf (char const *fmt, va_list va) { return VSprintfAtOffset(fmt, va, 0 /*offset*/); }
int VSprintfAppend(char const *fmt, va_list argList); int VSprintfAppend (char const *fmt, va_list va) { return VSprintfAtOffset(fmt, va, len/*offset*/); }
void Clear (Dqn::ZeroClear clear = Dqn::ZeroClear::No) { if (clear == Dqn::ZeroClear::Yes) DqnMem_Set(str, 0, MAX); *this = {}; } void Clear (Dqn::ZeroClear clear = Dqn::ZeroClear::No) { if (clear == Dqn::ZeroClear::Yes) DqnMem_Set(str, 0, MAX); *this = {}; }
int VSprintfAtOffset(char const *fmt, va_list va, int offset) { char *start = str + offset; int result = Dqn_vsnprintf(start, static_cast<int>((str + MAX) - start), fmt, va); len = (offset + result); return result; }
}; };
template <unsigned int MAX> using DqnFixedString16 = DqnFixedString<16>;
DQN_FILE_SCOPE int using DqnFixedString32 = DqnFixedString<32>;
DqnFixedString__VSprintf(DqnFixedString<MAX> *me, char const *fmt, va_list argList, int bufOffset) using DqnFixedString64 = DqnFixedString<64>;
{ using DqnFixedString128 = DqnFixedString<128>;
char *bufStart = me->str + bufOffset; using DqnFixedString256 = DqnFixedString<256>;
i32 const remainingSpace = static_cast<i32>((me->str + MAX) - bufStart); using DqnFixedString512 = DqnFixedString<512>;
int result = Dqn_vsnprintf(bufStart, remainingSpace, fmt, argList); using DqnFixedString1024 = DqnFixedString<1024>;
me->len = bufOffset + result;
return result;
}
template <unsigned int MAX>
int DqnFixedString<MAX>::VSprintf(char const *fmt, va_list argList)
{
int bufOffset = 0;
int result = DqnFixedString__VSprintf(this, fmt, argList, bufOffset);
return result;
}
template <unsigned int MAX>
int DqnFixedString<MAX>::Sprintf(char const *fmt, ...)
{
va_list argList;
va_start(argList, fmt);
int result = this->VSprintf(fmt, argList);
va_end(argList);
return result;
}
template <unsigned int MAX>
int DqnFixedString<MAX>::VSprintfAppend(char const *fmt, va_list argList)
{
int bufOffset = this->len;
int result = DqnFixedString__VSprintf(this, fmt, argList, bufOffset);
return result;
}
template <unsigned int MAX>
int DqnFixedString<MAX>::SprintfAppend(char const *fmt, ...)
{
va_list argList;
va_start(argList, fmt);
int result = this->VSprintfAppend(fmt, argList);
va_end(argList);
return result;
}
// TODO(doyle): Load factor // TODO(doyle): Load factor
// #DqnHashTable API // #DqnHashTable API
@ -2684,16 +2647,19 @@ DQN_VHASH_TABLE_TEMPLATE struct DqnVHashTable
isize *indexesOfUsedBuckets; isize *indexesOfUsedBuckets;
isize indexInIndexesOfUsedBuckets; isize indexInIndexesOfUsedBuckets;
DqnVHashTable() = default; DqnVHashTable () = default;
DqnVHashTable(isize size) { LazyInit(size); } DqnVHashTable (isize size) { LazyInit(size); }
void Free () { if (buckets) DqnOS_VFree(buckets, sizeof(buckets) * numBuckets); *this = {}; } void LazyInit (isize size = DQN_MAX(DQN_MEGABYTE(1)/sizeof(Bucket), 1024) );
void LazyInit(isize size); void Free () { if (buckets) DqnOS_VFree(buckets, sizeof(buckets) * numBuckets); *this = {}; }
void Erase (Key const &key);
Item *Set (Key const &key, Item const &item);
Item *Get (Key const &key);
Item *operator[](Key const &key) { return Get(key); } Entry *GetEntry (Key const &key); // return: The (key, item) entry associated with the key, nullptr if key not in table yet.
void Erase (Key const &key); // Delete the element matching key, does nothing if key not found.
Item *GetOrMake(Key const &key); // return: Item if found, otherwise make an entry (key, item) and return the ptr to the uninitialised item
Item *Get (Key const &key) { Entry *entry = GetEntry(key); return (entry) ? &entry->item : nullptr; }
Item *Set (Key const &key, Item const &item) { Item *result = GetOrMake(key); *result = item; return result; }
Item *operator[](Key const &key) { return Get(key); }
struct Iterator struct Iterator
{ {
@ -2717,8 +2683,8 @@ DQN_VHASH_TABLE_TEMPLATE struct DqnVHashTable
Iterator operator- (int offset) const { Iterator result = *this; DQN_FOR_EACH(i, offset) { (offset > 0) ? --result : ++result; } return result; } // TODO(doyle): Improve Iterator operator- (int offset) const { Iterator result = *this; DQN_FOR_EACH(i, offset) { (offset > 0) ? --result : ++result; } return result; } // TODO(doyle): Improve
}; };
Iterator begin() { return Iterator(this); } Iterator begin() { return Iterator(this); }
Iterator end() { isize lastBucketIndex = indexesOfUsedBuckets[indexInIndexesOfUsedBuckets - 1]; isize lastIndexInBucket = (buckets + lastBucketIndex)->entryIndex - 1; return Iterator(this, DQN_MAX(lastBucketIndex, 0), DQN_MAX(lastIndexInBucket, 0)); } Iterator end() { isize lastBucketIndex = indexesOfUsedBuckets[indexInIndexesOfUsedBuckets - 1]; isize lastIndexInBucket = (buckets + lastBucketIndex)->entryIndex - 1; return Iterator(this, DQN_MAX(lastBucketIndex, 0), DQN_MAX(lastIndexInBucket, 0)); }
}; };
DQN_VHASH_TABLE_TEMPLATE void DQN_VHASH_TABLE_DECL::LazyInit(isize size) DQN_VHASH_TABLE_TEMPLATE void DQN_VHASH_TABLE_DECL::LazyInit(isize size)
@ -2730,14 +2696,32 @@ DQN_VHASH_TABLE_TEMPLATE void DQN_VHASH_TABLE_DECL::LazyInit(isize size)
DQN_ASSERT(this->buckets && this->indexesOfUsedBuckets); DQN_ASSERT(this->buckets && this->indexesOfUsedBuckets);
} }
DQN_VHASH_TABLE_TEMPLATE Item *DQN_VHASH_TABLE_DECL::Set(Key const &key, Item const &item) DQN_VHASH_TABLE_TEMPLATE typename DQN_VHASH_TABLE_DECL::Entry *
DQN_VHASH_TABLE_DECL::GetEntry(Key const &key)
{ {
if (!buckets) LazyInit(1024); if (!buckets) return nullptr;
isize index = Hash(this->numBuckets, key); isize index = Hash(this->numBuckets, key);
Bucket *bucket = this->buckets + index; Bucket *bucket = this->buckets + index;
Entry *entry = nullptr;
Entry *result = nullptr;
for (isize i = 0; i < bucket->entryIndex && !result; i++)
{
Entry *entry = bucket->entries + i;
result = Equals(entry->key, key) ? entry : nullptr;
}
return result;
}
DQN_VHASH_TABLE_TEMPLATE Item *DQN_VHASH_TABLE_DECL::GetOrMake(Key const &key)
{
if (!this->buckets) LazyInit();
isize index = Hash(this->numBuckets, key);
Bucket *bucket = this->buckets + index;
Entry *entry = nullptr;
for (isize i = 0; i < bucket->entryIndex && !entry; i++) for (isize i = 0; i < bucket->entryIndex && !entry; i++)
{ {
Entry *check = bucket->entries + i; Entry *check = bucket->entries + i;
@ -2746,51 +2730,32 @@ DQN_VHASH_TABLE_TEMPLATE Item *DQN_VHASH_TABLE_DECL::Set(Key const &key, Item co
if (!entry) if (!entry)
{ {
DQN_ALWAYS_ASSERTM(bucket->entryIndex < DQN_ARRAY_COUNT(bucket->entries), "More than %zu collisions in hash table, increase the size of the table or buckets", DQN_ARRAY_COUNT(bucket->entries)); DQN_ALWAYS_ASSERTM(bucket->entryIndex < DQN_ARRAY_COUNT(bucket->entries),
"More than %zu collisions in hash table, increase the size of the table or buckets",
DQN_ARRAY_COUNT(bucket->entries));
if (bucket->entryIndex == 0) if (bucket->entryIndex == 0)
this->indexesOfUsedBuckets[this->indexInIndexesOfUsedBuckets++] = index; this->indexesOfUsedBuckets[this->indexInIndexesOfUsedBuckets++] = index;
entry = bucket->entries + bucket->entryIndex++; entry = bucket->entries + bucket->entryIndex++;
} entry->key = key;
// TODO(doyle): A maybe case. We're using virtual memory, so you should // TODO(doyle): A maybe case. We're using virtual memory, so you should
// just initialise a larger size. It's essentially free ... maybe one // just initialise a larger size. It's essentially free ... maybe one
// day we care about resizing the table but at the cost of a lot more code // day we care about resizing the table but at the cost of a lot more code
// complexity. // complexity.
isize const threshold = static_cast<isize>(0.75f * this->numBuckets); isize const threshold = static_cast<isize>(0.75f * this->numBuckets);
DQN_ALWAYS_ASSERTM(this->indexInIndexesOfUsedBuckets < threshold, "%zu >= %zu", this->indexInIndexesOfUsedBuckets, threshold); DQN_ALWAYS_ASSERTM(this->indexInIndexesOfUsedBuckets < threshold, "%zu >= %zu", this->indexInIndexesOfUsedBuckets, threshold);
entry->key = key;
entry->item = item;
return &entry->item;
}
DQN_VHASH_TABLE_TEMPLATE Item *DQN_VHASH_TABLE_DECL::Get(Key const &key)
{
Item *result = nullptr;
if (!buckets)
{
return result;
}
isize index = Hash(this->numBuckets, key);
Bucket *bucket = this->buckets + index;
for (isize i = 0; i < bucket->entryIndex && !result; i++)
{
Entry *entry = bucket->entries + i;
result = Equals(entry->key, key) ? &entry->item : nullptr;
} }
Item *result = &entry->item;
return result; return result;
} }
DQN_VHASH_TABLE_TEMPLATE void DQN_VHASH_TABLE_DECL::Erase(Key const &key) DQN_VHASH_TABLE_TEMPLATE void DQN_VHASH_TABLE_DECL::Erase(Key const &key)
{ {
if (!buckets) if (!buckets)
{
return; return;
}
isize index = Hash(this->numBuckets, key); isize index = Hash(this->numBuckets, key);
Bucket *bucket = this->buckets + index; Bucket *bucket = this->buckets + index;
@ -2830,11 +2795,12 @@ struct DqnCatalog
struct Entry struct Entry
{ {
u64 timeLastModified; u64 timeLastModified;
T *data; T data;
}; };
DqnVHashTable<DqnSlice<const char>, T> assetTable; DqnVHashTable<DqnFixedString128, Entry> assetTable;
void Update(); // void Update();
T *Get (DqnFixedString128 file);
}; };
// XPlatform > #DqnFile API // XPlatform > #DqnFile API