Skip to the content.

:heavy_check_mark: numeric/internal/two_pointer_technique.hpp

Depends on

Required by

Verified with

Code

#pragma once


#include <cassert>
#include <iterator>
#include <vector>
#include <utility>
#include <functional>
#include <valarray>

#include "snippet/iterations.hpp"

#include "internal/dev_env.hpp"
#include "internal/exception.hpp"


namespace uni {

namespace internal {

namespace interval_scanner_impl {


template<class T> using interval = std::pair<T, T>;
template<class T> using intervals = std::vector<std::pair<T, T>>;


template<class T>
struct base {
  protected:
    std::function<bool(T)> _validate;

  public:
    base(std::function<bool(T)> validate) : _validate(validate) {}

    void scan(T, T, T) {
        static_assert(internal::EXCEPTION_ON_TYPE<T>, "not implemented: scan()");
    }

    void split(const T first, const T last, intervals<T> *intervals) const {
        std::valarray<bool> _valid(false, last - first);
        for(auto itr=first,index=0; itr!=last; ++itr, ++index) _valid[index] = _validate(itr);

        auto can_begin = [&](const T itr) {
            const auto index = itr - first;
            if(itr == first) return _valid[index];
            if(itr == last) return false;
            if(not _valid[index-1] and _valid[index]) return true;
            return false;
        };

        auto is_end = [&](const T itr) {
            const  auto index = itr - first;
            if(itr == first) return false;
            if(itr == last) return _valid[index-1];
            if(_valid[index-1] and not _valid[index]) return true;
            return false;
        };

        {
            intervals->clear();
            T start = first;
            for(auto itr=first; ; ++itr) {
                if(can_begin(itr)) start = itr;
                if(is_end(itr)) intervals->emplace_back(start, itr);
                if(itr == last) break;
            }
        }
    }

    void scan_all(const T first, const T last) const {
        intervals<T> targets;
        this->split(first, last, &targets);
        ITR(start, end, targets) this->scan(first, start, end);
    }
};


} // namespace interval_scanner_impl

} // namespace internal


template<class T>
struct exclusive_interval_scanner : internal::interval_scanner_impl::base<T> {
  private:
    std::function<void(T)> _init;
    std::function<bool(T)> _can_expand;
    std::function<void(T)> _expand, _contract;
    std::function<void(T, T)> _apply;

  public:
    using interval = internal::interval_scanner_impl::interval<T>;
    using intervals = internal::interval_scanner_impl::intervals<T>;

    exclusive_interval_scanner(
        std::function<bool(T)> validate,
        std::function<void(T)> init,
        std::function<bool(T)> can_expand,
        std::function<void(T)> expand,
        std::function<void(T)> contract,
        std::function<void(T, T)> apply
    )
      : internal::interval_scanner_impl::base<T>(validate), _init(init), _can_expand(can_expand),
        _expand(expand), _contract(contract), _apply(apply)
    {}

    template<const bool FOLLOWING = true>
    void scan(const T start, const T end) const {
        T l_itr=start, r_itr=start;
        while(l_itr < end) {
            if (FOLLOWING and r_itr <= l_itr) {
                r_itr = l_itr+1;
                _init(l_itr);
            }
            while(r_itr < end && _can_expand(r_itr)) {
                _expand(r_itr++);
            }
            _apply(l_itr, r_itr);
            _contract(l_itr++);
        }
    };

    template<const bool FOLLOWING = true>
    void scan_all(const T first, const T last) const {
        intervals targets;
        this->split(first, last, &targets);
        ITR(start, end, targets) this->scan<FOLLOWING>(start, end);
    }
};


template<class T>
struct inclusive_interval_scanner : internal::interval_scanner_impl::base<T> {
  protected:
    std::function<void()> _init;
    std::function<bool()> _valid;
    std::function<void(T)> _expand, _contract;
    std::function<void(T, T)> _apply;

  public:
    using interval = internal::interval_scanner_impl::interval<T>;
    using intervals = internal::interval_scanner_impl::intervals<T>;

    inclusive_interval_scanner(
        std::function<bool(T)> validate,
        std::function<void()> init,
        std::function<bool()> valid,
        std::function<void(T)> expand,
        std::function<void(T)> contract,
        std::function<void(T, T)> apply
    ) : internal::interval_scanner_impl::base<T>(validate), _init(init), _valid(valid), _expand(expand), _contract(contract), _apply(apply) {}

