[video output=day015 member=cmuratori stream_platform=twitch stream_username=handmade_hero project=code title="Platform-independent Debug File I/O" vod_platform=youtube id=kdAte9pdLv8 annotator=garlandobloom annotator=jacebennett annotator=schme annotator=Miblo]
[01:26][Overview of the two classes of game file I/O]
[05:30][Today's goals (building a minimal set of I/O functions)]
[06:48][A brief lesson on the sad history of file I/O]
[12:40][The modern and better way of handling files]
[14:54][A first pass at the usage code]
[18:56][Locking our janky code out of the release build]
[22:01][Implementing the I/O functions in the platform layer]
[23:46][File handles and CreateFile() breakdown]
[29:07][GetFileSize() and GetFileSizeEx()]
[35:03][A janky situation with ReadFile()]
[37:07][An inline function, SafeTruncateUInt64()]
[43:15][Step-through of our read function]
[47:01][Making a write based on the read function]
[50:19][Using the write function]
[53:29][Step-through of the write function]
[56:40][Editing the .emacs file]
[58:27][Breaking the .emacs file]
[1:00:19][An IMPORTANT note on the safety of file I/O code]
[1:02:15][Q&A][:speech]
[1:02:54][Will the game be able to carry on in spite of some big time failure, like a graphics device reset. And does software rendering make that easier to deal with?]
[1:04:28][Would it make sense to call normal GetFileSize() and then assert that the high 32-bit value is zero?]
[1:06:00][Would it be useful for us to write our own allocation function that specifically allocates sections of our already-reserved temporary memory? I am having trouble understanding why we are doing separate allocations.]
[1:07:54][Will we implement some kind of cloud storage for the writes?]
[1:08:55][I know you removed it for now, but wouldn't a reserve memory method with an arbitrary size still introduce a failure point since it could fail like VirtualAlloc() and we have simply moved the burden onto ourselves?]
[1:09:59][You can reload your emacs settings without blowing everything up each time with evalbuffer.]
[1:10:55][Are there any other benefits to doing one massive allocation, aside from having one failure point. Also does the order of properties in your structs matter when it comes to performance efficiency?]
[1:16:00][Do games really usually write to a second file rather than using some soft of safe write function that won't overwrite it if it somehow fails?]
[1:17:31][Do you miss multiple return values in C?]
[1:18:30][Why don't we just map the file into memory?]
[1:19:19][Will allocating a single amount of memory up front make it more difficult to selectively enable/disable certain features of the game, since there could be many combinations, each requiring different amounts of memory?]
[1:20:32][Why does the order of fake_struct_a and b matter?]
[1:21:10][Why did you do the byte macros, but hesitate on the swap? Is there some hidden complexity on pointer swaps?]
[1:24:35][So structs with unions in them have bad performance issues?]
[1:25:11][You mentioned IOCP (I/O Completion Ports) for async file I/O. Are you planning to use multiple worker threads? I've been doing some multithreaded epoll code on Linux, and it's a very janky API unless you're using one worker thread. There are even a few articles on LWN.net only about how to safely remove a file descriptor with epoll.]
[1:26:27][On the swap, why does it have to be a macro. Wouldn't a function do the job and cover the janky complexity with types in the macro?]
[1:27:06][Why don't you define the swap macro to be #define swap(a,b){ type_of(a) temp...?]
[1:27:33][Does ArrayCount macro work with strings?]
[1:27:46][Won Chun: Async file I/O in Linux is nutty.]
[1:28:13][(Key Switches)Brown or blue?]
[1:28:53][It (ArrayCount) actually works with string literals.]
[/video]
