一个快速读写库

一个快速读写库。

使用方法

fastio.min.h 粘贴到自己代码前,将 fastio.cpp 粘贴到自己代码后(当然,代码前也可以)。

注意函数都在 mirai 命名空间内。

具体函数参数请看下文。

代码下载

  1. 直接下载文件 fastio.min.h fastio.h fastio.cpp
  2. 访问 GitHub 的 Mirai 仓库;
  3. 在下面“代码”章节复制。

宏标记

MIRAI_INPUT_BUFFER

打开输入缓存。

MIRAI_INPUT_BUFFER_SIZE

应当能够被转化为 std::size_t 类型字面量。表示输入缓存的大小(具体实现会在末尾添加一位,值恒为 '\0')。缺省值为 (1UL << 22)

MIRAI_OUTPUT_BUFFER*

打开输出缓存。

MIRAI_OUTPUT_BUFFER_SIZE*

应当能够被转化为 std::size_t 类型字面量。表示输出缓存的大小。缺省值为 (1UL << 22)

MIRAI_USE_READ_FUNC

使用 unistd.h 内的 read 函数读取。

MIRAI_USE_ISDIGIT

使用 cctype 内的 std::isdigit 执行数字的判断。如果关闭则会使用 #define digit(x) ((x)>='0'&&(x)<='9') 宏。

MIRAI_USE_ARG_LIST

mirai::readmirai::sread 使用可变参数模板(C++11 特性)。如果以下两者都被满足,则库会忽略此宏:

  • C++ 版本不到 C++11;
  • MIRAI_FORCE_USE_ARG_LIST 被打开。

MIRAI_FORCE_USE_ARG_LIST

强制对 mirai::readmirai::sread 使用可变参数模板,忽略 C++ 版本。

MIRAI_ATTR_EXPECT

ifwhile 使用 [[likely]] /[[unlikely]] 属性分支预测(C++20 特性)。如果以下两者都被满足,则库会忽略此宏:

  • C++ 版本不到 C++20;
  • MIRAI_FORCE_ATTR_EXPECT 被打开。

MIRAI_FORCE_ATTR_EXPECT

强制对 ifwhile 使用 [[likely]] /[[unlikely]] 属性分支预测,忽略 C++ 版本。

MIRAI_BUILTIN_EXPECT

ifwhile 使用 __builtin_expect 分支预测。

函数

以下函数都在 mirai 命名空间内。

flush_input

1
void flush_input(void);

如果开启输入缓存,则刷新输入缓存。

sscan

1
long long sscan(void);

读入一个 long long 类型的数。支持的整数表达由如下两部分组成:

  • (可选)一个正号或负号;
  • 一个仅包含数字的字符串,表示整数的十进制表示。

无论读入多大的整数,都不会引起有符号整形溢出(Signed overflow)。如果输入值过大,返回值会为输入的整数对 ULLONG_MAX 取模再转化为 long long 的结果。

在实际读取中,所有正号都被忽略(即,不尾随数字的正号会被忽略);不尾随数字的负号会被识别为 0。

scan

1
unsigned long long scan(void);

读入一个 unsigned long long 类型的数。支持的整数表达由如下两部分组成:

  • (可选)一个正号。
  • 一个仅包含数字的字符串,表示整数的十进制表示。

无论读入多大的整数,都不会引起有符号整形溢出(Signed overflow)。如果输入值过大,返回值会为输入的整数对 ULLONG_MAX 取模的结果。

在实际读取中,所有正号都被忽略(即,不尾随数字的正号会被忽略)。

sread

1
2
3
4
5
6
7
8
9
void sread(bool&);
void sread(int&);
void sread(short&);
void sread(long&);
void sread(long long&);
void sread(unsigned int&);
void sread(unsigned short&);
void sread(unsigned long&);
void sread(unsigned long long&);

sscan 读入,然后强制转化成目标类型。

1
void sread(char&);

读入一个字符。不忽略空白字符。

1
void sread(char*);

读入一个 C 风格字符串。

