Commit 04b7828a by Maarten L. Hekkelman

validator work

parent 9c621eca
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include <cif++/v2/iterator.hpp> #include <cif++/v2/iterator.hpp>
#include <cif++/v2/row.hpp> #include <cif++/v2/row.hpp>
#include <cif++/v2/validate.hpp> #include <cif++/v2/validate.hpp>
namespace cif::v2 namespace cif::v2
{ {
...@@ -127,17 +128,22 @@ class category ...@@ -127,17 +128,22 @@ class category
throw std::runtime_error("No Validator specified"); throw std::runtime_error("No Validator specified");
if (m_cat_validator == nullptr) if (m_cat_validator == nullptr)
m_validator->reportError("undefined Category", true); m_validator->report_error("undefined Category", true);
iset result; iset result;
for (auto &iv : m_cat_validator->mItemValidators) for (auto &iv : m_cat_validator->m_item_validators)
result.insert(iv.mTag); result.insert(iv.m_tag);
return result; return result;
} }
const Validator *get_validator() const { return m_validator; } void set_validator(const validator *v, datablock &db);
const ValidateCategory *get_cat_validator() const { return m_cat_validator; } void update_links(datablock &db);
const validator *get_validator() const { return m_validator; }
const category_validator *get_cat_validator() const { return m_cat_validator; }
bool is_valid() const;
// -------------------------------------------------------------------- // --------------------------------------------------------------------
...@@ -379,6 +385,10 @@ class category ...@@ -379,6 +385,10 @@ class category
// insert_impl(pos, std::move(row)); // insert_impl(pos, std::move(row));
// } // }
iterator erase(iterator pos);
size_t erase(condition &&cond);
size_t erase(condition &&cond, std::function<void(row_handle)> &&visit);
iterator emplace(std::initializer_list<item> items) iterator emplace(std::initializer_list<item> items)
{ {
return this->emplace(items.begin(), items.end()); return this->emplace(items.begin(), items.end());
...@@ -388,29 +398,29 @@ class category ...@@ -388,29 +398,29 @@ class category
iterator emplace(ItemIter b, ItemIter e) iterator emplace(ItemIter b, ItemIter e)
{ {
// First, make sure all mandatory fields are supplied // First, make sure all mandatory fields are supplied
// if (mCatValidator != nullptr and b != e) if (m_cat_validator != nullptr and b != e)
// { {
// for (auto &col : m_columns) for (const auto &[column, iv] : m_columns)
// { {
// auto iv = mCatValidator->getValidatorForItem(col.mName); if (iv == nullptr)
continue;
// if (iv == nullptr) bool seen = false;
// continue;
// bool seen = false; for (auto v = b; v != e; ++v)
{
if (iequals(v->name(), column))
{
iv->operator()(v->value());
// for (auto v = b; v != e; ++v) seen = true;
// { break;
// if (iequals(v->name(), col.mName)) }
// { }
// seen = true;
// break;
// }
// }
// if (not seen and iv->mMandatory) if (not seen and iv->m_mandatory)
// throw std::runtime_error("missing mandatory field " + col.mName + " for category " + mName); throw std::runtime_error("missing mandatory field " + column + " for category " + m_name);
// } }
// if (mIndex != nullptr) // if (mIndex != nullptr)
// { // {
...@@ -433,7 +443,7 @@ class category ...@@ -433,7 +443,7 @@ class category
// isNew = false; // isNew = false;
// } // }
// } // }
// } }
row *r = this->create_row(); row *r = this->create_row();
...@@ -486,12 +496,12 @@ class category ...@@ -486,12 +496,12 @@ class category
break; break;
} }
// if (VERBOSE > 0 and result == m_columns.size() and mCatValidator != nullptr) // validate the name, if it is known at all (since it was not found) if (VERBOSE > 0 and result == m_columns.size() and m_cat_validator != nullptr) // validate the name, if it is known at all (since it was not found)
// { {
// auto iv = mCatValidator->getValidatorForItem(name); auto iv = m_cat_validator->get_validator_for_item(column_name);
// if (iv == nullptr) if (iv == nullptr)
// std::cerr << "Invalid name used '" << name << "' is not a known column in " + mName << std::endl; std::cerr << "Invalid name used '" << name << "' is not a known column in " + m_name << std::endl;
// } }
return result; return result;
} }
...@@ -504,14 +514,14 @@ class category ...@@ -504,14 +514,14 @@ class category
if (result == m_columns.size()) if (result == m_columns.size())
{ {
const ValidateItem *item_validator = nullptr; const item_validator *item_validator = nullptr;
// if (mCatValidator != nullptr) if (m_cat_validator != nullptr)
// { {
// item_validator = mCatValidator->getValidatorForItem(column_name); item_validator = m_cat_validator->get_validator_for_item(column_name);
// if (item_validator == nullptr) if (item_validator == nullptr)
// m_validator->reportError("tag " + std::string(column_name) + " not allowed in category " + mName, false); m_validator->report_error("tag " + std::string(column_name) + " not allowed in category " + m_name, false);
// } }
m_columns.emplace_back(column_name, item_validator); m_columns.emplace_back(column_name, item_validator);
} }
...@@ -523,6 +533,9 @@ class category ...@@ -523,6 +533,9 @@ class category
void update_value(row *row, size_t column, std::string_view value, bool updateLinked, bool validate = true); void update_value(row *row, size_t column, std::string_view value, bool updateLinked, bool validate = true);
private: private:
bool is_orphan(row_handle r) const;
void erase_orphans(condition &&cond);
using allocator_type = std::allocator<void>; using allocator_type = std::allocator<void>;
constexpr allocator_type get_allocator() const constexpr allocator_type get_allocator() const
...@@ -645,15 +658,27 @@ class category ...@@ -645,15 +658,27 @@ class category
struct item_column struct item_column
{ {
std::string m_name; std::string m_name;
const ValidateItem *m_validator; const item_validator *m_validator;
item_column(std::string_view name, const ValidateItem *validator) item_column(std::string_view name, const item_validator *validator)
: m_name(name) : m_name(name)
, m_validator(validator) , m_validator(validator)
{ {
} }
}; };
struct link
{
link(category *linked, const link_validator *v)
: linked(linked)
, v(v)
{
}
category *linked;
const link_validator *v;
};
// proxy methods for every insertion // proxy methods for every insertion
iterator insert_impl(const_iterator pos, row *n); iterator insert_impl(const_iterator pos, row *n);
...@@ -661,8 +686,10 @@ class category ...@@ -661,8 +686,10 @@ class category
std::string m_name; std::string m_name;
std::vector<item_column> m_columns; std::vector<item_column> m_columns;
const Validator *m_validator = nullptr; const validator *m_validator = nullptr;
const ValidateCategory *m_cat_validator = nullptr; const category_validator *m_cat_validator = nullptr;
std::vector<link> m_parent_links, m_child_links;
bool m_cascade = true;
row *m_head = nullptr, *m_tail = nullptr; row *m_head = nullptr, *m_tail = nullptr;
}; };
......
...@@ -63,6 +63,31 @@ class datablock ...@@ -63,6 +63,31 @@ class datablock
const std::string &name() const { return m_name; } const std::string &name() const { return m_name; }
void set_validator(const validator *v)
{
m_validator = v;
for (auto &cat : *this)
cat.set_validator(v, *this);
}
const validator *get_validator() const
{
return m_validator;
}
bool is_valid() const
{
if (m_validator == nullptr)
throw std::runtime_error("Validator not specified");
bool result = true;
for (auto &cat : *this)
result = cat.is_valid() and result;
return result;
}
// -------------------------------------------------------------------- // --------------------------------------------------------------------
bool empty() const { return m_categories.empty(); } bool empty() const { return m_categories.empty(); }
...@@ -102,6 +127,18 @@ class datablock ...@@ -102,6 +127,18 @@ class datablock
return i == m_categories.end() ? s_empty : *i; return i == m_categories.end() ? s_empty : *i;
} }
category *get(std::string_view name)
{
auto i = std::find_if(m_categories.begin(), m_categories.end(), [name](const category &c)
{ return iequals(c.name(), name); });
return i == m_categories.end() ? nullptr : &*i;
}
const category *get(std::string_view name) const
{
return const_cast<datablock *>(this)->get(name);
}
std::tuple<iterator, bool> emplace(std::string_view name) std::tuple<iterator, bool> emplace(std::string_view name)
{ {
bool is_new = true; bool is_new = true;
...@@ -182,6 +219,7 @@ class datablock ...@@ -182,6 +219,7 @@ class datablock
private: private:
category_list m_categories; category_list m_categories;
std::string m_name; std::string m_name;
const validator *m_validator = nullptr;
}; };
} // namespace cif::v2 } // namespace cif::v2
\ No newline at end of file
...@@ -31,6 +31,6 @@ ...@@ -31,6 +31,6 @@
namespace cif::v2 namespace cif::v2
{ {
Validator parse_dictionary(std::string_view name, std::istream &is); validator parse_dictionary(std::string_view name, std::istream &is);
} // namespace cif::v2 } // namespace cif::v2
...@@ -60,6 +60,57 @@ class file ...@@ -60,6 +60,57 @@ class file
file &operator=(const file &) = default; file &operator=(const file &) = default;
file &operator=(file &&) = default; file &operator=(file &&) = default;
void set_validator(const validator *v)
{
m_validator = v;
for (auto &db : *this)
db.set_validator(v);
}
const validator *get_validator() const
{
return m_validator;
}
bool is_valid() const
{
if (m_validator == nullptr)
std::runtime_error("No validator loaded explicitly, cannot continue");
bool result = true;
for (auto &d : *this)
result = d.is_valid() and result;
return result;
}
bool is_valid()
{
if (m_validator == nullptr)
{
if (VERBOSE > 0)
std::cerr << "No dictionary loaded explicitly, loading default" << std::endl;
load_dictionary();
}
bool result = true;
for (auto &d : *this)
result = d.is_valid() and result;
return result;
}
void load_dictionary()
{
load_dictionary("mmcif_ddl");
}
void load_dictionary(std::string_view name)
{
set_validator(&validator_factory::instance()[name]);
}
datablock &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 &c) auto i = std::find_if(m_datablocks.begin(), m_datablocks.end(), [name](const datablock &c)
...@@ -112,27 +163,36 @@ class file ...@@ -112,27 +163,36 @@ class file
bool empty() const { return m_datablocks.empty(); } bool empty() const { return m_datablocks.empty(); }
size_t size() const { return m_datablocks.size(); } size_t size() const { return m_datablocks.size(); }
iterator begin() { return m_datablocks.begin(); }
iterator end() { return m_datablocks.end(); }
const_iterator cbegin() { return m_datablocks.begin(); }
const_iterator cend() { return m_datablocks.end(); }
const_iterator begin() const { return m_datablocks.begin(); }
const_iterator end() const { return m_datablocks.end(); }
reference front() { return m_datablocks.front(); } reference front() { return m_datablocks.front(); }
reference back() { return m_datablocks.back(); } reference back() { return m_datablocks.back(); }
void load(std::istream &is) void load(std::istream &is)
{ {
// auto saved = mValidator; auto saved = m_validator;
// setValidator(nullptr); set_validator(nullptr);
parser p(is, *this); parser p(is, *this);
p.parse_file(); p.parse_file();
// if (saved != nullptr) if (saved != nullptr)
// { {
// setValidator(saved); set_validator(saved);
// (void)isValid(); (void)is_valid();
// } }
} }
private: private:
datablock_list m_datablocks; datablock_list m_datablocks;
std::unique_ptr<Validator> m_validator; const validator* m_validator = nullptr;
}; };
} }
\ No newline at end of file
...@@ -199,7 +199,7 @@ struct item_handle ...@@ -199,7 +199,7 @@ struct item_handle
item_handle &operator=(const T &value) item_handle &operator=(const T &value)
{ {
item v{"", value}; item v{"", value};
m_row_handle.assign(m_column, v.value(), false); assign_value(v);
return *this; return *this;
} }
...@@ -281,6 +281,8 @@ struct item_handle ...@@ -281,6 +281,8 @@ struct item_handle
uint16_t m_column; uint16_t m_column;
row_handle &m_row_handle; row_handle &m_row_handle;
void assign_value(const item &value);
static constexpr const char *s_empty_result = ""; static constexpr const char *s_empty_result = "";
}; };
...@@ -432,6 +434,20 @@ struct item_handle::item_value_as<T, std::enable_if_t<std::is_same_v<T, const ch ...@@ -432,6 +434,20 @@ struct item_handle::item_value_as<T, std::enable_if_t<std::is_same_v<T, const ch
}; };
template <typename T> template <typename T>
struct item_handle::item_value_as<T, std::enable_if_t<std::is_same_v<T, std::string_view>>>
{
// static std::string_view convert(const item_handle &ref)
// {
// return ref.text();
// }
static int compare(const item_handle &ref, const std::string_view &value, bool icase)
{
return icase ? cif::icompare(ref.text(), value) : ref.text().compare(value);
}
};
template <typename T>
struct item_handle::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) static std::string convert(const item_handle &ref)
......
...@@ -135,6 +135,7 @@ class row_handle ...@@ -135,6 +135,7 @@ class row_handle
{ {
public: public:
friend class item_handle; friend class item_handle;
friend class category;
row_handle() = default; row_handle() = default;
...@@ -262,6 +263,11 @@ class row_handle ...@@ -262,6 +263,11 @@ class row_handle
uint16_t add_column(std::string_view name); uint16_t add_column(std::string_view name);
operator row*()
{
return m_row;
}
void assign(const item &i, bool updateLinked) void assign(const item &i, bool updateLinked)
{ {
assign(i.name(), i.value(), updateLinked); assign(i.name(), i.value(), updateLinked);
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#pragma once #pragma once
#include <filesystem> #include <filesystem>
#include <mutex>
// duh.. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86164 // duh.. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86164
// #include <regex> // #include <regex>
...@@ -43,19 +44,19 @@ namespace io = boost::iostreams; ...@@ -43,19 +44,19 @@ namespace io = boost::iostreams;
namespace cif::v2 namespace cif::v2
{ {
struct ValidateCategory; struct category_validator;
class ValidatorFactory; class validator_factory;
// -------------------------------------------------------------------- // --------------------------------------------------------------------
class ValidationError : public std::exception class validation_error : public std::exception
{ {
public: public:
ValidationError(const std::string &msg); validation_error(const std::string &msg);
ValidationError(const std::string &cat, const std::string &item, validation_error(const std::string &cat, const std::string &item,
const std::string &msg); const std::string &msg);
const char *what() const noexcept { return mMsg.c_str(); } const char *what() const noexcept { return m_msg.c_str(); }
std::string mMsg; std::string m_msg;
}; };
// -------------------------------------------------------------------- // --------------------------------------------------------------------
...@@ -67,126 +68,120 @@ enum class DDL_PrimitiveType ...@@ -67,126 +68,120 @@ enum class DDL_PrimitiveType
Numb Numb
}; };
DDL_PrimitiveType mapToPrimitiveType(std::string_view s); DDL_PrimitiveType map_to_primitive_type(std::string_view s);
struct ValidateType struct type_validator
{ {
std::string mName; std::string m_name;
DDL_PrimitiveType mPrimitiveType; DDL_PrimitiveType m_primitive_type;
// std::regex mRx; // std::regex mRx;
boost::regex mRx; boost::regex m_rx;
bool operator<(const ValidateType &rhs) const bool operator<(const type_validator &rhs) const
{ {
return icompare(mName, rhs.mName) < 0; return icompare(m_name, rhs.m_name) < 0;
} }
// compare values based on type
// int compare(const std::string& a, const std::string& b) const
// {
// return compare(a.c_str(), b.c_str());
// }
int compare(const char *a, const char *b) const; int compare(const char *a, const char *b) const;
}; };
struct ValidateItem struct item_validator
{ {
std::string mTag; std::string m_tag;
bool mMandatory; bool m_mandatory;
const ValidateType *mType; const type_validator *m_type;
cif::iset mEnums; cif::iset m_enums;
std::string mDefault; std::string m_default;
bool mDefaultIsNull; bool m_default_is_null;
ValidateCategory *mCategory = nullptr; category_validator *m_category = nullptr;
// ItemLinked is used for non-key links // ItemLinked is used for non-key links
struct ItemLinked struct item_link
{ {
ValidateItem *mParent; item_validator *m_parent;
std::string mParentItem; std::string m_parent_item;
std::string mChildItem; std::string m_child_item;
}; };
std::vector<ItemLinked> mLinked; std::vector<item_link> mLinked;
bool operator<(const ValidateItem &rhs) const bool operator<(const item_validator &rhs) const
{ {
return icompare(mTag, rhs.mTag) < 0; return icompare(m_tag, rhs.m_tag) < 0;
} }
bool operator==(const ValidateItem &rhs) const bool operator==(const item_validator &rhs) const
{ {
return iequals(mTag, rhs.mTag); return iequals(m_tag, rhs.m_tag);
} }
void operator()(std::string value) const; void operator()(std::string_view value) const;
}; };
struct ValidateCategory struct category_validator
{ {
std::string mName; std::string m_name;
std::vector<std::string> mKeys; std::vector<std::string> m_keys;
cif::iset mGroups; cif::iset m_groups;
cif::iset mMandatoryFields; cif::iset m_mandatory_fields;
std::set<ValidateItem> mItemValidators; std::set<item_validator> m_item_validators;
bool operator<(const ValidateCategory &rhs) const bool operator<(const category_validator &rhs) const
{ {
return icompare(mName, rhs.mName) < 0; return icompare(m_name, rhs.m_name) < 0;
} }
void addItemValidator(ValidateItem &&v); void addItemValidator(item_validator &&v);
const ValidateItem *getValidatorForItem(std::string_view tag) const; const item_validator *get_validator_for_item(std::string_view tag) const;
const std::set<ValidateItem> &itemValidators() const const std::set<item_validator> &item_validators() const
{ {
return mItemValidators; return m_item_validators;
} }
}; };
struct ValidateLink struct link_validator
{ {
int mLinkGroupID; int m_link_group_id;
std::string mParentCategory; std::string m_parent_category;
std::vector<std::string> mParentKeys; std::vector<std::string> m_parent_keys;
std::string mChildCategory; std::string m_child_category;
std::vector<std::string> mChildKeys; std::vector<std::string> m_child_keys;
std::string mLinkGroupLabel; std::string m_link_group_label;
}; };
// -------------------------------------------------------------------- // --------------------------------------------------------------------
class Validator class validator
{ {
public: public:
Validator(std::string_view name) validator(std::string_view name)
: m_name(name) : m_name(name)
{ {
} }
~Validator() = default; ~validator() = default;
Validator(const Validator &rhs) = delete; validator(const validator &rhs) = delete;
Validator &operator=(const Validator &rhs) = delete; validator &operator=(const validator &rhs) = delete;
Validator(Validator &&rhs) = default; validator(validator &&rhs) = default;
Validator &operator=(Validator &&rhs) = default; validator &operator=(validator &&rhs) = default;
friend class dictionary_parser; friend class dictionary_parser;
void addTypeValidator(ValidateType &&v); void add_type_validator(type_validator &&v);
const ValidateType *getValidatorForType(std::string_view typeCode) const; const type_validator *get_validator_for_type(std::string_view type_code) const;
void addCategoryValidator(ValidateCategory &&v); void add_category_validator(category_validator &&v);
const ValidateCategory *getValidatorForCategory(std::string_view category) const; const category_validator *get_validator_for_category(std::string_view category) const;
void addLinkValidator(ValidateLink &&v); void add_link_validator(link_validator &&v);
std::vector<const ValidateLink *> getLinksForParent(std::string_view category) const; std::vector<const link_validator *> get_links_for_parent(std::string_view category) const;
std::vector<const ValidateLink *> getLinksForChild(std::string_view category) const; std::vector<const link_validator *> get_links_for_child(std::string_view category) const;
void reportError(const std::string &msg, bool fatal) const; void report_error(const std::string &msg, bool fatal) const;
const std::string &name() const { return m_name; } const std::string &name() const { return m_name; }
void set_name(const std::string &name) { m_name = name; } void set_name(const std::string &name) { m_name = name; }
...@@ -196,37 +191,37 @@ class Validator ...@@ -196,37 +191,37 @@ class Validator
private: private:
// name is fully qualified here: // name is fully qualified here:
ValidateItem *getValidatorForItem(std::string_view name) const; item_validator *get_validator_for_item(std::string_view name) const;
std::string m_name; std::string m_name;
std::string m_version; std::string m_version;
bool m_strict = false; bool m_strict = false;
std::set<ValidateType> mTypeValidators; std::set<type_validator> m_type_validators;
std::set<ValidateCategory> mCategoryValidators; std::set<category_validator> m_category_validators;
std::vector<ValidateLink> mLinkValidators; std::vector<link_validator> m_link_validators;
}; };
// -------------------------------------------------------------------- // --------------------------------------------------------------------
class ValidatorFactory class validator_factory
{ {
public: public:
static ValidatorFactory &instance() static validator_factory &instance()
{ {
static ValidatorFactory s_instance; static validator_factory s_instance;
return s_instance; return s_instance;
} }
const Validator &operator[](std::string_view dictionary_name); const validator &operator[](std::string_view dictionary_name);
private: private:
void construct_validator(std::string_view name, std::istream &is); void construct_validator(std::string_view name, std::istream &is);
// -------------------------------------------------------------------- // --------------------------------------------------------------------
ValidatorFactory() = default; validator_factory() = default;
std::mutex mMutex; std::mutex m_mutex;
std::list<Validator> mValidators; std::list<validator> m_validators;
}; };
} // namespace cif::v2 } // namespace cif::v2
...@@ -47,11 +47,11 @@ bool is_column_type_uchar(const category &cat, std::string_view col) ...@@ -47,11 +47,11 @@ bool is_column_type_uchar(const category &cat, std::string_view col)
auto cv = cat.get_cat_validator(); auto cv = cat.get_cat_validator();
if (cv) if (cv)
{ {
auto iv = cv->getValidatorForItem(col); auto iv = cv->get_validator_for_item(col);
if (iv != nullptr and iv->mType != nullptr) if (iv != nullptr and iv->m_type != nullptr)
{ {
auto type = iv->mType; auto type = iv->m_type;
result = type->mPrimitiveType == DDL_PrimitiveType::UChar; result = type->m_primitive_type == DDL_PrimitiveType::UChar;
} }
} }
......
...@@ -31,13 +31,21 @@ namespace cif::v2 ...@@ -31,13 +31,21 @@ namespace cif::v2
std::string_view item_handle::text() const std::string_view item_handle::text() const
{ {
if (m_row_handle.m_row != nullptr)
{
for (auto iv = m_row_handle.m_row->m_head; iv != nullptr; iv = iv->m_next) for (auto iv = m_row_handle.m_row->m_head; iv != nullptr; iv = iv->m_next)
{ {
if (iv->m_column_ix == m_column) if (iv->m_column_ix == m_column)
return iv->text(); return iv->text();
} }
}
return {}; return {};
} }
void item_handle::assign_value(const item &v)
{
m_row_handle.assign(m_column, v.value(), false);
}
} }
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