Commit 24fa80ba by Maarten L. Hekkelman

parser just started working again, a bit

parent 3999d792
......@@ -432,22 +432,190 @@ class category_t
if (result == m_columns.size())
{
const ValidateItem *itemValidator = nullptr;
const ValidateItem *item_validator = nullptr;
// if (mCatValidator != nullptr)
// {
// itemValidator = mCatValidator->getValidatorForItem(column_name);
// if (itemValidator == nullptr)
// mValidator->reportError("tag " + std::string(column_name) + " not allowed in Category " + mName, false);
// item_validator = mCatValidator->getValidatorForItem(column_name);
// if (item_validator == nullptr)
// m_validator->reportError("tag " + std::string(column_name) + " not allowed in Category " + mName, false);
// }
m_columns.emplace_back(column_name, itemValidator);
m_columns.emplace_back(column_name, item_validator);
}
return result;
}
private:
void update_value(row *row, size_t column, std::string_view value, bool updateLinked, bool validate = true)
{
auto &col = m_columns[column];
const char *oldValue = nullptr;
for (auto iv = row->m_head; iv != nullptr; iv = iv->m_next)
{
assert(iv != iv->m_next and (iv->m_next == nullptr or iv != iv->m_next->m_next));
if (iv->m_column_ix == column)
{
oldValue = iv->c_str();
break;
}
}
if (oldValue != nullptr and value == oldValue) // no need to update
return;
std::string oldStrValue = oldValue ? oldValue : "";
// // check the value
// if (col.m_validator and validate)
// (*col.m_validator)(value);
// 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->mIndex != nullptr and cat->keyFieldsByIndex().count(column))
// {
// reinsert = cat->mIndex->find(mData);
// if (reinsert)
// cat->mIndex->erase(mData);
// }
// first remove old value with cix
if (row->m_head == nullptr)
; // nothing to do
else if (row->m_head->m_column_ix == column)
{
auto iv = row->m_head;
row->m_head = iv->m_next;
iv->m_next = nullptr;
delete_item(iv);
}
else
{
for (auto iv = row->m_head; iv->m_next != nullptr; iv = iv->m_next)
{
if (iv->m_next->m_column_ix != column)
continue;
auto nv = iv->m_next;
iv->m_next = nv->m_next;
nv->m_next = nullptr;
delete_item(nv);
break;
}
}
if (not value.empty())
{
auto nv = create_item(column, value);
if (row->m_head == nullptr)
row->m_head = nv;
else
{
auto iv = row->m_head;
while (iv->m_next != nullptr)
iv = iv->m_next;
iv->m_next = nv;
}
}
// if (reinsert)
// cat->mIndex->insert(mData);
// // see if we need to update any child categories that depend on this value
// auto iv = col.m_validator;
// if (not skipUpdateLinked and iv != nullptr and mCascade)
// {
// for (auto &&[childCat, linked] : cat->mChildLinks)
// {
// if (find(linked->mParentKeys.begin(), linked->mParentKeys.end(), iv->mTag) == linked->mParentKeys.end())
// continue;
// Condition cond;
// std::string childTag;
// for (size_t ix = 0; ix < linked->mParentKeys.size(); ++ix)
// {
// std::string pk = linked->mParentKeys[ix];
// std::string ck = linked->mChildKeys[ix];
// // TODO add code to *NOT* test mandatory fields for Empty
// if (pk == iv->mTag)
// {
// childTag = ck;
// cond = std::move(cond) && Key(ck) == oldStrValue;
// }
// else
// {
// const char *pk_value = (*this)[pk].c_str();
// if (*pk_value == 0)
// cond = std::move(cond) && Key(ck) == Empty();
// else
// cond = std::move(cond) && ((Key(ck) == pk_value) or Key(ck) == Empty());
// }
// }
// auto rows = childCat->find(std::move(cond));
// if (rows.empty())
// continue;
// // if (cif::VERBOSE > 2)
// // {
// // std::cerr << "Parent: " << linked->mParentCategory << " Child: " << linked->mChildCategory << std::endl
// // << cond << std::endl;
// // }
// // Now, suppose there are already rows in child that conform to the new value,
// // we then skip this renam
// Condition cond_n;
// for (size_t ix = 0; ix < linked->mParentKeys.size(); ++ix)
// {
// std::string pk = linked->mParentKeys[ix];
// std::string ck = linked->mChildKeys[ix];
// // TODO add code to *NOT* test mandatory fields for Empty
// if (pk == iv->mTag)
// cond_n = std::move(cond_n) && Key(ck) == value;
// else
// {
// const char *pk_value = (*this)[pk].c_str();
// if (*pk_value == 0)
// cond_n = std::move(cond_n) && Key(ck) == Empty();
// else
// cond_n = std::move(cond_n) && ((Key(ck) == pk_value) or Key(ck) == Empty());
// }
// }
// auto rows_n = childCat->find(std::move(cond_n));
// if (not rows_n.empty())
// {
// if (cif::VERBOSE > 0)
// std::cerr << "Will not rename in child category since there are already rows that link to the parent" << std::endl;
// continue;
// }
// for (auto &cr : rows)
// cr.assign(childTag, value, false);
// }
// }
}
private:
using char_allocator_type = typename std::allocator_traits<Alloc>::template rebind_alloc<char>;
using char_allocator_traits = std::allocator_traits<char_allocator_type>;
......
......@@ -34,17 +34,22 @@ namespace cif::v2
// --------------------------------------------------------------------
template <
typename Category = category,
typename Alloc = std::allocator<Category>>
class datablock_t : public std::list<Category, Alloc>
typename Alloc = std::allocator<void>,
typename Category = category_t<Alloc>>
class datablock_t
{
public:
using category_type = Category;
using base_type = std::list<category_type, Alloc>;
using allocator_type = Alloc;
datablock_t(const std::string &name, const allocator_type &alloc = allocator_type())
: base_type(alloc)
using category_allocator_type = typename std::allocator_traits<Alloc>::template rebind_alloc<category_type>;
using category_type_list = std::list<category_type, category_allocator_type>;
using iterator = category_type_list::iterator;
using const_iterator = category_type_list::const_iterator;
datablock_t(std::string_view name, const allocator_type &alloc = allocator_type())
: m_categories(alloc)
, m_name(name)
{
}
......@@ -53,19 +58,19 @@ class datablock_t : public std::list<Category, Alloc>
datablock_t(datablock_t &&) = default;
template <typename Alloc2>
datablock_t(const datablock_t &db, const Alloc2 &a)
: base_type(db, a)
, m_name(db.m_name)
{
}
// template <typename Alloc2>
// datablock_t(const datablock_t &db, const Alloc2 &a)
// : m_categories(db, a)
// , m_name(db.m_name)
// {
// }
template <typename Alloc2>
datablock_t(datablock_t &&db, const Alloc2 &a)
: base_type(std::move(db), a)
, m_name(db.m_name)
{
}
// template <typename Alloc2>
// datablock_t(datablock_t &&db, const Alloc2 &a)
// : base_type(std::move(db), a)
// , m_name(db.m_name)
// {
// }
datablock_t &operator=(const datablock_t &) = default;
datablock_t &operator=(datablock_t &&) = default;
......@@ -78,19 +83,57 @@ class datablock_t : public std::list<Category, Alloc>
category_type &operator[](std::string_view name)
{
auto i = std::find_if(this->begin(), this->end(), [name](const category_type &c)
auto i = std::find_if(m_categories.begin(), m_categories.end(), [name](const category_type &c)
{ return iequals(c.name(), name); });
if (i == this->end())
i = this->emplace(name);
return *i;
if (i != m_categories.end())
return *i;
m_categories.emplace_back(name);
return m_categories.back();
}
const category_type &operator[](std::string_view name) const
{
static const category_type s_empty;
auto i = std::find_if(this->begin(), this->end(), [name](const category_type &c)
auto i = std::find_if(m_categories.begin(), m_categories.end(), [name](const category_type &c)
{ return iequals(c.name(), name); });
return i == this->end() ? s_empty : *i;
return i == m_categories.end() ? s_empty : *i;
}
std::tuple<iterator, bool> emplace(std::string_view name)
{
bool is_new = true;
auto i = m_categories.begin();
while (i != m_categories.end())
{
if (iequals(name, i->name()))
{
is_new = false;
if (i != m_categories.begin())
{
auto n = std::next(i);
m_categories.splice(m_categories.begin(), m_categories, i, n);
}
break;
}
++i;
}
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();
}
return std::make_tuple(m_categories.begin(), is_new);
}
void write(std::ostream &os) const
......@@ -104,7 +147,7 @@ class datablock_t : public std::list<Category, Alloc>
// and if it exists, _AND_ we have a Validator, write out the
// audit_conform record.
for (auto &cat : *this)
for (auto &cat : m_categories)
{
if (cat.name() != "entry")
continue;
......@@ -122,7 +165,7 @@ class datablock_t : public std::list<Category, Alloc>
break;
}
for (auto &cat : *this)
for (auto &cat : m_categories)
{
if (cat.name() != "entry" and cat.name() != "audit_conform")
cat.write(os);
......@@ -136,6 +179,7 @@ class datablock_t : public std::list<Category, Alloc>
}
private:
category_type_list m_categories;
std::string m_name;
};
......
......@@ -27,6 +27,7 @@
#pragma once
#include "datablock.hpp"
#include "parser.hpp"
namespace cif::v2
{
......@@ -34,25 +35,121 @@ namespace cif::v2
// --------------------------------------------------------------------
template <
typename Datablock = datablock,
typename Alloc = std::allocator<Datablock>>
class file_t : public std::list<Datablock, Alloc>
typename Alloc = std::allocator<void>,
typename Datablock = datablock_t<Alloc>,
typename Category = typename Datablock::category_type>
class file_t
{
public:
using value_type = Datablock;
using base_type = std::list<value_type, Alloc>;
using allocator_type = Alloc;
using datablock_type = Datablock;
using category_type = typename datablock_type::category_type;
using datablock_allocator_type = typename std::allocator_traits<Alloc>::template rebind_alloc<datablock_type>;
using datablock_list = std::list<datablock_type, datablock_allocator_type>;
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;
using parser_type = parser_t<file_t, datablock_type, category_type>;
file_t() = default;
file_t(const allocator_type &a = allocator_type())
: m_datablocks(a)
{
}
file_t(std::istream &is, const allocator_type &alloc = allocator_type())
: m_datablocks(alloc)
{
load(is);
}
file_t(const file_t &) = default;
file_t(file_t &&) = default;
file_t &operator=(const file_t &) = default;
file_t &operator=(file_t &&) = default;
datablock_type &operator[](std::string_view name)
{
auto i = std::find_if(m_datablocks.begin(), m_datablocks.end(), [name](const datablock_type &c)
{ return iequals(c.name(), name); });
if (i != m_datablocks.end())
return *i;
m_datablocks.emplace_back(name);
return m_datablocks.back();
}
const datablock_type &operator[](std::string_view name) const
{
static const datablock_type s_empty;
auto i = std::find_if(m_datablocks.begin(), m_datablocks.end(), [name](const datablock_type &c)
{ return iequals(c.name(), name); });
return i == m_datablocks.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())
{
if (iequals(name, i->name()))
{
is_new = false;
if (i != m_datablocks.begin())
{
auto n = std::next(i);
m_datablocks.splice(m_datablocks.begin(), m_datablocks, i, n);
}
break;
}
++i;
}
if (is_new)
m_datablocks.emplace(m_datablocks.begin(), name);
return std::make_tuple(m_datablocks.begin(), is_new);
}
bool empty() const { return m_datablocks.empty(); }
size_t size() const { return m_datablocks.size(); }
reference front() { return m_datablocks.front(); }
reference back() { return m_datablocks.back(); }
void load(std::istream &is)
{
// auto saved = mValidator;
// setValidator(nullptr);
parser_type p(is, *this);
p.parseFile();
// if (saved != nullptr)
// {
// setValidator(saved);
// (void)isValid();
// }
}
private:
datablock_list m_datablocks;
};
using file = file_t<>;
......
......@@ -66,7 +66,7 @@ class item
auto r = cif::to_chars(m_buffer, m_buffer + sizeof(m_buffer) - 1, value, cif::chars_format::fixed, precision);
if (r.ec != std::errc())
throw std::runtime_error("Could not format number");
assert(r.ptr >= m_buffer and r.ptr < m_buffer + sizeof(m_buffer));
*r.ptr = 0;
m_value = std::string_view(m_buffer, r.ptr - m_buffer);
......@@ -94,7 +94,7 @@ class item
auto r = std::to_chars(m_buffer, m_buffer + sizeof(m_buffer) - 1, value);
if (r.ec != std::errc())
throw std::runtime_error("Could not format number");
assert(r.ptr >= m_buffer and r.ptr < m_buffer + sizeof(m_buffer));
*r.ptr = 0;
m_value = std::string_view(m_buffer, r.ptr - m_buffer);
......@@ -134,44 +134,52 @@ class item
private:
std::string_view m_name;
std::string_view m_value;
char m_buffer[64]; // TODO: optimize this magic number, might be too large
char m_buffer[64]; // TODO: optimize this magic number, might be too large
};
// --------------------------------------------------------------------
// Transient object to access stored data
template <typename Row>
template <typename RowHandle>
struct item_handle
{
using row_type = Row;
using row_handle_type = RowHandle;
public:
// conversion helper class
template <typename T, typename = void>
struct item_value_as;
template <typename T, std::enable_if_t<std::is_arithmetic_v<T>, int> = 0>
template <typename T>
item_handle &operator=(const T &value)
{
this->operator=(std::to_string(value));
item v{"", value};
m_row_handle.assign(m_column, v.value(), false);
return *this;
}
template <typename T>
item_handle &operator=(const std::optional<T> &value)
{
if (value)
this->operator=(*value);
else
this->operator=("?");
return *this;
}
// template <typename T, std::enable_if_t<std::is_arithmetic_v<T>, int> = 0>
// item_handle &operator=(const T &value)
// {
// this->operator=(std::to_string(value));
// return *this;
// }
item_handle &operator=(const std::string &value)
{
m_row.assign(m_column, value, false);
return *this;
}
// template <typename T>
// item_handle &operator=(const std::optional<T> &value)
// {
// if (value)
// this->operator=(*value);
// else
// this->operator=("?");
// return *this;
// }
// item_handle &operator=(std::string_view value)
// {
// m_row_handle.assign(m_column, value, false);
// return *this;
// }
template <typename... Ts>
void os(const Ts &...v)
......@@ -227,7 +235,7 @@ struct item_handle
// const char *c_str() const
// {
// for (auto iv = m_row.m_head; iv != nullptr; iv = iv->m_next)
// for (auto iv = m_row_handle.m_head; iv != nullptr; iv = iv->m_next)
// {
// if (iv->m_column_ix == m_column)
// return iv->m_text;
......@@ -238,7 +246,7 @@ struct item_handle
std::string_view text() const
{
for (auto iv = m_row.m_head; iv != nullptr; iv = iv->m_next)
for (auto iv = m_row_handle.m_row->m_head; iv != nullptr; iv = iv->m_next)
{
if (iv->m_column_ix == m_column)
return iv->text();
......@@ -250,15 +258,15 @@ struct item_handle
// bool operator!=(const std::string &s) const { return s != c_str(); }
// bool operator==(const std::string &s) const { return s == c_str(); }
item_handle(uint16_t column, row_type &row)
item_handle(uint16_t column, row_handle_type &row)
: m_column(column)
, m_row(row)
, m_row_handle(row)
{
}
private:
uint16_t m_column;
row_type &m_row;
row_handle_type &m_row_handle;
// bool mConst = false;
static constexpr const char *s_empty_result = "";
......
......@@ -55,6 +55,8 @@ class iterator_impl
using pointer = std::conditional_t<N == 0, row_handle_type, value_type *>;
using reference = std::conditional_t<N == 0, row_handle_type, value_type &>;
iterator_impl() = default;
iterator_impl(const iterator_impl &rhs) = default;
template<typename C2, typename... T2s>
......@@ -188,8 +190,8 @@ class iterator_impl
return {};
}
category_type *m_category;
row_type *m_current;
category_type *m_category = nullptr;
row_type *m_current = nullptr;
value_type m_value;
std::array<size_t, N> m_column_ix;
};
......
......@@ -120,9 +120,14 @@ class row_handle
using category_type = Category;
using row_type = std::conditional_t<std::is_const_v<category_type>, const typename category_type::row, typename category_type::row>;
using item_handle_type = item_handle<row_handle>;
template <typename>
friend class row_handle;
template <typename>
friend class item_handle;
row_handle() = default;
row_handle(const row_handle &) = default;
......@@ -149,24 +154,24 @@ class row_handle
return m_cat != nullptr and m_row != nullptr;
}
item_handle<row_type> operator[](uint32_t column_ix)
item_handle_type operator[](uint32_t column_ix)
{
return item_handle<row_type>(column_ix, *m_row);
return item_handle_type(column_ix, *this);
}
const item_handle<const row_type> operator[](uint32_t column_ix) const
const item_handle_type operator[](uint32_t column_ix) const
{
return item_handle<const row_type>(column_ix, *m_row);
return item_handle_type(column_ix, const_cast<row_handle &>(*this));
}
item_handle<row_type> operator[](std::string_view column_name)
item_handle_type operator[](std::string_view column_name)
{
return item_handle<row_type>(get_column_ix(column_name), *m_row);
return item_handle_type(add_column(column_name), *this);
}
const item_handle<const row_type> operator[](std::string_view column_name) const
const item_handle_type operator[](std::string_view column_name) const
{
return item_handle<const row_type>(get_column_ix(column_name), *m_row);
return item_handle_type(get_column_ix(column_name), *this);
}
template <typename... Ts, size_t N>
......@@ -186,12 +191,85 @@ class row_handle
return detail::get_row_result<category_type, C...>(*this, {get_column_ix(columns)...});
}
void assign(const std::vector<item> &values)
{
// std::map<std::string, std::tuple<size_t, std::string, std::string>> changed;
for (auto &value : values)
{
assign(value, true);
// auto columnIx = cat->add_column(value.name());
// auto &col = cat->m_columns[columnIx];
// std::string tag = col.mValidator ? col.mValidator->mTag : std::to_string(columnIx);
// changed[tag] = std::make_tuple(columnIx, operator[](columnIx).c_str(), value.value());
// assign(columnIx, value.value(), true);
}
// // see if we need to update any child categories that depend on these values
// // auto iv = col.mValidator;
// if (mCascade)
// {
// for (auto &&[childCat, linked] : cat->mChildLinks)
// {
// Condition cond;
// std::string childTag;
// std::vector<Item> newValues;
// for (size_t ix = 0; ix < linked->mParentKeys.size(); ++ix)
// {
// std::string pk = linked->mParentKeys[ix];
// std::string ck = linked->mChildKeys[ix];
// if (changed.count(pk) > 0)
// {
// childTag = ck;
// cond = std::move(cond) && (Key(ck) == std::get<1>(changed[pk]));
// newValues.emplace_back(ck, std::get<2>(changed[pk]));
// }
// else
// {
// const char *value = (*this)[pk].c_str();
// cond = std::move(cond) && (Key(ck) == value);
// }
// }
// auto rows = childCat->find(std::move(cond));
// for (auto &cr : rows)
// cr.assign(newValues);
// }
// }
}
void assign(std::string_view name, std::string_view value, bool updateLinked, bool validate = true)
{
assign(m_cat->add_column(name), value, updateLinked, validate);
}
void assign(size_t column, std::string_view value, bool updateLinked, bool validate = true)
{
m_cat->update_value(m_row, column, value, updateLinked, validate);
}
private:
uint32_t get_column_ix(std::string_view name) const
uint16_t get_column_ix(std::string_view name) const
{
return m_cat->get_column_ix(name);
}
uint16_t add_column(std::string_view name)
{
return m_cat->add_column(name);
}
void assign(const item &i, bool updateLinked)
{
assign(i.name(), i.value(), updateLinked);
}
category_type *m_cat = nullptr;
row_type *m_row = nullptr;
};
......
This diff is collapsed. Click to expand it.
......@@ -35,6 +35,8 @@
// #include <cif++/CifValidator.hpp>
// #include <cif++/CifParser.hpp>
#include <cif++/v2/parser.hpp>
namespace tt = boost::test_tools;
std::filesystem::path gTestDir = std::filesystem::current_path(); // filled in first test
......@@ -264,45 +266,54 @@ BOOST_AUTO_TEST_CASE(ci_1)
// --------------------------------------------------------------------
// BOOST_AUTO_TEST_CASE(f_1)
// {
// // using namespace mmcif;
BOOST_AUTO_TEST_CASE(f_1)
{
// using namespace mmcif;
// auto f = R"(data_TEST
// #
// loop_
// _test.id
// _test.name
// 1 aap
// 2 noot
// 3 mies
// )"_cf;
auto f = R"(data_TEST
#
loop_
_test.id
_test.name
1 aap
2 noot
3 mies
)"_cf;
// BOOST_ASSERT(not f.empty());
// BOOST_ASSERT(f.size() == 1);
BOOST_ASSERT(not f.empty());
BOOST_ASSERT(f.size() == 1);
// auto &db = f.front();
auto &db = f.front();
// BOOST_CHECK(db.name() == "TEST");
BOOST_CHECK(db.name() == "TEST");
// auto &test = db["test"];
// BOOST_CHECK(test.size() == 3);
auto &test = db["test"];
BOOST_CHECK(test.size() == 3);
// // wrong! the next lines will crash. And that's OK, don't do that
// // for (auto r: test)
// // test.erase(r);
const char *ts[] = {"aap", "noot", "mies"};
// // BOOST_CHECK(test.empty());
int n = 1;
for (const auto &[i, s] : test.rows<int, std::string>("id", "name"))
{
BOOST_CHECK_EQUAL(i, n);
BOOST_CHECK_EQUAL(s.compare(ts[n - 1]), 0);
++n;
}
// // test.purge();
// for (auto r: test)
// test.erase(r);
// // auto n = test.erase(cif::Key("id") == 1, [](const cif::Row &r)
// // {
// // BOOST_CHECK_EQUAL(r["id"].as<int>(), 1);
// // BOOST_CHECK_EQUAL(r["name"].as<std::string>(), "aap"); });
// BOOST_CHECK(test.empty());
// // BOOST_CHECK_EQUAL(n, 1);
// }
// test.clear();
// auto n = test.erase(cif::Key("id") == 1, [](const cif::Row &r)
// {
// BOOST_CHECK_EQUAL(r["id"].as<int>(), 1);
// BOOST_CHECK_EQUAL(r["name"].as<std::string>(), "aap"); });
// BOOST_CHECK_EQUAL(n, 1);
}
// // --------------------------------------------------------------------
......
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