shogo-library

競技プログラミング用の C++ ライブラリ

View the Project on GitHub shogo314/shogo-library

:heavy_check_mark: test/unittest/range.test.cpp

Depends on

Code

#define PROBLEM "https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=ITP1_1_A"

// Range を愚直に作った std::vector (Python の range と同じ列) とランダムに比較する
// 問題の入力は使わず、すべて一致したら Hello World を出力する

#include <algorithm>
#include <iostream>
#include <iterator>
#include <random>
#include <string>
#include <vector>

#include "../../src/base/range.hpp"

using ll = long long;

// Python の range(start, stop, step) と同じ列
std::vector<ll> naive_range(ll start, ll stop, ll step) {
    std::vector<ll> v;
    if (step > 0) {
        for (ll x = start; x < stop; x += step) v.push_back(x);
    } else {
        for (ll x = start; x > stop; x += step) v.push_back(x);
    }
    return v;
}

std::vector<ll> by_iteration(const Range& r) {
    std::vector<ll> v;
    for (ll x : r) v.push_back(x);
    return v;
}

// コンパイル時にも使える
static_assert(Range(0, 10, 3).size() == 4);
static_assert(Range(10, 0, -3).sum() == 22);
static_assert(Range(5).max() == 4);

int main() {
    std::mt19937_64 rng(314);
    auto rnd = [&](ll lo, ll hi) { return lo + (ll)(rng() % (unsigned long long)(hi - lo + 1)); };
    bool ok = true;
    auto check = [&](bool cond, const char* what) {
        if (!cond) {
            if (ok) std::cerr << "failed: " << what << std::endl;
            ok = false;
        }
    };

    // コンストラクタ
    check(by_iteration(Range(5)) == naive_range(0, 5, 1), "Range(stop)");
    check(by_iteration(Range(-3)).empty(), "Range(negative stop)");
    check(by_iteration(Range(2, 7)) == naive_range(2, 7, 1), "Range(start, stop)");
    check(Range().empty() && Range().size() == 0 && by_iteration(Range()).empty(), "Range()");
    {
        Range a(1, 20, 4);
        Range b(a);  // コピー
        check(by_iteration(b) == naive_range(1, 20, 4), "copy");
    }

    for (int rep = 0; rep < 20000 && ok; rep++) {
        ll start = rnd(-20, 20), stop = rnd(-20, 20), step = rnd(1, 7) * (rng() % 2 ? 1 : -1);
        Range r(start, stop, step);
        std::vector<ll> v = naive_range(start, stop, step);
        int n = v.size();

        check(r.start == start && r.stop == stop && r.step == step, "members");
        check(by_iteration(r) == v, "iteration");
        check(r.to_vector() == v, "to_vector");
        check(std::vector<ll>(r.begin(), r.end()) == v, "iterator range constructor");
        check(r.size() == (size_t)n, "size");
        check(r.empty() == v.empty(), "empty");
        check(r.end() - r.begin() == n, "end - begin");
        for (int i = 0; i < n; i++) {
            check(r.at(i) == v[i] && r[i] == v[i], "at / []");
        }

        // count, contains, index, find
        for (ll x = -30; x <= 30; x++) {
            int c = std::count(v.begin(), v.end(), x);
            check(r.count(x) == c, "count");
            check(r.contains(x) == (c > 0), "contains");
            if (c > 0) {
                int idx = std::find(v.begin(), v.end(), x) - v.begin();
                check(r.index(x) == (size_t)idx, "index");
                check(*r.find(x) == x && r.find(x) - r.begin() == idx, "find (found)");
            } else {
                check(r.find(x) == r.end(), "find (not found)");
            }
        }

        // lower_bound, upper_bound (step > 0 のときだけ使える)
        if (step > 0) {
            for (ll x = -30; x <= 30; x++) {
                check(r.lower_bound(x) - r.begin() == std::lower_bound(v.begin(), v.end(), x) - v.begin(), "lower_bound");
                check(r.upper_bound(x) - r.begin() == std::upper_bound(v.begin(), v.end(), x) - v.begin(), "upper_bound");
            }
        }

        // sum, min, max
        ll sum = 0;
        for (ll x : v) sum += x;
        check(r.sum() == sum, "sum");
        if (n > 0) {
            check(r.min() == *std::min_element(v.begin(), v.end()), "min");
            check(r.max() == *std::max_element(v.begin(), v.end()), "max");
        }

        // reversed, sorted
        std::vector<ll> rv(v.rbegin(), v.rend()), sv = v;
        std::sort(sv.begin(), sv.end());
        check(by_iteration(r.reversed()) == rv && r.reversed().size() == (size_t)n, "reversed");
        check(by_iteration(r.sorted()) == sv && r.sorted().size() == (size_t)n, "sorted");

        // clipped: 値が [l, r] の要素だけを順番を保って残す
        {
            ll l = rnd(-25, 25), rr = rnd(-25, 25);
            std::vector<ll> expect;
            if (l <= rr) {
                for (ll x : v)
                    if (l <= x && x <= rr) expect.push_back(x);
            }
            Range c = r.clipped(l, rr);
            check(by_iteration(c) == expect && c.size() == expect.size(), "clipped");
        }

        // slice: インデックスを Range で指定する (範囲外のインデックスは無視)
        {
            ll s2 = rnd(-25, 25), t2 = rnd(-25, 25), st2 = rnd(1, 5) * (rng() % 2 ? 1 : -1);
            Range idx(s2, t2, st2);
            std::vector<ll> expect;
            for (ll i : naive_range(s2, t2, st2))
                if (0 <= i && i < n) expect.push_back(v[i]);
            Range s = r.slice(idx);
            check(by_iteration(s) == expect && s.size() == expect.size(), "slice");
        }

        // ==, != は列として等しいか
        {
            ll start2 = rng() % 4 == 0 ? start : rnd(-20, 20);
            ll stop2 = rng() % 2 == 0 ? stop + rnd(-3, 3) : rnd(-20, 20);
            ll step2 = rng() % 2 == 0 ? step : rnd(1, 7) * (rng() % 2 ? 1 : -1);
            Range r2(start2, stop2, step2);
            bool same = v == naive_range(start2, stop2, step2);
            check((r == r2) == same && (r != r2) == !same, "== / !=");
        }

        // イテレータの各演算
        if (n > 0) {
            int i = rnd(0, n - 1), j = rnd(0, n - 1);
            auto it = r.begin() + i;
            check(*it == v[i] && it.base() == v[i], "begin + i");
            check(*(i + r.begin()) == v[i], "i + begin");
            check(*(r.end() - (n - i)) == v[i], "end - k");
            check((r.begin() + j) - it == j - i, "iterator difference");
            auto it2 = it;  // コピーコンストラクタ
            check(it2 == it && !(it2 != it), "copy / ==");
            it2 = r.begin();  // 同じ Range のイテレータの代入
            check(*it2 == v[0], "operator=");
            auto a = it;
            auto b = a++;
            check(*b == v[i] && a - b == 1, "post ++");
            auto c = ++b;
            check(c == a && *c == *a, "pre ++");
            auto d = a--;
            check(d - a == 1 && *a == v[i], "post --");
            --d;
            check(d == a, "pre --");
            auto e = it;
            e += j - i;
            check(*(e) == v[j] || j == n, "+=");
            e -= j - i;
            check(e == it, "-=");
            check(it != r.end(), "!= end");
        }
        check(r.begin() + n == r.end(), "begin + size == end");
    }

    // product_xor (負を含まない列)
    for (int rep = 0; rep < 5000 && ok; rep++) {
        ll start, stop, step;
        if (rep % 2 == 0) {
            start = rnd(0, 100), stop = rnd(0, 100), step = rnd(1, 9) * (rng() % 2 ? 1 : -1);
            if (step < 0 && stop < -1) stop = -1;
        } else {
            // 大きい値 (要素数は少なめ)
            start = rnd(0, 1000000000000LL), step = rnd(1, 1000000000LL) * (rng() % 2 ? 1 : -1);
            stop = start + step * rnd(0, 300);
            if (stop < -1) stop = -1;
        }
        Range r(start, stop, step);
        ll x = 0;
        for (ll y : naive_range(start, stop, step)) x ^= y;
        check(r.product_xor() == x, "product_xor");
    }

    // 文字列化
    {
        Range r(-3, 10, 2);
        check(Range::type_str() == "Range", "type_str");
        check(r.initializer_str() == "{-3, 10, 2}", "initializer_str");
        check(r.repr() == "Range(-3, 10, 2)", "repr");
    }

    if (ok) std::cout << "Hello World" << std::endl;
}
#line 1 "test/unittest/range.test.cpp"
#define PROBLEM "https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=ITP1_1_A"

