27 #include "cif++/dictionary_parser.hpp" 28 #include "cif++/validate.hpp" 29 #include "cif++/utilities.hpp" 30 #include "cif++/gzio.hpp" 42 #include <boost/regex.hpp> 55 : regex(rx.begin(), rx.end(), regex::extended | regex::optimize)
60 validation_error::validation_error(
const std::string &msg)
65 validation_error::validation_error(
const std::string &cat,
const std::string &item,
const std::string &msg)
66 : m_msg(
"When validating _" + cat +
'.' + item +
": " + msg)
74 DDL_PrimitiveType result;
76 result = DDL_PrimitiveType::Char;
78 result = DDL_PrimitiveType::UChar;
80 result = DDL_PrimitiveType::Numb;
82 throw validation_error(
"Not a known primitive type");
88 type_validator::type_validator(std::string_view name, DDL_PrimitiveType
type, std::string_view rx)
90 , m_primitive_type(type)
95 type_validator::~type_validator()
100 template <
typename T>
103 static std::from_chars_result
from_chars(
const char *
a,
const char *
b, T &
d)
105 return cif::from_chars(a, b, d);
109 template <
typename T>
112 static std::from_chars_result
from_chars(
const char *
a,
const char *
b, T &
d)
114 return std::from_chars(a, b, d);
123 result = b.empty() ? 0 : -1;
125 result = a.empty() ? 0 : +1;
128 switch (m_primitive_type)
130 case DDL_PrimitiveType::Numb:
137 std::from_chars_result ra, rb;
139 ra = selected_charconv<double>::from_chars(a.data(), a.data() + a.length(), da);
140 rb = selected_charconv<double>::from_chars(b.data(), b.data() + b.length(), db);
142 if (ra.ec == std::errc() and rb.ec == std::errc())
153 else if (ra.ec == std::errc())
160 case DDL_PrimitiveType::UChar:
161 case DDL_PrimitiveType::Char:
166 auto ai = a.begin(), bi = b.begin();
175 else if (bi == b.end())
184 if (m_primitive_type == DDL_PrimitiveType::UChar)
237 void item_validator::operator()(std::string_view value)
const 239 if (not value.empty() and value !=
"?" and value !=
".")
241 if (m_type !=
nullptr and not regex_match(value.begin(), value.end(), *m_type->m_rx))
242 throw validation_error(m_category->m_name, m_tag,
"Value '" + std::string{ value } +
"' does not match type expression for type " + m_type->m_name);
244 if (not m_enums.empty())
246 if (m_enums.count(std::string{ value }) == 0)
247 throw validation_error(m_category->m_name, m_tag,
"Value '" + std::string{ value } +
"' is not in the list of allowed values");
254 void category_validator::addItemValidator(item_validator &&v)
257 m_mandatory_fields.insert(v.m_tag);
261 auto r = m_item_validators.insert(std::move(v));
262 if (not r.second and
VERBOSE >= 4)
263 std::cout <<
"Could not add validator for item " << v.m_tag <<
" to category " << m_name << std::endl;
266 const item_validator *category_validator::get_validator_for_item(std::string_view tag)
const 268 const item_validator *result =
nullptr;
269 auto i = m_item_validators.find(item_validator{ std::string(tag) });
270 if (
i != m_item_validators.end())
273 std::cout <<
"No validator for tag " << tag << std::endl;
279 void validator::add_type_validator(type_validator &&v)
281 auto r = m_type_validators.insert(std::move(v));
282 if (not r.second and
VERBOSE > 4)
283 std::cout <<
"Could not add validator for type " << v.m_name << std::endl;
286 const type_validator *validator::get_validator_for_type(std::string_view typeCode)
const 288 const type_validator *result =
nullptr;
290 auto i = m_type_validators.find(type_validator{ std::string(typeCode), DDL_PrimitiveType::Char, {} });
291 if (
i != m_type_validators.end())
294 std::cout <<
"No validator for type " << typeCode << std::endl;
298 void validator::add_category_validator(category_validator &&v)
300 auto r = m_category_validators.insert(std::move(v));
301 if (not r.second and
VERBOSE > 4)
302 std::cout <<
"Could not add validator for category " << v.m_name << std::endl;
305 const category_validator *validator::get_validator_for_category(std::string_view category)
const 307 const category_validator *result =
nullptr;
308 auto i = m_category_validators.find(category_validator{ std::string(category) });
309 if (
i != m_category_validators.end())
312 std::cout <<
"No validator for category " << category << std::endl;
316 item_validator *validator::get_validator_for_item(std::string_view tag)
const 318 item_validator *result =
nullptr;
320 std::string cat, item;
323 auto *cv = get_validator_for_category(cat);
325 result =
const_cast<item_validator *
>(cv->get_validator_for_item(item));
327 if (result ==
nullptr and
VERBOSE > 4)
328 std::cout <<
"No validator for item " << tag << std::endl;
333 void validator::add_link_validator(link_validator &&v)
335 assert(v.m_parent_keys.size() == v.m_child_keys.size());
336 if (v.m_parent_keys.size() != v.m_child_keys.size())
337 throw std::runtime_error(
"unequal number of keys for parent and child in link");
339 auto pcv = get_validator_for_category(v.m_parent_category);
340 auto ccv = get_validator_for_category(v.m_child_category);
343 throw std::runtime_error(
"unknown parent category " + v.m_parent_category);
346 throw std::runtime_error(
"unknown child category " + v.m_child_category);
348 for (
size_t i = 0;
i < v.m_parent_keys.size(); ++
i)
350 auto piv = pcv->get_validator_for_item(v.m_parent_keys[
i]);
353 throw std::runtime_error(
"unknown parent tag _" + v.m_parent_category +
'.' + v.m_parent_keys[
i]);
355 auto civ = ccv->get_validator_for_item(v.m_child_keys[
i]);
357 throw std::runtime_error(
"unknown child tag _" + v.m_child_category +
'.' + v.m_child_keys[
i]);
359 if (civ->m_type ==
nullptr and piv->m_type !=
nullptr)
360 const_cast<item_validator *
>(civ)->m_type = piv->m_type;
363 m_link_validators.emplace_back(std::move(v));
366 std::vector<const link_validator *> validator::get_links_for_parent(std::string_view category)
const 368 std::vector<const link_validator *> result;
370 for (
auto &l : m_link_validators)
372 if (l.m_parent_category == category)
373 result.push_back(&l);
379 std::vector<const link_validator *> validator::get_links_for_child(std::string_view category)
const 381 std::vector<const link_validator *> result;
383 for (
auto &l : m_link_validators)
385 if (l.m_child_category == category)
386 result.push_back(&l);
392 void validator::report_error(
const std::string &msg,
bool fatal)
const 394 if (m_strict
or fatal)
395 throw validation_error(msg);
397 std::cerr << msg << std::endl;
402 const validator &validator_factory::operator[](std::string_view dictionary_name)
404 std::lock_guard lock(m_mutex);
406 for (
auto &validator : m_validators)
408 if (
iequals(validator.name(), dictionary_name))
415 std::filesystem::path dictionary(dictionary_name.data(), dictionary_name.data() + dictionary_name.length());
417 if (dictionary.extension() !=
".dic")
419 auto dict_name = dictionary.filename().string() +
".dic";
421 for (
auto &validator : m_validators)
423 if (
iequals(validator.name(), dict_name))
433 if (not data and dictionary.extension().string() !=
".dic")
434 data =
load_resource(dictionary.parent_path() / (dictionary.filename().string() +
".dic"));
437 construct_validator(dictionary_name, *data);
443 std::filesystem::path p = dictionary;
444 if (p.extension() ==
".dic")
445 p = p.parent_path() / (p.filename().string() +
".gz");
447 p = p.parent_path() / (p.filename().string() +
".dic.gz");
449 #if defined(CACHE_DIR) or defined(DATA_DIR) 450 if (not std::filesystem::exists(p, ec)
or ec)
452 for (
const char *dir : {
453 #if defined(CACHE_DIR) 456 #if defined(DATA_DIR) 461 auto p2 = std::filesystem::path(dir) / p;
462 if (std::filesystem::exists(p2, ec) and not ec)
471 if (std::filesystem::exists(p, ec) and not ec)
473 gzio::ifstream
in(p);
475 if (not in.is_open())
476 throw std::runtime_error(
"Could not open dictionary (" + p.string() +
")");
478 construct_validator(dictionary_name, in);
481 throw std::runtime_error(
"Dictionary not found or defined (" + dictionary.string() +
")");
484 return m_validators.back();
487 void validator_factory::construct_validator(std::string_view name,
std::istream &is)
void compare(Image< double > &op1, const Image< double > &op2)
void abs(Image< double > &op)
validator parse_dictionary(std::string_view name, std::istream &is)
std::unique_ptr< std::istream > load_resource(std::filesystem::path name)
DDL_PrimitiveType map_to_primitive_type(std::string_view s)
bool iequals(std::string_view a, std::string_view b)
regex_impl(std::string_view rx)
std::tuple< std::string, std::string > split_tag_name(std::string_view tag)
basic_istream< char, std::char_traits< char > > istream
static std::from_chars_result from_chars(const char *a, const char *b, T &d)
static std::from_chars_result from_chars(const char *a, const char *b, T &d)