#ifndef EXAMPLES_CTREE_MAP_PERSISTENT_HPP
#define EXAMPLES_CTREE_MAP_PERSISTENT_HPP
#include <cstdint>
#include <ex_common.h>
#include <functional>
#include <stdlib.h>
#include <libpmemobj++/make_persistent.hpp>
#include <libpmemobj++/make_persistent_atomic.hpp>
#include <libpmemobj++/p.hpp>
#include <libpmemobj++/persistent_ptr.hpp>
#include <libpmemobj++/pool.hpp>
#include <libpmemobj++/transaction.hpp>
#include <libpmemobj++/utils.hpp>
#define BIT_IS_SET(n, i) (!!((n) & (1ULL << (i))))
namespace nvobj = pmem::obj;
namespace examples
{
template <typename K, typename T>
class ctree_map_p {
public:
typedef K key_type;
typedef nvobj::persistent_ptr<T> value_type;
typedef std::function<int(key_type, value_type, void *)> callback;
ctree_map_p()
{
auto pop = nvobj::pool_by_vptr(this);
nvobj::transaction::exec_tx(pop, [&] {
this->root = nvobj::make_persistent<entry>();
});
}
int
insert(key_type key, value_type value)
{
auto dest_entry = root;
while (dest_entry->inode != nullptr) {
auto n = dest_entry->inode;
dest_entry = n->entries[BIT_IS_SET(key, n->diff)];
}
entry e(key, value);
auto pop = nvobj::pool_by_vptr(this);
nvobj::transaction::exec_tx(pop, [&] {
if (dest_entry->key == 0 || dest_entry->key == key) {
nvobj::delete_persistent<T>(dest_entry->value);
*dest_entry = e;
} else {
insert_leaf(&e, find_crit_bit(dest_entry->key,
key));
}
});
return 0;
}
template <typename... Args>
int
insert_new(key_type key, const Args &... args)
{
auto pop = nvobj::pool_by_vptr(this);
nvobj::transaction::exec_tx(pop, [&] {
return insert(key, nvobj::make_persistent<T>(args...));
});
return -1;
}
value_type
remove(key_type key)
{
nvobj::persistent_ptr<entry> parent = nullptr;
auto leaf = get_leaf(key, &parent);
if (leaf == nullptr)
return nullptr;
auto ret = leaf->value;
auto pop = nvobj::pool_by_vptr(this);
nvobj::transaction::exec_tx(pop, [&] {
if (parent == nullptr) {
leaf->key = 0;
leaf->value = nullptr;
} else {
auto n = parent->inode;
*parent = *(
n->entries[parent->inode->entries[0]
->key == leaf->key]);
nvobj::delete_persistent<entry>(n->entries[0]);
nvobj::delete_persistent<entry>(n->entries[1]);
nvobj::delete_persistent<node>(n);
}
});
return ret;
}
int
remove_free(key_type key)
{
auto pop = nvobj::pool_by_vptr(this);
nvobj::transaction::exec_tx(
pop, [&] { nvobj::delete_persistent<T>(remove(key)); });
return 0;
}
int
clear()
{
auto pop = nvobj::pool_by_vptr(this);
nvobj::transaction::exec_tx(pop, [&] {
if (this->root->inode) {
this->root->inode->clear();
nvobj::delete_persistent<node>(
this->root->inode);
this->root->inode = nullptr;
}
nvobj::delete_persistent<T>(this->root->value);
this->root->value = nullptr;
this->root->key = 0;
});
return 0;
}
value_type
get(key_type key)
{
auto ret = get_leaf(key, nullptr);
return ret ? ret->value : nullptr;
}
int
lookup(key_type key) const
{
return get(key) != nullptr;
}
int foreach (callback clb, void *args)
{
if (is_empty())
return 0;
return foreach_node(root, clb, args);
}
int
is_empty() const
{
return root->value == nullptr && root->inode == nullptr;
}
int
check() const
{
return 0;
}
~ctree_map_p()
{
clear();
}
private:
struct node;
struct entry {
entry() : key(0), inode(nullptr), value(nullptr)
{
}
entry(key_type _key, value_type _value)
: key(_key), inode(nullptr), value(_value)
{
}
nvobj::p<key_type> key;
nvobj::persistent_ptr<node> inode;
value_type value;
void
clear()
{
if (inode) {
inode->clear();
nvobj::delete_persistent<node>(inode);
inode = nullptr;
}
nvobj::delete_persistent<T>(value);
value = nullptr;
}
};
struct node {
node() : diff(0)
{
entries[0] = nullptr;
entries[1] = nullptr;
}
nvobj::p<int> diff;
nvobj::persistent_ptr<entry> entries[2];
void
clear()
{
if (entries[0]) {
entries[0]->clear();
nvobj::delete_persistent<entry>(entries[0]);
entries[0] = nullptr;
}
if (entries[1]) {
entries[1]->clear();
nvobj::delete_persistent<entry>(entries[1]);
entries[1] = nullptr;
}
}
};
static int
find_crit_bit(key_type lhs, key_type rhs)
{
return find_last_set_64(lhs ^ rhs);
}
void
insert_leaf(const entry *e, int diff)
{
auto new_node = nvobj::make_persistent<node>();
new_node->diff = diff;
int d = BIT_IS_SET(e->key, new_node->diff);
new_node->entries[d] = nvobj::make_persistent<entry>(*e);
auto dest_entry = root;
while (dest_entry->inode != nullptr) {
auto n = dest_entry->inode;
if (n->diff < new_node->diff)
break;
dest_entry = n->entries[BIT_IS_SET(e->key, n->diff)];
}
new_node->entries[!d] =
nvobj::make_persistent<entry>(*dest_entry);
dest_entry->key = 0;
dest_entry->inode = new_node;
dest_entry->value = nullptr;
}
nvobj::persistent_ptr<entry>
get_leaf(key_type key, nvobj::persistent_ptr<entry> *parent)
{
auto n = root;
nvobj::persistent_ptr<entry> p = nullptr;
while (n->inode != nullptr) {
p = n;
n = n->inode->entries[BIT_IS_SET(key, n->inode->diff)];
}
if (n->key == key) {
if (parent)
*parent = p;
return n;
}
return nullptr;
}
int
foreach_node(const nvobj::persistent_ptr<entry> e, callback clb,
void *arg)
{
int ret = 0;
if (e->inode != nullptr) {
auto n = e->inode;
if (foreach_node(n->entries[0], clb, arg) == 0)
foreach_node(n->entries[1], clb, arg);
} else {
ret = clb(e->key, e->value, arg);
}
return ret;
}
nvobj::persistent_ptr<entry> root;
};
}
#endif