// Range を愚直に作った std::vector (Python の range と同じ列) とランダムに比較する
// 問題の入力は使わず、すべて一致したら Hello World を出力する

#include <algorithm>
#include <iostream>
#include <iterator>
#include <random>
#include <string>
#include <vector>

#line 2 "src/base/range.hpp"

/**
 * @file range.hpp
 * @brief Python の range のような整数列
 */

#include <cassert>
#include <cstddef>
#line 12 "src/base/range.hpp"
#include <type_traits>
#include <utility>
#line 15 "src/base/range.hpp"

struct Range {
   public:
    using value_type = long long;
    using const_reference = const value_type&;
    using size_type = std::size_t;
    using difference_type = std::ptrdiff_t;

    const value_type start;
    const value_type stop;
    const value_type step;

   private:
    const value_type norm_stop;

    constexpr static value_type normalize(value_type _start, value_type _stop, value_type _step) {
        assert(_step != 0);
        if (_step > 0) {
            if (_start >= _stop) {
                return _start;
            } else {
                return _start + (_stop - _start + _step - 1) / _step * _step;
            }
        } else {
            if (_start <= _stop) {
                return _start;
            } else {
                return _start - (_start - _stop - _step - 1) / _step * _step;
            }
        }
    }

    constexpr Range(value_type _start, value_type _stop, value_type _step, value_type _norm_stop)
        : start(_start), stop(_stop), step(_step), norm_stop(_norm_stop) {
    }

   public:
    /**
     * @brief start から stop の手前まで step ずつ進む整数列
     * @pre step != 0
     */
    constexpr Range(value_type _start, value_type _stop, value_type _step)
        : start(_start), stop(_stop), step(_step), norm_stop(normalize(_start, _stop, _step)) {
    }
    constexpr Range(value_type _start, value_type _stop)
        : start(_start), stop(_stop), step(1), norm_stop(normalize(_start, _stop, 1)) {}
    constexpr Range(value_type _stop)
        : start(0), stop(_stop), step(1), norm_stop(normalize(0, _stop, 1)) {}
    constexpr Range()
        : start(0), stop(0), step(1), norm_stop(0) {
    }
    constexpr Range(const Range& o) = default;
    Range& operator=(const Range& o) = delete;

    struct const_iterator {
       public:
        using difference_type = Range::difference_type;
        using value_type = Range::value_type;
        using pointer = const Range::value_type*;
        using reference = const Range::value_type&;
        using iterator_category = std::random_access_iterator_tag;

       private:
        const Range& range;
        value_type value;

        constexpr bool same_range(const const_iterator& o) const noexcept {
            return range.start == o.range.start and range.stop == o.range.stop and range.step == o.range.step;
        }

       public:
        constexpr const_iterator(const Range& _range, value_type _value) noexcept
            : range(_range), value(_value) {}
        constexpr const_iterator(const const_iterator& o) noexcept
            : range(o.range), value(o.value) {}
        constexpr reference base() const noexcept {
            return value;
        }
        constexpr const_iterator& operator=(const const_iterator& o) {
            assert(same_range(o));
            value = o.value;
            return *this;
        };
        constexpr const_iterator& operator++() noexcept {
            value += range.step;
            return *this;
        }
        constexpr const_iterator operator++(int) noexcept {
            const_iterator ret(*this);
            value += range.step;
            return ret;
        }
        constexpr const_iterator& operator+=(difference_type _n) noexcept {
            value += _n * range.step;
            return *this;
        }
        constexpr friend const_iterator operator+(const const_iterator& i, difference_type _n) noexcept {
            const_iterator ret(i);
            ret += _n;
            return ret;
        }
        constexpr friend const_iterator operator+(difference_type _n, const const_iterator& i) noexcept {
            const_iterator ret(i);
            ret += _n;
            return ret;
        }
        constexpr const_iterator& operator--() noexcept {
            value -= range.step;
            return *this;
        }
        constexpr const_iterator operator--(int) noexcept {
            const_iterator ret(*this);
            value -= range.step;
            return ret;
        }
        constexpr const_iterator& operator-=(difference_type _n) noexcept {
            value -= _n * range.step;
            return *this;
        }
        constexpr friend const_iterator operator-(const const_iterator& i, difference_type _n) noexcept {
            const_iterator ret(i);
            ret -= _n;
            return ret;
        }
        constexpr reference operator*() const noexcept {
            return value;
        }
        constexpr friend bool operator!=(const const_iterator& a, const const_iterator& b) noexcept {
            return !a.same_range(b) or a.value != b.value;
        }
        constexpr friend bool operator==(const const_iterator& a, const const_iterator& b) noexcept {
            return !(a != b);
        }
        constexpr friend difference_type operator-(const const_iterator& a, const const_iterator& b) {
            assert(a.same_range(b));
            if (a.range.step > 0) {
                return (a.value - b.value) / a.range.step;
            } else {
                return (b.value - a.value) / (-a.range.step);
            }
        }
    };

