Skip to content

Instantly share code, notes, and snippets.

@Nnwww
Last active July 8, 2017 19:04
Show Gist options
  • Save Nnwww/227521f87233ac21498f to your computer and use it in GitHub Desktop.
Save Nnwww/227521f87233ac21498f to your computer and use it in GitHub Desktop.
ちょっと前にpythonのzip関数を真似て作った必要最低限実装、forward_iteratorの可変個引数&非正格評価対応
#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