Skip to content

Instantly share code, notes, and snippets.

@tetsuok
Created February 13, 2021 17:48
Show Gist options
  • Save tetsuok/2a9c7a533dd02492f2680beb2d2c3235 to your computer and use it in GitHub Desktop.
Save tetsuok/2a9c7a533dd02492f2680beb2d2c3235 to your computer and use it in GitHub Desktop.
Fast input reader for competitive programming
#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