    constexpr const_iterator begin() const noexcept {
        return {*this, start};
    }
    constexpr const_iterator end() const noexcept {
        return {*this, norm_stop};
    }
    /**
     * @brief x の個数 (0 か 1)
     */
    constexpr difference_type count(value_type x) const noexcept {
        if (step > 0) {
            if (start <= x and x < stop) {
                if ((x - start) % step == 0) {
                    return 1;
                }
            }
        } else {
            if (stop < x and x <= start) {
                if ((start - x) % (-step) == 0) {
                    return 1;
                }
            }
        }
        return 0;
    }
    /**
     * @brief x が含まれるか
     */
    constexpr bool contains(value_type x) const noexcept {
        return count(x) != 0;
    }
    /**
     * @brief x のインデックス
     * x が含まれないとエラー
     */
    constexpr size_type index(value_type x) const {
        assert(contains(x));
        return (x - start) / step;
    }
    /**
     * @brief 要素が x のイテレータ
     * x が含まれないと end() を返す
     */
    constexpr const_iterator find(value_type x) const noexcept {
        if (contains(x)) {
            return {*this, x};
        } else {
            return {*this, norm_stop};
        }
    }
    /**
     * @brief 要素が x 以上の最小のイテレータ
     * step > 0 じゃないとエラー
     */
    constexpr const_iterator lower_bound(value_type x) const {
        assert(step > 0);
        if (norm_stop <= x) {
            return end();
        } else if (x < start) {
            return begin();
        } else {
            return {*this, start + (x - start + step - 1) / step * step};
        }
    }
    /**
     * @brief 要素が x より大きい最小のイテレータ
     * step > 0 じゃないとエラー
     */
    constexpr const_iterator upper_bound(value_type x) const {
        assert(step > 0);
        if (norm_stop <= x) {
            return end();
        } else if (x < start) {
            return begin();
        } else {
            return {*this, start + (x - start + step) / step * step};
        }
    }
    /**
     * @brief コンテナの要素数
     */
    constexpr size_type size() const noexcept {
        if (step > 0) {
            return (norm_stop - start) / step;
        } else {
            return (start - norm_stop) / (-step);
        }
    }
    constexpr value_type at(size_type i) const {
        assert(i < size());
        return start + i * step;
    }
    constexpr value_type operator[](size_type i) const {
        return at(i);
    }
    constexpr bool empty() const noexcept {
        return start == norm_stop;
    }
    constexpr value_type sum() const noexcept {
        return static_cast<Range::value_type>(size()) * (norm_stop - step + start) / 2;
    }
    /**
     * @brief 最小値
     * 空だとエラー
     */
    constexpr value_type min() const {
        assert(not empty());
        if (step > 0) {
            return start;
        } else {
            return norm_stop - step;
        }
    }
    /**
     * @brief 最大値
     * 空だとエラー
     */
    constexpr value_type max() const {
        assert(not empty());
        if (step > 0) {
            return norm_stop - step;
        } else {
            return start;
        }
    }
    /**
     * @brief 総 xor
     * 負を含むとエラー
     */
    constexpr value_type product_xor() const noexcept {
        if (empty()) return 0;
        assert(min() >= 0);
        Range sorted_range(sorted());
        value_type res = 0;
        std::make_unsigned_t<value_type> t = 1;
        while (t <= static_cast<std::make_unsigned_t<value_type>>(max())) {
            std::make_unsigned_t<value_type> tmp = 0, n = size(), m = t, a = sorted_range.step, b = sorted_range.start;
            while (true) {
                if (a >= m) {
                    tmp += n * (n - 1) / 2 * (a / m);
                    a %= m;
                }
                if (b >= m) {
                    tmp += n * (b / m);
                    b %= m;
                }
                std::make_unsigned_t<value_type> y_max = a * n + b;
                if (y_max < m) break;
                n = y_max / m;
                b = y_max % m;
                std::swap(m, a);
            }
            if (tmp % 2 == 1) {
                res += t;
            }
            t <<= 1;
        }
        return res;
    }
    /**
     * @brief 逆順にしたもの
     */
    constexpr Range reversed() const noexcept {
        return {norm_stop - step, start - step, -step, start - step};
    }
    /**
     * @brief step > 0 だとそのまま step < 0 だと逆順にしたもの
     */
    constexpr Range sorted() const noexcept {
        if (step > 0) {
            return {start, norm_stop, step, norm_stop};
        } else {
            return {norm_stop - step, start - step, -step, start - step};
        }
    }
    /**
     * @brief 要素が [l,r] である範囲を返す
     */
    constexpr Range clipped(value_type l, value_type r) const {
        if (l > r) return {};
        if (step > 0) {
            value_type _start = [&] {
                if (norm_stop <= l) {
                    return norm_stop;
                } else if (l < start) {
                    return start;
                } else {
                    return start + (l - start + step - 1) / step * step;
                }
            }();
            value_type _stop = [&] {
                if (norm_stop <= r) {
                    return norm_stop;
                } else if (r < start) {
                    return start;
                } else {
                    return start + (r - start + step) / step * step;
                }
            }();
            return {_start, _stop, step, _stop};
        } else {
            value_type _start = [&] {
                if (start - step <= r) {
                    return start;
                } else if (r < norm_stop - step) {
                    return norm_stop;
                } else {
                    return norm_stop + (r - norm_stop) / step * step;
                }
            }();
            value_type _stop = [&] {
                if (start - step <= l) {
                    return start;
                } else if (l < norm_stop - step) {
                    return norm_stop;
                } else {
                    return norm_stop + (l - norm_stop - 1) / step * step;
                }
            }();
            return {_start, _stop, step, _stop};
        }
    }
    /**
     * @brief 要素を Range で指定したコンテナ
     */
    constexpr Range slice(const Range& r) const {
        if (r.empty()) return {};
        if (r.max() < 0) return {};
        if (r.min() >= static_cast<Range::value_type>(size())) return {};
        Range trimmed_range(r.clipped(0, static_cast<Range::value_type>(size()) - 1));
        if (trimmed_range.empty()) return {};
        value_type _step = step * trimmed_range.step;
        value_type _start = at(trimmed_range.start);
        value_type _stop = _start + _step * static_cast<Range::value_type>(trimmed_range.size());
        return {_start, _stop, _step, _stop};
    }

