Lumenarium/src/core/lumenarium_core_file.h

252 lines
6.2 KiB
C

#if !defined(LUMENARIUM_CORE_FILE_H)
#define LUMENARIUM_CORE_FILE_H
typedef struct File_Handle File_Handle;
struct File_Handle
{
u64 value;
};
typedef u32 File_Access_Flags;
enum
{
FileAccess_None = 0,
FileAccess_Read = 1,
FileAccess_Write = 2,
};
typedef u32 File_Create_Flags;
enum
{
// these match https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
FileCreate_None = 0,
// Creates a new file, only if it does not already exist.
// If the file exists, an error is returned
FileCreate_New = 1,
// Creates a new file, always.
// If the specified file exists and is writable, the file is overwritten
FileCreate_CreateAlways = 2,
// Opens a file or device, only if it exists.
FileCreate_OpenExisting = 3,
// Opens a file, always.
FileCreate_OpenAlways = 4,
};
typedef u32 File_Flags;
enum
{
FileFlag_IsFile = 0,
FileFlag_IsDir = 1,
};
typedef struct File_Info File_Info;
struct File_Info
{
String path;
String path_abs;
u64 size;
u64 time_created;
u64 time_last_write;
File_Flags flags;
};
typedef struct File_Info_List_Ele File_Info_List_Ele;
struct File_Info_List_Ele
{
File_Info info;
File_Info_List_Ele* next;
};
typedef struct File_Info_List File_Info_List;
struct File_Info_List
{
File_Info_List_Ele* first;
File_Info_List_Ele* last;
};
// For Cross Platform File Operations use these:
typedef u32 File_Async_Job_Flags;
enum
{
FileAsyncJob_Invalid = 0,
FileAsyncJob_Read = 1 << 0,
FileAsyncJob_Write = 1 << 1,
FileAsyncJob_InFlight = 1 << 2,
FileAsyncJob_Success = 1 << 3,
FileAsyncJob_Failed = 1 << 4,
};
typedef struct File_Async_Job_Args File_Async_Job_Args;
struct File_Async_Job_Args
{
String path;
Data data;
File_Async_Job_Flags flags;
u32 error;
};
typedef void File_Async_Cb(File_Async_Job_Args args, u8* user_data);
typedef struct File_Async_Job File_Async_Job;
struct File_Async_Job
{
Data job_memory;
File_Async_Job_Args args;
File_Async_Cb* cb;
};
typedef void File_Async_Job_System_Do_Job(File_Async_Job* job);
typedef struct File_Async_Job_System File_Async_Job_System;
struct File_Async_Job_System
{
File_Async_Job_System_Do_Job* do_job;
};
global Allocator* file_jobs_arena = 0;
#define FILE_ASYNC_MAX_JOBS 32
global File_Async_Job file_async_jobs[FILE_ASYNC_MAX_JOBS];
global u32 file_async_jobs_len = 0;
internal File_Async_Job_System file_async_jobs_init(File_Async_Job_System_Do_Job* do_job);
internal bool file_async_job_add(File_Async_Job job);
internal File_Async_Job file_async_job_rem(u64 index);
internal bool file_async_read(String path, File_Async_Cb* cb);
internal bool file_async_write(String path, Data data, File_Async_Cb* cb);
internal void file_async_job_complete(File_Async_Job* job, u8* user_data);
internal void file_async_jobs_do_work(File_Async_Job_System* system, u64 max_jobs, u8* user_data);
internal void file_async_jobs_do_work(File_Async_Job_System* system, u64 max_jobs, u8* user_data);
typedef u32 Platform_Enum_Dir_Flags;
enum
{
EnumDir_Recursive = 1,
EnumDir_IncludeDirectories = 2,
};
///////////////////////////////////////
///////////////////////////////////////
// IMPLEMENTATION
///////////////////////////////////////
///////////////////////////////////////
internal File_Async_Job_System
file_async_jobs_init(File_Async_Job_System_Do_Job* do_job)
{
file_jobs_arena = paged_allocator_create_reserve(MB(4), 256);
File_Async_Job_System result = {};
result.do_job = do_job;
return result;
}
internal bool
file_async_job_add(File_Async_Job job)
{
if (file_async_jobs_len >= FILE_ASYNC_MAX_JOBS) return false;
// Copy data to job local memory
u64 size_needed = job.args.path.len + job.args.data.size + 1;
u8* job_mem = allocator_alloc(file_jobs_arena, size_needed);
String job_path = string_create(job_mem, 0, job.args.path.len + 1);
u64 copied = string_copy_to(&job_path, job.args.path);
Data job_data = data_create(job_mem + job_path.cap + 1, size_needed - (job_path.cap + 1));
memory_copy(job.args.data.base, job_data.base, job.args.data.size);
job.args.path = job_path;
job.args.data = job_data;
job.job_memory = data_create(job_mem, size_needed);
file_async_jobs[file_async_jobs_len++] = job;
return true;
}
internal File_Async_Job
file_async_job_rem(u64 index)
{
assert(index < file_async_jobs_len);
File_Async_Job result = file_async_jobs[index];
file_async_jobs_len -= 1;
if (file_async_jobs_len > 0)
{
u32 last_job = file_async_jobs_len;
file_async_jobs[index] = file_async_jobs[last_job];
}
return result;
}
internal bool
file_async_read(String path, File_Async_Cb* cb)
{
File_Async_Job job = {};
job.args.path = path;
job.args.flags = (
FileAsyncJob_Read |
FileAsyncJob_InFlight
);
job.cb = cb;
bool result = file_async_job_add(job);
return result;
}
internal bool
file_async_write(String path, Data data, File_Async_Cb* cb)
{
File_Async_Job job = {};
job.args.path = path;
job.args.data = data;
job.args.flags = (
FileAsyncJob_Write |
FileAsyncJob_InFlight
);
job.cb = cb;
bool result = file_async_job_add(job);
return result;
}
internal void
file_async_job_complete(File_Async_Job* job, u8* user_data)
{
job->cb(job->args, user_data);
allocator_free(file_jobs_arena, job->job_memory.base, job->job_memory.size);
if (has_flag(job->args.flags, FileAsyncJob_Write))
{
allocator_free(file_jobs_arena, job->args.data.base, job->args.data.size);
}
}
internal void
file_async_jobs_do_work(File_Async_Job_System* system, u64 max_jobs, u8* user_data)
{
assert(system->do_job);
u64 to_do = max_jobs;
if (max_jobs > file_async_jobs_len) to_do = file_async_jobs_len;
File_Async_Job_Flags completed = (
FileAsyncJob_Success |
FileAsyncJob_Failed
);
for (u64 i = to_do - 1; i < to_do; i--)
{
File_Async_Job* job = file_async_jobs + i;
system->do_job(job);
if (has_flag(job->args.flags, completed))
{
if (has_flag_exact(job->args.flags, FileAsyncJob_Success))
{
file_async_job_complete(job, user_data);
}
file_async_job_rem(i);
}
}
}
#endif // LUMENARIUM_CORE_FILE_H