dqn: Allow DSMap to accept arbitrary keys
This commit is contained in:
		
							parent
							
								
									c8b93840c0
								
							
						
					
					
						commit
						84bfc91362
					
				
							
								
								
									
										370
									
								
								dqn.h
									
									
									
									
									
								
							
							
						
						
									
										370
									
								
								dqn.h
									
									
									
									
									
								
							| @ -353,10 +353,12 @@ struct Dqn_String8 ///< Pointer and length style UTF8 strings | |||||||
|     char      *data; ///< The UTF8 bytes of the string
 |     char      *data; ///< The UTF8 bytes of the string
 | ||||||
|     Dqn_isize  size; ///< The number of bytes in the string
 |     Dqn_isize  size; ///< The number of bytes in the string
 | ||||||
| 
 | 
 | ||||||
|  |     #if defined(__cplusplus) | ||||||
|     char const *begin() const { return data; }        ///< Const begin iterator for range-for loops
 |     char const *begin() const { return data; }        ///< Const begin iterator for range-for loops
 | ||||||
|     char const *end  () const { return data + size; } ///< Const end iterator for range-for loops
 |     char const *end  () const { return data + size; } ///< Const end iterator for range-for loops
 | ||||||
|     char       *begin()       { return data; }        ///< Begin iterator for range-for loops
 |     char       *begin()       { return data; }        ///< Begin iterator for range-for loops
 | ||||||
|     char       *end  ()       { return data + size; } ///< End iterator for range-for loops
 |     char       *end  ()       { return data + size; } ///< End iterator for range-for loops
 | ||||||
|  |     #endif | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| // ---------------------------------+-----------------------------+---------------------------------
 | // ---------------------------------+-----------------------------+---------------------------------
 | ||||||
| @ -870,10 +872,10 @@ DQN_API Dqn_isize Dqn_CString8_FVSize(char const *fmt, va_list args); | |||||||
| /// returned if the arguments were invalid.
 | /// returned if the arguments were invalid.
 | ||||||
| DQN_API char const *Dqn_CString8_BinarySplit(char const *string, Dqn_isize string_size, char delimiter, Dqn_isize *lhs_size, char **rhs, Dqn_isize *rhs_size); | DQN_API char const *Dqn_CString8_BinarySplit(char const *string, Dqn_isize string_size, char delimiter, Dqn_isize *lhs_size, char **rhs, Dqn_isize *rhs_size); | ||||||
| 
 | 
 | ||||||
| enum struct Dqn_CString8EqCase | enum Dqn_CString8EqCase | ||||||
| { | { | ||||||
|     Sensitive, |     Dqn_CString8EqCase_Sensitive, | ||||||
|     Insensitive, |     Dqn_CString8EqCase_Insensitive, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /// Compare a string for equality with or without case sensitivity.
 | /// Compare a string for equality with or without case sensitivity.
 | ||||||
| @ -884,7 +886,7 @@ enum struct Dqn_CString8EqCase | |||||||
| /// @param[in] eq_case Set the comparison to be case sensitive or insensitive
 | /// @param[in] eq_case Set the comparison to be case sensitive or insensitive
 | ||||||
| /// @return True if the arguments are valid, non-null and the strings
 | /// @return True if the arguments are valid, non-null and the strings
 | ||||||
| /// are equal, false otherwise.
 | /// are equal, false otherwise.
 | ||||||
| DQN_API bool Dqn_CString8_Eq(char const *lhs, char const *rhs, Dqn_isize lhs_size = -1, Dqn_isize rhs_size = -1, Dqn_CString8EqCase eq_case = Dqn_CString8EqCase::Sensitive); | DQN_API bool Dqn_CString8_Eq(char const *lhs, char const *rhs, Dqn_isize lhs_size = -1, Dqn_isize rhs_size = -1, Dqn_CString8EqCase eq_case = Dqn_CString8EqCase_Sensitive); | ||||||
| 
 | 
 | ||||||
| /// Compare a string for equality, case insensitive
 | /// Compare a string for equality, case insensitive
 | ||||||
| /// @see Dqn_CString8_Eq
 | /// @see Dqn_CString8_Eq
 | ||||||
| @ -898,7 +900,7 @@ DQN_API bool Dqn_CString8_EqInsensitive(char const *lhs, char const *rhs, Dqn_is | |||||||
| /// @param[in] eq_case Set the comparison to be case sensitive or insensitive
 | /// @param[in] eq_case Set the comparison to be case sensitive or insensitive
 | ||||||
| /// @return True if the string is valid, non-null and has the specified prefix,
 | /// @return True if the string is valid, non-null and has the specified prefix,
 | ||||||
| /// false otherwise.
 | /// false otherwise.
 | ||||||
| DQN_API bool Dqn_CString8_StartsWith(char const *string, char const *prefix, Dqn_isize string_size = -1, Dqn_isize prefix_size = -1, Dqn_CString8EqCase eq_case = Dqn_CString8EqCase::Sensitive); | DQN_API bool Dqn_CString8_StartsWith(char const *string, char const *prefix, Dqn_isize string_size = -1, Dqn_isize prefix_size = -1, Dqn_CString8EqCase eq_case = Dqn_CString8EqCase_Sensitive); | ||||||
| 
 | 
 | ||||||
| /// Check if a string starts with the specified prefix, case insensitive
 | /// Check if a string starts with the specified prefix, case insensitive
 | ||||||
| /// @see Dqn_CString8_StartsWith
 | /// @see Dqn_CString8_StartsWith
 | ||||||
| @ -909,7 +911,7 @@ DQN_API bool Dqn_CString8_StartsWithInsensitive(char const *string, char const * | |||||||
| /// @param[in] suffix The suffix to check against the string
 | /// @param[in] suffix The suffix to check against the string
 | ||||||
| /// @param[in] eq_case Set the comparison to be case sensitive or insensitive
 | /// @param[in] eq_case Set the comparison to be case sensitive or insensitive
 | ||||||
| /// @return True if the string has the specified suffix, false otherwise
 | /// @return True if the string has the specified suffix, false otherwise
 | ||||||
| DQN_API bool Dqn_CString8_EndsWith(char const *string, char const *suffix, Dqn_isize string_size = -1, Dqn_isize suffix_size = -1, Dqn_CString8EqCase eq_case = Dqn_CString8EqCase::Sensitive); | DQN_API bool Dqn_CString8_EndsWith(char const *string, char const *suffix, Dqn_isize string_size = -1, Dqn_isize suffix_size = -1, Dqn_CString8EqCase eq_case = Dqn_CString8EqCase_Sensitive); | ||||||
| 
 | 
 | ||||||
| /// Check if a string ends with the specified suffix, case insensitive
 | /// Check if a string ends with the specified suffix, case insensitive
 | ||||||
| /// @param[in] string The string to check for the suffix
 | /// @param[in] string The string to check for the suffix
 | ||||||
| @ -929,7 +931,7 @@ DQN_API bool Dqn_CString8_EndsWithInsensitive(char const *string, char const *su | |||||||
| ///
 | ///
 | ||||||
| /// @return The trimmed string. The original input string is returned if
 | /// @return The trimmed string. The original input string is returned if
 | ||||||
| /// arguments are invalid or no trim was possible.
 | /// arguments are invalid or no trim was possible.
 | ||||||
| DQN_API char const *Dqn_CString8_TrimPrefix(char const *string, char const *prefix, Dqn_isize string_size = -1, Dqn_isize prefix_size = -1, Dqn_CString8EqCase eq_case = Dqn_CString8EqCase::Sensitive, Dqn_isize *trimmed_size = nullptr); | DQN_API char const *Dqn_CString8_TrimPrefix(char const *string, char const *prefix, Dqn_isize string_size = -1, Dqn_isize prefix_size = -1, Dqn_CString8EqCase eq_case = Dqn_CString8EqCase_Sensitive, Dqn_isize *trimmed_size = nullptr); | ||||||
| 
 | 
 | ||||||
| /// Remove the prefix from the given `string` if it ends with it by
 | /// Remove the prefix from the given `string` if it ends with it by
 | ||||||
| /// adjusting the input string size.
 | /// adjusting the input string size.
 | ||||||
| @ -943,7 +945,7 @@ DQN_API char const *Dqn_CString8_TrimPrefix(char const *string, char const *pref | |||||||
| ///
 | ///
 | ||||||
| /// @return The trimmed string. The original input string is returned if
 | /// @return The trimmed string. The original input string is returned if
 | ||||||
| /// arguments are invalid or no trim was possible.
 | /// arguments are invalid or no trim was possible.
 | ||||||
| DQN_API char const *Dqn_CString8_TrimSuffix(char const *string, char const *suffix, Dqn_isize string_size = -1, Dqn_isize suffix_size = -1, Dqn_CString8EqCase eq_case = Dqn_CString8EqCase::Sensitive, Dqn_isize *trimmed_size = nullptr); | DQN_API char const *Dqn_CString8_TrimSuffix(char const *string, char const *suffix, Dqn_isize string_size = -1, Dqn_isize suffix_size = -1, Dqn_CString8EqCase eq_case = Dqn_CString8EqCase_Sensitive, Dqn_isize *trimmed_size = nullptr); | ||||||
| 
 | 
 | ||||||
| /// Trim whitespace from the prefix and suffix of the string
 | /// Trim whitespace from the prefix and suffix of the string
 | ||||||
| ///
 | ///
 | ||||||
| @ -1079,10 +1081,12 @@ struct Dqn_String16 /// A pointer and length style string that holds slices to U | |||||||
|     wchar_t   *data; ///< The UTF16 bytes of the string
 |     wchar_t   *data; ///< The UTF16 bytes of the string
 | ||||||
|     Dqn_isize  size; ///< The number of bytes in the string
 |     Dqn_isize  size; ///< The number of bytes in the string
 | ||||||
| 
 | 
 | ||||||
|  |     #if defined(__cplusplus) | ||||||
|     wchar_t const *begin() const { return data; }        ///< Const begin iterator for range-for loops
 |     wchar_t const *begin() const { return data; }        ///< Const begin iterator for range-for loops
 | ||||||
|     wchar_t const *end  () const { return data + size; } ///< Const end iterator for range-for loops
 |     wchar_t const *end  () const { return data + size; } ///< Const end iterator for range-for loops
 | ||||||
|     wchar_t       *begin()       { return data; }        ///< Begin iterator for range-for loops
 |     wchar_t       *begin()       { return data; }        ///< Begin iterator for range-for loops
 | ||||||
|     wchar_t       *end  ()       { return data + size; } ///< End iterator for range-for loops
 |     wchar_t       *end  ()       { return data + size; } ///< End iterator for range-for loops
 | ||||||
|  |     #endif | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /// Initialise a string from a pointer and length
 | /// Initialise a string from a pointer and length
 | ||||||
| @ -1148,28 +1152,28 @@ DQN_API Dqn_String8 Dqn_String8_Copy_(DQN_LEAK_TRACE_FUNCTION Dqn_Allocator allo | |||||||
| DQN_API Dqn_String8 Dqn_String8_BinarySplit(Dqn_String8 string, char delimiter, Dqn_String8 *rhs); | DQN_API Dqn_String8 Dqn_String8_BinarySplit(Dqn_String8 string, char delimiter, Dqn_String8 *rhs); | ||||||
| 
 | 
 | ||||||
| /// @see Dqn_CString8_Eq
 | /// @see Dqn_CString8_Eq
 | ||||||
| DQN_API bool Dqn_String8_Eq(Dqn_String8 lhs, Dqn_String8 rhs, Dqn_CString8EqCase eq_case = Dqn_CString8EqCase::Sensitive); | DQN_API bool Dqn_String8_Eq(Dqn_String8 lhs, Dqn_String8 rhs, Dqn_CString8EqCase eq_case = Dqn_CString8EqCase_Sensitive); | ||||||
| 
 | 
 | ||||||
| /// @see Dqn_CString8_EqInsensitive
 | /// @see Dqn_CString8_EqInsensitive
 | ||||||
| DQN_API bool Dqn_String8_EqInsensitive(Dqn_String8 lhs, Dqn_String8 rhs); | DQN_API bool Dqn_String8_EqInsensitive(Dqn_String8 lhs, Dqn_String8 rhs); | ||||||
| 
 | 
 | ||||||
| /// @see Dqn_CString8_StartsWith
 | /// @see Dqn_CString8_StartsWith
 | ||||||
| DQN_API bool Dqn_String8_StartsWith(Dqn_String8 string, Dqn_String8 prefix, Dqn_CString8EqCase eq_case = Dqn_CString8EqCase::Sensitive); | DQN_API bool Dqn_String8_StartsWith(Dqn_String8 string, Dqn_String8 prefix, Dqn_CString8EqCase eq_case = Dqn_CString8EqCase_Sensitive); | ||||||
| 
 | 
 | ||||||
| /// @see Dqn_CString8_StartsWithInsensitive
 | /// @see Dqn_CString8_StartsWithInsensitive
 | ||||||
| DQN_API bool Dqn_String8_StartsWithInsensitive(Dqn_String8 string, Dqn_String8 prefix); | DQN_API bool Dqn_String8_StartsWithInsensitive(Dqn_String8 string, Dqn_String8 prefix); | ||||||
| 
 | 
 | ||||||
| /// @see Dqn_CString8_EndsWith
 | /// @see Dqn_CString8_EndsWith
 | ||||||
| DQN_API bool Dqn_String8_EndsWith(Dqn_String8 string, Dqn_String8 prefix, Dqn_CString8EqCase eq_case = Dqn_CString8EqCase::Sensitive); | DQN_API bool Dqn_String8_EndsWith(Dqn_String8 string, Dqn_String8 prefix, Dqn_CString8EqCase eq_case = Dqn_CString8EqCase_Sensitive); | ||||||
| 
 | 
 | ||||||
| /// @see Dqn_CString8_EndsWithInsensitive
 | /// @see Dqn_CString8_EndsWithInsensitive
 | ||||||
| DQN_API bool Dqn_String8_EndsWithInsensitive(Dqn_String8 string, Dqn_String8 prefix); | DQN_API bool Dqn_String8_EndsWithInsensitive(Dqn_String8 string, Dqn_String8 prefix); | ||||||
| 
 | 
 | ||||||
| /// @see Dqn_CString8_TrimPrefix
 | /// @see Dqn_CString8_TrimPrefix
 | ||||||
| DQN_API Dqn_String8 Dqn_String8_TrimPrefix(Dqn_String8 string, Dqn_String8 prefix, Dqn_CString8EqCase eq_case = Dqn_CString8EqCase::Sensitive); | DQN_API Dqn_String8 Dqn_String8_TrimPrefix(Dqn_String8 string, Dqn_String8 prefix, Dqn_CString8EqCase eq_case = Dqn_CString8EqCase_Sensitive); | ||||||
| 
 | 
 | ||||||
| /// @see Dqn_CString8_TrimSuffix
 | /// @see Dqn_CString8_TrimSuffix
 | ||||||
| DQN_API Dqn_String8 Dqn_String8_TrimSuffix(Dqn_String8 string, Dqn_String8 suffix, Dqn_CString8EqCase eq_case = Dqn_CString8EqCase::Sensitive); | DQN_API Dqn_String8 Dqn_String8_TrimSuffix(Dqn_String8 string, Dqn_String8 suffix, Dqn_CString8EqCase eq_case = Dqn_CString8EqCase_Sensitive); | ||||||
| 
 | 
 | ||||||
| /// @see Dqn_CString8_TrimWhitespaceAround
 | /// @see Dqn_CString8_TrimWhitespaceAround
 | ||||||
| DQN_API Dqn_String8 Dqn_String8_TrimWhitespaceAround(Dqn_String8 string); | DQN_API Dqn_String8 Dqn_String8_TrimWhitespaceAround(Dqn_String8 string); | ||||||
| @ -1218,16 +1222,21 @@ DQN_API void        Dqn_String8_Remove(Dqn_String8 *string, Dqn_isize begin, Dqn | |||||||
| /// @param[in] start_index Set an index within the string string to start the
 | /// @param[in] start_index Set an index within the string string to start the
 | ||||||
| /// search from, if not desired, set to 0
 | /// search from, if not desired, set to 0
 | ||||||
| /// @return The index of the matching find, -1 if it is not found
 | /// @return The index of the matching find, -1 if it is not found
 | ||||||
| DQN_API Dqn_isize   Dqn_String8_FindOffset(Dqn_String8 string, Dqn_String8 find, Dqn_isize start_index, Dqn_CString8EqCase eq_case = Dqn_CString8EqCase::Sensitive); | DQN_API Dqn_isize   Dqn_String8_FindOffset(Dqn_String8 string, Dqn_String8 find, Dqn_isize start_index, Dqn_CString8EqCase eq_case = Dqn_CString8EqCase_Sensitive); | ||||||
| 
 | 
 | ||||||
| /// @param start_index Set an index within the string string to start the search
 | /// @param start_index Set an index within the string string to start the search
 | ||||||
| /// from, if not desired, set to 0
 | /// from, if not desired, set to 0
 | ||||||
| /// @return A string that points to the matching find, otherwise a 0 length string.
 | /// @return A string that points to the matching find, otherwise a 0 length string.
 | ||||||
| DQN_API Dqn_String8 Dqn_String8_Find(Dqn_String8 string, Dqn_String8 find, Dqn_isize start_index, Dqn_CString8EqCase eq_case = Dqn_CString8EqCase::Sensitive); | DQN_API Dqn_String8 Dqn_String8_Find(Dqn_String8 string, Dqn_String8 find, Dqn_isize start_index, Dqn_CString8EqCase eq_case = Dqn_CString8EqCase_Sensitive); | ||||||
| 
 | 
 | ||||||
| DQN_API Dqn_String8 Dqn_String8_Replace(Dqn_String8 string, Dqn_String8 find, Dqn_String8 replace, Dqn_isize start_index, Dqn_Allocator allocator, Dqn_CString8EqCase eq_case = Dqn_CString8EqCase::Sensitive); | DQN_API Dqn_String8 Dqn_String8_Replace(Dqn_String8 string, Dqn_String8 find, Dqn_String8 replace, Dqn_isize start_index, Dqn_Allocator allocator, Dqn_CString8EqCase eq_case = Dqn_CString8EqCase_Sensitive); | ||||||
| DQN_API Dqn_String8 Dqn_String8_ReplaceInsensitive(Dqn_String8 string, Dqn_String8 find, Dqn_String8 replace, Dqn_isize start_index, Dqn_Allocator allocator); | DQN_API Dqn_String8 Dqn_String8_ReplaceInsensitive(Dqn_String8 string, Dqn_String8 find, Dqn_String8 replace, Dqn_isize start_index, Dqn_Allocator allocator); | ||||||
| 
 | 
 | ||||||
|  | #if defined(__cplusplus) | ||||||
|  | bool operator==(Dqn_String8 const &lhs, Dqn_String8 const &rhs); | ||||||
|  | bool operator!=(Dqn_String8 const &lhs, Dqn_String8 const &rhs); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| // ---------------------------------+-----------------------------+---------------------------------
 | // ---------------------------------+-----------------------------+---------------------------------
 | ||||||
| // [SECT-PRIN] Dqn_Print            |                             | Console printing
 | // [SECT-PRIN] Dqn_Print            |                             | Console printing
 | ||||||
| // ---------------------------------+-----------------------------+---------------------------------
 | // ---------------------------------+-----------------------------+---------------------------------
 | ||||||
| @ -1498,16 +1507,22 @@ template <typename T> void Dqn_Map_Erase(Dqn_Map<T> *map, uint64_t hash, Dqn_Zer | |||||||
|     static_assert((DQN_DSMAP_MIN_SIZE & (DQN_DSMAP_MIN_SIZE - 1)) == 0, "DSMap lazy initialisation size must be a power of two"); |     static_assert((DQN_DSMAP_MIN_SIZE & (DQN_DSMAP_MIN_SIZE - 1)) == 0, "DSMap lazy initialisation size must be a power of two"); | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| template <typename T> | #define DQN_DS_MAP_API template <typename K, typename V> DQN_API | ||||||
|  | #define DQN_DS_MAP     Dqn_DSMap<K, V> | ||||||
|  | 
 | ||||||
|  | template <typename K, typename V> | ||||||
| struct Dqn_DSMapItem | struct Dqn_DSMapItem | ||||||
| { | { | ||||||
|     uint64_t          hash; |     K                    key; | ||||||
|     T                 value; |     V                    value; | ||||||
|     uint8_t              occupied; |     uint8_t              occupied; | ||||||
|     Dqn_DSMapItem<T> *next; |     Dqn_DSMapItem<K, V> *next; | ||||||
|     Dqn_DSMapItem<T> *prev; |     Dqn_DSMapItem<K, V> *prev; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | /// The hashing function prototype
 | ||||||
|  | using Dqn_DSMapHashProc = uint64_t(void *data, size_t size); | ||||||
|  | 
 | ||||||
| /// A hash table configured using the presets recommended by Demitri Spanos from
 | /// A hash table configured using the presets recommended by Demitri Spanos from
 | ||||||
| /// the Handmade Network,
 | /// the Handmade Network,
 | ||||||
| /// - 70% max load
 | /// - 70% max load
 | ||||||
| @ -1515,15 +1530,16 @@ struct Dqn_DSMapItem | |||||||
| /// - linear probing on collision
 | /// - linear probing on collision
 | ||||||
| /// - tombstoneless deletes (e.g. deletes slots get filled with linear probed
 | /// - tombstoneless deletes (e.g. deletes slots get filled with linear probed
 | ||||||
| /// entries if there are any).
 | /// entries if there are any).
 | ||||||
| template <typename T> | template <typename K, typename V> | ||||||
| struct Dqn_DSMap | struct Dqn_DSMap | ||||||
| { | { | ||||||
|     Dqn_Arena            arena; |     Dqn_Arena            arena; | ||||||
|     Dqn_DSMapItem<T> *slots; |     Dqn_DSMapItem<K, V> *slots; | ||||||
|     Dqn_isize            size;      ///< The number of slots
 |     Dqn_isize            size;      ///< The number of slots
 | ||||||
|     Dqn_isize            count;     ///< The number of slots occupied in the list
 |     Dqn_isize            count;     ///< The number of slots occupied in the list
 | ||||||
|     Dqn_DSMapItem<T> *link_head; ///< Linked list of items allocated in the map
 |     Dqn_DSMapItem<K, V> *link_head; ///< Linked list of items allocated in the map
 | ||||||
|     Dqn_DSMapItem<T> *link_tail; ///< Linked list of items allocated in the map
 |     Dqn_DSMapItem<K, V> *link_tail; ///< Linked list of items allocated in the map
 | ||||||
|  |     Dqn_DSMapHashProc   *hash_function; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /// Initialise a hash table with a given size. The given size must be a power of
 | /// Initialise a hash table with a given size. The given size must be a power of
 | ||||||
| @ -1531,29 +1547,32 @@ struct Dqn_DSMap | |||||||
| /// the hash table will default to the size specified in DQN_DSMAP_MIN_SIZE.
 | /// the hash table will default to the size specified in DQN_DSMAP_MIN_SIZE.
 | ||||||
| /// @param[in] size The number of slots in the hash-table. This value must be
 | /// @param[in] size The number of slots in the hash-table. This value must be
 | ||||||
| /// a power of two.
 | /// a power of two.
 | ||||||
| template <typename T> | DQN_DS_MAP_API | ||||||
| Dqn_DSMap<T> Dqn_DSMap_Init(Dqn_isize size); | DQN_DS_MAP Dqn_DSMap_Init(Dqn_isize size); | ||||||
| 
 | 
 | ||||||
| template <typename T> | DQN_DS_MAP_API | ||||||
| void Dqn_DSMap_Free(Dqn_DSMap<T> *map, Dqn_ZeroMem zero_mem); | void Dqn_DSMap_Free(DQN_DS_MAP *map, Dqn_ZeroMem zero_mem); | ||||||
| 
 | 
 | ||||||
| template <typename T> | DQN_DS_MAP_API | ||||||
| Dqn_DSMapItem<T> *Dqn_DSMap_Find(Dqn_DSMap<T> *map, uint64_t hash); | Dqn_DSMapItem<K, V> *Dqn_DSMap_Find(DQN_DS_MAP *map, K const &key); | ||||||
| 
 | 
 | ||||||
| enum Dqn_DSMapFindOnly    { Dqn_DSMapFindOnly_No,    Dqn_DSMapFindOnly_Yes }; | enum Dqn_DSMapFindOnly    { Dqn_DSMapFindOnly_No,    Dqn_DSMapFindOnly_Yes }; | ||||||
| enum Dqn_DSMapItemCreated { Dqn_DSMapItemCreated_No, Dqn_DSMapItemCreated_Yes }; | enum Dqn_DSMapItemCreated { Dqn_DSMapItemCreated_No, Dqn_DSMapItemCreated_Yes }; | ||||||
| 
 | 
 | ||||||
| template <typename T> | DQN_DS_MAP_API | ||||||
| Dqn_DSMapItem<T> *Dqn_DSMap_FindOrAdd(Dqn_DSMap<T> *map, uint64_t hash, Dqn_DSMapFindOnly find_only, Dqn_DSMapItemCreated *created); | Dqn_DSMapItem<K, V> *Dqn_DSMap_FindOrAdd(DQN_DS_MAP *map, K const &key, Dqn_DSMapFindOnly find_only, Dqn_DSMapItemCreated *created); | ||||||
| 
 | 
 | ||||||
| template <typename T> | DQN_DS_MAP_API | ||||||
| Dqn_DSMapItem<T> *Dqn_DSMap_Add(Dqn_DSMap<T> *map, uint64_t hash, T const &value); | Dqn_DSMapItem<K, V> *Dqn_DSMap_Add(DQN_DS_MAP *map, K const &key, V const &value); | ||||||
| 
 | 
 | ||||||
| template <typename T> | DQN_DS_MAP_API | ||||||
| Dqn_DSMapItem<T> *Dqn_DSMap_Get(Dqn_DSMap<T> *map, uint64_t hash); | Dqn_DSMapItem<K, V> *Dqn_DSMap_Make(DQN_DS_MAP *map, K const &key); | ||||||
| 
 | 
 | ||||||
| template <typename T> | DQN_DS_MAP_API | ||||||
| void Dqn_DSMap_Erase(Dqn_DSMap<T> *map, uint64_t hash, Dqn_ZeroMem zero_mem); | Dqn_DSMapItem<K, V> *Dqn_DSMap_Get(DQN_DS_MAP *map, K const &key); | ||||||
|  | 
 | ||||||
|  | DQN_DS_MAP_API | ||||||
|  | void Dqn_DSMap_Erase(DQN_DS_MAP *map, K const &key, Dqn_ZeroMem zero_mem); | ||||||
| #endif // !defined(DQN_NO_DSMAP)
 | #endif // !defined(DQN_NO_DSMAP)
 | ||||||
| 
 | 
 | ||||||
| // ---------------------------------+-----------------------------+---------------------------------
 | // ---------------------------------+-----------------------------+---------------------------------
 | ||||||
| @ -1869,25 +1888,37 @@ struct Dqn_List | |||||||
|     Dqn_ListChunk<T> *tail; |     Dqn_ListChunk<T> *tail; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| template <typename T> DQN_API Dqn_List<T>  Dqn_List_InitWithArena(Dqn_Arena *arena, Dqn_isize chunk_size = 128); | template <typename T> DQN_API | ||||||
| 
 | Dqn_List<T> Dqn_List_InitWithArena(Dqn_Arena *arena, Dqn_isize chunk_size = 128); | ||||||
| // Produce an iterator for the data in the list
 |  | ||||||
| /*
 |  | ||||||
|    Dqn_List<int> list = {}; |  | ||||||
|    for (Dqn_ListIterator<int> it = {}; Dqn_List_Iterate(&list, &it, 0);) |  | ||||||
|    { |  | ||||||
|        int *item = it.data; |  | ||||||
|    } |  | ||||||
| */ |  | ||||||
| // start_index: The index to start iterating from
 |  | ||||||
| template <typename T> DQN_API bool Dqn_List_Iterate(Dqn_List<T> *list, Dqn_ListIterator<T> *iterator, Dqn_isize start_index); |  | ||||||
| 
 |  | ||||||
| // at_chunk: (Optional) The chunk that the index belongs to will be set in this parameter if given
 |  | ||||||
| // return: The element, or null pointer if it is not a valid index.
 |  | ||||||
| template <typename T> DQN_API T *Dqn_List_At(Dqn_List<T> *list, Dqn_isize index, Dqn_ListChunk<T> *at_chunk); |  | ||||||
| 
 | 
 | ||||||
| #define Dqn_List_Make(list, count) Dqn_List_Make_(DQN_LEAK_TRACE list, count) | #define Dqn_List_Make(list, count) Dqn_List_Make_(DQN_LEAK_TRACE list, count) | ||||||
| template <typename T> DQN_API T *Dqn_List_Make_(DQN_LEAK_TRACE_FUNCTION Dqn_List<T> *list, Dqn_isize count); | template <typename T> DQN_API | ||||||
|  | T *Dqn_List_Make_(DQN_LEAK_TRACE_FUNCTION Dqn_List<T> *list, Dqn_isize count); | ||||||
|  | 
 | ||||||
|  | #define Dqn_List_Add(list, count) Dqn_List_Add_(DQN_LEAK_TRACE list, count) | ||||||
|  | template <typename T> DQN_API | ||||||
|  | T *Dqn_List_Add_(DQN_LEAK_TRACE_FUNCTION Dqn_List<T> *list, Dqn_isize count); | ||||||
|  | 
 | ||||||
|  | /// @param at_chunk[out] (Optional) The chunk that the index belongs to will 
 | ||||||
|  | /// be set in this parameter if given
 | ||||||
|  | /// @return The element, or null pointer if it is not a valid index.
 | ||||||
|  | template <typename T> DQN_API | ||||||
|  | T *Dqn_List_At(Dqn_List<T> *list, Dqn_isize index, Dqn_ListChunk<T> *at_chunk); | ||||||
|  | 
 | ||||||
|  | /// Produce an iterator for the data in the list
 | ||||||
|  | ///
 | ||||||
|  | /// @param[in] start_index The index to start iterating from
 | ||||||
|  | ///
 | ||||||
|  | /// @begincode
 | ||||||
|  | /// Dqn_List<int> list = {};
 | ||||||
|  | /// for (Dqn_ListIterator<int> it = {}; Dqn_List_Iterate(&list, &it, 0);)
 | ||||||
|  | /// {
 | ||||||
|  | ///     int *item = it.data;
 | ||||||
|  | /// }
 | ||||||
|  | /// @endcode
 | ||||||
|  | ///
 | ||||||
|  | template <typename T> DQN_API | ||||||
|  | bool Dqn_List_Iterate(Dqn_List<T> *list, Dqn_ListIterator<T> *it, Dqn_isize start_index); | ||||||
| 
 | 
 | ||||||
| // ---------------------------------+-----------------------------+---------------------------------
 | // ---------------------------------+-----------------------------+---------------------------------
 | ||||||
| // [SECT-MATH] Math                 | DQN_NO_MATH                 | v2i, V2, V3, V4, Mat4, Rect, RectI32, Lerp
 | // [SECT-MATH] Math                 | DQN_NO_MATH                 | v2i, V2, V3, V4, Mat4, Rect, RectI32, Lerp
 | ||||||
| @ -2547,14 +2578,14 @@ DQN_API uint64_t Dqn_Date_EpochTime(); | |||||||
| // ---------------------------------+-----------------------------+---------------------------------
 | // ---------------------------------+-----------------------------+---------------------------------
 | ||||||
| // [SECT-WIND] Dqn_Win              |                             | Windows OS helpers
 | // [SECT-WIND] Dqn_Win              |                             | Windows OS helpers
 | ||||||
| // ---------------------------------+-----------------------------+---------------------------------
 | // ---------------------------------+-----------------------------+---------------------------------
 | ||||||
| struct Dqn_Win_ErrorMsg | struct Dqn_WinErrorMsg | ||||||
| { | { | ||||||
|     unsigned long code; |     unsigned long code; | ||||||
|     char          data[DQN_KILOBYTES(64) - 1]; // Maximum error size
 |     char          data[DQN_KILOBYTES(64) - 1]; // Maximum error size
 | ||||||
|     unsigned long size; |     unsigned long size; | ||||||
| }; | }; | ||||||
| DQN_API void Dqn_Win_LastErrorToBuffer(Dqn_Win_ErrorMsg *msg); | DQN_API void Dqn_Win_LastErrorToBuffer(Dqn_WinErrorMsg *msg); | ||||||
| DQN_API Dqn_Win_ErrorMsg Dqn_Win_LastError(); | DQN_API Dqn_WinErrorMsg Dqn_Win_LastError(); | ||||||
| 
 | 
 | ||||||
| /// Call once at application start-up to ensure that the application is DPI
 | /// Call once at application start-up to ensure that the application is DPI
 | ||||||
| /// aware on Windows and ensure that application UI is scaled up appropriately
 | /// aware on Windows and ensure that application UI is scaled up appropriately
 | ||||||
| @ -3114,11 +3145,11 @@ DQN_API uint64_t Dqn_FNV1A64_Iterate(void const *bytes, Dqn_isize size, uint64_t | |||||||
| /// algorithms are optimized for their respective platforms. You can still
 | /// algorithms are optimized for their respective platforms. You can still
 | ||||||
| /// compile and run any of them on any platform, but your performance with the
 | /// compile and run any of them on any platform, but your performance with the
 | ||||||
| /// non-native version will be less than optimal.
 | /// non-native version will be less than optimal.
 | ||||||
| struct Dqn_MurmurHash3128 { uint64_t e[2]; }; | struct Dqn_MurmurHash3 { uint64_t e[2]; }; | ||||||
| 
 | 
 | ||||||
| DQN_API uint32_t           Dqn_MurmurHash3x86_32 (void const *key, int len, uint32_t seed); | DQN_API uint32_t        Dqn_MurmurHash3_x86U32 (void const *key, int len, uint32_t seed); | ||||||
| DQN_API Dqn_MurmurHash3128 Dqn_MurmurHash3x64_128(void const *key, int len, uint32_t seed); | DQN_API Dqn_MurmurHash3 Dqn_MurmurHash3_x64U128(void const *key, int len, uint32_t seed); | ||||||
| #define DQN_MURMUR_HASH3_U128_AS_U64(key, len, seed) (Dqn_MurmurHash3x64_128(key, len, seed).e[0]) | #define Dqn_MurmurHash3_x64U128AsU64(key, len, seed) (Dqn_MurmurHash3_x64U128(key, len, seed).e[0]) | ||||||
| 
 | 
 | ||||||
| // NOTE: Dqn_Map Template Implementation
 | // NOTE: Dqn_Map Template Implementation
 | ||||||
| // -------------------------------------------------------------------------------------------------
 | // -------------------------------------------------------------------------------------------------
 | ||||||
| @ -3235,34 +3266,48 @@ void Dqn_Map_Erase(Dqn_Map<T> *map, uint64_t hash, Dqn_ZeroMem zero_mem) | |||||||
| // NOTE: Dqn_DSMap Template Implementation
 | // NOTE: Dqn_DSMap Template Implementation
 | ||||||
| // -------------------------------------------------------------------------------------------------
 | // -------------------------------------------------------------------------------------------------
 | ||||||
| #if !defined(DQN_NO_DSMAP) | #if !defined(DQN_NO_DSMAP) | ||||||
| template <typename T> | DQN_DS_MAP_API | ||||||
| Dqn_DSMap<T> Dqn_DSMap_Init(Dqn_isize size) | DQN_DS_MAP Dqn_DSMap_Init(Dqn_isize size) | ||||||
| { | { | ||||||
|     Dqn_DSMap<T> result = {}; |     DQN_DS_MAP result = {}; | ||||||
|     if (Dqn_Safe_AssertF(size > 0 && (size & (size - 1)) == 0, "Non-zero & power of 2 table size required")) { |     if (Dqn_Safe_AssertF(size > 0 && (size & (size - 1)) == 0, "Non-zero & power of 2 table size required")) { | ||||||
|         result.slots = Dqn_Arena_NewArray(&result.arena, Dqn_DSMapItem<T>, size, Dqn_ZeroMem_Yes); |         // TODO: We need to use placement new for C++ crap
 | ||||||
|  |         result.slots = (Dqn_DSMapItem<K, V> *)Dqn_Arena_Allocate_(DQN_LEAK_TRACE &result.arena, | ||||||
|  |                                                                   sizeof(Dqn_DSMapItem<K, V>) * size, | ||||||
|  |                                                                   alignof(Dqn_DSMapItem<K, V>), | ||||||
|  |                                                                   Dqn_ZeroMem_Yes); | ||||||
|         if (result.slots) |         if (result.slots) | ||||||
|             result.size = size; |             result.size = size; | ||||||
|     } |     } | ||||||
|     return result; |     return result; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| template <typename T> | DQN_DS_MAP_API | ||||||
| void Dqn_DSMap_Free(Dqn_DSMap<T> *map, Dqn_ZeroMem zero_mem) | void Dqn_DSMap_Free(DQN_DS_MAP *map, Dqn_ZeroMem zero_mem) | ||||||
| { | { | ||||||
|     Dqn_Arena_Free(&map->arena, zero_mem); |     Dqn_Arena_Free(&map->arena, zero_mem); | ||||||
|     *map = {}; |     *map = {}; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| template <typename T> | DQN_DS_MAP_API | ||||||
| Dqn_DSMapItem<T> *Dqn_DSMap_Find(Dqn_DSMap<T> *map, uint64_t hash) | Dqn_DSMapItem<K, V> *Dqn_DSMap_Find(DQN_DS_MAP *map, uint64_t hash) | ||||||
| { | { | ||||||
|     Dqn_DSMapItem<T> *result = Dqn_DSMap_FindOrAdd(map, hash, true /*find_only*/); |     Dqn_DSMapItem<K, V> *result = Dqn_DSMap_FindOrAdd(map, hash, true /*find_only*/); | ||||||
|     return result; |     return result; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| template <typename T> | DQN_FILE_SCOPE uint64_t Dqn_DSMap_KeyHash_(Dqn_DSMapHashProc *hash_function, void const *key, int key_size) | ||||||
| Dqn_DSMapItem<T> *Dqn_DSMap_FindOrAdd(Dqn_DSMap<T> *map, uint64_t hash, Dqn_DSMapFindOnly find_only, Dqn_DSMapItemCreated *created) | { | ||||||
|  |     uint64_t result; | ||||||
|  |     if (hash_function) | ||||||
|  |         result = hash_function(&key, key_size); | ||||||
|  |     else | ||||||
|  |         result = Dqn_MurmurHash3_x64U128AsU64(&key, key_size, 0xc8f451ac/*seed*/); | ||||||
|  |     return result; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | DQN_DS_MAP_API | ||||||
|  | Dqn_DSMapItem<K, V> *Dqn_DSMap_FindOrAdd(DQN_DS_MAP *map, K const &key, Dqn_DSMapFindOnly find_only, Dqn_DSMapItemCreated *created) | ||||||
| { | { | ||||||
|     if (created) |     if (created) | ||||||
|         *created = Dqn_DSMapItemCreated_No; |         *created = Dqn_DSMapItemCreated_No; | ||||||
| @ -3274,26 +3319,27 @@ Dqn_DSMapItem<T> *Dqn_DSMap_FindOrAdd(Dqn_DSMap<T> *map, uint64_t hash, Dqn_DSMa | |||||||
|         if (find_only) |         if (find_only) | ||||||
|             return nullptr; |             return nullptr; | ||||||
|         else |         else | ||||||
|             *map = Dqn_DSMap_Init<T>(DQN_DSMAP_MIN_SIZE); |             *map = Dqn_DSMap_Init<K, V>(DQN_DSMAP_MIN_SIZE); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // NOTE: Search for a vacant entry, linear probe if hash collision
 |     // NOTE: Search for a vacant entry, linear probe if hash collision
 | ||||||
|  |     uint64_t hash               = Dqn_DSMap_KeyHash_(map->hash_function, &key, sizeof(key)); | ||||||
|     Dqn_isize            index  = hash % map->size; |     Dqn_isize            index  = hash % map->size; | ||||||
|     Dqn_DSMapItem<T> *result = map->slots + index; |     Dqn_DSMapItem<K, V> *result = map->slots + index; | ||||||
|     while (result->occupied && result->hash != hash) { |     while (result->occupied && result->key != key) { | ||||||
|         index  = (index + 1) % map->size; |         index  = (index + 1) % map->size; | ||||||
|         result = map->slots + index; |         result = map->slots + index; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (result->occupied) { |     if (result->occupied) { | ||||||
|         DQN_ASSERT_MSG(result->hash == hash, |         DQN_ASSERT_MSG(result->key == key, | ||||||
|                        "We have a max load factor of 70%% so we should never get an occupied slot that doesn't match " |                        "We have a max load factor of 70%% so we should never get an occupied slot that doesn't match " | ||||||
|                        "the hash we were searching for"); |                        "the hash we were searching for"); | ||||||
|     } else if (find_only == Dqn_DSMapFindOnly_Yes) { |     } else if (find_only == Dqn_DSMapFindOnly_Yes) { | ||||||
|         result = nullptr; |         result = nullptr; | ||||||
|     } else { |     } else { | ||||||
|         // NOTE: Fill the entry
 |         // NOTE: Fill the entry
 | ||||||
|         result->hash     = hash; |         result->key      = key; | ||||||
|         result->occupied = true; |         result->occupied = true; | ||||||
| 
 | 
 | ||||||
|         if (created) |         if (created) | ||||||
| @ -3312,13 +3358,13 @@ Dqn_DSMapItem<T> *Dqn_DSMap_FindOrAdd(Dqn_DSMap<T> *map, uint64_t hash, Dqn_DSMa | |||||||
|         Dqn_f32 load_factor = ++map->count / DQN_CAST(Dqn_f32)map->size; |         Dqn_f32 load_factor = ++map->count / DQN_CAST(Dqn_f32)map->size; | ||||||
|         if (load_factor >= 0.7f) { |         if (load_factor >= 0.7f) { | ||||||
| 
 | 
 | ||||||
|             auto new_map = Dqn_DSMap_Init<T>(map->size << 1); |             auto new_map = Dqn_DSMap_Init<K, V>(map->size << 1); | ||||||
|             for (Dqn_DSMapItem<T> *entry = map->link_head; entry; entry = entry->next) { |             for (Dqn_DSMapItem<K, V> *entry = map->link_head; entry; entry = entry->next) { | ||||||
|                 if (!entry->occupied) |                 if (!entry->occupied) | ||||||
|                     continue; |                     continue; | ||||||
| 
 | 
 | ||||||
|                 Dqn_DSMapItem<T> *new_entry = Dqn_DSMap_Add(&new_map, entry->hash, entry->value); |                 Dqn_DSMapItem<K, V> *new_entry = Dqn_DSMap_Add(&new_map, entry->key, entry->value); | ||||||
|                 if (new_entry->hash == hash) |                 if (new_entry->key == key) | ||||||
|                     result = new_entry; |                     result = new_entry; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
| @ -3330,31 +3376,39 @@ Dqn_DSMapItem<T> *Dqn_DSMap_FindOrAdd(Dqn_DSMap<T> *map, uint64_t hash, Dqn_DSMa | |||||||
|     return result; |     return result; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| template <typename T> | DQN_DS_MAP_API | ||||||
| Dqn_DSMapItem<T> *Dqn_DSMap_Add(Dqn_DSMap<T> *map, uint64_t hash, T const &value) | Dqn_DSMapItem<K, V> *Dqn_DSMap_Add(DQN_DS_MAP *map, K const &key, V const &value) | ||||||
| { | { | ||||||
|     Dqn_DSMapItem<T> *result = Dqn_DSMap_FindOrAdd(map, hash, Dqn_DSMapFindOnly_No, nullptr /*added*/); |     Dqn_DSMapItem<K, V> *result = Dqn_DSMap_FindOrAdd(map, key, Dqn_DSMapFindOnly_No, nullptr /*added*/); | ||||||
|     if (result) |     if (result) | ||||||
|         result->value = value; |         result->value = value; | ||||||
| 
 | 
 | ||||||
|     return result; |     return result; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| template <typename T> | DQN_DS_MAP_API | ||||||
| Dqn_DSMapItem<T> *Dqn_DSMap_Get(Dqn_DSMap<T> *map, uint64_t hash) | Dqn_DSMapItem<K, V> *Dqn_DSMap_Make(DQN_DS_MAP *map, K const &key) | ||||||
| { | { | ||||||
|     Dqn_DSMapItem<T> *result = Dqn_DSMap_FindOrAdd(map, hash, Dqn_DSMapFindOnly_Yes, nullptr /*added*/); |     Dqn_DSMapItem<K, V> *result = Dqn_DSMap_FindOrAdd(map, key, Dqn_DSMapFindOnly_No, nullptr /*added*/); | ||||||
|     return result; |     return result; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| template <typename T> | DQN_DS_MAP_API | ||||||
| void Dqn_DSMap_Erase(Dqn_DSMap<T> *map, uint64_t hash, Dqn_ZeroMem zero_mem) | Dqn_DSMapItem<K, V> *Dqn_DSMap_Get(DQN_DS_MAP *map, K const &key) | ||||||
|  | { | ||||||
|  |     Dqn_DSMapItem<K, V> *result = Dqn_DSMap_FindOrAdd(map, key, Dqn_DSMapFindOnly_Yes, nullptr /*added*/); | ||||||
|  |     return result; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | DQN_DS_MAP_API | ||||||
|  | void Dqn_DSMap_Erase(DQN_DS_MAP *map, K const &key, Dqn_ZeroMem zero_mem) | ||||||
| { | { | ||||||
|     if (!map) |     if (!map) | ||||||
|         return; |         return; | ||||||
| 
 | 
 | ||||||
|  |     uint64_t hash               = Dqn_DSMap_KeyHash_(map, &key, sizeof(key)); | ||||||
|     Dqn_isize            index  = hash % map->size; |     Dqn_isize            index  = hash % map->size; | ||||||
|     Dqn_DSMapItem<T> *result = map->slots + index; |     Dqn_DSMapItem<K, V> *result = map->slots + index; | ||||||
|     if (!result || !result->occupied) |     if (!result || !result->occupied) | ||||||
|         return; |         return; | ||||||
| 
 | 
 | ||||||
| @ -3373,7 +3427,7 @@ void Dqn_DSMap_Erase(Dqn_DSMap<T> *map, uint64_t hash, Dqn_ZeroMem zero_mem) | |||||||
|     Dqn_isize probe_index = index; |     Dqn_isize probe_index = index; | ||||||
|     for (;;) { |     for (;;) { | ||||||
|         probe_index                = (probe_index + 1) % map->size; |         probe_index                = (probe_index + 1) % map->size; | ||||||
|         Dqn_DSMapItem<T> *probe = map->slots + probe_index; |         Dqn_DSMapItem<K, V> *probe = map->slots + probe_index; | ||||||
|         if (!probe->occupied) |         if (!probe->occupied) | ||||||
|             break; |             break; | ||||||
| 
 | 
 | ||||||
| @ -3881,38 +3935,46 @@ DQN_API T *Dqn_List_Make_(DQN_LEAK_TRACE_FUNCTION Dqn_List<T> *list, Dqn_isize c | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| template <typename T> | template <typename T> | ||||||
| DQN_API bool Dqn_List_IterateFrom(Dqn_List<T> *list, Dqn_ListIterator<T> *iterator, Dqn_isize start_index) | DQN_API T *Dqn_List_Add_(DQN_LEAK_TRACE_FUNCTION Dqn_List<T> *list, T const &value) | ||||||
|  | { | ||||||
|  |     T *result = Dqn_List_Make_(list, 1); | ||||||
|  |     *result = value; | ||||||
|  |     return result; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | template <typename T> | ||||||
|  | DQN_API bool Dqn_List_Iterate(Dqn_List<T> *list, Dqn_ListIterator<T> *it, Dqn_isize start_index) | ||||||
| { | { | ||||||
|     bool result = false; |     bool result = false; | ||||||
|     if (!list || !iterator || start_index < 0 || list->chunk_size <= 0) |     if (!list || !it || start_index < 0 || list->chunk_size <= 0) | ||||||
|         return result; |         return result; | ||||||
| 
 | 
 | ||||||
|     if (!iterator->init) { |     if (!it->init) { | ||||||
|         *iterator = {}; |         *it = {}; | ||||||
|         if (start_index == 0) { |         if (start_index == 0) { | ||||||
|             iterator->chunk = list->head; |             it->chunk = list->head; | ||||||
|         } else { |         } else { | ||||||
|             Dqn_List_At(list, start_index, &iterator->chunk); |             Dqn_List_At(list, start_index, &it->chunk); | ||||||
|             if (list->chunk_size > 0) |             if (list->chunk_size > 0) | ||||||
|                 iterator->chunk_data_index = start_index % list->chunk_size; |                 it->chunk_data_index = start_index % list->chunk_size; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         iterator->init = true; |         it->init = true; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (iterator->chunk) { |     if (it->chunk) { | ||||||
|         if (iterator->chunk_data_index >= iterator->chunk->count) { |         if (it->chunk_data_index >= it->chunk->count) { | ||||||
|             iterator->chunk            = iterator->chunk->next; |             it->chunk            = it->chunk->next; | ||||||
|             iterator->chunk_data_index = 0; |             it->chunk_data_index = 0; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (iterator->chunk) { |         if (it->chunk) { | ||||||
|             iterator->data = iterator->chunk->data + iterator->chunk_data_index++; |             it->data = it->chunk->data + it->chunk_data_index++; | ||||||
|             result         = true; |             result         = true; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (!iterator->chunk) |     if (!it->chunk) | ||||||
|         DQN_ASSERT(result == false); |         DQN_ASSERT(result == false); | ||||||
|     return result; |     return result; | ||||||
| } | } | ||||||
| @ -4676,7 +4738,7 @@ DQN_API bool Dqn_CString8_Eq(char const *lhs, char const *rhs, Dqn_isize lhs_siz | |||||||
| 
 | 
 | ||||||
|     bool result = lhs_size == rhs_size; |     bool result = lhs_size == rhs_size; | ||||||
|     if (result) { |     if (result) { | ||||||
|         if (eq_case == Dqn_CString8EqCase::Sensitive) { |         if (eq_case == Dqn_CString8EqCase_Sensitive) { | ||||||
|             result = (DQN_MEMCMP(lhs, rhs, DQN_CAST(size_t)lhs_size) == 0); |             result = (DQN_MEMCMP(lhs, rhs, DQN_CAST(size_t)lhs_size) == 0); | ||||||
|         } else { |         } else { | ||||||
|             for (Dqn_isize index = 0; index < lhs_size && result; index++) |             for (Dqn_isize index = 0; index < lhs_size && result; index++) | ||||||
| @ -4689,7 +4751,7 @@ DQN_API bool Dqn_CString8_Eq(char const *lhs, char const *rhs, Dqn_isize lhs_siz | |||||||
| 
 | 
 | ||||||
| DQN_API bool Dqn_CString8_EqInsensitive(char const *lhs, char const *rhs, Dqn_isize lhs_size, Dqn_isize rhs_size) | DQN_API bool Dqn_CString8_EqInsensitive(char const *lhs, char const *rhs, Dqn_isize lhs_size, Dqn_isize rhs_size) | ||||||
| { | { | ||||||
|     bool result = Dqn_CString8_Eq(lhs, rhs, lhs_size, rhs_size, Dqn_CString8EqCase::Insensitive); |     bool result = Dqn_CString8_Eq(lhs, rhs, lhs_size, rhs_size, Dqn_CString8EqCase_Insensitive); | ||||||
|     return result; |     return result; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -4708,7 +4770,7 @@ DQN_API bool Dqn_CString8_StartsWith(char const *string, char const *prefix, Dqn | |||||||
| 
 | 
 | ||||||
| DQN_API bool Dqn_CString8_StartsWithInsensitive(char const *string, char const *prefix, Dqn_isize string_size, Dqn_isize prefix_size) | DQN_API bool Dqn_CString8_StartsWithInsensitive(char const *string, char const *prefix, Dqn_isize string_size, Dqn_isize prefix_size) | ||||||
| { | { | ||||||
|     bool result = Dqn_CString8_StartsWith(string, prefix, string_size, prefix_size, Dqn_CString8EqCase::Insensitive); |     bool result = Dqn_CString8_StartsWith(string, prefix, string_size, prefix_size, Dqn_CString8EqCase_Insensitive); | ||||||
|     return result; |     return result; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -4729,7 +4791,7 @@ DQN_API bool Dqn_CString8_EndsWith(char const *string, char const *suffix, Dqn_i | |||||||
| 
 | 
 | ||||||
| DQN_API bool Dqn_CString8_EndsWithInsensitive(char const *string, char const *suffix, Dqn_isize string_size, Dqn_isize suffix_size) | DQN_API bool Dqn_CString8_EndsWithInsensitive(char const *string, char const *suffix, Dqn_isize string_size, Dqn_isize suffix_size) | ||||||
| { | { | ||||||
|     bool result = Dqn_CString8_EndsWith(string, suffix, string_size, suffix_size, Dqn_CString8EqCase::Insensitive); |     bool result = Dqn_CString8_EndsWith(string, suffix, string_size, suffix_size, Dqn_CString8EqCase_Insensitive); | ||||||
|     return result; |     return result; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -4813,11 +4875,11 @@ DQN_API char const *Dqn_CString8_TrimByteOrderMark(char const *string, Dqn_isize | |||||||
|     char const UTF32_BOM_LE[] = "\xFF\xFE\x00\x00"; |     char const UTF32_BOM_LE[] = "\xFF\xFE\x00\x00"; | ||||||
| 
 | 
 | ||||||
|     Dqn_isize result_size = string_size; |     Dqn_isize result_size = string_size; | ||||||
|     result = Dqn_CString8_TrimPrefix(result, UTF8_BOM,     result_size, DQN_CHAR_COUNT(UTF8_BOM),     Dqn_CString8EqCase::Sensitive, &result_size); |     result = Dqn_CString8_TrimPrefix(result, UTF8_BOM,     result_size, DQN_CHAR_COUNT(UTF8_BOM),     Dqn_CString8EqCase_Sensitive, &result_size); | ||||||
|     result = Dqn_CString8_TrimPrefix(result, UTF16_BOM_BE, result_size, DQN_CHAR_COUNT(UTF16_BOM_BE), Dqn_CString8EqCase::Sensitive, &result_size); |     result = Dqn_CString8_TrimPrefix(result, UTF16_BOM_BE, result_size, DQN_CHAR_COUNT(UTF16_BOM_BE), Dqn_CString8EqCase_Sensitive, &result_size); | ||||||
|     result = Dqn_CString8_TrimPrefix(result, UTF16_BOM_LE, result_size, DQN_CHAR_COUNT(UTF16_BOM_LE), Dqn_CString8EqCase::Sensitive, &result_size); |     result = Dqn_CString8_TrimPrefix(result, UTF16_BOM_LE, result_size, DQN_CHAR_COUNT(UTF16_BOM_LE), Dqn_CString8EqCase_Sensitive, &result_size); | ||||||
|     result = Dqn_CString8_TrimPrefix(result, UTF32_BOM_BE, result_size, DQN_CHAR_COUNT(UTF32_BOM_BE), Dqn_CString8EqCase::Sensitive, &result_size); |     result = Dqn_CString8_TrimPrefix(result, UTF32_BOM_BE, result_size, DQN_CHAR_COUNT(UTF32_BOM_BE), Dqn_CString8EqCase_Sensitive, &result_size); | ||||||
|     result = Dqn_CString8_TrimPrefix(result, UTF32_BOM_LE, result_size, DQN_CHAR_COUNT(UTF32_BOM_LE), Dqn_CString8EqCase::Sensitive, &result_size); |     result = Dqn_CString8_TrimPrefix(result, UTF32_BOM_LE, result_size, DQN_CHAR_COUNT(UTF32_BOM_LE), Dqn_CString8EqCase_Sensitive, &result_size); | ||||||
| 
 | 
 | ||||||
|     if (trimmed_size) |     if (trimmed_size) | ||||||
|         *trimmed_size = result_size; |         *trimmed_size = result_size; | ||||||
| @ -5252,7 +5314,7 @@ DQN_API bool Dqn_String8_Eq(Dqn_String8 lhs, Dqn_String8 rhs, Dqn_CString8EqCase | |||||||
| 
 | 
 | ||||||
| DQN_API bool Dqn_String8_EqInsensitive(Dqn_String8 lhs, Dqn_String8 rhs) | DQN_API bool Dqn_String8_EqInsensitive(Dqn_String8 lhs, Dqn_String8 rhs) | ||||||
| { | { | ||||||
|     bool result = Dqn_String8_Eq(lhs, rhs, Dqn_CString8EqCase::Insensitive); |     bool result = Dqn_String8_Eq(lhs, rhs, Dqn_CString8EqCase_Insensitive); | ||||||
|     return result; |     return result; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -5264,7 +5326,7 @@ DQN_API bool Dqn_String8_StartsWith(Dqn_String8 string, Dqn_String8 prefix, Dqn_ | |||||||
| 
 | 
 | ||||||
| DQN_API bool Dqn_String8_StartsWithInsensitive(Dqn_String8 string, Dqn_String8 prefix) | DQN_API bool Dqn_String8_StartsWithInsensitive(Dqn_String8 string, Dqn_String8 prefix) | ||||||
| { | { | ||||||
|     bool result = Dqn_String8_StartsWith(string, prefix, Dqn_CString8EqCase::Insensitive); |     bool result = Dqn_String8_StartsWith(string, prefix, Dqn_CString8EqCase_Insensitive); | ||||||
|     return result; |     return result; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -5276,7 +5338,7 @@ DQN_API bool Dqn_String8_EndsWith(Dqn_String8 string, Dqn_String8 suffix, Dqn_CS | |||||||
| 
 | 
 | ||||||
| DQN_API bool Dqn_String8_EndsWithInsensitive(Dqn_String8 string, Dqn_String8 suffix) | DQN_API bool Dqn_String8_EndsWithInsensitive(Dqn_String8 string, Dqn_String8 suffix) | ||||||
| { | { | ||||||
|     bool result = Dqn_String8_EndsWith(string, suffix, Dqn_CString8EqCase::Insensitive); |     bool result = Dqn_String8_EndsWith(string, suffix, Dqn_CString8EqCase_Insensitive); | ||||||
|     return result; |     return result; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -5385,7 +5447,7 @@ DQN_API bool Dqn_String8_IsAllDigits(Dqn_String8 string) | |||||||
| 
 | 
 | ||||||
| DQN_API bool Dqn_String8_IsAllHex(Dqn_String8 string) | DQN_API bool Dqn_String8_IsAllHex(Dqn_String8 string) | ||||||
| { | { | ||||||
|     Dqn_String8 trimmed = Dqn_String8_TrimPrefix(string, DQN_STRING8("0x"), Dqn_CString8EqCase::Insensitive); |     Dqn_String8 trimmed = Dqn_String8_TrimPrefix(string, DQN_STRING8("0x"), Dqn_CString8EqCase_Insensitive); | ||||||
|     bool result        = Dqn_String8_IsValid(trimmed) && trimmed.size > 0; |     bool result        = Dqn_String8_IsValid(trimmed) && trimmed.size > 0; | ||||||
|     for (Dqn_isize index = 0; result && index < trimmed.size; index++) { |     for (Dqn_isize index = 0; result && index < trimmed.size; index++) { | ||||||
|         char ch = trimmed.data[index]; |         char ch = trimmed.data[index]; | ||||||
| @ -5493,10 +5555,24 @@ DQN_API Dqn_String8 Dqn_String8_Replace(Dqn_String8 string, | |||||||
| 
 | 
 | ||||||
| DQN_API Dqn_String8 Dqn_String8_ReplaceInsensitive(Dqn_String8 string, Dqn_String8 find, Dqn_String8 replace, Dqn_isize start_index, Dqn_Arena *arena, Dqn_Arena *temp_arena) | DQN_API Dqn_String8 Dqn_String8_ReplaceInsensitive(Dqn_String8 string, Dqn_String8 find, Dqn_String8 replace, Dqn_isize start_index, Dqn_Arena *arena, Dqn_Arena *temp_arena) | ||||||
| { | { | ||||||
|     Dqn_String8 result = Dqn_String8_Replace(string, find, replace, start_index, arena, temp_arena, Dqn_CString8EqCase::Insensitive); |     Dqn_String8 result = Dqn_String8_Replace(string, find, replace, start_index, arena, temp_arena, Dqn_CString8EqCase_Insensitive); | ||||||
|     return result; |     return result; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #if defined(__cplusplus) | ||||||
|  | bool operator==(Dqn_String8 const &lhs, Dqn_String8 const &rhs) | ||||||
|  | { | ||||||
|  |     bool result = Dqn_String8_Eq(lhs, rhs, Dqn_CString8EqCase_Sensitive); | ||||||
|  |     return result; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool operator!=(Dqn_String8 const &lhs, Dqn_String8 const &rhs) | ||||||
|  | { | ||||||
|  |     bool result = !(lhs == rhs); | ||||||
|  |     return result; | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| // ---------------------------------+-----------------------------+---------------------------------
 | // ---------------------------------+-----------------------------+---------------------------------
 | ||||||
| // [SECT-PRIN] Dqn_Print            |                             | Printing
 | // [SECT-PRIN] Dqn_Print            |                             | Printing
 | ||||||
| // ---------------------------------+-----------------------------+---------------------------------
 | // ---------------------------------+-----------------------------+---------------------------------
 | ||||||
| @ -7271,7 +7347,7 @@ DQN_API uint64_t Dqn_Date_EpochTime() | |||||||
| // ---------------------------------+-----------------------------+---------------------------------
 | // ---------------------------------+-----------------------------+---------------------------------
 | ||||||
| // [SECT-WIND] Dqn_Win              |                             | Windows OS helpers
 | // [SECT-WIND] Dqn_Win              |                             | Windows OS helpers
 | ||||||
| // ---------------------------------+-----------------------------+---------------------------------
 | // ---------------------------------+-----------------------------+---------------------------------
 | ||||||
| DQN_API void Dqn_Win_LastErrorToBuffer(Dqn_Win_ErrorMsg *msg) | DQN_API void Dqn_Win_LastErrorToBuffer(Dqn_WinErrorMsg *msg) | ||||||
| { | { | ||||||
|     msg->code    = GetLastError(); |     msg->code    = GetLastError(); | ||||||
|     msg->data[0] = 0; |     msg->data[0] = 0; | ||||||
| @ -7279,8 +7355,7 @@ DQN_API void Dqn_Win_LastErrorToBuffer(Dqn_Win_ErrorMsg *msg) | |||||||
|     unsigned long flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS; |     unsigned long flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS; | ||||||
|     void *module_to_get_errors_from = nullptr; |     void *module_to_get_errors_from = nullptr; | ||||||
| 
 | 
 | ||||||
|     if (msg->code >= 12000 && msg->code <= 12175) // WinINET Errors
 |     if (msg->code >= 12000 && msg->code <= 12175) { // WinINET Errors
 | ||||||
|     { |  | ||||||
|         flags |= FORMAT_MESSAGE_FROM_HMODULE; |         flags |= FORMAT_MESSAGE_FROM_HMODULE; | ||||||
|         module_to_get_errors_from = GetModuleHandleA("wininet.dll"); |         module_to_get_errors_from = GetModuleHandleA("wininet.dll"); | ||||||
|     } |     } | ||||||
| @ -7292,11 +7367,16 @@ DQN_API void Dqn_Win_LastErrorToBuffer(Dqn_Win_ErrorMsg *msg) | |||||||
|                                  msg->data,                   // LPSTR   lpBuffer,
 |                                  msg->data,                   // LPSTR   lpBuffer,
 | ||||||
|                                  DQN_ARRAY_ICOUNT(msg->data), // unsigned long   nSize,
 |                                  DQN_ARRAY_ICOUNT(msg->data), // unsigned long   nSize,
 | ||||||
|                                  nullptr);                    // va_list * Arguments
 |                                  nullptr);                    // va_list * Arguments
 | ||||||
|  | 
 | ||||||
|  |     if (msg->size >= 2 && | ||||||
|  |         (msg->data[msg->size - 2] == '\r' && msg->data[msg->size - 1] == '\n')) { | ||||||
|  |         msg->size -= 2; | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| DQN_API Dqn_Win_ErrorMsg Dqn_Win_LastError() | DQN_API Dqn_WinErrorMsg Dqn_Win_LastError() | ||||||
| { | { | ||||||
|     Dqn_Win_ErrorMsg result = {}; |     Dqn_WinErrorMsg result = {}; | ||||||
|     Dqn_Win_LastErrorToBuffer(&result); |     Dqn_Win_LastErrorToBuffer(&result); | ||||||
|     return result; |     return result; | ||||||
| } | } | ||||||
| @ -7326,7 +7406,7 @@ DQN_API void Dqn_Win_DumpLastError_(Dqn_CallSite call_site, char const *fmt, ... | |||||||
| { | { | ||||||
|     // TODO(dqn): Hmmm .. should this be a separate log or part of the above
 |     // TODO(dqn): Hmmm .. should this be a separate log or part of the above
 | ||||||
|     // macro. If so we need to make the logging macros more flexible.
 |     // macro. If so we need to make the logging macros more flexible.
 | ||||||
|     Dqn_Win_ErrorMsg msg = Dqn_Win_LastError(); |     Dqn_WinErrorMsg msg = Dqn_Win_LastError(); | ||||||
|     if (fmt) { |     if (fmt) { | ||||||
|         va_list args; |         va_list args; | ||||||
|         va_start(args, fmt); |         va_start(args, fmt); | ||||||
| @ -8370,10 +8450,11 @@ DQN_API bool Dqn_Fs_Copy(Dqn_String8 src, Dqn_String8 dest, bool overwrite) | |||||||
|     result = CopyFileW(src16.data, dest16.data, fail_if_exists) != 0; |     result = CopyFileW(src16.data, dest16.data, fail_if_exists) != 0; | ||||||
| 
 | 
 | ||||||
|     if (!result) { |     if (!result) { | ||||||
|         Dqn_Log_ErrorF("Failed to copy file [from=%.*s, to=%.*s, reason=%.*s]", |         Dqn_WinErrorMsg error = Dqn_Win_LastError(); | ||||||
|                   DQN_STRING_FMT(src16), |         Dqn_Log_ErrorF("Copy file failed [src=\"%.*s\", dest=\"%.*s\", reason=\"%.*s\"]", | ||||||
|                   DQN_STRING_FMT(dest16), |                        DQN_STRING_FMT(src), | ||||||
|                   DQN_STRING_FMT(Dqn_Win_LastError())); |                        DQN_STRING_FMT(dest), | ||||||
|  |                        DQN_STRING_FMT(error)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| #elif defined(DQN_OS_UNIX) | #elif defined(DQN_OS_UNIX) | ||||||
| @ -8591,7 +8672,7 @@ DQN_API char *Dqn_Fs_ReadCString8_(DQN_LEAK_TRACE_FUNCTION char const *path, Dqn | |||||||
|     Dqn_ThreadScratch scratch   = Dqn_Thread_GetScratch(allocator.user_context); |     Dqn_ThreadScratch scratch   = Dqn_Thread_GetScratch(allocator.user_context); | ||||||
|     Dqn_String8       path8     = Dqn_String8_Init(path, path_size); |     Dqn_String8       path8     = Dqn_String8_Init(path, path_size); | ||||||
|     Dqn_String16      path16    = Dqn_Win_String8ToString16Allocator(path8, scratch.allocator); |     Dqn_String16      path16    = Dqn_Win_String8ToString16Allocator(path8, scratch.allocator); | ||||||
|     Dqn_Win_ErrorMsg  error_msg = {}; |     Dqn_WinErrorMsg   error_msg = {}; | ||||||
| 
 | 
 | ||||||
|     // NOTE: Get the file handle
 |     // NOTE: Get the file handle
 | ||||||
|     // -------------------------------------------------------------------------
 |     // -------------------------------------------------------------------------
 | ||||||
| @ -8812,7 +8893,7 @@ DQN_API Dqn_FsFile Dqn_Fs_OpenFile(Dqn_String8 path, Dqn_FsFileOpen open_mode, u | |||||||
|                                             /*HANDLE                hTemplateFile*/         nullptr); |                                             /*HANDLE                hTemplateFile*/         nullptr); | ||||||
| 
 | 
 | ||||||
|     if (handle == INVALID_HANDLE_VALUE) { |     if (handle == INVALID_HANDLE_VALUE) { | ||||||
|         Dqn_Win_ErrorMsg msg = Dqn_Win_LastError(); |         Dqn_WinErrorMsg msg = Dqn_Win_LastError(); | ||||||
|         result.error_size = |         result.error_size = | ||||||
|             DQN_CAST(uint16_t) Dqn_SNPrintF2DotsOnOverflow(result.error, |             DQN_CAST(uint16_t) Dqn_SNPrintF2DotsOnOverflow(result.error, | ||||||
|                                                            DQN_ARRAY_UCOUNT(result.error), |                                                            DQN_ARRAY_UCOUNT(result.error), | ||||||
| @ -8896,7 +8977,7 @@ DQN_API bool Dqn_Fs_WriteFile(Dqn_FsFile *file, char const *buffer, Dqn_isize si | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (!result) { |     if (!result) { | ||||||
|         Dqn_Win_ErrorMsg msg = Dqn_Win_LastError(); |         Dqn_WinErrorMsg msg = Dqn_Win_LastError(); | ||||||
|         file->error_size = |         file->error_size = | ||||||
|             DQN_CAST(uint16_t) Dqn_SNPrintF2DotsOnOverflow(file->error, |             DQN_CAST(uint16_t) Dqn_SNPrintF2DotsOnOverflow(file->error, | ||||||
|                                                            DQN_ARRAY_UCOUNT(file->error), |                                                            DQN_ARRAY_UCOUNT(file->error), | ||||||
| @ -9302,11 +9383,10 @@ void Dqn_JSONBuilder_Bool(Dqn_JSONBuilder *builder, bool value) | |||||||
| #endif // !defined(DQN_NO_JSON_BUILDER)
 | #endif // !defined(DQN_NO_JSON_BUILDER)
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| // NOTE: Hashing - Dqn_FNV1A[32|64]
 | // ---------------------------------+-----------------------------+---------------------------------
 | ||||||
| // -------------------------------------------------------------------------------------------------
 | // [SECT-FNV1] Dqn_FNV1A            |                             | Hash(x) -> 32/64bit via FNV1a
 | ||||||
| //
 | // ---------------------------------+-----------------------------+---------------------------------
 | ||||||
| // Default values recommended by: http://isthe.com/chongo/tech/comp/fnv/
 | // Default values recommended by: http://isthe.com/chongo/tech/comp/fnv/
 | ||||||
| //
 |  | ||||||
| DQN_API uint32_t Dqn_FNV1A32_Iterate(void const *bytes, Dqn_isize size, uint32_t hash) | DQN_API uint32_t Dqn_FNV1A32_Iterate(void const *bytes, Dqn_isize size, uint32_t hash) | ||||||
| { | { | ||||||
|     auto buffer = DQN_CAST(uint8_t const *)bytes; |     auto buffer = DQN_CAST(uint8_t const *)bytes; | ||||||
| @ -9335,9 +9415,9 @@ DQN_API uint64_t Dqn_FNV1A64_Hash(void const *bytes, Dqn_isize size) | |||||||
|     return result; |     return result; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // NOTE: Hashing - Dqn_MurmurHash3
 | // ---------------------------------+-----------------------------+---------------------------------
 | ||||||
| // -------------------------------------------------------------------------------------------------
 | // [SECT-MMUR] Dqn_MurmurHash3      |                             | Hash(x) -> 32/128bit via MurmurHash3
 | ||||||
| 
 | // ---------------------------------+-----------------------------+---------------------------------
 | ||||||
| #if defined(DQN_COMPILER_W32_MSVC) || defined(DQN_COMPILER_W32_CLANG) | #if defined(DQN_COMPILER_W32_MSVC) || defined(DQN_COMPILER_W32_CLANG) | ||||||
|     #define DQN_MMH3_ROTL32(x, y) _rotl(x, y) |     #define DQN_MMH3_ROTL32(x, y) _rotl(x, y) | ||||||
|     #define DQN_MMH3_ROTL64(x, y) _rotl64(x, y) |     #define DQN_MMH3_ROTL64(x, y) _rotl64(x, y) | ||||||
| @ -9383,7 +9463,7 @@ DQN_FORCE_INLINE uint64_t Dqn_MurmurHash3_FMix64(uint64_t k) | |||||||
|     return k; |     return k; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| DQN_API uint32_t Dqn_MurmurHash3x86_32(void const *key, int len, uint32_t seed) | DQN_API uint32_t Dqn_MurmurHash3_x86U32(void const *key, int len, uint32_t seed) | ||||||
| { | { | ||||||
|     const uint8_t *data = (const uint8_t *)key; |     const uint8_t *data = (const uint8_t *)key; | ||||||
|     const int nblocks   = len / 4; |     const int nblocks   = len / 4; | ||||||
| @ -9442,7 +9522,7 @@ DQN_API uint32_t Dqn_MurmurHash3x86_32(void const *key, int len, uint32_t seed) | |||||||
|     return h1; |     return h1; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| DQN_API Dqn_MurmurHash3128 Dqn_MurmurHash3x64_128(void const *key, int len, uint32_t seed) | DQN_API Dqn_MurmurHash3 Dqn_MurmurHash3_x64U128(void const *key, int len, uint32_t seed) | ||||||
| { | { | ||||||
|     const uint8_t *data = (const uint8_t *)key; |     const uint8_t *data = (const uint8_t *)key; | ||||||
|     const int nblocks   = len / 16; |     const int nblocks   = len / 16; | ||||||
| @ -9548,7 +9628,7 @@ DQN_API Dqn_MurmurHash3128 Dqn_MurmurHash3x64_128(void const *key, int len, uint | |||||||
|     h1 += h2; |     h1 += h2; | ||||||
|     h2 += h1; |     h2 += h1; | ||||||
| 
 | 
 | ||||||
|     Dqn_MurmurHash3128 result = {}; |     Dqn_MurmurHash3 result = {}; | ||||||
|     result.e[0]            = h1; |     result.e[0]            = h1; | ||||||
|     result.e[1]            = h2; |     result.e[1]            = h2; | ||||||
|     return result; |     return result; | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user