    static std::string type_str() {
        return "Range";
    }
    std::string initializer_str() const {
        return "{" + std::to_string(start) + ", " + std::to_string(stop) + ", " + std::to_string(step) + "}";
    }
    std::string repr() const {
        return "Range(" + std::to_string(start) + ", " + std::to_string(stop) + ", " + std::to_string(step) + ")";
    }

    std::vector<value_type> to_vector() const {
        std::vector<value_type> ret;
        ret.reserve(size());
        if (step > 0) {
            for (value_type x = start; x < stop; x += step) {
                ret.push_back(x);
            }
        } else {
            for (value_type x = start; x > stop; x += step) {
                ret.push_back(x);
            }
        }
        return ret;
    }
    constexpr friend bool operator==(const Range& a, const Range& b) noexcept {
        if (a.empty() and b.empty()) return true;
        if (a.size() != b.size()) return false;
        if (a.start != b.start) return false;
        if (a.size() == 1) return true;
        if (a.step != b.step) return false;
        return true;
    }
    constexpr friend bool operator!=(const Range& a, const Range& b) noexcept {
        return !(a == b);
    }
};
#line 14 "test/unittest/range.test.cpp"

using ll = long long;

// Python の range(start, stop, step) と同じ列
std::vector<ll> naive_range(ll start, ll stop, ll step) {
    std::vector<ll> v;
    if (step > 0) {
        for (ll x = start; x < stop; x += step) v.push_back(x);
    } else {
        for (ll x = start; x > stop; x += step) v.push_back(x);
    }
    return v;
}

