Reputation: 2106
I'm trying to create an iterator on a library that allows reading a specific file format.
From the docs, to read the file content you need do something like this:
CKMCFile database;
if (!database.OpenForListing(path)) {
std::cerr << "ERROR: unable to open " << path << std::endl;
}
CKMCFileInfo info;
database.Info(info);
CKmerAPI kmer(info.kmer_length);
uint32 cnt;
std::vector<uint64_t> data;
std::vector<uint64> ulong_kmer;
data.reserve(info.total_kmers);
while (database.ReadNextKmer(kmer, cnt)) {
kmer.to_long(ulong_kmer);
data.push_back(ulong_kmer[0]);
}
Now, I started with this class wrapper
:
class FileWrapper {
CKMCFile database;
CKMCFileInfo info;
Iterator _end;
public:
explicit FileWrapper(const std::string &path) {
if (!database.OpenForListing(path)) {
std::cout << "ERROR: unable to open " << path << std::endl;
}
database.Info(info);
}
Iterator begin() {
Iterator it;
it.database = &database;
it.total = 0;
uint32_t cnt;
std::vector<uint64_t> ulong_kmer;
CKmerAPI tmp(info.kmer_length);
database.ReadNextKmer(tmp, cnt);
tmp.to_long(ulong_kmer);
return it;
}
Iterator end() const { return _end; }
uint64_t size() { return info.total_kmers; }
};
And then, this is the Iterator
class:
class Iterator {
friend class FileWrapper;
CKMCFileInfo info;
CKMCFile *database;
uint64_t kmer, total;
public:
Iterator &operator++() {
++total;
uint32_t cnt;
std::vector<uint64_t> ulong_kmer;
CKmerAPI tmp(info.kmer_length);
database->ReadNextKmer(tmp, cnt);
tmp.to_long(ulong_kmer);
return *this;
}
bool operator<(const Iterator &rhs) const { return total < rhs.total; }
uint64_t operator*() const { return kmer; }
};
But, during some test I can't use into a for loop
for something like for (auto it = begin(); it != end(); ++i) { ... }
or begin() + size()
. How can I overload correctly this two operatos? opeartor!=
and operato+
Upvotes: 0
Views: 831
Reputation: 556
You'll have to think about 2 major things before:
FileWrapper
survives at least as long as any Iterator
returned from it by calling its begin()
(since your Iterator
s store pointers to data owned by the FileWrapper
object). If you cannot guarantee that, maybe think about using unique_ptr
s or shared_ptr
soperator+(int)
) and dereferenced. Indeed, what would the iterator begin() + 10
look like? If this should advance your file-pointer, then you cannot define the end as begin() + size()
as that would just skip through the file.database == nullptr
. In this case, an operator!=
might look like this:bool is_end() const { return database == nullptr; }
bool operator==(const Iterator& other) const {
if(is_end()) return other.is_end();
if(other.is_end()) return false;
return (database == other.database) && (total == other.total);
}
bool operator!=(const Iterator& other) const { return !operator==(other); }
Now, you'll need code that ensures that all end-iterators have database == nullptr
and, whenever a non-end iterator becomes and end-iterator by application of operator++()
, you'll need to set database = nullptr
and total = 0
(or something).
A note at the end: your Iterator
s may be in an inconsistent state after construction and before assignment of their database
member. It is prudent to declare a proper constructor for Iterator
that initializes its members.
EDIT: here's a suggestion for an integration
Upvotes: 1