1
2
3
void read(float& u);
void read(double& u);
void read(long double& u);

读入一个浮点类型。格式参考 readf

1
template <typename type> void sread(type&);

除上述特化以外皆没有实现。

1
template <typename type, typename... Args) void sread(type&, Args&... args);

按从前往后的顺序为传入的每个变量逐一读入。

如果 MIRAI_USE_ARG_LIST/MIRAI_FORCE_USE_ARG_LIST 未打开,则不会实现此函数。

read

1
2
3
4
5
6
7
8
9
void read(bool&);
void read(int&);
void read(short&);
void read(long&);
void read(long long&);
void read(unsigned int&);
void read(unsigned short&);
void read(unsigned long&);
void read(unsigned long long&);

scan 读入,然后强制转化成目标类型。

1
void read(char&);

读入一个字符。不忽略空白字符。

1
void read(char*);

读入一个 C 风格字符串。

1
2
3
void read(float& u);
void read(double& u);
void read(long double& u);

读入一个浮点类型。格式参考 readf

1
template <typename type> void read(type&);

除上述特化以外皆没有实现。

1
template <typename type, typename... Args) void read(type&, Args&... args);

按从前往后的顺序为传入的每个变量逐一读入。

如果 MIRAI_USE_ARG_LIST/MIRAI_FORCE_USE_ARG_LIST 未打开,则不会实现此函数。

readch

1
char readch(void);

读入一个字符。

readc

1
char readc(void);

读入一个字符,忽略空白字符。

readstr

1
void readstr(char*);

读入一个 C 风格字符串,到空白字符停止。

readf/readdf/readlf

1
2
3
float readf(void);
double readdf(void);
long double readlf(void);

读入一个浮点数,支持的浮点数表达由以下部分组成:

  • (可选)一个正号或负号;
  • 一个非空数字串,中间有可选的一个小数点;
  • (可选)一个 eE,后紧跟:
    • (可选)一个正号或负号;
    • 一个非空字符串。

效率还有很大优化空间。

(TODO)实现 scanf 的大多数功能

(TODO)添加输出缓存,并实现 printf 的大多数功能

效率测试

输入规模 std::scanf std::cin std::cin(关闭同步) scan,0B scan,25536B1 mirai::read(...) scan using read
$10^7$ 个 $32$ 位有符号(Linux) 795 2623 760 340 174 1718
1. 实测 Linux 上大约 $2^8$​ Byte 之后就不会怎么变动了,Windows 下的值大约是 $2^{16}$​ Byte。
log2(缓存大小) 0 1 log2(3) 2 log2(5) 3 4 5 6 7 8 9 10 11 12 13 14
std::fread 1372 802 572 471 384 353 275 238 211 200 197 194 185 183 180 182 178
read 25709 2550 2449 2513 2571 2591 2683 2843 3283 3940 5260 9030 13614 -2 -2 -2 -2
2. 太慢了,没测。

代码

fastio.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include <cstdio>
#include <cstdlib>
#include <cctype>
#include <cmath>

#define MIRAI_INPUT_BUFFER
#define MIRAI_INPUT_BUFFER_SIZE (1L << 16)
#define MIRAI_USE_ARG_LIST

#ifdef MIRAI_USE_READ_FUNC
#include <unistd.h>
#endif

namespace mirai {

void fflush_input(void);

long long sscan(void);
void sread(bool&);
void sread(int&);
void sread(short&);
void sread(long&);
void sread(long long&);
void sread(unsigned int&);
void sread(unsigned short&);
void sread(unsigned long&);
void sread(unsigned long long&);
void sread(char&);
void sread(char*);
void sread(float&);
void sread(double&);
void sread(long double&);
template <typename type> void sread(type&);
template <typename type, typename... Args> void sread(type&, Args&...);

unsigned long long scan(void);

void read(bool&);
void read(int&);
void read(short&);
void read(long&);
void read(long long&);
void read(unsigned int&);
void read(unsigned short&);
void read(unsigned long&);
void read(unsigned long long&);
void read(char&);
void read(char*);
void read(float&);
void read(double&);
void read(long double&);
template <typename type> void read(type&);
template <typename type, typename... Args> void read(type&, Args&...);
char readch(void);
char readc(void);
void readstr(char*);

float readf(void);
double readdf(void);
long double readlf(void);

} // namespace mirai

