Ikaleio 特制超级快读

传送门:压行版代码

特性

  • ⚡ 极优秀的性能,再也不用担心读写卡常了!
  • 🔍 一行宏定义轻松开启缓存读写,专治毒瘤出题人!
  • 🌈 全部基础数据类型的读写支持
  • ⚙️ 简洁易用的 API,具备高度可扩展性
  • 😍 支持判断 EOF,手动刷新缓冲区,设置浮点输出精度等辅助功能
  • 📕 非常详细的文档
  • 😘 Ikaleio 信仰加成
  • 😅 长达 5KB 的代码,让你的教练骂娘
  • 🤡 一个浮点快写发了五个版本才正确实现,Ikaleio 太菜了!

用前须知

仅适用于 C++11 及以上,否则得到 CE 后果自负。

如果发生运行时错误并附有 [Floating point overflow] 开头的错误消息,说明你正在尝试输出一个超出 long long 范围( ±1018\pm 10^{18} )的超大浮点数。如果你确信你要输出的数没有这么离谱,说明你正在尝试输出 infinfnannan,请检查你的代码。(大部分的算法竞赛题目并不会要求你输出 infinfnannan,或以科学计数法输出实数。如果你确实需要,请自行修改 write(double) 函数)

IO 交互题请不要开启缓存模式,这会导致你读不到交互库的输入造成 TLE。

代码

引入快读代码之前需要先 using namespace std;

原版

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
/* Ikaleio FastIO ver. 5.0 */
#define dIO_USE_BUFFER // 本地调试时将这行注释掉,提交时取消注释
struct IO {
#ifdef dIO_USE_BUFFER
const static int BUFSIZE = 1 << 20;
char ibuf[BUFSIZE], obuf[BUFSIZE], *p1, *p2, *pp;
inline int getchar() {
return (p1 == p2 && (p2 = (p1 = ibuf) + fread(ibuf, 1, BUFSIZE, stdin), p1 == p2)
? EOF
: *p1++);
}
inline int putchar(char x) {
return ((pp - obuf == BUFSIZE && (fwrite(obuf, 1, BUFSIZE, stdout), pp = obuf)),
*pp = x,
pp++),
x;
}
inline IO &flush() {
return fwrite(obuf, 1, pp - obuf, stdout), pp = obuf, fflush(stdout), *this;
}
IO() { p1 = p2 = ibuf, pp = obuf; }
~IO() { flush(); }
#else
int (*getchar)() = &::getchar;
int (*putchar)(int) = &::putchar;
inline IO &flush() { return fflush(stdout), *this; }
#endif
string _sep = " ";
int k = 2;
template <typename Tp,
typename enable_if<is_integral<Tp>::value
|| is_same<Tp, __int128_t>::value>::type * = nullptr>
inline int read(Tp &s) {
int f = 1, ch = getchar();
s = 0;
while (!isdigit(ch) && ch != EOF) f = (ch == '-' ? -1 : 1), ch = getchar();
if (ch == EOF) return false;
while (ch == '0') ch = getchar();
while (isdigit(ch)) s = s * 10 + (ch ^ 48), ch = getchar();
s *= f;
return true;
}
template <typename Tp,
typename enable_if<is_floating_point<Tp>::value>::type * = nullptr>
inline int read(Tp &s) {
int f = 1, ch = getchar();
s = 0;
while (!isdigit(ch) && ch != '.' && ch != EOF)
f = (ch == '-' ? -1 : 1), ch = getchar();
if (ch == EOF) return false;
while (isdigit(ch)) s = s * 10 + (ch ^ 48), ch = getchar();
if (ch == '.') {
Tp eps = 0.1;
ch = getchar();
while (isdigit(ch)) s = s + (ch ^ 48) * eps, ch = getchar(), eps /= 10;
}
s *= f;
return true;
}
inline int read(char &ch) {
ch = getchar();
while (isspace(ch) && ch != EOF) ch = getchar();
return ch != EOF;
}
inline int read(char *c) {
char ch = getchar(), *s = c;
while (isspace(ch) && ch != EOF) ch = getchar();
while (!isspace(ch) && ch != EOF) *(c++) = ch, ch = getchar();
*c = '\0';
return s != c;
}
inline int read(string &s) {
s.clear();
char ch = getchar();
while (isspace(ch) && ch != EOF) ch = getchar();
while (!isspace(ch) && ch != EOF) s += ch, ch = getchar();
return s.size() > 0;
}
template <typename Tp = int> inline Tp read() {
Tp x;
read(x);
return x;
}
template <typename Tp, typename... Ts> inline int read(Tp &x, Ts &...val) {
return read(x) && read(val...);
}
inline int getline(char *c, const char &ed = '\n') {
char ch = getchar(), *s = c;
while (ch != ed && ch != EOF) *(c++) = ch, ch = getchar();
*c = '\0';
return s != c;
}
inline int getline(string &s, const char &ed = '\n') {
s.clear();
char ch = getchar();
while (ch != ed && ch != EOF) s += ch, ch = getchar();
return s.size() > 0;
}
template <typename Tp,
typename enable_if<is_integral<Tp>::value
|| is_same<Tp, __int128_t>::value>::type * = nullptr>
inline IO &write(Tp x) {
if (x < 0) putchar('-'), x = -x;
static char sta[41];
int top = 0;
do sta[top++] = x % 10 ^ 48, x /= 10;
while (x);
while (top) putchar(sta[--top]);
return *this;
}
inline IO &write(const string &str) {
for (char ch : str) putchar(ch);
return *this;
}
inline IO &write(const char *str) {
while (*str != '\0') putchar(*(str++));
return *this;
}
inline IO &write(char *str) { return write((const char *)str); }
inline IO &write(const char &ch) { return putchar(ch), *this; }
template <typename Tp,
typename enable_if<is_floating_point<Tp>::value>::type * = nullptr>
inline IO &write(Tp x) {
if (x > 1e18 || x < -1e18) {
write("[Floating point overflow]");
throw;
}
if (x < 0) putchar('-'), x = -x;
const static long long pow10[] = {1,
10,
100,
1000,
10000,
100000,
1000000,
10000000,
100000000,
1000000000,
10000000000,
100000000000,
1000000000000,
10000000000000,
100000000000000,
1000000000000000,
10000000000000000,
100000000000000000,
100000000000000000,
100000000000000000};
const auto &n = pow10[k];
long long whole = x;
double tmp = (x - whole) * n;
long long frac = tmp;
double diff = tmp - frac;
if (diff > 0.5) {
++frac;
if (frac >= n) frac = 0, ++whole;
} else if (diff == 0.5 && ((frac == 0U) || (frac & 1U)))
++frac;
write(whole);
if (k == 0U) {
diff = x - whole;
if ((!(diff < 0.5) || (diff > 0.5)) && (whole & 1)) ++whole;
} else {
putchar('.');
static char sta[21];
int count = k, top = 0;
while (frac) {
sta[top++] = frac % 10 ^ 48;
frac /= 10, count--;
}
while (count--) putchar('0');
while (top) putchar(sta[--top]);
}
return *this;
}
template <typename Tp, typename... Ts> inline IO &write(Tp x, Ts... val) {
return write(x), write(_sep), write(val...), *this;
}
template <typename... Ts> inline IO &writeln(Ts... val) {
return write(val...), putchar('\n'), *this;
}
template <typename... Ts> inline IO &writesp(Ts... val) {
return write(val...), putchar(' '), *this;
}
inline IO &writeln(void) { return putchar('\n'), *this; }
inline IO &sep(const string &s = " ") { return _sep = s, *this; }
inline IO &prec(const int &K = 2) { return k = K, *this; }
} io;

压行版