    template<const bool INVERSE = false, const bool FOLLOWING = true, const bool CONFIRMATION = true>
    void scan(const T start, const T end) const {
        T l_itr = start, r_itr = start;
        _init();
        while(l_itr < end) {
            if(FOLLOWING and r_itr < l_itr) {
                r_itr = l_itr;
                _init();
            }
            if(r_itr < end and (INVERSE ^ _valid())) {
                _expand(r_itr++);
            }
            else {
                _contract(l_itr++);
            }
            if(!CONFIRMATION or _valid()) _apply(l_itr, r_itr);
        }
    }

    template<const bool INVERSE = false, const bool FOLLOWING = true, const bool CONFIRMATION = true>
    void scan_all(const T first, const T last) const {
        intervals targets;
        this->split(first, last, &targets);
        ITR(start, end, targets) this->scan<INVERSE,FOLLOWING,CONFIRMATION>(start, end);
    }
};


} // namespace uni
#line 2 "numeric/internal/two_pointer_technique.hpp"


#include <cassert>
#include <iterator>
#include <vector>
#include <utility>
#include <functional>
#include <valarray>

#line 2 "snippet/iterations.hpp"

#include <type_traits>
#line 2 "macro/overload.hpp"

#define $OVERLOAD2(arg0, arg1, cmd, ...) cmd
#define $OVERLOAD3(arg0, arg1, arg2, cmd, ...) cmd
#define $OVERLOAD4(arg0, arg1, arg2, arg3, cmd, ...) cmd
#define $OVERLOAD5(arg0, arg1, arg2, arg3, arg4, cmd, ...) cmd
#define $OVERLOAD6(arg0, arg1, arg2, arg3, arg4, arg5, cmd, ...) cmd
#line 2 "macro/basic.hpp"

#define TO_STRING_AUX(x) #x
#define TO_STRING(x) TO_STRING_AUX(x)

#define CONCAT_AUX(x, y) x##y
#define CONCAT(x, y) CONCAT_AUX(x, y)

#define UNPAREN_AUX(...) __VA_ARGS__
#define UNPAREN(...) __VA_ARGS__
#line 6 "snippet/iterations.hpp"


#define LOOP(n) REPI(CONCAT(_$, __COUNTER__), n)

#define REPI(i,n) for(std::remove_cvref_t<decltype(n)> i=0, CONCAT(i, $)=(n); i<CONCAT(i, $); ++i)
#define REPF(i,l,r) for(std::common_type_t<std::remove_cvref_t<decltype(l)>,std::remove_cvref_t<decltype(r)>> i=(l), CONCAT(i, $)=(r); i<CONCAT(i, $); ++i)
#define REPIS(i,l,r,s) for(std::common_type_t<std::remove_cvref_t<decltype(l)>,std::remove_cvref_t<decltype(r)>,std::remove_cvref_t<decltype(s)>> i=(l), CONCAT(i, $)=(r); i<CONCAT(i, $); i+=(s))

#define REPR(i,n) for(auto i=(n); --i>=0;)
#define REPB(i,l,r) for(std::common_type_t<std::remove_cvref_t<decltype(l)>,std::remove_cvref_t<decltype(r)>> i=(r), CONCAT(i, $)=(l); --i>=CONCAT(i, $);)
#define REPRS(i,l,r,s) for(std::common_type_t<std::remove_cvref_t<decltype(l)>,std::remove_cvref_t<decltype(r)>,std::remove_cvref_t<decltype(s)>> i=(l)+((r)-(l)-1)/(s)*(s), CONCAT(i, $)=(l); i>=CONCAT(i, $); (i-=(s)))

#define REP(...) $OVERLOAD4(__VA_ARGS__, REPIS, REPF, REPI, LOOP)(__VA_ARGS__)
#define REPD(...) $OVERLOAD4(__VA_ARGS__, REPRS, REPB, REPR)(__VA_ARGS__)

#define FORO(i,n) for(int i=0, CONCAT(i, $)=static_cast<int>(n); i<=CONCAT(i, $); ++i)
#define FORI(i,l,r) for(std::common_type_t<std::remove_cvref_t<decltype(l)>,std::remove_cvref_t<decltype(r)>> i=(l), CONCAT(i, $)=(r); i<=CONCAT(i, $); ++i)
#define FORIS(i,l,r,s) for(std::common_type_t<std::remove_cvref_t<decltype(l)>,std::remove_cvref_t<decltype(r)>,std::remove_cvref_t<decltype(s)>> i=(l), CONCAT(i, $)=(r); i<=CONCAT(i, $); i+=(s))

#define FORRO(i,n) for(auto i=(n); i>=0; --i)
#define FORR(i,l,r) for(std::common_type_t<std::remove_cvref_t<decltype(l)>,std::remove_cvref_t<decltype(r)>> i=(r), CONCAT(i, $)=(l); i>=CONCAT(i, $); --i)
#define FORRS(i,l,r,s) for(std::common_type_t<std::remove_cvref_t<decltype(l)>,std::remove_cvref_t<decltype(r)>,std::remove_cvref_t<decltype(s)>> i=(l)+((r)-(l))/(s)*(s), CONCAT(i, $)=(l); i>=CONCAT(i, $); i-=(s))

#define FOR(...) $OVERLOAD4(__VA_ARGS__, FORIS, FORI, FORO)(__VA_ARGS__)
#define FORD(...) $OVERLOAD4(__VA_ARGS__, FORRS, FORR, FORRO)(__VA_ARGS__)

#define ITR1(e0,v) for(const auto &e0 : (v))
#define ITRP1(e0,v) for(auto e0 : (v))
#define ITRR1(e0,v) for(auto &e0 : (v))

#define ITR2(e0,e1,v) for(const auto [e0, e1] : (v))
#define ITRP2(e0,e1,v) for(auto [e0, e1] : (v))
#define ITRR2(e0,e1,v) for(auto &[e0, e1] : (v))

#define ITR3(e0,e1,e2,v) for(const auto [e0, e1, e2] : (v))
#define ITRP3(e0,e1,e2,v) for(auto [e0, e1, e2] : (v))
#define ITRR3(e0,e1,e2,v) for(auto &[e0, e1, e2] : (v))

#define ITR4(e0,e1,e2,e3,v) for(const auto [e0, e1, e2, e3] : (v))
#define ITRP4(e0,e1,e2,e3,v) for(auto [e0, e1, e2, e3] : (v))
#define ITRR4(e0,e1,e2,e3,v) for(auto &[e0, e1, e2, e3] : (v))

#define ITR5(e0,e1,e2,e3,e4,v) for(const auto [e0, e1, e2, e3, e4] : (v))
#define ITRP5(e0,e1,e2,e3,e4,v) for(auto [e0, e1, e2, e3, e4] : (v))
#define ITRR5(e0,e1,e2,e3,e4,v) for(auto &[e0, e1, e2, e3, e4] : (v))

#define ITR(...) $OVERLOAD6(__VA_ARGS__, ITR5, ITR4, ITR3, ITR2, ITR1)(__VA_ARGS__)
#define ITRP(...) $OVERLOAD6(__VA_ARGS__, ITRP5, ITRP4, ITRP3, ITRP2, ITRP1)(__VA_ARGS__)
#define ITRR(...) $OVERLOAD6(__VA_ARGS__, ITRR5, ITRR4, ITRR3, ITRR2, ITRR1)(__VA_ARGS__)
#line 12 "numeric/internal/two_pointer_technique.hpp"

#line 2 "internal/dev_env.hpp"


#ifdef LOCAL_JUDGE
    inline constexpr bool DEV_ENV = true;
    inline constexpr bool NO_EXCEPT = false;
#else
    inline constexpr bool DEV_ENV = false;
    inline constexpr bool NO_EXCEPT = true;
#endif // LOCAL_JUDGE


#if __cplusplus >= 202100L
    #define CPP20 true
    #define CPP23 true
#elif __cplusplus >= 202002L
    #define CPP20 true
    #define CPP23 false
#else
    #define CPP20 false
    #define CPP23 false
#endif
#line 2 "internal/exception.hpp"


namespace uni {

namespace internal {


template<class... T> inline constexpr bool EXCEPTION_ON_TYPE = false;
template<auto T> inline constexpr bool EXCEPTION_ON_VALUE = false;


} // namespace internal

} // namespace uni
#line 15 "numeric/internal/two_pointer_technique.hpp"


namespace uni {

namespace internal {

namespace interval_scanner_impl {


template<class T> using interval = std::pair<T, T>;
template<class T> using intervals = std::vector<std::pair<T, T>>;


template<class T>
struct base {
  protected:
    std::function<bool(T)> _validate;

  public:
    base(std::function<bool(T)> validate) : _validate(validate) {}

    void scan(T, T, T) {
        static_assert(internal::EXCEPTION_ON_TYPE<T>, "not implemented: scan()");
    }

    void split(const T first, const T last, intervals<T> *intervals) const {
        std::valarray<bool> _valid(false, last - first);
        for(auto itr=first,index=0; itr!=last; ++itr, ++index) _valid[index] = _validate(itr);

        auto can_begin = [&](const T itr) {
            const auto index = itr - first;
            if(itr == first) return _valid[index];
            if(itr == last) return false;
            if(not _valid[index-1] and _valid[index]) return true;
            return false;
        };

        auto is_end = [&](const T itr) {
            const  auto index = itr - first;
            if(itr == first) return false;
            if(itr == last) return _valid[index-1];
            if(_valid[index-1] and not _valid[index]) return true;
            return false;
        };

        {
            intervals->clear();
            T start = first;
            for(auto itr=first; ; ++itr) {
                if(can_begin(itr)) start = itr;
                if(is_end(itr)) intervals->emplace_back(start, itr);
                if(itr == last) break;
            }
        }
    }

    void scan_all(const T first, const T last) const {
        intervals<T> targets;
        this->split(first, last, &targets);
        ITR(start, end, targets) this->scan(first, start, end);
    }
};


} // namespace interval_scanner_impl

} // namespace internal


template<class T>
struct exclusive_interval_scanner : internal::interval_scanner_impl::base<T> {
  private:
    std::function<void(T)> _init;
    std::function<bool(T)> _can_expand;
    std::function<void(T)> _expand, _contract;
    std::function<void(T, T)> _apply;

  public:
    using interval = internal::interval_scanner_impl::interval<T>;
    using intervals = internal::interval_scanner_impl::intervals<T>;

    exclusive_interval_scanner(
        std::function<bool(T)> validate,
        std::function<void(T)> init,
        std::function<bool(T)> can_expand,
        std::function<void(T)> expand,
        std::function<void(T)> contract,
        std::function<void(T, T)> apply
    )
      : internal::interval_scanner_impl::base<T>(validate), _init(init), _can_expand(can_expand),
        _expand(expand), _contract(contract), _apply(apply)
    {}

    template<const bool FOLLOWING = true>
    void scan(const T start, const T end) const {
        T l_itr=start, r_itr=start;
        while(l_itr < end) {
            if (FOLLOWING and r_itr <= l_itr) {
                r_itr = l_itr+1;
                _init(l_itr);
            }
            while(r_itr < end && _can_expand(r_itr)) {
                _expand(r_itr++);
            }
            _apply(l_itr, r_itr);
            _contract(l_itr++);
        }
    };

    template<const bool FOLLOWING = true>
    void scan_all(const T first, const T last) const {
        intervals targets;
        this->split(first, last, &targets);
        ITR(start, end, targets) this->scan<FOLLOWING>(start, end);
    }
};


template<class T>
struct inclusive_interval_scanner : internal::interval_scanner_impl::base<T> {
  protected:
    std::function<void()> _init;
    std::function<bool()> _valid;
    std::function<void(T)> _expand, _contract;
    std::function<void(T, T)> _apply;

  public:
    using interval = internal::interval_scanner_impl::interval<T>;
    using intervals = internal::interval_scanner_impl::intervals<T>;

    inclusive_interval_scanner(
        std::function<bool(T)> validate,
        std::function<void()> init,
        std::function<bool()> valid,
        std::function<void(T)> expand,
        std::function<void(T)> contract,
        std::function<void(T, T)> apply
    ) : internal::interval_scanner_impl::base<T>(validate), _init(init), _valid(valid), _expand(expand), _contract(contract), _apply(apply) {}

    template<const bool INVERSE = false, const bool FOLLOWING = true, const bool CONFIRMATION = true>
    void scan(const T start, const T end) const {
        T l_itr = start, r_itr = start;
        _init();
        while(l_itr < end) {
            if(FOLLOWING and r_itr < l_itr) {
                r_itr = l_itr;
                _init();
            }
            if(r_itr < end and (INVERSE ^ _valid())) {
                _expand(r_itr++);
            }
            else {
                _contract(l_itr++);
            }
            if(!CONFIRMATION or _valid()) _apply(l_itr, r_itr);
        }
    }

    template<const bool INVERSE = false, const bool FOLLOWING = true, const bool CONFIRMATION = true>
    void scan_all(const T first, const T last) const {
        intervals targets;
        this->split(first, last, &targets);
        ITR(start, end, targets) this->scan<INVERSE,FOLLOWING,CONFIRMATION>(start, end);
    }
};


} // namespace uni
Back to top page