Skip to content
This repository was archived by the owner on Aug 2, 2022. It is now read-only.

Update eos rodeos key_value.hpp and abieos module based on CDT 📦 #10889

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion libraries/abieos
257 changes: 200 additions & 57 deletions libraries/rodeos/include/eosio/key_value.hpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// TODO: this file duplicates a CDT file
// this file is updated based on CDT eosio.cdt/libraries/eosiolib/contracts/eosio/table.hpp

// clang-format off
#pragma once
Expand Down Expand Up @@ -254,31 +254,31 @@ class kv_table {

class kv_index;

class iterator {
class iterator_base {
public:
enum class status {
iterator_ok = 0, // Iterator is positioned at a key-value pair
iterator_erased = -1, // The key-value pair that the iterator used to be positioned at was erased
iterator_end = -2, // Iterator is out-of-bounds
};

iterator() = default;
iterator_base() = default;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer to have itr == 0 && itr_stat == iterator_endas a class invariant; i.e. whenever, you set itr to 0, also set itr_stat to iterator_end. This will simplify a lot of the compare code.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add is_end() method


iterator(uint32_t itr, status itr_stat, const kv_index* index) : itr{itr}, itr_stat{itr_stat}, index{index} {}
iterator_base(uint32_t itr, status itr_stat, const kv_index* index) : itr{itr}, itr_stat{itr_stat}, index{index} {}

iterator(iterator&& other) :
iterator_base(iterator_base&& other) :
itr(std::exchange(other.itr, 0)),
itr_stat(other.itr_stat),
index(other.index)
{}

~iterator() {
~iterator_base() {
if (itr) {
index->tbl->environment.kv_it_destroy(itr);
}
}

iterator& operator=(iterator&& other) {
iterator_base& operator=(iterator_base&& other) {
if (itr) {
index->tbl->environment.kv_it_destroy(itr);
}
Expand Down Expand Up @@ -357,64 +357,26 @@ class kv_table {
return {(char*)buffer, actual_value_size};
}

iterator& operator++() {
eosio::check(itr_stat != status::iterator_end, "cannot increment end iterator");
uint32_t found_key_size, found_value_size;
itr_stat = static_cast<status>(index->tbl->environment.kv_it_next(itr, &found_key_size, &found_value_size));
return *this;
}

iterator& operator--() {
if (!itr) {
itr = index->tbl->environment.kv_it_create(index->contract_name.value, index->prefix.data(), index->prefix.size());
}
uint32_t found_key_size, found_value_size;
itr_stat = static_cast<status>(index->tbl->environment.kv_it_prev(itr, &found_key_size, &found_value_size));
eosio::check(itr_stat != status::iterator_end, "decremented past the beginning");
return *this;
}
bool valid() const { return itr_stat == status::iterator_ok; }
bool is_end() const { return itr == 0 || itr_stat == status::iterator_end; }

int32_t key_compare(key_type kt) const {
if (itr == 0 || itr_stat == status::iterator_end) {
return 1;
} else {
return index->tbl->environment.kv_it_key_compare(itr, kt.data(), kt.size());
}
}

bool operator==(const iterator& b) const {
return compare(b) == 0;
}

bool operator!=(const iterator& b) const {
return compare(b) != 0;
}

bool operator<(const iterator& b) const {
return compare(b) < 0;
if (is_end()) {
return 1;
} else {
return index->tbl->environment.kv_it_key_compare(itr, kt.data(), kt.size());
}
}

bool operator<=(const iterator& b) const {
return compare(b) <= 0;
}

bool operator>(const iterator& b) const {
return compare(b) > 0;
}

bool operator>=(const iterator& b) const {
return compare(b) >= 0;
}

private:

protected:
uint32_t itr;
status itr_stat;

const kv_index* index;

int compare(const iterator& b) const {
bool a_is_end = !itr || itr_stat == status::iterator_end;
bool b_is_end = !b.itr || b.itr_stat == status::iterator_end;
int compare(const iterator_base& b) const {
bool a_is_end = this->is_end();
bool b_is_end = b.is_end();
if (a_is_end && b_is_end) {
return 0;
} else if (a_is_end && b.itr) {
Expand All @@ -427,6 +389,162 @@ class kv_table {
}
};

class iterator : public iterator_base {
using iterator_base::itr;
using iterator_base::itr_stat;
using iterator_base::index;

public:
using status = typename iterator_base::status;

iterator() = default;

iterator(uint32_t itr, status itr_stat, const kv_index* index) : iterator_base{itr, itr_stat, index} {}

iterator(iterator&& other) : iterator_base{std::move(other)} {}

iterator& operator=(iterator&& other) {
if (itr) {
index->tbl->environment.kv_it_destroy(itr);
}
itr = std::exchange(other.itr, 0);
itr_stat = other.itr_stat;
index = other.index;
return *this;
}

iterator& operator++() {
eosio::check(itr_stat != status::iterator_end, "cannot increment end iterator");
uint32_t found_key_size, found_value_size;
itr_stat = static_cast<status>(index->tbl->environment.kv_it_next(itr, &found_key_size, &found_value_size));
return *this;
}

iterator& operator--() {
if (!itr) {
itr = index->tbl->environment.kv_it_create(index->contract_name.value, index->prefix.data(), index->prefix.size());
}
uint32_t found_key_size, found_value_size;
itr_stat = static_cast<status>(index->tbl->environment.kv_it_prev(itr, &found_key_size, &found_value_size));
eosio::check(itr_stat != status::iterator_end, "decremented past the beginning");
return *this;
}

bool operator==(const iterator& b) const {
return iterator_base::compare(b) == 0;
}

bool operator!=(const iterator& b) const {
return iterator_base::compare(b) != 0;
}

bool operator<(const iterator& b) const {
return iterator_base::compare(b) < 0;
}

bool operator<=(const iterator& b) const {
return iterator_base::compare(b) <= 0;
}

bool operator>(const iterator& b) const {
return iterator_base::compare(b) > 0;
}

bool operator>=(const iterator& b) const {
return iterator_base::compare(b) >= 0;
}

explicit operator bool() const {
return this->valid();
}
};

class reverse_iterator : public iterator_base {
using iterator_base::itr;
using iterator_base::itr_stat;
using iterator_base::index;

public:
using status = typename iterator_base::status;

reverse_iterator() = default;

reverse_iterator(uint32_t itr, status itr_stat, const kv_index* index) : iterator_base{itr, itr_stat, index} {}

reverse_iterator(reverse_iterator&& other) : iterator_base{std::move(other)} {}

reverse_iterator& operator=(reverse_iterator&& other) {
if (itr) {
index->tbl->environment.kv_it_destroy(itr);
}
itr = std::exchange(other.itr, 0);
itr_stat = other.itr_stat;
index = other.index;
return *this;
}

reverse_iterator& operator++() {
if (!itr) {
itr = index->tbl->environment.kv_it_create(index->contract_name.value, index->prefix.data(), index->prefix.size());
}
uint32_t found_key_size, found_value_size;
itr_stat = static_cast<status>(index->tbl->environment.kv_it_prev(itr, &found_key_size, &found_value_size));
eosio::check(itr_stat != status::iterator_end, "reverse_iterator incremented past the beginning");
return *this;
}

reverse_iterator& operator--() {
eosio::check(itr_stat != status::iterator_end, "reverse_iterator cannot decrement end iterator");
uint32_t found_key_size, found_value_size;
itr_stat = static_cast<status>(index->tbl->environment.kv_it_next(itr, &found_key_size, &found_value_size));
return *this;

}

int compare(const reverse_iterator& b) const {
bool a_is_end = this->is_end();
bool b_is_end = b.is_end();
if (a_is_end && b_is_end) {
return 0;
} else if (a_is_end && b.itr) {
return 1;
} else if (itr && b_is_end) {
return -1;
} else {
//need return negative compare value here for reverse_iterator
return -(index->tbl->environment.kv_it_compare(itr, b.itr));
}
}

bool operator==(const reverse_iterator& b) const {
return compare(b) == 0;
}

bool operator!=(const reverse_iterator& b) const {
return compare(b) != 0;
}

bool operator<(const reverse_iterator& b) const {
return compare(b) < 0;
}

bool operator<=(const reverse_iterator& b) const {
return compare(b) <= 0;
}

bool operator>(const reverse_iterator& b) const {
return compare(b) > 0;
}

bool operator>=(const reverse_iterator& b) const {
return compare(b) >= 0;
}

explicit operator bool() const {
return this->valid();
}
};

class kv_index {

public:
Expand Down Expand Up @@ -627,6 +745,31 @@ class kv_table {
return {0, iterator::status::iterator_end, this};
}

/**
* Returns a reverse iterator to the object with the highest key (by this index) in the table.
* @ingroup keyvaluetable
*
* @return A reverse iterator to the object with the highest key (by this index) in the table.
*/
reverse_iterator rbegin() const {
uint32_t itr = tbl->environment.kv_it_create(contract_name.value, prefix.data(), prefix.size());
uint32_t found_key_size, found_value_size;

//typename is needed before iterator::status, because iterator::status is a dependent name
int32_t itr_stat = static_cast<typename iterator::status>(tbl->environment.kv_it_prev(itr, &found_key_size, &found_value_size));
return {itr, itr_stat, this};
}

/**
* Returns a reverse iterator pointing past the beginning. It does not point to any element, therefore `value` should not be called on it.
* @ingroup keyvaluetable
*
* @return A reverse iterator pointing past the beginning.
*/
reverse_iterator rend() const {
return {0, iterator::status::iterator_end, this};
}

/**
* Returns an iterator pointing to the element with the lowest key greater than or equal to the given key.
* @ingroup keyvalue
Expand Down