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
write_somemay do a partial write — it returns the first unwritten position.write_allloops until everything is written.- Every operation has a
_bytesvariant that takes::std::byte const*for binary data. pwrite_*operations write at a given offset without changing the file position (like POSIXpwrite()).scatter_write_*writes multiple buffers in one syscall (like POSIXwritev()) — avoids copying into a temporary contiguous buffer.scatter_pwrite_*combines scatter and positional writes.char_putwrites a single character — cheap on buffered devices, catastrophically slow on unbuffered ones.- Prefer
write_all(or buffered::fast_io::println) for most code. Reach forwrite_someonly when you need to handle partial writes yourself.