fastio.min.h

fastio.h 的最小化(主要是在行数上)版本。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <cstdio>
#include <cstdlib>
#include <cctype>
#include <cmath>
#include <unistd.h>
#define MIRAI_INPUT_BUFFER
#define MIRAI_INPUT_BUFFER_SIZE (1L << 16)
#define MIRAI_USE_ARG_LIST
#define ll long long
#define u unsigned
namespace mirai { void fflush_input(); ll sscan(); void sread(bool&); void sread(int&); void sread(u&);
void sread(short&); void sread(long&); void sread(ll&); void sread(u short&); void sread(u long&); void sread(u ll&);
void sread(char&); void sread(char*); void sread(float&); void sread(double&); void sread(long double&);
template <typename type> void sread(type&); template <typename type, typename... Args> void sread(type&, Args&...);
u ll scan(); void read(bool&); void read(int&); void read(short&); void read(long&); void read(ll&); void read(u int&);
void read(u short&); void read(u long&); void read(u ll&); void read(char&); void read(char*); void read(float&);
void read(double&); void read(long double&); template <typename type> void read(type&);
template <typename type, typename... Args> void read(type&, Args&...); char readch(); char readc(); void readstr(char*);
float readf(); double readdf(); long double readlf(); }
#undef u
#undef ll

