📄 ienumiterator.hpp
字号:
Next();
numSkipped++;
}
return numSkipped;
}
template <class T, class E>
void TCache<T,E>::Destroy()
{
EmptyCache();
delete [] m_pCache;
}
template <class T, class E>
void TCache<T,E>::DestroyItem(E item)
{
// It's easier to place the replacable code for destroying an
// item in the iterator.... So, we'll call a private static member function
// on our iterator to destroy it
T::DestroyItem(item);
}
template <class T, class E>
E *TCache<T,E>::CopyCache() const
{
return CopyCache(m_pCache, m_current, m_cached, m_allocatedSize);
}
template <class T, class E>
E *TCache<T,E>::CopyCache(
E *pCache,
unsigned long current,
unsigned long cached,
unsigned long newSize)
{
E *pNewCache = 0;
if (newSize)
{
pNewCache = new E[newSize];
// Only copy the valid area of the cache...
for (unsigned long i = current; i < cached; i++)
{
pNewCache[i] = T::CopyItem(pCache[i]);
}
}
return pNewCache;
}
///////////////////////////////////////////////////////////////////////////////
// Implement IEnumIterator
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Construction and destruction
///////////////////////////////////////////////////////////////////////////////
template <class T, class I, class E>
IEnumIterator<T,I,E>::IEnumIterator(I *pIEnum, unsigned long max /* = 1 */)
: m_pIEnum(SafeAddRef(pIEnum)),
m_cache(max),
m_bAtEnd(false),
m_bNotPrimed(true)
{
if (!m_pIEnum)
{
m_bAtEnd = true;
m_bNotPrimed = false;
}
}
template <class T, class I, class E>
IEnumIterator<T,I,E>::IEnumIterator(const IEnumIterator<T,I,E> &rhs)
: m_pIEnum(0),
m_cache(rhs.m_cache),
m_bAtEnd(rhs.m_bAtEnd),
m_bNotPrimed(rhs.m_bNotPrimed)
{
if (rhs.m_pIEnum)
{
HRESULT hr = rhs.m_pIEnum->Clone(&m_pIEnum);
if (FAILED(hr))
{
throw CComException(_T("IEnumIterator<T,I,E>::IEnumIterator()"), hr);
}
}
}
template <class T, class I, class E>
IEnumIterator<T,I,E>::~IEnumIterator()
{
m_pIEnum = SafeRelease(m_pIEnum);
}
template <class T, class I, class E>
IEnumIterator<T,I,E> &IEnumIterator<T,I,E>::operator=(const IEnumIterator<T,I,E> &rhs)
{
if (this != &rhs)
{
if (rhs.m_pIEnum)
{
I *pNewEnum = 0;
HRESULT hr = rhs.m_pIEnum->Clone(&pNewEnum);
if (SUCCEEDED(hr))
{
m_pIEnum->Release();
m_pIEnum = pNewEnum;
m_cache = rhs.m_cache;
}
else
{
throw CComException("IEnumIterator<T,I,E>::operator=", hr);
}
}
else
{
m_pIEnum = 0;
}
m_bAtEnd = rhs.m_bAtEnd;
m_bNotPrimed = rhs.m_bNotPrimed;
}
return *this;
}
///////////////////////////////////////////////////////////////////////////////
// Iteration
///////////////////////////////////////////////////////////////////////////////
template <class T, class I, class E>
IEnumIterator<T,I,E> &IEnumIterator<T,I,E>::operator++()
{
// Since we no longer call advance in the ctor we must
// make sure it's been called once to make the first item
// valid before we advance away from the first item,
// It's messier but at least we don't have a fully primed
// iterator to copy around straight after construction...
CheckPrimed();
Advance();
return *this;
}
#ifdef IENUM_ITERATOR_USE_POST_INC
template <class T, class I, class E>
IEnumIterator<T,I,E> IEnumIterator<T,I,E>::operator++(int)
{
// Since we no longer call advance in the ctor we must
// make sure it's been called once to make the first item
// valid before we advance away from the first item,
// It's messier but at least we don't have a fully primed
// iterator to copy around straight after construction...
CheckPrimed();
T oldValue = *this;
Advance();
return oldValue;
}
#endif // IENUM_ITERATOR_USE_POST_INC
template <class T, class I, class E>
bool IEnumIterator<T,I,E>::operator!=(const IEnumIterator<T,I,E> &rhs)
{
// defer to operator==
return !(*this == rhs);
}
template <class T, class I, class E>
bool IEnumIterator<T,I,E>::operator==(const IEnumIterator<T,I,E> &rhs)
{
// Since we no longer call advance in the ctor we must
// make sure it's been called once to make the first item
// valid before we access it for the first time.
// It's messier but at least we don't have a fully primed
// iterator to copy around straight after construction...
CheckPrimed();
// should compare contents of Enumerated?
return ((m_pIEnum == rhs.m_pIEnum && (true)) ||
m_bAtEnd && m_cache.IsEmpty() &&
rhs.m_bAtEnd && rhs.m_cache.IsEmpty());
}
template <class T, class I, class E>
const T &IEnumIterator<T,I,E>::End()
{
static T End(0,0);
return End;
}
template <class T, class I, class E>
void IEnumIterator<T,I,E>::Reset()
{
if (m_pIEnum)
{
HRESULT hr = m_pIEnum->Reset();
if (S_OK != hr)
{
throw CComException(_T("IEnumIterator<T,I,E>::Reset()"), hr);
}
m_bAtEnd = false;
m_cache.EmptyCache();
m_bNotPrimed = true;
}
}
template <class T, class I, class E>
unsigned long IEnumIterator<T,I,E>::Skip(unsigned long numToSkip)
{
unsigned long numSkipped = 0;
if (m_pIEnum)
{
numSkipped = m_cache.Skip(numToSkip);
if (numSkipped != numToSkip)
{
// Even after skipping all entries in the cache, we still must
// skip more...
if (S_OK == m_pIEnum->Skip(numToSkip - numSkipped))
{
numSkipped = numToSkip;
}
else
{
// That's all folks...
m_bAtEnd = true;
}
// cache is empty now, but we'll leave priming it until we need
// to access it...
m_bNotPrimed = true;
}
}
return numSkipped;
}
///////////////////////////////////////////////////////////////////////////////
// Access to what we're enumerating...
///////////////////////////////////////////////////////////////////////////////
template <class T, class I, class E>
const E &IEnumIterator<T,I,E>::Enumerated() const
{
// Since we no longer call advance in the ctor we must
// make sure it's been called once to make the first item
// valid before we access it for the first time.
// It's messier but at least we don't have a fully primed
// iterator to copy around straight after construction...
CheckPrimed();
CheckValid();
return m_cache.GetCurrent();
}
template <class T, class I, class E>
IEnumIterator<T,I,E>::operator E() const
{
return Enumerated();
}
///////////////////////////////////////////////////////////////////////////////
// Helper function for cache management
///////////////////////////////////////////////////////////////////////////////
template <class T, class I, class E>
void IEnumIterator<T,I,E>::SetCacheSize(unsigned long max)
{
m_cache.ResizeCache(max);
}
///////////////////////////////////////////////////////////////////////////////
// Helper function for operator ++
///////////////////////////////////////////////////////////////////////////////
template <class T, class I, class E>
void IEnumIterator<T,I,E>::Advance()
{
if (m_pIEnum)
{
if (!m_cache.Next() && !m_bAtEnd)
{
// Grab some more elements and cache them...
m_cache.EmptyCache();
unsigned long cached = 0;
HRESULT hr = m_pIEnum->Next(m_cache.GetSize(), m_cache.GetCache(), &cached);
m_cache.FillCache(cached);
if (S_FALSE == hr)
{
m_bAtEnd = true;
}
else if (S_OK != hr)
{
throw CComException(_T("IEnumIterator<T,I,E>::Advance()"), hr);
}
}
}
}
template <class T, class I, class E>
void IEnumIterator<T,I,E>::CheckValid() const
{
if (!m_pIEnum || m_cache.IsEmpty())
{
// Can't dereference an "End" iterator.
throw NullIterator();
}
}
template <class T, class I, class E>
void IEnumIterator<T,I,E>::CheckPrimed() const
{
// Since we no longer call advance in the ctor we must
// make sure it's been called once to make the first item
// valid before we advance away from the first item, or
// access it for the first time.
// It's messier but at least we don't have a fully primed
// iterator to copy around straight after construction...
if (m_bNotPrimed)
{
// Even though everything is mutable, we still can't call
// Advance() as it's a non-const member function. We could
// declare it as const (which seems wrong, it's not) or
// we can cheat like this... We'll cheat for now...
const_cast<IEnumIterator<T,I,E>*>(this)->Advance();
m_bNotPrimed = false;
}
}
///////////////////////////////////////////////////////////////////////////////
// Interface for TCache<T,E>
///////////////////////////////////////////////////////////////////////////////
template <class T, class I, class E>
void IEnumIterator<T,I,E>::DestroyItem(E item)
{
// Jump through hoops...
// Access an object known to exist.
// through a pointer to its base class (us)
const IEnumIterator<T,I,E> *pB = &End();
// As we can't call a private member function of another class
// but we can call one of ours... (and it's virtual)
pB->Destroy(item);
}
template <class T, class I, class E>
E IEnumIterator<T,I,E>::CopyItem(E item)
{
// Jump through hoops...
// Access an object known to exist.
// through a pointer to its base class (us)
const IEnumIterator<T,I,E> *pB = &End();
// As we can't call a private member function of another class
// but we can call one of ours... (and it's virtual)
return pB->Copy(item);
}
///////////////////////////////////////////////////////////////////////////////
// Namespace: JetByteTools
///////////////////////////////////////////////////////////////////////////////
} // End of namespace JetByteTools
#endif // __IENUM_ITERATOR__
///////////////////////////////////////////////////////////////////////////////
// End of file
///////////////////////////////////////////////////////////////////////////////
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -