Source

swish_comet / 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.