Add more default hashing procs, name changes, Dqn_EatLine
This commit is contained in:
parent
e0fc9f7b44
commit
3501dd41c1
@ -1778,17 +1778,6 @@ void DqnFile_Test()
|
||||
file.Close();
|
||||
DQN_ASSERT(!file.handle && file.size == 0 && file.flags == 0);
|
||||
|
||||
if (1)
|
||||
{
|
||||
DqnSmartFile raiiFile = {};
|
||||
if (raiiFile.Open(
|
||||
FILE_TO_OPEN, DqnFile::Flag::FileReadWrite, DqnFile::Action::OpenOnly))
|
||||
{
|
||||
i32 breakHereToTestRaii = 0;
|
||||
(void)breakHereToTestRaii;
|
||||
}
|
||||
}
|
||||
|
||||
Log(Status::Ok, "General test");
|
||||
}
|
||||
|
||||
|
243
dqn.h
243
dqn.h
@ -803,12 +803,6 @@ DQN_FILE_SCOPE char *DqnChar_SkipWhitespace (char const *ptr);
|
||||
// return: The ptr to the last char, null if it could not find.
|
||||
DQN_FILE_SCOPE char *DqnChar_FindLastChar (char *ptr, char ch, i32 len, u32 *len_to_char);
|
||||
|
||||
// Finds up to the first [\r]\n and destroy the line, giving you a null terminated line at the newline.
|
||||
// returns: The value to advance the ptr by, this can be different from the line
|
||||
// length if there are new lines or leading whitespaces in the next line
|
||||
DQN_FILE_SCOPE i32 DqnChar_FindNextLine(char *ptr, i32 *line_len);
|
||||
DQN_FILE_SCOPE char *DqnChar_GetNextLine (char *ptr, i32 *line_len);
|
||||
|
||||
// #DqnStr API
|
||||
// =================================================================================================
|
||||
// num_bytes_to_cmp: If -1, cmp runs until \0 is encountered.
|
||||
@ -907,6 +901,11 @@ i32 Dqn_SplitString(char const *src, i32 src_len, char split_char, DqnSlice<char
|
||||
// return: The number of splits, splitting by "split_char" would generate.
|
||||
i32 Dqn_GetNumSplits(char const *src, i32 src_len, char split_char);
|
||||
|
||||
// Skips whitespace then reads UTF8 rune upto first \r or \n and null terminates at that point. Advances input to the start of the next line.
|
||||
// return: The immediate null terminated line
|
||||
DQN_FILE_SCOPE char *Dqn_EatLine(char **input, int *line_len);
|
||||
DQN_FILE_SCOPE wchar_t *Dqn_EatLine(wchar_t **input, int *line_len);
|
||||
|
||||
DQN_FILE_SCOPE inline bool Dqn_BitIsSet (u32 bits, u32 flag);
|
||||
DQN_FILE_SCOPE inline u32 Dqn_BitSet (u32 bits, u32 flag);
|
||||
DQN_FILE_SCOPE inline u32 Dqn_BitUnset (u32 bits, u32 flag);
|
||||
@ -1514,7 +1513,8 @@ struct DqnMemStack
|
||||
char *head; // Read
|
||||
char *tail; // Read
|
||||
|
||||
Block(void *memory_, isize size_) : memory((char *)memory_), size(size_), prev_block(nullptr), head((char *)memory_), tail((char *)memory_ + size_) {}
|
||||
Block() = default;
|
||||
Block(void *memory_, isize size_) { *this = {}; memory = (char *)memory_; size = size_; head = memory; tail = memory + size; }
|
||||
};
|
||||
|
||||
DqnMemTracker tracker; // Read: Metadata for managing ptr allocation
|
||||
@ -2142,6 +2142,11 @@ const u64 DQN_VHASH_TABLE_DEFAULT_SEED = 0x9747B28CAB3F8A7B;
|
||||
template <typename T> DQN_VHASH_TABLE_HASHING_PROC(DqnVHashTableDefaultHash, T) { return DqnHash_Murmur64Seed(&key, sizeof(key), DQN_VHASH_TABLE_DEFAULT_SEED) % count; }
|
||||
template <typename T> DQN_VHASH_TABLE_EQUALS_PROC (DqnVHashTableDefaultEquals, T) { return (DqnMem_Cmp(&a, &b, sizeof(a)) == 0); }
|
||||
|
||||
template <> DQN_VHASH_TABLE_HASHING_PROC(DqnVHashTableDefaultHash<DqnString>, DqnString) { return DqnHash_Murmur64Seed(&key.str, key.len, DQN_VHASH_TABLE_DEFAULT_SEED) % count; }
|
||||
template <> DQN_VHASH_TABLE_EQUALS_PROC (DqnVHashTableDefaultEquals<DqnString>, DqnString) { return (a.len == b.len) && (DqnStr_Cmp(a.str, b.str, a.len) == 0); }
|
||||
template <> DQN_VHASH_TABLE_HASHING_PROC(DqnVHashTableDefaultHash<DqnBuffer<char>>, DqnBuffer<char>) { return DqnHash_Murmur64Seed(&key.str, key.len, DQN_VHASH_TABLE_DEFAULT_SEED) % count; }
|
||||
template <> DQN_VHASH_TABLE_EQUALS_PROC (DqnVHashTableDefaultEquals<DqnBuffer<char>>, DqnBuffer<char>) { return DQN_BUFFER_STRCMP(a, b, Dqn::IgnoreCase::No); }
|
||||
|
||||
// TODO(doyle): Fix this so we don't have to manually declare the fixed string sizes for hashing and equals
|
||||
#define DQN_VHASH_TABLE_DEFAULT_FIXED_STRING_PROCS(StringCapacity) \
|
||||
template <> \
|
||||
@ -2190,19 +2195,19 @@ struct DqnVHashTable
|
||||
struct Bucket
|
||||
{
|
||||
Entry entries[4];
|
||||
isize entryIndex;
|
||||
isize entry_index;
|
||||
};
|
||||
|
||||
Bucket *buckets;
|
||||
isize numBuckets;
|
||||
isize *indexesOfUsedBuckets;
|
||||
isize indexInUsedBuckets;
|
||||
isize num_buckets;
|
||||
isize *indexes_of_used_buckets;
|
||||
isize num_used_buckets;
|
||||
|
||||
DqnVHashTable () = default;
|
||||
DqnVHashTable (isize size) { LazyInit(size); }
|
||||
DqnVHashTable (isize size) { LazyInit(size); }
|
||||
|
||||
void LazyInit (isize size = DQN_MAX(DQN_MEGABYTE(1)/sizeof(Bucket), 1024) );
|
||||
void Free () { if (buckets) DqnOS_VFree(buckets, sizeof(buckets) * numBuckets); *this = {}; }
|
||||
void Free () { if (buckets) DqnOS_VFree(buckets, sizeof(buckets) * num_buckets); *this = {}; }
|
||||
|
||||
void Erase (Key const &key); // Delete the element matching key, does nothing if key not found.
|
||||
Entry *GetEntry (Key const &key); // return: The (key, item) entry associated with the key, nullptr if key not in table yet.
|
||||
@ -2215,15 +2220,15 @@ struct DqnVHashTable
|
||||
struct Iterator
|
||||
{
|
||||
Entry *entry;
|
||||
Iterator(DqnVHashTable *table_, isize indexInUsedBuckets_ = 0, isize indexInBucket_ = 0);
|
||||
Bucket *GetCurrBucket() const { return (table->buckets + table->indexesOfUsedBuckets[indexInUsedBuckets]); }
|
||||
Entry *GetCurrEntry() const { return GetCurrBucket()->entries + indexInBucket; }
|
||||
Iterator(DqnVHashTable *table_, isize num_used_buckets_ = 0, isize index_in_bucket_ = 0);
|
||||
Bucket *GetCurrBucket() const { return (table->buckets + table->indexes_of_used_buckets[num_used_buckets]); }
|
||||
Entry *GetCurrEntry() const { return GetCurrBucket()->entries + index_in_bucket; }
|
||||
Item *GetCurrItem () const { return &(GetCurrEntry()->item); }
|
||||
|
||||
bool operator!=(Iterator const &other) const { return !(indexInUsedBuckets == other.indexInUsedBuckets && indexInBucket == other.indexInBucket); }
|
||||
bool operator!=(Iterator const &other) const { return !(num_used_buckets == other.num_used_buckets && index_in_bucket == other.index_in_bucket); }
|
||||
Entry &operator* () const { return *GetCurrEntry(); }
|
||||
Iterator &operator++();
|
||||
Iterator &operator--() { if (--indexInBucket < 0) { indexInBucket = 0; indexInUsedBuckets = DQN_MAX(--indexInUsedBuckets, 0); } entry = GetCurrEntry(); return *this; }
|
||||
Iterator &operator--() { if (--index_in_bucket < 0) { index_in_bucket = 0; num_used_buckets = DQN_MAX(--num_used_buckets, 0); } entry = GetCurrEntry(); return *this; }
|
||||
Iterator operator++(int) { Iterator result = *this; ++(*this); return result; }
|
||||
Iterator operator--(int) { Iterator result = *this; --(*this); return result; }
|
||||
Iterator operator+ (int offset) const { Iterator result = *this; DQN_FOR_EACH(i, DQN_ABS(offset)) { (offset > 0) ? ++result : --result; } return result; } // TODO(doyle): Improve
|
||||
@ -2231,33 +2236,33 @@ struct DqnVHashTable
|
||||
|
||||
private:
|
||||
DqnVHashTable *table;
|
||||
isize indexInUsedBuckets;
|
||||
isize indexInBucket;
|
||||
isize num_used_buckets;
|
||||
isize index_in_bucket;
|
||||
};
|
||||
|
||||
Iterator Begin() { return begin(); }
|
||||
Iterator End() { return end(); }
|
||||
Iterator begin() { return Iterator(this); }
|
||||
Iterator end() { return Iterator(this, numBuckets, DQN_ARRAY_COUNT(this->buckets[0].entries)); }
|
||||
Iterator end() { return Iterator(this, num_buckets, DQN_ARRAY_COUNT(this->buckets[0].entries)); }
|
||||
};
|
||||
|
||||
DQN_VHASH_TABLE_TEMPLATE DQN_VHASH_TABLE_DECL::Iterator::Iterator(DqnVHashTable *table_,
|
||||
isize indexInUsedBuckets_,
|
||||
isize indexInBucket_)
|
||||
isize num_used_buckets_,
|
||||
isize index_in_bucket_)
|
||||
: table(table_)
|
||||
, indexInUsedBuckets(indexInUsedBuckets_)
|
||||
, indexInBucket(indexInBucket_)
|
||||
, num_used_buckets(num_used_buckets_)
|
||||
, index_in_bucket(index_in_bucket_)
|
||||
, entry(nullptr)
|
||||
{
|
||||
bool sentinelIndex = (indexInUsedBuckets == table->numBuckets &&
|
||||
indexInBucket == DQN_ARRAY_COUNT(table->buckets[0].entries));
|
||||
bool emptyTable = (table->indexInUsedBuckets == 0);
|
||||
if (emptyTable || sentinelIndex)
|
||||
bool sentinel_index = (num_used_buckets == table->num_buckets &&
|
||||
index_in_bucket == DQN_ARRAY_COUNT(table->buckets[0].entries));
|
||||
bool empty_table = (table->num_used_buckets == 0);
|
||||
if (empty_table || sentinel_index)
|
||||
{
|
||||
if (emptyTable)
|
||||
if (empty_table)
|
||||
{
|
||||
this->indexInUsedBuckets = table->numBuckets;
|
||||
this->indexInBucket = DQN_ARRAY_COUNT(table->buckets[0].entries);
|
||||
this->num_used_buckets = table->num_buckets;
|
||||
this->index_in_bucket = DQN_ARRAY_COUNT(table->buckets[0].entries);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -2268,13 +2273,13 @@ DQN_VHASH_TABLE_TEMPLATE DQN_VHASH_TABLE_DECL::Iterator::Iterator(DqnVHashTable
|
||||
|
||||
DQN_VHASH_TABLE_TEMPLATE typename DQN_VHASH_TABLE_DECL::Iterator &DQN_VHASH_TABLE_DECL::Iterator::operator++()
|
||||
{
|
||||
if (++indexInBucket >= GetCurrBucket()->entryIndex)
|
||||
if (++index_in_bucket >= GetCurrBucket()->entry_index)
|
||||
{
|
||||
indexInBucket = 0;
|
||||
indexInUsedBuckets++;
|
||||
index_in_bucket = 0;
|
||||
num_used_buckets++;
|
||||
}
|
||||
|
||||
if (indexInUsedBuckets < table->indexInUsedBuckets)
|
||||
if (num_used_buckets < table->num_used_buckets)
|
||||
entry = GetCurrEntry();
|
||||
else
|
||||
*this = table->end();
|
||||
@ -2285,10 +2290,10 @@ DQN_VHASH_TABLE_TEMPLATE typename DQN_VHASH_TABLE_DECL::Iterator &DQN_VHASH_TABL
|
||||
DQN_VHASH_TABLE_TEMPLATE void DQN_VHASH_TABLE_DECL::LazyInit(isize size)
|
||||
{
|
||||
*this = {};
|
||||
this->numBuckets = size;
|
||||
this->num_buckets = size;
|
||||
this->buckets = static_cast<Bucket *>(DqnOS_VAlloc(size * sizeof(*this->buckets)));
|
||||
this->indexesOfUsedBuckets = static_cast<isize *> (DqnOS_VAlloc(size * sizeof(*this->indexesOfUsedBuckets)));
|
||||
DQN_ASSERT(this->buckets && this->indexesOfUsedBuckets);
|
||||
this->indexes_of_used_buckets = static_cast<isize *> (DqnOS_VAlloc(size * sizeof(*this->indexes_of_used_buckets)));
|
||||
DQN_ASSERT(this->buckets && this->indexes_of_used_buckets);
|
||||
}
|
||||
|
||||
DQN_VHASH_TABLE_TEMPLATE typename DQN_VHASH_TABLE_DECL::Entry *
|
||||
@ -2296,11 +2301,11 @@ DQN_VHASH_TABLE_DECL::GetEntry(Key const &key)
|
||||
{
|
||||
if (!buckets) return nullptr;
|
||||
|
||||
isize index = Hash(this->numBuckets, key);
|
||||
isize index = Hash(this->num_buckets, key);
|
||||
Bucket *bucket = this->buckets + index;
|
||||
|
||||
Entry *result = nullptr;
|
||||
for (isize i = 0; i < bucket->entryIndex && !result; i++)
|
||||
for (isize i = 0; i < bucket->entry_index && !result; i++)
|
||||
{
|
||||
Entry *entry = bucket->entries + i;
|
||||
result = Equals(entry->key, key) ? entry : nullptr;
|
||||
@ -2313,11 +2318,11 @@ DQN_VHASH_TABLE_TEMPLATE Item *DQN_VHASH_TABLE_DECL::GetOrMake(Key const &key, b
|
||||
{
|
||||
if (!this->buckets) LazyInit();
|
||||
|
||||
isize index = Hash(this->numBuckets, key);
|
||||
isize index = Hash(this->num_buckets, key);
|
||||
Bucket *bucket = this->buckets + index;
|
||||
|
||||
Entry *entry = nullptr;
|
||||
for (isize i = 0; i < bucket->entryIndex && !entry; i++)
|
||||
for (isize i = 0; i < bucket->entry_index && !entry; i++)
|
||||
{
|
||||
Entry *check = bucket->entries + i;
|
||||
entry = Equals(check->key, key) ? check : nullptr;
|
||||
@ -2328,22 +2333,22 @@ DQN_VHASH_TABLE_TEMPLATE Item *DQN_VHASH_TABLE_DECL::GetOrMake(Key const &key, b
|
||||
|
||||
if (!entry)
|
||||
{
|
||||
DQN_ALWAYS_ASSERTM(bucket->entryIndex < DQN_ARRAY_COUNT(bucket->entries),
|
||||
DQN_ALWAYS_ASSERTM(bucket->entry_index < 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)
|
||||
this->indexesOfUsedBuckets[this->indexInUsedBuckets++] = index;
|
||||
if (bucket->entry_index == 0)
|
||||
this->indexes_of_used_buckets[this->num_used_buckets++] = index;
|
||||
|
||||
entry = bucket->entries + bucket->entryIndex++;
|
||||
entry = bucket->entries + bucket->entry_index++;
|
||||
entry->key = key;
|
||||
|
||||
// TODO(doyle): A maybe case. We're using virtual memory, so you should
|
||||
// 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
|
||||
// complexity.
|
||||
isize const threshold = static_cast<isize>(0.75f * this->numBuckets);
|
||||
DQN_ALWAYS_ASSERTM(this->indexInUsedBuckets < threshold, "%zu >= %zu", this->indexInUsedBuckets, threshold);
|
||||
isize const threshold = static_cast<isize>(0.75f * this->num_buckets);
|
||||
DQN_ALWAYS_ASSERTM(this->num_used_buckets < threshold, "%zu >= %zu", this->num_used_buckets, threshold);
|
||||
}
|
||||
|
||||
Item *result = &entry->item;
|
||||
@ -2355,31 +2360,31 @@ DQN_VHASH_TABLE_TEMPLATE void DQN_VHASH_TABLE_DECL::Erase(Key const &key)
|
||||
if (!buckets)
|
||||
return;
|
||||
|
||||
isize index = Hash(this->numBuckets, key);
|
||||
isize index = Hash(this->num_buckets, key);
|
||||
Bucket *bucket = this->buckets + index;
|
||||
|
||||
DQN_FOR_EACH(i, bucket->entryIndex)
|
||||
DQN_FOR_EACH(i, bucket->entry_index)
|
||||
{
|
||||
Entry *check = bucket->entries + i;
|
||||
if (Equals(check->key, key))
|
||||
{
|
||||
for (isize j = i; j < (bucket->entryIndex - 1); ++j)
|
||||
for (isize j = i; j < (bucket->entry_index - 1); ++j)
|
||||
bucket->entries[j] = bucket->entries[j + 1];
|
||||
|
||||
if (--bucket->entryIndex == 0)
|
||||
if (--bucket->entry_index == 0)
|
||||
{
|
||||
DQN_FOR_EACH(bucketIndex, this->indexInUsedBuckets)
|
||||
DQN_FOR_EACH(bucketIndex, this->num_used_buckets)
|
||||
{
|
||||
if (this->indexesOfUsedBuckets[bucketIndex] == index)
|
||||
if (this->indexes_of_used_buckets[bucketIndex] == index)
|
||||
{
|
||||
indexesOfUsedBuckets[bucketIndex] =
|
||||
indexesOfUsedBuckets[--this->indexInUsedBuckets];
|
||||
indexes_of_used_buckets[bucketIndex] =
|
||||
indexes_of_used_buckets[--this->num_used_buckets];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DQN_ASSERT(this->indexInUsedBuckets >= 0);
|
||||
DQN_ASSERT(bucket->entryIndex >= 0);
|
||||
DQN_ASSERT(this->num_used_buckets >= 0);
|
||||
DQN_ASSERT(bucket->entry_index >= 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -2463,7 +2468,7 @@ DQN_FILE_SCOPE bool DqnFile_Size(wchar_t const *path, usize *size);
|
||||
|
||||
DQN_FILE_SCOPE bool DqnFile_MakeDir(char const *path);
|
||||
|
||||
// info: Pass in to fill with file attributes.
|
||||
// info: (Optional) Pass in to fill with file attributes
|
||||
// return: False if file access failure
|
||||
DQN_FILE_SCOPE bool DqnFile_GetInfo(char const *path, DqnFileInfo *info);
|
||||
DQN_FILE_SCOPE bool DqnFile_GetInfo(wchar_t const *path, DqnFileInfo *info);
|
||||
@ -2482,11 +2487,6 @@ DQN_FILE_SCOPE bool DqnFile_Copy (wchar_t const *src, wchar_t const *dest);
|
||||
DQN_FILE_SCOPE char **DqnFile_ListDir (char const *dir, i32 *num_files, DqnMemAPI *api = DQN_DEFAULT_HEAP_ALLOCATOR);
|
||||
DQN_FILE_SCOPE void DqnFile_ListDirFree (char **file_list, i32 num_files, DqnMemAPI *api = DQN_DEFAULT_HEAP_ALLOCATOR);
|
||||
|
||||
struct DqnSmartFile : public DqnFile
|
||||
{
|
||||
~DqnSmartFile() { this->Close(); }
|
||||
};
|
||||
|
||||
// XPlatform > #DqnCatalog API
|
||||
// =================================================================================================
|
||||
using DqnCatalogPath = DqnFixedString1024;
|
||||
@ -3365,7 +3365,7 @@ DqnMemStack__AllocateBlock(isize size, Dqn::ZeroClear clear, DqnMemAPI *api)
|
||||
DQN_ALWAYS_ASSERTM(result, "Allocated memory block was null");
|
||||
|
||||
char *block_offset = reinterpret_cast<char *>(result) + sizeof(*result);
|
||||
*result = DqnMemStack::Block(block_offset, size);
|
||||
*result = DqnMemStack::Block(block_offset, size);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -3463,6 +3463,7 @@ void *DqnMemStack::Push(isize size, AllocTo allocTo, u8 alignment)
|
||||
DQN_ASSERT(this->block->tail >= this->block->head);
|
||||
}
|
||||
|
||||
this->block->used_ = this->block->size - (this->block->tail - this->block->head);
|
||||
// Instrument allocation with guards and tracker
|
||||
// =============================================================================================
|
||||
{
|
||||
@ -4645,48 +4646,58 @@ DQN_FILE_SCOPE char *DqnChar_FindLastChar(char *ptr, char ch, i32 len, u32 *len_
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DQN_FILE_SCOPE i32 DqnChar_FindNextLine(char *ptr, i32 *line_len)
|
||||
DQN_FILE_SCOPE char *Dqn_EatLine(char **input, int *line_len)
|
||||
{
|
||||
i32 len = 0;
|
||||
ptr = DqnChar_SkipWhitespace(ptr);
|
||||
*input = DqnChar_SkipWhitespace(*input);
|
||||
char *result = *input;
|
||||
|
||||
// Advance pointer to first new line
|
||||
while (ptr && *ptr != 0 && *ptr != '\r' && *ptr != '\n')
|
||||
for (int rune_len = -1;; rune_len = -1)
|
||||
{
|
||||
ptr++;
|
||||
len++;
|
||||
}
|
||||
u32 rune = 0;
|
||||
for (; rune_len != 0 && rune_len != 1; *input += rune_len)
|
||||
rune_len = DqnStr_ReadUTF8Codepoint(reinterpret_cast<u32 *>(*input), &rune);
|
||||
|
||||
if (!ptr || *ptr == 0)
|
||||
{
|
||||
if (line_len) *line_len = len;
|
||||
return -1;
|
||||
if (rune_len == 1)
|
||||
{
|
||||
if (rune == '\r' || rune == '\n')
|
||||
{
|
||||
char *ptr_to_rune = (*input - rune_len);
|
||||
*ptr_to_rune = 0;
|
||||
*line_len = static_cast<int>(ptr_to_rune - result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
else if (rune_len == 0)
|
||||
{
|
||||
*line_len = static_cast<int>(*input - result);
|
||||
*input = nullptr;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// Destroy all new lines
|
||||
i32 extra_chars = 0;
|
||||
while (ptr && (*ptr == '\r' || *ptr == '\n' || *ptr == ' '))
|
||||
{
|
||||
*ptr = 0;
|
||||
ptr++;
|
||||
extra_chars++;
|
||||
}
|
||||
|
||||
if (line_len) *line_len = len;
|
||||
return len + extra_chars;
|
||||
}
|
||||
|
||||
DQN_FILE_SCOPE char *DqnChar_GetNextLine (char *ptr, i32 *line_len)
|
||||
DQN_FILE_SCOPE wchar_t *Dqn_EatLine(wchar_t **input, int *line_len)
|
||||
{
|
||||
i32 offset_to_next_line = DqnChar_FindNextLine(ptr, line_len);
|
||||
*input = DqnWChar_SkipWhitespace(*input);
|
||||
wchar_t *result = *input;
|
||||
|
||||
char *result = nullptr;
|
||||
if (offset_to_next_line != -1)
|
||||
for (;; (*input)++)
|
||||
{
|
||||
result = ptr + offset_to_next_line;
|
||||
}
|
||||
if (!(*input))
|
||||
{
|
||||
*line_len = static_cast<int>(*input - result);
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
wchar_t ch = (*input)[0];
|
||||
if (ch == '\r' || ch == '\n')
|
||||
{
|
||||
(*input)[0] = 0;
|
||||
*line_len = static_cast<int>(*input - result);
|
||||
(*input)++;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// #DqnStr Implementation
|
||||
@ -7908,14 +7919,14 @@ FILE_SCOPE bool DqnFile__UnixGetFileSize(char const *path, usize *size)
|
||||
{
|
||||
struct stat file_stat = {};
|
||||
stat(path, &file_stat);
|
||||
*size = file_stat.st_size;
|
||||
if (size) *size = file_stat.st_size;
|
||||
|
||||
if (*size != 0)
|
||||
if (file_stat.st_size != 0)
|
||||
return true;
|
||||
|
||||
// NOTE: Can occur in some instances where files are generated on demand, i.e. /proc/cpuinfo.
|
||||
// But there can also be zero-byte files, we can't be sure. So manual check by counting bytes
|
||||
if (FILE *file = fopen(path, "rb"))
|
||||
if (size && FILE *file = fopen(path, "rb"))
|
||||
{
|
||||
DQN_DEFER(fclose(file));
|
||||
while (fgetc(file) != EOF)
|
||||
@ -8332,7 +8343,7 @@ bool DqnFile_Size(wchar_t const *path, usize *size)
|
||||
DqnFileInfo info = {};
|
||||
if (DqnFile_GetInfo(path, &info))
|
||||
{
|
||||
*size = info.size;
|
||||
if (size) *size = info.size;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -8382,15 +8393,18 @@ bool DqnFile_GetInfo(wchar_t const *path, DqnFileInfo *info)
|
||||
WIN32_FILE_ATTRIBUTE_DATA attrib_data = {};
|
||||
if (GetFileAttributesExW(path, GetFileExInfoStandard, &attrib_data))
|
||||
{
|
||||
info->create_time_in_s = FileTimeToSeconds(&attrib_data.ftCreationTime);
|
||||
info->last_access_time_in_s = FileTimeToSeconds(&attrib_data.ftLastAccessTime);
|
||||
info->last_write_time_in_s = FileTimeToSeconds(&attrib_data.ftLastWriteTime);
|
||||
if (info)
|
||||
{
|
||||
info->create_time_in_s = FileTimeToSeconds(&attrib_data.ftCreationTime);
|
||||
info->last_access_time_in_s = FileTimeToSeconds(&attrib_data.ftLastAccessTime);
|
||||
info->last_write_time_in_s = FileTimeToSeconds(&attrib_data.ftLastWriteTime);
|
||||
|
||||
// TODO(doyle): What if usize is < Quad.part?
|
||||
LARGE_INTEGER large_int = {};
|
||||
large_int.HighPart = attrib_data.nFileSizeHigh;
|
||||
large_int.LowPart = attrib_data.nFileSizeLow;
|
||||
info->size = (usize)large_int.QuadPart;
|
||||
// TODO(doyle): What if usize is < Quad.part?
|
||||
LARGE_INTEGER large_int = {};
|
||||
large_int.HighPart = attrib_data.nFileSizeHigh;
|
||||
large_int.LowPart = attrib_data.nFileSizeLow;
|
||||
info->size = (usize)large_int.QuadPart;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -8419,10 +8433,13 @@ bool DqnFile_GetInfo(char const *path, DqnFileInfo *info)
|
||||
return false;
|
||||
}
|
||||
|
||||
info->size = file_stat.st_size;
|
||||
info->create_time_in_s = 0;
|
||||
info->last_write_time_in_s = file_stat.st_mtime;
|
||||
info->last_access_time_in_s = file_stat.st_atime;
|
||||
if (info)
|
||||
{
|
||||
info->size = file_stat.st_size;
|
||||
info->create_time_in_s = 0;
|
||||
info->last_write_time_in_s = file_stat.st_mtime;
|
||||
info->last_access_time_in_s = file_stat.st_atime;
|
||||
}
|
||||
|
||||
return true;
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user