1
2
3
4
5
6
7
8
#define dIO_USE_BUFFER
struct IO{
#ifdef dIO_USE_BUFFER
const static int BUFSIZE=1<<20;char ibuf[BUFSIZE],obuf[BUFSIZE],*p1,*p2,*pp;inline int getchar(){return(p1==p2&&(p2=(p1=ibuf)+fread(ibuf,1,BUFSIZE,stdin),p1==p2)?EOF:*p1++);}inline int putchar(char x){return((pp-obuf==BUFSIZE&&(fwrite(obuf,1,BUFSIZE,stdout),pp=obuf)),*pp=x,pp++),x;}inline IO&flush(){return fwrite(obuf,1,pp-obuf,stdout),pp=obuf,fflush(stdout),*this;}IO(){p1=p2=ibuf,pp=obuf;}~IO(){flush();}
#else
int(*getchar)()=&::getchar;int(*putchar)(int)=&::putchar;inline IO&flush(){return fflush(stdout),*this;}
#endif
string _sep=" ";int k=2;template<typename Tp,typename enable_if<is_integral<Tp>::value||is_same<Tp,__int128_t>::value>::type* =nullptr>inline int read(Tp&s){int f=1,ch=getchar();s=0;while(!isdigit(ch)&&ch!=EOF)f=(ch=='-'?-1:1),ch=getchar();if(ch==EOF)return false;while(ch=='0')ch=getchar();while(isdigit(ch))s=s*10+(ch^48),ch=getchar();s*=f;return true;}template<typename Tp,typename enable_if<is_floating_point<Tp>::value>::type* =nullptr>inline int read(Tp&s){int f=1,ch=getchar();s=0;while(!isdigit(ch)&&ch!='.'&&ch!=EOF)f=(ch=='-'?-1:1),ch=getchar();if(ch==EOF)return false;while(isdigit(ch))s=s*10+(ch^48),ch=getchar();if(ch=='.'){Tp eps=0.1;ch=getchar();while(isdigit(ch))s=s+(ch^48)*eps,ch=getchar(),eps/=10;}s*=f;return true;}inline int read(char&ch){ch=getchar();while(isspace(ch)&&ch!=EOF)ch=getchar();return ch!=EOF;}inline int read(char*c){char ch=getchar(),*s=c;while(isspace(ch)&&ch!=EOF)ch=getchar();while(!isspace(ch)&&ch!=EOF)*(c++)=ch,ch=getchar();*c='\0';return s!=c;}inline int read(string&s){s.clear();char ch=getchar();while(isspace(ch)&&ch!=EOF)ch=getchar();while(!isspace(ch)&&ch!=EOF)s+=ch,ch=getchar();return s.size()>0;}template<typename Tp=int>inline Tp read(){Tp x;read(x);return x;}template<typename Tp,typename...Ts>inline int read(Tp&x,Ts&...val){return read(x)&&read(val...);}inline int getline(char*c,const char&ed='\n'){char ch=getchar(),*s=c;while(ch!=ed&&ch!=EOF)*(c++)=ch,ch=getchar();*c='\0';return s!=c;}inline int getline(string&s,const char&ed='\n'){s.clear();char ch=getchar();while(ch!=ed&&ch!=EOF)s+=ch,ch=getchar();return s.size()>0;}template<typename Tp,typename enable_if<is_integral<Tp>::value||is_same<Tp,__int128_t>::value>::type* =nullptr>inline IO&write(Tp x){if(x<0)putchar('-'),x=-x;static char sta[41];int top=0;do sta[top++]=x%10^48,x/=10;while(x);while(top)putchar(sta[--top]);return*this;}inline IO&write(const string&str){for(char ch:str)putchar(ch);return*this;}inline IO&write(const char*str){while(*str!='\0')putchar(*(str++));return*this;}inline IO&write(char*str){return write((const char*)str);}inline IO&write(const char&ch){return putchar(ch),*this;}template<typename Tp,typename enable_if<is_floating_point<Tp>::value>::type* =nullptr>inline IO&write(Tp x){if(x>1e18||x<-1e18){write("[Floating point overflow]");throw;}if(x<0)putchar('-'),x=-x;const static long long pow10[]={1,10,100,1000,10000,100000,1000000,10000000,100000000,1000000000,10000000000,100000000000,1000000000000,10000000000000,100000000000000,1000000000000000,10000000000000000,100000000000000000,100000000000000000,100000000000000000};const auto&n=pow10[k];long long whole=x;double tmp=(x-whole)*n;long long frac=tmp;double diff=tmp-frac;if(diff>0.5){++frac;if(frac>=n)frac=0,++whole;}else if(diff==0.5&&((frac==0U)||(frac&1U)))++frac;write(whole);if(k==0U){diff=x-whole;if((!(diff<0.5)||(diff>0.5))&&(whole&1))++whole;}else{putchar('.');static char sta[21];int count=k,top=0;while(frac){sta[top++]=frac%10^48;frac/=10,count--;}while(count--)putchar('0');while(top)putchar(sta[--top]);}return*this;}template<typename Tp,typename...Ts>inline IO&write(Tp x,Ts...val){return write(x),write(_sep),write(val...),*this;}template<typename...Ts>inline IO&writeln(Ts...val){return write(val...),putchar('\n'),*this;}template<typename...Ts>inline IO&writesp(Ts...val){return write(val...),putchar(' '),*this;}inline IO&writeln(void){return putchar('\n'),*this;}inline IO&sep(const string&s=" "){return _sep=s,*this;}inline IO&prec(const int&K=2){return k=K,*this;}}io;

(魔改完想自己打包?将代码放入 Mivik 的 C++ 压行机 压缩后将所有的 *=nullptr 替换为 * =nullptr 即可!)

用法

本模板实现了所有整数类型/所有浮点类型/字符类型/ std::string /C 风格字符串的读入/输出,且支持用户实现自定义 IO 函数。

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
/* 读入 */
int x = io.read(); // 返回值方式
io.read(x); // 传参方式

long long i64 = io.read<long long>(); // 可以通过模板指定返回值方式读入的数据类型,默认为 int
io.read(i64); // 若通过传参方式读入则会自动推断类型

double db;
string str;
io.read(x,i64,db,str); // 传参方式可以一次读入多个任意类型的数据

// 传参方式下的返回值用于判断 EOF,一种常见的使用场景是具有多组数据的题目
// 若成功读入,则返回 1,读到 EOF 则返回 0
// 如果一次读入多个变量,只要有任何一个变量读到 EOF 则立刻终止并返回 0,全部成功读取返回 1
while(io.read(x))
io.writeln(x);

/* 输出 */
io.write(x); // cout << x;
io.writeln(x); // cout << x << endl;

// cout << x << ' ' << i64 << ' ' << str << endl;
io.writeln(x,i64,str);

// 输出后加空格(用于输出数组等)
io.writesp(x); // cout << x << " ";

// prec(int) 用于设置浮点输出精度,默认保留两位小数
db = 3.1415926;
io.writeln(db); // 3.14
io.prec(5).writeln(db); //3.14159
io.prec(0).writeln(db); //3

// sep(string) 用于设置输出分隔符,默认为空格
// 同样的,参数只能为字符串!
x = 1,i64 = 2;
io.writeln(x,i64); // 1 2
io.sep(",").writeln(x,i64); // 1,2

// 一种常见的使用场景,用于实现格式化字符串的效果
int T = io.read(), a, b;
for(int t = 1; t <= T; t++){
io.read(a, b);
io.sep("").writeln("Test case #",t,": ",a + b).sep();
}
/*
输入:
2
1 2
5 5

输出:
Test case #1: 3
Test case #2: 10
*/

// 自定义 IO 函数
// putchar -> io.putchar
// getchar -> io.getchar
// 你应当把这个玩意放在 struct IO{} 外面
void writeString(string str){
for(char ch:str) io.putchar(ch);
}
writeString("Nr is very cute");

// 刷新输出缓冲区 和 IO 交互题
/*
默认情况下,缓存模式开启后输出会被保存到缓存中,当缓存区满或程序退出时会自动将缓存内的所有东西吐到 stdout(读入同理,fread 一次从 stdin 读入一大块东西到缓存,解析干净之后再读第二块,因此你不能在缓存模式开启时使用键盘输入,也不能在交互题中使用缓存模式)。

但是你可以用 io.flush() 函数手动刷新输出缓冲区,如果缓存模式开启,这会把输出缓存里所有东西吐到 stdout,否则会刷新 stdout 自带的缓存。

因此在 IO 交互题中关闭缓存模式并在每次输出后调用 io.flush(),就像使用 cout/printf 一样。
*/

io.writeln("Hello World!").flush();

// 叠叠乐
// 所有函数支持链式调用
io.setprec(3).writeln(114.514).setsep("").writeln("My name is Tadokoro Koji, my telephone number is ",1919810).setsep(" ").writeln("I am a 24-year-old student.");

性能

LOJ #7 / 读入 3×1063\times 10^6long long / 五组数据加和开启-O2优化不开启优化
调试模式(getchar)288ms479ms
缓存模式(fread)175ms429ms

Ikaleio 特制超级快读
https://blog.ikale.io/p/d420019/
作者
Ikaleio
发布于
2021年10月10日
许可协议
CC-BY-SA