Ch11.4: I/O Operations

Overview

All low-level I/O operations live in the ::fast_io::operations namespace. These are the raw building blocks that higher-level functions like ::fast_io::println and ::fast_io::read are built on. You rarely need to call them directly, but understanding them is important for performance-critical code and for writing custom devices.

1. write_some / write_all

write_some attempts to write a contiguous buffer to a device. It may write fewer bytes than requested and returns a pointer to the first unwritten character. This mirrors the semantics of POSIX write() — a short write is not an error.

write_all loops internally until every byte has been written or a hard error occurs. This is what you usually want.


#include <fast_io.h>
#include <fast_io_device.h>

int main() {
    ::fast_io::obuf_file obf{"output.txt"};

    char const message[] = "Hello, fast_io operations!\n";
    char const* first{message};
    char const* last{message + sizeof(message) - 1}; // exclude null terminator

    // write_some: may do a partial write.
    // Returns pointer to first unwritten char.
    char const* next = ::fast_io::operations::write_some(obf, first, last);

    // Write the rest with write_all (loops until done)
    ::fast_io::operations::write_all(obf, next, last);
}

2. write_some_bytes / write_all_bytes

Identical to write_some / write_all but operate on ::std::byte const* instead of char const*. Use these for binary data.


#include <fast_io.h>
#include <fast_io_device.h>
#include <cstddef>

int main() {
    ::fast_io::obuf_file obf{"binary.bin"};

    ::std::byte const data[]{
        ::std::byte{0xDE}, ::std::byte{0xAD},
        ::std::byte{0xBE}, ::std::byte{0xEF}
    };

    ::std::byte const* first{data};
    ::std::byte const* last{data + 4uz};

    // Write all bytes (loops until complete)
    ::fast_io::operations::write_all_bytes(obf, first, last);
}

3. pwrite_some / pwrite_all

Positional writes — write at a given file offset without changing the file’s current position. This mirrors POSIX pwrite(). Useful for concurrent writers that must not disturb each other’s file position.

The signature takes an extra offset parameter (in bytes from the start of the file).


#include <fast_io.h>
#include <fast_io_device.h>

int main() {
    ::fast_io::obuf_file obf{"data.bin",
        ::fast_io::open_mode::out | ::fast_io::open_mode::trunc};

    char const block0[] = "AAAA";
    char const block1[] = "BBBB";

    // Write "BBBB" at offset 1024 without moving the file position
    ::fast_io::operations::pwrite_all(obf, block1, block1 + 4uz, 1024uz);

    // Write "AAAA" at offset 0; file position is still 0
    ::fast_io::operations::pwrite_all(obf, block0, block0 + 4uz, 0uz);
}

4. pwrite_some_bytes / pwrite_all_bytes

Same as pwrite_some / pwrite_all but accept ::std::byte const*. Use for binary positional writes.


#include <fast_io.h>
#include <fast_io_device.h>
#include <cstddef>

int main() {
    ::fast_io::obuf_file obf{"binary.bin",
        ::fast_io::open_mode::out | ::fast_io::open_mode::trunc};

    ::std::byte const header[]{
        ::std::byte{0x89}, ::std::byte{0x50},
        ::std::byte{0x4E}, ::std::byte{0x47}
    };

    ::fast_io::operations::pwrite_all_bytes(obf, header, header + 4uz, 0uz);
}

5. scatter_write_some / scatter_write_all

Scatter (gather) writes write multiple non-contiguous buffers in a single syscall — equivalent to POSIX writev(). This avoids copying scattered data into a temporary contiguous buffer.

The argument is a span of ::fast_io::io_scatter_t, each describing one base/length pair.


#include <fast_io.h>
#include <fast_io_device.h>

int main() {
    ::fast_io::obuf_file obf{"scatter.txt"};

    char const part1[] = "Hello, ";
    char const part2[] = "scatter ";
    char const part3[] = "write!\n";

    ::fast_io::io_scatter_t const scatters[]{
        {part1, sizeof(part1) - 1uz},
        {part2, sizeof(part2) - 1uz},
        {part3, sizeof(part3) - 1uz},
    };

    // One syscall writes all three parts
    ::fast_io::operations::scatter_write_all(obf, scatters, scatters + 3uz);
}

6. scatter_pwrite_some / scatter_pwrite_all

Combines scatter writes with positional writes — writes multiple buffers at a given offset without changing the file position. This is the scatter equivalent of pwritev().


#include <fast_io.h>
#include <fast_io_device.h>

int main() {
    ::fast_io::obuf_file obf{"scatter_pos.bin",
        ::fast_io::open_mode::out | ::fast_io::open_mode::trunc};

    char const part1[] = "AAA";
    char const part2[] = "BBB";

    ::fast_io::io_scatter_t const scatters[]{
        {part1, 3uz},
        {part2, 3uz},
    };

    // Write "AAABBB" at offset 512, file position unchanged
    ::fast_io::operations::scatter_pwrite_all(obf, scatters, scatters + 2uz, 512uz);
}

7. char_put

Writes a single character. All write variants also have a char_put counterpart for emitting one character at a time.


#include <fast_io.h>
#include <fast_io_device.h>

int main() {
    ::fast_io::obuf_file obf{"chars.txt"};

    ::fast_io::operations::char_put(obf, 'H');
    ::fast_io::operations::char_put(obf, 'i');
    ::fast_io::operations::char_put(obf, '\n');
}

For buffered devices (obuf_file), repeated char_put calls are cheap — they just write into the user-space buffer. For unbuffered devices (native_file), each char_put is a syscall — extremely slow. See Ch11.5.

8. Complete Reference Table

Operation Pointer Type Positional? Scatter? Loops?
write_some char const* No No No (partial OK)
write_all char const* No No Yes
write_some_bytes ::std::byte const* No No No (partial OK)
write_all_bytes ::std::byte const* No No Yes
pwrite_some char const* Yes No No (partial OK)
pwrite_all char const* Yes No Yes
pwrite_some_bytes ::std::byte const* Yes No No (partial OK)
pwrite_all_bytes ::std::byte const* Yes No Yes
scatter_write_some char (scatter) No Yes No (partial OK)
scatter_write_all char (scatter) No Yes Yes
scatter_pwrite_some char (scatter) Yes Yes No (partial OK)
scatter_pwrite_all char (scatter) Yes Yes Yes
char_put single char No No N/A

Key takeaways