Alex Rivera | Logout

How to realize a custom implementation of a std-like iterator?

Asked 2012-03-30T14:57:32.233
9

I have written a very simple file managing database that basicly looks like this:

class FileDB
{
public:
    FileDB(std::string dir) : rootDir(dir) { }

    void loadFile(std::string filename, File &file) const;
    void saveFile(std::string filename, const File &file) const;

private:
    std::string rootDir;
}

Now I would like to iterate through all files contained in the database like using a std::iterator:

void iterateFiles()
{
    FileDB filedb("C:\\MyFiles");

    for (FileDB::iterator file_it = filedb.begin(); file_it != filedb.end(); ++file_it)
    {
        File f = *file_it;
        // do something with file
    }
}

I've read answers to similar questions, some suggesting to derive std::iterator, some to use std::iterator_traits, but I don't really understand how to do that. What can possibly go wrong when trying to implement a custom iterator? And what's a simple yet elegant way to do it?

EDIT: Please don't consider using boost, my question is of more conceptual nature.

EDIT 2:

The FileDB works like this:

  • rootDir

    • foo1
      • bar1
        • foo1bar1_1.txt
        • foo1bar1_2.txt
      • bar2
        • foo1bar2_1.txt
        • foo1bar2_2.txt
    • foo2

    • fooN

      • barM

        • fooNBarM_x.txt

So basicly, I can find a file by its name.

As my container is not in memory, I don't have pointers to its data. So my idea was to store the file's path in the iterator. This way, I can implement operator== with a string comparison, as the paths should be unique. The iterator returned from fileDB.end() would be an empty string and operator* would call fileDB::loadFile() with its filepath.

Edit
Report

1 Answer

3

Here is iterator which calculatetes subnodes during traversal. I wrote it for windows, but I think it is not difficult to castomize it for other platforms.

#include <list>
#include <windows.h>
#include <assert.h>
#include <iostream>
#include <string>

class File{};

class Iterator
{
public:
  virtual bool isDone() = 0;
  virtual void next() = 0;

  virtual std::string getFileName() = 0;

  virtual ~Iterator(){};
};

bool operator== (Iterator& lhs, Iterator& rhs);

class EndIterator : public Iterator
{
public:
  virtual bool isDone() {return true;}
  virtual void next(){};
  virtual std::string getFileName() {return "end";};
};

class DirectoryIterator : public Iterator
{
public:
  DirectoryIterator(const std::string& path);

  virtual bool isDone();
  virtual void next();

  virtual std::string getFileName();

  virtual ~DirectoryIterator();

private:
  std::list<Iterator*> getSubelementsList(const std::string& path) const;
  void init();

private:
  bool m_wasInit;
  std::string m_path;
  std::list<Iterator*> m_leaves;
  std::list<Iterator*>::iterator m_current;
};

class FilesIterator : public Iterator
{
public:
  FilesIterator(const std::string& fileName);

  virtual bool isDone(){return true;};
  virtual void next(){}; 

  virtual std::string getFileName();

  virtual ~FilesIterator(){};

private:
  std::string m_fileName;
};


class DbItertor
{
public:
  DbItertor(Iterator* iterator) : m_ptr(iterator){}
  DbItertor(const DbItertor& rhs) {*m_ptr = *rhs.m_ptr;}

  std::string operator*() 
  {
    if(m_ptr->isDone())
      return "end";
    return m_ptr->getFileName();
  }
  //File operator->(){return FileOpen(m_ptr->getFileName());}

  void operator++() {m_ptr->next();}

  ~DbItertor(){delete m_ptr;}
private:
  Iterator* m_ptr;
};


class FileDB
{
public:
  FileDB(std::string dir) : m_rootDir(dir){}


  DbItertor begin()
  {
    return DbItertor(new Directory
answered 2012-03-30T23:51:30.297

Your Answer