Commit 782f7c46 by Maarten L. Hekkelman

Support for cifv1.0 (empty category names)

parent c45d02cb
Version 5.0.1
- Fix loading dictionaries
- Support for cifv1.0 files
Version 5.0.0
- Total rewrite of cif part
......
......@@ -86,7 +86,7 @@ class category
const std::string &name() const { return m_name; }
iset fields() const;
iset key_fields() const;
std::set<uint16_t> key_field_indices() const;
......@@ -482,6 +482,8 @@ class category
return get_column_ix(name) < m_columns.size();
}
iset get_columns() const;
// --------------------------------------------------------------------
void sort(std::function<int(row_handle,row_handle)> f);
......
......@@ -410,7 +410,7 @@ category_index::entry *category_index::insert(entry *h, row *v)
row_handle rh(m_category, *v);
std::ostringstream os;
for (auto col : m_category.fields())
for (auto col : m_category.key_fields())
{
if (rh[col])
os << col << ": " << std::quoted(rh[col].text()) << "; ";
......@@ -686,7 +686,17 @@ category::~category()
// --------------------------------------------------------------------
iset category::fields() const
iset category::get_columns() const
{
iset result;
for (auto &col : m_columns)
result.insert(col.m_name);
return result;
}
iset category::key_fields() const
{
if (m_validator == nullptr)
throw std::runtime_error("No Validator specified");
......@@ -1853,7 +1863,10 @@ void category::write(std::ostream &os, const std::vector<uint16_t> &order, bool
for (auto cix : order)
{
auto &col = m_columns[cix];
os << '_' << m_name << '.' << col.m_name << ' ' << '\n';
os << '_';
if (not m_name.empty())
os << m_name << '.';
os << col.m_name << ' ' << '\n';
columnWidths[cix] = 2;
}
......@@ -1941,7 +1954,10 @@ void category::write(std::ostream &os, const std::vector<uint16_t> &order, bool
{
auto &col = m_columns[cix];
os << '_' << m_name << '.' << col.m_name << std::string(l - col.m_name.length() - m_name.length() - 2, ' ');
os << '_';
if (not m_name.empty())
os << m_name << '.';
os << col.m_name << std::string(l - col.m_name.length() - m_name.length() - 2, ' ');
std::string_view s;
auto iv = m_head->get(cix);
......@@ -1978,29 +1994,44 @@ bool category::operator==(const category &rhs) const
// if (tagsA != tagsB)
// std::cout << "Unequal number of fields" << std::endl;
const category_validator *catValidator = nullptr;
auto validator = a.get_validator();
auto catValidator = validator->get_validator_for_category(a.name());
if (catValidator == nullptr)
throw std::runtime_error("missing cat validator");
if (validator != nullptr)
catValidator = validator->get_validator_for_category(a.name());
typedef std::function<int(std::string_view,std::string_view)> compType;
std::vector<std::tuple<std::string,compType>> tags;
auto keys = catValidator->m_keys;
std::vector<std::string> keys;
std::vector<size_t> keyIx;
for (auto& tag: a.fields())
if (catValidator == nullptr)
{
auto iv = catValidator->get_validator_for_item(tag);
if (iv == nullptr)
throw std::runtime_error("missing item validator");
auto tv = iv->m_type;
if (tv == nullptr)
throw std::runtime_error("missing type validator");
tags.push_back(std::make_tuple(tag, std::bind(&cif::type_validator::compare, tv, std::placeholders::_1, std::placeholders::_2)));
auto pred = [tag](const std::string& s) -> bool { return cif::iequals(tag, s) == 0; };
if (find_if(keys.begin(), keys.end(), pred) == keys.end())
keyIx.push_back(tags.size() - 1);
for (auto& tag: a.get_columns())
{
tags.push_back(std::make_tuple(tag, [](std::string_view va, std::string_view vb) { return va.compare(vb); }));
keyIx.push_back(keys.size());
keys.push_back(tag);
}
}
else
{
keys = catValidator->m_keys;
for (auto& tag: a.key_fields())
{
auto iv = catValidator->get_validator_for_item(tag);
if (iv == nullptr)
throw std::runtime_error("missing item validator");
auto tv = iv->m_type;
if (tv == nullptr)
throw std::runtime_error("missing type validator");
tags.push_back(std::make_tuple(tag, std::bind(&cif::type_validator::compare, tv, std::placeholders::_1, std::placeholders::_2)));
auto pred = [tag](const std::string& s) -> bool { return cif::iequals(tag, s) == 0; };
if (find_if(keys.begin(), keys.end(), pred) == keys.end())
keyIx.push_back(tags.size() - 1);
}
}
// a.reorderByIndex();
......
......@@ -32,7 +32,7 @@ namespace cif
iset get_category_fields(const category &cat)
{
return cat.fields();
return cat.key_fields();
}
uint16_t get_column_ix(const category &cat, std::string_view col)
......
......@@ -695,7 +695,8 @@ void sac_parser::parse_global()
void sac_parser::parse_datablock()
{
std::string cat;
static const std::string kUnitializedCategory("<invalid>");
std::string cat = kUnitializedCategory; // intial value acts as a guard for empty category names
while (m_lookahead == CIFToken::LOOP or m_lookahead == CIFToken::Tag or m_lookahead == CIFToken::SAVE)
{
......@@ -703,7 +704,7 @@ void sac_parser::parse_datablock()
{
case CIFToken::LOOP:
{
cat.clear(); // should start a new category
cat = kUnitializedCategory; // should start a new category
match(CIFToken::LOOP);
......@@ -714,7 +715,7 @@ void sac_parser::parse_datablock()
std::string catName, itemName;
std::tie(catName, itemName) = split_tag_name(m_token_value);
if (cat.empty())
if (cat == kUnitializedCategory)
{
produce_category(catName);
cat = catName;
......@@ -800,6 +801,9 @@ void parser::produce_row()
if (VERBOSE >= 4)
std::cerr << "producing row for category " << m_category->name() << std::endl;
if (m_category == nullptr)
error("inconsistent categories in loop_");
m_category->emplace({});
m_row = m_category->back();
// m_row.lineNr(m_line_nr);
......@@ -810,7 +814,7 @@ void parser::produce_item(const std::string &category, const std::string &item,
if (VERBOSE >= 4)
std::cerr << "producing _" << category << '.' << item << " -> " << value << std::endl;
if (not iequals(category, m_category->name()))
if (m_category == nullptr or not iequals(category, m_category->name()))
error("inconsistent categories in loop_");
m_row[item] = m_token_value;
......
......@@ -1483,7 +1483,7 @@ bool Remark3Parser::parse(const std::string &expMethod, PDBRecord *r, cif::datab
auto r1 = cat1.front();
auto r2 = cat2.front();
for (auto column : cat1.fields())
for (auto column : cat1.key_fields())
r2[column] = r1[column].text();
}
}
......
......@@ -224,9 +224,10 @@ std::tuple<std::string, std::string> split_tag_name(std::string_view tag)
auto s = tag.find('.');
if (s == std::string::npos)
throw std::runtime_error("tag does not contain dot (" + std::string{ tag } + ')');
return std::tuple<std::string, std::string>{
tag.substr(1, s - 1), tag.substr(s + 1)};
// throw std::runtime_error("tag does not contain dot (" + std::string{ tag } + ')');
return std::tuple<std::string, std::string>{ "", tag.substr(1) };
else
return std::tuple<std::string, std::string>{tag.substr(1, s - 1), tag.substr(s + 1)};
}
// --------------------------------------------------------------------
......
......@@ -2970,3 +2970,91 @@ _cat_1.id_2
for (const auto &[key, test] : TESTS)
BOOST_CHECK_EQUAL((bool)cat1[key], test);
}
// --------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(cifv1_0_1)
{
auto f = R"(data_TEST
#
loop_
_id
_name
1 aap
2 noot
3 mies
4 ?
5 .
)"_cf;
auto &db = f.front();
auto &cat = db[""];
for (auto r : cat)
{
int id;
std::optional<std::string> name;
cif::tie(id, name) = r.get("id", "name");
switch (id)
{
case 1: BOOST_CHECK_EQUAL(*name, "aap"); break;
case 2: BOOST_CHECK_EQUAL(*name, "noot"); break;
case 3: BOOST_CHECK_EQUAL(*name, "mies"); break;
default: BOOST_CHECK(name.has_value() == false);
}
}
std::stringstream ss;
ss << db;
auto f2 = cif::file(ss);
auto &db2 = f2.front();
BOOST_TEST(db == db2);
}
// BOOST_AUTO_TEST_CASE(cifv1_0_2)
// {
// BOOST_CHECK_THROW(R"(data_TEST
// #
// _version 1.0
// loop_
// _id
// _name
// 1 aap
// 2 noot
// 3 mies
// 4 ?
// 5 .
// )"_cf, cif::parse_error);
// }
BOOST_AUTO_TEST_CASE(cifv1_0_3)
{
auto f = R"(data_TEST
#
_version 1.0
_date today
)"_cf;
auto &db = f.front();
auto &cat = db[""];
BOOST_CHECK(not cat.empty());
auto r = cat.front();
BOOST_CHECK_EQUAL(r["version"].as<std::string>(), "1.0");
BOOST_CHECK_EQUAL(r["date"].as<std::string>(), "today");
std::stringstream ss;
ss << db;
auto f2 = cif::file(ss);
auto &db2 = f2.front();
BOOST_TEST(db == db2);
}
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