It seems like I had to inline quite a bit of code here. I'm wondering if it's bad design practice to leave this entirely in a header file like this:
#pragma once
#include <string>
#include <boost/noncopyable.hpp>
#include <boost/make_shared.hpp>
#include <boost/iterator/iterator_facade.hpp>
#include <Windows.h>
#include "../Exception.hpp"
namespace WindowsAPI { namespace FileSystem {
class FileData;
struct AllResults;
struct FilesOnly;
template <typename Filter_T = AllResults>
class DirectoryIterator;
namespace detail {
class DirectoryIteratorImpl : public boost::noncopyable
{
WIN32_FIND_DATAW currentData;
HANDLE hFind;
std::wstring root;
public:
inline DirectoryIteratorImpl();
inline explicit DirectoryIteratorImpl(const std::wstring& pathSpec);
inline void increment();
inline bool equal(const DirectoryIteratorImpl& other) const;
inline const std::wstring& GetPathRoot() const;
inline const WIN32_FIND_DATAW& GetCurrentFindData() const;
inline ~DirectoryIteratorImpl();
};
}
class FileData //Serves as a proxy to the WIN32_FIND_DATA struture inside the iterator.
{
boost::shared_ptr<detail::DirectoryIteratorImpl> iteratorSource;
public:
FileData(const boost::shared_ptr<detail::DirectoryIteratorImpl>& parent) : iteratorSource(parent) {};
DWORD GetAttributes() const {
return iteratorSource->GetCurrentFindData().dwFileAttributes;
};
bool IsDirectory() const {
return (GetAttributes() | FILE_ATTRIBUTE_DIRECTORY) != 0;
};
bool IsFile() const {
return !IsDirectory();
};
bool IsArchive() const {
return (GetAttributes() | FILE_ATTRIBUTE_ARCHIVE) != 0;
};
bool IsReadOnly() const {
return (GetAttributes() | FILE_ATTRIBUTE_READONLY) != 0;
};
unsigned __int64 GetSize() const {
ULARGE_INTEGER intValue;
intValue.LowPart = iteratorSource->GetCurrentFindData().nFileSizeLow;
intValue.HighPart = iteratorSource->GetCurrentFindData().nFileSizeHigh;
return intValue.QuadPart;
};
std::wstring GetFolderPath() const {
return iteratorSource->GetPathRoot();
};
std::wstring GetFileName() const {
return iteratorSource->GetCurrentFindData().cFileName;
};
std::wstring GetFullFileName() const {
return GetFolderPath() + GetFileName();
};
std::wstring GetShortFileName() const {
return iteratorSource->GetCurrentFindData().cAlternateFileName;
};
FILETIME GetCreationTime() const {
return iteratorSource->GetCurrentFindData().ftCreationTime;
};
FILETIME GetLastAccessTime() const {
return iteratorSource->GetCurrentFindData().ftLastAccessTime;
};
FILETIME GetLastWriteTime() const {
return iteratorSource->GetCurrentFindData().ftLastWriteTime;
};
};
struct AllResults : public std::unary_function<const FileData&, bool>
{
bool operator()(const FileData&) {
return true;
};
};
struct FilesOnly : public std::unary_function<const FileData&, bool>
{
bool operator()(const FileData& arg) {
return arg.IsFile();
};
};
template <typename Filter_T>
class DirectoryIterator : public boost::iterator_facade<DirectoryIterator<Filter_T>, const FileData, std::input_iterator_tag>
{
friend class boost::iterator_core_access;
boost::shared_ptr<detail::DirectoryIteratorImpl> impl;
FileData current;
Filter_T filter;
void increment() {
do {
impl->increment();
} while (! filter(current));
};
bool equal(const DirectoryIterator& other) const {
return impl->equal(*other.impl);
};
const FileData& dereference() const {
return current;
};
public:
DirectoryIterator(Filter_T functor = Filter_T()) :
impl(boost::make_shared<detail::DirectoryIteratorImpl>()),
current(impl),
filter(functor) {
};
explicit DirectoryIterator(const std::wstring& pathSpec, Filter_T functor = Filter_T()) :
impl(boost::make_shared<detail::DirectoryIteratorImpl>(pathSpec)),
current(impl),
filter(functor) {
};
};
namespace detail {
DirectoryIteratorImpl::DirectoryIteratorImpl() : hFind(INVALID_HANDLE_VALUE) {
}
DirectoryIteratorImpl::DirectoryIteratorImpl(const std::wstring& pathSpec) {
std::wstring::const_iterator lastSlash =
std::find(pathSpec.rbegin(), pathSpec.rend(), L'\\').base();
root.assign(pathSpec.begin(), lastSlash);
hFind = FindFirstFileW(pathSpec.c_str(), ¤tData);
if (hFind == INVALID_HANDLE_VALUE)
WindowsApiException::ThrowFromLastError();
while (!wcscmp(currentData.cFileName, L".") || !wcscmp(currentData.cFileName, L"..")) {
increment();
}
}
void DirectoryIteratorImpl::increment() {
BOOL success =
FindNextFile(hFind, ¤tData);
if (success)
return;
DWORD error = GetLastError();
if (error == ERROR_NO_MORE_FILES) {
FindClose(hFind);
hFind = INVALID_HANDLE_VALUE;
} else {
WindowsApiException::Throw(error);
}
}
DirectoryIteratorImpl::~DirectoryIteratorImpl() {
if (hFind != INVALID_HANDLE_VALUE)
FindClose(hFind);
}
bool DirectoryIteratorImpl::equal(const DirectoryIteratorImpl& other) const {
if (this == &other)
return true;
return hFind == other.hFind;
}
const std::wstring& DirectoryIteratorImpl::GetPathRoot() const {
return root;
}
const WIN32_FIND_DATAW& DirectoryIteratorImpl::GetCurrentFindData() const {
return currentData;
}
}
}}