IDBBackingStoreCursorLevelDB.cpp [plain text]
#include "config.h"
#include "IDBBackingStoreCursorLevelDB.h"
#if ENABLE(INDEXED_DATABASE) && USE(LEVELDB)
#include "IDBBackingStoreLevelDB.h"
#include "LevelDBTransaction.h"
namespace WebCore {
IDBBackingStoreCursorLevelDB::IDBBackingStoreCursorLevelDB(const IDBBackingStoreCursorLevelDB* other)
: m_transaction(other->m_transaction)
, m_cursorOptions(other->m_cursorOptions)
, m_currentKey(other->m_currentKey)
, m_recordIdentifier(IDBRecordIdentifier::create())
{
if (other->m_iterator) {
m_iterator = m_transaction->createIterator();
if (other->m_iterator->isValid()) {
m_iterator->seek(other->m_iterator->key());
ASSERT(m_iterator->isValid());
}
}
m_recordIdentifier->reset(other->m_recordIdentifier->encodedPrimaryKey(), other->m_recordIdentifier->version());
}
bool IDBBackingStoreCursorLevelDB::firstSeek()
{
m_iterator = m_transaction->createIterator();
if (m_cursorOptions.forward)
m_iterator->seek(m_cursorOptions.lowKey);
else
m_iterator->seek(m_cursorOptions.highKey);
return continueFunction(0, Ready);
}
bool IDBBackingStoreCursorLevelDB::advance(unsigned long count)
{
while (count--) {
if (!continueFunction())
return false;
}
return true;
}
bool IDBBackingStoreCursorLevelDB::continueFunction(const IDBKey* key, IteratorState nextState)
{
RefPtr<IDBKey> previousKey = m_currentKey;
bool firstIteration = true;
RefPtr<IDBKey> lastDuplicateKey;
bool forward = m_cursorOptions.forward;
for (;;) {
if (nextState == Seek) {
if (firstIteration && key && forward) {
m_iterator->seek(encodeKey(*key));
firstIteration = false;
} else if (forward)
m_iterator->next();
else
m_iterator->prev();
} else
nextState = Seek;
if (!m_iterator->isValid()) {
if (!forward && lastDuplicateKey.get()) {
forward = true;
continue;
}
return false;
}
if (isPastBounds()) {
if (!forward && lastDuplicateKey.get()) {
forward = true;
continue;
}
return false;
}
if (!haveEnteredRange())
continue;
if (!loadCurrentRow())
continue;
if (key) {
if (forward) {
if (m_currentKey->isLessThan(key))
continue;
} else {
if (key->isLessThan(m_currentKey.get()))
continue;
}
}
if (m_cursorOptions.unique) {
if (m_currentKey->isEqual(previousKey.get())) {
ASSERT(!lastDuplicateKey.get());
continue;
}
if (!forward) {
if (!lastDuplicateKey.get()) {
lastDuplicateKey = m_currentKey;
continue;
}
if (!lastDuplicateKey->isEqual(m_currentKey.get())) {
forward = true;
continue;
}
continue;
}
}
break;
}
ASSERT(!lastDuplicateKey.get() || (forward && lastDuplicateKey->isEqual(m_currentKey.get())));
return true;
}
bool IDBBackingStoreCursorLevelDB::haveEnteredRange() const
{
if (m_cursorOptions.forward) {
if (m_cursorOptions.lowOpen)
return IDBBackingStoreLevelDB::compareIndexKeys(m_iterator->key(), m_cursorOptions.lowKey) > 0;
return IDBBackingStoreLevelDB::compareIndexKeys(m_iterator->key(), m_cursorOptions.lowKey) >= 0;
}
if (m_cursorOptions.highOpen)
return IDBBackingStoreLevelDB::compareIndexKeys(m_iterator->key(), m_cursorOptions.highKey) < 0;
return IDBBackingStoreLevelDB::compareIndexKeys(m_iterator->key(), m_cursorOptions.highKey) <= 0;
}
bool IDBBackingStoreCursorLevelDB::isPastBounds() const
{
if (m_cursorOptions.forward) {
if (m_cursorOptions.highOpen)
return IDBBackingStoreLevelDB::compareIndexKeys(m_iterator->key(), m_cursorOptions.highKey) >= 0;
return IDBBackingStoreLevelDB::compareIndexKeys(m_iterator->key(), m_cursorOptions.highKey) > 0;
}
if (m_cursorOptions.lowOpen)
return IDBBackingStoreLevelDB::compareIndexKeys(m_iterator->key(), m_cursorOptions.lowKey) <= 0;
return IDBBackingStoreLevelDB::compareIndexKeys(m_iterator->key(), m_cursorOptions.lowKey) < 0;
}
}
#endif // ENABLE(INDEXED_DATABASE) && USE(LEVELDB)