一个快速读写库。
使用方法
将 fastio.min.h
粘贴到自己代码前,将 fastio.cpp
粘贴到自己代码后(当然,代码前也可以)。
注意函数都在 mirai
命名空间内。
具体函数参数请看下文。
代码下载
- 直接下载文件 fastio.min.h fastio.h fastio.cpp;
- 访问 GitHub 的 Mirai 仓库;
- 在下面“代码”章节复制。
宏标记
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::read
和 mirai::sread
使用可变参数模板(C++11 特性)。如果以下两者都被满足,则库会忽略此宏:
- C++ 版本不到 C++11;
MIRAI_FORCE_USE_ARG_LIST
被打开。
MIRAI_FORCE_USE_ARG_LIST
强制对 mirai::read
和 mirai::sread
使用可变参数模板,忽略 C++ 版本。
MIRAI_ATTR_EXPECT
对 if
和 while
使用 [[likely]]
/[[unlikely]]
属性分支预测(C++20 特性)。如果以下两者都被满足,则库会忽略此宏:
- C++ 版本不到 C++20;
MIRAI_FORCE_ATTR_EXPECT
被打开。
MIRAI_FORCE_ATTR_EXPECT
强制对 if
和 while
使用 [[likely]]
/[[unlikely]]
属性分支预测,忽略 C++ 版本。
MIRAI_BUILTIN_EXPECT
对 if
和 while
使用 __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 | void sread(bool&); |
用 sscan
读入,然后强制转化成目标类型。
1 | void sread(char&); |
读入一个字符。不忽略空白字符。
1 | void sread(char*); |
读入一个 C 风格字符串。
1 | void read(float& 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 | void read(bool&); |
用 scan
读入,然后强制转化成目标类型。
1 | void read(char&); |
读入一个字符。不忽略空白字符。
1 | void read(char*); |
读入一个 C 风格字符串。
1 | void read(float& 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 | float readf(void); |
读入一个浮点数,支持的浮点数表达由以下部分组成:
- (可选)一个正号或负号;
- 一个非空数字串,中间有可选的一个小数点;
- (可选)一个
e
或E
,后紧跟:- (可选)一个正号或负号;
- 一个非空字符串。
效率还有很大优化空间。
(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 |
|
fastio.min.h
fastio.h 的最小化(主要是在行数上)版本。
1 |
|
fastio.cpp
1 | namespace mirai { |
fastio.min.h
1 |