Last active
July 8, 2017 19:04
-
-
Save Nnwww/227521f87233ac21498f to your computer and use it in GitHub Desktop.
ちょっと前にpythonのzip関数を真似て作った必要最低限実装、forward_iteratorの可変個引数&非正格評価対応
This file contains 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 <tuple> | |
#include <iterator> | |
#include "tpl_utl.hpp" | |
namespace m_utl | |
{ | |
// support only forward_iterator | |
// e.g.) input {1,2,3}, {"abc","def","ghi"} -> output {{1,"abc"},{2,"def"},{3,"ghi"}} | |
// It will stop according to the most short container. | |
namespace detail | |
{ | |
template<typename Iter_Type, std::size_t Tpl_Size = std::tuple_size<Iter_Type>::value> | |
class zip { | |
Iter_Type _contents; | |
public: | |
explicit zip(Iter_Type &&arg) : | |
_contents(std::forward<Iter_Type>(arg)) { } | |
zip& operator++() | |
{ | |
m_utl::tpl_each(_contents, [](auto &elem) { ++elem; }); | |
return *this; | |
} | |
// 全ての要素が等しく、タプルの長さが等しいならば真 | |
template<typename Rhs> | |
bool equals(Iter_Type &lhs, Rhs &&rhs) | |
{ | |
// 本来なら実装せずタプルの演算子を使うべき… | |
std::size_t endidx = m_utl::tpl_all_of<Tpl_Size>(lhs, std::forward<Rhs>(rhs), [](auto &&ls, auto &&rs) { | |
return std::forward<decltype(ls)>(ls) == std::forward<decltype(rs)>(rs); | |
}); | |
return Tpl_Size == endidx; | |
} | |
template<typename Rhs> | |
bool operator==(Rhs &&rhs) | |
{ | |
return equals(_contents, std::forward<Rhs>(rhs).contents()); | |
} | |
template<typename Rhs> | |
bool operator!=(Rhs &&rhs) | |
{ | |
return !equals(_contents, std::forward<Rhs>(rhs).contents()); | |
} | |
auto operator*() | |
{ | |
// まずapply関数でtupleの内容物を取り出し、 | |
// 取り出された可変個のイテレータに対して更に内容物を取り出すための*演算子を実行したものをタプルとしてまとめて返す | |
auto applies_raw = m_utl::make_apply([](auto &... args) { | |
return std::make_tuple((*args)...); | |
}); | |
auto res = applies_raw(contents()); | |
return res; | |
} | |
Iter_Type& contents() | |
{ | |
return _contents; | |
} | |
}; | |
// 上記のzipを生成するためのクラス | |
// range-based forが要求するbegin/endと、sizeを実装 | |
template<typename... Args> | |
class zipper { | |
using value_type = decltype(std::make_tuple(std::declval<Args>()...)); | |
value_type values; | |
public: | |
explicit zipper(Args &&... args) : | |
values(std::make_tuple(std::forward<Args>(args)...)) { } | |
// beginが要求されたら、各コンテナの参照を展開しbeginを要求、それら値をタプルにまとめzipのインスタンスを生成 | |
auto begin() const | |
{ | |
auto applies_begin = m_utl::make_apply([](auto &... args) { | |
using std::begin; | |
return std::make_tuple(begin(args)...); | |
}); | |
return zip<decltype(applies_begin(values))>(applies_begin(values)); | |
} | |
auto end() const | |
{ | |
auto applies_end = m_utl::make_apply([](auto &... args) { | |
using std::end; | |
return std::make_tuple(end(args)...); | |
}); | |
return zip<decltype(applies_end(values))>(applies_end(values)); | |
} | |
// サイズは各コンテナを巡回し最も小さいものを返す | |
size_t size() | |
{ | |
std::size_t min_size; | |
m_utl::tpl_each(values, [&min_size](auto &elem) { min_size = std::min(min_size, elem.size()); }); | |
return min_size; | |
} | |
}; | |
} // namespace detail | |
// zipperを作成するユーティリティ関数 | |
template < typename... Args > | |
detail::zipper<Args...> make_zipper(Args&&... args) | |
{ | |
return detail::zipper<Args...>(std::forward<Args>(args)...); | |
} | |
} // namespace m_utl |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment