Miscellany / Fast IO
8.2 Fast IO
Fast input and output wrappers based on fread() and fwrite(). For most problems, ios::sync_with_stdio(false); cin.tie(nullptr); is simpler and fast enough. Use these classes when input is huge or when iostream overhead is measurable.
set_in(name),set_out(name), andset_io(iname, oname)redirect standard input/output to files. For example,set_io("task.in", "task.out")is convenient for USACO-style problems.FastInput in(file = stdin)constructs a faster reader from aFILE*.in >> xreads a non-whitespace token intochar,std::string, integral types, or floating point types.FastOutput out(file = stdout)constructs a faster writer to aFILE*.out << xwriteschar, C strings,std::string, integral types, or floating point types.out.flush()writes any buffered output immediately.
The parser assumes valid input. Floating point input/output is provided for convenience, not as the main performance path.
Implementation
#include <cassert>
#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <limits>
#include <string>
#include <type_traits>
void set_in(const std::string &name) {
FILE *result = freopen(name.c_str(), "r", stdin);
assert(result != nullptr);
(void)result;
}
void set_out(const std::string &name) {
FILE *result = freopen(name.c_str(), "w", stdout);
assert(result != nullptr);
(void)result;
}
void set_io(const std::string &iname, const std::string &oname) {
set_in(iname);
set_out(oname);
}
struct FastInput {
static constexpr int BUF_SIZE = 1 << 20;
FILE *file;
char buf[BUF_SIZE];
int pos = 0, len = 0;
explicit FastInput(FILE *file_ = stdin) : file(file_) {}
FastInput(const FastInput &) = delete;
FastInput &operator=(const FastInput &) = delete;
char get_char() {
if (pos == len) {
len = static_cast<int>(fread(buf, 1, BUF_SIZE, file));
pos = 0;
if (len == 0) {
return 0;
}
}
return buf[pos++];
}
void skip_blanks() {
while (true) {
char c = get_char();
if (!c) {
return;
}
if (!std::isspace(static_cast<unsigned char>(c))) {
--pos;
return;
}
}
}
FastInput &operator>>(char &c) {
skip_blanks();
c = get_char();
return *this;
}
FastInput &operator>>(std::string &s) {
skip_blanks();
s.clear();
while (true) {
char c = get_char();
if (!c || std::isspace(static_cast<unsigned char>(c))) {
break;
}
s += c;
}
return *this;
}
FastInput &operator>>(bool &x) {
int val;
*this >> val;
x = val != 0;
return *this;
}
template<typename T>
typename std::enable_if<
std::is_integral<T>::value && !std::is_same<T, bool>::value, FastInput &>::type
operator>>(T &x) {
skip_blanks();
char c = get_char();
bool neg = false;
if (c == '-') {
neg = true;
c = get_char();
}
using U = typename std::make_unsigned<T>::type;
U val = 0;
while (c && !std::isspace(static_cast<unsigned char>(c))) {
val = U(10) * val + U(c - '0');
c = get_char();
}
if constexpr (std::is_signed<T>::value) {
x = neg ? T(U{0} - val) : T(val);
} else {
x = T(val);
}
return *this;
}
template<typename T>
typename std::enable_if<std::is_floating_point<T>::value, FastInput &>::type operator>>(T &x) {
std::string s;
*this >> s;
x = static_cast<T>(std::strtold(s.c_str(), nullptr));
return *this;
}
};
struct FastOutput {
static constexpr int BUF_SIZE = 1 << 20;
FILE *file;
char buf[BUF_SIZE];
int pos = 0;
explicit FastOutput(FILE *file_ = stdout) : file(file_) {}
~FastOutput() { flush(); }
FastOutput(const FastOutput &) = delete;
FastOutput &operator=(const FastOutput &) = delete;
void flush() {
if (pos) {
fwrite(buf, 1, pos, file);
pos = 0;
}
}
void put_char(char c) {
if (pos == BUF_SIZE) {
flush();
}
buf[pos++] = c;
}
FastOutput &operator<<(char c) {
put_char(c);
return *this;
}
FastOutput &operator<<(const char *s) {
while (*s) {
put_char(*s++);
}
return *this;
}
FastOutput &operator<<(const std::string &s) {
for (char c : s) {
put_char(c);
}
return *this;
}
FastOutput &operator<<(bool x) {
put_char(x ? '1' : '0');
return *this;
}
template<typename T>
typename std::enable_if<
std::is_integral<T>::value && !std::is_same<T, bool>::value, FastOutput &>::type
operator<<(T x) {
if (x == 0) {
put_char('0');
return *this;
}
using U = typename std::make_unsigned<T>::type;
U val;
if constexpr (std::is_signed<T>::value) {
if (x < 0) {
put_char('-');
val = U{0} - U(x);
} else {
val = U(x);
}
} else {
val = x;
}
char s[32];
int n = 0;
while (val > 0) {
s[n++] = char('0' + val % 10);
val /= 10;
}
while (n--) {
put_char(s[n]);
}
return *this;
}
template<typename T>
typename std::enable_if<std::is_floating_point<T>::value, FastOutput &>::type operator<<(T x) {
char s[64];
std::snprintf(
s, sizeof(s), "%.*Lg", std::numeric_limits<T>::max_digits10, static_cast<long double>(x)
);
return *this << s;
}
};
Example Usage
using namespace std;
int main() {
// set_io("file.in", "file.out");
FILE *input = tmpfile();
fputs("42 hello 3.5 -2147483648 1 Z 1234567890123\n", input);
rewind(input);
FastInput in(input);
int x;
string s;
double y;
int z;
bool flag;
char ch;
long long big;
in >> x >> s >> y >> z >> flag >> ch >> big;
assert(x == 42 && s == "hello" && y == 3.5);
assert(z == -2147483648);
assert(flag && ch == 'Z' && big == 1234567890123LL);
fclose(input);
FILE *output = tmpfile();
{
FastOutput out(output);
out << x << ' ' << s << ' ' << y << ' ' << z << ' ' << flag << ' ' << ch << ' ' << big << '\n';
out.flush();
}
rewind(output);
char buf[96] = {};
assert(fgets(buf, sizeof(buf), output));
assert(string(buf) == "42 hello 3.5 -2147483648 1 Z 1234567890123\n");
fclose(output);
return 0;
}
/*
Fast input and output wrappers based on `fread()` and `fwrite()`. For most problems,
`ios::sync_with_stdio(false); cin.tie(nullptr);` is simpler and fast enough. Use these classes when
input is huge or when `iostream` overhead is measurable.
- `set_in(name)`, `set_out(name)`, and `set_io(iname, oname)` redirect standard input/output to
files. For example, `set_io("task.in", "task.out")` is convenient for USACO-style problems.
- `FastInput in(file = stdin)` constructs a faster reader from a `FILE*`.
- `in >> x` reads a non-whitespace token into `char`, `std::string`, integral types, or floating
point types.
- `FastOutput out(file = stdout)` constructs a faster writer to a `FILE*`.
- `out << x` writes `char`, C strings, `std::string`, integral types, or floating point types.
- `out.flush()` writes any buffered output immediately.
The parser assumes valid input. Floating point input/output is provided for convenience, not as the
main performance path.
*/
#include <cassert>
#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <limits>
#include <string>
#include <type_traits>
void set_in(const std::string &name) {
FILE *result = freopen(name.c_str(), "r", stdin);
assert(result != nullptr);
(void)result;
}
void set_out(const std::string &name) {
FILE *result = freopen(name.c_str(), "w", stdout);
assert(result != nullptr);
(void)result;
}
void set_io(const std::string &iname, const std::string &oname) {
set_in(iname);
set_out(oname);
}
struct FastInput {
static constexpr int BUF_SIZE = 1 << 20;
FILE *file;
char buf[BUF_SIZE];
int pos = 0, len = 0;
explicit FastInput(FILE *file_ = stdin) : file(file_) {}
FastInput(const FastInput &) = delete;
FastInput &operator=(const FastInput &) = delete;
char get_char() {
if (pos == len) {
len = static_cast<int>(fread(buf, 1, BUF_SIZE, file));
pos = 0;
if (len == 0) {
return 0;
}
}
return buf[pos++];
}
void skip_blanks() {
while (true) {
char c = get_char();
if (!c) {
return;
}
if (!std::isspace(static_cast<unsigned char>(c))) {
--pos;
return;
}
}
}
FastInput &operator>>(char &c) {
skip_blanks();
c = get_char();
return *this;
}
FastInput &operator>>(std::string &s) {
skip_blanks();
s.clear();
while (true) {
char c = get_char();
if (!c || std::isspace(static_cast<unsigned char>(c))) {
break;
}
s += c;
}
return *this;
}
FastInput &operator>>(bool &x) {
int val;
*this >> val;
x = val != 0;
return *this;
}
template<typename T>
typename std::enable_if<
std::is_integral<T>::value && !std::is_same<T, bool>::value, FastInput &>::type
operator>>(T &x) {
skip_blanks();
char c = get_char();
bool neg = false;
if (c == '-') {
neg = true;
c = get_char();
}
using U = typename std::make_unsigned<T>::type;
U val = 0;
while (c && !std::isspace(static_cast<unsigned char>(c))) {
val = U(10) * val + U(c - '0');
c = get_char();
}
if constexpr (std::is_signed<T>::value) {
x = neg ? T(U{0} - val) : T(val);
} else {
x = T(val);
}
return *this;
}
template<typename T>
typename std::enable_if<std::is_floating_point<T>::value, FastInput &>::type operator>>(T &x) {
std::string s;
*this >> s;
x = static_cast<T>(std::strtold(s.c_str(), nullptr));
return *this;
}
};
struct FastOutput {
static constexpr int BUF_SIZE = 1 << 20;
FILE *file;
char buf[BUF_SIZE];
int pos = 0;
explicit FastOutput(FILE *file_ = stdout) : file(file_) {}
~FastOutput() { flush(); }
FastOutput(const FastOutput &) = delete;
FastOutput &operator=(const FastOutput &) = delete;
void flush() {
if (pos) {
fwrite(buf, 1, pos, file);
pos = 0;
}
}
void put_char(char c) {
if (pos == BUF_SIZE) {
flush();
}
buf[pos++] = c;
}
FastOutput &operator<<(char c) {
put_char(c);
return *this;
}
FastOutput &operator<<(const char *s) {
while (*s) {
put_char(*s++);
}
return *this;
}
FastOutput &operator<<(const std::string &s) {
for (char c : s) {
put_char(c);
}
return *this;
}
FastOutput &operator<<(bool x) {
put_char(x ? '1' : '0');
return *this;
}
template<typename T>
typename std::enable_if<
std::is_integral<T>::value && !std::is_same<T, bool>::value, FastOutput &>::type
operator<<(T x) {
if (x == 0) {
put_char('0');
return *this;
}
using U = typename std::make_unsigned<T>::type;
U val;
if constexpr (std::is_signed<T>::value) {
if (x < 0) {
put_char('-');
val = U{0} - U(x);
} else {
val = U(x);
}
} else {
val = x;
}
char s[32];
int n = 0;
while (val > 0) {
s[n++] = char('0' + val % 10);
val /= 10;
}
while (n--) {
put_char(s[n]);
}
return *this;
}
template<typename T>
typename std::enable_if<std::is_floating_point<T>::value, FastOutput &>::type operator<<(T x) {
char s[64];
std::snprintf(
s, sizeof(s), "%.*Lg", std::numeric_limits<T>::max_digits10, static_cast<long double>(x)
);
return *this << s;
}
};
/*** Example Usage ***/
using namespace std;
int main() {
// set_io("file.in", "file.out");
FILE *input = tmpfile();
fputs("42 hello 3.5 -2147483648 1 Z 1234567890123\n", input);
rewind(input);
FastInput in(input);
int x;
string s;
double y;
int z;
bool flag;
char ch;
long long big;
in >> x >> s >> y >> z >> flag >> ch >> big;
assert(x == 42 && s == "hello" && y == 3.5);
assert(z == -2147483648);
assert(flag && ch == 'Z' && big == 1234567890123LL);
fclose(input);
FILE *output = tmpfile();
{
FastOutput out(output);
out << x << ' ' << s << ' ' << y << ' ' << z << ' ' << flag << ' ' << ch << ' ' << big << '\n';
out.flush();
}
rewind(output);
char buf[96] = {};
assert(fgets(buf, sizeof(buf), output));
assert(string(buf) == "42 hello 3.5 -2147483648 1 Z 1234567890123\n");
fclose(output);
return 0;
}