Index: llvm/trunk/include/llvm/ADT/STLExtras.h =================================================================== --- llvm/trunk/include/llvm/ADT/STLExtras.h +++ llvm/trunk/include/llvm/ADT/STLExtras.h @@ -356,65 +356,120 @@ template struct index_sequence_for; namespace detail { -template class zip_first { -public: - typedef std::input_iterator_tag iterator_category; - typedef std::tuple())...> value_type; +using std::declval; + +template +using zip_traits = iterator_facade_base< + ZipType, typename std::common_type::iterator_category...>::type, + // ^ TODO: Implement random access methods. + std::tuple())...>, + typename std::iterator_traits>::type>::difference_type, + // ^ FIXME: This follows boost::make_zip_iterator's assumption that all + // inner iterators have the same difference_type. It would fail if, for + // instance, the second field's difference_type were non-numeric while the + // first is. + std::tuple())...> *, + std::tuple())...>>; + +template +struct zip_common : public zip_traits { + using Base = zip_traits; + using value_type = typename Base::value_type; + std::tuple iterators; -private: - template value_type deres(index_sequence) { +protected: + template value_type deref(index_sequence) const { return value_type(*std::get(iterators)...); } - template decltype(iterators) tup_inc(index_sequence) { + template + decltype(iterators) tup_inc(index_sequence) const { return std::tuple(std::next(std::get(iterators))...); } + template + decltype(iterators) tup_dec(index_sequence) const { + return std::tuple(std::prev(std::get(iterators))...); + } + public: - value_type operator*() { return deres(index_sequence_for{}); } + zip_common(Iters &&... ts) : iterators(std::forward(ts)...) {} - void operator++() { iterators = tup_inc(index_sequence_for{}); } + value_type operator*() { return deref(index_sequence_for{}); } - bool operator!=(const zip_first &other) const { - return std::get<0>(iterators) != std::get<0>(other.iterators); + const value_type operator*() const { + return deref(index_sequence_for{}); } - zip_first(Iters &&... ts) : iterators(std::forward(ts)...) {} + + ZipType &operator++() { + iterators = tup_inc(index_sequence_for{}); + return *reinterpret_cast(this); + } + + ZipType &operator--() { + static_assert(Base::IsBidirectional, + "All inner iterators must be at least bidirectional."); + iterators = tup_dec(index_sequence_for{}); + return *reinterpret_cast(this); + } +}; + +template +struct zip_first : public zip_common, Iters...> { + using Base = zip_common, Iters...>; + + bool operator==(const zip_first &other) const { + return std::get<0>(this->iterators) == std::get<0>(other.iterators); + } + + zip_first(Iters &&... ts) : Base(std::forward(ts)...) {} }; -template class zip_shortest : public zip_first { +template +class zip_shortest : public zip_common, Iters...> { template - bool test(const zip_first &other, index_sequence) const { + bool test(const zip_shortest &other, index_sequence) const { return all_of(std::initializer_list{std::get(this->iterators) != std::get(other.iterators)...}, identity{}); } public: - bool operator!=(const zip_first &other) const { - return test(other, index_sequence_for{}); + using Base = zip_common, Iters...>; + + bool operator==(const zip_shortest &other) const { + return !test(other, index_sequence_for{}); } - zip_shortest(Iters &&... ts) - : zip_first(std::forward(ts)...) {} + + zip_shortest(Iters &&... ts) : Base(std::forward(ts)...) {} }; template