This documentation is automatically generated by online-judge-tools/verification-helper
when not declared CPLIB_TMPL_FASTIO:
const CPLIB_TMPL_FASTIO* = 1
{.passC: "-mavx2".}
# mmapは明示指定時のみ使用する。旧来の無効化指定も優先して尊重する。
when not defined(fastioMmap) or defined(fastioNoMmap):
{.passC: "-DCPLIB_FASTIO_NO_MMAP".}
import macros
# 入力系
{.emit: """
#include <cstdio>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <immintrin.h>
#include <string>
#include <sys/mman.h>
#include <sys/stat.h>
namespace cplib_fastio_input {
constexpr std::size_t buffer_size = 1U << 20;
constexpr std::size_t safe_integer_bytes = 32;
struct InputState {
alignas(64) char buffer[buffer_size];
std::size_t cursor;
std::size_t length;
const char* mapped;
bool initialized;
};
inline InputState& input_state() {
static InputState state = {};
return state;
}
inline std::string& token_storage() {
static std::string storage;
return storage;
}
#if defined(__GNUC__) || defined(__clang__)
#define CPLIB_FASTIO_ALWAYS_INLINE inline __attribute__((always_inline))
#define CPLIB_FASTIO_NIM_ALWAYS_INLINE \
static inline __attribute__((always_inline))
#define CPLIB_FASTIO_UNLIKELY(condition) (__builtin_expect(!!(condition), 0))
#elif defined(_MSC_VER)
#define CPLIB_FASTIO_ALWAYS_INLINE __forceinline
#define CPLIB_FASTIO_NIM_ALWAYS_INLINE static __forceinline
#define CPLIB_FASTIO_UNLIKELY(condition) (condition)
#else
#define CPLIB_FASTIO_ALWAYS_INLINE inline
#define CPLIB_FASTIO_NIM_ALWAYS_INLINE static inline
#define CPLIB_FASTIO_UNLIKELY(condition) (condition)
#endif
inline void initialize(InputState& state) {
if (state.initialized) return;
state.initialized = true;
#ifndef CPLIB_FASTIO_NO_MMAP
struct stat st;
const int fd = fileno(stdin);
if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode) && st.st_size > 0) {
void* p = mmap(nullptr, static_cast<std::size_t>(st.st_size),
PROT_READ, MAP_PRIVATE, fd, 0);
if (p != MAP_FAILED) {
state.mapped = static_cast<const char*>(p);
state.length = static_cast<std::size_t>(st.st_size);
madvise(const_cast<char*>(state.mapped), state.length,
MADV_SEQUENTIAL);
}
}
#endif
}
inline bool refill(InputState& state) {
state.length =
fread_unlocked(state.buffer, 1, buffer_size, stdin);
state.cursor = 0;
return state.length != 0;
}
inline int get_char() {
InputState& state = input_state();
if (CPLIB_FASTIO_UNLIKELY(!state.initialized)) initialize(state);
if (state.mapped != nullptr) {
if (state.cursor == state.length) return -1;
return static_cast<unsigned char>(state.mapped[state.cursor++]);
}
if (state.cursor == state.length && !refill(state)) return -1;
return static_cast<unsigned char>(state.buffer[state.cursor++]);
}
inline bool has_eight_digits(const char* source) {
// 正しい整数入力では、数字・符号・空白を上位4bitだけで判別できる。
std::uint64_t bytes;
std::memcpy(&bytes, source, sizeof(bytes));
return ((bytes ^ 0x3030303030303030ULL) &
0xf0f0f0f0f0f0f0f0ULL) == 0;
}
inline unsigned parse_eight_digits(const char* source) {
std::uint64_t digits;
std::memcpy(&digits, source, sizeof(digits));
digits ^= 0x3030303030303030ULL;
digits = (digits * ((10ULL << 8) + 1) >> 8) &
0x00ff00ff00ff00ffULL;
digits = (digits * ((100ULL << 16) + 1) >> 16) &
0x0000ffff0000ffffULL;
return static_cast<unsigned>(
digits * ((10000ULL << 32) + 1) >> 32);
}
inline unsigned digit_at(const char* source) {
return static_cast<unsigned>(static_cast<unsigned char>(*source)) -
static_cast<unsigned>('0');
}
template <bool negative>
CPLIB_FASTIO_ALWAYS_INLINE bool try_parse_digits_unchecked(
const char*& source, long long& output) {
long long value = 0;
if (has_eight_digits(source)) {
const long long digits =
static_cast<long long>(parse_eight_digits(source));
value = negative ? value * 100000000LL - digits
: value * 100000000LL + digits;
source += 8;
if (has_eight_digits(source)) {
const long long next_digits =
static_cast<long long>(parse_eight_digits(source));
value = negative ? value * 100000000LL - next_digits
: value * 100000000LL + next_digits;
source += 8;
for (int pair = 0; pair < 2; ++pair) {
const unsigned first = digit_at(source);
if (first >= 10U) {
output = value;
return true;
}
const unsigned second = digit_at(source + 1);
if (second >= 10U) {
++source;
output = negative
? value * 10 - static_cast<long long>(first)
: value * 10 + static_cast<long long>(first);
return true;
}
value = negative
? value * 100 - static_cast<long long>(first * 10U + second)
: value * 100 + static_cast<long long>(first * 10U + second);
source += 2;
}
if (digit_at(source) < 10U) return false;
output = value;
return true;
}
}
for (;;) {
const unsigned first = digit_at(source);
if (first >= 10U) {
output = value;
return true;
}
const unsigned second = digit_at(source + 1);
if (second >= 10U) {
++source;
output = negative ? value * 10 - static_cast<long long>(first)
: value * 10 + static_cast<long long>(first);
return true;
}
value = negative
? value * 100 - static_cast<long long>(first * 10U + second)
: value * 100 + static_cast<long long>(first * 10U + second);
source += 2;
}
}
template <bool negative>
inline long long parse_digits_bounded(const char*& source,
const char* end) {
long long value = 0;
while (end - source >= 8 && has_eight_digits(source)) {
const long long digits =
static_cast<long long>(parse_eight_digits(source));
value = negative ? value * 100000000LL - digits
: value * 100000000LL + digits;
source += 8;
}
while (end - source >= 2) {
const unsigned first = digit_at(source);
const unsigned second = digit_at(source + 1);
if (first >= 10U) return value;
if (second >= 10U) {
++source;
return negative ? value * 10 - static_cast<long long>(first)
: value * 10 + static_cast<long long>(first);
}
value = negative
? value * 100 - static_cast<long long>(first * 10U + second)
: value * 100 + static_cast<long long>(first * 10U + second);
source += 2;
}
if (source != end) {
const unsigned digit = digit_at(source);
if (digit < 10U) {
value = negative ? value * 10 - static_cast<long long>(digit)
: value * 10 + static_cast<long long>(digit);
++source;
}
}
return value;
}
CPLIB_FASTIO_ALWAYS_INLINE bool try_parse_unsigned_digits_unchecked(
const char*& source, unsigned long long& output) {
unsigned long long value = 0;
if (has_eight_digits(source)) {
value = static_cast<unsigned long long>(parse_eight_digits(source));
source += 8;
if (has_eight_digits(source)) {
value = value * 100000000ULL +
static_cast<unsigned long long>(parse_eight_digits(source));
source += 8;
for (int pair = 0; pair < 2; ++pair) {
const unsigned first = digit_at(source);
if (first >= 10U) {
output = value;
return true;
}
const unsigned second = digit_at(source + 1);
if (second >= 10U) {
++source;
output = value * 10ULL + first;
return true;
}
value = value * 100ULL + first * 10U + second;
source += 2;
}
if (digit_at(source) < 10U) return false;
output = value;
return true;
}
}
for (;;) {
const unsigned first = digit_at(source);
if (first >= 10U) {
output = value;
return true;
}
const unsigned second = digit_at(source + 1);
if (second >= 10U) {
++source;
output = value * 10ULL + first;
return true;
}
value = value * 100ULL + first * 10U + second;
source += 2;
}
}
inline unsigned long long parse_unsigned_digits_bounded(
const char*& source, const char* end) {
unsigned long long value = 0;
while (end - source >= 8 && has_eight_digits(source)) {
value = value * 100000000ULL +
static_cast<unsigned long long>(parse_eight_digits(source));
source += 8;
}
while (end - source >= 2) {
const unsigned first = digit_at(source);
const unsigned second = digit_at(source + 1);
if (first >= 10U) return value;
if (second >= 10U) {
++source;
return value * 10ULL + first;
}
value = value * 100ULL + first * 10U + second;
source += 2;
}
if (source != end) {
const unsigned digit = digit_at(source);
if (digit < 10U) {
value = value * 10ULL + digit;
++source;
}
}
return value;
}
CPLIB_FASTIO_ALWAYS_INLINE long long read_mapped_at(
const char*& source, const char* end) {
while (source != end &&
static_cast<unsigned char>(*source) <=
static_cast<unsigned char>(' ')) {
++source;
}
if (source == end) return 0;
const bool negative = *source == '-';
if (negative || *source == '+') ++source;
if (end - source >= static_cast<std::ptrdiff_t>(safe_integer_bytes)) {
const char* parsed = source;
long long value;
const bool complete = negative
? try_parse_digits_unchecked<true>(parsed, value)
: try_parse_digits_unchecked<false>(parsed, value);
if (complete) {
source = parsed;
return value;
}
}
return negative ? parse_digits_bounded<true>(source, end)
: parse_digits_bounded<false>(source, end);
}
CPLIB_FASTIO_ALWAYS_INLINE unsigned long long read_uint_mapped_at(
const char*& source, const char* end) {
while (source != end &&
static_cast<unsigned char>(*source) <=
static_cast<unsigned char>(' ')) {
++source;
}
if (source == end) return 0;
const bool negative = *source == '-';
if (negative || *source == '+') ++source;
if (end - source >= static_cast<std::ptrdiff_t>(safe_integer_bytes)) {
const char* parsed = source;
unsigned long long value;
if (try_parse_unsigned_digits_unchecked(parsed, value)) {
source = parsed;
return negative ? 0ULL - value : value;
}
}
const unsigned long long value =
parse_unsigned_digits_bounded(source, end);
return negative ? 0ULL - value : value;
}
inline long long read_int_stream_slow(InputState& state) {
bool negative = state.buffer[state.cursor] == '-';
if (negative || state.buffer[state.cursor] == '+') {
++state.cursor;
if (state.cursor == state.length && !refill(state)) return 0;
}
long long value = 0;
for (;;) {
while (state.cursor != state.length) {
const unsigned digit = digit_at(state.buffer + state.cursor);
if (digit >= 10U) return value;
value = negative ? value * 10 - static_cast<long long>(digit)
: value * 10 + static_cast<long long>(digit);
++state.cursor;
}
if (!refill(state)) return value;
}
}
inline unsigned long long read_uint_stream_slow(InputState& state) {
const bool negative = state.buffer[state.cursor] == '-';
if (negative || state.buffer[state.cursor] == '+') {
++state.cursor;
if (state.cursor == state.length && !refill(state)) return 0;
}
unsigned long long value = 0;
for (;;) {
while (state.cursor != state.length) {
const unsigned digit = digit_at(state.buffer + state.cursor);
if (digit >= 10U) return negative ? 0ULL - value : value;
value = value * 10ULL + digit;
++state.cursor;
}
if (!refill(state)) return negative ? 0ULL - value : value;
}
}
CPLIB_FASTIO_ALWAYS_INLINE long long read_int_stream(InputState& state) {
for (;;) {
if (state.cursor == state.length && !refill(state)) return 0;
while (state.cursor != state.length &&
static_cast<unsigned char>(state.buffer[state.cursor]) <=
static_cast<unsigned char>(' ')) {
++state.cursor;
}
if (state.cursor != state.length) break;
}
if (state.length - state.cursor < safe_integer_bytes) {
return read_int_stream_slow(state);
}
const char* source = state.buffer + state.cursor;
const bool negative = *source == '-';
if (negative || *source == '+') ++source;
long long value;
const bool complete = negative
? try_parse_digits_unchecked<true>(source, value)
: try_parse_digits_unchecked<false>(source, value);
if (!complete) return read_int_stream_slow(state);
state.cursor = static_cast<std::size_t>(source - state.buffer);
return value;
}
CPLIB_FASTIO_ALWAYS_INLINE unsigned long long read_uint_stream(
InputState& state) {
for (;;) {
if (state.cursor == state.length && !refill(state)) return 0;
while (state.cursor != state.length &&
static_cast<unsigned char>(state.buffer[state.cursor]) <=
static_cast<unsigned char>(' ')) {
++state.cursor;
}
if (state.cursor != state.length) break;
}
if (state.length - state.cursor < safe_integer_bytes) {
return read_uint_stream_slow(state);
}
const char* source = state.buffer + state.cursor;
const bool negative = *source == '-';
if (negative || *source == '+') ++source;
unsigned long long value;
if (!try_parse_unsigned_digits_unchecked(source, value)) {
return read_uint_stream_slow(state);
}
state.cursor = static_cast<std::size_t>(source - state.buffer);
return negative ? 0ULL - value : value;
}
CPLIB_FASTIO_ALWAYS_INLINE long long read_int() {
InputState& state = input_state();
if (CPLIB_FASTIO_UNLIKELY(!state.initialized)) initialize(state);
if (state.mapped == nullptr) return read_int_stream(state);
const char* source = state.mapped + state.cursor;
const long long value =
read_mapped_at(source, state.mapped + state.length);
state.cursor = static_cast<std::size_t>(source - state.mapped);
return value;
}
CPLIB_FASTIO_ALWAYS_INLINE unsigned long long read_uint() {
InputState& state = input_state();
if (CPLIB_FASTIO_UNLIKELY(!state.initialized)) initialize(state);
if (state.mapped == nullptr) return read_uint_stream(state);
const char* source = state.mapped + state.cursor;
const unsigned long long value =
read_uint_mapped_at(source, state.mapped + state.length);
state.cursor = static_cast<std::size_t>(source - state.mapped);
return value;
}
template <class T>
inline void read_int_array(T* output, std::size_t count) {
InputState& state = input_state();
if (CPLIB_FASTIO_UNLIKELY(!state.initialized)) initialize(state);
if (state.mapped != nullptr) {
const char* source = state.mapped + state.cursor;
const char* const end = state.mapped + state.length;
for (std::size_t i = 0; i < count; ++i) {
output[i] = static_cast<T>(read_mapped_at(source, end));
}
state.cursor = static_cast<std::size_t>(source - state.mapped);
} else {
for (std::size_t i = 0; i < count; ++i) {
output[i] = static_cast<T>(read_int_stream(state));
}
}
}
inline bool fastio_is_space(char value) {
return static_cast<unsigned char>(value) <=
static_cast<unsigned char>(' ');
}
inline void skip_spaces(const char*& source, const char* end) {
while (source != end && fastio_is_space(*source)) ++source;
}
inline void consume_separator(const char*& source, const char* end) {
if (source != end) {
++source;
skip_spaces(source, end);
}
}
inline unsigned parse_eight_digits_simd(const char* source) {
const __m128i bytes = _mm_loadl_epi64(
reinterpret_cast<const __m128i*>(source));
const __m128i digits = _mm_sub_epi8(bytes, _mm_set1_epi8('0'));
const __m128i pairs = _mm_maddubs_epi16(
digits, _mm_setr_epi8(10, 1, 10, 1, 10, 1, 10, 1,
0, 0, 0, 0, 0, 0, 0, 0));
const __m128i quads = _mm_madd_epi16(
pairs, _mm_setr_epi16(100, 1, 100, 1, 0, 0, 0, 0));
return static_cast<unsigned>(_mm_cvtsi128_si32(quads)) * 10000U +
static_cast<unsigned>(_mm_cvtsi128_si32(_mm_srli_si128(quads, 4)));
}
// 呼び出し元で空白を除去済み。長い先頭ゼロと末尾は境界付き処理へ戻す。
inline std::uint32_t read_u32_digits(const char*& source, const char* end) {
if (source == end) return 0;
const bool negative = *source == '-';
if (negative || *source == '+') ++source;
unsigned long long value = 0;
if (end - source >= 16) {
if (has_eight_digits(source)) {
value = parse_eight_digits_simd(source);
const unsigned ninth = digit_at(source + 8);
const unsigned tenth = digit_at(source + 9);
if (ninth >= 10U) {
source += 8;
} else if (tenth >= 10U) {
value = value * 10ULL + ninth;
source += 9;
} else if (digit_at(source + 10) >= 10U) {
value = value * 100ULL + ninth * 10U + tenth;
source += 10;
} else {
value = parse_unsigned_digits_bounded(source, end);
}
} else {
for (;;) {
const unsigned first = digit_at(source);
if (first >= 10U) break;
const unsigned second = digit_at(source + 1);
if (second >= 10U) {
value = value * 10ULL + first;
++source;
break;
}
value = value * 100ULL + first * 10U + second;
source += 2;
}
}
} else {
value = parse_unsigned_digits_bounded(source, end);
}
return static_cast<std::uint32_t>(negative ? 0ULL - value : value);
}
CPLIB_FASTIO_ALWAYS_INLINE std::uint32_t read_u32() {
InputState& state = input_state();
if (CPLIB_FASTIO_UNLIKELY(!state.initialized)) initialize(state);
if (state.mapped != nullptr) {
const char* source = state.mapped + state.cursor;
const char* const end = state.mapped + state.length;
skip_spaces(source, end);
const std::uint32_t value = read_u32_digits(source, end);
consume_separator(source, end);
state.cursor = static_cast<std::size_t>(source - state.mapped);
return value;
}
const char* source = state.buffer + state.cursor;
const char* const end = state.buffer + state.length;
skip_spaces(source, end);
if (CPLIB_FASTIO_UNLIKELY(end - source <
static_cast<std::ptrdiff_t>(safe_integer_bytes))) {
return static_cast<std::uint32_t>(read_uint_stream(state));
}
const std::uint32_t value = read_u32_digits(source, end);
// 長い先頭ゼロがrefill境界をまたぐ場合は、元の位置から読み直す。
if (CPLIB_FASTIO_UNLIKELY(source == end)) {
return static_cast<std::uint32_t>(read_uint_stream(state));
}
consume_separator(source, end);
state.cursor = static_cast<std::size_t>(source - state.buffer);
return value;
}
inline bool try_read_four_nine_digit_u32(
const char*& source, const char* end, std::uint32_t* output) {
if (end - source < 40) return false;
if (!fastio_is_space(source[9]) || !fastio_is_space(source[19]) ||
!fastio_is_space(source[29]) || !fastio_is_space(source[39])) {
return false;
}
const __m128i first_two = _mm_unpacklo_epi64(
_mm_loadl_epi64(reinterpret_cast<const __m128i*>(source)),
_mm_loadl_epi64(reinterpret_cast<const __m128i*>(source + 10)));
const __m128i last_two = _mm_unpacklo_epi64(
_mm_loadl_epi64(reinterpret_cast<const __m128i*>(source + 20)),
_mm_loadl_epi64(reinterpret_cast<const __m128i*>(source + 30)));
const __m256i bytes = _mm256_set_m128i(last_two, first_two);
const __m256i is_digit = _mm256_and_si256(
_mm256_cmpgt_epi8(bytes, _mm256_set1_epi8('/')),
_mm256_cmpgt_epi8(_mm256_set1_epi8(':'), bytes));
if (static_cast<unsigned>(_mm256_movemask_epi8(is_digit)) !=
0xffffffffU) {
return false;
}
const unsigned digit0 = digit_at(source + 8);
const unsigned digit1 = digit_at(source + 18);
const unsigned digit2 = digit_at(source + 28);
const unsigned digit3 = digit_at(source + 38);
const bool ninth_digits = (digit0 < 10U) & (digit1 < 10U) &
(digit2 < 10U) & (digit3 < 10U);
if (!ninth_digits) return false;
const __m256i digits =
_mm256_sub_epi8(bytes, _mm256_set1_epi8('0'));
const __m256i pairs = _mm256_maddubs_epi16(
digits, _mm256_setr_epi8(
10, 1, 10, 1, 10, 1, 10, 1,
10, 1, 10, 1, 10, 1, 10, 1,
10, 1, 10, 1, 10, 1, 10, 1,
10, 1, 10, 1, 10, 1, 10, 1));
const __m256i quads = _mm256_madd_epi16(
pairs, _mm256_setr_epi16(
100, 1, 100, 1, 100, 1, 100, 1,
100, 1, 100, 1, 100, 1, 100, 1));
const __m256i weighted = _mm256_mullo_epi32(
quads, _mm256_setr_epi32(
10000, 1, 10000, 1, 10000, 1, 10000, 1));
const __m256i sums =
_mm256_hadd_epi32(weighted, _mm256_setzero_si256());
const __m128i first_eight = _mm_unpacklo_epi64(
_mm256_castsi256_si128(sums),
_mm256_extracti128_si256(sums, 1));
const __m128i values = _mm_add_epi32(
_mm_mullo_epi32(first_eight, _mm_set1_epi32(10)),
_mm_setr_epi32(static_cast<int>(digit0),
static_cast<int>(digit1),
static_cast<int>(digit2),
static_cast<int>(digit3)));
_mm_storeu_si128(reinterpret_cast<__m128i*>(output), values);
source += 40;
return true;
}
inline void read_uint_array(std::uint32_t* output, std::size_t count) {
InputState& state = input_state();
if (CPLIB_FASTIO_UNLIKELY(!state.initialized)) initialize(state);
if (state.mapped != nullptr) {
const char* source = state.mapped + state.cursor;
const char* const end = state.mapped + state.length;
skip_spaces(source, end);
std::size_t i = 0;
unsigned nine_digit_count = 0;
// 最初の16要素を読みながら分布を確認し、短い整数ではAVX判定を省く。
if (count >= 64) {
for (; i < 16; ++i) {
nine_digit_count += end - source >= 10 &&
fastio_is_space(source[9]) && has_eight_digits(source) &&
digit_at(source + 8) < 10U;
output[i] = read_u32_digits(source, end);
consume_separator(source, end);
}
}
if (nine_digit_count >= 12) {
while (i < count) {
if (count - i >= 4 && try_read_four_nine_digit_u32(
source, end, output + i)) {
i += 4;
skip_spaces(source, end);
} else {
output[i++] = read_u32_digits(source, end);
if (i != count) consume_separator(source, end);
}
}
} else {
while (i < count) {
output[i++] = read_u32_digits(source, end);
if (i != count) consume_separator(source, end);
}
}
state.cursor = static_cast<std::size_t>(source - state.mapped);
} else {
std::size_t i = 0;
unsigned nine_digit_count = 0;
if (count >= 64) {
for (; i < 16; ++i) {
output[i] = static_cast<std::uint32_t>(read_uint_stream(state));
nine_digit_count += output[i] >= 100000000U &&
output[i] < 1000000000U;
}
}
if (nine_digit_count >= 12) {
while (count - i >= 4) {
const char* source = state.buffer + state.cursor;
const char* const end = state.buffer + state.length;
skip_spaces(source, end);
if (try_read_four_nine_digit_u32(source, end, output + i)) {
state.cursor = static_cast<std::size_t>(source - state.buffer);
i += 4;
} else {
state.cursor = static_cast<std::size_t>(source - state.buffer);
// refillをまたぐ整数は既存のストリーム処理で最後まで読む。
output[i++] = static_cast<std::uint32_t>(read_uint_stream(state));
}
}
}
for (; i < count; ++i) {
output[i] = static_cast<std::uint32_t>(read_uint_stream(state));
}
}
}
template <class T>
inline void read_uint_array(T* output, std::size_t count) {
InputState& state = input_state();
if (CPLIB_FASTIO_UNLIKELY(!state.initialized)) initialize(state);
if (state.mapped != nullptr) {
const char* source = state.mapped + state.cursor;
const char* const end = state.mapped + state.length;
for (std::size_t i = 0; i < count; ++i) {
output[i] = static_cast<T>(read_uint_mapped_at(source, end));
}
state.cursor = static_cast<std::size_t>(source - state.mapped);
} else {
for (std::size_t i = 0; i < count; ++i) {
output[i] = static_cast<T>(read_uint_stream(state));
}
}
}
inline const char* read_token(std::size_t* output_length) {
InputState& state = input_state();
if (CPLIB_FASTIO_UNLIKELY(!state.initialized)) initialize(state);
if (state.mapped != nullptr) {
const char* source = state.mapped + state.cursor;
const char* const end = state.mapped + state.length;
while (source != end &&
static_cast<unsigned char>(*source) <=
static_cast<unsigned char>(' ')) {
++source;
}
const char* const token = source;
while (source != end &&
static_cast<unsigned char>(*source) >
static_cast<unsigned char>(' ')) {
++source;
}
state.cursor = static_cast<std::size_t>(source - state.mapped);
*output_length = static_cast<std::size_t>(source - token);
return token;
}
for (;;) {
if (state.cursor == state.length && !refill(state)) {
*output_length = 0;
return "";
}
while (state.cursor != state.length &&
static_cast<unsigned char>(state.buffer[state.cursor]) <=
static_cast<unsigned char>(' ')) {
++state.cursor;
}
if (state.cursor != state.length) break;
}
const std::size_t token_begin = state.cursor;
while (state.cursor != state.length &&
static_cast<unsigned char>(state.buffer[state.cursor]) >
static_cast<unsigned char>(' ')) {
++state.cursor;
}
if (state.cursor != state.length) {
*output_length = state.cursor - token_begin;
return state.buffer + token_begin;
}
std::string& storage = token_storage();
storage.assign(state.buffer + token_begin,
state.length - token_begin);
while (refill(state)) {
while (state.cursor != state.length &&
static_cast<unsigned char>(state.buffer[state.cursor]) >
static_cast<unsigned char>(' ')) {
++state.cursor;
}
storage.append(state.buffer, state.cursor);
if (state.cursor != state.length) break;
}
*output_length = storage.size();
return storage.c_str();
}
#undef CPLIB_FASTIO_UNLIKELY
#undef CPLIB_FASTIO_ALWAYS_INLINE
} // namespace cplib_fastio_input
""".}
proc fastioGetChar(): cint {.importcpp: "cplib_fastio_input::get_char()", nodecl, inline.}
proc fastioReadInt(): clonglong {.importcpp: "cplib_fastio_input::read_int()", nodecl, inline.}
proc fastioReadUInt(): culonglong {.importcpp: "cplib_fastio_input::read_uint()", nodecl, inline.}
proc fastioReadUInt32(): uint32 {.importcpp: "cplib_fastio_input::read_u32()", nodecl, inline.}
proc fastioReadSignedArray[T: SomeSignedInt](values: ptr T, count: csize_t) {.importcpp: "cplib_fastio_input::read_int_array(@)", nodecl, inline.}
proc fastioReadUnsignedArray[T: SomeUnsignedInt](values: ptr T, count: csize_t) {.importcpp: "cplib_fastio_input::read_uint_array(@)", nodecl, inline.}
proc fastioReadToken(length: ptr csize_t): cstring
{.importcpp: "cplib_fastio_input::read_token(@)", nodecl, inline.}
type FastioInteger = int | int8 | int16 | int32 | int64 |
uint | uint8 | uint16 | uint32 | uint64
when NimMajor >= 2:
template fastioNewSeqUninit(T: typedesc, length: int): untyped =
newSeqUninit[T](length)
template fastioNewStringUninit(length: int): untyped =
newStringUninit(length)
else:
template fastioNewSeqUninit(T: typedesc, length: int): untyped =
newSeqUninitialized[T](length)
template fastioNewStringUninit(length: int): untyped =
newString(length)
proc ii(): int {.inline,
codegenDecl: "CPLIB_FASTIO_NIM_ALWAYS_INLINE $# $#$#".} =
fastioReadInt().int
proc lii(N: int): seq[int] {.inline.} =
result = fastioNewSeqUninit(int, N)
if N > 0:
fastioReadSignedArray(addr result[0], N.csize_t)
# 型だけなら1要素、長さと型ならseqとして読み込む。
proc input[T: FastioInteger](valueType: typedesc[T]): T {.inline,
codegenDecl: "CPLIB_FASTIO_NIM_ALWAYS_INLINE $# $#$#".} =
when T is range:
{.error: "input supports only primitive integer types".}
elif T is SomeSignedInt:
T(fastioReadInt())
elif T is uint32:
fastioReadUInt32()
else:
T(fastioReadUInt())
proc input[T: FastioInteger](N: int, valueType: typedesc[T]): seq[T] {.inline.} =
when T is range:
{.error: "input supports only primitive integer types".}
else:
result = fastioNewSeqUninit(T, N)
if N > 0:
when T is SomeSignedInt:
fastioReadSignedArray(addr result[0], N.csize_t)
else:
fastioReadUnsignedArray(addr result[0], N.csize_t)
proc si(): string {.inline.} =
var length: csize_t
let source = fastioReadToken(addr length)
result = fastioNewStringUninit(length.int)
if length != 0:
copyMem(addr result[0], source, length.int)
proc input(valueType: typedesc[string]): string {.inline.} =
si()
proc input(N: int, valueType: typedesc[string]): seq[string] {.inline.} =
result = newSeq[string](N)
for i in 0 ..< N:
result[i] = input(string)
# 出力系
{.emit: """
#include <cstdio>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <type_traits>
namespace cplib_fastio_output {
struct StdoutBuffer {
static constexpr std::size_t capacity = 1U << 16;
alignas(64) char data[capacity];
StdoutBuffer() { setvbuf(stdout, data, _IOFBF, capacity); }
};
static StdoutBuffer stdout_buffer;
struct FourDigits {
char data[10000][4];
constexpr FourDigits() : data{} {
for (unsigned i = 0; i < 10000; ++i) {
data[i][0] = static_cast<char>('0' + i / 1000);
data[i][1] = static_cast<char>('0' + i / 100 % 10);
data[i][2] = static_cast<char>('0' + i / 10 % 10);
data[i][3] = static_cast<char>('0' + i % 10);
}
}
};
constexpr FourDigits four_digit_table{};
inline const FourDigits& four_digits() {
return four_digit_table;
}
inline char* reserve_bytes(std::FILE* output, std::size_t size) {
#if defined(__GLIBC__)
// stdio自身のバッファを使い、echo/write/flushFileとの出力順を保つ。
if (output->_IO_write_ptr != nullptr &&
output->_IO_write_end != nullptr &&
static_cast<std::size_t>(output->_IO_write_end -
output->_IO_write_ptr) >= size) {
return output->_IO_write_ptr;
}
#endif
return nullptr;
}
inline void commit_bytes(std::FILE* output, char* end) {
#if defined(__GLIBC__)
output->_IO_write_ptr = end;
#else
(void)output;
(void)end;
#endif
}
inline char* write_small(char* output, unsigned value,
const FourDigits& table) {
if (value >= 1000) {
std::memcpy(output, table.data[value], 4);
return output + 4;
}
if (value >= 100) {
std::memcpy(output, table.data[value] + 1, 3);
return output + 3;
}
if (value >= 10) {
std::memcpy(output, table.data[value] + 2, 2);
return output + 2;
}
*output++ = static_cast<char>('0' + value);
return output;
}
inline char* write_four(char* output, unsigned value,
const FourDigits& table) {
std::memcpy(output, table.data[value], 4);
return output + 4;
}
inline char* write_unsigned_32(char* output, std::uint32_t value,
const FourDigits& table) {
if (value < 10000U) return write_small(output, value, table);
const std::uint32_t quotient = value / 10000U;
const unsigned low = static_cast<unsigned>(value - quotient * 10000U);
if (quotient < 10000U) {
output = write_small(output, quotient, table);
return write_four(output, low, table);
}
const unsigned high = quotient / 10000U;
const unsigned middle = quotient - high * 10000U;
output = write_small(output, high, table);
output = write_four(output, middle, table);
return write_four(output, low, table);
}
inline char* write_unsigned_64(char* output, std::uint64_t value,
const FourDigits& table) {
if (value < 10000ULL) {
return write_small(output, static_cast<unsigned>(value), table);
}
const std::uint64_t quotient1 = value / 10000ULL;
const unsigned chunk1 = static_cast<unsigned>(value - quotient1 * 10000ULL);
if (quotient1 < 10000ULL) {
output = write_small(output, static_cast<unsigned>(quotient1), table);
return write_four(output, chunk1, table);
}
const std::uint64_t quotient2 = quotient1 / 10000ULL;
const unsigned chunk2 = static_cast<unsigned>(quotient1 - quotient2 * 10000ULL);
if (quotient2 < 10000ULL) {
output = write_small(output, static_cast<unsigned>(quotient2), table);
output = write_four(output, chunk2, table);
return write_four(output, chunk1, table);
}
const std::uint64_t quotient3 = quotient2 / 10000ULL;
const unsigned chunk3 = static_cast<unsigned>(quotient2 - quotient3 * 10000ULL);
if (quotient3 < 10000ULL) {
output = write_small(output, static_cast<unsigned>(quotient3), table);
output = write_four(output, chunk3, table);
output = write_four(output, chunk2, table);
return write_four(output, chunk1, table);
}
const std::uint64_t quotient4 = quotient3 / 10000ULL;
const unsigned chunk4 = static_cast<unsigned>(quotient3 - quotient4 * 10000ULL);
output = write_small(output, static_cast<unsigned>(quotient4), table);
output = write_four(output, chunk4, table);
output = write_four(output, chunk3, table);
output = write_four(output, chunk2, table);
return write_four(output, chunk1, table);
}
template <class Unsigned>
inline char* write_unsigned_dispatch(char* output, Unsigned value,
const FourDigits& table,
std::true_type) {
return write_unsigned_32(output, static_cast<std::uint32_t>(value), table);
}
template <class Unsigned>
inline char* write_unsigned_dispatch(char* output, Unsigned value,
const FourDigits& table,
std::false_type) {
return write_unsigned_64(output, static_cast<std::uint64_t>(value), table);
}
template <class Unsigned>
inline char* write_unsigned(char* output, Unsigned value,
const FourDigits& table) {
return write_unsigned_dispatch(output, value, table,
std::integral_constant<bool, (sizeof(Unsigned) <= 4)>{});
}
template <class Integer>
inline std::size_t join_integers(
const Integer* values, std::size_t count, char* output,
const char* separator, std::size_t separator_length) {
const FourDigits& table = four_digits();
char* cursor = output;
using Unsigned = typename std::make_unsigned<Integer>::type;
for (std::size_t i = 0; i < count; ++i) {
const Integer value = values[i];
Unsigned magnitude = static_cast<Unsigned>(value);
if (std::is_signed<Integer>::value && value < 0) {
*cursor++ = '-';
magnitude = Unsigned(0) - magnitude;
}
cursor = write_unsigned(cursor, magnitude, table);
if (i + 1 != count) {
std::memcpy(cursor, separator, separator_length);
cursor += separator_length;
}
}
return static_cast<std::size_t>(cursor - output);
}
class BufferedWriter {
public:
static constexpr std::size_t capacity = 1U << 16;
explicit BufferedWriter(std::FILE* output)
: length_(0), output_(output) {}
inline char* reserve_integer() {
constexpr std::size_t max_integer_length = 21;
if (capacity - length_ < max_integer_length) flush();
return data_ + length_;
}
inline void commit(char* end) {
length_ = static_cast<std::size_t>(end - data_);
}
inline void append(const char* source, std::size_t size) {
if (size <= capacity - length_) {
std::memcpy(data_ + length_, source, size);
length_ += size;
return;
}
flush();
if (size >= capacity) {
fwrite_unlocked(source, 1, size, output_);
} else {
std::memcpy(data_, source, size);
length_ = size;
}
}
inline void flush() {
if (length_ != 0) {
fwrite_unlocked(data_, 1, length_, output_);
length_ = 0;
}
}
private:
char data_[capacity];
std::size_t length_;
std::FILE* output_;
};
template <class Integer>
inline void print_integers(std::FILE* output, const Integer* values,
std::size_t count,
const char* separator,
std::size_t separator_length) {
const FourDigits& table = four_digits();
BufferedWriter writer(output);
using Unsigned = typename std::make_unsigned<Integer>::type;
for (std::size_t i = 0; i < count; ++i) {
char* cursor = writer.reserve_integer();
const Integer value = values[i];
Unsigned magnitude = static_cast<Unsigned>(value);
if (std::is_signed<Integer>::value && value < 0) {
*cursor++ = '-';
magnitude = Unsigned(0) - magnitude;
}
cursor = write_unsigned(cursor, magnitude, table);
writer.commit(cursor);
if (i + 1 != count) writer.append(separator, separator_length);
}
writer.append("\n", 1);
writer.flush();
}
template <class Integer>
inline void print_one(std::FILE* output, Integer value) {
const FourDigits& table = four_digits();
char buffer[22];
char* const reserved = reserve_bytes(output, sizeof(buffer));
char* const begin = reserved == nullptr ? buffer : reserved;
char* cursor = begin;
using Unsigned = typename std::make_unsigned<Integer>::type;
Unsigned magnitude = static_cast<Unsigned>(value);
if (std::is_signed<Integer>::value && value < 0) {
*cursor++ = '-';
magnitude = Unsigned(0) - magnitude;
}
cursor = write_unsigned(cursor, magnitude, table);
*cursor++ = '\n';
if (reserved != nullptr) {
commit_bytes(output, cursor);
} else {
fwrite_unlocked(buffer, 1,
static_cast<std::size_t>(cursor - buffer), output);
}
}
} // namespace cplib_fastio_output
""".}
proc fastioJoinInts[T: SomeInteger](values: ptr T, count: csize_t,
output: ptr char, separator: cstring, separatorLen: csize_t): csize_t
{.importcpp: "cplib_fastio_output::join_integers(@)", nodecl.}
proc fastioPrintInts[T: SomeInteger](output: File, values: ptr T,
count: csize_t, separator: cstring, separatorLen: csize_t)
{.importcpp: "cplib_fastio_output::print_integers(@)", nodecl.}
proc fastioPrintInt[T: SomeInteger](output: File, value: T)
{.importcpp: "cplib_fastio_output::print_one(@)", nodecl.}
proc print_internal(prop: tuple[f: File, sepc: string, endc: string,
flush: bool], args: openArray[string]) =
for i in 0 ..< args.len:
prop.f.write(args[i])
if i != args.len - 1:
prop.f.write(prop.sepc)
else:
prop.f.write(prop.endc)
if prop.flush:
prop.f.flushFile()
proc print*(prop: tuple[f: File, sepc: string, endc: string, flush: bool],
args: varargs[string, `$`]) =
print_internal(prop, args)
proc fastioPrintWithSeparator(sep: string, args: varargs[string, `$`]) =
print_internal((f: stdout, sepc: sep, endc: "\n", flush: false), args)
proc fastioAppendInteger[T: SomeInteger](destination: var string, value: T) =
var magnitude: uint64
when T is SomeSignedInt:
let signedValue = value.int64
if signedValue < 0:
destination.add('-')
magnitude = uint64(-(signedValue + 1)) + 1'u64
else:
magnitude = signedValue.uint64
else:
magnitude = value.uint64
if magnitude == 0:
destination.add('0')
return
var digits: array[20, char]
var count = 0
while magnitude != 0:
digits[count] = char(ord('0') + int(magnitude mod 10))
magnitude = magnitude div 10
inc count
while count != 0:
dec count
destination.add(digits[count])
# 整数は4桁テーブルを使うC++フォーマッタへまとめて渡す。
proc fastioJoinImpl[T](a: openArray[T], sep: string): string =
when nimvm:
result = newStringOfCap(a.len * 4)
for i, value in a:
if i != 0:
result.add(sep)
when T is SomeInteger:
fastioAppendInteger(result, value)
else:
result.add($value)
else:
if a.len == 0:
return ""
when T is SomeInteger and sizeof(T) in [4, 8]:
const digits = when sizeof(T) == 8: 20
elif T is SomeSignedInt: 11
else: 10
result = fastioNewStringUninit(
a.len * digits + (a.len - 1) * sep.len)
let written = fastioJoinInts(unsafeAddr a[0],
a.len.csize_t, addr result[0], sep.cstring, sep.len.csize_t)
result.setLen(written.int)
elif compiles(T.umod()) and compiles(a[0].val()):
# Montgomery表現を含め、公開値へ正規化してから一括変換する。
var canonical = fastioNewSeqUninit(uint32, a.len)
for i, value in a:
canonical[i] = value.val.uint32
result = fastioJoinImpl(canonical, sep)
else:
result = newStringOfCap(a.len * 4)
for i, value in a:
if i != 0:
result.add(sep)
when T is SomeInteger:
fastioAppendInteger(result, value)
else:
result.add($value)
proc join*[T: not string](a: openArray[T], sep: string = ""): string {.inline.} =
fastioJoinImpl(a, sep)
proc fastioPrintArrayImpl[T](a: openArray[T], sep: string) =
if a.len == 0:
stdout.write('\n')
return
when T is SomeInteger and sizeof(T) in [4, 8]:
fastioPrintInts(stdout, unsafeAddr a[0], a.len.csize_t,
sep.cstring, sep.len.csize_t)
elif compiles(T.umod()) and compiles(a[0].val()):
var canonical = fastioNewSeqUninit(uint32, a.len)
for i, value in a:
canonical[i] = value.val.uint32
fastioPrintArrayImpl(canonical, sep)
else:
stdout.write(fastioJoinImpl(a, sep))
stdout.write('\n')
proc fastioPrintOneImpl[T](value: T, sep: string) =
when T is SomeInteger and sizeof(T) in [4, 8]:
fastioPrintInt(stdout, value)
elif compiles(T.umod()) and compiles(value.val()):
fastioPrintInt(stdout, value.val.uint32)
else:
fastioPrintWithSeparator(sep, value)
proc fastioPrintIntegerMany[T: SomeInteger](sep: string,
values: varargs[T]) =
fastioPrintArrayImpl(values, sep)
# Python風に print(*X) と書くと、Xを空白区切りで1行に出力する。
template `*`*[T](values: openArray[T]): string =
fastioJoinImpl(values, " ")
# 最後の文字列引数をsepと誤認しないよう、名前付きsepはマクロで処理する。
macro print*(args: varargs[untyped]): untyped =
var sep = newLit(" ")
var hasSep = false
var values: seq[NimNode]
for arg in args:
if arg.kind == nnkExprEqExpr and arg[0].eqIdent("sep"):
if hasSep:
error("sep can only be specified once", arg)
sep = arg[1]
hasSep = true
else:
values.add(arg)
var splatValues: NimNode
if values.len == 1:
if values[0].kind == nnkPrefix and values[0][0].eqIdent("*"):
splatValues = values[0][1]
elif values[0].kind in nnkCallKinds and values[0].len == 3 and
values[0][0].eqIdent("fastioJoinImpl"):
# オーバーロード解決時に *values が先に展開された場合。
splatValues = values[0][1]
if not splatValues.isNil:
result = newCall(bindSym"fastioPrintArrayImpl", splatValues, sep)
elif values.len == 1:
result = newCall(bindSym"fastioPrintOneImpl", values[0], sep)
else:
let integerCall = newCall(bindSym"fastioPrintIntegerMany", sep)
let fallbackCall = newCall(bindSym"fastioPrintWithSeparator", sep)
for value in values:
integerCall.add(value)
fallbackCall.add(value)
result = quote do:
when compiles(`integerCall`):
`integerCall`
else:
`fallbackCall`Traceback (most recent call last):
File "/home/runner/.local/lib/python3.12/site-packages/onlinejudge_verify/documentation/build.py", line 71, in _render_source_code_stat
bundled_code = language.bundle(stat.path, basedir=basedir, options={'include_paths': [basedir]}).decode()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/runner/.local/lib/python3.12/site-packages/onlinejudge_verify/languages/nim.py", line 86, in bundle
raise NotImplementedError
NotImplementedError