Commit 4dd4f663 by Maarten L. Hekkelman

backup

parent 04b7828a
......@@ -54,88 +54,25 @@ class category
category() = default;
category(std::string_view name)
: m_name(name)
{
}
category(std::string_view name);
category(const category &rhs)
: m_name(rhs.m_name)
, m_columns(rhs.m_columns)
{
for (auto r = rhs.m_head; r != nullptr; r = r->m_next)
insert_impl(end(), clone_row(*r));
}
category(const category &rhs);
category(category &&rhs)
: m_name(std::move(rhs.m_name))
, m_columns(std::move(rhs.m_columns))
, m_head(rhs.m_head)
, m_tail(rhs.m_tail)
{
rhs.m_head = nullptr;
rhs.m_tail = nullptr;
}
category(category &&rhs);
category &operator=(const category &rhs)
{
if (this != &rhs)
{
if (not empty())
clear();
category &operator=(const category &rhs);
m_name = rhs.m_name;
m_columns = rhs.m_columns;
category &operator=(category &&rhs);
for (auto r = rhs.m_head; r != nullptr; r = r->m_next)
insert_impl(cend(), clone_row(*r));
}
return *this;
}
category &operator=(category &&rhs)
{
if (this != &rhs)
{
if (not empty())
clear();
m_name = std::move(rhs.m_name);
m_columns = std::move(rhs.m_columns);
m_head = rhs.m_head;
m_tail = rhs.m_tail;
rhs.m_head = rhs.m_tail = nullptr;
}
return *this;
}
~category()
{
clear();
}
~category();
// --------------------------------------------------------------------
const std::string &name() const { return m_name; }
iset fields() const
{
if (m_validator == nullptr)
throw std::runtime_error("No Validator specified");
if (m_cat_validator == nullptr)
m_validator->report_error("undefined Category", true);
iset fields() const;
iset result;
for (auto &iv : m_cat_validator->m_item_validators)
result.insert(iv.m_tag);
return result;
}
std::set<uint16_t> key_field_indices() const;
void set_validator(const validator *v, datablock &db);
void update_links(datablock &db);
......@@ -374,6 +311,20 @@ class category
}
// --------------------------------------------------------------------
bool has_children(row_handle r) const;
bool has_parents(row_handle r) const;
std::vector<row_handle> get_children(row_handle r, category &childCat);
// std::vector<row_handle> getChildren(row_handle r, const char *childCat);
std::vector<row_handle> get_parents(row_handle r, category &parentCat);
// std::vector<row_handle> getParents(row_handle r, const char *parentCat);
std::vector<row_handle> get_linked(row_handle r, category &cat);
// std::vector<row_handle> getLinked(row_handle r, const char *cat);
// --------------------------------------------------------------------
// void insert(const_iterator pos, const row &row)
// {
......@@ -500,7 +451,7 @@ class category
{
auto iv = m_cat_validator->get_validator_for_item(column_name);
if (iv == nullptr)
std::cerr << "Invalid name used '" << name << "' is not a known column in " + m_name << std::endl;
std::cerr << "Invalid name used '" << column_name << "' is not a known column in " + m_name << std::endl;
}
return result;
......@@ -690,6 +641,7 @@ class category
const category_validator *m_cat_validator = nullptr;
std::vector<link> m_parent_links, m_child_links;
bool m_cascade = true;
class category_index* m_index = nullptr;
row *m_head = nullptr, *m_tail = nullptr;
};
......
......@@ -604,11 +604,6 @@ inline condition all()
return condition(new detail::all_condition_impl());
}
// inline condition_t<category> Not(condition_t<category> &&cond)
// {
// return condition_t<category>(new detail::not_condition_impl(std::move(cond)));
// }
namespace literals
{
inline key operator""_key(const char *text, size_t length)
......
......@@ -35,16 +35,9 @@ namespace cif::v2
// --------------------------------------------------------------------
class datablock
class datablock : public std::list<category>
{
public:
using category_list = std::list<category>;
using iterator = category_list::iterator;
using const_iterator = category_list::const_iterator;
using reference = typename category_list::reference;
datablock() = default;
datablock(std::string_view name)
......@@ -90,48 +83,31 @@ class datablock
// --------------------------------------------------------------------
bool empty() const { return m_categories.empty(); }
size_t size() const { return m_categories.size(); }
reference front() { return m_categories.front(); }
reference back() { return m_categories.back(); }
iterator begin() { return m_categories.begin(); }
iterator end() { return m_categories.end(); }
const_iterator cbegin() { return m_categories.cbegin(); }
const_iterator cend() { return m_categories.cend(); }
const_iterator begin() const { return m_categories.begin(); }
const_iterator end() const { return m_categories.end(); }
// --------------------------------------------------------------------
category &operator[](std::string_view name)
{
auto i = std::find_if(m_categories.begin(), m_categories.end(), [name](const category &c)
auto i = std::find_if(begin(), end(), [name](const category &c)
{ return iequals(c.name(), name); });
if (i != m_categories.end())
if (i != end())
return *i;
m_categories.emplace_back(name);
return m_categories.back();
emplace_back(name);
return back();
}
const category &operator[](std::string_view name) const
{
static const category s_empty;
auto i = std::find_if(m_categories.begin(), m_categories.end(), [name](const category &c)
auto i = std::find_if(begin(), end(), [name](const category &c)
{ return iequals(c.name(), name); });
return i == m_categories.end() ? s_empty : *i;
return i == end() ? s_empty : *i;
}
category *get(std::string_view name)
{
auto i = std::find_if(m_categories.begin(), m_categories.end(), [name](const category &c)
auto i = std::find_if(begin(), end(), [name](const category &c)
{ return iequals(c.name(), name); });
return i == m_categories.end() ? nullptr : &*i;
return i == end() ? nullptr : &*i;
}
const category *get(std::string_view name) const
......@@ -143,17 +119,17 @@ class datablock
{
bool is_new = true;
auto i = m_categories.begin();
while (i != m_categories.end())
auto i = begin();
while (i != end())
{
if (iequals(name, i->name()))
{
is_new = false;
if (i != m_categories.begin())
if (i != begin())
{
auto n = std::next(i);
m_categories.splice(m_categories.begin(), m_categories, i, n);
splice(begin(), *this, i, n);
}
break;
......@@ -164,14 +140,11 @@ class datablock
if (is_new)
{
m_categories.emplace(m_categories.begin(), name);
// m_categories.emplace(begin(), *this, std::string(name), mValidator);
// for (auto &cat : mCategories)
// cat.updateLinks();
auto &c = emplace_front(name);
c.set_validator(m_validator, *this);
}
return std::make_tuple(m_categories.begin(), is_new);
return std::make_tuple(begin(), is_new);
}
// void write(std::ostream &os) const
......@@ -217,7 +190,6 @@ class datablock
// }
private:
category_list m_categories;
std::string m_name;
const validator *m_validator = nullptr;
};
......
......@@ -36,17 +36,9 @@ namespace cif::v2
// --------------------------------------------------------------------
class file
class file : public std::list<datablock>
{
public:
using datablock_list = std::list<datablock>;
using value_type = datablock_list::value_type;
using reference = datablock_list::reference;
using pointer = datablock_list::pointer;
using iterator = datablock_list::iterator;
using const_iterator = datablock_list::const_iterator;
file() = default;
......@@ -113,39 +105,39 @@ class file
datablock &operator[](std::string_view name)
{
auto i = std::find_if(m_datablocks.begin(), m_datablocks.end(), [name](const datablock &c)
auto i = std::find_if(begin(), end(), [name](const datablock &c)
{ return iequals(c.name(), name); });
if (i != m_datablocks.end())
if (i != end())
return *i;
m_datablocks.emplace_back(name);
return m_datablocks.back();
emplace_back(name);
return back();
}
const datablock &operator[](std::string_view name) const
{
static const datablock s_empty;
auto i = std::find_if(m_datablocks.begin(), m_datablocks.end(), [name](const datablock &c)
auto i = std::find_if(begin(), end(), [name](const datablock &c)
{ return iequals(c.name(), name); });
return i == m_datablocks.end() ? s_empty : *i;
return i == end() ? s_empty : *i;
}
std::tuple<iterator, bool> emplace(std::string_view name)
{
bool is_new = true;
auto i = m_datablocks.begin();
while (i != m_datablocks.end())
auto i = begin();
while (i != end())
{
if (iequals(name, i->name()))
{
is_new = false;
if (i != m_datablocks.begin())
if (i != begin())
{
auto n = std::next(i);
m_datablocks.splice(m_datablocks.begin(), m_datablocks, i, n);
splice(begin(), *this, i, n);
}
break;
......@@ -155,26 +147,14 @@ class file
}
if (is_new)
m_datablocks.emplace(m_datablocks.begin(), name);
{
auto &db = emplace_front(name);
db.set_validator(m_validator);
}
return std::make_tuple(m_datablocks.begin(), is_new);
return std::make_tuple(begin(), is_new);
}
bool empty() const { return m_datablocks.empty(); }
size_t size() const { return m_datablocks.size(); }
iterator begin() { return m_datablocks.begin(); }
iterator end() { return m_datablocks.end(); }
const_iterator cbegin() { return m_datablocks.begin(); }
const_iterator cend() { return m_datablocks.end(); }
const_iterator begin() const { return m_datablocks.begin(); }
const_iterator end() const { return m_datablocks.end(); }
reference front() { return m_datablocks.front(); }
reference back() { return m_datablocks.back(); }
void load(std::istream &is)
{
auto saved = m_validator;
......@@ -191,7 +171,6 @@ class file
}
private:
datablock_list m_datablocks;
const validator* m_validator = nullptr;
};
......
......@@ -89,7 +89,7 @@ class iterator_impl
template <typename IRowType>
iterator_impl(iterator_impl<IRowType, Ts...> &rhs)
: m_category(rhs.m_category)
, m_current(rhs.m_current)
, m_current(const_cast<row_type *>(rhs.m_current))
, m_value(rhs.m_value)
, m_column_ix(rhs.m_column_ix)
{
......@@ -274,7 +274,7 @@ class conditional_iterator_proxy
using value_type = conditional_iterator_proxy::value_type;
using difference_type = std::ptrdiff_t;
using pointer = value_type *;
using reference = row_handle;
using reference = value_type;
conditional_iterator_impl(CategoryType &cat, row_iterator pos, const condition &cond, const std::array<size_t, N> &cix);
conditional_iterator_impl(const conditional_iterator_impl &i) = default;
......
......@@ -110,6 +110,7 @@ class row
private:
friend class item_handle;
friend class category_index;
template <typename, typename...>
friend class iterator_impl;
......@@ -136,6 +137,7 @@ class row_handle
public:
friend class item_handle;
friend class category;
friend class category_index;
row_handle() = default;
......@@ -258,6 +260,9 @@ class row_handle
void assign(size_t column, std::string_view value, bool updateLinked, bool validate = true);
bool operator==(const row_handle &rhs) const { return m_category == rhs.m_category and m_row == rhs.m_row; }
bool operator!=(const row_handle &rhs) const { return m_category != rhs.m_category or m_row != rhs.m_row; }
private:
uint16_t get_column_ix(std::string_view name) const;
......
......@@ -82,7 +82,7 @@ struct type_validator
return icompare(m_name, rhs.m_name) < 0;
}
int compare(const char *a, const char *b) const;
int compare(std::string_view a, std::string_view b) const;
};
struct item_validator
......
......@@ -27,6 +27,10 @@
#include <cif++/v2/category.hpp>
#include <cif++/v2/datablock.hpp>
// TODO: Find out what the rules are exactly for linked items, the current implementation
// is inconsistent. It all depends whether a link is satified if a field taking part in the
// set of linked items is null at one side and not null in the other.
namespace cif::v2
{
......@@ -56,29 +60,638 @@ std::string join(const V &arr, std::string_view sep)
return s.str();
}
// --------------------------------------------------------------------
class row_comparator
{
public:
row_comparator(category &cat)
: m_category(cat)
{
auto cv = cat.get_cat_validator();
for (auto k : cv->m_keys)
{
size_t ix = cat.get_column_ix(k);
auto iv = cv->get_validator_for_item(k);
if (iv == nullptr)
throw std::runtime_error("Incomplete dictionary, no Item Validator for Key " + k);
auto tv = iv->m_type;
if (tv == nullptr)
throw std::runtime_error("Incomplete dictionary, no type Validator for Item " + k);
using namespace std::placeholders;
m_comparator.emplace_back(ix, std::bind(&type_validator::compare, tv, _1, _2));
}
}
int operator()(const row *a, const row *b) const
{
assert(a);
assert(b);
row_handle rha(m_category, *a);
row_handle rhb(m_category, *b);
int d = 0;
for (auto &c : m_comparator)
{
size_t k;
compareFunc f;
std::tie(k, f) = c;
std::string_view ka = rha[k].text();
std::string_view kb = rhb[k].text();
d = f(ka, kb);
if (d != 0)
break;
}
return d;
}
private:
typedef std::function<int(std::string_view, std::string_view)> compareFunc;
typedef std::tuple<size_t, compareFunc> key_comparator;
std::vector<key_comparator> m_comparator;
category &m_category;
};
// --------------------------------------------------------------------
//
// class to keep an index on the keys of a category. This is a red/black
// tree implementation.
class category_index
{
public:
category_index(category *cat)
: m_category(*cat)
, m_row_comparator(m_category)
, m_root(nullptr)
{
reconstruct();
}
~category_index()
{
delete m_root;
}
row *find(row *k) const;
void insert(row *r);
void erase(row *r);
// batch create
void reconstruct();
// reorder the row's and returns new head and tail
std::tuple<row *, row *> reorder()
{
std::tuple<row *, row *> result = std::make_tuple(nullptr, nullptr);
if (m_root != nullptr)
{
entry *head = find_min(m_root);
entry *tail = reorder(m_root);
tail->m_row->m_next = nullptr;
result = std::make_tuple(head->m_row, tail->m_row);
}
return result;
}
size_t size() const;
// bool isValid() const;
private:
struct entry
{
entry(row *r)
: m_row(r)
, m_left(nullptr)
, m_right(nullptr)
, m_red(true)
{
}
~entry()
{
delete m_left;
delete m_right;
}
row *m_row;
entry *m_left;
entry *m_right;
bool m_red;
};
entry *insert(entry *h, row *v);
entry *erase(entry *h, row *k);
// void validate(entry* h, bool isParentRed, uint32_t blackDepth, uint32_t& minBlack, uint32_t& maxBlack) const;
entry *rotateLeft(entry *h)
{
entry *x = h->m_right;
h->m_right = x->m_left;
x->m_left = h;
x->m_red = h->m_red;
h->m_red = true;
return x;
}
entry *rotateRight(entry *h)
{
entry *x = h->m_left;
h->m_left = x->m_right;
x->m_right = h;
x->m_red = h->m_red;
h->m_red = true;
return x;
}
void flipColour(entry *h)
{
h->m_red = not h->m_red;
if (h->m_left != nullptr)
h->m_left->m_red = not h->m_left->m_red;
if (h->m_right != nullptr)
h->m_right->m_red = not h->m_right->m_red;
}
bool is_red(entry *h) const
{
return h != nullptr and h->m_red;
}
entry *move_red_left(entry *h)
{
flipColour(h);
if (h->m_right != nullptr and is_red(h->m_right->m_left))
{
h->m_right = rotateRight(h->m_right);
h = rotateLeft(h);
flipColour(h);
}
return h;
}
entry *move_red_right(entry *h)
{
flipColour(h);
if (h->m_left != nullptr and is_red(h->m_left->m_left))
{
h = rotateRight(h);
flipColour(h);
}
return h;
}
entry *fix_up(entry *h)
{
if (is_red(h->m_right))
h = rotateLeft(h);
if (is_red(h->m_left) and is_red(h->m_left->m_left))
h = rotateRight(h);
if (is_red(h->m_left) and is_red(h->m_right))
flipColour(h);
return h;
}
entry *find_min(entry *h)
{
while (h->m_left != nullptr)
h = h->m_left;
return h;
}
entry *erase_min(entry *h)
{
if (h->m_left == nullptr)
{
delete h;
h = nullptr;
}
else
{
if (not is_red(h->m_left) and not is_red(h->m_left->m_left))
h = move_red_left(h);
h->m_left = erase_min(h->m_left);
h = fix_up(h);
}
return h;
}
// Fix m_next fields for rows in order of this index
entry *reorder(entry *e)
{
auto result = e;
if (e->m_left != nullptr)
{
auto l = reorder(e->m_left);
l->m_row->m_next = e->m_row;
}
if (e->m_right != nullptr)
{
auto mr = find_min(e->m_right);
e->m_row->m_next = mr->m_row;
result = reorder(e->m_right);
}
return result;
}
category &m_category;
row_comparator m_row_comparator;
entry *m_root;
};
row *category_index::find(row *k) const
{
const entry *r = m_root;
while (r != nullptr)
{
int d = m_row_comparator(k, r->m_row);
if (d < 0)
r = r->m_left;
else if (d > 0)
r = r->m_right;
else
break;
}
return r ? r->m_row : nullptr;
}
void category_index::insert(row *k)
{
m_root = insert(m_root, k);
m_root->m_red = false;
}
category_index::entry *category_index::insert(entry *h, row *v)
{
if (h == nullptr)
return new entry(v);
int d = m_row_comparator(v, h->m_row);
if (d < 0)
h->m_left = insert(h->m_left, v);
else if (d > 0)
h->m_right = insert(h->m_right, v);
else
{
row_handle rh(m_category, *v);
std::ostringstream os;
for (auto col : m_category.fields())
os << col << ": " << std::quoted(rh[col].text()) << "; ";
throw std::runtime_error("Duplicate Key violation, cat: " + m_category.name() + " values: " + os.str());
}
if (is_red(h->m_right) and not is_red(h->m_left))
h = rotateLeft(h);
if (is_red(h->m_left) and is_red(h->m_left->m_left))
h = rotateRight(h);
if (is_red(h->m_left) and is_red(h->m_right))
flipColour(h);
return h;
}
void category_index::erase(row *k)
{
m_root = erase(m_root, k);
if (m_root != nullptr)
m_root->m_red = false;
}
category_index::entry *category_index::erase(entry *h, row *k)
{
if (m_row_comparator(k, h->m_row) < 0)
{
if (h->m_left != nullptr)
{
if (not is_red(h->m_left) and not is_red(h->m_left->m_left))
h = move_red_left(h);
h->m_left = erase(h->m_left, k);
}
}
else
{
if (is_red(h->m_left))
h = rotateRight(h);
if (m_row_comparator(k, h->m_row) == 0 and h->m_right == nullptr)
{
delete h;
return nullptr;
}
if (h->m_right != nullptr)
{
if (not is_red(h->m_right) and not is_red(h->m_right->m_left))
h = move_red_right(h);
if (m_row_comparator(k, h->m_row) == 0)
{
h->m_row = find_min(h->m_right)->m_row;
h->m_right = erase_min(h->m_right);
}
else
h->m_right = erase(h->m_right, k);
}
}
return fix_up(h);
}
void category_index::reconstruct()
{
delete m_root;
m_root = nullptr;
for (auto r : m_category)
insert(r);
// maybe reconstruction can be done quicker by using the following commented code.
// however, I've not had the time to think of a way to set the red/black flag correctly in that case.
// std::vector<row*> rows;
// transform(mCat.begin(), mCat.end(), backInserter(rows),
// [](Row r) -> row* { assert(r.mData); return r.mData; });
//
// assert(std::find(rows.begin(), rows.end(), nullptr) == rows.end());
//
// // don't use sort here, it will run out of the stack of something.
// // quicksort is notorious for using excessive recursion.
// // Besides, most of the time, the data is ordered already anyway.
//
// stable_sort(rows.begin(), rows.end(), [this](row* a, row* b) -> bool { return this->mComp(a, b) < 0; });
//
// for (size_t i = 0; i < rows.size() - 1; ++i)
// assert(mComp(rows[i], rows[i + 1]) < 0);
//
// deque<entry*> e;
// transform(rows.begin(), rows.end(), back_inserter(e),
// [](row* r) -> entry* { return new entry(r); });
//
// while (e.size() > 1)
// {
// deque<entry*> ne;
//
// while (not e.empty())
// {
// entry* a = e.front();
// e.pop_front();
//
// if (e.empty())
// ne.push_back(a);
// else
// {
// entry* b = e.front();
// b->mLeft = a;
//
// assert(mComp(a->mRow, b->mRow) < 0);
//
// e.pop_front();
//
// if (not e.empty())
// {
// entry* c = e.front();
// e.pop_front();
//
// assert(mComp(b->mRow, c->mRow) < 0);
//
// b->mRight = c;
// }
//
// ne.push_back(b);
//
// if (not e.empty())
// {
// ne.push_back(e.front());
// e.pop_front();
// }
// }
// }
//
// swap (e, ne);
// }
//
// assert(e.size() == 1);
// mRoot = e.front();
}
size_t category_index::size() const
{
std::stack<entry *> s;
s.push(m_root);
size_t result = 0;
while (not s.empty())
{
entry *e = s.top();
s.pop();
if (e == nullptr)
continue;
++result;
s.push(e->m_left);
s.push(e->m_right);
}
return result;
}
// --------------------------------------------------------------------
category::category(std::string_view name)
: m_name(name)
{
}
category::category(const category &rhs)
: m_name(rhs.m_name)
, m_columns(rhs.m_columns)
, m_validator(rhs.m_validator)
, m_cat_validator(rhs.m_cat_validator)
, m_parent_links(rhs.m_parent_links)
, m_child_links(rhs.m_child_links)
, m_cascade(rhs.m_cascade)
{
for (auto r = rhs.m_head; r != nullptr; r = r->m_next)
insert_impl(end(), clone_row(*r));
if (m_validator != nullptr)
m_index = new category_index(this);
}
category::category(category &&rhs)
: m_name(std::move(rhs.m_name))
, m_columns(std::move(rhs.m_columns))
, m_validator(rhs.m_validator)
, m_cat_validator(rhs.m_cat_validator)
, m_parent_links(std::move(rhs.m_parent_links))
, m_child_links(std::move(rhs.m_child_links))
, m_cascade(rhs.m_cascade)
, m_index(rhs.m_index)
, m_head(rhs.m_head)
, m_tail(rhs.m_tail)
{
rhs.m_head = nullptr;
rhs.m_tail = nullptr;
rhs.m_index = nullptr;
}
category &category::operator=(const category &rhs)
{
if (this != &rhs)
{
if (not empty())
clear();
m_name = rhs.m_name;
m_columns = rhs.m_columns;
m_cascade = rhs.m_cascade;
m_validator = nullptr;
m_cat_validator = nullptr;
delete m_index;
m_index = nullptr;
for (auto r = rhs.m_head; r != nullptr; r = r->m_next)
insert_impl(cend(), clone_row(*r));
m_validator = rhs.m_validator;
m_cat_validator = rhs.m_cat_validator;
m_parent_links = rhs.m_parent_links;
m_child_links = rhs.m_child_links;
if (m_validator != nullptr)
m_index = new category_index(this);
}
return *this;
}
category &category::operator=(category &&rhs)
{
if (this != &rhs)
{
if (not empty())
clear();
m_name = std::move(rhs.m_name);
m_columns = std::move(rhs.m_columns);
m_cascade = rhs.m_cascade;
m_validator = rhs.m_validator;
m_cat_validator = rhs.m_cat_validator;
m_parent_links = rhs.m_parent_links;
m_child_links = rhs.m_child_links;
m_index = rhs.m_index;
m_head = rhs.m_head;
m_tail = rhs.m_tail;
rhs.m_head = rhs.m_tail = nullptr;
rhs.m_index = nullptr;
}
return *this;
}
category::~category()
{
clear();
delete m_index;
}
// --------------------------------------------------------------------
iset category::fields() const
{
if (m_validator == nullptr)
throw std::runtime_error("No Validator specified");
if (m_cat_validator == nullptr)
m_validator->report_error("undefined Category", true);
iset result;
for (auto &iv : m_cat_validator->m_item_validators)
result.insert(iv.m_tag);
return result;
}
std::set<uint16_t> category::key_field_indices() const
{
if (m_validator == nullptr)
throw std::runtime_error("No Validator specified");
if (m_cat_validator == nullptr)
m_validator->report_error("undefined Category", true);
std::set<uint16_t> result;
for (auto &k : m_cat_validator->m_keys)
result.insert(get_column_ix(k));
return result;
}
// --------------------------------------------------------------------
void category::set_validator(const validator *v, datablock &db)
{
m_validator = v;
// if (m_index != nullptr)
// {
// delete m_index;
// m_index = nullptr;
// }
if (m_index != nullptr)
{
delete m_index;
m_index = nullptr;
}
if (m_validator != nullptr)
{
m_cat_validator = m_validator->get_validator_for_category(m_name);
// if (m_cat_validator != nullptr)
// {
// m_index = new CatIndex(this);
// m_index->reconstruct();
// //#if DEBUG
// // assert(m_index->size() == size());
// // m_index->validate();
// //#endif
// }
if (m_cat_validator != nullptr)
m_index = new category_index(this);
}
else
m_cat_validator = nullptr;
......@@ -124,13 +737,13 @@ bool category::is_valid() const
if (empty())
{
if (VERBOSE > 2)
std::cerr << "Skipping validation of empty Category " << m_name << std::endl;
std::cerr << "Skipping validation of empty category " << m_name << std::endl;
return true;
}
if (m_cat_validator == nullptr)
{
m_validator->report_error("undefined Category " + m_name, false);
m_validator->report_error("undefined category " + m_name, false);
return false;
}
......@@ -141,7 +754,7 @@ bool category::is_valid() const
auto iv = m_cat_validator->get_validator_for_item(col.m_name);
if (iv == nullptr)
{
m_validator->report_error("Field " + col.m_name + " is not valid in Category " + m_name, false);
m_validator->report_error("Field " + col.m_name + " is not valid in category " + m_name, false);
result = false;
}
......@@ -154,22 +767,22 @@ bool category::is_valid() const
if (not mandatory.empty())
{
m_validator->report_error("In Category " + m_name + " the following mandatory fields are missing: " + join(mandatory, ", "), false);
m_validator->report_error("In category " + m_name + " the following mandatory fields are missing: " + join(mandatory, ", "), false);
result = false;
}
//#if not defined(NDEBUG)
// // check index?
// if (m_index)
// {
// m_index->validate();
// for (auto r: *this)
// {
// if (m_index->find(r.mData) != r.mData)
// m_validator->report_error("Key not found in index for Category " + m_name);
// }
// }
//#endif
#if not defined(NDEBUG)
// check index?
if (m_index)
{
// m_index->validate();
for (auto r : *this)
{
if (m_index->find(r) != r)
m_validator->report_error("Key not found in index for category " + m_name, true);
}
}
#endif
// validate all values
mandatory = m_cat_validator->m_mandatory_fields;
......@@ -183,7 +796,7 @@ bool category::is_valid() const
if (iv == nullptr)
{
m_validator->report_error("invalid field " + m_columns[cix].m_name + " for Category " + m_name, false);
m_validator->report_error("invalid field " + m_columns[cix].m_name + " for category " + m_name, false);
result = false;
continue;
}
......@@ -210,7 +823,7 @@ bool category::is_valid() const
if (iv != nullptr and iv->m_mandatory)
{
m_validator->report_error("missing mandatory field " + m_columns[cix].m_name + " for Category " + m_name, false);
m_validator->report_error("missing mandatory field " + m_columns[cix].m_name + " for category " + m_name, false);
result = false;
}
}
......@@ -219,6 +832,136 @@ bool category::is_valid() const
return result;
}
// --------------------------------------------------------------------
bool category::has_children(row_handle r) const
{
assert(m_validator != nullptr);
assert(m_cat_validator != nullptr);
bool result = false;
for (auto &&[childCat, link] : m_child_links)
{
condition cond;
for (size_t ix = 0; ix < link->m_parent_keys.size(); ++ix)
{
std::string_view value = r[link->m_parent_keys[ix]].text();
// cond = std::move(cond) and (key(link->m_child_keys[ix]) == value or key(link->m_child_keys[ix]) == null);
cond = std::move(cond) and (key(link->m_child_keys[ix]) == value);
}
result = not childCat->find(std::move(cond)).empty();
if (result)
break;
}
return result;
}
bool category::has_parents(row_handle r) const
{
assert(m_validator != nullptr);
assert(m_cat_validator != nullptr);
bool result = false;
for (auto &&[parentCat, link] : m_parent_links)
{
condition cond;
for (size_t ix = 0; ix < link->m_child_keys.size(); ++ix)
{
std::string_view value = r[link->m_child_keys[ix]].text();
cond = std::move(cond) and (key(link->m_parent_keys[ix]) == value);
}
result = not parentCat->find(std::move(cond)).empty();
if (result)
break;
}
return result;
}
std::vector<row_handle> category::get_children(row_handle r, category &childCat)
{
assert(m_validator != nullptr);
assert(m_cat_validator != nullptr);
std::vector<row_handle> result;
for (auto &link : m_validator->get_links_for_parent(m_name))
{
if (link->m_child_category != childCat.m_name)
continue;
condition cond;
for (size_t ix = 0; ix < link->m_parent_keys.size(); ++ix)
{
std::string_view value = r[link->m_parent_keys[ix]].text();
// cond = std::move(cond) and (key(link->m_child_keys[ix]) == value or key(link->m_child_keys[ix]) == null);
cond = std::move(cond) and (key(link->m_child_keys[ix]) == value);
}
for (auto child: childCat.find(std::move(cond)))
{
if (std::find(result.begin(), result.end(), child) == result.end())
result.push_back(child);
}
}
return result;
}
std::vector<row_handle> category::get_parents(row_handle r, category &parentCat)
{
assert(m_validator != nullptr);
assert(m_cat_validator != nullptr);
std::vector<row_handle> result;
for (auto &link : m_validator->get_links_for_child(m_name))
{
if (link->m_parent_category != parentCat.m_name)
continue;
condition cond;
for (size_t ix = 0; ix < link->m_child_keys.size(); ++ix)
{
std::string_view value = r[link->m_child_keys[ix]].text();
cond = std::move(cond) and (key(link->m_parent_keys[ix]) == value);
}
for (auto parent: parentCat.find(std::move(cond)))
{
if (std::find(result.begin(), result.end(), parent) == result.end())
result.push_back(parent);
}
}
return result;
}
std::vector<row_handle> category::get_linked(row_handle r, category &cat)
{
std::vector<row_handle> result = get_children(r, cat);
if (result.empty())
result = get_parents(r, cat);
return result;
}
// --------------------------------------------------------------------
category::iterator category::erase(iterator pos)
{
row_handle rh = *pos;
......@@ -232,8 +975,8 @@ category::iterator category::erase(iterator pos)
if (m_head == nullptr)
throw std::runtime_error("erase");
// if (mIndex != nullptr)
// mIndex->erase(r.mData);
if (m_index != nullptr)
m_index->erase(r);
if (r == m_head)
{
......@@ -270,6 +1013,7 @@ category::iterator category::erase(iterator pos)
for (size_t ix = 0; ix < link->m_parent_keys.size(); ++ix)
{
std::string_view value = rh[link->m_parent_keys[ix]].text();
// cond = std::move(cond) and (key(link->m_child_keys[ix]) == value or key(link->m_child_keys[ix]) == null);
cond = std::move(cond) and (key(link->m_child_keys[ix]) == value);
}
......@@ -288,7 +1032,7 @@ category::iterator category::erase(iterator pos)
m_tail = m_tail->m_next;
}
return result;
return result;
}
size_t category::erase(condition &&cond)
......@@ -351,7 +1095,7 @@ bool category::is_orphan(row_handle r) const
}
// if (VERBOSE > 2)
// std::cerr << "Check condition '" << cond << "' in parent category " << link->mParentCategory << " for child cat " << mName << std::endl;
// std::cerr << "Check condition '" << cond << "' in parent category " << link->mParentcategory << " for child cat " << m_name << std::endl;
if (parentCat->exists(std::move(cond)))
{
......@@ -389,7 +1133,6 @@ void category::erase_orphans(condition &&cond)
erase(iterator(*this, r));
}
void category::update_value(row *row, size_t column, std::string_view value, bool updateLinked, bool validate)
{
auto &col = m_columns[column];
......@@ -415,18 +1158,18 @@ void category::update_value(row *row, size_t column, std::string_view value, boo
if (col.m_validator and validate)
col.m_validator->operator()(value);
// If the field is part of the Key for this Category, remove it from the index
// If the field is part of the Key for this category, remove it from the index
// before updating
bool reinsert = false;
// if (updateLinked and // an update of an Item's value
// cat->m_index != nullptr and cat->keyFieldsByIndex().count(column))
// {
// reinsert = cat->m_index->find(mData);
// if (reinsert)
// cat->m_index->erase(mData);
// }
if (updateLinked and // an update of an Item's value
m_index != nullptr and key_field_indices().count(column))
{
reinsert = m_index->find(row);
if (reinsert)
m_index->erase(row);
}
// first remove old value with cix
......@@ -470,8 +1213,8 @@ void category::update_value(row *row, size_t column, std::string_view value, boo
}
}
// if (reinsert)
// cat->mIndex->insert(mData);
if (reinsert)
m_index->insert(row);
// see if we need to update any child categories that depend on this value
auto iv = col.m_validator;
......@@ -515,7 +1258,7 @@ void category::update_value(row *row, size_t column, std::string_view value, boo
// if (cif::VERBOSE > 2)
// {
// std::cerr << "Parent: " << linked->mParentCategory << " Child: " << linked->mChildCategory << std::endl
// std::cerr << "Parent: " << linked->mParentcategory << " Child: " << linked->m_child_category << std::endl
// << cond << std::endl;
// }
......
......@@ -45,7 +45,7 @@ std::string_view item_handle::text() const
void item_handle::assign_value(const item &v)
{
m_row_handle.assign(m_column, v.value(), false);
m_row_handle.assign(m_column, v.value(), true);
}
}
......@@ -31,6 +31,8 @@
#include <cif++/v2/dictionary_parser.hpp>
#include <cif++/v2/validate.hpp>
#include <cif++/CifUtils.hpp>
namespace cif
{
extern int VERBOSE;
......@@ -69,25 +71,27 @@ DDL_PrimitiveType map_to_primitive_type(std::string_view s)
// --------------------------------------------------------------------
int type_validator::compare(const char *a, const char *b) const
int type_validator::compare(std::string_view a, std::string_view b) const
{
int result = 0;
if (*a == 0)
result = *b == 0 ? 0 : -1;
else if (*b == 0)
result = *a == 0 ? 0 : +1;
if (a.empty())
result = b.empty() ? 0 : -1;
else if (b.empty())
result = a.empty() ? 0 : +1;
else
{
try
switch (m_primitive_type)
{
switch (m_primitive_type)
case DDL_PrimitiveType::Numb:
{
case DDL_PrimitiveType::Numb:
{
double da = strtod(a, nullptr);
double db = strtod(b, nullptr);
double da, db;
auto ra = cif::from_chars(a.begin(), a.end(), da);
auto rb = cif::from_chars(b.begin(), b.end(), db);
if (ra.ec == std::errc() and rb.ec == std::errc())
{
auto d = da - db;
if (std::abs(d) > std::numeric_limits<double>::epsilon())
{
......@@ -96,64 +100,64 @@ int type_validator::compare(const char *a, const char *b) const
else if (d < 0)
result = -1;
}
break;
}
else if (ra.ec == std::errc())
result = 1;
else
result = -1;
break;
}
case DDL_PrimitiveType::UChar:
case DDL_PrimitiveType::Char:
{
// CIF is guaranteed to have ascii only, therefore this primitive code will do
// also, we're collapsing spaces
case DDL_PrimitiveType::UChar:
case DDL_PrimitiveType::Char:
{
// CIF is guaranteed to have ascii only, therefore this primitive code will do
// also, we're collapsing spaces
auto ai = a, bi = b;
for (;;)
auto ai = a.begin(), bi = b.begin();
for (;;)
{
if (ai == a.end())
{
if (*ai == 0)
{
if (*bi != 0)
result = -1;
break;
}
else if (*bi == 0)
{
result = 1;
break;
}
char ca = *ai;
char cb = *bi;
if (bi != b.end())
result = -1;
break;
}
else if (bi == b.end())
{
result = 1;
break;
}
if (m_primitive_type == DDL_PrimitiveType::UChar)
{
ca = tolower(ca);
cb = tolower(cb);
}
char ca = *ai;
char cb = *bi;
result = ca - cb;
if (m_primitive_type == DDL_PrimitiveType::UChar)
{
ca = tolower(ca);
cb = tolower(cb);
}
if (result != 0)
break;
result = ca - cb;
if (ca == ' ')
{
while (ai[1] == ' ')
++ai;
while (bi[1] == ' ')
++bi;
}
if (result != 0)
break;
++ai;
++bi;
if (ca == ' ')
{
while (ai[1] == ' ')
++ai;
while (bi[1] == ' ')
++bi;
}
break;
++ai;
++bi;
}
break;
}
}
catch (const std::invalid_argument &ex)
{
result = 1;
}
}
return result;
......
......@@ -553,1215 +553,1216 @@ _cat_2.desc
std::exception);
}
// // --------------------------------------------------------------------
// --------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(d2)
{
const char dict[] = R"(
data_test_dict.dic
_datablock.id test_dict.dic
_datablock.description
;
A test dictionary
;
_dictionary.title test_dict.dic
_dictionary.datablock_id test_dict.dic
_dictionary.version 1.0
loop_
_item_type_list.code
_item_type_list.primitive_code
_item_type_list.construct
_item_type_list.detail
code char
'[][_,.;:"&<>()/\{}'`~!@#$%A-Za-z0-9*|+-]*'
; code item types/single words ...
;
ucode uchar
'[][_,.;:"&<>()/\{}'`~!@#$%A-Za-z0-9*|+-]*'
; code item types/single words, case insensitive
;
text char
'[][ \n\t()_,.;:"&<>/\{}'`~!@#$%?+=*A-Za-z0-9|^-]*'
; text item types / multi-line text ...
;
int numb
'[+-]?[0-9]+'
; int item types are the subset of numbers that are the negative
or positive integers.
;
save_cat_1
_category.description 'A simple test category'
_category.id cat_1
_category.mandatory_code no
_category_key.name '_cat_1.id'
save_
save__cat_1.id
_item.name '_cat_1.id'
_item.category_id cat_1
_item.mandatory_code yes
_item_type.code code
save_
save__cat_1.c
_item.name '_cat_1.c'
_item.category_id cat_1
_item.mandatory_code yes
_item_type.code ucode
save_
)";
struct membuf : public std::streambuf
{
membuf(char *text, size_t length)
{
this->setg(text, text, text + length);
}
} buffer(const_cast<char *>(dict), sizeof(dict) - 1);
std::istream is_dict(&buffer);
auto validator = cif::v2::parse_dictionary("test", is_dict);
cif::v2::file f;
f.set_validator(&validator);
// --------------------------------------------------------------------
const char data[] = R"(
data_test
loop_
_cat_1.id
_cat_1.c
aap Aap
noot Noot
mies Mies
)";
struct data_membuf : public std::streambuf
{
data_membuf(char *text, size_t length)
{
this->setg(text, text, text + length);
}
} data_buffer(const_cast<char *>(data), sizeof(data) - 1);
std::istream is_data(&data_buffer);
f.load(is_data);
auto &cat1 = f.front()["cat_1"];
BOOST_CHECK(cat1.size() == 3);
cat1.erase(cif::v2::key("id") == "AAP");
BOOST_CHECK(cat1.size() == 3);
cat1.erase(cif::v2::key("id") == "noot");
BOOST_CHECK(cat1.size() == 2);
}
// --------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(d3)
{
const char dict[] = R"(
data_test_dict.dic
_datablock.id test_dict.dic
_datablock.description
;
A test dictionary
;
_dictionary.title test_dict.dic
_dictionary.datablock_id test_dict.dic
_dictionary.version 1.0
loop_
_item_type_list.code
_item_type_list.primitive_code
_item_type_list.construct
code char
'[][_,.;:"&<>()/\{}'`~!@#$%A-Za-z0-9*|+-]*'
text char
'[][ \n\t()_,.;:"&<>/\{}'`~!@#$%?+=*A-Za-z0-9|^-]*'
int numb
'[+-]?[0-9]+'
save_cat_1
_category.description 'A simple test category'
_category.id cat_1
_category.mandatory_code no
_category_key.name '_cat_1.id'
save_
save__cat_1.id
_item.name '_cat_1.id'
_item.category_id cat_1
_item.mandatory_code yes
_item_linked.child_name '_cat_2.parent_id'
_item_linked.parent_name '_cat_1.id'
_item_type.code code
save_
save__cat_1.name1
_item.name '_cat_1.name1'
_item.category_id cat_1
_item.mandatory_code yes
_item_type.code text
save_
save__cat_1.name2
_item.name '_cat_1.name2'
_item.category_id cat_1
_item.mandatory_code no
_item_linked.child_name '_cat_2.name2'
_item_linked.parent_name '_cat_1.name2'
_item_type.code text
save_
save_cat_2
_category.description 'A second simple test category'
_category.id cat_2
_category.mandatory_code no
_category_key.name '_cat_2.id'
save_
save__cat_2.id
_item.name '_cat_2.id'
_item.category_id cat_2
_item.mandatory_code yes
_item_type.code int
save_
save__cat_2.parent_id
_item.name '_cat_2.parent_id'
_item.category_id cat_2
_item.mandatory_code yes
_item_type.code code
save_
save__cat_2.name2
_item.name '_cat_2.name2'
_item.category_id cat_2
_item.mandatory_code no
_item_type.code text
save_
save__cat_2.desc
_item.name '_cat_2.desc'
_item.category_id cat_2
_item.mandatory_code yes
_item_type.code text
save_
)";
struct membuf : public std::streambuf
{
membuf(char *text, size_t length)
{
this->setg(text, text, text + length);
}
} buffer(const_cast<char *>(dict), sizeof(dict) - 1);
std::istream is_dict(&buffer);
auto validator = cif::v2::parse_dictionary("test", is_dict);
cif::v2::file f;
f.set_validator(&validator);
// --------------------------------------------------------------------
const char data[] = R"(
data_test
loop_
_cat_1.id
_cat_1.name1
_cat_1.name2
1 Aap aap
2 Noot noot
3 Mies mies
loop_
_cat_2.id
_cat_2.parent_id
_cat_2.name2
_cat_2.desc
1 1 aap 'Een dier'
2 1 . 'Een andere aap'
3 2 noot 'walnoot bijvoorbeeld'
4 2 n2 hazelnoot
)";
struct data_membuf : public std::streambuf
{
data_membuf(char *text, size_t length)
{
this->setg(text, text, text + length);
}
} data_buffer(const_cast<char *>(data), sizeof(data) - 1);
std::istream is_data(&data_buffer);
f.load(is_data);
auto &cat1 = f.front()["cat_1"];
auto &cat2 = f.front()["cat_2"];
// check a rename in parent and child
for (auto r : cat1.find(cif::v2::key("id") == 1))
{
r["id"] = 10;
break;
}
BOOST_CHECK(cat1.size() == 3);
BOOST_CHECK(cat2.size() == 4);
BOOST_CHECK(cat1.find(cif::v2::key("id") == 1).size() == 0);
BOOST_CHECK(cat1.find(cif::v2::key("id") == 10).size() == 1);
BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 1).size() == 0);
BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 10).size() == 2);
// check a rename in parent and child, this time only one child should be renamed
for (auto r : cat1.find(cif::v2::key("id") == 2))
{
r["id"] = 20;
break;
}
BOOST_CHECK(cat1.size() == 3);
BOOST_CHECK(cat2.size() == 4);
BOOST_CHECK(cat1.find(cif::v2::key("id") == 2).size() == 0);
BOOST_CHECK(cat1.find(cif::v2::key("id") == 20).size() == 1);
BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 2).size() == 1);
BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 20).size() == 1);
BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 2 and cif::v2::key("name2") == "noot").size() == 0);
BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 2 and cif::v2::key("name2") == "n2").size() == 1);
BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 20 and cif::v2::key("name2") == "noot").size() == 1);
BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 20 and cif::v2::key("name2") == "n2").size() == 0);
// --------------------------------------------------------------------
cat1.erase(cif::v2::key("id") == 10);
BOOST_CHECK(cat1.size() == 2);
BOOST_CHECK(cat2.size() == 2);
cat1.erase(cif::v2::key("id") == 20);
BOOST_CHECK(cat1.size() == 1);
BOOST_CHECK(cat2.size() == 1);
}
// --------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(d4)
{
const char dict[] = R"(
data_test_dict.dic
_datablock.id test_dict.dic
_datablock.description
;
A test dictionary
;
_dictionary.title test_dict.dic
_dictionary.datablock_id test_dict.dic
_dictionary.version 1.0
loop_
_item_type_list.code
_item_type_list.primitive_code
_item_type_list.construct
code char
'[][_,.;:"&<>()/\{}'`~!@#$%A-Za-z0-9*|+-]*'
text char
'[][ \n\t()_,.;:"&<>/\{}'`~!@#$%?+=*A-Za-z0-9|^-]*'
int numb
'[+-]?[0-9]+'
save_cat_1
_category.description 'A simple test category'
_category.id cat_1
_category.mandatory_code no
_category_key.name '_cat_1.id'
save_
save__cat_1.id
_item.name '_cat_1.id'
_item.category_id cat_1
_item.mandatory_code yes
_item_linked.child_name '_cat_2.parent_id'
_item_linked.parent_name '_cat_1.id'
_item_type.code int
save_
save__cat_1.id2
_item.name '_cat_1.id2'
_item.category_id cat_1
_item.mandatory_code no
_item_linked.child_name '_cat_2.parent_id2'
_item_linked.parent_name '_cat_1.id2'
_item_type.code code
save_
save__cat_1.id3
_item.name '_cat_1.id3'
_item.category_id cat_1
_item.mandatory_code no
_item_linked.child_name '_cat_2.parent_id3'
_item_linked.parent_name '_cat_1.id3'
_item_type.code text
save_
save_cat_2
_category.description 'A second simple test category'
_category.id cat_2
_category.mandatory_code no
_category_key.name '_cat_2.id'
save_
save__cat_2.id
_item.name '_cat_2.id'
_item.category_id cat_2
_item.mandatory_code yes
_item_type.code int
save_
save__cat_2.parent_id
_item.name '_cat_2.parent_id'
_item.category_id cat_2
_item.mandatory_code yes
_item_type.code int
save_
save__cat_2.parent_id2
_item.name '_cat_2.parent_id2'
_item.category_id cat_2
_item.mandatory_code no
_item_type.code code
save_
save__cat_2.parent_id3
_item.name '_cat_2.parent_id3'
_item.category_id cat_2
_item.mandatory_code no
_item_type.code code
save_
)";
// BOOST_AUTO_TEST_CASE(d2)
// {
// const char dict[] = R"(
// data_test_dict.dic
// _datablock.id test_dict.dic
// _datablock.description
// ;
// A test dictionary
// ;
// _dictionary.title test_dict.dic
// _dictionary.datablock_id test_dict.dic
// _dictionary.version 1.0
// loop_
// _item_type_list.code
// _item_type_list.primitive_code
// _item_type_list.construct
// _item_type_list.detail
// code char
// '[][_,.;:"&<>()/\{}'`~!@#$%A-Za-z0-9*|+-]*'
// ; code item types/single words ...
// ;
// ucode uchar
// '[][_,.;:"&<>()/\{}'`~!@#$%A-Za-z0-9*|+-]*'
// ; code item types/single words, case insensitive
// ;
// text char
// '[][ \n\t()_,.;:"&<>/\{}'`~!@#$%?+=*A-Za-z0-9|^-]*'
// ; text item types / multi-line text ...
// ;
// int numb
// '[+-]?[0-9]+'
// ; int item types are the subset of numbers that are the negative
// or positive integers.
// ;
// save_cat_1
// _category.description 'A simple test category'
// _category.id cat_1
// _category.mandatory_code no
// _category_key.name '_cat_1.id'
// save_
// save__cat_1.id
// _item.name '_cat_1.id'
// _item.category_id cat_1
// _item.mandatory_code yes
// _item_type.code code
// save_
// save__cat_1.c
// _item.name '_cat_1.c'
// _item.category_id cat_1
// _item.mandatory_code yes
// _item_type.code ucode
// save_
// )";
// struct membuf : public std::streambuf
// {
// membuf(char *text, size_t length)
// {
// this->setg(text, text, text + length);
// }
// } buffer(const_cast<char *>(dict), sizeof(dict) - 1);
struct membuf : public std::streambuf
{
membuf(char *text, size_t length)
{
this->setg(text, text, text + length);
}
} buffer(const_cast<char *>(dict), sizeof(dict) - 1);
// std::istream is_dict(&buffer);
std::istream is_dict(&buffer);
// cif::v2::validator validator("test", is_dict);
auto validator = cif::v2::parse_dictionary("test", is_dict);
// cif::File f;
// f.setValidator(&validator);
cif::v2::file f;
f.set_validator(&validator);
// // --------------------------------------------------------------------
// --------------------------------------------------------------------
// const char data[] = R"(
// data_test
// loop_
// _cat_1.id
// _cat_1.c
// aap Aap
// noot Noot
// mies Mies
// )";
// struct data_membuf : public std::streambuf
// {
// data_membuf(char *text, size_t length)
// {
// this->setg(text, text, text + length);
// }
// } data_buffer(const_cast<char *>(data), sizeof(data) - 1);
const char data[] = R"(
data_test
loop_
_cat_1.id
_cat_1.id2
_cat_1.id3
1 aap aap
2 . noot
3 mies .
4 . .
// std::istream is_data(&data_buffer);
// f.load(is_data);
loop_
_cat_2.id
_cat_2.parent_id
_cat_2.parent_id2
_cat_2.parent_id3
1 1 aap aap
2 1 . x
3 1 aap .
4 2 noot noot
5 2 . noot
6 2 noot .
7 2 . .
8 3 mies mies
9 3 . mies
10 3 mies .
11 4 roos roos
12 4 . roos
13 4 roos .
)";
// auto &cat1 = f.front()["cat_1"];
struct data_membuf : public std::streambuf
{
data_membuf(char *text, size_t length)
{
this->setg(text, text, text + length);
}
} data_buffer(const_cast<char *>(data), sizeof(data) - 1);
// BOOST_CHECK(cat1.size() == 3);
std::istream is_data(&data_buffer);
f.load(is_data);
// cat1.erase(cif::v2::key("id") == "AAP");
auto &cat1 = f.front()["cat_1"];
auto &cat2 = f.front()["cat_2"];
// BOOST_CHECK(cat1.size() == 3);
// check a rename in parent and child
// cat1.erase(cif::v2::key("id") == "noot");
for (auto r : cat1.find(cif::v2::key("id") == 1))
{
r["id"] = 10;
break;
}
// BOOST_CHECK(cat1.size() == 2);
// }
BOOST_CHECK(cat1.size() == 4);
BOOST_CHECK(cat2.size() == 13);
// // --------------------------------------------------------------------
BOOST_CHECK(cat1.find(cif::v2::key("id") == 1).size() == 0);
BOOST_CHECK(cat1.find(cif::v2::key("id") == 10).size() == 1);
// BOOST_AUTO_TEST_CASE(d3)
// {
// const char dict[] = R"(
// data_test_dict.dic
// _datablock.id test_dict.dic
// _datablock.description
// ;
// A test dictionary
// ;
// _dictionary.title test_dict.dic
// _dictionary.datablock_id test_dict.dic
// _dictionary.version 1.0
// loop_
// _item_type_list.code
// _item_type_list.primitive_code
// _item_type_list.construct
// code char
// '[][_,.;:"&<>()/\{}'`~!@#$%A-Za-z0-9*|+-]*'
// text char
// '[][ \n\t()_,.;:"&<>/\{}'`~!@#$%?+=*A-Za-z0-9|^-]*'
// int numb
// '[+-]?[0-9]+'
// save_cat_1
// _category.description 'A simple test category'
// _category.id cat_1
// _category.mandatory_code no
// _category_key.name '_cat_1.id'
// save_
// save__cat_1.id
// _item.name '_cat_1.id'
// _item.category_id cat_1
// _item.mandatory_code yes
// _item_linked.child_name '_cat_2.parent_id'
// _item_linked.parent_name '_cat_1.id'
// _item_type.code code
// save_
// save__cat_1.name1
// _item.name '_cat_1.name1'
// _item.category_id cat_1
// _item.mandatory_code yes
// _item_type.code text
// save_
// save__cat_1.name2
// _item.name '_cat_1.name2'
// _item.category_id cat_1
// _item.mandatory_code no
// _item_linked.child_name '_cat_2.name2'
// _item_linked.parent_name '_cat_1.name2'
// _item_type.code text
// save_
// save_cat_2
// _category.description 'A second simple test category'
// _category.id cat_2
// _category.mandatory_code no
// _category_key.name '_cat_2.id'
// save_
// save__cat_2.id
// _item.name '_cat_2.id'
// _item.category_id cat_2
// _item.mandatory_code yes
// _item_type.code int
// save_
// save__cat_2.parent_id
// _item.name '_cat_2.parent_id'
// _item.category_id cat_2
// _item.mandatory_code yes
// _item_type.code code
// save_
// save__cat_2.name2
// _item.name '_cat_2.name2'
// _item.category_id cat_2
// _item.mandatory_code no
// _item_type.code text
// save_
// save__cat_2.desc
// _item.name '_cat_2.desc'
// _item.category_id cat_2
// _item.mandatory_code yes
// _item_type.code text
// save_
// )";
// struct membuf : public std::streambuf
// {
// membuf(char *text, size_t length)
// {
// this->setg(text, text, text + length);
// }
// } buffer(const_cast<char *>(dict), sizeof(dict) - 1);
BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 1).size() == 1);
BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 10).size() == 2);
// std::istream is_dict(&buffer);
for (auto r : cat1.find(cif::v2::key("id") == 2))
{
r["id"] = 20;
break;
}
// cif::v2::validator validator("test", is_dict);
BOOST_CHECK(cat1.size() == 4);
BOOST_CHECK(cat2.size() == 13);
// cif::File f;
// f.setValidator(&validator);
BOOST_CHECK(cat1.find(cif::v2::key("id") == 2).size() == 0);
BOOST_CHECK(cat1.find(cif::v2::key("id") == 20).size() == 1);
// // --------------------------------------------------------------------
BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 2).size() == 2);
BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 20).size() == 2);
// const char data[] = R"(
// data_test
// loop_
// _cat_1.id
// _cat_1.name1
// _cat_1.name2
// 1 Aap aap
// 2 Noot noot
// 3 Mies mies
for (auto r : cat1.find(cif::v2::key("id") == 3))
{
r["id"] = 30;
break;
}
// loop_
// _cat_2.id
// _cat_2.parent_id
// _cat_2.name2
// _cat_2.desc
// 1 1 aap 'Een dier'
// 2 1 . 'Een andere aap'
// 3 2 noot 'walnoot bijvoorbeeld'
// 4 2 n2 hazelnoot
// )";
// struct data_membuf : public std::streambuf
// {
// data_membuf(char *text, size_t length)
// {
// this->setg(text, text, text + length);
// }
// } data_buffer(const_cast<char *>(data), sizeof(data) - 1);
BOOST_CHECK(cat1.size() == 4);
BOOST_CHECK(cat2.size() == 13);
// std::istream is_data(&data_buffer);
// f.load(is_data);
BOOST_CHECK(cat1.find(cif::v2::key("id") == 3).size() == 0);
BOOST_CHECK(cat1.find(cif::v2::key("id") == 30).size() == 1);
// auto &cat1 = f.front()["cat_1"];
// auto &cat2 = f.front()["cat_2"];
BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 3).size() == 2);
BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 30).size() == 1);
// // check a rename in parent and child
for (auto r : cat1.find(cif::v2::key("id") == 4))
{
r["id"] = 40;
break;
}
// for (auto r : cat1.find(cif::v2::key("id") == 1))
// {
// r["id"] = 10;
// break;
// }
BOOST_CHECK(cat1.size() == 4);
BOOST_CHECK(cat2.size() == 13);
// BOOST_CHECK(cat1.size() == 3);
// BOOST_CHECK(cat2.size() == 4);
BOOST_CHECK(cat1.find(cif::v2::key("id") == 4).size() == 0);
BOOST_CHECK(cat1.find(cif::v2::key("id") == 10).size() == 1);
// BOOST_CHECK(cat1.find(cif::v2::key("id") == 1).size() == 0);
// BOOST_CHECK(cat1.find(cif::v2::key("id") == 10).size() == 1);
BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 4).size() == 3);
BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 40).size() == 0);
}
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 1).size() == 0);
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 10).size() == 2);
// --------------------------------------------------------------------
// // check a rename in parent and child, this time only one child should be renamed
BOOST_AUTO_TEST_CASE(d5)
{
const char dict[] = R"(
data_test_dict.dic
_datablock.id test_dict.dic
_datablock.description
;
A test dictionary
;
_dictionary.title test_dict.dic
_dictionary.datablock_id test_dict.dic
_dictionary.version 1.0
// for (auto r : cat1.find(cif::v2::key("id") == 2))
// {
// r["id"] = 20;
// break;
// }
loop_
_item_type_list.code
_item_type_list.primitive_code
_item_type_list.construct
code char
'[][_,.;:"&<>()/\{}'`~!@#$%A-Za-z0-9*|+-]*'
// BOOST_CHECK(cat1.size() == 3);
// BOOST_CHECK(cat2.size() == 4);
text char
'[][ \n\t()_,.;:"&<>/\{}'`~!@#$%?+=*A-Za-z0-9|^-]*'
// BOOST_CHECK(cat1.find(cif::v2::key("id") == 2).size() == 0);
// BOOST_CHECK(cat1.find(cif::v2::key("id") == 20).size() == 1);
int numb
'[+-]?[0-9]+'
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 2).size() == 1);
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 20).size() == 1);
save_cat_1
_category.description 'A simple test category'
_category.id cat_1
_category.mandatory_code no
_category_key.name '_cat_1.id'
save_
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 2 and cif::v2::key("name2") == "noot").size() == 0);
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 2 and cif::v2::key("name2") == "n2").size() == 1);
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 20 and cif::v2::key("name2") == "noot").size() == 1);
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 20 and cif::v2::key("name2") == "n2").size() == 0);
save__cat_1.id
_item.name '_cat_1.id'
_item.category_id cat_1
_item.mandatory_code yes
_item_type.code int
save_
// // // --------------------------------------------------------------------
save_cat_2
_category.description 'A second simple test category'
_category.id cat_2
_category.mandatory_code no
_category_key.name '_cat_2.id'
save_
// // cat1.erase(cif::v2::key("id") == 10);
save__cat_2.id
_item.name '_cat_2.id'
_item.category_id cat_2
_item.mandatory_code yes
_item_type.code int
save_
// // BOOST_CHECK(cat1.size() == 2);
// // BOOST_CHECK(cat2.size() == 2);
save__cat_2.parent_id
_item.name '_cat_2.parent_id'
_item.category_id cat_2
_item.mandatory_code yes
_item_type.code int
save_
// // cat1.erase(cif::v2::key("id") == 20);
save__cat_2.parent_id2
_item.name '_cat_2.parent_id2'
_item.category_id cat_2
_item.mandatory_code no
_item_type.code code
save_
// // BOOST_CHECK(cat1.size() == 1);
// // BOOST_CHECK(cat2.size() == 1);
// }
save__cat_2.parent_id3
_item.name '_cat_2.parent_id3'
_item.category_id cat_2
_item.mandatory_code no
_item_type.code code
save_
// // --------------------------------------------------------------------
loop_
_pdbx_item_linked_group_list.child_category_id
_pdbx_item_linked_group_list.link_group_id
_pdbx_item_linked_group_list.child_name
_pdbx_item_linked_group_list.parent_name
_pdbx_item_linked_group_list.parent_category_id
cat_2 1 '_cat_2.parent_id' '_cat_1.id' cat_1
cat_2 2 '_cat_2.parent_id2' '_cat_1.id' cat_1
cat_2 3 '_cat_2.parent_id3' '_cat_1.id' cat_1
// BOOST_AUTO_TEST_CASE(d4)
// {
// const char dict[] = R"(
// data_test_dict.dic
// _datablock.id test_dict.dic
// _datablock.description
// ;
// A test dictionary
// ;
// _dictionary.title test_dict.dic
// _dictionary.datablock_id test_dict.dic
// _dictionary.version 1.0
// loop_
// _item_type_list.code
// _item_type_list.primitive_code
// _item_type_list.construct
// code char
// '[][_,.;:"&<>()/\{}'`~!@#$%A-Za-z0-9*|+-]*'
// text char
// '[][ \n\t()_,.;:"&<>/\{}'`~!@#$%?+=*A-Za-z0-9|^-]*'
// int numb
// '[+-]?[0-9]+'
// save_cat_1
// _category.description 'A simple test category'
// _category.id cat_1
// _category.mandatory_code no
// _category_key.name '_cat_1.id'
// save_
// save__cat_1.id
// _item.name '_cat_1.id'
// _item.category_id cat_1
// _item.mandatory_code yes
// _item_linked.child_name '_cat_2.parent_id'
// _item_linked.parent_name '_cat_1.id'
// _item_type.code int
// save_
// save__cat_1.id2
// _item.name '_cat_1.id2'
// _item.category_id cat_1
// _item.mandatory_code no
// _item_linked.child_name '_cat_2.parent_id2'
// _item_linked.parent_name '_cat_1.id2'
// _item_type.code code
// save_
// save__cat_1.id3
// _item.name '_cat_1.id3'
// _item.category_id cat_1
// _item.mandatory_code no
// _item_linked.child_name '_cat_2.parent_id3'
// _item_linked.parent_name '_cat_1.id3'
// _item_type.code text
// save_
// save_cat_2
// _category.description 'A second simple test category'
// _category.id cat_2
// _category.mandatory_code no
// _category_key.name '_cat_2.id'
// save_
// save__cat_2.id
// _item.name '_cat_2.id'
// _item.category_id cat_2
// _item.mandatory_code yes
// _item_type.code int
// save_
// save__cat_2.parent_id
// _item.name '_cat_2.parent_id'
// _item.category_id cat_2
// _item.mandatory_code yes
// _item_type.code int
// save_
// save__cat_2.parent_id2
// _item.name '_cat_2.parent_id2'
// _item.category_id cat_2
// _item.mandatory_code no
// _item_type.code code
// save_
// save__cat_2.parent_id3
// _item.name '_cat_2.parent_id3'
// _item.category_id cat_2
// _item.mandatory_code no
// _item_type.code code
// save_
// )";
// struct membuf : public std::streambuf
// {
// membuf(char *text, size_t length)
// {
// this->setg(text, text, text + length);
// }
// } buffer(const_cast<char *>(dict), sizeof(dict) - 1);
loop_
_pdbx_item_linked_group.category_id
_pdbx_item_linked_group.link_group_id
_pdbx_item_linked_group.label
cat_2 1 cat_2:cat_1:1
cat_2 2 cat_2:cat_1:2
cat_2 3 cat_2:cat_1:3
)";
// std::istream is_dict(&buffer);
struct membuf : public std::streambuf
{
membuf(char *text, size_t length)
{
this->setg(text, text, text + length);
}
} buffer(const_cast<char *>(dict), sizeof(dict) - 1);
// cif::v2::validator validator("test", is_dict);
std::istream is_dict(&buffer);
// cif::File f;
// f.setValidator(&validator);
auto validator = cif::v2::parse_dictionary("test", is_dict);
// // --------------------------------------------------------------------
cif::v2::file f;
f.set_validator(&validator);
// const char data[] = R"(
// data_test
// loop_
// _cat_1.id
// _cat_1.id2
// _cat_1.id3
// 1 aap aap
// 2 . noot
// 3 mies .
// 4 . .
// --------------------------------------------------------------------
// loop_
// _cat_2.id
// _cat_2.parent_id
// _cat_2.parent_id2
// _cat_2.parent_id3
// 1 1 aap aap
// 2 1 . x
// 3 1 aap .
// 4 2 noot noot
// 5 2 . noot
// 6 2 noot .
// 7 2 . .
// 8 3 mies mies
// 9 3 . mies
// 10 3 mies .
// 11 4 roos roos
// 12 4 . roos
// 13 4 roos .
// )";
// struct data_membuf : public std::streambuf
// {
// data_membuf(char *text, size_t length)
// {
// this->setg(text, text, text + length);
// }
// } data_buffer(const_cast<char *>(data), sizeof(data) - 1);
const char data[] = R"(
data_test
loop_
_cat_1.id
1
2
3
loop_
_cat_2.id
_cat_2.parent_id
_cat_2.parent_id2
_cat_2.parent_id3
1 1 ? ?
2 ? 1 ?
3 ? ? 1
4 2 2 ?
5 2 ? 2
6 ? 2 2
7 3 3 3
)";
// std::istream is_data(&data_buffer);
// f.load(is_data);
// --------------------------------------------------------------------
// auto &cat1 = f.front()["cat_1"];
// auto &cat2 = f.front()["cat_2"];
struct data_membuf : public std::streambuf
{
data_membuf(char *text, size_t length)
{
this->setg(text, text, text + length);
}
} data_buffer(const_cast<char *>(data), sizeof(data) - 1);
// // check a rename in parent and child
std::istream is_data(&data_buffer);
f.load(is_data);
// for (auto r : cat1.find(cif::v2::key("id") == 1))
// {
// r["id"] = 10;
// break;
// }
auto &cat1 = f.front()["cat_1"];
auto &cat2 = f.front()["cat_2"];
// BOOST_CHECK(cat1.size() == 4);
// BOOST_CHECK(cat2.size() == 13);
// --------------------------------------------------------------------
// check iterate children
// BOOST_CHECK(cat1.find(cif::v2::key("id") == 1).size() == 0);
// BOOST_CHECK(cat1.find(cif::v2::key("id") == 10).size() == 1);
auto PR2set = cat1.find(cif::v2::key("id") == 2);
BOOST_ASSERT(PR2set.size() == 1);
auto PR2 = PR2set.front();
BOOST_CHECK(PR2["id"].as<int>() == 2);
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 1).size() == 1);
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 10).size() == 2);
auto CR2set = cat1.get_children(PR2, cat2);
BOOST_ASSERT(CR2set.size() == 3);
// for (auto r : cat1.find(cif::v2::key("id") == 2))
// {
// r["id"] = 20;
// break;
// }
std::vector<int> CRids;
std::transform(CR2set.begin(), CR2set.end(), std::back_inserter(CRids), [](cif::v2::row_handle r)
{ return r["id"].as<int>(); });
std::sort(CRids.begin(), CRids.end());
BOOST_CHECK(CRids == std::vector<int>({4, 5, 6}));
// BOOST_CHECK(cat1.size() == 4);
// BOOST_CHECK(cat2.size() == 13);
// check a rename in parent and child
// BOOST_CHECK(cat1.find(cif::v2::key("id") == 2).size() == 0);
// BOOST_CHECK(cat1.find(cif::v2::key("id") == 20).size() == 1);
for (auto r : cat1.find(cif::v2::key("id") == 1))
{
r["id"] = 10;
break;
}
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 2).size() == 2);
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 20).size() == 2);
BOOST_CHECK(cat1.size() == 3);
BOOST_CHECK(cat2.size() == 7);
// for (auto r : cat1.find(cif::v2::key("id") == 3))
// {
// r["id"] = 30;
// break;
// }
BOOST_CHECK(cat1.find(cif::v2::key("id") == 1).size() == 0);
BOOST_CHECK(cat1.find(cif::v2::key("id") == 10).size() == 1);
// BOOST_CHECK(cat1.size() == 4);
// BOOST_CHECK(cat2.size() == 13);
BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 1).size() == 0);
BOOST_CHECK(cat2.find(cif::v2::key("parent_id2") == 1).size() == 0);
BOOST_CHECK(cat2.find(cif::v2::key("parent_id3") == 1).size() == 0);
BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 10).size() == 1);
BOOST_CHECK(cat2.find(cif::v2::key("parent_id2") == 10).size() == 1);
BOOST_CHECK(cat2.find(cif::v2::key("parent_id3") == 10).size() == 1);
// BOOST_CHECK(cat1.find(cif::v2::key("id") == 3).size() == 0);
// BOOST_CHECK(cat1.find(cif::v2::key("id") == 30).size() == 1);
for (auto r : cat1.find(cif::v2::key("id") == 2))
{
r["id"] = 20;
break;
}
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 3).size() == 2);
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 30).size() == 1);
BOOST_CHECK(cat1.size() == 3);
BOOST_CHECK(cat2.size() == 7);
// for (auto r : cat1.find(cif::v2::key("id") == 4))
// {
// r["id"] = 40;
// break;
// }
BOOST_CHECK(cat1.find(cif::v2::key("id") == 2).size() == 0);
BOOST_CHECK(cat1.find(cif::v2::key("id") == 20).size() == 1);
// BOOST_CHECK(cat1.size() == 4);
// BOOST_CHECK(cat2.size() == 13);
BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 2).size() == 0);
BOOST_CHECK(cat2.find(cif::v2::key("parent_id2") == 2).size() == 0);
BOOST_CHECK(cat2.find(cif::v2::key("parent_id3") == 2).size() == 0);
BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 20).size() == 2);
BOOST_CHECK(cat2.find(cif::v2::key("parent_id2") == 20).size() == 2);
BOOST_CHECK(cat2.find(cif::v2::key("parent_id3") == 20).size() == 2);
// BOOST_CHECK(cat1.find(cif::v2::key("id") == 4).size() == 0);
// BOOST_CHECK(cat1.find(cif::v2::key("id") == 10).size() == 1);
for (auto r : cat1.find(cif::v2::key("id") == 3))
{
r["id"] = 30;
break;
}
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 4).size() == 3);
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 40).size() == 0);
// }
BOOST_CHECK(cat1.size() == 3);
BOOST_CHECK(cat2.size() == 7);
// // --------------------------------------------------------------------
BOOST_CHECK(cat1.find(cif::v2::key("id") == 3).size() == 0);
BOOST_CHECK(cat1.find(cif::v2::key("id") == 30).size() == 1);
// BOOST_AUTO_TEST_CASE(d5)
// {
// const char dict[] = R"(
// data_test_dict.dic
// _datablock.id test_dict.dic
// _datablock.description
// ;
// A test dictionary
// ;
// _dictionary.title test_dict.dic
// _dictionary.datablock_id test_dict.dic
// _dictionary.version 1.0
// loop_
// _item_type_list.code
// _item_type_list.primitive_code
// _item_type_list.construct
// code char
// '[][_,.;:"&<>()/\{}'`~!@#$%A-Za-z0-9*|+-]*'
// text char
// '[][ \n\t()_,.;:"&<>/\{}'`~!@#$%?+=*A-Za-z0-9|^-]*'
// int numb
// '[+-]?[0-9]+'
// save_cat_1
// _category.description 'A simple test category'
// _category.id cat_1
// _category.mandatory_code no
// _category_key.name '_cat_1.id'
// save_
// save__cat_1.id
// _item.name '_cat_1.id'
// _item.category_id cat_1
// _item.mandatory_code yes
// _item_type.code int
// save_
// save_cat_2
// _category.description 'A second simple test category'
// _category.id cat_2
// _category.mandatory_code no
// _category_key.name '_cat_2.id'
// save_
// save__cat_2.id
// _item.name '_cat_2.id'
// _item.category_id cat_2
// _item.mandatory_code yes
// _item_type.code int
// save_
// save__cat_2.parent_id
// _item.name '_cat_2.parent_id'
// _item.category_id cat_2
// _item.mandatory_code yes
// _item_type.code int
// save_
// save__cat_2.parent_id2
// _item.name '_cat_2.parent_id2'
// _item.category_id cat_2
// _item.mandatory_code no
// _item_type.code code
// save_
// save__cat_2.parent_id3
// _item.name '_cat_2.parent_id3'
// _item.category_id cat_2
// _item.mandatory_code no
// _item_type.code code
// save_
BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 3).size() == 0);
BOOST_CHECK(cat2.find(cif::v2::key("parent_id2") == 3).size() == 0);
BOOST_CHECK(cat2.find(cif::v2::key("parent_id3") == 3).size() == 0);
BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 30).size() == 1);
BOOST_CHECK(cat2.find(cif::v2::key("parent_id2") == 30).size() == 1);
BOOST_CHECK(cat2.find(cif::v2::key("parent_id3") == 30).size() == 1);
// loop_
// _pdbx_item_linked_group_list.child_category_id
// _pdbx_item_linked_group_list.link_group_id
// _pdbx_item_linked_group_list.child_name
// _pdbx_item_linked_group_list.parent_name
// _pdbx_item_linked_group_list.parent_category_id
// cat_2 1 '_cat_2.parent_id' '_cat_1.id' cat_1
// cat_2 2 '_cat_2.parent_id2' '_cat_1.id' cat_1
// cat_2 3 '_cat_2.parent_id3' '_cat_1.id' cat_1
// test delete
// loop_
// _pdbx_item_linked_group.category_id
// _pdbx_item_linked_group.link_group_id
// _pdbx_item_linked_group.label
// cat_2 1 cat_2:cat_1:1
// cat_2 2 cat_2:cat_1:2
// cat_2 3 cat_2:cat_1:3
// )";
// struct membuf : public std::streambuf
// {
// membuf(char *text, size_t length)
// {
// this->setg(text, text, text + length);
// }
// } buffer(const_cast<char *>(dict), sizeof(dict) - 1);
cat1.erase(cif::v2::key("id") == 10);
BOOST_CHECK(cat1.size() == 2);
BOOST_CHECK(cat2.size() == 4);
// std::istream is_dict(&buffer);
cat1.erase(cif::v2::key("id") == 20);
BOOST_CHECK(cat1.size() == 1);
BOOST_CHECK(cat2.size() == 1);
// cif::v2::validator validator("test", is_dict);
cat1.erase(cif::v2::key("id") == 30);
BOOST_CHECK(cat1.size() == 0);
BOOST_CHECK(cat2.size() == 0);
}
// cif::File f;
// f.setValidator(&validator);
// --------------------------------------------------------------------
// // --------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(c1)
{
cif::VERBOSE = 1;
// const char data[] = R"(
// data_test
// loop_
// _cat_1.id
// 1
// 2
// 3
auto f = R"(data_TEST
#
loop_
_test.id
_test.name
1 aap
2 noot
3 mies
4 .
5 ?
)"_cf;
// loop_
// _cat_2.id
// _cat_2.parent_id
// _cat_2.parent_id2
// _cat_2.parent_id3
// 1 1 ? ?
// 2 ? 1 ?
// 3 ? ? 1
// 4 2 2 ?
// 5 2 ? 2
// 6 ? 2 2
// 7 3 3 3
// )";
// // --------------------------------------------------------------------
// struct data_membuf : public std::streambuf
// {
// data_membuf(char *text, size_t length)
// {
// this->setg(text, text, text + length);
// }
// } data_buffer(const_cast<char *>(data), sizeof(data) - 1);
auto &db = f.front();
// std::istream is_data(&data_buffer);
// f.load(is_data);
for (auto r : db["test"].find(cif::v2::key("id") == 1))
{
const auto &[id, name] = r.get<int, std::string>({"id", "name"});
BOOST_CHECK(id == 1);
BOOST_CHECK(name == "aap");
}
// auto &cat1 = f.front()["cat_1"];
// auto &cat2 = f.front()["cat_2"];
for (auto r : db["test"].find(cif::v2::key("id") == 4))
{
const auto &[id, name] = r.get<int, std::string>({"id", "name"});
BOOST_CHECK(id == 4);
BOOST_CHECK(name.empty());
}
// // --------------------------------------------------------------------
// // check iterate children
for (auto r : db["test"].find(cif::v2::key("id") == 5))
{
const auto &[id, name] = r.get<int, std::string>({"id", "name"});
BOOST_CHECK(id == 5);
BOOST_CHECK(name.empty());
}
// auto PR2set = cat1.find(cif::v2::key("id") == 2);
// BOOST_ASSERT(PR2set.size() == 1);
// auto PR2 = PR2set.front();
// BOOST_CHECK(PR2["id"].as<int>() == 2);
// optional
// auto CR2set = cat1.getChildren(PR2, "cat_2");
// BOOST_ASSERT(CR2set.size() == 3);
for (auto r : db["test"])
{
const auto &[id, name] = r.get<int, std::optional<std::string>>({"id", "name"});
switch (id)
{
case 1: BOOST_CHECK(name == "aap"); break;
case 2: BOOST_CHECK(name == "noot"); break;
case 3: BOOST_CHECK(name == "mies"); break;
case 4:
case 5: BOOST_CHECK(not name); break;
default:
BOOST_CHECK(false);
}
}
}
// std::vector<int> CRids;
// std::transform(CR2set.begin(), CR2set.end(), std::back_inserter(CRids), [](cif::Row r)
// { return r["id"].as<int>(); });
// std::sort(CRids.begin(), CRids.end());
// BOOST_CHECK(CRids == std::vector<int>({4, 5, 6}));
BOOST_AUTO_TEST_CASE(c2)
{
cif::VERBOSE = 1;
// // check a rename in parent and child
auto f = R"(data_TEST
#
loop_
_test.id
_test.name
1 aap
2 noot
3 mies
4 .
5 ?
)"_cf;
// for (auto r : cat1.find(cif::v2::key("id") == 1))
// {
// r["id"] = 10;
// break;
// }
auto &db = f.front();
// BOOST_CHECK(cat1.size() == 3);
// BOOST_CHECK(cat2.size() == 7);
// query tests
// BOOST_CHECK(cat1.find(cif::v2::key("id") == 1).size() == 0);
// BOOST_CHECK(cat1.find(cif::v2::key("id") == 10).size() == 1);
for (const auto &[id, name] : db["test"].rows<int, std::optional<std::string>>("id", "name"))
{
switch (id)
{
case 1: BOOST_CHECK(name == "aap"); break;
case 2: BOOST_CHECK(name == "noot"); break;
case 3: BOOST_CHECK(name == "mies"); break;
case 4:
case 5: BOOST_CHECK(not name); break;
default:
BOOST_CHECK(false);
}
}
}
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 1).size() == 0);
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id2") == 1).size() == 0);
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id3") == 1).size() == 0);
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 10).size() == 1);
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id2") == 10).size() == 1);
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id3") == 10).size() == 1);
BOOST_AUTO_TEST_CASE(c3)
{
cif::VERBOSE = 1;
// for (auto r : cat1.find(cif::v2::key("id") == 2))
// {
// r["id"] = 20;
// break;
// }
auto f = R"(data_TEST
#
loop_
_test.id
_test.name
1 aap
2 noot
3 mies
4 .
5 ?
)"_cf;
// BOOST_CHECK(cat1.size() == 3);
// BOOST_CHECK(cat2.size() == 7);
auto &db = f.front();
// BOOST_CHECK(cat1.find(cif::v2::key("id") == 2).size() == 0);
// BOOST_CHECK(cat1.find(cif::v2::key("id") == 20).size() == 1);
// query tests
for (const auto &[id, name] : db["test"].find<int, std::optional<std::string>>(cif::v2::all(), "id", "name"))
{
switch (id)
{
case 1: BOOST_CHECK(name == "aap"); break;
case 2: BOOST_CHECK(name == "noot"); break;
case 3: BOOST_CHECK(name == "mies"); break;
case 4:
case 5: BOOST_CHECK(not name); break;
default:
BOOST_CHECK(false);
}
}
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 2).size() == 0);
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id2") == 2).size() == 0);
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id3") == 2).size() == 0);
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 20).size() == 2);
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id2") == 20).size() == 2);
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id3") == 20).size() == 2);
const auto &[id, name] = db["test"].find1<int, std::string>(cif::v2::key("id") == 1, "id", "name");
// for (auto r : cat1.find(cif::v2::key("id") == 3))
// {
// r["id"] = 30;
// break;
// }
BOOST_CHECK(id == 1);
BOOST_CHECK(name == "aap");
}
// BOOST_CHECK(cat1.size() == 3);
// BOOST_CHECK(cat2.size() == 7);
// --------------------------------------------------------------------
// rename test
// BOOST_CHECK(cat1.find(cif::v2::key("id") == 3).size() == 0);
// BOOST_CHECK(cat1.find(cif::v2::key("id") == 30).size() == 1);
BOOST_AUTO_TEST_CASE(r1)
{
/*
Rationale:
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 3).size() == 0);
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id2") == 3).size() == 0);
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id3") == 3).size() == 0);
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 30).size() == 1);
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id2") == 30).size() == 1);
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id3") == 30).size() == 1);
The pdbx_mmcif dictionary contains inconsistent child-parent relations. E.g. atom_site is parent
of pdbx_nonpoly_scheme which itself is a parent of pdbx_entity_nonpoly. If I want to rename a residue
I cannot update pdbx_nonpoly_scheme since changing a parent changes children, but not vice versa.
// // test delete
But if I change the comp_id in atom_site, the pdbx_nonpoly_scheme is update, that's good, and then
pdbx_entity_nonpoly is updated and that's bad.
// cat1.erase(cif::v2::key("id") == 10);
// BOOST_CHECK(cat1.size() == 2);
// BOOST_CHECK(cat2.size() == 4);
The idea is now that if we update a parent and a child that must change as well, we first check
if there are more parents of this child that will not change. In that case we have to split the
child into two, one with the new value and one with the old. We then of course have to split all
children of this split row that are direct children.
*/
// cat1.erase(cif::v2::key("id") == 20);
// BOOST_CHECK(cat1.size() == 1);
// BOOST_CHECK(cat2.size() == 1);
const char dict[] = R"(
data_test_dict.dic
_datablock.id test_dict.dic
_datablock.description
;
A test dictionary
;
_dictionary.title test_dict.dic
_dictionary.datablock_id test_dict.dic
_dictionary.version 1.0
// cat1.erase(cif::v2::key("id") == 30);
// BOOST_CHECK(cat1.size() == 0);
// BOOST_CHECK(cat2.size() == 0);
// }
loop_
_item_type_list.code
_item_type_list.primitive_code
_item_type_list.construct
code char
'[][_,.;:"&<>()/\{}'`~!@#$%A-Za-z0-9*|+-]*'
// // --------------------------------------------------------------------
text char
'[][ \n\t()_,.;:"&<>/\{}'`~!@#$%?+=*A-Za-z0-9|^-]*'
// BOOST_AUTO_TEST_CASE(c1)
// {
// cif::VERBOSE = 1;
int numb
'[+-]?[0-9]+'
// auto f = R"(data_TEST
// #
// loop_
// _test.id
// _test.name
// 1 aap
// 2 noot
// 3 mies
// 4 .
// 5 ?
// )"_cf;
// auto &db = f.front();
// for (auto r : db["test"].find(cif::v2::key("id") == 1))
// {
// const auto &[id, name] = r.get<int, std::string>({"id", "name"});
// BOOST_CHECK(id == 1);
// BOOST_CHECK(name == "aap");
// }
save_cat_1
_category.description 'A simple test category'
_category.id cat_1
_category.mandatory_code no
_category_key.name '_cat_1.id'
save_
// for (auto r : db["test"].find(cif::v2::key("id") == 4))
// {
// const auto &[id, name] = r.get<int, std::string>({"id", "name"});
// BOOST_CHECK(id == 4);
// BOOST_CHECK(name.empty());
// }
save__cat_1.id
_item.name '_cat_1.id'
_item.category_id cat_1
_item.mandatory_code yes
_item_linked.child_name '_cat_2.parent_id'
_item_linked.parent_name '_cat_1.id'
_item_type.code int
save_
// for (auto r : db["test"].find(cif::v2::key("id") == 5))
// {
// const auto &[id, name] = r.get<int, std::string>({"id", "name"});
// BOOST_CHECK(id == 5);
// BOOST_CHECK(name.empty());
// }
save__cat_1.name
_item.name '_cat_1.name'
_item.category_id cat_1
_item.mandatory_code yes
_item_type.code code
save_
// // optional
save__cat_1.desc
_item.name '_cat_1.desc'
_item.category_id cat_1
_item.mandatory_code yes
_item_type.code text
save_
// for (auto r : db["test"])
// {
// const auto &[id, name] = r.get<int, std::optional<std::string>>({"id", "name"});
// switch (id)
// {
// case 1: BOOST_CHECK(name == "aap"); break;
// case 2: BOOST_CHECK(name == "noot"); break;
// case 3: BOOST_CHECK(name == "mies"); break;
// case 4:
// case 5: BOOST_CHECK(not name); break;
// default:
// BOOST_CHECK(false);
// }
// }
// }
save_cat_2
_category.description 'A second simple test category'
_category.id cat_2
_category.mandatory_code no
_category_key.name '_cat_2.id'
save_
// BOOST_AUTO_TEST_CASE(c2)
// {
// cif::VERBOSE = 1;
save__cat_2.id
_item.name '_cat_2.id'
_item.category_id cat_2
_item.mandatory_code yes
_item_type.code int
save_
// auto f = R"(data_TEST
// #
// loop_
// _test.id
// _test.name
// 1 aap
// 2 noot
// 3 mies
// 4 .
// 5 ?
// )"_cf;
save__cat_2.name
_item.name '_cat_2.name'
_item.category_id cat_2
_item.mandatory_code yes
_item_type.code code
save_
// auto &db = f.front();
save__cat_2.num
_item.name '_cat_2.num'
_item.category_id cat_2
_item.mandatory_code yes
_item_type.code int
save_
// // query tests
save__cat_2.desc
_item.name '_cat_2.desc'
_item.category_id cat_2
_item.mandatory_code yes
_item_type.code text
save_
// for (const auto &[id, name] : db["test"].rows<int, std::optional<std::string>>("id", "name"))
// {
// switch (id)
// {
// case 1: BOOST_CHECK(name == "aap"); break;
// case 2: BOOST_CHECK(name == "noot"); break;
// case 3: BOOST_CHECK(name == "mies"); break;
// case 4:
// case 5: BOOST_CHECK(not name); break;
// default:
// BOOST_CHECK(false);
// }
// }
// }
save_cat_3
_category.description 'A third simple test category'
_category.id cat_3
_category.mandatory_code no
_category_key.name '_cat_3.id'
save_
// BOOST_AUTO_TEST_CASE(c3)
// {
// cif::VERBOSE = 1;
save__cat_3.id
_item.name '_cat_3.id'
_item.category_id cat_3
_item.mandatory_code yes
_item_type.code int
save_
// auto f = R"(data_TEST
// #
// loop_
// _test.id
// _test.name
// 1 aap
// 2 noot
// 3 mies
// 4 .
// 5 ?
// )"_cf;
// auto &db = f.front();
// // query tests
// for (const auto &[id, name] : db["test"].find<int, std::optional<std::string>>(cif::All(), "id", "name"))
// {
// switch (id)
// {
// case 1: BOOST_CHECK(name == "aap"); break;
// case 2: BOOST_CHECK(name == "noot"); break;
// case 3: BOOST_CHECK(name == "mies"); break;
// case 4:
// case 5: BOOST_CHECK(not name); break;
// default:
// BOOST_CHECK(false);
// }
// }
save__cat_3.name
_item.name '_cat_3.name'
_item.category_id cat_3
_item.mandatory_code yes
_item_type.code code
save_
// const auto &[id, name] = db["test"].find1<int, std::string>(cif::v2::key("id") == 1, "id", "name");
save__cat_3.num
_item.name '_cat_3.num'
_item.category_id cat_3
_item.mandatory_code yes
_item_type.code int
save_
// BOOST_CHECK(id == 1);
// BOOST_CHECK(name == "aap");
// }
loop_
_pdbx_item_linked_group_list.child_category_id
_pdbx_item_linked_group_list.link_group_id
_pdbx_item_linked_group_list.child_name
_pdbx_item_linked_group_list.parent_name
_pdbx_item_linked_group_list.parent_category_id
cat_1 1 '_cat_1.name' '_cat_2.name' cat_2
cat_2 1 '_cat_2.name' '_cat_3.name' cat_3
cat_2 1 '_cat_2.num' '_cat_3.num' cat_3
// // --------------------------------------------------------------------
// // rename test
)";
// BOOST_AUTO_TEST_CASE(r1)
// {
// /*
// Rationale:
// The pdbx_mmcif dictionary contains inconsistent child-parent relations. E.g. atom_site is parent
// of pdbx_nonpoly_scheme which itself is a parent of pdbx_entity_nonpoly. If I want to rename a residue
// I cannot update pdbx_nonpoly_scheme since changing a parent changes children, but not vice versa.
// But if I change the comp_id in atom_site, the pdbx_nonpoly_scheme is update, that's good, and then
// pdbx_entity_nonpoly is updated and that's bad.
// The idea is now that if we update a parent and a child that must change as well, we first check
// if there are more parents of this child that will not change. In that case we have to split the
// child into two, one with the new value and one with the old. We then of course have to split all
// children of this split row that are direct children.
// */
// const char dict[] = R"(
// data_test_dict.dic
// _datablock.id test_dict.dic
// _datablock.description
// ;
// A test dictionary
// ;
// _dictionary.title test_dict.dic
// _dictionary.datablock_id test_dict.dic
// _dictionary.version 1.0
// loop_
// _item_type_list.code
// _item_type_list.primitive_code
// _item_type_list.construct
// code char
// '[][_,.;:"&<>()/\{}'`~!@#$%A-Za-z0-9*|+-]*'
// text char
// '[][ \n\t()_,.;:"&<>/\{}'`~!@#$%?+=*A-Za-z0-9|^-]*'
// int numb
// '[+-]?[0-9]+'
// save_cat_1
// _category.description 'A simple test category'
// _category.id cat_1
// _category.mandatory_code no
// _category_key.name '_cat_1.id'
// save_
// save__cat_1.id
// _item.name '_cat_1.id'
// _item.category_id cat_1
// _item.mandatory_code yes
// _item_linked.child_name '_cat_2.parent_id'
// _item_linked.parent_name '_cat_1.id'
// _item_type.code int
// save_
// save__cat_1.name
// _item.name '_cat_1.name'
// _item.category_id cat_1
// _item.mandatory_code yes
// _item_type.code code
// save_
// save__cat_1.desc
// _item.name '_cat_1.desc'
// _item.category_id cat_1
// _item.mandatory_code yes
// _item_type.code text
// save_
// save_cat_2
// _category.description 'A second simple test category'
// _category.id cat_2
// _category.mandatory_code no
// _category_key.name '_cat_2.id'
// save_
// save__cat_2.id
// _item.name '_cat_2.id'
// _item.category_id cat_2
// _item.mandatory_code yes
// _item_type.code int
// save_
// save__cat_2.name
// _item.name '_cat_2.name'
// _item.category_id cat_2
// _item.mandatory_code yes
// _item_type.code code
// save_
// save__cat_2.num
// _item.name '_cat_2.num'
// _item.category_id cat_2
// _item.mandatory_code yes
// _item_type.code int
// save_
// save__cat_2.desc
// _item.name '_cat_2.desc'
// _item.category_id cat_2
// _item.mandatory_code yes
// _item_type.code text
// save_
// save_cat_3
// _category.description 'A third simple test category'
// _category.id cat_3
// _category.mandatory_code no
// _category_key.name '_cat_3.id'
// save_
// save__cat_3.id
// _item.name '_cat_3.id'
// _item.category_id cat_3
// _item.mandatory_code yes
// _item_type.code int
// save_
// save__cat_3.name
// _item.name '_cat_3.name'
// _item.category_id cat_3
// _item.mandatory_code yes
// _item_type.code code
// save_
// save__cat_3.num
// _item.name '_cat_3.num'
// _item.category_id cat_3
// _item.mandatory_code yes
// _item_type.code int
// save_
struct membuf : public std::streambuf
{
membuf(char *text, size_t length)
{
this->setg(text, text, text + length);
}
} buffer(const_cast<char *>(dict), sizeof(dict) - 1);
// loop_
// _pdbx_item_linked_group_list.child_category_id
// _pdbx_item_linked_group_list.link_group_id
// _pdbx_item_linked_group_list.child_name
// _pdbx_item_linked_group_list.parent_name
// _pdbx_item_linked_group_list.parent_category_id
// cat_1 1 '_cat_1.name' '_cat_2.name' cat_2
// cat_2 1 '_cat_2.name' '_cat_3.name' cat_3
// cat_2 1 '_cat_2.num' '_cat_3.num' cat_3
// )";
// struct membuf : public std::streambuf
// {
// membuf(char *text, size_t length)
// {
// this->setg(text, text, text + length);
// }
// } buffer(const_cast<char *>(dict), sizeof(dict) - 1);
std::istream is_dict(&buffer);
// std::istream is_dict(&buffer);
// cif::v2::validator validator("test", is_dict);
auto validator = cif::v2::parse_dictionary("test", is_dict);
// cif::File f;
// f.setValidator(&validator);
cif::v2::file f;
f.set_validator(&validator);
// // --------------------------------------------------------------------
// --------------------------------------------------------------------
// const char data[] = R"(
// data_test
// loop_
// _cat_1.id
// _cat_1.name
// _cat_1.desc
// 1 aap Aap
// 2 noot Noot
// 3 mies Mies
const char data[] = R"(
data_test
loop_
_cat_1.id
_cat_1.name
_cat_1.desc
1 aap Aap
2 noot Noot
3 mies Mies
// loop_
// _cat_2.id
// _cat_2.name
// _cat_2.num
// _cat_2.desc
// 1 aap 1 'Een dier'
// 2 aap 2 'Een andere aap'
// 3 noot 1 'walnoot bijvoorbeeld'
loop_
_cat_2.id
_cat_2.name
_cat_2.num
_cat_2.desc
1 aap 1 'Een dier'
2 aap 2 'Een andere aap'
3 noot 1 'walnoot bijvoorbeeld'
// loop_
// _cat_3.id
// _cat_3.name
// _cat_3.num
// 1 aap 1
// 2 aap 2
// )";
loop_
_cat_3.id
_cat_3.name
_cat_3.num
1 aap 1
2 aap 2
)";
// using namespace cif::literals;
using namespace cif::v2::literals;
// struct data_membuf : public std::streambuf
// {
// data_membuf(char *text, size_t length)
// {
// this->setg(text, text, text + length);
// }
// } data_buffer(const_cast<char *>(data), sizeof(data) - 1);
struct data_membuf : public std::streambuf
{
data_membuf(char *text, size_t length)
{
this->setg(text, text, text + length);
}
} data_buffer(const_cast<char *>(data), sizeof(data) - 1);
// std::istream is_data(&data_buffer);
// f.load(is_data);
std::istream is_data(&data_buffer);
f.load(is_data);
// auto &cat1 = f.front()["cat_1"];
// auto &cat2 = f.front()["cat_2"];
// auto &cat3 = f.front()["cat_3"];
auto &cat1 = f.front()["cat_1"];
auto &cat2 = f.front()["cat_2"];
auto &cat3 = f.front()["cat_3"];
// cat3.update_value("name"_key == "aap" and "num"_key == 1, "name", "aapje");
cat3.update_value("name"_key == "aap" and "num"_key == 1, "name", "aapje");
// BOOST_CHECK(cat3.size() == 2);
BOOST_CHECK(cat3.size() == 2);
// {
// int id, num;
// std::string name;
// cif::tie(id, name, num) = cat3.front().get("id", "name", "num");
// BOOST_CHECK(id == 1);
// BOOST_CHECK(num == 1);
// BOOST_CHECK(name == "aapje");
// cif::tie(id, name, num) = cat3.back().get("id", "name", "num");
// BOOST_CHECK(id == 2);
// BOOST_CHECK(num == 2);
// BOOST_CHECK(name == "aap");
// }
{
int id, num;
std::string name;
cif::v2::tie(id, name, num) = cat3.front().get("id", "name", "num");
BOOST_CHECK(id == 1);
BOOST_CHECK(num == 1);
BOOST_CHECK(name == "aapje");
cif::v2::tie(id, name, num) = cat3.back().get("id", "name", "num");
BOOST_CHECK(id == 2);
BOOST_CHECK(num == 2);
BOOST_CHECK(name == "aap");
}
// int i = 0;
// for (const auto &[id, name, num, desc] : cat2.rows<int, std::string, int, std::string>("id", "name", "num", "desc"))
// {
// switch (++i)
// {
// case 1:
// BOOST_CHECK(id == 1);
// BOOST_CHECK(num == 1);
// BOOST_CHECK(name == "aapje");
// BOOST_CHECK(desc == "Een dier");
// break;
// case 2:
// BOOST_CHECK(id == 2);
// BOOST_CHECK(num == 2);
// BOOST_CHECK(name == "aap");
// BOOST_CHECK(desc == "Een andere aap");
// break;
// case 3:
// BOOST_CHECK(id == 3);
// BOOST_CHECK(num == 1);
// BOOST_CHECK(name == "noot");
// BOOST_CHECK(desc == "walnoot bijvoorbeeld");
// break;
// default:
// BOOST_FAIL("Unexpected record");
// }
// }
int i = 0;
for (const auto &[id, name, num, desc] : cat2.rows<int, std::string, int, std::string>("id", "name", "num", "desc"))
{
switch (++i)
{
case 1:
BOOST_CHECK(id == 1);
BOOST_CHECK(num == 1);
BOOST_CHECK(name == "aapje");
BOOST_CHECK(desc == "Een dier");
break;
case 2:
BOOST_CHECK(id == 2);
BOOST_CHECK(num == 2);
BOOST_CHECK(name == "aap");
BOOST_CHECK(desc == "Een andere aap");
break;
case 3:
BOOST_CHECK(id == 3);
BOOST_CHECK(num == 1);
BOOST_CHECK(name == "noot");
BOOST_CHECK(desc == "walnoot bijvoorbeeld");
break;
default:
BOOST_FAIL("Unexpected record");
}
}
// BOOST_CHECK(cat1.size() == 4);
// i = 0;
// for (const auto &[id, name, desc] : cat1.rows<int, std::string, std::string>("id", "name", "desc"))
// {
// switch (++i)
// {
// case 1:
// BOOST_CHECK(id == 1);
// BOOST_CHECK(name == "aapje");
// BOOST_CHECK(desc == "Aap");
// break;
// case 2:
// BOOST_CHECK(id == 2);
// BOOST_CHECK(name == "noot");
// BOOST_CHECK(desc == "Noot");
// break;
// case 3:
// BOOST_CHECK(id == 3);
// BOOST_CHECK(name == "mies");
// BOOST_CHECK(desc == "Mies");
// break;
// case 4:
// BOOST_CHECK(id == 4);
// BOOST_CHECK(name == "aap");
// BOOST_CHECK(desc == "Aap");
// break;
// default:
// BOOST_FAIL("Unexpected record");
// }
// }
BOOST_CHECK(cat1.size() == 4);
i = 0;
for (const auto &[id, name, desc] : cat1.rows<int, std::string, std::string>("id", "name", "desc"))
{
switch (++i)
{
case 1:
BOOST_CHECK(id == 1);
BOOST_CHECK(name == "aapje");
BOOST_CHECK(desc == "Aap");
break;
case 2:
BOOST_CHECK(id == 2);
BOOST_CHECK(name == "noot");
BOOST_CHECK(desc == "Noot");
break;
case 3:
BOOST_CHECK(id == 3);
BOOST_CHECK(name == "mies");
BOOST_CHECK(desc == "Mies");
break;
case 4:
BOOST_CHECK(id == 4);
BOOST_CHECK(name == "aap");
BOOST_CHECK(desc == "Aap");
break;
default:
BOOST_FAIL("Unexpected record");
}
}
// f.save(std::cout);
// }
// f.save(std::cout);
}
// // --------------------------------------------------------------------
// --------------------------------------------------------------------
// BOOST_AUTO_TEST_CASE(bondmap_1)
// {
......@@ -1929,195 +1930,101 @@ _cat_2.desc
// BOOST_CHECK(mmcif::BondMap::atomIDsForCompound("UN_").empty() == false);
// }
// BOOST_AUTO_TEST_CASE(reading_file_1)
// {
// std::istringstream is("Hello, world!");
// cif::File file;
// BOOST_CHECK_THROW(file.load(is), std::runtime_error);
// }
// // 3d tests
// using namespace mmcif;
// BOOST_AUTO_TEST_CASE(t1)
// {
// // std::random_device rnd;
// // std::mt19937 gen(rnd());
// // std::uniform_real_distribution<float> dis(0, 1);
// // Quaternion q{ dis(gen), dis(gen), dis(gen), dis(gen) };
// // q = Normalize(q);
// // Quaternion q{ 0.1, 0.2, 0.3, 0.4 };
// Quaternion q{0.5, 0.5, 0.5, 0.5};
// q = Normalize(q);
// const auto &&[angle0, axis0] = QuaternionToAngleAxis(q);
// std::vector<Point> p1{
// {16.979, 13.301, 44.555},
// {18.150, 13.525, 43.680},
// {18.656, 14.966, 43.784},
// {17.890, 15.889, 44.078},
// {17.678, 13.270, 42.255},
// {16.248, 13.734, 42.347},
// {15.762, 13.216, 43.724}};
// auto p2 = p1;
// CenterPoints(p1);
// for (auto &p : p2)
// p.rotate(q);
// CenterPoints(p2);
// auto q2 = AlignPoints(p1, p2);
// const auto &&[angle, axis] = QuaternionToAngleAxis(q2);
// BOOST_TEST(std::fmod(360 + angle, 360) == std::fmod(360 - angle0, 360), tt::tolerance(0.01));
// for (auto &p : p1)
// p.rotate(q2);
// float rmsd = RMSd(p1, p2);
// BOOST_TEST(rmsd < 1e-5);
// // std::cout << "rmsd: " << RMSd(p1, p2) << std::endl;
// }
// BOOST_AUTO_TEST_CASE(t2)
// {
// Point p[] = {
// { 1, 1, 0 },
// { 2, 1, 0 },
// { 1, 2, 0 }
// };
// Point xp = mmcif::CrossProduct(p[1] - p[0], p[2] - p[0]);
// Quaternion q = ConstructFromAngleAxis(45, xp); //mmcif::Normalize(Quaternion{45 * mmcif::kPI / 180, xp.mX, xp.mY, xp.mZ});
// auto &&[angle, axis] = mmcif::QuaternionToAngleAxis(q);
// BOOST_TEST(angle == 45, tt::tolerance(0.01));
// }
// BOOST_AUTO_TEST_CASE(t3)
// {
// Point p[] = {
// { 1, 1, 0 },
// { 2, 1, 0 },
// { 1, 2, 0 }
// };
// Point xp = mmcif::CrossProduct(p[1] - p[0], p[2] - p[0]);
// Quaternion q = ConstructFromAngleAxis(45, xp); //mmcif::Normalize(Quaternion{45 * mmcif::kPI / 180, xp.mX, xp.mY, xp.mZ});
// Point v = p[1];
// v -= p[0];
// v.rotate(q);
// v += p[0];
// std::cout << v << std::endl;
// double a = mmcif::Angle(v, p[0], p[1]);
// BOOST_TEST(a == 45, tt::tolerance(0.01));
// }
// BOOST_AUTO_TEST_CASE(parser_test_1)
// {
// auto data1 = R"(
// data_QM
// _test.text ??
// )"_cf;
BOOST_AUTO_TEST_CASE(reading_file_1)
{
std::istringstream is("Hello, world!");
// auto &db1 = data1.front();
// auto &test1 = db1["test"];
cif::v2::file file;
BOOST_CHECK_THROW(file.load(is), std::runtime_error);
}
// BOOST_CHECK_EQUAL(test1.size(), 1);
BOOST_AUTO_TEST_CASE(parser_test_1)
{
auto data1 = R"(
data_QM
_test.text ??
)"_cf;
// for (auto r : test1)
// {
// const auto &[text] = r.get<std::string>({"text"});
// BOOST_CHECK_EQUAL(text, "??");
// }
auto &db1 = data1.front();
auto &test1 = db1["test"];
// std::stringstream ss;
// data1.save(ss);
BOOST_CHECK_EQUAL(test1.size(), 1);
// auto data2 = cif::File(ss);
for (auto r : test1)
{
const auto &[text] = r.get<std::string>({"text"});
BOOST_CHECK_EQUAL(text, "??");
}
// auto &db2 = data2.front();
// auto &test2 = db2["test"];
std::stringstream ss;
data1.save(ss);
// BOOST_CHECK_EQUAL(test2.size(), 1);
auto data2 = cif::File(ss);
// for (auto r : test2)
// {
// const auto &[text] = r.get<std::string>({"text"});
// BOOST_CHECK_EQUAL(text, "??");
// }
// }
auto &db2 = data2.front();
auto &test2 = db2["test"];
// BOOST_AUTO_TEST_CASE(output_test_1)
// {
// auto data1 = R"(
// data_Q
// loop_
// _test.text
// "stop_the_crap"
// 'and stop_ this too'
// 'data_dinges'
// 'blablaglobal_bla'
// boo.data_.whatever
// )"_cf;
BOOST_CHECK_EQUAL(test2.size(), 1);
// auto &db1 = data1.front();
// auto &test1 = db1["test"];
for (auto r : test2)
{
const auto &[text] = r.get<std::string>({"text"});
BOOST_CHECK_EQUAL(text, "??");
}
}
// struct T {
// const char *s;
// bool q;
// } kS[] = {
// { "stop_the_crap", false },
// { "and stop_ this too", false },
// { "data_dinges", false },
// { "blablaglobal_bla", false },
// { "boo.data_.whatever", true }
// };
BOOST_AUTO_TEST_CASE(output_test_1)
{
auto data1 = R"(
data_Q
loop_
_test.text
"stop_the_crap"
'and stop_ this too'
'data_dinges'
'blablaglobal_bla'
boo.data_.whatever
)"_cf;
auto &db1 = data1.front();
auto &test1 = db1["test"];
struct T {
const char *s;
bool q;
} kS[] = {
{ "stop_the_crap", false },
{ "and stop_ this too", false },
{ "data_dinges", false },
{ "blablaglobal_bla", false },
{ "boo.data_.whatever", true }
};
// BOOST_CHECK_EQUAL(test1.size(), sizeof(kS) / sizeof(T));
BOOST_CHECK_EQUAL(test1.size(), sizeof(kS) / sizeof(T));
// size_t i = 0;
// for (auto r : test1)
// {
// const auto &[text] = r.get<std::string>({"text"});
// BOOST_CHECK_EQUAL(text, kS[i].s);
// BOOST_CHECK_EQUAL(cif::isUnquotedString(kS[i].s), kS[i].q);
// ++i;
// }
size_t i = 0;
for (auto r : test1)
{
const auto &[text] = r.get<std::string>({"text"});
BOOST_CHECK_EQUAL(text, kS[i].s);
BOOST_CHECK_EQUAL(cif::isUnquotedString(kS[i].s), kS[i].q);
++i;
}
// std::stringstream ss;
// data1.save(ss);
std::stringstream ss;
data1.save(ss);
// auto data2 = cif::File(ss);
auto data2 = cif::File(ss);
// auto &db2 = data2.front();
// auto &test2 = db2["test"];
auto &db2 = data2.front();
auto &test2 = db2["test"];
// BOOST_CHECK_EQUAL(test2.size(), sizeof(kS) / sizeof(T));
BOOST_CHECK_EQUAL(test2.size(), sizeof(kS) / sizeof(T));
// i = 0;
// for (auto r : test2)
// {
// const auto &[text] = r.get<std::string>({"text"});
// BOOST_CHECK_EQUAL(text, kS[i++].s);
// }
// }
i = 0;
for (auto r : test2)
{
const auto &[text] = r.get<std::string>({"text"});
BOOST_CHECK_EQUAL(text, kS[i++].s);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment