J'essaie d'écrire mon premier type de classe/conteneur d'itération. Fondamentalement, je veux être capable d'itérer à travers un fichier, avoir le fichier converti en HEX à la volée, et passer le résultat dans la bibliothèque boost :: xpressive. Je ne veux pas faire une conversion en une seule fois dans une RAM, car certains des fichiers dont j'ai besoin pour traiter sont plus grands que la RAM système attendue (plusieurs Go).Problèmes conceptuels avec Iterator
Voici à quoi ressemble mon code. J'utilise MSVC++ 2008.
tête pour Iterator:
class hexFile;
class hexIterator : public std::iterator<std::bidirectional_iterator_tag, wchar_t>
{
hexFile *parent;
__int64 cacheCurrentFor;
wchar_t cacheCharacters[2];
void updateCache();
public:
bool highCharacter;
__int64 filePosition;
hexIterator();
hexIterator(hexFile *file, bool begin);
hexIterator operator++();
hexIterator operator++(int)
{
return ++(*this);
}
hexIterator operator--();
hexIterator operator--(int)
{
return --(*this);
}
bool operator==(const hexIterator& toCompare) const;
bool operator!=(const hexIterator& toCompare) const;
wchar_t& operator*();
wchar_t* operator->();
};
mise en œuvre pour iterator:
#include <stdafx.h>
class hexFile;
hexIterator::hexIterator()
{
parent = NULL;
highCharacter = false;
filePosition = 0;
}
hexIterator::hexIterator(hexFile *file, bool begin) : parent(file)
{
if(begin)
{
filePosition = 0;
highCharacter = false;
} else
{
filePosition = parent->fileLength;
highCharacter = true;
}
}
hexIterator hexIterator::operator++()
{
if (highCharacter)
{
highCharacter = false;
filePosition++;
} else
{
highCharacter = true;
}
return (*this);
}
hexIterator hexIterator::operator--()
{
if (highCharacter)
{
highCharacter = false;
} else
{
filePosition--;
highCharacter = true;
}
return (*this);
}
bool hexIterator::operator==(const hexIterator& toCompare) const
{
if (toCompare.filePosition == filePosition &&
toCompare.highCharacter == highCharacter)
return true;
else return false;
}
bool hexIterator::operator!=(const hexIterator& toCompare) const
{
if (toCompare.filePosition == filePosition &&
toCompare.highCharacter == highCharacter)
return false;
else return true;
}
wchar_t& hexIterator::operator*()
{
updateCache();
if (highCharacter)
return cacheCharacters[1];
return cacheCharacters[0];
}
wchar_t* hexIterator::operator->()
{
updateCache();
if (highCharacter)
return cacheCharacters + 1;
return cacheCharacters;
}
void hexIterator::updateCache()
{
if (filePosition == cacheCurrentFor)
return;
BYTE rawData;
DWORD numberRead;
LONG lowValue = static_cast<LONG>(filePosition);
LONG highValue = static_cast<LONG>(filePosition >> 32);
SetFilePointer(parent->theFile, lowValue, &highValue, FILE_BEGIN);
if (!ReadFile(parent->theFile, &rawData, 1, &numberRead, 0))
throw std::runtime_error(eAsciiMsg("Error reading from file."));
static const wchar_t hexCharacters[] = L"ABCDEF";
cacheCharacters[0] = hexCharacters[rawData & 0x0F];
cacheCharacters[1] = hexCharacters[rawData >> 4];
cacheCurrentFor = filePosition;
}
tête pour conteneur
class hexFile {
public:
HANDLE theFile;
unsigned __int64 fileLength;
hexFile(const std::wstring& fileName)
{
theFile = CreateFile(fileName.c_str(),GENERIC_READ,FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,NULL,NULL);
if (theFile == INVALID_HANDLE_VALUE)
{
throw std::runtime_error(eAsciiMsg("Could not open file!"));
}
BY_HANDLE_FILE_INFORMATION sizeFinder;
GetFileInformationByHandle(theFile, &sizeFinder);
fileLength = sizeFinder.nFileSizeHigh;
fileLength <<= 32;
fileLength += sizeFinder.nFileSizeLow;
};
~hexFile()
{
CloseHandle(theFile);
};
hexIterator begin()
{
hexIterator theIterator(this, true);
return theIterator;
};
hexIterator end()
{
hexIterator theIterator(this, false);
return theIterator;
};
};
Cependant, peu importe quel cas de test J'essaie, l'expression rationnelle ne correspond jamais. Je suppose que c'est un problème conceptuel avec mon itérateur ... il est supposé être un itérateur bidirectionnel constant dans tous les cas.
Tout ce qui me manque, ou existe-t-il un moyen plus facile de le faire?
Billy3
Le problème est que boost :: xpressive ne sait pas comment utiliser un iostream. –
Après le test, l'itérateur produit des résultats corrects. Ce n'est pas un bug avec le code de l'itérateur lui-même, c'est un échec d'assertion dans boost :: xpressive. –
Vous pouvez toujours l'implémenter en tant que filtre iostream (comme celui de base64) et utiliser un istream_iterator sur l'entrée. Juste mes 2 cents :) –