mirror of
https://github.com/GothenburgBitFactory/timewarrior.git
synced 2025-07-07 20:06:39 +02:00
Database: Add forward/reverse iterator
This allows the database to be treated as a single collection of strings, but can be used to avoid loading the entire database when only interested in recent entries. Related to issue #245.
This commit is contained in:
parent
ea3bbd0e85
commit
557fd4cb34
2 changed files with 245 additions and 0 deletions
186
src/Database.cpp
186
src/Database.cpp
|
@ -24,6 +24,7 @@
|
||||||
//
|
//
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
#include <Database.h>
|
#include <Database.h>
|
||||||
#include <format.h>
|
#include <format.h>
|
||||||
#include <JSON.h>
|
#include <JSON.h>
|
||||||
|
@ -32,6 +33,191 @@
|
||||||
#include <shared.h>
|
#include <shared.h>
|
||||||
#include <timew.h>
|
#include <timew.h>
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
Database::iterator::iterator (files_iterator fbegin, files_iterator fend) :
|
||||||
|
files_it(fbegin),
|
||||||
|
files_end(fend)
|
||||||
|
{
|
||||||
|
if (files_end != files_it) {
|
||||||
|
auto &lines = files_it->allLines ();
|
||||||
|
lines_it = lines.begin ();
|
||||||
|
lines_end = lines.end ();
|
||||||
|
while ((lines_it == lines_end) && (files_it != files_end))
|
||||||
|
++files_it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
Database::iterator& Database::iterator::operator++()
|
||||||
|
{
|
||||||
|
if (files_it != files_end)
|
||||||
|
{
|
||||||
|
if (lines_it != lines_end)
|
||||||
|
{
|
||||||
|
++lines_it;
|
||||||
|
|
||||||
|
// If we are at the end of the current file, we will need to advance to
|
||||||
|
// the next file here. A file may be empty, which is why we need to wait
|
||||||
|
// until we are pointing at a valid line.
|
||||||
|
while ((lines_it == lines_end) && (files_it != files_end))
|
||||||
|
{
|
||||||
|
++files_it;
|
||||||
|
if (files_it != files_end)
|
||||||
|
{
|
||||||
|
auto& lines = files_it->allLines ();
|
||||||
|
lines_it = lines.begin ();
|
||||||
|
lines_end = lines.end ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool Database::iterator::operator==(const iterator & other) const
|
||||||
|
{
|
||||||
|
return (other.files_it == other.files_end) ?
|
||||||
|
files_it == files_end :
|
||||||
|
((files_it == other.files_it) &&
|
||||||
|
(files_end == other.files_end) &&
|
||||||
|
(lines_it == other.lines_it) &&
|
||||||
|
(lines_end == other.lines_end));
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool Database::iterator::operator!=(const iterator & other) const
|
||||||
|
{
|
||||||
|
return ! (*this == other);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
const std::string& Database::iterator::operator*() const
|
||||||
|
{
|
||||||
|
assert(lines_it != lines_end);
|
||||||
|
return *lines_it;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
const std::string* Database::iterator::operator->() const
|
||||||
|
{
|
||||||
|
assert(lines_it != lines_end);
|
||||||
|
return &(*lines_it);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
Database::reverse_iterator::reverse_iterator (files_iterator fbegin,
|
||||||
|
files_iterator fend) :
|
||||||
|
files_it(fbegin),
|
||||||
|
files_end(fend)
|
||||||
|
{
|
||||||
|
if (files_end != files_it)
|
||||||
|
{
|
||||||
|
lines_it = files_it->allLines ().rbegin ();
|
||||||
|
lines_end = files_it->allLines ().rend ();
|
||||||
|
while ((lines_it == lines_end) && (files_it != files_end))
|
||||||
|
++files_it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
Database::reverse_iterator& Database::reverse_iterator::operator++()
|
||||||
|
{
|
||||||
|
if (files_it != files_end)
|
||||||
|
{
|
||||||
|
if (lines_it != lines_end)
|
||||||
|
{
|
||||||
|
++lines_it;
|
||||||
|
|
||||||
|
// If we are at the end of the current file, we will need to advance to
|
||||||
|
// the next file here. A file may be empty, which is why we need to wait
|
||||||
|
// until we are pointing at a valid line.
|
||||||
|
while ((lines_it == lines_end) && (files_it != files_end))
|
||||||
|
{
|
||||||
|
++files_it;
|
||||||
|
if (files_it != files_end)
|
||||||
|
{
|
||||||
|
lines_it = files_it->allLines ().rbegin ();
|
||||||
|
lines_end = files_it->allLines ().rend ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool
|
||||||
|
Database::reverse_iterator::operator==(const reverse_iterator & other) const
|
||||||
|
{
|
||||||
|
return (other.files_it == other.files_end) ?
|
||||||
|
files_it == files_end :
|
||||||
|
((files_it == other.files_it) &&
|
||||||
|
(files_end == other.files_end) &&
|
||||||
|
(lines_it == other.lines_it) &&
|
||||||
|
(lines_end == other.lines_end));
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool
|
||||||
|
Database::reverse_iterator::operator!=(const reverse_iterator & other) const
|
||||||
|
{
|
||||||
|
return ! (*this == other);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
const std::string& Database::reverse_iterator::operator*() const
|
||||||
|
{
|
||||||
|
assert (lines_it != lines_end);
|
||||||
|
return *lines_it;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
const std::string* Database::reverse_iterator::operator->() const
|
||||||
|
{
|
||||||
|
return &operator*();
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
Database::iterator Database::begin ()
|
||||||
|
{
|
||||||
|
if (_files.empty ())
|
||||||
|
{
|
||||||
|
initializeDatafiles ();
|
||||||
|
}
|
||||||
|
|
||||||
|
return iterator(_files.begin (), _files.end ());
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
Database::iterator Database::end ()
|
||||||
|
{
|
||||||
|
return iterator (_files.end (), _files.end ());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
Database::reverse_iterator Database::rbegin ()
|
||||||
|
{
|
||||||
|
if (_files.empty ())
|
||||||
|
{
|
||||||
|
initializeDatafiles ();
|
||||||
|
}
|
||||||
|
|
||||||
|
return reverse_iterator (_files.rbegin (), _files.rend ());
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
Database::reverse_iterator Database::rend ()
|
||||||
|
{
|
||||||
|
if (_files.empty ())
|
||||||
|
{
|
||||||
|
initializeDatafiles ();
|
||||||
|
}
|
||||||
|
|
||||||
|
return reverse_iterator (_files.rend (), _files.rend ());
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
void Database::initialize (const std::string& location, Journal& journal)
|
void Database::initialize (const std::string& location, Journal& journal)
|
||||||
{
|
{
|
||||||
|
|
|
@ -38,6 +38,60 @@
|
||||||
|
|
||||||
class Database
|
class Database
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
class iterator
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
friend class Database;
|
||||||
|
typedef std::vector <Datafile>::iterator files_iterator;
|
||||||
|
typedef std::vector <std::string>::const_iterator lines_iterator;
|
||||||
|
typedef std::string value_type;
|
||||||
|
|
||||||
|
files_iterator files_it;
|
||||||
|
files_iterator files_end;
|
||||||
|
|
||||||
|
lines_iterator lines_it;
|
||||||
|
lines_iterator lines_end;
|
||||||
|
|
||||||
|
iterator (files_iterator fbegin, files_iterator fend);
|
||||||
|
|
||||||
|
public:
|
||||||
|
iterator& operator++ ();
|
||||||
|
iterator& operator++ (int);
|
||||||
|
iterator& operator-- ();
|
||||||
|
bool operator== (const iterator & other) const;
|
||||||
|
bool operator!= (const iterator & other) const;
|
||||||
|
const value_type& operator* () const;
|
||||||
|
const value_type* operator-> () const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class reverse_iterator
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
friend class Database;
|
||||||
|
typedef std::vector <Datafile>::reverse_iterator files_iterator;
|
||||||
|
typedef std::vector <std::string>::const_reverse_iterator lines_iterator;
|
||||||
|
typedef std::string value_type;
|
||||||
|
|
||||||
|
files_iterator files_it;
|
||||||
|
files_iterator files_end;
|
||||||
|
|
||||||
|
lines_iterator lines_it;
|
||||||
|
lines_iterator lines_end;
|
||||||
|
|
||||||
|
reverse_iterator(files_iterator fbegin, files_iterator fend);
|
||||||
|
|
||||||
|
public:
|
||||||
|
reverse_iterator& operator++ ();
|
||||||
|
reverse_iterator& operator++ (int);
|
||||||
|
reverse_iterator& operator-- ();
|
||||||
|
bool operator== (const reverse_iterator & other) const;
|
||||||
|
bool operator!= (const reverse_iterator & other) const;
|
||||||
|
const value_type& operator* () const;
|
||||||
|
const value_type* operator-> () const;
|
||||||
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Database () = default;
|
Database () = default;
|
||||||
void initialize (const std::string&, Journal& journal);
|
void initialize (const std::string&, Journal& journal);
|
||||||
|
@ -53,6 +107,11 @@ public:
|
||||||
|
|
||||||
std::string dump () const;
|
std::string dump () const;
|
||||||
|
|
||||||
|
iterator begin ();
|
||||||
|
iterator end ();
|
||||||
|
reverse_iterator rbegin ();
|
||||||
|
reverse_iterator rend ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
unsigned int getDatafile (int, int);
|
unsigned int getDatafile (int, int);
|
||||||
std::vector <Range> segmentRange (const Range&);
|
std::vector <Range> segmentRange (const Range&);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue