Browse Source

Creating an indexed iterator, for when you need to keep track of the 'index' while iterating through a collection.
For example, suppose you are creating a command line program that has a list of options. Instead of storing a map from index to value you want to use a vector, as there are no gaps. While iterating, you would then have to have a separate index counter, or use index iteration with operator[] instead of iterators, which means it would only work on random_access collections. indexed_iterator works on all types of iterables.

Samuel Jaffe 8 years ago
parent
commit
88ff581e82
3 changed files with 89 additions and 1 deletions
  1. 60 0
      indexed_iterator.hpp
  2. 23 0
      indexed_iterator.t.h
  3. 6 1
      iterator.xcodeproj/project.pbxproj

+ 60 - 0
indexed_iterator.hpp

@@ -0,0 +1,60 @@
+//
+//  indexed_iterator.hpp
+//  iterator
+//
+//  Created by Sam Jaffe on 3/5/17.
+//
+
+#pragma once
+
+#include <iterator>
+
+namespace iterator {
+  template <typename Iterator>
+  class indexed_iterator {
+  private:
+    using base_value_type = typename std::iterator_traits<Iterator>::value_type;
+    using base_reference = typename std::iterator_traits<Iterator>::reference;
+  public:
+    using index_type = typename std::iterator_traits<Iterator>::difference_type;
+    using value_type = std::pair<index_type, base_value_type>;
+    using reference = std::pair<index_type, base_reference>;
+    using pointer = void;
+    using difference_type = typename std::iterator_traits<Iterator>::difference_type;
+    using iterator_category = typename std::iterator_traits<Iterator>::iterator_category;
+    
+    indexed_iterator() : _base(), _index(0) {}
+    indexed_iterator(Iterator base, index_type idx = 0) : _base(base), _index(idx) {}
+    
+    template <typename OtherIterator>
+    indexed_iterator(indexed_iterator<OtherIterator> const & oiter) :
+    _base(oiter._base), _index(oiter._index) {
+      
+    }
+    
+    reference operator*() const { return reference{ _index, *_base }; }
+    
+    indexed_iterator & operator++() { ++_base; ++_index; return *this; }
+    indexed_iterator operator++(int) { indexed_iterator tmp{*this}; operator++(); return tmp; }
+    bool operator==(indexed_iterator const & other) const { return _base == other._base; }
+    bool operator!=(indexed_iterator const & other) const { return _base != other._base; }
+    
+    // Requires: iterator_category = bidirectional_iterator_tag
+    indexed_iterator & operator--() { --_base; --_index; return *this; }
+    indexed_iterator operator--(int) { indexed_iterator tmp{*this}; operator--(); return tmp; }
+    
+    // Requires: iterator_category = random_access_iterator_tag
+    indexed_iterator operator+(difference_type n) const { return indexed_iterator{*this} += n; }
+    indexed_iterator & operator+=(difference_type n) { _index += n; _base += n; return *this; }
+    indexed_iterator operator-(difference_type n) const { return indexed_iterator{*this} -= n; }
+    indexed_iterator & operator-=(difference_type n) { _index -= n; _base -= n;return *this; }
+    bool operator<=(indexed_iterator const & other) const { return _base <= other._base; }
+    bool operator< (indexed_iterator const & other) const { return _base <  other._base; }
+    bool operator>=(indexed_iterator const & other) const { return _base >= other._base; }
+    bool operator> (indexed_iterator const & other) const { return _base >  other._base; }
+  private:
+    template <typename It> friend class ::iterator::indexed_iterator;
+    Iterator _base;
+    index_type _index;
+  };
+}

+ 23 - 0
indexed_iterator.t.h

@@ -0,0 +1,23 @@
+//
+//  indexed_iterator.t.h
+//  iterator
+//
+//  Created by Sam Jaffe on 3/5/17.
+//
+
+#pragma once
+
+#include <cxxtest/TestSuite.h>
+
+#include "indexed_iterator.hpp"
+
+class indexed_iterator_TestSuite : public CxxTest::TestSuite {
+public:
+  void test_index_aligns_with_data() {
+    std::vector<int> const vec{5, 3, 2, 8, 9, 11, 2, 4};
+    iterator::indexed_iterator<std::vector<int>::const_iterator> it{vec.begin()}, end{vec.end()};
+    for (; it != end; ++it) {
+      TS_ASSERT_EQUALS((*it).second, vec[(*it).first]);
+    }
+  }
+};

+ 6 - 1
iterator.xcodeproj/project.pbxproj

@@ -23,6 +23,8 @@
 /* End PBXCopyFilesBuildPhase section */
 
 /* Begin PBXFileReference section */
+		CD13DDDC1E6CAB0A00554B52 /* indexed_iterator.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = indexed_iterator.hpp; sourceTree = "<group>"; };
+		CD13DDDD1E6CAB1500554B52 /* indexed_iterator.t.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = indexed_iterator.t.h; sourceTree = "<group>"; };
 		CD21AE1D1E4A3E7900536178 /* iterator_tc */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = iterator_tc; sourceTree = BUILT_PRODUCTS_DIR; };
 		CD21AE291E4A3EB000536178 /* iterator_tc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = iterator_tc.cpp; sourceTree = "<group>"; };
 		CD21AE2A1E4A3EB000536178 /* join_iterator.t.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = join_iterator.t.h; sourceTree = "<group>"; };
@@ -78,6 +80,7 @@
 				CD7172EE1E58C9930048DFFF /* recursive_iterator_mixed_container.t.h */,
 				CD679D731E5D19B900F9F843 /* recursive_iterator_accessors.t.h */,
 				CD595EE01E5BA3D300FC25BB /* unkeyed_iterator.t.h */,
+				CD13DDDD1E6CAB1500554B52 /* indexed_iterator.t.h */,
 				CD21AE291E4A3EB000536178 /* iterator_tc.cpp */,
 			);
 			name = test;
@@ -92,6 +95,7 @@
 				CD7172E91E57C6580048DFFF /* recursive_iterator.hpp */,
 				CD679D721E5D127600F9F843 /* recursive_iterator_meta.hpp */,
 				CD595EDF1E5BA27300FC25BB /* unkeyed_iterator.hpp */,
+				CD13DDDC1E6CAB0A00554B52 /* indexed_iterator.hpp */,
 			);
 			name = src;
 			sourceTree = "<group>";
@@ -162,13 +166,14 @@
 				"$(SRCROOT)/recursive_iterator_mixed_container.t.h",
 				"$(SRCROOT)/recursive_iterator_accessors.t.h",
 				"$(SRCROOT)/unkeyed_iterator.t.h",
+				"$(SRCROOT)/indexed_iterator.t.h",
 			);
 			outputPaths = (
 				"$(SRCROOT)/iterator_tc.cpp",
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
-			shellScript = "cxxtestgen --error-printer -o iterator_tc.cpp end_aware_iterator.t.h join_iterator.t.h recursive_iterator_one_dimension.t.h recursive_iterator_nested_map.t.h recursive_iterator_mixed_container.t.h recursive_iterator_accessors.t.h unkeyed_iterator.t.h";
+			shellScript = "cxxtestgen --error-printer -o iterator_tc.cpp end_aware_iterator.t.h join_iterator.t.h recursive_iterator_one_dimension.t.h recursive_iterator_nested_map.t.h recursive_iterator_mixed_container.t.h recursive_iterator_accessors.t.h unkeyed_iterator.t.h indexed_iterator.t.h";
 		};
 /* End PBXShellScriptBuildPhase section */