Created
February 13, 2021 17:48
-
-
Save tetsuok/2a9c7a533dd02492f2680beb2d2c3235 to your computer and use it in GitHub Desktop.
Fast input reader for competitive programming
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <ctype.h> | |
#include <cstdio> | |
#include <cstdlib> | |
#include <cstring> | |
#include <string_view> | |
#include <type_traits> | |
namespace scan_internal { | |
enum Error { | |
NoError = 0, | |
BadReadCount, | |
}; | |
constexpr size_t kBufSize = 1 << 16; | |
char g_buf[kBufSize]; | |
class Scanner final { | |
public: | |
Scanner() {} | |
// No copying allowed. | |
Scanner(const Scanner&) = delete; | |
void operator=(const Scanner&) = delete; | |
std::string_view Token() const { return token_; } | |
bool Scan(); | |
private: | |
void ReadFromStream(); | |
size_t start_ = 0; | |
size_t end_ = 0; | |
bool done_ = false; | |
int error_ = NoError; | |
std::string_view token_; | |
}; | |
std::string_view ScanToken(std::string_view data, int& advance) { | |
// Ignore leading space | |
size_t start = 0; | |
for (auto c : data) { | |
if (!isspace(c)) break; | |
++start; | |
} | |
for (size_t i = start; i < data.size(); ++i) { | |
if (isspace(data[i])) { | |
advance = i + 1; | |
return data.substr(start, i - start); | |
} | |
} | |
advance = start; | |
return {}; | |
} | |
bool Scanner::Scan() { | |
if (done_) return false; | |
for (;;) { | |
if (end_ > start_) { | |
int advance = 0; | |
token_ = ScanToken({g_buf + start_, end_ - start_}, advance); | |
start_ += advance; | |
if (!token_.empty()) { | |
return true; | |
} | |
} | |
if (error_ != NoError) { | |
start_ = 0; | |
end_ = 0; | |
token_ = {}; | |
return false; | |
} | |
if (start_ > 0 && (end_ == kBufSize || start_ > kBufSize / 2)) { | |
std::memcpy(g_buf, g_buf + start_, end_ - start_); | |
end_ -= start_; | |
start_ = 0; | |
} | |
ReadFromStream(); | |
} | |
} | |
void Scanner::ReadFromStream() { | |
const size_t nread = | |
std::fread(g_buf + end_, sizeof(char), kBufSize - end_, stdin); | |
if (kBufSize - end_ < nread) { | |
error_ = BadReadCount; | |
return; | |
} | |
if (nread == 0) { | |
error_ = BadReadCount; | |
done_ = true; | |
return; | |
} | |
end_ += nread; | |
} | |
static Scanner g_scanner; | |
} // namespace scan_internal | |
template <typename T> | |
bool scan(T& out) { | |
const bool ok = scan_internal::g_scanner.Scan(); | |
auto token = scan_internal::g_scanner.Token(); | |
if constexpr (std::is_integral_v<T>) { | |
out = static_cast<T>(strtol(token.data(), (char**)nullptr, 10)); | |
} else if constexpr (std::is_floating_point_v<T>) { | |
out = atof(token.data()); | |
} else { | |
out = token; | |
} | |
return ok; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment