Anonymous avatar Anonymous committed bd51035

Added new enum_iterator that can iterate over the items of any COM enumerator.

The details of how the items are copied into the target need some work. The target may be a POD, in which case we must be careful to clear them, or a smart wrapper, in which case we don't need to. It's not clear how to do this in a way that satisfies both well.

Comments (0)

Files changed (1)

include/comet/enum_iterator.h

+/** \file 
+  * Standard C++ iterators wrapping any COM enumerator
+  */
+/*
+ * Copyright Š 2000 Sofus Mortensen
+ * Copyright Š 2011 Alexander Lamaison
+ *
+ * This material is provided "as is", with absolutely no warranty 
+ * expressed or implied. Any use is at your own risk. Permission to 
+ * use or copy this software for any purpose is hereby granted without 
+ * fee, provided the above notices are retained on all copies. 
+ * Permission to modify the code and to distribute modified code is 
+ * granted, provided the above notices are retained, and a notice that 
+ * the code was modified is included with the above copyright notice. 
+ *
+ * This header is part of comet.
+ * http://www.lambdasoft.dk/comet
+ */
+
+#ifndef COMET_ENUM_ITERATOR_H
+#define COMET_ENUM_ITERATOR_H
+
+#include <comet/config.h>
+
+#include <comet/enum_common.h>
+#include <comet/ptr.h>
+
+#include <stdexcept>
+
+namespace comet {
+
+	/**
+	 * STL style iterator for COM enumerator interfaces
+	 */
+	template<typename E, typename T=enumerated_type_of<E>::is>
+	class enum_iterator
+	{
+		typedef E                                   enumerator_type;
+		typedef T                                   value_type;
+		typedef typename enumerated_type_of<E>::is  element_type;
+		typedef impl::type_policy<element_type>     policy;
+
+		com_ptr<enumerator_type> enum_;
+
+		static value_type policy_init(const element_type& element)
+		{
+			value_type out;
+			policy::init(out, element);
+			return out;
+		}
+
+		static value_type copy_value_from_other(const enum_iterator& other)
+		{
+			value_type v;
+			if (other.is_value_set_)
+				return policy::init(v, other.value_);
+			return v;
+		}
+
+		value_type value_;
+
+		/**
+		 * Flag that ensures the value only gets cleared if it's been set.
+		 *
+		 * Clearing an uninitialised value could be disastrous as it could
+		 * contain any random bits which the clearing code could interpret as
+		 * pointers.
+		 *
+		 * This could happen in the situation where the enumerator has no
+		 * items so the value never gets set.
+		 */
+		bool is_value_set_;
+
+	public:
+		enum_iterator(const com_ptr<enumerator_type>& e) :
+		  enum_(e), is_value_set_(false)
+		{
+			next();
+		}
+		
+		enum_iterator() : is_value_set_(false) {}
+
+		enum_iterator(const enum_iterator& other) :
+			enum_(other.enum_), value_(copy_value_from_other(other)),
+			is_value_set_(other.is_value_set_) {}
+
+		enum_iterator& operator=(const enum_iterator& other)
+		{
+			enum_iterator copy(other);
+			swap(copy);
+			return *this;
+		}
+
+		void swap(enum_iterator& other)
+		{
+			enum_.swap(other.enum_);
+			std::swap(value_, other.value_);
+		}
+		
+		/** Move to next element. */
+		enum_iterator& operator++()
+		{
+			next();
+			return *this;
+		}
+		
+		/** Move to next element (post increment). */
+		enum_iterator operator++(int)
+		{
+			enum_iterator t(*this);
+			operator++();
+			return t;
+		}
+		
+		/**
+		 * Compare against end.
+		 * Comparisons against a non-end iterator throw an exception.
+		 * \todo Look into doing element comparisons.
+		 */
+		bool operator!=(const enum_iterator& other)
+		{
+			if (enum_ && other.enum_)
+				throw std::logic_error(
+					"enum_iterator comparison does not work");
+			
+			return enum_ || other.enum_;
+		}
+		
+		/** Current element. */
+		value_type& operator*()
+		{
+			return value_;
+		}
+
+		value_type* operator->()
+		{
+			return &value_;
+		}
+
+	private:
+
+		void next()
+		{
+			if (enum_)
+			{
+				unsigned long fetched = 0;
+				element_type pod;
+
+				enum_->Next(1, &pod, &fetched) | raise_exception;
+				if (fetched == 0)
+				{
+					enum_ = NULL;
+					return;
+				}
+
+				try
+				{
+					if (is_value_set_)
+						policy::clear(value_);
+					value_ = policy_init(pod);
+					is_value_set_ = true;
+				}
+				catch (...)
+				{
+					policy::clear(pod);
+					throw;
+				}
+				policy::clear(pod);
+			}
+		}
+	};	
+}	
+	
+#endif
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.