Refactor DqnVHashTable to be simpler
This commit is contained in:
		
							parent
							
								
									71a1446fe0
								
							
						
					
					
						commit
						34907eeb04
					
				| @ -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
									
									
									
									
									
								
							
							
						
						
									
										182
									
								
								dqn.h
									
									
									
									
									
								
							| @ -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
 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user