Commit ab9c4d94 by Maarten L. Hekkelman

compiling again

parent e5eb6225
......@@ -215,7 +215,11 @@ set(project_sources
${PROJECT_SOURCE_DIR}/src/Symmetry.cpp
${PROJECT_SOURCE_DIR}/src/TlsParser.cpp
${PROJECT_SOURCE_DIR}/src/v2/category.cpp
${PROJECT_SOURCE_DIR}/src/v2/dictionary_parser.cpp
${PROJECT_SOURCE_DIR}/src/v2/item.cpp
${PROJECT_SOURCE_DIR}/src/v2/parser.cpp
${PROJECT_SOURCE_DIR}/src/v2/row.cpp
${PROJECT_SOURCE_DIR}/src/v2/validate.cpp
)
......
......@@ -37,119 +37,38 @@ namespace cif::v2
// --------------------------------------------------------------------
template <typename Alloc>
class category_t
class category
{
private:
// --------------------------------------------------------------------
// Internal storage, strictly forward linked list with minimal space
// requirements. Strings of size 7 or shorter are stored internally.
// Typically, more than 99% of the strings in an mmCIF file are less
// than 8 bytes in length.
struct item_value
{
item_value(uint16_t column_ix, uint16_t length)
: m_next(nullptr)
, m_column_ix(column_ix)
, m_length(length)
{
}
item_value() = delete;
item_value(const item_value &) = delete;
item_value &operator=(const item_value &) = delete;
item_value *m_next;
uint16_t m_column_ix;
uint16_t m_length;
union
{
char m_local_data[8];
char *m_data;
};
static constexpr size_t kBufferSize = sizeof(m_local_data);
std::string_view text() const
{
return {m_length >= kBufferSize ? m_data : m_local_data, m_length};
}
const char *c_str() const
{
return m_length >= kBufferSize ? m_data : m_local_data;
}
};
static_assert(sizeof(item_value) == 24, "sizeof(item_value) should be 24 bytes");
public:
using allocator_type = Alloc;
allocator_type get_allocator() const
{
return m_allocator;
}
template <typename>
friend class row_handle;
template <typename, typename...>
friend class iterator_impl;
using value_type = row_handle<category_t>;
using value_type = row_handle;
using reference = value_type;
using const_reference = const value_type;
using iterator = iterator_impl<category_t>;
using const_iterator = iterator_impl<const category_t>;
class row
{
public:
row() = default;
private:
template <typename>
friend class item_handle;
template <typename, typename...>
friend class iterator_impl;
using iterator = iterator_impl<category>;
using const_iterator = iterator_impl<const category>;
friend class category_t;
category() = default;
void append(item_value *iv)
{
if (m_head == nullptr)
m_head = m_tail = iv;
else
m_tail = m_tail->m_next = iv;
}
row *m_next = nullptr;
item_value *m_head = nullptr, *m_tail = nullptr;
};
category_t() = default;
category_t(std::string_view name, const allocator_type &alloc = allocator_type())
: m_allocator(alloc)
, m_name(name)
category(std::string_view name)
: m_name(name)
{
}
category_t(const category_t &rhs)
: m_allocator(std::allocator_traits<allocator_type>::select_on_container_copy_construction(rhs.get_allocator()))
, m_name(rhs.m_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_t(category_t &&rhs)
: m_allocator(std::move(rhs.m_allocator))
, m_name(std::move(rhs.m_name))
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)
......@@ -158,28 +77,13 @@ class category_t
rhs.m_tail = nullptr;
}
template <typename Alloc2>
category_t(const category_t &c, const Alloc2 &a)
: m_allocator(a)
, m_name(c.m_name)
{
}
template <typename Alloc2>
category_t(category_t &&c, const Alloc2 &a)
: m_allocator(a)
, m_name(std::move(c.m_name))
{
}
category_t &operator=(const category_t &rhs)
category &operator=(const category &rhs)
{
if (this != &rhs)
{
if (not empty())
clear();
m_allocator = std::allocator_traits<allocator_type>::select_on_container_copy_construction(rhs.get_allocator());
m_name = rhs.m_name;
m_columns = rhs.m_columns;
......@@ -190,14 +94,13 @@ class category_t
return *this;
}
category_t &operator=(category_t &&rhs)
category &operator=(category &&rhs)
{
if (this != &rhs)
{
if (not empty())
clear();
m_allocator = std::move(rhs.m_allocator);
m_name = std::move(rhs.m_name);
m_columns = std::move(rhs.m_columns);
......@@ -210,7 +113,7 @@ class category_t
return *this;
}
~category_t()
~category()
{
clear();
}
......@@ -226,7 +129,7 @@ class category_t
const_reference front() const
{
return {*this, *m_head};
return {const_cast<category &>(*this), const_cast<row &>(*m_head)};
}
reference back()
......@@ -236,7 +139,7 @@ class category_t
const_reference back() const
{
return {*this, *m_tail};
return {const_cast<category &>(*this), const_cast<row &>(*m_tail)};
}
iterator begin()
......@@ -282,31 +185,165 @@ class category_t
// --------------------------------------------------------------------
template <typename... Ts, typename... Ns>
iterator_proxy<const category_t, Ts...> rows(Ns... names) const
iterator_proxy<const category, Ts...> rows(Ns... names) const
{
static_assert(sizeof...(Ts) == sizeof...(Ns), "The number of column titles should be equal to the number of types to return");
return iterator_proxy<const category, Ts...>(*this, begin(), {names...});
}
template <typename... Ts, typename... Ns>
iterator_proxy<category, Ts...> rows(Ns... names)
{
static_assert(sizeof...(Ts) == sizeof...(Ns), "The number of column titles should be equal to the number of types to return");
return iterator_proxy<category, Ts...>(*this, begin(), {names...});
}
// --------------------------------------------------------------------
conditional_iterator_proxy<category> find(condition &&cond)
{
return find(begin(), std::forward<condition>(cond));
}
conditional_iterator_proxy<category> find(iterator pos, condition &&cond)
{
return {*this, pos, std::forward<condition>(cond)};
}
conditional_iterator_proxy<const category> find(condition &&cond) const
{
return find(cbegin(), std::forward<condition>(cond));
}
conditional_iterator_proxy<const category> find(const_iterator pos, condition &&cond) const
{
return conditional_iterator_proxy<const category>{*this, pos, std::forward<condition>(cond)};
}
template <typename... Ts, typename... Ns>
conditional_iterator_proxy<category, Ts...> find(condition &&cond, Ns... names)
{
static_assert(sizeof...(Ts) == sizeof...(Ns), "The number of column titles should be equal to the number of types to return");
return find<Ts...>(cbegin(), std::forward<condition>(cond), std::forward<Ns>(names)...);
}
template <typename... Ts, typename... Ns>
conditional_iterator_proxy<const category, Ts...> find(condition &&cond, Ns... names) const
{
static_assert(sizeof...(Ts) == sizeof...(Ns), "The number of column titles should be equal to the number of types to return");
return iterator_proxy<const category_t, Ts...>(*this, begin(), {names...});
return find<Ts...>(cbegin(), std::forward<condition>(cond), std::forward<Ns>(names)...);
}
template <typename... Ts, typename... Ns>
iterator_proxy<category_t, Ts...> rows(Ns... names)
conditional_iterator_proxy<category, Ts...> find(const_iterator pos, condition &&cond, Ns... names)
{
static_assert(sizeof...(Ts) == sizeof...(Ns), "The number of column titles should be equal to the number of types to return");
return iterator_proxy<category_t, Ts...>(*this, begin(), {names...});
return {*this, pos, std::forward<condition>(cond), std::forward<Ns>(names)...};
}
template <typename... Ts, typename... Ns>
conditional_iterator_proxy<const category, Ts...> find(const_iterator pos, condition &&cond, Ns... names) const
{
static_assert(sizeof...(Ts) == sizeof...(Ns), "The number of column titles should be equal to the number of types to return");
return {*this, pos, std::forward<condition>(cond), std::forward<Ns>(names)...};
}
// --------------------------------------------------------------------
// if you only expect a single row
row_handle find1(condition &&cond)
{
return find1(begin(), std::forward<condition>(cond));
}
row_handle find1(iterator pos, condition &&cond)
{
auto h = find(pos, std::forward<condition>(cond));
void insert(const_iterator pos, const row &row)
if (h.empty())
throw std::runtime_error("No hits found");
if (h.size() != 1)
throw std::runtime_error("Hit not unique");
return *h.begin();
}
const row_handle find1(condition &&cond) const
{
return find1(cbegin(), std::forward<condition>(cond));
}
const row_handle find1(const_iterator pos, condition &&cond) const
{
auto h = find(pos, std::forward<condition>(cond));
if (h.empty())
throw std::runtime_error("No hits found");
if (h.size() != 1)
throw std::runtime_error("Hit not unique");
return *h.begin();
}
template <typename T>
T find1(condition &&cond, const char *column) const
{
insert_impl(pos, row);
return find1<T>(cbegin(), std::forward<condition>(cond), column);
}
void insert(const_iterator pos, row &&row)
template <typename T>
T find1(const_iterator pos, condition &&cond, const char *column) const
{
insert_impl(pos, std::move(row));
auto h = find<T>(pos, std::forward<condition>(cond), column);
if (h.empty())
throw std::runtime_error("No hits found");
if (h.size() != 1)
throw std::runtime_error("Hit not unique");
return std::get<0>(*h.begin());
}
template <typename... Ts, typename... Cs, typename U = std::enable_if_t<sizeof...(Ts) != 1>>
std::tuple<Ts...> find1(condition &&cond, Cs... columns) const
{
static_assert(sizeof...(Ts) == sizeof...(Cs), "The number of column titles should be equal to the number of types to return");
// static_assert(std::is_same_v<Cs, const char*>..., "The column names should be const char");
return find1<Ts...>(cbegin(), std::forward<condition>(cond), std::forward<Cs>(columns)...);
}
template <typename... Ts, typename... Cs, typename U = std::enable_if_t<sizeof...(Ts) != 1>>
std::tuple<Ts...> find1(const_iterator pos, condition &&cond, Cs... columns) const
{
static_assert(sizeof...(Ts) == sizeof...(Cs), "The number of column titles should be equal to the number of types to return");
auto h = find<Ts...>(pos, std::forward<condition>(cond), std::forward<Cs>(columns)...);
if (h.empty())
throw std::runtime_error("No hits found");
if (h.size() != 1)
throw std::runtime_error("Hit not unique");
return *h.begin();
}
bool exists(condition &&cond) const;
// --------------------------------------------------------------------
// void insert(const_iterator pos, const row &row)
// {
// insert_impl(pos, row);
// }
// void insert(const_iterator pos, row &&row)
// {
// insert_impl(pos, std::move(row));
// }
iterator emplace(std::initializer_list<item> items)
{
return this->emplace(items.begin(), items.end());
......@@ -337,7 +374,7 @@ class category_t
// }
// if (not seen and iv->mMandatory)
// throw std::runtime_error("missing mandatory field " + col.mName + " for Category " + mName);
// throw std::runtime_error("missing mandatory field " + col.mName + " for category " + mName);
// }
// if (mIndex != nullptr)
......@@ -438,7 +475,7 @@ class category_t
// {
// 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_validator->reportError("tag " + std::string(column_name) + " not allowed in category " + mName, false);
// }
m_columns.emplace_back(column_name, item_validator);
......@@ -448,177 +485,20 @@ class category_t
}
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());
// }
// }
void update_value(row *row, size_t column, std::string_view value, bool updateLinked, bool validate = true);
// 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;
// }
private:
using allocator_type = std::allocator<void>;
// for (auto &cr : rows)
// cr.assign(childTag, value, false);
// }
// }
constexpr allocator_type get_allocator() const
{
return {};
}
private:
using char_allocator_type = typename std::allocator_traits<Alloc>::template rebind_alloc<char>;
using char_allocator_type = typename std::allocator_traits<allocator_type>::template rebind_alloc<char>;
using char_allocator_traits = std::allocator_traits<char_allocator_type>;
using item_allocator_type = typename std::allocator_traits<Alloc>::template rebind_alloc<item_value>;
using item_allocator_type = typename std::allocator_traits<allocator_type>::template rebind_alloc<item_value>;
using item_allocator_traits = std::allocator_traits<item_allocator_type>;
item_allocator_traits::pointer get_item()
......@@ -740,89 +620,13 @@ class category_t
};
// proxy methods for every insertion
iterator insert_impl(const_iterator pos, row *n)
{
assert(n != nullptr);
assert(n->m_next == nullptr);
if (n == nullptr)
throw std::runtime_error("Invalid pointer passed to insert");
// insert at end, most often this is the case
if (pos.m_current == nullptr)
{
if (m_head == nullptr)
m_tail = m_head = n;
else
m_tail = m_tail->m_next = n;
}
else
{
assert(m_head != nullptr);
if (pos.m_current == m_head)
m_head = n->m_next = m_head;
else
n = n->m_next = m_head->m_next;
}
return iterator(*this, n);
}
iterator erase_impl(const_iterator pos)
{
if (pos == cend())
return pos;
row *n = const_cast<row *>(&*pos);
row *cur;
if (m_head == n)
{
m_head = static_cast<row *>(m_head->m_next);
if (m_head != nullptr)
m_head->m_prev = nullptr;
else
m_tail = nullptr;
n->m_next = n->m_prev = n->m_parent = nullptr;
delete_row(n);
iterator insert_impl(const_iterator pos, row *n);
cur = m_head;
}
else
{
cur = static_cast<row *>(n->m_next);
if (m_tail == n)
m_tail = static_cast<row *>(n->m_prev);
iterator erase_impl(const_iterator pos);
row *p = m_head;
while (p != nullptr and p->m_next != n)
p = p->m_next;
if (p != nullptr and p->m_next == n)
{
p->m_next = n->m_next;
if (p->m_next != nullptr)
p->m_next->m_prev = p;
n->m_next = nullptr;
}
else
throw std::runtime_error("remove for a row not found in the list");
delete_row(n);
}
return iterator(*this, cur);
}
allocator_type m_allocator;
std::string m_name;
std::vector<item_column, typename std::allocator_traits<allocator_type>::template rebind_alloc<item_column>> m_columns;
std::vector<item_column> m_columns;
row *m_head = nullptr, *m_tail = nullptr;
};
using category = category_t<>;
} // namespace cif::v2
\ No newline at end of file
......@@ -41,145 +41,120 @@ namespace cif::v2
namespace detail
{
template <typename Category>
struct condition_impl
{
using category_type = Category;
using row_type = row_handle<category_type>;
virtual ~condition_impl() {}
virtual void prepare(const Category &c) {}
virtual bool test(const Category &c, const row_type &r) const = 0;
virtual void prepare(const category &c) {}
virtual bool test(row_handle r) const = 0;
virtual void str(std::ostream &os) const = 0;
};
template <typename Category>
struct all_condition_impl : public condition_impl<Category>
struct all_condition_impl : public condition_impl
{
using base_type = condition_impl<Category>;
using row_type = base_type::row_type;
virtual bool test(const Category &c, const row_type &r) const { return true; }
virtual void str(std::ostream &os) const { os << "*"; }
bool test(row_handle r) const override { return true; }
void str(std::ostream &os) const override { os << "*"; }
};
template <typename>
struct or_condition_impl;
template <typename>
struct and_condition_impl;
template <typename>
struct not_condition_impl;
} // namespace detail
template <typename Category>
class condition_t
class condition
{
public:
using category_type = Category;
using condition_impl = detail::condition_impl<category_type>;
using row_type = row_handle<category_type>;
using condition_impl = detail::condition_impl;
condition_t()
condition()
: m_impl(nullptr)
{
}
condition_t(condition_impl *impl)
condition(condition_impl *impl)
: m_impl(impl)
{
}
condition_t(const condition_t &) = delete;
condition(const condition &) = delete;
condition_t(condition_t &&rhs) noexcept
condition(condition &&rhs) noexcept
: m_impl(nullptr)
{
std::swap(m_impl, rhs.m_impl);
}
condition_t &operator=(const condition_t &) = delete;
condition &operator=(const condition &) = delete;
condition_t &operator=(condition_t &&rhs) noexcept
condition &operator=(condition &&rhs) noexcept
{
std::swap(m_impl, rhs.m_impl);
return *this;
}
~condition_t()
~condition()
{
delete m_impl;
m_impl = nullptr;
}
void prepare(const category_type &c)
void prepare(const category &c)
{
if (m_impl)
m_impl->prepare(c);
m_prepared = true;
}
bool operator()(const category_type &c, const row_type &r) const
bool operator()(row_handle r) const
{
assert(this->m_impl != nullptr);
assert(this->m_prepared);
return m_impl ? m_impl->test(c, r) : false;
return m_impl ? m_impl->test(r) : false;
}
bool empty() const { return m_impl == nullptr; }
template<typename C> friend condition_t operator||(condition_t<C> &&a, condition_t<C> &&b);
template<typename C> friend condition_t operator&&(condition_t<C> &&a, condition_t<C> &&b);
friend condition operator||(condition &&a, condition &&b);
friend condition operator&&(condition &&a, condition &&b);
template <typename>
friend struct detail::or_condition_impl;
template <typename>
friend struct detail::and_condition_impl;
template <typename>
friend struct detail::not_condition_impl;
void swap(condition_t &rhs)
void swap(condition &rhs)
{
std::swap(m_impl, rhs.m_impl);
std::swap(m_prepared, rhs.m_prepared);
}
template<typename C> friend std::ostream &operator<<(std::ostream &os, const condition_t<C> &cond);
friend std::ostream &operator<<(std::ostream &os, const condition &cond)
{
if (cond.m_impl)
cond.m_impl->str(os);
return os;
}
private:
condition_impl *m_impl;
bool m_prepared = false;
};
template <typename Category>
inline std::ostream &operator<<(std::ostream &os, const condition_t<Category> &cond)
{
if (cond.m_impl)
cond.m_impl->str(os);
return os;
}
namespace detail
{
template <typename Category>
struct keyIsemptycondition_impl : public condition_impl<Category>
struct key_is_empty_condition_impl : public condition_impl
{
using base_type = condition_impl<Category>;
using row_type = base_type::row_type;
keyIsemptycondition_impl(const std::string &item_tag)
key_is_empty_condition_impl(const std::string &item_tag)
: m_item_tag(item_tag)
{
}
virtual void prepare(const Category &c);
void prepare(const category &c) override;
virtual bool test(const Category &c, const row_type &r) const
bool test(row_handle r) const override
{
return r[m_item_ix].empty();
}
virtual void str(std::ostream &os) const
void str(std::ostream &os) const override
{
os << m_item_tag << " IS NULL";
}
......@@ -188,61 +163,53 @@ namespace detail
size_t m_item_ix = 0;
};
template <typename Category>
struct keyComparecondition_impl : public condition_impl<Category>
struct key_compare_condition_impl : public condition_impl
{
using base_type = condition_impl<Category>;
using row_type = base_type::row_type;
template <typename COMP>
keyComparecondition_impl(const std::string &item_tag, COMP &&comp, const std::string &s)
key_compare_condition_impl(const std::string &item_tag, COMP &&comp, const std::string &s)
: m_item_tag(item_tag)
, m_compare(std::move(comp))
, mStr(s)
, m_str(s)
{
}
virtual void prepare(const Category &c);
void prepare(const category &c) override;
virtual bool test(const Category &c, const row_type &r) const
bool test(row_handle r) const override
{
return m_compare(c, r, m_icase);
return m_compare(r, m_icase);
}
virtual void str(std::ostream &os) const
void str(std::ostream &os) const override
{
os << m_item_tag << (m_icase ? "^ " : " ") << mStr;
os << m_item_tag << (m_icase ? "^ " : " ") << m_str;
}
std::string m_item_tag;
size_t m_item_ix = 0;
bool m_icase = false;
std::function<bool(const Category &, const row_type &, bool)> m_compare;
std::string mStr;
std::function<bool(row_handle, bool)> m_compare;
std::string m_str;
};
template <typename Category>
struct keyMatchescondition_impl : public condition_impl<Category>
struct key_matches_condition_impl : public condition_impl
{
using base_type = condition_impl<Category>;
using row_type = base_type::row_type;
keyMatchescondition_impl(const std::string &item_tag, const std::regex &rx)
key_matches_condition_impl(const std::string &item_tag, const std::regex &rx)
: m_item_tag(item_tag)
, m_item_ix(0)
, mRx(rx)
{
}
virtual void prepare(const Category &c);
void prepare(const category &c) override;
virtual bool test(const Category &c, const row_type &r) const
bool test(row_handle r) const override
{
std::string_view txt = r[m_item_ix].text();
return std::regex_match(txt.begin(), txt.end(), mRx);
}
virtual void str(std::ostream &os) const
void str(std::ostream &os) const override
{
os << m_item_tag << " =~ expression";
}
......@@ -252,21 +219,40 @@ namespace detail
std::regex mRx;
};
template <typename Category, typename T>
struct AnyIscondition_impl : public condition_impl<Category>
template <typename T>
struct any_is_condition_impl : public condition_impl
{
using base_type = condition_impl<Category>;
using row_type = base_type::row_type;
typedef T valueType;
AnyIscondition_impl(const valueType &value)
any_is_condition_impl(const valueType &value)
: mValue(value)
{
}
virtual bool test(const Category &c, const row_type &r) const;
virtual void str(std::ostream &os) const
bool test(row_handle r) const override
{
auto &c = r.cat();
bool result = false;
for (auto &f : get_category_fields(c))
{
try
{
if (r[f].compare(mValue) == 0)
{
result = true;
break;
}
}
catch (...)
{
}
}
return result;
}
void str(std::ostream &os) const override
{
os << "<any> == " << mValue;
}
......@@ -274,19 +260,38 @@ namespace detail
valueType mValue;
};
template <typename Category>
struct AnyMatchescondition_impl : public condition_impl<Category>
struct any_matches_condition_impl : public condition_impl
{
using base_type = condition_impl<Category>;
using row_type = base_type::row_type;
AnyMatchescondition_impl(const std::regex &rx)
any_matches_condition_impl(const std::regex &rx)
: mRx(rx)
{
}
virtual bool test(const Category &c, const row_type &r) const;
virtual void str(std::ostream &os) const
bool test(row_handle r) const override
{
auto &c = r.cat();
bool result = false;
for (auto &f : get_category_fields(c))
{
try
{
std::string_view txt = r[f].text();
if (std::regex_match(txt.begin(), txt.end(), mRx))
{
result = true;
break;
}
}
catch (...)
{
}
}
return result;
}
void str(std::ostream &os) const override
{
os << "<any> =~ expression";
}
......@@ -294,13 +299,9 @@ namespace detail
std::regex mRx;
};
template <typename Category>
struct and_condition_impl : public condition_impl<Category>
struct and_condition_impl : public condition_impl
{
using base_type = condition_impl<Category>;
using row_type = base_type::row_type;
and_condition_impl(condition_t<Category> &&a, condition_t<Category> &&b)
and_condition_impl(condition &&a, condition &&b)
: mA(nullptr)
, mB(nullptr)
{
......@@ -314,18 +315,18 @@ namespace detail
delete mB;
}
virtual void prepare(const Category &c)
void prepare(const category &c) override
{
mA->prepare(c);
mB->prepare(c);
}
virtual bool test(const Category &c, const row_type &r) const
bool test(row_handle r) const override
{
return mA->test(c, r) and mB->test(c, r);
return mA->test(r) and mB->test(r);
}
virtual void str(std::ostream &os) const
void str(std::ostream &os) const override
{
os << '(';
mA->str(os);
......@@ -334,17 +335,13 @@ namespace detail
os << ')';
}
base_type *mA;
base_type *mB;
condition_impl *mA;
condition_impl *mB;
};
template <typename Category>
struct or_condition_impl : public condition_impl<Category>
struct or_condition_impl : public condition_impl
{
using base_type = condition_impl<Category>;
using row_type = base_type::row_type;
or_condition_impl(condition_t<Category> &&a, condition_t<Category> &&b)
or_condition_impl(condition &&a, condition &&b)
: mA(nullptr)
, mB(nullptr)
{
......@@ -358,18 +355,18 @@ namespace detail
delete mB;
}
virtual void prepare(const Category &c)
void prepare(const category &c) override
{
mA->prepare(c);
mB->prepare(c);
}
virtual bool test(const Category &c, const row_type &r) const
bool test(row_handle r) const override
{
return mA->test(c, r) or mB->test(c, r);
return mA->test(r) or mB->test(r);
}
virtual void str(std::ostream &os) const
void str(std::ostream &os) const override
{
os << '(';
mA->str(os);
......@@ -378,17 +375,13 @@ namespace detail
os << ')';
}
base_type *mA;
base_type *mB;
condition_impl *mA;
condition_impl *mB;
};
template <typename Category>
struct not_condition_impl : public condition_impl<Category>
struct not_condition_impl : public condition_impl
{
using base_type = condition_impl<Category>;
using row_type = base_type::row_type;
not_condition_impl(condition_t<Category> &&a)
not_condition_impl(condition &&a)
: mA(nullptr)
{
std::swap(mA, a.m_impl);
......@@ -399,55 +392,53 @@ namespace detail
delete mA;
}
virtual void prepare(const Category &c)
void prepare(const category &c) override
{
mA->prepare(c);
}
virtual bool test(const Category &c, const row_type &r) const
bool test(row_handle r) const override
{
return not mA->test(c, r);
return not mA->test(r);
}
virtual void str(std::ostream &os) const
void str(std::ostream &os) const override
{
os << "NOT (";
mA->str(os);
os << ')';
}
base_type *mA;
condition_impl *mA;
};
} // namespace detail
template <typename Category>
inline condition_t<Category> operator&&(condition_t<Category> &&a, condition_t<Category> &&b)
inline condition operator&&(condition &&a, condition &&b)
{
if (a.m_impl and b.m_impl)
return condition_t<Category>(new detail::and_condition_impl<Category>(std::move(a), std::move(b)));
return condition(new detail::and_condition_impl(std::move(a), std::move(b)));
if (a.m_impl)
return condition_t<Category>(std::move(a));
return condition_t<Category>(std::move(b));
return condition(std::move(a));
return condition(std::move(b));
}
template <typename Category>
inline condition_t<Category> operator||(condition_t<Category> &&a, condition_t<Category> &&b)
inline condition operator||(condition &&a, condition &&b)
{
if (a.m_impl and b.m_impl)
return condition_t<Category>(new detail::or_condition_impl<Category>(std::move(a), std::move(b)));
return condition(new detail::or_condition_impl(std::move(a), std::move(b)));
if (a.m_impl)
return condition_t<Category>(std::move(a));
return condition_t<Category>(std::move(b));
return condition(std::move(a));
return condition(std::move(b));
}
struct empty
struct empty_type
{
};
/// \brief A helper to make it possible to have conditions like ("id"_key == cif::null)
inline constexpr empty null = empty();
inline constexpr empty_type null = empty_type();
struct key
{
......@@ -467,161 +458,138 @@ struct key
std::string m_item_tag;
};
template <typename Category, typename T>
condition_t<Category> operator==(const key &key, const T &v)
template <typename T>
condition operator==(const key &key, const T &v)
{
using category_type = Category;
using row_type = row_handle<category_type>;
std::ostringstream s;
s << " == " << v;
return condition_t<Category>(new detail::keyComparecondition_impl<Category>(
key.m_item_tag, [tag = key.m_item_tag, v](const Category &c, const row_type &r, bool icase)
return condition(new detail::key_compare_condition_impl(
key.m_item_tag, [tag = key.m_item_tag, v](row_handle r, bool icase)
{ return r[tag].template compare<T>(v, icase) == 0; },
s.str()));
}
template <typename Category>
inline condition_t<Category> operator==(const key &key, const char *value)
inline condition operator==(const key &key, const char *value)
{
using category_type = Category;
using row_type = row_handle<category_type>;
if (value != nullptr and *value != 0)
{
std::ostringstream s;
s << " == " << value;
return condition_t<Category>(new detail::keyComparecondition_impl<Category>(
key.m_item_tag, [tag = key.m_item_tag, value](const Category &c, const row_type &r, bool icase)
return condition(new detail::key_compare_condition_impl(
key.m_item_tag, [tag = key.m_item_tag, value](row_handle r, bool icase)
{ return r[tag].compare(value, icase) == 0; },
s.str()));
}
else
return condition_t(new detail::keyIsemptycondition_impl<Category>(key.m_item_tag));
return condition(new detail::key_is_empty_condition_impl(key.m_item_tag));
}
// inline condition_t operator==(const key& key, const detail::ItemReference& v)
// {
// if (v.empty())
// return condition_t(new detail::keyIsemptycondition_impl(key.m_item_tag));
// return condition_t(new detail::key_is_empty_condition_impl(key.m_item_tag));
// else
// return condition_t(new detail::keyComparecondition_impl(key.m_item_tag, [tag = key.m_item_tag, v](const Category& c, const row_type& r, bool icase)
// return condition_t(new detail::key_compare_condition_impl(key.m_item_tag, [tag = key.m_item_tag, v](const category& c, const row& r, bool icase)
// { return r[tag].template compare<(v, icase) == 0; }));
// }
template <typename Category, typename T>
condition_t<Category> operator!=(const key &key, const T &v)
template <typename T>
condition operator!=(const key &key, const T &v)
{
return condition_t<Category>(new detail::not_condition_impl<Category>(operator==(key, v)));
return condition(new detail::not_condition_impl(operator==(key, v)));
}
template <typename Category>
inline condition_t<Category> operator!=(const key &key, const char *v)
inline condition operator!=(const key &key, const char *v)
{
std::string value(v ? v : "");
return condition_t<Category>(new detail::not_condition_impl<Category>(operator==(key, value)));
return condition(new detail::not_condition_impl(operator==(key, value)));
}
template <typename Category, typename T>
condition_t<Category> operator>(const key &key, const T &v)
template <typename T>
condition operator>(const key &key, const T &v)
{
using category_type = Category;
using row_type = row_handle<category_type>;
std::ostringstream s;
s << " > " << v;
return condition_t<Category>(new detail::keyComparecondition_impl<Category>(
key.m_item_tag, [tag = key.m_item_tag, v](const Category &c, const row_type &r, bool icase)
return condition(new detail::key_compare_condition_impl(
key.m_item_tag, [tag = key.m_item_tag, v](const category &c, row_handle r, bool icase)
{ return r[tag].template compare<T>(v, icase) > 0; },
s.str()));
}
template <typename Category, typename T>
condition_t<Category> operator>=(const key &key, const T &v)
template <typename T>
condition operator>=(const key &key, const T &v)
{
using category_type = Category;
using row_type = row_handle<category_type>;
std::ostringstream s;
s << " >= " << v;
return condition_t<Category>(new detail::keyComparecondition_impl<Category>(
key.m_item_tag, [tag = key.m_item_tag, v](const Category &c, const row_type &r, bool icase)
return condition(new detail::key_compare_condition_impl(
key.m_item_tag, [tag = key.m_item_tag, v](const category &c, row_handle r, bool icase)
{ return r[tag].template compare<T>(v, icase) >= 0; },
s.str()));
}
template <typename Category, typename T>
condition_t<Category> operator<(const key &key, const T &v)
template <typename T>
condition operator<(const key &key, const T &v)
{
using category_type = Category;
using row_type = row_handle<category_type>;
std::ostringstream s;
s << " < " << v;
return condition_t<Category>(new detail::keyComparecondition_impl<Category>(
key.m_item_tag, [tag = key.m_item_tag, v](const Category &c, const row_type &r, bool icase)
return condition(new detail::key_compare_condition_impl(
key.m_item_tag, [tag = key.m_item_tag, v](const category &c, row_handle r, bool icase)
{ return r[tag].template compare<T>(v, icase) < 0; },
s.str()));
}
template <typename Category, typename T>
condition_t<Category> operator<=(const key &key, const T &v)
template <typename T>
condition operator<=(const key &key, const T &v)
{
using category_type = Category;
using row_type = row_handle<category_type>;
std::ostringstream s;
s << " <= " << v;
return condition_t<Category>(new detail::keyComparecondition_impl<Category>(
key.m_item_tag, [tag = key.m_item_tag, v](const Category &c, const row_type &r, bool icase)
return condition(new detail::key_compare_condition_impl(
key.m_item_tag, [tag = key.m_item_tag, v](const category &c, row_handle r, bool icase)
{ return r[tag].template compare<T>(v, icase) <= 0; },
s.str()));
}
template <typename Category>
inline condition_t<Category> operator==(const key &key, const std::regex &rx)
inline condition operator==(const key &key, const std::regex &rx)
{
return condition_t<Category>(new detail::keyMatchescondition_impl<Category>(key.m_item_tag, rx));
return condition(new detail::key_matches_condition_impl(key.m_item_tag, rx));
}
template <typename Category>
inline condition_t<Category> operator==(const key &key, const empty &)
inline condition operator==(const key &key, const empty_type &)
{
return condition_t<Category>(new detail::keyIsemptycondition_impl<Category>(key.m_item_tag));
return condition(new detail::key_is_empty_condition_impl(key.m_item_tag));
}
template <typename Category>
struct any_t
struct any_type
{
};
template <typename Category, typename T>
condition_t<Category> operator==(const any_t<Category> &, const T &v)
inline constexpr any_type any = any_type{};
template <typename T>
condition operator==(const any_type &, const T &v)
{
return condition_t<Category>(new detail::AnyIscondition_impl<Category, T>(v));
return condition(new detail::any_is_condition_impl<T>(v));
}
template <typename Category>
condition_t<Category> operator==(any_t<Category> &, const std::regex &rx)
inline condition operator==(const any_type &, const std::regex &rx)
{
return condition_t<Category>(new detail::AnyMatchescondition_impl<Category>(rx));
return condition(new detail::any_matches_condition_impl(rx));
}
template <typename Category>
inline condition_t<Category> all()
inline condition all()
{
return condition_t<Category>(new detail::all_condition_impl<Category>());
return condition(new detail::all_condition_impl());
}
// inline condition_t<Category> Not(condition_t<Category> &&cond)
// inline condition_t<category> Not(condition_t<category> &&cond)
// {
// return condition_t<Category>(new detail::not_condition_impl<Category>(std::move(cond)));
// return condition_t<category>(new detail::not_condition_impl(std::move(cond)));
// }
namespace literals
......@@ -630,9 +598,6 @@ namespace literals
{
return key(std::string(text, length));
}
inline constexpr empty null = empty();
} // namespace literals
} // namespace cif::v2
\ No newline at end of file
......@@ -35,47 +35,29 @@ namespace cif::v2
// --------------------------------------------------------------------
template <typename Alloc, typename Category>
class datablock_t
class datablock
{
public:
using category_type = Category;
using allocator_type = Alloc;
using category_list = std::list<category>;
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_list::iterator;
using const_iterator = category_list::const_iterator;
using iterator = category_type_list::iterator;
using const_iterator = category_type_list::const_iterator;
using reference = typename category_list::reference;
using reference = typename category_type_list::reference;
datablock() = default;
datablock_t(std::string_view name, const allocator_type &alloc = allocator_type())
: m_categories(alloc)
, m_name(name)
datablock(std::string_view name)
: m_name(name)
{
}
datablock_t(const datablock_t &) = default;
datablock(const datablock &) = default;
datablock_t(datablock_t &&) = default;
datablock(datablock &&) = default;
// 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)
// {
// }
datablock_t &operator=(const datablock_t &) = default;
datablock_t &operator=(datablock_t &&) = default;
datablock &operator=(const datablock &) = default;
datablock &operator=(datablock &&) = default;
// --------------------------------------------------------------------
......@@ -100,9 +82,9 @@ class datablock_t
// --------------------------------------------------------------------
category_type &operator[](std::string_view name)
category &operator[](std::string_view name)
{
auto i = std::find_if(m_categories.begin(), m_categories.end(), [name](const category_type &c)
auto i = std::find_if(m_categories.begin(), m_categories.end(), [name](const category &c)
{ return iequals(c.name(), name); });
if (i != m_categories.end())
......@@ -112,10 +94,10 @@ class datablock_t
return m_categories.back();
}
const category_type &operator[](std::string_view name) const
const category &operator[](std::string_view name) const
{
static const category_type s_empty;
auto i = std::find_if(m_categories.begin(), m_categories.end(), [name](const category_type &c)
static const category s_empty;
auto i = std::find_if(m_categories.begin(), m_categories.end(), [name](const category &c)
{ return iequals(c.name(), name); });
return i == m_categories.end() ? s_empty : *i;
}
......@@ -155,53 +137,51 @@ class datablock_t
return std::make_tuple(m_categories.begin(), is_new);
}
void write(std::ostream &os) const
{
// std::shared_lock lock(mLock);
os << "data_" << m_name << std::endl
<< "# " << std::endl;
// mmcif support, sort of. First write the 'entry' Category
// and if it exists, _AND_ we have a Validator, write out the
// audit_conform record.
for (auto &cat : m_categories)
{
if (cat.name() != "entry")
continue;
cat.write(os);
// if (mValidator != nullptr)
// {
// Category auditConform(*this, "audit_conform", nullptr);
// auditConform.emplace({{"dict_name", mValidator->dictName()},
// {"dict_version", mValidator->dictVersion()}});
// auditConform.write(os);
// }
break;
}
for (auto &cat : m_categories)
{
if (cat.name() != "entry" and cat.name() != "audit_conform")
cat.write(os);
}
}
// void write(std::ostream &os) const
// {
// // std::shared_lock lock(mLock);
// os << "data_" << m_name << std::endl
// << "# " << std::endl;
// // mmcif support, sort of. First write the 'entry' Category
// // and if it exists, _AND_ we have a Validator, write out the
// // audit_conform record.
// for (auto &cat : m_categories)
// {
// if (cat.name() != "entry")
// continue;
// cat.write(os);
// // if (mValidator != nullptr)
// // {
// // Category auditConform(*this, "audit_conform", nullptr);
// // auditConform.emplace({{"dict_name", mValidator->dictName()},
// // {"dict_version", mValidator->dictVersion()}});
// // auditConform.write(os);
// // }
// break;
// }
// for (auto &cat : m_categories)
// {
// if (cat.name() != "entry" and cat.name() != "audit_conform")
// cat.write(os);
// }
// }
friend std::ostream &operator<<(std::ostream &os, const datablock_t &db)
{
db.write(os);
return os;
}
// friend std::ostream &operator<<(std::ostream &os, const datablock &db)
// {
// db.write(os);
// return os;
// }
private:
category_type_list m_categories;
category_list m_categories;
std::string m_name;
};
using datablock = datablock_t<>;
} // namespace cif::v2
\ No newline at end of file
......@@ -36,20 +36,10 @@ namespace cif::v2
// --------------------------------------------------------------------
template <
typename Alloc,
typename Datablock,
typename Category>
class file_t
class file
{
public:
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 datablock_list = std::list<datablock>;
using value_type = datablock_list::value_type;
using reference = datablock_list::reference;
......@@ -58,29 +48,21 @@ class file_t
using iterator = datablock_list::iterator;
using const_iterator = datablock_list::const_iterator;
using parser_type = parser_t<allocator_type, file_t, datablock_type, category_type>;
file_t() = default;
file() = 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)
file(std::istream &is)
{
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;
file(const file &) = default;
file(file &&) = default;
file &operator=(const file &) = default;
file &operator=(file &&) = default;
datablock_type &operator[](std::string_view name)
datablock &operator[](std::string_view name)
{
auto i = std::find_if(m_datablocks.begin(), m_datablocks.end(), [name](const datablock_type &c)
auto i = std::find_if(m_datablocks.begin(), m_datablocks.end(), [name](const datablock &c)
{ return iequals(c.name(), name); });
if (i != m_datablocks.end())
......@@ -90,10 +72,10 @@ class file_t
return m_datablocks.back();
}
const datablock_type &operator[](std::string_view name) const
const datablock &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)
static const datablock s_empty;
auto i = std::find_if(m_datablocks.begin(), m_datablocks.end(), [name](const datablock &c)
{ return iequals(c.name(), name); });
return i == m_datablocks.end() ? s_empty : *i;
}
......@@ -133,14 +115,12 @@ class file_t
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);
parser p(is, *this);
p.parse_file();
// if (saved != nullptr)
......@@ -152,8 +132,7 @@ class file_t
private:
datablock_list m_datablocks;
std::unique_ptr<Validator> m_validator;
};
using file = file_t<>;
}
\ No newline at end of file
......@@ -26,21 +26,27 @@
#pragma once
#include <memory>
#include <string>
#include <vector>
namespace cif::v2
{
template <typename Alloc = std::allocator<void>>
class category_t;
class category;
class datablock;
class file;
class parser;
template <typename Alloc = std::allocator<void>, typename Category = category_t<Alloc>>
class datablock_t;
class row;
class row_handle;
template <typename Alloc = std::allocator<void>, typename Datablock = datablock_t<Alloc>, typename Category = typename Datablock::category_type>
class file_t;
class item;
class item_handle;
// --------------------------------------------------------------------
// let's make life easier
std::vector<std::string> get_category_fields(const category &cat);
template <typename Alloc = std::allocator<void>, typename File = file_t<Alloc>, typename Datablock = datablock_t<Alloc>, typename Category = typename Datablock::category_type>
class parser_t;
} // namespace cif::v2
\ No newline at end of file
......@@ -29,12 +29,15 @@
#include <charconv>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <limits>
#include <memory>
#include <optional>
#include <cif++/CifUtils.hpp>
#include <cif++/v2/forward_decl.hpp>
namespace cif
{
extern int VERBOSE;
......@@ -80,7 +83,7 @@ class item
auto r = cif::to_chars(m_buffer, m_buffer + sizeof(m_buffer) - 1, value, cif::chars_format::general);
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);
......@@ -138,13 +141,55 @@ class item
};
// --------------------------------------------------------------------
/// \brief the internal storage for items in a category
///
/// Internal storage, strictly forward linked list with minimal space
/// requirements. Strings of size 7 or shorter are stored internally.
/// Typically, more than 99% of the strings in an mmCIF file are less
/// than 8 bytes in length.
struct item_value
{
item_value(uint16_t column_ix, uint16_t length)
: m_next(nullptr)
, m_column_ix(column_ix)
, m_length(length)
{
}
item_value() = delete;
item_value(const item_value &) = delete;
item_value &operator=(const item_value &) = delete;
item_value *m_next;
uint16_t m_column_ix;
uint16_t m_length;
union
{
char m_local_data[8];
char *m_data;
};
static constexpr size_t kBufferSize = sizeof(m_local_data);
std::string_view text() const
{
return {m_length >= kBufferSize ? m_data : m_local_data, m_length};
}
const char *c_str() const
{
return m_length >= kBufferSize ? m_data : m_local_data;
}
};
static_assert(sizeof(item_value) == 24, "sizeof(item_value) should be 24 bytes");
// --------------------------------------------------------------------
// Transient object to access stored data
template <typename RowHandle>
struct item_handle
{
using row_handle_type = RowHandle;
public:
// conversion helper class
template <typename T, typename = void>
......@@ -158,29 +203,6 @@ struct item_handle
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;
// }
// 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)
{
......@@ -199,7 +221,7 @@ struct item_handle
}
template <typename T>
auto value_or(const T &dv)
auto value_or(const T &dv) const
{
return empty() ? dv : this->as<T>();
}
......@@ -244,21 +266,12 @@ struct item_handle
// return s_empty_result;
// }
std::string_view text() const
{
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();
}
return {};
}
std::string_view text() const;
// 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_handle_type &row)
item_handle(uint16_t column, row_handle &row)
: m_column(column)
, m_row_handle(row)
{
......@@ -266,17 +279,15 @@ struct item_handle
private:
uint16_t m_column;
row_handle_type &m_row_handle;
// bool mConst = false;
row_handle &m_row_handle;
static constexpr const char *s_empty_result = "";
};
// So sad that the gcc implementation of from_chars does not support floats yet...
template <typename Row>
template <typename T>
struct item_handle<Row>::item_value_as<T, std::enable_if_t<std::is_arithmetic_v<T>>>
struct item_handle::item_value_as<T, std::enable_if_t<std::is_arithmetic_v<T>>>
{
using value_type = std::remove_reference_t<std::remove_cv_t<T>>;
......@@ -348,9 +359,8 @@ struct item_handle<Row>::item_value_as<T, std::enable_if_t<std::is_arithmetic_v<
}
};
template <typename Row>
template <typename T>
struct item_handle<Row>::item_value_as<std::optional<T>>
struct item_handle::item_value_as<std::optional<T>>
{
static std::optional<T> convert(const item_handle &ref)
{
......@@ -374,9 +384,8 @@ struct item_handle<Row>::item_value_as<std::optional<T>>
}
};
template <typename Row>
template <typename T>
struct item_handle<Row>::item_value_as<T, std::enable_if_t<std::is_same_v<T, bool>>>
struct item_handle::item_value_as<T, std::enable_if_t<std::is_same_v<T, bool>>>
{
static bool convert(const item_handle &ref)
{
......@@ -394,9 +403,8 @@ struct item_handle<Row>::item_value_as<T, std::enable_if_t<std::is_same_v<T, boo
}
};
template <typename Row>
template <size_t N>
struct item_handle<Row>::item_value_as<char[N]>
struct item_handle::item_value_as<char[N]>
{
// static std::string_view convert(const item_handle &ref)
// {
......@@ -409,9 +417,8 @@ struct item_handle<Row>::item_value_as<char[N]>
}
};
template <typename Row>
template <typename T>
struct item_handle<Row>::item_value_as<T, std::enable_if_t<std::is_same_v<T, const char *>>>
struct item_handle::item_value_as<T, std::enable_if_t<std::is_same_v<T, const char *>>>
{
// static std::string_view convert(const item_handle &ref)
// {
......@@ -424,14 +431,13 @@ struct item_handle<Row>::item_value_as<T, std::enable_if_t<std::is_same_v<T, con
}
};
template <typename Row>
template <typename T>
struct item_handle<Row>::item_value_as<T, std::enable_if_t<std::is_same_v<T, std::string>>>
struct item_handle::item_value_as<T, std::enable_if_t<std::is_same_v<T, std::string>>>
{
static std::string convert(const item_handle &ref)
{
std::string_view txt = ref.text();
return { txt.data(), txt.size() };
return {txt.data(), txt.size()};
}
static int compare(const item_handle &ref, const std::string &value, bool icase)
......
......@@ -40,26 +40,24 @@ class iterator_impl
template <typename, typename...>
friend class iterator_impl;
template <typename>
friend class category_t;
friend class category;
static constexpr size_t N = sizeof...(Ts);
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 row_handle_type = std::conditional_t<std::is_const_v<category_type>, const row_handle<category_type>, row_handle<category_type>>;
using category_type = std::remove_cv_t<Category>;
using row_type = std::conditional_t<std::is_const_v<Category>, const row, row>;
using iterator_category = std::forward_iterator_tag;
using value_type = std::conditional_t<N == 0, row_handle_type, std::tuple<Ts...>>;
using value_type = std::conditional_t<N == 0, row_handle, std::tuple<Ts...>>;
using difference_type = std::ptrdiff_t;
using pointer = std::conditional_t<N == 0, row_handle_type, value_type *>;
using reference = std::conditional_t<N == 0, row_handle_type, value_type &>;
using pointer = std::conditional_t<N == 0, row_handle, value_type *>;
using reference = std::conditional_t<N == 0, row_handle, value_type &>;
iterator_impl() = default;
iterator_impl(const iterator_impl &rhs) = default;
template<typename C2, typename... T2s>
template <typename C2, typename... T2s>
iterator_impl(const iterator_impl<C2, T2s...> &rhs)
: m_category(rhs.m_category)
, m_current(rhs.m_current)
......@@ -68,10 +66,10 @@ class iterator_impl
{
}
iterator_impl(category_type &cat, row_type *current)
: m_category(&cat)
iterator_impl(Category &cat, row *current)
: m_category(const_cast<category_type *>(&cat))
, m_current(current)
, m_value(cat, *current)
, m_value(*m_category, *current)
{
static_assert(N == 0, "Only valid if this is a row iterator, not a row<xxx> iterator");
}
......@@ -139,10 +137,15 @@ class iterator_impl
return &m_value;
}
row_type row() const
{
return m_current;
}
// const row_type *get_row() const
// {
// return m_current;
// }
// row_type *get_row()
// {
// return m_current;
// }
iterator_impl &operator++()
{
......@@ -183,7 +186,7 @@ class iterator_impl
{
if (m_current != nullptr)
{
row_handle_type rh{*m_category, *m_current};
row_handle rh{*m_category, *m_current};
return std::tuple<Ts...>{rh[m_column_ix[Is]].template as<Ts>()...};
}
......@@ -206,8 +209,7 @@ class iterator_proxy
static constexpr const size_t N = sizeof...(Ts);
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 row_handle_type = std::conditional_t<std::is_const_v<category_type>, const row_handle<category_type>, row_handle<category_type>>;
using row_type = std::conditional_t<std::is_const_v<category_type>, const row, row>;
using iterator = iterator_impl<category_type, Ts...>;
using row_iterator = iterator_impl<category_type>;
......@@ -230,8 +232,8 @@ class iterator_proxy
size_t size() const { return std::distance(begin(), end()); }
row_type front() { return *begin(); }
row_type back() { return *(std::prev(end())); }
// row front() { return *begin(); }
// row back() { return *(std::prev(end())); }
category_type &category() const { return *m_category; }
......@@ -249,114 +251,116 @@ class iterator_proxy
std::array<size_t, N> m_column_ix;
};
// // --------------------------------------------------------------------
// // conditional iterator proxy
// --------------------------------------------------------------------
// conditional iterator proxy
// template <typename CategoryType, typename... Ts>
// class conditional_iterator_proxy
// {
// public:
// static constexpr const size_t N = sizeof...(Ts);
template <typename CategoryType, typename... Ts>
class conditional_iterator_proxy
{
public:
static constexpr const size_t N = sizeof...(Ts);
// using base_iterator = iterator_impl<CategoryType, Ts...>;
// using value_type = typename base_iterator::value_type;
// using row_type = typename base_iterator::row_type;
// using row_iterator = iterator_impl<row_type>;
using category_type = std::remove_cv_t<CategoryType>;
// class conditional_iterator_impl
// {
// public:
// using iterator_category = std::forward_iterator_tag;
// using value_type = conditional_iterator_proxy::value_type;
// using difference_type = std::ptrdiff_t;
// using pointer = value_type *;
// using reference = value_type &;
using base_iterator = iterator_impl<CategoryType, Ts...>;
using value_type = typename base_iterator::value_type;
using row_type = typename base_iterator::row_type;
using row_iterator = iterator_impl<CategoryType>;
// 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;
// conditional_iterator_impl &operator=(const conditional_iterator_impl &i) = default;
class conditional_iterator_impl
{
public:
using iterator_category = std::forward_iterator_tag;
using value_type = conditional_iterator_proxy::value_type;
using difference_type = std::ptrdiff_t;
using pointer = value_type *;
using reference = row_handle;
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;
conditional_iterator_impl &operator=(const conditional_iterator_impl &i) = default;
// virtual ~conditional_iterator_impl() = default;
virtual ~conditional_iterator_impl() = default;
// reference operator*()
// {
// return *mBegin;
// }
reference operator*()
{
return *mBegin;
}
// pointer operator->()
// {
// return &*mBegin;
// }
pointer operator->()
{
return &*mBegin;
}
// conditional_iterator_impl &operator++()
// {
// while (mBegin != mEnd)
// {
// if (++mBegin == mEnd)
// break;
conditional_iterator_impl &operator++()
{
while (mBegin != mEnd)
{
if (++mBegin == mEnd)
break;
// if ((*mCondition)(*mCat, mBegin.row()))
// break;
// }
if ((*m_condition)(*mBegin))
break;
}
// return *this;
// }
return *this;
}
// conditional_iterator_impl operator++(int)
// {
// conditional_iterator_impl result(*this);
// this->operator++();
// return result;
// }
conditional_iterator_impl operator++(int)
{
conditional_iterator_impl result(*this);
this->operator++();
return result;
}
// bool operator==(const conditional_iterator_impl &rhs) const { return mBegin == rhs.mBegin; }
// bool operator!=(const conditional_iterator_impl &rhs) const { return mBegin != rhs.mBegin; }
bool operator==(const conditional_iterator_impl &rhs) const { return mBegin == rhs.mBegin; }
bool operator!=(const conditional_iterator_impl &rhs) const { return mBegin != rhs.mBegin; }
// template <typename IRowType, typename... ITs>
// bool operator==(const iterator_impl<IRowType, ITs...> &rhs) const { return mBegin == rhs; }
template <typename IRowType, typename... ITs>
bool operator==(const iterator_impl<IRowType, ITs...> &rhs) const { return mBegin == rhs; }
// template <typename IRowType, typename... ITs>
// bool operator!=(const iterator_impl<IRowType, ITs...> &rhs) const { return mBegin != rhs; }
template <typename IRowType, typename... ITs>
bool operator!=(const iterator_impl<IRowType, ITs...> &rhs) const { return mBegin != rhs; }
// private:
// CategoryType *mCat;
// base_iterator mBegin, mEnd;
// const Condition *mCondition;
// };
private:
CategoryType *mCat;
base_iterator mBegin, mEnd;
const condition *m_condition;
};
// using iterator = conditional_iterator_impl;
// using reference = typename iterator::reference;
using iterator = conditional_iterator_impl;
using reference = typename iterator::reference;
// template <typename... Ns>
// conditional_iterator_proxy(CategoryType &cat, row_iterator pos, Condition &&cond, Ns... names);
template <typename... Ns>
conditional_iterator_proxy(CategoryType &cat, row_iterator pos, condition &&cond, Ns... names);
// conditional_iterator_proxy(conditional_iterator_proxy &&p);
// conditional_iterator_proxy &operator=(conditional_iterator_proxy &&p);
conditional_iterator_proxy(conditional_iterator_proxy &&p);
conditional_iterator_proxy &operator=(conditional_iterator_proxy &&p);
// conditional_iterator_proxy(const conditional_iterator_proxy &) = delete;
// conditional_iterator_proxy &operator=(const conditional_iterator_proxy &) = delete;
conditional_iterator_proxy(const conditional_iterator_proxy &) = delete;
conditional_iterator_proxy &operator=(const conditional_iterator_proxy &) = delete;
// iterator begin() const;
// iterator end() const;
iterator begin() const;
iterator end() const;
// bool empty() const;
bool empty() const;
// explicit operator bool() const { return not empty(); }
explicit operator bool() const { return not empty(); }
// size_t size() const { return std::distance(begin(), end()); }
size_t size() const { return std::distance(begin(), end()); }
// row_type front() { return *begin(); }
// row front() { return *begin(); }
// CategoryType &category() const { return *mCat; }
CategoryType &category() const { return *mCat; }
// void swap(conditional_iterator_proxy &rhs);
void swap(conditional_iterator_proxy &rhs);
// private:
// CategoryType *mCat;
// Condition mCondition;
// row_iterator mCBegin, mCEnd;
// std::array<size_t, N> mCix;
// };
private:
CategoryType *mCat;
condition m_condition;
row_iterator mCBegin, mCEnd;
std::array<size_t, N> mCix;
};
// --------------------------------------------------------------------
......@@ -385,80 +389,80 @@ iterator_proxy<Category, Ts...>::iterator_proxy(Category &cat, row_iterator pos,
// --------------------------------------------------------------------
// template <typename Category, typename... Ts>
// conditional_iterator_proxy<Category, Ts...>::conditional_iterator_impl::conditional_iterator_impl(
// Category &cat, row_iterator pos, const Condition &cond, const std::array<size_t, N> &cix)
// : mCat(&cat)
// , mBegin(pos, cix)
// , mEnd(cat.end(), cix)
// , mCondition(&cond)
// {
// }
// template <typename Category, typename... Ts>
// conditional_iterator_proxy<Category, Ts...>::conditional_iterator_proxy(conditional_iterator_proxy &&p)
// : mCat(nullptr)
// , mCBegin(p.mCBegin)
// , mCEnd(p.mCEnd)
// , mCix(p.mCix)
// {
// std::swap(mCat, p.mCat);
// std::swap(mCix, p.mCix);
// mCondition.swap(p.mCondition);
// }
// template <typename Category, typename... Ts>
// template <typename... Ns>
// conditional_iterator_proxy<Category, Ts...>::conditional_iterator_proxy(Category &cat, row_iterator pos, Condition &&cond, Ns... names)
// : mCat(&cat)
// , mCondition(std::move(cond))
// , mCBegin(pos)
// , mCEnd(cat.end())
// {
// static_assert(sizeof...(Ts) == sizeof...(Ns), "Number of column names should be equal to number of requested value types");
// mCondition.prepare(cat);
// while (mCBegin != mCEnd and not mCondition(*mCat, mCBegin.row()))
// ++mCBegin;
// size_t i = 0;
// ((mCix[i++] = mCat->getColumnIndex(names)), ...);
// }
// template <typename Category, typename... Ts>
// conditional_iterator_proxy<Category, Ts...> &conditional_iterator_proxy<Category, Ts...>::operator=(conditional_iterator_proxy &&p)
// {
// swap(p);
// return *this;
// }
// template <typename Category, typename... Ts>
// typename conditional_iterator_proxy<Category, Ts...>::iterator conditional_iterator_proxy<Category, Ts...>::begin() const
// {
// return iterator(*mCat, mCBegin, mCondition, mCix);
// }
// template <typename Category, typename... Ts>
// typename conditional_iterator_proxy<Category, Ts...>::iterator conditional_iterator_proxy<Category, Ts...>::end() const
// {
// return iterator(*mCat, mCEnd, mCondition, mCix);
// }
// template <typename Category, typename... Ts>
// bool conditional_iterator_proxy<Category, Ts...>::empty() const
// {
// return mCBegin == mCEnd;
// }
// template <typename Category, typename... Ts>
// void conditional_iterator_proxy<Category, Ts...>::swap(conditional_iterator_proxy &rhs)
// {
// std::swap(mCat, rhs.mCat);
// mCondition.swap(rhs.mCondition);
// std::swap(mCBegin, rhs.mCBegin);
// std::swap(mCEnd, rhs.mCEnd);
// std::swap(mCix, rhs.mCix);
// }
template <typename Category, typename... Ts>
conditional_iterator_proxy<Category, Ts...>::conditional_iterator_impl::conditional_iterator_impl(
Category &cat, row_iterator pos, const condition &cond, const std::array<size_t, N> &cix)
: mCat(&cat)
, mBegin(pos, cix)
, mEnd(cat.end(), cix)
, m_condition(&cond)
{
}
template <typename Category, typename... Ts>
conditional_iterator_proxy<Category, Ts...>::conditional_iterator_proxy(conditional_iterator_proxy &&p)
: mCat(nullptr)
, mCBegin(p.mCBegin)
, mCEnd(p.mCEnd)
, mCix(p.mCix)
{
std::swap(mCat, p.mCat);
std::swap(mCix, p.mCix);
m_condition.swap(p.m_condition);
}
template <typename Category, typename... Ts>
template <typename... Ns>
conditional_iterator_proxy<Category, Ts...>::conditional_iterator_proxy(Category &cat, row_iterator pos, condition &&cond, Ns... names)
: mCat(&cat)
, m_condition(std::move(cond))
, mCBegin(pos)
, mCEnd(cat.end())
{
static_assert(sizeof...(Ts) == sizeof...(Ns), "Number of column names should be equal to number of requested value types");
m_condition.prepare(cat);
while (mCBegin != mCEnd and not m_condition(*mCBegin))
++mCBegin;
size_t i = 0;
((mCix[i++] = mCat->getColumnIndex(names)), ...);
}
template <typename Category, typename... Ts>
conditional_iterator_proxy<Category, Ts...> &conditional_iterator_proxy<Category, Ts...>::operator=(conditional_iterator_proxy &&p)
{
swap(p);
return *this;
}
template <typename Category, typename... Ts>
typename conditional_iterator_proxy<Category, Ts...>::iterator conditional_iterator_proxy<Category, Ts...>::begin() const
{
return iterator(*mCat, mCBegin, m_condition, mCix);
}
template <typename Category, typename... Ts>
typename conditional_iterator_proxy<Category, Ts...>::iterator conditional_iterator_proxy<Category, Ts...>::end() const
{
return iterator(*mCat, mCEnd, m_condition, mCix);
}
template <typename Category, typename... Ts>
bool conditional_iterator_proxy<Category, Ts...>::empty() const
{
return mCBegin == mCEnd;
}
template <typename Category, typename... Ts>
void conditional_iterator_proxy<Category, Ts...>::swap(conditional_iterator_proxy &rhs)
{
std::swap(mCat, rhs.mCat);
m_condition.swap(rhs.m_condition);
std::swap(mCBegin, rhs.mCBegin);
std::swap(mCEnd, rhs.mCEnd);
std::swap(mCix, rhs.mCix);
}
} // namespace cif::v2
\ No newline at end of file
......@@ -26,19 +26,7 @@
#pragma once
#include <cassert>
#include <iostream>
#include <map>
#include <stack>
#include <regex>
#include <cif++/v2/forward_decl.hpp>
#include <cif++/CifUtils.hpp>
namespace cif
{
extern int VERBOSE;
}
#include <cif++/v2/row.hpp>
namespace cif::v2
{
......@@ -61,16 +49,7 @@ class sac_parser
public:
using datablock_index = std::map<std::string, std::size_t>;
sac_parser(std::istream &is, bool init = true)
: m_source(is)
{
m_validate = true;
m_line_nr = 1;
m_bol = true;
if (init)
m_lookahead = get_next_token();
}
sac_parser(std::istream &is, bool init = true);
virtual ~sac_parser() = default;
......@@ -201,719 +180,31 @@ class sac_parser
// get_next_char takes a char from the buffer, or if it is empty
// from the istream. This function also does carriage/linefeed
// translation.
int get_next_char()
{
int result;
if (m_buffer.empty())
result = m_source.get();
else
{
result = m_buffer.top();
m_buffer.pop();
}
// very simple CR/LF translation into LF
if (result == '\r')
{
int lookahead = m_source.get();
if (lookahead != '\n')
m_buffer.push(lookahead);
result = '\n';
}
m_token_value += static_cast<char>(result);
int get_next_char();
if (result == '\n')
++m_line_nr;
if (VERBOSE >= 6)
{
std::cerr << "get_next_char => ";
if (iscntrl(result) or not isprint(result))
std::cerr << int(result) << std::endl;
else
std::cerr << char(result) << std::endl;
}
return result;
}
void retract()
{
assert(not m_token_value.empty());
void retract();
char ch = m_token_value.back();
if (ch == '\n')
--m_line_nr;
m_buffer.push(ch);
m_token_value.pop_back();
}
int restart(int start)
{
int result = 0;
while (not m_token_value.empty())
retract();
switch (start)
{
case State::Start:
result = State::Float;
break;
case State::Float:
result = State::Int;
break;
case State::Int:
result = State::Value;
break;
default:
error("Invalid state in SacParser");
}
m_bol = false;
return result;
}
CIFToken get_next_token()
{
const auto kEOF = std::char_traits<char>::eof();
CIFToken result = CIFToken::Unknown;
int quoteChar = 0;
int state = State::Start, start = State::Start;
m_bol = false;
m_token_value.clear();
mTokenType = CIFValue::Unknown;
while (result == CIFToken::Unknown)
{
auto ch = get_next_char();
int restart(int start);
switch (state)
{
case State::Start:
if (ch == kEOF)
result = CIFToken::Eof;
else if (ch == '\n')
{
m_bol = true;
state = State::White;
}
else if (ch == ' ' or ch == '\t')
state = State::White;
else if (ch == '#')
state = State::Comment;
else if (ch == '_')
state = State::Tag;
else if (ch == ';' and m_bol)
state = State::TextField;
else if (ch == '\'' or ch == '"')
{
quoteChar = ch;
state = State::QuotedString;
}
else
state = start = restart(start);
break;
CIFToken get_next_token();
case State::White:
if (ch == kEOF)
result = CIFToken::Eof;
else if (not isspace(ch))
{
state = State::Start;
retract();
m_token_value.clear();
}
else
m_bol = (ch == '\n');
break;
case State::Comment:
if (ch == '\n')
{
state = State::Start;
m_bol = true;
m_token_value.clear();
}
else if (ch == kEOF)
result = CIFToken::Eof;
else if (not is_any_print(ch))
error("invalid character in comment");
break;
case State::TextField:
if (ch == '\n')
state = State::TextField + 1;
else if (ch == kEOF)
error("unterminated textfield");
else if (not is_any_print(ch))
warning("invalid character in text field '" + std::string({static_cast<char>(ch)}) + "' (" + std::to_string((int)ch) + ")");
break;
case State::TextField + 1:
if (is_text_lead(ch) or ch == ' ' or ch == '\t')
state = State::TextField;
else if (ch == ';')
{
assert(m_token_value.length() >= 2);
m_token_value = m_token_value.substr(1, m_token_value.length() - 3);
mTokenType = CIFValue::TextField;
result = CIFToken::Value;
}
else if (ch == kEOF)
error("unterminated textfield");
else if (ch != '\n')
error("invalid character in text field");
break;
case State::QuotedString:
if (ch == kEOF)
error("unterminated quoted string");
else if (ch == quoteChar)
state = State::QuotedStringQuote;
else if (not is_any_print(ch))
warning("invalid character in quoted string: '" + std::string({static_cast<char>(ch)}) + '\'');
break;
case State::QuotedStringQuote:
if (is_white(ch))
{
retract();
result = CIFToken::Value;
mTokenType = CIFValue::String;
if (m_token_value.length() < 2)
error("Invalid quoted string token");
m_token_value = m_token_value.substr(1, m_token_value.length() - 2);
}
else if (ch == quoteChar)
;
else if (is_any_print(ch))
state = State::QuotedString;
else if (ch == kEOF)
error("unterminated quoted string");
else
error("invalid character in quoted string");
break;
case State::Tag:
if (not is_non_blank(ch))
{
retract();
result = CIFToken::Tag;
}
break;
case State::Float:
if (ch == '+' or ch == '-')
{
state = State::Float + 1;
}
else if (isdigit(ch))
state = State::Float + 1;
else
state = start = restart(start);
break;
case State::Float + 1:
// if (ch == '(') // numeric???
// mState = State::NumericSuffix;
// else
if (ch == '.')
state = State::Float + 2;
else if (tolower(ch) == 'e')
state = State::Float + 3;
else if (is_white(ch) or ch == kEOF)
{
retract();
result = CIFToken::Value;
mTokenType = CIFValue::Int;
}
else
state = start = restart(start);
break;
// parsed '.'
case State::Float + 2:
if (tolower(ch) == 'e')
state = State::Float + 3;
else if (is_white(ch) or ch == kEOF)
{
retract();
result = CIFToken::Value;
mTokenType = CIFValue::Float;
}
else
state = start = restart(start);
break;
// parsed 'e'
case State::Float + 3:
if (ch == '-' or ch == '+')
state = State::Float + 4;
else if (isdigit(ch))
state = State::Float + 5;
else
state = start = restart(start);
break;
case State::Float + 4:
if (isdigit(ch))
state = State::Float + 5;
else
state = start = restart(start);
break;
case State::Float + 5:
if (is_white(ch) or ch == kEOF)
{
retract();
result = CIFToken::Value;
mTokenType = CIFValue::Float;
}
else
state = start = restart(start);
break;
case State::Int:
if (isdigit(ch) or ch == '+' or ch == '-')
state = State::Int + 1;
else
state = start = restart(start);
break;
case State::Int + 1:
if (is_white(ch) or ch == kEOF)
{
retract();
result = CIFToken::Value;
mTokenType = CIFValue::Int;
}
else
state = start = restart(start);
break;
case State::Value:
if (ch == '_')
{
std::string s = toLowerCopy(m_token_value);
if (s == "global_")
result = CIFToken::GLOBAL;
else if (s == "stop_")
result = CIFToken::STOP;
else if (s == "loop_")
result = CIFToken::LOOP;
else if (s == "data_")
{
state = State::DATA;
continue;
}
else if (s == "save_")
{
state = State::SAVE;
continue;
}
}
if (result == CIFToken::Unknown and not is_non_blank(ch))
{
retract();
result = CIFToken::Value;
if (m_token_value == ".")
mTokenType = CIFValue::Inapplicable;
else if (m_token_value == "?")
{
mTokenType = CIFValue::Unknown;
m_token_value.clear();
}
}
break;
case State::DATA:
case State::SAVE:
if (not is_non_blank(ch))
{
retract();
if (state == State::DATA)
result = CIFToken::DATA;
else
result = CIFToken::SAVE;
m_token_value.erase(m_token_value.begin(), m_token_value.begin() + 5);
}
break;
default:
assert(false);
error("Invalid state in get_next_token");
break;
}
}
if (VERBOSE >= 5)
{
std::cerr << get_token_name(result);
if (mTokenType != CIFValue::Unknown)
std::cerr << ' ' << get_value_name(mTokenType);
if (result != CIFToken::Eof)
std::cerr << " " << std::quoted(m_token_value);
std::cerr << std::endl;
}
return result;
}
void match(CIFToken token)
{
if (m_lookahead != token)
error(std::string("Unexpected token, expected ") + get_token_name(token) + " but found " + get_token_name(m_lookahead));
m_lookahead = get_next_token();
}
void match(CIFToken token);
public:
bool parse_single_datablock(const std::string &datablock)
{
// first locate the start, as fast as we can
auto &sb = *m_source.rdbuf();
enum
{
start,
comment,
string,
string_quote,
qstring,
data
} state = start;
int quote = 0;
bool bol = true;
std::string dblk = "data_" + datablock;
std::string::size_type si = 0;
bool found = false;
for (auto ch = sb.sbumpc(); not found and ch != std::streambuf::traits_type::eof(); ch = sb.sbumpc())
{
switch (state)
{
case start:
switch (ch)
{
case '#': state = comment; break;
case 'd':
case 'D':
state = data;
si = 1;
break;
case '\'':
case '"':
state = string;
quote = ch;
break;
case ';':
if (bol)
state = qstring;
break;
}
break;
case comment:
if (ch == '\n')
state = start;
break;
bool parse_single_datablock(const std::string &datablock);
case string:
if (ch == quote)
state = string_quote;
break;
datablock_index index_datablocks();
case string_quote:
if (std::isspace(ch))
state = start;
else
state = string;
break;
bool parse_single_datablock(const std::string &datablock, const datablock_index &index);
case qstring:
if (ch == ';' and bol)
state = start;
break;
case data:
if (isspace(ch) and dblk[si] == 0)
found = true;
else if (dblk[si++] != ch)
state = start;
break;
}
bol = (ch == '\n');
}
if (found)
{
produce_datablock(datablock);
m_lookahead = get_next_token();
parse_datablock();
}
return found;
}
datablock_index index_datablocks()
{
datablock_index index;
// first locate the start, as fast as we can
auto &sb = *m_source.rdbuf();
enum
{
start,
comment,
string,
string_quote,
qstring,
data,
data_name
} state = start;
int quote = 0;
bool bol = true;
const char dblk[] = "data_";
std::string::size_type si = 0;
std::string datablock;
for (auto ch = sb.sbumpc(); ch != std::streambuf::traits_type::eof(); ch = sb.sbumpc())
{
switch (state)
{
case start:
switch (ch)
{
case '#': state = comment; break;
case 'd':
case 'D':
state = data;
si = 1;
break;
case '\'':
case '"':
state = string;
quote = ch;
break;
case ';':
if (bol)
state = qstring;
break;
}
break;
case comment:
if (ch == '\n')
state = start;
break;
case string:
if (ch == quote)
state = string_quote;
break;
case string_quote:
if (std::isspace(ch))
state = start;
else
state = string;
break;
case qstring:
if (ch == ';' and bol)
state = start;
break;
case data:
if (dblk[si] == 0 and is_non_blank(ch))
{
datablock = {static_cast<char>(ch)};
state = data_name;
}
else if (dblk[si++] != ch)
state = start;
break;
case data_name:
if (is_non_blank(ch))
datablock.insert(datablock.end(), char(ch));
else if (isspace(ch))
{
if (not datablock.empty())
index[datablock] = m_source.tellg();
state = start;
}
else
state = start;
break;
}
bol = (ch == '\n');
}
return index;
}
bool parse_single_datablock(const std::string &datablock, const datablock_index &index)
{
bool result = false;
auto i = index.find(datablock);
if (i != index.end())
{
m_source.seekg(i->second);
produce_datablock(datablock);
m_lookahead = get_next_token();
parse_datablock();
result = true;
}
return result;
}
void parse_file()
{
while (m_lookahead != CIFToken::Eof)
{
switch (m_lookahead)
{
case CIFToken::GLOBAL:
parse_global();
break;
case CIFToken::DATA:
produce_datablock(m_token_value);
match(CIFToken::DATA);
parse_datablock();
break;
default:
error("This file does not seem to be an mmCIF file");
break;
}
}
}
void parse_file();
protected:
void parse_global()
{
match(CIFToken::GLOBAL);
while (m_lookahead == CIFToken::Tag)
{
match(CIFToken::Tag);
match(CIFToken::Value);
}
}
void parse_datablock()
{
std::string cat;
while (m_lookahead == CIFToken::LOOP or m_lookahead == CIFToken::Tag or m_lookahead == CIFToken::SAVE)
{
switch (m_lookahead)
{
case CIFToken::LOOP:
{
cat.clear(); // should start a new category
match(CIFToken::LOOP);
std::vector<std::string> tags;
while (m_lookahead == CIFToken::Tag)
{
std::string catName, itemName;
std::tie(catName, itemName) = splitTagName(m_token_value);
if (cat.empty())
{
produce_category(catName);
cat = catName;
}
else if (not iequals(cat, catName))
error("inconsistent categories in loop_");
tags.push_back(itemName);
match(CIFToken::Tag);
}
while (m_lookahead == CIFToken::Value)
{
produce_row();
for (auto tag : tags)
{
produce_item(cat, tag, m_token_value);
match(CIFToken::Value);
}
}
cat.clear();
break;
}
case CIFToken::Tag:
{
std::string catName, itemName;
std::tie(catName, itemName) = splitTagName(m_token_value);
if (not iequals(cat, catName))
{
produce_category(catName);
cat = catName;
produce_row();
}
void parse_global();
match(CIFToken::Tag);
void parse_datablock();
produce_item(cat, itemName, m_token_value);
match(CIFToken::Value);
break;
}
case CIFToken::SAVE:
parse_save_frame();
break;
default:
assert(false);
break;
}
}
}
virtual void parse_save_frame()
{
error("A regular CIF file should not contain a save frame");
}
virtual void parse_save_frame();
void error(const std::string &msg)
{
......@@ -966,61 +257,28 @@ class sac_parser
// --------------------------------------------------------------------
template <typename Alloc, typename File, typename Datablock, typename Category>
class parser_t : public sac_parser
class parser : public sac_parser
{
public:
using file_type = File;
using datablock_type = Datablock;
using category_type = Category;
using row_handle_type = category_type::reference;
parser_t(std::istream &is, file_type &file)
parser(std::istream &is, file &file)
: sac_parser(is)
, m_file(file)
{
}
void produce_datablock(const std::string &name) override
{
const auto &[iter, ignore] = m_file.emplace(name);
m_datablock = &(*iter);
}
void produce_datablock(const std::string &name) override;
void produce_category(const std::string &name) override
{
if (VERBOSE >= 4)
std::cerr << "producing category " << name << std::endl;
std::tie(m_category, std::ignore) = m_datablock->emplace(name);
}
void produce_row() override
{
if (VERBOSE >= 4)
std::cerr << "producing row for category " << m_category->name() << std::endl;
void produce_category(const std::string &name) override;
m_category->emplace({});
m_row = m_category->back();
// m_row.lineNr(m_line_nr);
}
void produce_item(const std::string &category, const std::string &item, const std::string &value) override
{
if (VERBOSE >= 4)
std::cerr << "producing _" << category << '.' << item << " -> " << value << std::endl;
void produce_row() override;
if (not iequals(category, m_category->name()))
error("inconsistent categories in loop_");
m_row[item] = m_token_value;
}
void produce_item(const std::string &category, const std::string &item, const std::string &value) override;
protected:
file_type &m_file;
datablock_type *m_datablock;
datablock_type::iterator m_category;
row_handle_type m_row;
file &m_file;
datablock *m_datablock = nullptr;
category *m_category = nullptr;
row_handle m_row;
};
} // namespace cif::v2
......@@ -27,37 +27,26 @@
#pragma once
#include <cif++/v2/item.hpp>
#include <cif++/v2/condition.hpp>
namespace cif::v2
{
template <typename>
class row_handle;
namespace detail
{
// some helper classes to help create tuple result types
template <
typename Category,
typename... C>
template <typename... C>
struct get_row_result
{
using category_type = Category;
using row_type = category_type::row;
using row_handle_type = row_handle<category_type>;
using item_handle_type = item_handle<row_type>;
static constexpr size_t N = sizeof...(C);
get_row_result(const row_handle_type &r, std::array<size_t, N> &&columns)
get_row_result(const row_handle &r, std::array<size_t, N> &&columns)
: m_row(r)
, m_columns(std::move(columns))
{
}
const item_handle_type operator[](size_t ix) const
const item_handle operator[](size_t ix) const
{
return m_row[m_columns[ix]];
}
......@@ -74,7 +63,7 @@ namespace detail
return std::tuple<Ts...>{m_row[m_columns[Is]].template as<Ts>()...};
}
const row_handle_type &m_row;
const row_handle &m_row;
std::array<size_t, N> m_columns;
};
......@@ -112,21 +101,39 @@ auto tie(Ts &...v)
}
// --------------------------------------------------------------------
/// \brief row_handle is the way to access data in rows
/// \brief the row class, this one is not directly accessible from the outside
template <typename Category>
class row_handle
class row
{
public:
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>;
row() = default;
using item_handle_type = item_handle<row_handle>;
private:
friend class item_handle;
template <typename>
friend class row_handle;
template <typename, typename...>
friend class iterator_impl;
friend class category;
void append(item_value *iv)
{
if (m_head == nullptr)
m_head = m_tail = iv;
else
m_tail = m_tail->m_next = iv;
}
row *m_next = nullptr;
item_value *m_head = nullptr, *m_tail = nullptr;
};
template <typename>
// --------------------------------------------------------------------
/// \brief row_handle is the way to access data in rows
class row_handle
{
public:
friend class item_handle;
row_handle() = default;
......@@ -137,42 +144,40 @@ class row_handle
row_handle &operator=(const row_handle &) = default;
row_handle &operator=(row_handle &&) = default;
template <typename C2>
row_handle(const row_handle<C2> &rhs)
: m_cat(rhs.m_cat)
, m_row(rhs.m_row)
row_handle(const category &cat, const row &r)
: m_category(const_cast<category *>(&cat))
, m_row(const_cast<row *>(&r))
{
}
row_handle(category_type &cat, row_type &row)
: m_cat(&cat)
, m_row(&row)
const category &cat() const
{
return *m_category;
}
explicit operator bool() const
{
return m_cat != nullptr and m_row != nullptr;
return m_category != nullptr and m_row != nullptr;
}
item_handle_type operator[](uint32_t column_ix)
item_handle operator[](uint32_t column_ix)
{
return item_handle_type(column_ix, *this);
return item_handle(column_ix, *this);
}
const item_handle_type operator[](uint32_t column_ix) const
const item_handle operator[](uint32_t column_ix) const
{
return item_handle_type(column_ix, const_cast<row_handle &>(*this));
return item_handle(column_ix, const_cast<row_handle &>(*this));
}
item_handle_type operator[](std::string_view column_name)
item_handle operator[](std::string_view column_name)
{
return item_handle_type(add_column(column_name), *this);
return item_handle(add_column(column_name), *this);
}
const item_handle_type operator[](std::string_view column_name) const
const item_handle operator[](std::string_view column_name) const
{
return item_handle_type(get_column_ix(column_name), *this);
return item_handle(get_column_ix(column_name), const_cast<row_handle &>(*this));
}
template <typename... Ts, size_t N>
......@@ -183,13 +188,13 @@ class row_handle
std::array<size_t, N> cix;
for (size_t i = 0; i < N; ++i)
cix[i] = get_column_ix(columns[i]);
return detail::get_row_result<category_type, Ts...>(*this, std::move(cix));
return detail::get_row_result<Ts...>(*this, std::move(cix));
}
template <typename... C>
auto get(C... columns) const
{
return detail::get_row_result<category_type, C...>(*this, {get_column_ix(columns)...});
return detail::get_row_result<C...>(*this, {get_column_ix(columns)...});
}
void assign(const std::vector<item> &values)
......@@ -247,32 +252,23 @@ class row_handle
void assign(std::string_view name, std::string_view value, bool updateLinked, bool validate = true)
{
assign(m_cat->add_column(name), value, updateLinked, validate);
assign(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);
}
void assign(size_t column, std::string_view value, bool updateLinked, bool validate = true);
private:
uint16_t get_column_ix(std::string_view name) const
{
return m_cat->get_column_ix(name);
}
uint16_t get_column_ix(std::string_view name) const;
uint16_t add_column(std::string_view name)
{
return m_cat->add_column(name);
}
uint16_t add_column(std::string_view name);
void assign(const item &i, bool updateLinked)
{
assign(i.name(), i.value(), updateLinked);
}
category_type *m_cat = nullptr;
row_type *m_row = nullptr;
category *m_category = nullptr;
row *m_row = nullptr;
};
} // namespace cif::v2
\ No newline at end of file
......@@ -166,7 +166,7 @@ class Validator
{
}
~Validator();
~Validator() = default;
Validator(const Validator &rhs) = delete;
Validator &operator=(const Validator &rhs) = delete;
......@@ -175,7 +175,6 @@ class Validator
Validator &operator=(Validator &&rhs);
friend class dictionary_parser;
// friend class ValidatorFactory;
void addTypeValidator(ValidateType &&v);
const ValidateType *getValidatorForType(std::string_view typeCode) const;
......@@ -189,11 +188,11 @@ class Validator
void reportError(const std::string &msg, bool fatal) const;
const std::string &dictName() const { return m_name; }
void dictName(const std::string &name) { m_name = name; }
const std::string &name() const { return m_name; }
void set_name(const std::string &name) { m_name = name; }
const std::string &dictVersion() const { return m_version; }
void dictVersion(const std::string &version) { m_version = version; }
const std::string &version() const { return m_version; }
void version(const std::string &version) { m_version = version; }
private:
// name is fully qualified here:
......@@ -201,7 +200,7 @@ class Validator
std::string m_name;
std::string m_version;
bool mStrict = false;
bool m_strict = false;
std::set<ValidateType> mTypeValidators;
std::set<ValidateCategory> mCategoryValidators;
std::vector<ValidateLink> mLinkValidators;
......
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2022 NKI/AVL, Netherlands Cancer Institute
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <cif++/v2/category.hpp>
namespace cif::v2
{
void category::update_value(row *row, size_t column, std::string_view value, bool updateLinked, bool validate)
{
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);
// }
// }
}
// proxy methods for every insertion
category::iterator category::insert_impl(const_iterator pos, row *n)
{
assert(n != nullptr);
assert(n->m_next == nullptr);
if (n == nullptr)
throw std::runtime_error("Invalid pointer passed to insert");
// insert at end, most often this is the case
if (pos.m_current == nullptr)
{
if (m_head == nullptr)
m_tail = m_head = n;
else
m_tail = m_tail->m_next = n;
}
else
{
assert(m_head != nullptr);
if (pos.m_current == m_head)
m_head = n->m_next = m_head;
else
n = n->m_next = m_head->m_next;
}
return iterator(*this, n);
}
category::iterator category::erase_impl(const_iterator pos)
{
if (pos == cend())
return end();
assert(false);
// TODO: implement
// row *n = const_cast<row *>(pos.row());
// row *cur;
// if (m_head == n)
// {
// m_head = static_cast<row *>(m_head->m_next);
// if (m_head == nullptr)
// m_tail = nullptr;
// n->m_next = nullptr;
// delete_row(n);
// cur = m_head;
// }
// else
// {
// cur = static_cast<row *>(n->m_next);
// if (m_tail == n)
// m_tail = static_cast<row *>(n->m_prev);
// row *p = m_head;
// while (p != nullptr and p->m_next != n)
// p = p->m_next;
// if (p != nullptr and p->m_next == n)
// {
// p->m_next = n->m_next;
// if (p->m_next != nullptr)
// p->m_next->m_prev = p;
// n->m_next = nullptr;
// }
// else
// throw std::runtime_error("remove for a row not found in the list");
// delete_row(n);
// }
// return iterator(*this, cur);
}
std::vector<std::string> get_category_fields(const category &cat)
{
return {};
}
} // namespace cif::v2
\ No newline at end of file
......@@ -34,23 +34,24 @@ namespace cif::v2
using namespace literals;
class dictionary_parser : public parser_t<>
inline void replace_all(std::string &s, std::string_view pat, std::string_view rep)
{
public:
using base_type = parser_t<>;
using file_type = typename base_type::file_type;
using datablock_type = typename file_type::datablock_type;
using category_type = typename datablock_type::category_type;
for (std::string::size_type i = s.find(pat); i != std::string::npos; i = s.find(pat, i))
s.replace(i, pat.size(), rep.data(), rep.size());
}
dictionary_parser(Validator &validator, std::istream &is, file_type &f)
: base_type(is, f)
class dictionary_parser : public parser
{
public:
dictionary_parser(Validator &validator, std::istream &is, file &f)
: parser(is, f)
, m_validator(validator)
{
}
void load_dictionary()
{
std::unique_ptr<datablock_type> dict;
std::unique_ptr<datablock> dict;
auto savedDatablock = m_datablock;
try
......@@ -65,7 +66,7 @@ class dictionary_parser : public parser_t<>
default:
{
dict.reset(new datablock_type(m_token_value)); // dummy datablock, for constructing the validator only
dict.reset(new datablock(m_token_value)); // dummy datablock, for constructing the validator only
m_datablock = dict.get();
match(CIFToken::DATA);
......@@ -101,14 +102,14 @@ class dictionary_parser : public parser_t<>
link_items();
// store meta information
datablock_type::iterator info;
datablock::iterator info;
bool n;
std::tie(info, n) = m_datablock->emplace("dictionary");
if (n)
{
auto r = info->front();
m_validator.dictName(r["title"].as<std::string>());
m_validator.dictVersion(r["version"].as<std::string>());
m_validator.set_name(r["title"].as<std::string>());
m_validator.version(r["version"].as<std::string>());
}
m_datablock = savedDatablock;
......@@ -129,8 +130,8 @@ class dictionary_parser : public parser_t<>
bool isCategorySaveFrame = m_token_value[0] != '_';
datablock_type dict(m_token_value);
datablock_type::iterator cat = dict.end();
datablock dict(m_token_value);
datablock::iterator cat = dict.end();
match(CIFToken::SAVE);
while (m_lookahead == CIFToken::LOOP or m_lookahead == CIFToken::Tag)
......@@ -437,14 +438,14 @@ class dictionary_parser : public parser_t<>
auto &dict = *m_datablock;
for (auto &t : dict["item_type_list"])
for (auto t : dict["item_type_list"])
{
std::string code, primitiveCode, construct;
cif::v2::tie(code, primitiveCode, construct) = t.get("code", "primitive_code", "construct");
ba::replace_all(construct, "\\n", "\n");
ba::replace_all(construct, "\\t", "\t");
ba::replace_all(construct, "\\\n", "");
replace_all(construct, "\\n", "\n");
replace_all(construct, "\\t", "\t");
replace_all(construct, "\\\n", "");
try
{
......@@ -455,7 +456,7 @@ class dictionary_parser : public parser_t<>
}
catch (const std::exception &)
{
std::throw_with_nested(CifParserError(t.lineNr(), "error in regular expression"));
std::throw_with_nested(parse_error(/*t.lineNr()*/ 0, "error in regular expression"));
}
// Do not replace an already defined type validator, this won't work with pdbx_v40
......@@ -482,11 +483,12 @@ class dictionary_parser : public parser_t<>
// --------------------------------------------------------------------
Validator parse_dictionary(std::string_view name, std::istream &is);
Validator parse_dictionary(std::string_view name, std::istream &is)
{
Validator result(name);
dictionary_parser p(v, is, file{});
file f;
dictionary_parser p(result, is, f);
p.load_dictionary();
return result;
......
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2022 NKI/AVL, Netherlands Cancer Institute
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <cif++/v2/row.hpp>
namespace cif::v2
{
std::string_view item_handle::text() const
{
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();
}
return {};
}
}
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 NKI/AVL, Netherlands Cancer Institute
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <cassert>
#include <iostream>
#include <map>
#include <regex>
#include <stack>
#include <cif++/CifUtils.hpp>
#include <cif++/v2/forward_decl.hpp>
#include <cif++/v2/parser.hpp>
#include <cif++/v2/file.hpp>
namespace cif
{
extern int VERBOSE;
}
namespace cif::v2
{
// --------------------------------------------------------------------
sac_parser::sac_parser(std::istream &is, bool init)
: m_source(is)
{
m_validate = true;
m_line_nr = 1;
m_bol = true;
if (init)
m_lookahead = get_next_token();
}
// get_next_char takes a char from the buffer, or if it is empty
// from the istream. This function also does carriage/linefeed
// translation.
int sac_parser::get_next_char()
{
int result;
if (m_buffer.empty())
result = m_source.get();
else
{
result = m_buffer.top();
m_buffer.pop();
}
// very simple CR/LF translation into LF
if (result == '\r')
{
int lookahead = m_source.get();
if (lookahead != '\n')
m_buffer.push(lookahead);
result = '\n';
}
m_token_value += static_cast<char>(result);
if (result == '\n')
++m_line_nr;
if (VERBOSE >= 6)
{
std::cerr << "get_next_char => ";
if (iscntrl(result) or not isprint(result))
std::cerr << int(result) << std::endl;
else
std::cerr << char(result) << std::endl;
}
return result;
}
void sac_parser::retract()
{
assert(not m_token_value.empty());
char ch = m_token_value.back();
if (ch == '\n')
--m_line_nr;
m_buffer.push(ch);
m_token_value.pop_back();
}
int sac_parser::restart(int start)
{
int result = 0;
while (not m_token_value.empty())
retract();
switch (start)
{
case State::Start:
result = State::Float;
break;
case State::Float:
result = State::Int;
break;
case State::Int:
result = State::Value;
break;
default:
error("Invalid state in SacParser");
}
m_bol = false;
return result;
}
sac_parser::CIFToken sac_parser::get_next_token()
{
const auto kEOF = std::char_traits<char>::eof();
CIFToken result = CIFToken::Unknown;
int quoteChar = 0;
int state = State::Start, start = State::Start;
m_bol = false;
m_token_value.clear();
mTokenType = CIFValue::Unknown;
while (result == CIFToken::Unknown)
{
auto ch = get_next_char();
switch (state)
{
case State::Start:
if (ch == kEOF)
result = CIFToken::Eof;
else if (ch == '\n')
{
m_bol = true;
state = State::White;
}
else if (ch == ' ' or ch == '\t')
state = State::White;
else if (ch == '#')
state = State::Comment;
else if (ch == '_')
state = State::Tag;
else if (ch == ';' and m_bol)
state = State::TextField;
else if (ch == '\'' or ch == '"')
{
quoteChar = ch;
state = State::QuotedString;
}
else
state = start = restart(start);
break;
case State::White:
if (ch == kEOF)
result = CIFToken::Eof;
else if (not isspace(ch))
{
state = State::Start;
retract();
m_token_value.clear();
}
else
m_bol = (ch == '\n');
break;
case State::Comment:
if (ch == '\n')
{
state = State::Start;
m_bol = true;
m_token_value.clear();
}
else if (ch == kEOF)
result = CIFToken::Eof;
else if (not is_any_print(ch))
error("invalid character in comment");
break;
case State::TextField:
if (ch == '\n')
state = State::TextField + 1;
else if (ch == kEOF)
error("unterminated textfield");
else if (not is_any_print(ch))
warning("invalid character in text field '" + std::string({static_cast<char>(ch)}) + "' (" + std::to_string((int)ch) + ")");
break;
case State::TextField + 1:
if (is_text_lead(ch) or ch == ' ' or ch == '\t')
state = State::TextField;
else if (ch == ';')
{
assert(m_token_value.length() >= 2);
m_token_value = m_token_value.substr(1, m_token_value.length() - 3);
mTokenType = CIFValue::TextField;
result = CIFToken::Value;
}
else if (ch == kEOF)
error("unterminated textfield");
else if (ch != '\n')
error("invalid character in text field");
break;
case State::QuotedString:
if (ch == kEOF)
error("unterminated quoted string");
else if (ch == quoteChar)
state = State::QuotedStringQuote;
else if (not is_any_print(ch))
warning("invalid character in quoted string: '" + std::string({static_cast<char>(ch)}) + '\'');
break;
case State::QuotedStringQuote:
if (is_white(ch))
{
retract();
result = CIFToken::Value;
mTokenType = CIFValue::String;
if (m_token_value.length() < 2)
error("Invalid quoted string token");
m_token_value = m_token_value.substr(1, m_token_value.length() - 2);
}
else if (ch == quoteChar)
;
else if (is_any_print(ch))
state = State::QuotedString;
else if (ch == kEOF)
error("unterminated quoted string");
else
error("invalid character in quoted string");
break;
case State::Tag:
if (not is_non_blank(ch))
{
retract();
result = CIFToken::Tag;
}
break;
case State::Float:
if (ch == '+' or ch == '-')
{
state = State::Float + 1;
}
else if (isdigit(ch))
state = State::Float + 1;
else
state = start = restart(start);
break;
case State::Float + 1:
// if (ch == '(') // numeric???
// mState = State::NumericSuffix;
// else
if (ch == '.')
state = State::Float + 2;
else if (tolower(ch) == 'e')
state = State::Float + 3;
else if (is_white(ch) or ch == kEOF)
{
retract();
result = CIFToken::Value;
mTokenType = CIFValue::Int;
}
else
state = start = restart(start);
break;
// parsed '.'
case State::Float + 2:
if (tolower(ch) == 'e')
state = State::Float + 3;
else if (is_white(ch) or ch == kEOF)
{
retract();
result = CIFToken::Value;
mTokenType = CIFValue::Float;
}
else
state = start = restart(start);
break;
// parsed 'e'
case State::Float + 3:
if (ch == '-' or ch == '+')
state = State::Float + 4;
else if (isdigit(ch))
state = State::Float + 5;
else
state = start = restart(start);
break;
case State::Float + 4:
if (isdigit(ch))
state = State::Float + 5;
else
state = start = restart(start);
break;
case State::Float + 5:
if (is_white(ch) or ch == kEOF)
{
retract();
result = CIFToken::Value;
mTokenType = CIFValue::Float;
}
else
state = start = restart(start);
break;
case State::Int:
if (isdigit(ch) or ch == '+' or ch == '-')
state = State::Int + 1;
else
state = start = restart(start);
break;
case State::Int + 1:
if (is_white(ch) or ch == kEOF)
{
retract();
result = CIFToken::Value;
mTokenType = CIFValue::Int;
}
else
state = start = restart(start);
break;
case State::Value:
if (ch == '_')
{
std::string s = toLowerCopy(m_token_value);
if (s == "global_")
result = CIFToken::GLOBAL;
else if (s == "stop_")
result = CIFToken::STOP;
else if (s == "loop_")
result = CIFToken::LOOP;
else if (s == "data_")
{
state = State::DATA;
continue;
}
else if (s == "save_")
{
state = State::SAVE;
continue;
}
}
if (result == CIFToken::Unknown and not is_non_blank(ch))
{
retract();
result = CIFToken::Value;
if (m_token_value == ".")
mTokenType = CIFValue::Inapplicable;
else if (m_token_value == "?")
{
mTokenType = CIFValue::Unknown;
m_token_value.clear();
}
}
break;
case State::DATA:
case State::SAVE:
if (not is_non_blank(ch))
{
retract();
if (state == State::DATA)
result = CIFToken::DATA;
else
result = CIFToken::SAVE;
m_token_value.erase(m_token_value.begin(), m_token_value.begin() + 5);
}
break;
default:
assert(false);
error("Invalid state in get_next_token");
break;
}
}
if (VERBOSE >= 5)
{
std::cerr << get_token_name(result);
if (mTokenType != CIFValue::Unknown)
std::cerr << ' ' << get_value_name(mTokenType);
if (result != CIFToken::Eof)
std::cerr << " " << std::quoted(m_token_value);
std::cerr << std::endl;
}
return result;
}
void sac_parser::match(CIFToken token)
{
if (m_lookahead != token)
error(std::string("Unexpected token, expected ") + get_token_name(token) + " but found " + get_token_name(m_lookahead));
m_lookahead = get_next_token();
}
bool sac_parser::parse_single_datablock(const std::string &datablock)
{
// first locate the start, as fast as we can
auto &sb = *m_source.rdbuf();
enum
{
start,
comment,
string,
string_quote,
qstring,
data
} state = start;
int quote = 0;
bool bol = true;
std::string dblk = "data_" + datablock;
std::string::size_type si = 0;
bool found = false;
for (auto ch = sb.sbumpc(); not found and ch != std::streambuf::traits_type::eof(); ch = sb.sbumpc())
{
switch (state)
{
case start:
switch (ch)
{
case '#': state = comment; break;
case 'd':
case 'D':
state = data;
si = 1;
break;
case '\'':
case '"':
state = string;
quote = ch;
break;
case ';':
if (bol)
state = qstring;
break;
}
break;
case comment:
if (ch == '\n')
state = start;
break;
case string:
if (ch == quote)
state = string_quote;
break;
case string_quote:
if (std::isspace(ch))
state = start;
else
state = string;
break;
case qstring:
if (ch == ';' and bol)
state = start;
break;
case data:
if (isspace(ch) and dblk[si] == 0)
found = true;
else if (dblk[si++] != ch)
state = start;
break;
}
bol = (ch == '\n');
}
if (found)
{
produce_datablock(datablock);
m_lookahead = get_next_token();
parse_datablock();
}
return found;
}
sac_parser::datablock_index sac_parser::index_datablocks()
{
datablock_index index;
// first locate the start, as fast as we can
auto &sb = *m_source.rdbuf();
enum
{
start,
comment,
string,
string_quote,
qstring,
data,
data_name
} state = start;
int quote = 0;
bool bol = true;
const char dblk[] = "data_";
std::string::size_type si = 0;
std::string datablock;
for (auto ch = sb.sbumpc(); ch != std::streambuf::traits_type::eof(); ch = sb.sbumpc())
{
switch (state)
{
case start:
switch (ch)
{
case '#': state = comment; break;
case 'd':
case 'D':
state = data;
si = 1;
break;
case '\'':
case '"':
state = string;
quote = ch;
break;
case ';':
if (bol)
state = qstring;
break;
}
break;
case comment:
if (ch == '\n')
state = start;
break;
case string:
if (ch == quote)
state = string_quote;
break;
case string_quote:
if (std::isspace(ch))
state = start;
else
state = string;
break;
case qstring:
if (ch == ';' and bol)
state = start;
break;
case data:
if (dblk[si] == 0 and is_non_blank(ch))
{
datablock = {static_cast<char>(ch)};
state = data_name;
}
else if (dblk[si++] != ch)
state = start;
break;
case data_name:
if (is_non_blank(ch))
datablock.insert(datablock.end(), char(ch));
else if (isspace(ch))
{
if (not datablock.empty())
index[datablock] = m_source.tellg();
state = start;
}
else
state = start;
break;
}
bol = (ch == '\n');
}
return index;
}
bool sac_parser::parse_single_datablock(const std::string &datablock, const datablock_index &index)
{
bool result = false;
auto i = index.find(datablock);
if (i != index.end())
{
m_source.seekg(i->second);
produce_datablock(datablock);
m_lookahead = get_next_token();
parse_datablock();
result = true;
}
return result;
}
void sac_parser::parse_file()
{
while (m_lookahead != CIFToken::Eof)
{
switch (m_lookahead)
{
case CIFToken::GLOBAL:
parse_global();
break;
case CIFToken::DATA:
produce_datablock(m_token_value);
match(CIFToken::DATA);
parse_datablock();
break;
default:
error("This file does not seem to be an mmCIF file");
break;
}
}
}
void sac_parser::parse_global()
{
match(CIFToken::GLOBAL);
while (m_lookahead == CIFToken::Tag)
{
match(CIFToken::Tag);
match(CIFToken::Value);
}
}
void sac_parser::parse_datablock()
{
std::string cat;
while (m_lookahead == CIFToken::LOOP or m_lookahead == CIFToken::Tag or m_lookahead == CIFToken::SAVE)
{
switch (m_lookahead)
{
case CIFToken::LOOP:
{
cat.clear(); // should start a new category
match(CIFToken::LOOP);
std::vector<std::string> tags;
while (m_lookahead == CIFToken::Tag)
{
std::string catName, itemName;
std::tie(catName, itemName) = splitTagName(m_token_value);
if (cat.empty())
{
produce_category(catName);
cat = catName;
}
else if (not iequals(cat, catName))
error("inconsistent categories in loop_");
tags.push_back(itemName);
match(CIFToken::Tag);
}
while (m_lookahead == CIFToken::Value)
{
produce_row();
for (auto tag : tags)
{
produce_item(cat, tag, m_token_value);
match(CIFToken::Value);
}
}
cat.clear();
break;
}
case CIFToken::Tag:
{
std::string catName, itemName;
std::tie(catName, itemName) = splitTagName(m_token_value);
if (not iequals(cat, catName))
{
produce_category(catName);
cat = catName;
produce_row();
}
match(CIFToken::Tag);
produce_item(cat, itemName, m_token_value);
match(CIFToken::Value);
break;
}
case CIFToken::SAVE:
parse_save_frame();
break;
default:
assert(false);
break;
}
}
}
void sac_parser::parse_save_frame()
{
error("A regular CIF file should not contain a save frame");
}
// --------------------------------------------------------------------
void parser::produce_datablock(const std::string &name)
{
const auto &[iter, ignore] = m_file.emplace(name);
m_datablock = &(*iter);
}
void parser::produce_category(const std::string &name)
{
if (VERBOSE >= 4)
std::cerr << "producing category " << name << std::endl;
const auto &[cat, ignore] = m_datablock->emplace(name);
m_category = &*cat;
}
void parser::produce_row()
{
if (VERBOSE >= 4)
std::cerr << "producing row for category " << m_category->name() << std::endl;
m_category->emplace({});
m_row = m_category->back();
// m_row.lineNr(m_line_nr);
}
void parser::produce_item(const std::string &category, const std::string &item, const std::string &value)
{
if (VERBOSE >= 4)
std::cerr << "producing _" << category << '.' << item << " -> " << value << std::endl;
if (not iequals(category, m_category->name()))
error("inconsistent categories in loop_");
m_row[item] = m_token_value;
}
} // namespace cif::v2
\ No newline at end of file
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2022 NKI/AVL, Netherlands Cancer Institute
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <cif++/v2/category.hpp>
namespace cif::v2
{
void row_handle::assign(size_t column, std::string_view value, bool updateLinked, bool validate)
{
m_category->update_value(m_row, column, value, updateLinked, validate);
}
uint16_t row_handle::get_column_ix(std::string_view name) const
{
return m_category->get_column_ix(name);
}
uint16_t row_handle::add_column(std::string_view name)
{
return m_category->add_column(name);
}
} // namespace cif::v2
\ No newline at end of file
......@@ -24,6 +24,7 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <cassert>
#include <fstream>
#include <iostream>
......@@ -217,16 +218,12 @@ const ValidateItem *ValidateCategory::getValidatorForItem(std::string_view tag)
// --------------------------------------------------------------------
Validator::Validator(std::string_view name, std::istream &is)
: mName(name)
{
DictParser p(*this, is);
p.loadDictionary();
}
Validator::~Validator()
{
}
// Validator::Validator(std::string_view name, std::istream &is)
// : mName(name)
// {
// DictParser p(*this, is);
// p.loadDictionary();
// }
void Validator::addTypeValidator(ValidateType &&v)
{
......@@ -343,7 +340,7 @@ std::vector<const ValidateLink *> Validator::getLinksForChild(std::string_view c
void Validator::reportError(const std::string &msg, bool fatal) const
{
if (mStrict or fatal)
if (m_strict or fatal)
throw ValidationError(msg);
else if (VERBOSE > 0)
std::cerr << msg << std::endl;
......@@ -357,7 +354,7 @@ const Validator &ValidatorFactory::operator[](std::string_view dictionary_name)
for (auto &validator : mValidators)
{
if (iequals(validator.m_name, dictionary_name))
if (iequals(validator.name(), dictionary_name))
return validator;
}
......@@ -422,12 +419,12 @@ const Validator &ValidatorFactory::operator[](std::string_view dictionary_name)
throw std::runtime_error("Dictionary not found or defined (" + dictionary.string() + ")");
}
assert(iequals(mValidators.back().m_name, dictionary_name));
assert(iequals(mValidators.back().name(), dictionary_name));
return mValidators.back();
}
void ValiatorFactory::construct_validator(std::string_view name, std::istream &is)
void ValidatorFactory::construct_validator(std::string_view name, std::istream &is)
{
mValidators.emplace_back(parse_dictionary(name, is));
}
......
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