2009-06-23 7 views
0

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

Répondre

1

Il s'agit d'un peu de code à lire; à première vue, je ne vois rien. Pour les notes d'implémentation, cela ressemble plus à un iostream qu'à un itérateur, ce qui avec la mise en mémoire tampon peut être considérablement plus rapide. Boost a une bibliothèque pour aider à mettre en œuvre those.

Si vous voulez utiliser un itérateur, ils ont aussi un library pour vous aider, il s'assure que vous avez toutes les méthodes dont vous avez besoin tout en simplifiant beaucoup l'implémentation.

Pour le débogage, j'essaierais pour les tests unitaires; cela devrait indiquer le problème; Commencez par quelque chose de petit, comme un fichier avec deux caractères, parcourez un débogueur pour voir ce qui se passe et répétez jusqu'à ce que vous ayez tout passé.

+0

Le problème est que boost :: xpressive ne sait pas comment utiliser un iostream. –

+0

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. –

+0

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 :) –

1

operator++(int) doit être défini en termes de operator++(), et non l'inverse. Essayez de les changer. Idem pour operator--.

+0

Pas de joie :(Désolé. –

+0

Modifié ce qui précède pour refléter les différences. –

0

Essayez d'utiliser un Boost::transform_iterator.

+0

Le problème est que, lors de la conversion en hexadécimal, deux caractères sont retournés pour chaque caractère d'entrée. Par conséquent, le passage des opérateurs ++ et - à l'itérateur en dessous ne fonctionne pas comme prévu ... ceci doit être géré explicitement. –

1

Eh bien ... s'avère que je suis un idiot complet.

boost :: xpressive :: regex_match (fileInstance.begin(), fileInstance.end(), résultats, internalRegex);

Eh bien ... ce que je voulais faire était

boost :: Xpressive :: regex _search (fileInstance.begin(), fileInstance.end(), les résultats, internalRegex);

L'itérateur n'a jamais eu de problème avec ça.

Désolé pour perdre le temps des autres, Billy3