std::vector<ll> by_iteration(const Range& r) {
    std::vector<ll> v;
    for (ll x : r) v.push_back(x);
    return v;
}

// コンパイル時にも使える
static_assert(Range(0, 10, 3).size() == 4);
static_assert(Range(10, 0, -3).sum() == 22);
static_assert(Range(5).max() == 4);

int main() {
    std::mt19937_64 rng(314);
    auto rnd = [&](ll lo, ll hi) { return lo + (ll)(rng() % (unsigned long long)(hi - lo + 1)); };
    bool ok = true;
    auto check = [&](bool cond, const char* what) {
        if (!cond) {
            if (ok) std::cerr << "failed: " << what << std::endl;
            ok = false;
        }
    };

    // コンストラクタ
    check(by_iteration(Range(5)) == naive_range(0, 5, 1), "Range(stop)");
    check(by_iteration(Range(-3)).empty(), "Range(negative stop)");
    check(by_iteration(Range(2, 7)) == naive_range(2, 7, 1), "Range(start, stop)");
    check(Range().empty() && Range().size() == 0 && by_iteration(Range()).empty(), "Range()");
    {
        Range a(1, 20, 4);
        Range b(a);  // コピー
        check(by_iteration(b) == naive_range(1, 20, 4), "copy");
    }

    for (int rep = 0; rep < 20000 && ok; rep++) {
        ll start = rnd(-20, 20), stop = rnd(-20, 20), step = rnd(1, 7) * (rng() % 2 ? 1 : -1);
        Range r(start, stop, step);
        std::vector<ll> v = naive_range(start, stop, step);
        int n = v.size();

        check(r.start == start && r.stop == stop && r.step == step, "members");
        check(by_iteration(r) == v, "iteration");
        check(r.to_vector() == v, "to_vector");
        check(std::vector<ll>(r.begin(), r.end()) == v, "iterator range constructor");
        check(r.size() == (size_t)n, "size");
        check(r.empty() == v.empty(), "empty");
        check(r.end() - r.begin() == n, "end - begin");
        for (int i = 0; i < n; i++) {
            check(r.at(i) == v[i] && r[i] == v[i], "at / []");
        }

        // count, contains, index, find
        for (ll x = -30; x <= 30; x++) {
            int c = std::count(v.begin(), v.end(), x);
            check(r.count(x) == c, "count");
            check(r.contains(x) == (c > 0), "contains");
            if (c > 0) {
                int idx = std::find(v.begin(), v.end(), x) - v.begin();
                check(r.index(x) == (size_t)idx, "index");
                check(*r.find(x) == x && r.find(x) - r.begin() == idx, "find (found)");
            } else {
                check(r.find(x) == r.end(), "find (not found)");
            }
        }

        // lower_bound, upper_bound (step > 0 のときだけ使える)
        if (step > 0) {
            for (ll x = -30; x <= 30; x++) {
                check(r.lower_bound(x) - r.begin() == std::lower_bound(v.begin(), v.end(), x) - v.begin(), "lower_bound");
                check(r.upper_bound(x) - r.begin() == std::upper_bound(v.begin(), v.end(), x) - v.begin(), "upper_bound");
            }
        }

        // sum, min, max
        ll sum = 0;
        for (ll x : v) sum += x;
        check(r.sum() == sum, "sum");
        if (n > 0) {
            check(r.min() == *std::min_element(v.begin(), v.end()), "min");
            check(r.max() == *std::max_element(v.begin(), v.end()), "max");
        }

        // reversed, sorted
        std::vector<ll> rv(v.rbegin(), v.rend()), sv = v;
        std::sort(sv.begin(), sv.end());
        check(by_iteration(r.reversed()) == rv && r.reversed().size() == (size_t)n, "reversed");
        check(by_iteration(r.sorted()) == sv && r.sorted().size() == (size_t)n, "sorted");

        // clipped: 値が [l, r] の要素だけを順番を保って残す
        {
            ll l = rnd(-25, 25), rr = rnd(-25, 25);
            std::vector<ll> expect;
            if (l <= rr) {
                for (ll x : v)
                    if (l <= x && x <= rr) expect.push_back(x);
            }
            Range c = r.clipped(l, rr);
            check(by_iteration(c) == expect && c.size() == expect.size(), "clipped");
        }

        // slice: インデックスを Range で指定する (範囲外のインデックスは無視)
        {
            ll s2 = rnd(-25, 25), t2 = rnd(-25, 25), st2 = rnd(1, 5) * (rng() % 2 ? 1 : -1);
            Range idx(s2, t2, st2);
            std::vector<ll> expect;
            for (ll i : naive_range(s2, t2, st2))
                if (0 <= i && i < n) expect.push_back(v[i]);
            Range s = r.slice(idx);
            check(by_iteration(s) == expect && s.size() == expect.size(), "slice");
        }

        // ==, != は列として等しいか
        {
            ll start2 = rng() % 4 == 0 ? start : rnd(-20, 20);
            ll stop2 = rng() % 2 == 0 ? stop + rnd(-3, 3) : rnd(-20, 20);
            ll step2 = rng() % 2 == 0 ? step : rnd(1, 7) * (rng() % 2 ? 1 : -1);
            Range r2(start2, stop2, step2);
            bool same = v == naive_range(start2, stop2, step2);
            check((r == r2) == same && (r != r2) == !same, "== / !=");
        }

        // イテレータの各演算
        if (n > 0) {
            int i = rnd(0, n - 1), j = rnd(0, n - 1);
            auto it = r.begin() + i;
            check(*it == v[i] && it.base() == v[i], "begin + i");
            check(*(i + r.begin()) == v[i], "i + begin");
            check(*(r.end() - (n - i)) == v[i], "end - k");
            check((r.begin() + j) - it == j - i, "iterator difference");
            auto it2 = it;  // コピーコンストラクタ
            check(it2 == it && !(it2 != it), "copy / ==");
            it2 = r.begin();  // 同じ Range のイテレータの代入
            check(*it2 == v[0], "operator=");
            auto a = it;
            auto b = a++;
            check(*b == v[i] && a - b == 1, "post ++");
            auto c = ++b;
            check(c == a && *c == *a, "pre ++");
            auto d = a--;
            check(d - a == 1 && *a == v[i], "post --");
            --d;
            check(d == a, "pre --");
            auto e = it;
            e += j - i;
            check(*(e) == v[j] || j == n, "+=");
            e -= j - i;
            check(e == it, "-=");
            check(it != r.end(), "!= end");
        }
        check(r.begin() + n == r.end(), "begin + size == end");
    }

    // product_xor (負を含まない列)
    for (int rep = 0; rep < 5000 && ok; rep++) {
        ll start, stop, step;
        if (rep % 2 == 0) {
            start = rnd(0, 100), stop = rnd(0, 100), step = rnd(1, 9) * (rng() % 2 ? 1 : -1);
            if (step < 0 && stop < -1) stop = -1;
        } else {
            // 大きい値 (要素数は少なめ)
            start = rnd(0, 1000000000000LL), step = rnd(1, 1000000000LL) * (rng() % 2 ? 1 : -1);
            stop = start + step * rnd(0, 300);
            if (stop < -1) stop = -1;
        }
        Range r(start, stop, step);
        ll x = 0;
        for (ll y : naive_range(start, stop, step)) x ^= y;
        check(r.product_xor() == x, "product_xor");
    }

    // 文字列化
    {
        Range r(-3, 10, 2);
        check(Range::type_str() == "Range", "type_str");
        check(r.initializer_str() == "{-3, 10, 2}", "initializer_str");
        check(r.repr() == "Range(-3, 10, 2)", "repr");
    }

    if (ok) std::cout << "Hello World" << std::endl;
}
Back to top page