Note that there are some explanatory texts on larger screens.

plurals
  1. POCleaning up bidirectional iterator code
    primarykey
    data
    text
    <p>I've modified <a href="https://stackoverflow.com/questions/3623082/flattening-iterator/3623597#3623597">James' flattening iterator</a> to act as a bidirectional iterator if possible, but I don't think my changes are very elegant (particularly relying on a bool to see if the inner iterator has been set). However, I can't seem to come up with a nicer solution. Does anyone have any ideas?</p> <pre><code>#include &lt;algorithm&gt; #include &lt;iostream&gt; #include &lt;set&gt; #include &lt;vector&gt; #include &lt;iterator&gt; #include &lt;type_traits&gt; // An iterator that "flattens" a container of containers. For example, // a vector&lt;vector&lt;int&gt;&gt; containing { { 1, 2, 3 }, { 4, 5, 6 } } is iterated as // a single range, { 1, 2, 3, 4, 5, 6 }. template &lt;typename OuterIterator&gt; class flattening_iterator { public: typedef OuterIterator outer_iterator; typedef typename std::iterator_traits&lt;outer_iterator&gt;::value_type::iterator inner_iterator; typedef typename std::iterator_traits&lt;outer_iterator&gt;::iterator_category outer_category; typedef typename std::iterator_traits&lt;inner_iterator&gt;::iterator_category inner_category; typedef typename std::common_type&lt;outer_category, inner_category&gt;::type common_category; typedef typename std::conditional&lt;std::is_same&lt;common_category, std::random_access_iterator_tag&gt;::value, std::bidirectional_iterator_tag, common_category&gt;::type iterator_category; typedef typename std::iterator_traits&lt;inner_iterator&gt;::value_type value_type; typedef typename std::iterator_traits&lt;inner_iterator&gt;::difference_type difference_type; typedef typename std::iterator_traits&lt;inner_iterator&gt;::pointer pointer; typedef typename std::iterator_traits&lt;inner_iterator&gt;::reference reference; flattening_iterator() { } flattening_iterator(outer_iterator it, outer_iterator begin, outer_iterator end) : outer_it_(it), outer_begin_(begin), outer_end_(end), inner_it_assigned_(false) { if (outer_begin_ == outer_end_) { return; } if (outer_it_ == outer_end_) { return; } inner_it_ = outer_it_-&gt;begin(); inner_it_assigned_ = true; advance_past_empty_inner_containers(); } reference operator*() const { return *inner_it_; } pointer operator-&gt;() const { return &amp;*inner_it_; } flattening_iterator&amp; operator++() { ++inner_it_; if (inner_it_ == outer_it_-&gt;end()) advance_past_empty_inner_containers(); return *this; } flattening_iterator operator++(int) { flattening_iterator it(*this); ++*this; return it; } flattening_iterator&amp; operator--() { if(!inner_it_assigned_) { if(outer_begin_ != outer_end_) { decrement_through_empty_inner_containers(); } return *this; } if(inner_it_ == outer_it_-&gt;begin()) { decrement_through_empty_inner_containers(); } else { --inner_it_; } return *this; } flattening_iterator operator--(int) { flattening_iterator it(*this); --*this; return it; } friend bool operator==(const flattening_iterator&amp; a, const flattening_iterator&amp; b) { if (a.outer_it_ != b.outer_it_) return false; if(a.outer_it_ != a.outer_end_ &amp;&amp; b.outer_it_ != b.outer_end_ &amp;&amp; a.inner_it_assigned_ == false &amp;&amp; b.inner_it_assigned_ == false) return true; if (a.outer_it_ != a.outer_end_ &amp;&amp; b.outer_it_ != b.outer_end_ &amp;&amp; a.inner_it_ != b.inner_it_) return false; return true; } friend bool operator!=(const flattening_iterator&amp; a, const flattening_iterator&amp; b) { return !(a == b); } private: void advance_past_empty_inner_containers() { while (outer_it_ != outer_end_ &amp;&amp; inner_it_ == outer_it_-&gt;end()) { ++outer_it_; if (outer_it_ != outer_end_) inner_it_ = outer_it_-&gt;begin(); } } void decrement_through_empty_inner_containers() { --outer_it_; while(outer_it_ != outer_begin_ &amp;&amp; outer_it_-&gt;begin() == outer_it_-&gt;end()) { --outer_it_; } if(outer_it_-&gt;begin() != outer_it_-&gt;end()) { inner_it_ = --outer_it_-&gt;end(); inner_it_assigned_ = true; } } outer_iterator outer_it_; outer_iterator outer_begin_; outer_iterator outer_end_; inner_iterator inner_it_; bool inner_it_assigned_; }; template &lt;typename Iterator&gt; flattening_iterator&lt;Iterator&gt; flatten(Iterator start, Iterator first, Iterator last) { return flattening_iterator&lt;Iterator&gt;(start, first, last); } template &lt;typename Iterator&gt; std::reverse_iterator&lt;flattening_iterator&lt;Iterator&gt;&gt; flatten_reverse(Iterator start, Iterator first, Iterator last) { return std::reverse_iterator&lt;flattening_iterator&lt;Iterator&gt;&gt;(flatten(start, first, last)); } int main() { std::vector&lt;std::vector&lt;int&gt;&gt; v(3); int i(0); for (auto it(v.begin()); it != v.end(); ++it) { it-&gt;push_back(i++); it-&gt;push_back(i++); it-&gt;push_back(i++); it-&gt;push_back(i++); } v.insert(v.begin(), std::vector&lt;int&gt;()); v.insert(v.begin(), std::vector&lt;int&gt;()); v.insert(v.begin() + 4, std::vector&lt;int&gt;()); v.push_back(std::vector&lt;int&gt;()); v.push_back(std::vector&lt;int&gt;()); for (auto it(flatten(v.begin(), v.begin(), v.end())), end = flatten(v.end(), v.begin(), v.end()); it != end; ++it) { std::cout &lt;&lt; *it &lt;&lt; ", "; } std::cout &lt;&lt; "\n"; for (auto it(flatten_reverse(v.end(), v.begin(), v.end())), end = flatten_reverse(v.begin(), v.begin(), v.end()); it != end; ++it) { std::cout &lt;&lt; *it &lt;&lt; ", "; } std::cout &lt;&lt; "\n"; std::vector&lt;std::vector&lt;int&gt;&gt; v2; for (auto it(flatten(v2.end(), v2.begin(), v2.end())), end = flatten(v2.begin(), v2.begin(), v2.end()); it != end; --it) { std::cout &lt;&lt; *it &lt;&lt; ", "; } std::cout &lt;&lt; "\n"; } </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload