27 #include "cif++/category.hpp" 28 #include "cif++/datablock.hpp" 29 #include "cif++/parser.hpp" 30 #include "cif++/utilities.hpp" 52 auto cv = cat.get_cat_validator();
54 for (
auto k : cv->m_keys)
56 uint16_t ix = cat.add_column(
k);
58 auto iv = cv->get_validator_for_item(
k);
60 throw std::runtime_error(
"Incomplete dictionary, no Item Validator for Key " +
k);
64 throw std::runtime_error(
"Incomplete dictionary, no type Validator for Item " +
k);
66 using namespace std::placeholders;
77 row_handle rha(m_category, *a);
78 row_handle rhb(m_category, *b);
81 for (
auto &
c : m_comparator)
88 std::string_view ka = rha[
k].text();
89 std::string_view kb = rhb[
k].text();
104 row_handle rhb(m_category, *b);
107 for (
auto &
c : m_comparator)
114 std::string_view ka = a[
i++].value();
115 std::string_view kb = rhb[
k].text();
127 typedef std::function<int(std::string_view, std::string_view)> compareFunc;
128 typedef std::tuple<uint16_t, compareFunc> key_comparator;
130 std::vector<key_comparator> m_comparator;
131 category &m_category;
144 , m_row_comparator(m_category)
155 row *
find(row *
k)
const;
156 row *find_by_value(row_initializer k)
const;
167 std::tuple<row *, row *> result = std::make_tuple(
nullptr,
nullptr);
169 if (m_root !=
nullptr)
171 entry *head = find_min(m_root);
172 entry *tail = reorder(m_root);
174 tail->m_row->m_next =
nullptr;
176 result = std::make_tuple(head->m_row, tail->m_row);
208 entry *insert(entry *h, row *v);
209 entry *erase(entry *h, row *k);
213 entry *rotateLeft(entry *h)
215 entry *
x = h->m_right;
216 h->m_right = x->m_left;
223 entry *rotateRight(entry *h)
225 entry *
x = h->m_left;
226 h->m_left = x->m_right;
233 void flipColour(entry *h)
235 h->m_red = not h->m_red;
237 if (h->m_left !=
nullptr)
238 h->m_left->m_red = not h->m_left->m_red;
240 if (h->m_right !=
nullptr)
241 h->m_right->m_red = not h->m_right->m_red;
244 bool is_red(entry *h)
const 246 return h !=
nullptr and h->m_red;
249 entry *move_red_left(entry *h)
253 if (h->m_right !=
nullptr and is_red(h->m_right->m_left))
255 h->m_right = rotateRight(h->m_right);
263 entry *move_red_right(entry *h)
267 if (h->m_left !=
nullptr and is_red(h->m_left->m_left))
276 entry *fix_up(entry *h)
278 if (is_red(h->m_right))
281 if (is_red(h->m_left) and is_red(h->m_left->m_left))
284 if (is_red(h->m_left) and is_red(h->m_right))
290 entry *find_min(entry *h)
292 while (h->m_left !=
nullptr)
298 entry *erase_min(entry *h)
300 if (h->m_left ==
nullptr)
307 if (not is_red(h->m_left) and not is_red(h->m_left->m_left))
308 h = move_red_left(h);
310 h->m_left = erase_min(h->m_left);
319 entry *reorder(entry *e)
323 if (e->m_left !=
nullptr)
325 auto l = reorder(e->m_left);
326 l->m_row->m_next = e->m_row;
329 if (e->m_right !=
nullptr)
331 auto mr = find_min(e->m_right);
332 e->m_row->m_next = mr->m_row;
334 result = reorder(e->m_right);
340 category &m_category;
347 const entry *r = m_root;
350 int d = m_row_comparator(k, r->m_row);
359 return r ? r->m_row :
nullptr;
367 for (
auto &
f : m_category.key_field_indices())
369 auto fld = m_category.get_column_name(
f);
371 auto ki = find_if(k.begin(), k.end(), [&fld](
auto &
i) {
return i.name() == fld; });
373 k2.emplace_back(fld,
"");
375 k2.emplace_back(*ki);
378 const entry *r = m_root;
381 int d = m_row_comparator(k2, r->m_row);
390 return r ? r->m_row :
nullptr;
395 m_root = insert(m_root, k);
396 m_root->m_red =
false;
404 int d = m_row_comparator(v, h->m_row);
406 h->m_left = insert(h->m_left, v);
408 h->m_right = insert(h->m_right, v);
411 row_handle
rh(m_category, *v);
413 std::ostringstream os;
414 for (
auto col : m_category.key_fields())
417 os << col <<
": " << std::quoted(rh[col].text()) <<
"; ";
420 throw duplicate_key_error(
"Duplicate Key violation, cat: " + m_category.name() +
" values: " + os.str());
423 if (is_red(h->m_right) and not is_red(h->m_left))
426 if (is_red(h->m_left) and is_red(h->m_left->m_left))
429 if (is_red(h->m_left) and is_red(h->m_right))
437 assert(
find(k) == k);
439 m_root = erase(m_root, k);
440 if (m_root !=
nullptr)
441 m_root->m_red =
false;
446 if (m_row_comparator(k, h->m_row) < 0)
448 if (h->m_left !=
nullptr)
450 if (not is_red(h->m_left) and not is_red(h->m_left->m_left))
451 h = move_red_left(h);
453 h->m_left = erase(h->m_left, k);
458 if (is_red(h->m_left))
461 if (m_row_comparator(k, h->m_row) == 0 and h->m_right ==
nullptr)
467 if (h->m_right !=
nullptr)
469 if (not is_red(h->m_right) and not is_red(h->m_right->m_left))
470 h = move_red_right(h);
472 if (m_row_comparator(k, h->m_row) == 0)
474 h->m_row = find_min(h->m_right)->m_row;
475 h->m_right = erase_min(h->m_right);
478 h->m_right = erase(h->m_right, k);
490 for (
auto r : m_category)
564 std::stack<entry *> s;
569 while (not s.empty())
588 category::category(std::string_view name)
593 category::category(
const category &rhs)
595 , m_columns(rhs.m_columns)
596 , m_validator(rhs.m_validator)
597 , m_cat_validator(rhs.m_cat_validator)
598 , m_cascade(rhs.m_cascade)
600 for (
auto r = rhs.m_head; r !=
nullptr; r = r->m_next)
601 insert_impl(end(), clone_row(*r));
603 if (m_cat_validator !=
nullptr and m_index ==
nullptr)
607 category::category(category &&rhs)
608 : m_name(std::move(rhs.m_name))
609 , m_columns(std::move(rhs.m_columns))
610 , m_validator(rhs.m_validator)
611 , m_cat_validator(rhs.m_cat_validator)
612 , m_parent_links(std::move(rhs.m_parent_links))
613 , m_child_links(std::move(rhs.m_child_links))
614 , m_cascade(rhs.m_cascade)
615 , m_index(rhs.m_index)
619 rhs.m_head =
nullptr;
620 rhs.m_tail =
nullptr;
621 rhs.m_index =
nullptr;
624 category &category::operator=(
const category &rhs)
632 m_columns = rhs.m_columns;
633 m_cascade = rhs.m_cascade;
635 m_validator =
nullptr;
636 m_cat_validator =
nullptr;
641 for (
auto r = rhs.m_head; r !=
nullptr; r = r->m_next)
642 insert_impl(cend(), clone_row(*r));
644 m_validator = rhs.m_validator;
645 m_cat_validator = rhs.m_cat_validator;
647 if (m_cat_validator !=
nullptr and m_index ==
nullptr)
654 category &category::operator=(category &&rhs)
658 m_name = std::move(rhs.m_name);
659 m_columns = std::move(rhs.m_columns);
660 m_cascade = rhs.m_cascade;
661 m_validator = rhs.m_validator;
662 m_cat_validator = rhs.m_cat_validator;
663 m_parent_links = rhs.m_parent_links;
664 m_child_links = rhs.m_child_links;
666 std::swap(m_index, rhs.m_index);
667 std::swap(m_head, rhs.m_head);
668 std::swap(m_tail, rhs.m_tail);
674 category::~category()
681 iset category::get_columns()
const 685 for (
auto &
col : m_columns)
686 result.insert(
col.m_name);
691 iset category::key_fields()
const 693 if (m_validator ==
nullptr)
694 throw std::runtime_error(
"No Validator specified");
696 if (m_cat_validator ==
nullptr)
697 m_validator->report_error(
"undefined Category",
true);
700 for (
auto &iv : m_cat_validator->m_item_validators)
701 result.insert(iv.m_tag);
706 std::set<uint16_t> category::key_field_indices()
const 708 if (m_validator ==
nullptr)
709 throw std::runtime_error(
"No Validator specified");
711 if (m_cat_validator ==
nullptr)
712 m_validator->report_error(
"undefined Category",
true);
714 std::set<uint16_t> result;
715 for (
auto &k : m_cat_validator->m_keys)
723 void category::set_validator(
const validator *v, datablock &db)
727 if (m_index !=
nullptr)
733 if (m_validator !=
nullptr)
735 m_cat_validator = m_validator->get_validator_for_category(m_name);
737 if (m_cat_validator !=
nullptr)
739 std::set<std::string> missing;
743 std::vector<uint16_t> kix;
744 for (
auto k : m_cat_validator->m_keys)
747 if (kix.back() >= m_columns.size())
755 std::cerr <<
"Cannot construct index since the key field" << (missing.size() > 1 ?
"s" :
"") <<
" " 756 << cif::join(missing,
", ") +
" in " + m_name +
" " + (missing.size() == 1 ?
"is" :
"are") <<
" missing" << std::endl;
760 m_cat_validator =
nullptr;
762 for (
auto &&[column, cv] : m_columns)
763 cv = m_cat_validator ? m_cat_validator->get_validator_for_item(column) :
nullptr;
768 void category::update_links(datablock &db)
770 m_child_links.clear();
771 m_parent_links.clear();
773 if (m_validator !=
nullptr)
775 for (
auto link : m_validator->get_links_for_parent(m_name))
777 auto childCat = db.get(link->m_child_category);
778 if (childCat ==
nullptr)
780 m_child_links.emplace_back(childCat, link);
783 for (
auto link : m_validator->get_links_for_child(m_name))
785 auto parentCat = db.get(link->m_parent_category);
786 if (parentCat ==
nullptr)
788 m_parent_links.emplace_back(parentCat, link);
793 bool category::is_valid()
const 797 if (m_validator ==
nullptr)
798 throw std::runtime_error(
"no Validator specified");
803 std::cerr <<
"Skipping validation of empty category " << m_name << std::endl;
807 if (m_cat_validator ==
nullptr)
809 m_validator->report_error(
"undefined category " + m_name,
false);
813 auto mandatory = m_cat_validator->m_mandatory_fields;
815 for (
auto &
col : m_columns)
817 auto iv = m_cat_validator->get_validator_for_item(
col.m_name);
820 m_validator->report_error(
"Field " +
col.m_name +
" is not valid in category " + m_name,
false);
825 if (
col.m_validator != iv)
826 m_validator->report_error(
"Column validator is not specified correctly",
true);
828 mandatory.erase(
col.m_name);
831 if (not mandatory.empty())
833 m_validator->report_error(
"In category " + m_name +
" the following mandatory fields are missing: " + join(mandatory,
", "),
false);
837 if (m_cat_validator->m_keys.empty() ==
false and m_index ==
nullptr)
839 std::set<std::string> missing;
841 for (
auto k : m_cat_validator->m_keys)
847 m_validator->report_error(
"In category " + m_name +
" the index is missing, likely due to missing key fields: " + join(missing,
", "),
false);
851 #if not defined(NDEBUG) 855 if (m_index->size() != size())
856 m_validator->report_error(
"size of index is not equal to size of category " + m_name,
true);
861 auto p = r.get_row();
862 if (m_index->find(p) != p)
863 m_validator->report_error(
"Key not found in index for category " + m_name,
true);
869 mandatory = m_cat_validator->m_mandatory_fields;
871 for (
auto ri = m_head; ri !=
nullptr; ri = ri->m_next)
873 for (uint16_t cix = 0; cix < m_columns.size(); ++cix)
876 auto iv = m_columns[cix].m_validator;
880 m_validator->report_error(
"invalid field " + m_columns[cix].m_name +
" for category " + m_name,
false);
885 auto vi = ri->get(cix);
893 catch (
const std::exception &e)
896 m_validator->report_error(
"Error validating " + m_columns[cix].m_name +
": " + e.what(),
false);
901 if (seen
or ri != m_head)
904 if (iv !=
nullptr and iv->m_mandatory)
906 m_validator->report_error(
"missing mandatory field " + m_columns[cix].m_name +
" for category " + m_name,
false);
915 bool category::validate_links()
const 922 for (
auto &link : m_parent_links)
924 auto parent = link.linked;
926 if (parent ==
nullptr)
932 if (name() ==
"atom_site" and (parent->name() ==
"pdbx_poly_seq_scheme" or parent->name() ==
"entity_poly_seq"))
936 category first_missing_rows(name());
940 auto cond = get_parents_condition(r, *parent);
943 if (not parent->exists(std::move(cond)))
946 if (
VERBOSE and first_missing_rows.size() < 5)
947 first_missing_rows.emplace(r);
955 std::cerr <<
"Links for " << link.v->m_link_group_label <<
" are incomplete" << std::endl
956 <<
" There are " << missing <<
" items in " << m_name <<
" that don't have matching parent items in " << parent->m_name << std::endl;
960 std::cerr <<
"showing first " << first_missing_rows.size() <<
" rows" << std::endl
963 first_missing_rows.write(std::cerr, link.v->m_child_keys,
false);
965 std::cerr << std::endl;
975 row_handle category::operator[](
const key_type &key)
981 if (m_index ==
nullptr)
982 throw std::logic_error(
"Category " + m_name +
" does not have an index");
984 auto row = m_index->find_by_value(key);
986 result = { *
this, *row };
994 condition category::get_parents_condition(row_handle
rh,
const category &parentCat)
const 996 if (m_validator ==
nullptr or m_cat_validator ==
nullptr)
997 throw std::runtime_error(
"No validator known for category " + m_name);
1001 for (
auto &link : m_validator->get_links_for_child(m_name))
1003 if (link->m_parent_category != parentCat.m_name)
1008 for (
size_t ix = 0; ix < link->m_child_keys.size(); ++ix)
1010 auto childValue = rh[link->m_child_keys[ix]];
1012 if (childValue.empty())
1015 cond = std::move(cond) and key(link->m_parent_keys[ix]) == childValue.text();
1018 result = std::move(result)
or std::move(cond);
1024 condition category::get_children_condition(row_handle rh,
const category &childCat)
const 1026 if (m_validator ==
nullptr or m_cat_validator ==
nullptr)
1027 throw std::runtime_error(
"No validator known for category " + m_name);
1031 iset mandatoryChildFields;
1032 auto childCatValidator = m_validator->get_validator_for_category(childCat.name());
1033 if (childCatValidator !=
nullptr)
1034 mandatoryChildFields = childCatValidator->m_mandatory_fields;
1036 for (
auto &link : m_validator->get_links_for_parent(m_name))
1038 if (link->m_child_category != childCat.m_name)
1043 for (
size_t ix = 0; ix < link->m_parent_keys.size(); ++ix)
1045 auto childKey = link->m_child_keys[ix];
1046 auto parentKey = link->m_parent_keys[ix];
1048 auto parentValue = rh[parentKey];
1050 if (parentValue.empty())
1051 cond = std::move(cond) and key(childKey) == null;
1052 else if (link->m_parent_keys.size() > 1 and mandatoryChildFields.find(childKey) == mandatoryChildFields.end())
1053 cond = std::move(cond) and (key(childKey) == parentValue.text()
or key(childKey) == null);
1055 cond = std::move(cond) and key(childKey) == parentValue.text();
1058 result = std::move(result)
or std::move(cond);
1064 bool category::has_children(row_handle r)
const 1066 bool result =
false;
1068 for (
auto &&[childCat, link] : m_child_links)
1070 if (not childCat->exists(get_children_condition(r, *childCat)))
1080 bool category::has_parents(row_handle r)
const 1082 bool result =
false;
1084 for (
auto &&[parentCat, link] : m_parent_links)
1086 if (not parentCat->exists(get_parents_condition(r, *parentCat)))
1096 std::vector<row_handle> category::get_children(row_handle r,
const category &childCat)
const 1098 if (m_validator ==
nullptr or m_cat_validator ==
nullptr)
1099 throw std::runtime_error(
"No validator known for category " + m_name);
1101 std::vector<row_handle> result;
1103 for (
auto child : childCat.find(get_children_condition(r, childCat)))
1105 if (
std::find(result.begin(), result.end(), child) == result.end())
1106 result.push_back(child);
1112 std::vector<row_handle> category::get_parents(row_handle r,
const category &parentCat)
const 1114 assert(m_validator !=
nullptr);
1115 assert(m_cat_validator !=
nullptr);
1117 std::vector<row_handle> result;
1119 for (
auto parent : parentCat.find(get_parents_condition(r, parentCat)))
1121 if (
std::find(result.begin(), result.end(), parent) == result.end())
1122 result.push_back(parent);
1128 std::vector<row_handle> category::get_linked(row_handle r,
const category &cat)
const 1130 std::vector<row_handle> result = get_children(r, cat);
1132 result = get_parents(r, cat);
1138 category::iterator category::erase(iterator pos)
1140 row_handle rh = *pos;
1141 row *r = rh.get_row();
1142 iterator result = ++pos;
1144 if (m_head ==
nullptr)
1145 throw std::runtime_error(
"erase");
1147 if (m_index !=
nullptr)
1152 m_head = m_head->m_next;
1153 r->m_next =
nullptr;
1157 for (
auto pi = m_head;
pi !=
nullptr;
pi =
pi->m_next)
1159 if (
pi->m_next == r)
1161 pi->m_next = r->m_next;
1162 r->m_next =
nullptr;
1176 if (m_validator !=
nullptr)
1178 for (
auto &&[childCat, link] : m_child_links)
1179 childCat->erase_orphans(get_children_condition(rh, *childCat), *
this);
1188 if (m_tail !=
nullptr)
1189 while (m_tail->m_next !=
nullptr)
1190 m_tail = m_tail->m_next;
1196 template<
typename T>
1202 , m_sv(std::exchange(m_v, nv))
1216 size_t category::erase(condition &&cond)
1218 return erase(std::move(cond), {});
1221 size_t category::erase(condition &&cond, std::function<
void(row_handle)> &&visit)
1225 cond.prepare(*
this);
1227 std::map<category *, condition> potential_orphans;
1237 for (
auto &&[childCat, link] : m_child_links)
1239 auto ccond = get_children_condition(*ri, *childCat);
1242 potential_orphans[childCat] = std::move(potential_orphans[childCat])
or std::move(ccond);
1254 for (
auto &&[childCat, condition] : potential_orphans)
1255 childCat->erase_orphans(std::move(condition), *
this);
1260 void category::clear()
1263 while (
i !=
nullptr)
1270 m_head = m_tail =
nullptr;
1276 void category::erase_orphans(condition &&cond, category &parent)
1278 std::vector<row *>
remove;
1280 cond.prepare(*
this);
1282 for (
auto r : *
this)
1287 if (parent.exists(get_parents_condition(r, parent)))
1294 std::cerr <<
"Removing orphaned record: " << std::endl
1300 remove.emplace_back(r.m_row);
1303 for (
auto r :
remove)
1304 erase(iterator(*
this, r));
1307 std::string category::get_unique_id(std::function<std::string(
int)> generator)
1309 using namespace cif::literals;
1311 std::string id_tag =
"id";
1312 if (m_cat_validator !=
nullptr and m_cat_validator->m_keys.size() == 1)
1313 id_tag = m_cat_validator->m_keys.front();
1316 if (m_last_unique_num == 0)
1317 m_last_unique_num =
static_cast<uint32_t
>(size());
1321 std::string result = generator(static_cast<int>(m_last_unique_num++));
1323 if (exists(key(id_tag) == result))
1330 void category::update_value(
const std::vector<row_handle> &rows, std::string_view tag, std::string_view value)
1338 if (colIx >= m_columns.size())
1339 throw std::runtime_error(
"Invalid column " + std::string{ value } +
" for " + m_name);
1341 auto &
col = m_columns[colIx];
1344 if (
col.m_validator)
1345 (*
col.m_validator)(value);
1348 std::string oldValue{ rows.front()[tag].text() };
1349 for (
auto row : rows)
1351 if (oldValue != row[tag].text())
1352 throw std::runtime_error(
"Inconsistent old values in update_value");
1355 if (oldValue == value)
1359 for (
auto row : rows)
1360 row.assign(colIx, value,
false);
1363 for (
auto parent : rows)
1365 for (
auto &&[childCat, linked] : m_child_links)
1367 if (
std::find(linked->m_parent_keys.begin(), linked->m_parent_keys.end(), tag) == linked->m_parent_keys.end())
1371 std::string childTag;
1373 for (
size_t ix = 0; ix < linked->m_parent_keys.size(); ++ix)
1375 std::string pk = linked->m_parent_keys[ix];
1376 std::string ck = linked->m_child_keys[ix];
1381 cond = std::move(cond) && key(ck) == oldValue;
1384 cond = std::move(cond) && key(ck) == parent[pk].text();
1387 auto children = childCat->find(std::move(cond));
1388 if (children.empty())
1391 std::vector<row_handle> child_rows;
1392 std::copy(children.begin(), children.end(), std::back_inserter(child_rows));
1398 std::vector<row_handle> process;
1400 for (
auto child : child_rows)
1404 for (
size_t ix = 0; ix < linked->m_parent_keys.size(); ++ix)
1406 std::string pk = linked->m_parent_keys[ix];
1407 std::string ck = linked->m_child_keys[ix];
1409 cond_c = std::move(cond_c) && key(pk) == child[ck].text();
1412 auto parents =
find(std::move(cond_c));
1413 if (parents.empty())
1415 process.push_back(child);
1422 for (
size_t ix = 0; ix < linked->m_parent_keys.size(); ++ix)
1424 std::string pk = linked->m_parent_keys[ix];
1425 std::string ck = linked->m_child_keys[ix];
1428 check = std::move(check) && key(ck) == value;
1430 check = std::move(check) && key(ck) == parent[pk].text();
1433 if (childCat->exists(std::move(check)))
1437 if (childCat->m_cat_validator !=
nullptr and childCat->m_cat_validator->m_keys.size() == 1)
1439 auto copy = childCat->create_copy(child);
1442 process.push_back(child);
1449 std::cerr <<
"Cannot update child " << childCat->m_name <<
"." << childTag <<
" with value " << value << std::endl;
1453 if (not process.empty())
1454 childCat->update_value(process, childTag, value);
1459 void category::update_value(row *row, uint16_t column, std::string_view value,
bool updateLinked,
bool validate)
1462 if (m_index ==
nullptr and m_cat_validator !=
nullptr)
1465 auto &
col = m_columns[column];
1467 std::string_view oldValue;
1469 auto ival = row->get(column);
1470 if (ival !=
nullptr)
1471 oldValue = ival->text();
1473 if (value == oldValue)
1476 std::string oldStrValue{ oldValue };
1479 if (
col.m_validator and validate)
1480 col.m_validator->operator()(value);
1485 bool reinsert =
false;
1486 if (updateLinked and
1487 m_index !=
nullptr and key_field_indices().count(column))
1489 reinsert = m_index->find(row);
1491 m_index->erase(row);
1495 if (ival !=
nullptr)
1496 row->remove(column);
1498 if (not value.empty())
1499 row->append(column, { value });
1502 m_index->insert(row);
1505 auto iv =
col.m_validator;
1506 if (updateLinked and iv !=
nullptr )
1508 row_handle
rh(*
this, *row);
1510 for (
auto &&[childCat, linked] : m_child_links)
1512 if (
std::find(linked->m_parent_keys.begin(), linked->m_parent_keys.end(), iv->m_tag) == linked->m_parent_keys.end())
1516 std::string childTag;
1518 for (
size_t ix = 0; ix < linked->m_parent_keys.size(); ++ix)
1520 std::string pk = linked->m_parent_keys[ix];
1521 std::string ck = linked->m_child_keys[ix];
1525 if (pk == iv->m_tag)
1528 cond = std::move(cond) and key(ck) == oldStrValue;
1532 std::string_view pk_value = rh[pk].text();
1533 if (pk_value.empty())
1534 cond = std::move(cond) and key(ck) == null;
1536 cond = std::move(cond) and ((key(ck) == pk_value)
or key(ck) == null);
1540 auto rows = childCat->find(std::move(cond));
1555 for (
size_t ix = 0; ix < linked->m_parent_keys.size(); ++ix)
1557 std::string pk = linked->m_parent_keys[ix];
1558 std::string ck = linked->m_child_keys[ix];
1560 if (pk == iv->m_tag)
1561 cond_n = std::move(cond_n) and key(ck) == value;
1564 std::string_view pk_value = rh[pk].text();
1565 if (pk_value.empty())
1566 cond_n = std::move(cond_n) and key(ck) == null;
1568 cond_n = std::move(cond_n) and key(ck) == pk_value;
1572 auto rows_n = childCat->find(std::move(cond_n));
1573 if (not rows_n.empty())
1576 std::cerr <<
"Will not rename in child category since there are already rows that link to the parent" << std::endl;
1581 for (
auto cr : rows)
1582 cr.assign(childTag, value,
false);
1587 row *category::clone_row(
const row &r)
1589 row *result = create_row();
1593 for (uint16_t ix = 0; ix < r.size(); ++ix)
1599 result->append( ix, { i.text() });
1611 void category::delete_row(row *r)
1615 row_allocator_type ra(get_allocator());
1616 row_allocator_traits::destroy(ra, r);
1617 row_allocator_traits::deallocate(ra, r, 1);
1621 row_handle category::create_copy(row_handle r)
1624 std::vector<item> items;
1626 for (uint16_t ix = 0; ix < r.m_row->size(); ++ix)
1628 auto i = r.m_row->get(ix);
1630 items.emplace_back(m_columns[ix].m_name,
i->text());
1633 if (m_cat_validator and m_cat_validator->m_keys.size() == 1)
1635 auto key = m_cat_validator->m_keys.front();
1636 auto kv = m_cat_validator->get_validator_for_item(key);
1638 for (
auto &item : items)
1640 if (item.name() != key)
1643 if (kv->m_type->m_primitive_type == DDL_PrimitiveType::Numb)
1644 item.value(get_unique_id(
""));
1646 item.value(get_unique_id(m_name +
"_id_"));
1651 return emplace(items.begin(), items.end());
1655 category::iterator category::insert_impl(const_iterator pos, row *
n)
1657 if (m_index ==
nullptr and m_cat_validator !=
nullptr)
1660 assert(n !=
nullptr);
1661 assert(n->m_next ==
nullptr);
1664 throw std::runtime_error(
"Invalid pointer passed to insert");
1674 if (m_cat_validator !=
nullptr)
1676 for (uint16_t ix = 0; ix < static_cast<uint16_t>(m_columns.size()); ++ix)
1678 const auto &[column, iv] = m_columns[ix];
1685 auto i = n->get(ix);
1688 iv->operator()(
i->text());
1692 if (not seen and iv->m_mandatory)
1693 throw std::runtime_error(
"missing mandatory field " + column +
" for category " + m_name);
1697 if (m_index !=
nullptr)
1701 if (pos.m_current ==
nullptr)
1703 if (m_head ==
nullptr)
1704 m_tail = m_head =
n;
1706 m_tail = m_tail->m_next =
n;
1710 assert(m_head !=
nullptr);
1712 if (pos.m_current == m_head)
1713 m_head = n->m_next = m_head;
1715 n = n->m_next = m_head->m_next;
1718 return iterator(*
this, n);
1720 catch (
const std::exception &e)
1732 void category::swap_item(uint16_t column_ix, row_handle &
a, row_handle &
b)
1734 assert(
this == a.m_category);
1735 assert(
this == b.m_category);
1737 auto &ra = *a.m_row;
1738 auto &rb = *b.m_row;
1740 std::swap(ra.at(column_ix), rb.at(column_ix));
1745 if (m_head ==
nullptr)
1748 std::vector<row_handle> rows;
1749 for (
auto itemRow = m_head; itemRow !=
nullptr; itemRow = itemRow->m_next)
1750 rows.emplace_back(*
this, *itemRow);
1752 std::stable_sort(rows.begin(), rows.end(),
1753 [&
f](row_handle ia, row_handle ib)
1755 return f(ia, ib) < 0;
1758 m_head = rows.front().get_row();
1759 m_tail = rows.back().get_row();
1762 for (
size_t i = 1;
i < rows.size(); ++
i)
1763 r = r->m_next = rows[
i].get_row();
1764 r->m_next =
nullptr;
1766 assert(r == m_tail);
1767 assert(size() == rows.size());
1770 void category::reorder_by_index()
1773 std::tie(m_head, m_tail) = m_index->reorder();
1779 size_t write_value(std::ostream &os, std::string_view value,
size_t offset,
size_t width)
1781 if (value.find(
'\n') != std::string::npos
or width == 0
or value.length() > 132)
1788 for (
auto ch : value)
1790 if (pc ==
'\n' and ch ==
';')
1796 if (value.back() !=
'\n')
1801 else if (sac_parser::is_unquoted_string(value))
1805 if (value.length() < width)
1807 os << std::string(width - value.length(),
' ');
1813 offset += value.length() + 1;
1819 for (
char q : {
'\'',
'"' })
1821 auto p = value.find(q);
1822 while (p != std::string::npos and sac_parser::is_non_blank(value[p + 1]) and value[p + 1] != q)
1823 p = value.find(q, p + 1);
1825 if (p != std::string::npos)
1828 os << q << value << q;
1830 if (value.length() + 2 < width)
1832 os << std::string(width - value.length() - 2,
' ');
1838 offset += value.length() + 1;
1849 os <<
';' << value <<
'\n' 1860 std::vector<std::string> category::get_tag_order()
const 1862 std::vector<std::string> result;
1863 for (
auto &
c : m_columns)
1864 result.push_back(
"_" + m_name +
"." +
c.m_name);
1870 std::vector<uint16_t> order(m_columns.size());
1871 iota(order.begin(), order.end(),
static_cast<uint16_t
>(0));
1872 write(os, order,
false);
1875 void category::write(std::ostream &os,
const std::vector<std::string> &columns,
bool addMissingColumns)
1878 for (
auto &
c : columns)
1881 std::vector<uint16_t> order;
1882 order.reserve(m_columns.size());
1884 for (
auto &
c : columns)
1887 if (addMissingColumns)
1889 for (uint16_t
i = 0;
i < m_columns.size(); ++
i)
1891 if (
std::find(order.begin(), order.end(),
i) == order.end())
1896 write(os, order,
true);
1899 void category::write(std::ostream &os,
const std::vector<uint16_t> &order,
bool includeEmptyColumns)
const 1905 bool needLoop = (m_head->m_next !=
nullptr);
1909 os <<
"loop_" <<
'\n';
1911 std::vector<size_t> columnWidths(m_columns.size());
1913 for (
auto cix : order)
1915 auto &
col = m_columns[cix];
1917 if (not m_name.empty())
1918 os << m_name <<
'.';
1919 os <<
col.m_name <<
' ' <<
'\n';
1920 columnWidths[cix] = 2;
1923 for (
auto r = m_head; r !=
nullptr; r = r->m_next)
1925 for (uint16_t ix = 0; ix < r->size(); ++ix)
1927 auto v = r->get(ix);
1931 if (v->text().find(
'\n') == std::string_view::npos)
1933 size_t l = v->text().length();
1935 if (not sac_parser::is_unquoted_string(v->text()))
1941 if (columnWidths[ix] < l + 1)
1942 columnWidths[ix] = l + 1;
1947 for (
auto r = m_head; r !=
nullptr; r = r->m_next)
1951 for (uint16_t cix : order)
1953 size_t w = columnWidths[cix];
1956 auto iv = r->get(cix);
1963 size_t l = s.length();
1964 if (not sac_parser::is_unquoted_string(s))
1969 if (offset + l > 132 and offset > 0)
1993 for (
auto &
col : m_columns)
1995 std::string tag =
'_' + m_name +
'.' +
col.m_name;
1997 if (l < tag.length())
2003 for (uint16_t cix : order)
2005 auto &
col = m_columns[cix];
2008 if (not m_name.empty())
2009 os << m_name <<
'.';
2010 os <<
col.m_name << std::string(l -
col.m_name.length() - m_name.length() - 2,
' ');
2013 auto iv = m_head->get(cix);
2040 using namespace std::placeholders;
2047 const category_validator *catValidator =
nullptr;
2049 auto validator = a.get_validator();
2050 if (validator !=
nullptr)
2051 catValidator = validator->get_validator_for_category(a.name());
2053 typedef std::function<int(std::string_view,std::string_view)> compType;
2054 std::vector<std::tuple<std::string,compType>> tags;
2055 std::vector<std::string> keys;
2056 std::vector<size_t> keyIx;
2058 if (catValidator ==
nullptr)
2060 for (
auto& tag: a.get_columns())
2062 tags.push_back(std::make_tuple(tag, [](std::string_view va, std::string_view vb) {
return va.compare(vb); }));
2063 keyIx.push_back(keys.size());
2064 keys.push_back(tag);
2069 keys = catValidator->m_keys;
2071 for (
auto& tag: a.key_fields())
2073 auto iv = catValidator->get_validator_for_item(tag);
2075 throw std::runtime_error(
"missing item validator");
2076 auto tv = iv->m_type;
2078 throw std::runtime_error(
"missing type validator");
2081 auto pred = [tag](
const std::string& s) ->
bool {
return cif::iequals(tag, s) == 0; };
2082 if (find_if(keys.begin(), keys.end(), pred) == keys.end())
2083 keyIx.push_back(tags.size() - 1);
2090 auto rowEqual = [&](
const row_handle&
a,
const row_handle&
b)
2094 for (
auto kix: keyIx)
2099 std::tie(tag, compare) = tags[kix];
2101 d =
compare(a[tag].text(), b[tag].text());
2110 auto ai = a.begin(), bi = b.begin();
2111 while (ai != a.end()
or bi != b.end())
2113 if (ai == a.end()
or bi == b.end())
2116 auto ra = *ai, rb = *bi;
2118 if (not rowEqual(ra, rb))
2121 std::vector<std::string> missingA, missingB, different;
2123 for (
auto& tt: tags)
2128 std::tie(tag, compare) = tt;
2132 auto ta = ra[tag].text();
if (ta ==
"." or ta ==
"?") ta =
"";
2133 auto tb = rb[tag].text();
if (tb ==
"." or tb ==
"?") tb =
"";
row * find_by_value(row_initializer k) const
void write(std::ostream &os, const datablock &db)
int operator()(const row_initializer &a, const row *b) const
bool operator==(faketype, faketype)
std::vector< SelLine >::iterator find(std::vector< SelLine > &text, const std::string &img_name)
void compare(Image< double > &op1, const Image< double > &op2)
uint16_t get_column_ix(const category &cat, std::string_view col)
size_t write_value(std::ostream &os, std::string_view value, size_t offset, size_t width)
std::tuple< row *, row * > reorder()
bool iequals(std::string_view a, std::string_view b)
ql0001_ & k(htemp+1),(cvec+1),(atemp+1),(bj+1),(bl+1),(bu+1),(x+1),(clamda+1), &iout, infoqp, &zero,(w+1), &lenw,(iw+1), &leniw, &glob_grd.epsmac
save_value(T &v, const T nv={})
category_index(category *cat)
row_comparator(category &cat)
int operator()(const row *a, const row *b) const
void sort(struct DCEL_T *dcel)
const uint32_t kMaxLineLength
check(nparam, nf, nfsr, &Linfty, nineq, nineqn, neq, neqn, ncsrl, ncsrn, mode, &modem, eps, bgbnd, param)