fastio.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
namespace mirai {

#if !defined(MIRAI_FORCE_USE_ARG_LIST) && defined(MIRAI_USE_ARG_LIST) && \
__cplusplus < 201103L
#error MIRAI_USE_ARG_LIST needs C++11 to enable. \
use MIRAI_FORCE_USE_ARG_LIST if really need.
#endif
#ifdef MIRAI_FORCE_USE_ARG_LIST
#define MIRAI_USE_ARG_LIST
#endif

#if !defined(MIRAI_FORCE_ATTR_EXPECT) && defined(MIRAI_ATTR_EXPECT) && \
__cplusplus < 202002L
#error MIRAI_ATTR_EXPECT needs C++20 to enable. \
use MIRAI_FORCE_ATTR_EXPECT if really need.
#undef MIRAI_ATTR_EXPECT
#endif
#ifdef MIRAI_FORCE_ATTR_EXPECT
#define MIRAI_ATTR_EXPECT
#endif

#ifdef MIRAI_ATTR_EXPECT
#define ift(x) [[likely]] if (x)
#define iff(x) [[unlikely]] if (x)
#define whilet(x) [[unlikely]] while (x)
#define whilef(x) [[likely]] while (x)
#elif defined(MIRAI_BUILTIN_EXPECT)
#define ift(x) if (__builtin_expect(!!(x), 1))
#define iff(x) if (__builtin_expect(!!(x), 0))
#define whilet(x) while (__builtin_expect(!!(x), 1))
#define whilef(x) while (__builtin_expect(!!(x), 0))
#else
#define ift(x) if (x)
#define iff(x) if (x)
#define whilet(x) while (x)
#define whilef(x) while (x)
#endif

#ifndef MIRAI_INPUT_BUFFER_SIZE
#define MIRAI_INPUT_BUFFER_SIZE (1UL << 16)
#endif
#ifndef MIRAI_OUTPUT_BUFFER_SIZE
#define MIRAI_OUTPUT_BUFFER_SIZE (1UL << 16)
#endif

#ifdef MIRAI_INPUT_BUFFER
// let *input_buffer_end = '\0'.
char input_buffer[MIRAI_INPUT_BUFFER_SIZE + 1];
char *input_buffer_now = input_buffer;
char *input_buffer_end = input_buffer + MIRAI_INPUT_BUFFER_SIZE;

void flush_input(void) {
#ifdef MIRAI_USE_READ_FUNC
std::size_t ret = ::read(0, input_buffer, MIRAI_INPUT_BUFFER_SIZE);
#else
std::size_t ret = std::fread(input_buffer, sizeof(input_buffer[0]),
MIRAI_INPUT_BUFFER_SIZE, stdin);
#endif
iff(ret < MIRAI_INPUT_BUFFER_SIZE) {
input_buffer[ret] = '\0';
}
input_buffer_now = input_buffer;
return;
}
#else
void flush_input(void) {}
#endif

#ifndef MIRAI_INPUT_BUFFER
#define readchar() (std::getchar())
#else
char readchar(void) {
iff(input_buffer_now == input_buffer_end) {
flush_input();
}
return *(input_buffer_now++);
}
#endif

#ifdef MIRAI_USE_ISDIGIT
#define digit(x) (std::isdigit(x))
#else
#define digit(x) ((x) >= '0' && (x) <= '9')
#endif

void readstr(char*);

long long sscan(void) {
char ch = readchar();
whilet(!digit(ch) && ch != '-') {
ch = readchar();
}
unsigned long long ret = 0;
bool flag = false;
iff(ch != '-') {
ret = ch - '0';
} else {
flag = true;
}
ch = readchar();
whilet(digit(ch)) {
ret = ret * 10 + ch - '0';
ch = readchar();
}
iff(flag) {
return -ret;
} else {
return ret;
}
}

void sread(bool& u) { u = sscan(); }
void sread(int& u) { u = sscan(); }
void sread(short& u) { u = sscan(); }
void sread(long& u) { u = sscan(); }
void sread(long long& u) { u = sscan(); }
void sread(unsigned int& u) { u = sscan(); }
void sread(unsigned short& u) { u = sscan(); }
void sread(unsigned long& u) { u = sscan(); }
void sread(unsigned long long& u) { u = sscan(); }

void sread(char& u) {
u = readchar();
return;
}
void sread(char* str) {
readstr(str);
return;
}

void sread(float& u) { u = readf(); }
void sread(double& u) { u = readdf(); }
void sread(long double& u) { u = readlf(); }

#ifdef MIRAI_USE_ARG_LIST
// Very SLOW.
template <typename type, typename... Args>
void sread(type &u, Args&... args) {
sread(u);
sread(args...);
return;
}
#endif

// ignores character '-'.
unsigned long long scan(void) {
char ch = readchar();
whilet(!digit(ch)) {
ch = readchar();
}
unsigned long long ret = ch - '0';
ch = readchar();
whilet(digit(ch)) {
ret = ret * 10 + ch - '0';
ch = readchar();
}
return ret;
}

void read(bool& u) { u = scan(); }
void read(int& u) { u = scan(); }
void read(short& u) { u = scan(); }
void read(long& u) { u = scan(); }
void read(long long& u) { u = scan(); }
void read(unsigned int& u) { u = scan(); }
void read(unsigned short& u) { u = scan(); }
void read(unsigned long& u) { u = scan(); }
void read(unsigned long long& u) { u = scan(); }

void read(char& u) {
u = readchar();
}
void read(char* str) {
readstr(str);
return;
}

void read(float& u) { u = readf(); }
void read(double& u) { u = readdf(); }
void read(long double& u) { u = readlf(); }

#ifdef MIRAI_USE_ARG_LIST
// Very SLOW.
template <typename type, typename... Args>
void read(type &u, Args&... args) {
read(u);
read(args...);
return;
}
#endif

char readch(void) {
char ch;
ch = readchar();
return ch;
}
char readc(void) {
char ch;
ch = readchar();
whilet(std::isblank(ch)) {
ch = readchar();
}
return ch;
}

void readstr(char* str) {
*str = readchar();
whilef(std::isblank(*str)) {
*str = readchar();
str++;
}
*str = '\0';
return;
}

float readf(void) {
float x = 0;
char ch = readchar();
whilet(!digit(ch) && ch != '-') {
ch = readchar();
}
bool flag = false;
iff(ch == '-') {
flag = true;
} else iff(ch != '+' && ch != '.') {
x = ch - '0';
}
ch = readchar();
whilet(digit(ch)) {
x = x * 10 + ch - '0';
ch = readchar();
}
ift(ch == '.') {
float tmp = 0;
tmp = 0.1;
ch = readchar();
whilet(digit(ch)) {
x += tmp * (ch - '0');
tmp = tmp * 0.1;
ch = readchar();
}
}
ift(ch == 'e' || ch == 'E') {
unsigned int y = 0, cnt = 6;
ch = readchar();
bool flag2 = false;
iff(ch == '-') {
flag2 = true;
} else ift(digit(ch)) {
y = ch - '0';
cnt--;
}
ch = readchar();
whilet(digit(ch) && cnt) {
y = y * 10 + (ch - '0');
cnt--;
ch = readchar();
}
if (digit(ch) && cnt == 0) {
while (digit(ch)) {
ch = readchar();
}
}
if (flag2) {
x = x * std::pow(10.F, -1.F * y);
} else {
x = x * std::pow<float, float>(10, y);
}
}
iff(flag) {
return -x;
} else {
return x;
}
}
double readdf(void) {
double x = 0;
char ch = readchar();
whilet(!digit(ch) && ch != '-') {
ch = readchar();
}
bool flag = false;
iff(ch == '-') {
flag = true;
} else iff(ch != '+' && ch != '.') {
x = ch - '0';
}
ch = readchar();
whilet(digit(ch)) {
x = x * 10 + ch - '0';
ch = readchar();
}
ift(ch == '.') {
double tmp = 0;
tmp = 0.1;
ch = readchar();
whilet(digit(ch)) {
x += tmp * (ch - '0');
tmp = tmp * 0.1;
ch = readchar();
}
}
ift(ch == 'e' || ch == 'E') {
unsigned int y = 0, cnt = 6;
ch = readchar();
bool flag2 = false;
iff(ch == '-') {
flag2 = true;
} else ift(digit(ch)) {
y = ch - '0';
cnt--;
}
ch = readchar();
whilet(digit(ch) && cnt) {
y = y * 10 + (ch - '0');
cnt--;
ch = readchar();
}
if (digit(ch) && cnt == 0) {
while (digit(ch)) {
ch = readchar();
}
}
if (flag2) {
x = x * std::pow(10.F, -1.F * y);
} else {
x = x * std::pow<double, double>(10, y);
}
}
iff(flag) {
return -x;
} else {
return x;
}
}
long double readlf(void) {
long double x = 0;
char ch = readchar();
whilet(!digit(ch) && ch != '-') {
ch = readchar();
}
bool flag = false;
iff(ch == '-') {
flag = true;
} else iff(ch != '+' && ch != '.') {
x = ch - '0';
}
ch = readchar();
whilet(digit(ch)) {
x = x * 10 + ch - '0';
ch = readchar();
}
ift(ch == '.') {
long double tmp = 0;
tmp = 0.1;
ch = readchar();
whilet(digit(ch)) {
x += tmp * (ch - '0');
tmp = tmp * 0.1;
ch = readchar();
}
}
ift(ch == 'e' || ch == 'E') {
unsigned int y = 0, cnt = 6;
ch = readchar();
bool flag2 = false;
iff(ch == '-') {
flag2 = true;
} else ift(digit(ch)) {
y = ch - '0';
cnt--;
}
ch = readchar();
whilet(digit(ch) && cnt) {
y = y * 10 + (ch - '0');
cnt--;
ch = readchar();
}
if (digit(ch) && cnt == 0) {
while (digit(ch)) {
ch = readchar();
}
}
if (flag2) {
x = x * std::pow(10.L, -1.L * y);
} else {
x = x * std::pow<long double, long double>(10, y);
}
}
iff(flag) {
return -x;
} else {
return x;
}
}

#undef ift
#undef iff
#undef whilet
#undef whilef
#undef digit
#undef readchar

} // namespace mirai

fastio.min.h

1