Commit 2f249048 by Maarten L. Hekkelman

Merge branch 'develop' of github.com:PDB-REDO/libcifpp into develop

parents 974cb40a c01c16ea
......@@ -12,3 +12,5 @@ CMakeSettings.json
msvc/
Testing/
rsrc/feature-request.txt
test/test-create_sugar_?.cif
test/oprofile_data/
......@@ -192,6 +192,10 @@ set(project_sources
${PROJECT_SOURCE_DIR}/src/symmetry.cpp
${PROJECT_SOURCE_DIR}/src/model.cpp
${PROJECT_SOURCE_DIR}/src/pdb/cif2pdb.cpp
${PROJECT_SOURCE_DIR}/src/pdb/pdb2cif.cpp
${PROJECT_SOURCE_DIR}/src/pdb/pdb2cif_remark_3.cpp
)
set(project_headers
......@@ -216,7 +220,12 @@ set(project_headers
${PROJECT_SOURCE_DIR}/include/cif++/symmetry.hpp
${PROJECT_SOURCE_DIR}/include/cif++/model.hpp
)
${PROJECT_SOURCE_DIR}/include/cif++/pdb/cif2pdb.hpp
${PROJECT_SOURCE_DIR}/include/cif++/pdb/io.hpp
${PROJECT_SOURCE_DIR}/include/cif++/pdb/pdb2cif.hpp
${PROJECT_SOURCE_DIR}/include/cif++/pdb/pdb2cif_remark_3.hpp
)
add_library(cifpp ${project_sources} ${project_headers} ${PROJECT_SOURCE_DIR}/src/symop_table_data.hpp)
add_library(cifpp::cifpp ALIAS cifpp)
......@@ -370,8 +379,7 @@ if(ENABLE_TESTING)
find_package(Boost REQUIRED headers)
list(APPEND CIFPP_tests unit-v2 unit-3d format model
# rename-compound sugar
list(APPEND CIFPP_tests unit-v2 unit-3d format model rename-compound sugar
)
foreach(CIFPP_TEST IN LISTS CIFPP_tests)
......
......@@ -35,4 +35,6 @@
#include <cif++/point.hpp>
#include <cif++/symmetry.hpp>
#include <cif++/model.hpp>
\ No newline at end of file
#include <cif++/model.hpp>
#include <cif++/pdb/io.hpp>
......@@ -88,7 +88,7 @@ class category
const category_validator *get_cat_validator() const { return m_cat_validator; }
bool is_valid() const;
void validate_links() const;
bool validate_links() const;
bool operator==(const category &rhs) const;
bool operator!=(const category &rhs) const
......@@ -159,6 +159,22 @@ class category
}
// --------------------------------------------------------------------
// A category can have a key, as defined by the validator/dictionary
/// @brief The key type
using key_type = row_initializer;
/// @brief Return a row_handle for the row specified by \a key
/// @param key The value for the key, fields specified in the dictionary should have a value
/// @return The row found in the index, or an undefined row_handle
row_handle operator[](const key_type &key);
const row_handle operator[](const key_type &key) const
{
return const_cast<category *>(this)->operator[](key);
}
// --------------------------------------------------------------------
template <typename... Ts, typename... Ns>
iterator_proxy<const category, Ts...> rows(Ns... names) const
......@@ -290,12 +306,19 @@ class category
{
cond.prepare(*this);
for (auto r : *this)
auto sh = cond.single();
if (sh.has_value() and *sh)
result = true;
else
{
if (cond(r))
for (auto r : *this)
{
result = true;
break;
if (cond(r))
{
result = true;
break;
}
}
}
}
......@@ -335,7 +358,7 @@ class category
iterator emplace(row_initializer &&ri)
{
return this->emplace(ri.m_items.begin(), ri.m_items.end());
return this->emplace(ri.begin(), ri.end());
}
template <typename ItemIter>
......@@ -527,6 +550,14 @@ class category
return create_item(ix, i.value());
}
item_value *create_item(const std::tuple<std::string_view,std::string> &i)
{
const auto &[name, value] = i;
uint16_t ix = add_column(name);
return create_item(ix, value);
}
void delete_item(item_value *iv)
{
if (iv->m_length >= item_value::kBufferSize)
......
......@@ -30,6 +30,7 @@
#include <functional>
#include <iostream>
#include <regex>
#include <utility>
#include <cif++/row.hpp>
......@@ -52,9 +53,10 @@ namespace detail
{
virtual ~condition_impl() {}
virtual void prepare(const category &c) {}
virtual condition_impl *prepare(const category &c) { return this; }
virtual bool test(row_handle r) const = 0;
virtual void str(std::ostream &os) const = 0;
virtual std::optional<row_handle> single() const { return {}; };
};
struct all_condition_impl : public condition_impl
......@@ -105,12 +107,7 @@ class condition
m_impl = nullptr;
}
void prepare(const category &c)
{
if (m_impl)
m_impl->prepare(c);
m_prepared = true;
}
void prepare(const category &c);
bool operator()(row_handle r) const
{
......@@ -122,6 +119,11 @@ class condition
explicit operator bool() { return not empty(); }
bool empty() const { return m_impl == nullptr; }
std::optional<row_handle> single() const
{
return m_impl ? m_impl->single() : std::optional<row_handle>();
}
friend condition operator||(condition &&a, condition &&b);
friend condition operator&&(condition &&a, condition &&b);
......@@ -143,6 +145,9 @@ class condition
}
private:
void optimise(condition_impl *&impl);
condition_impl *m_impl;
bool m_prepared = false;
};
......@@ -156,9 +161,10 @@ namespace detail
{
}
void prepare(const category &c) override
condition_impl *prepare(const category &c) override
{
m_item_ix = get_column_ix(c, m_item_tag);
return this;
}
bool test(row_handle r) const override
......@@ -175,6 +181,85 @@ namespace detail
size_t m_item_ix = 0;
};
struct key_equals_condition_impl : public condition_impl
{
key_equals_condition_impl(item &&i)
: m_item_tag(i.name())
, m_value(i.value())
{
}
condition_impl *prepare(const category &c) override;
bool test(row_handle r) const override
{
return m_single_hit.has_value() ?
*m_single_hit == r :
r[m_item_ix].compare(m_value, m_icase) == 0;
}
void str(std::ostream &os) const override
{
os << m_item_tag << (m_icase ? "^ " : " ") << " == " << m_value;
}
virtual std::optional<row_handle> single() const override
{
return m_single_hit;
}
std::string m_item_tag;
size_t m_item_ix = 0;
bool m_icase = false;
std::string m_value;
std::optional<row_handle> m_single_hit;
};
struct key_equals_or_empty_condition_impl : public condition_impl
{
key_equals_or_empty_condition_impl(key_equals_condition_impl *equals, key_is_empty_condition_impl *empty)
: m_item_tag(equals->m_item_tag)
, m_value(equals->m_value)
, m_icase(equals->m_icase)
, m_single_hit(equals->m_single_hit)
{
assert(empty->m_item_ix == equals->m_item_ix);
}
condition_impl *prepare(const category &c) override
{
m_item_ix = get_column_ix(c, m_item_tag);
m_icase = is_column_type_uchar(c, m_item_tag);
return this;
}
bool test(row_handle r) const override
{
bool result = false;
if (m_single_hit.has_value())
result = *m_single_hit == r;
else
result = r[m_item_ix].empty() or r[m_item_ix].compare(m_value, m_icase) == 0;
return result;
}
void str(std::ostream &os) const override
{
os << m_item_tag << (m_icase ? "^ " : " ") << " == " << m_value << " OR " << m_item_tag << " IS NULL";
}
virtual std::optional<row_handle> single() const override
{
return m_single_hit;
}
std::string m_item_tag;
size_t m_item_ix = 0;
bool m_icase = false;
std::string m_value;
std::optional<row_handle> m_single_hit;
};
struct key_compare_condition_impl : public condition_impl
{
template <typename COMP>
......@@ -185,10 +270,11 @@ namespace detail
{
}
void prepare(const category &c) override
condition_impl *prepare(const category &c) override
{
m_item_ix = get_column_ix(c, m_item_tag);
m_icase = is_column_type_uchar(c, m_item_tag);
return this;
}
bool test(row_handle r) const override
......@@ -217,9 +303,10 @@ namespace detail
{
}
void prepare(const category &c) override
condition_impl *prepare(const category &c) override
{
m_item_ix = get_column_ix(c, m_item_tag);
return this;
}
bool test(row_handle r) const override
......@@ -318,44 +405,84 @@ namespace detail
std::regex mRx;
};
// TODO: Optimize and_condition by having a list of sub items.
// That way you can also collapse multiple _is_ conditions in
// case they make up an indexed tuple.
struct and_condition_impl : public condition_impl
{
and_condition_impl(condition &&a, condition &&b)
: mA(nullptr)
, mB(nullptr)
{
std::swap(mA, a.m_impl);
std::swap(mB, b.m_impl);
mSub.emplace_back(std::exchange(a.m_impl, nullptr));
mSub.emplace_back(std::exchange(b.m_impl, nullptr));
}
~and_condition_impl()
{
delete mA;
delete mB;
for (auto sub : mSub)
delete sub;
}
void prepare(const category &c) override
{
mA->prepare(c);
mB->prepare(c);
}
condition_impl *prepare(const category &c) override;
bool test(row_handle r) const override
{
return mA->test(r) and mB->test(r);
bool result = true;
for (auto sub : mSub)
{
if (sub->test(r))
continue;
result = false;
break;
}
return result;
}
void str(std::ostream &os) const override
{
os << '(';
mA->str(os);
os << ") AND (";
mB->str(os);
bool first = true;
for (auto sub : mSub)
{
if (first)
first = false;
else
os << " AND ";
sub->str(os);
}
os << ')';
}
condition_impl *mA;
condition_impl *mB;
virtual std::optional<row_handle> single() const override
{
std::optional<row_handle> result;
for (auto sub : mSub)
{
auto s = sub->single();
if (not result.has_value())
{
result = s;
continue;
}
if (s == result)
continue;
result.reset();
break;
}
return result;
}
std::vector<condition_impl *> mSub;
};
struct or_condition_impl : public condition_impl
......@@ -374,11 +501,7 @@ namespace detail
delete mB;
}
void prepare(const category &c) override
{
mA->prepare(c);
mB->prepare(c);
}
condition_impl *prepare(const category &c) override;
bool test(row_handle r) const override
{
......@@ -394,6 +517,19 @@ namespace detail
os << ')';
}
virtual std::optional<row_handle> single() const override
{
auto sa = mA->single();
auto sb = mB->single();
if (sa.has_value() and sb.has_value() and sa != sb)
sa.reset();
else if (not sa.has_value())
sa = sb;
return sa;
}
condition_impl *mA;
condition_impl *mB;
};
......@@ -411,9 +547,10 @@ namespace detail
delete mA;
}
void prepare(const category &c) override
condition_impl *prepare(const category &c) override
{
mA->prepare(c);
mA = mA->prepare(c);
return this;
}
bool test(row_handle r) const override
......@@ -480,27 +617,13 @@ struct key
template <typename T>
condition operator==(const key &key, const T &v)
{
std::ostringstream s;
s << " == " << v;
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()));
return condition(new detail::key_equals_condition_impl({ key.m_item_tag, v }));
}
inline condition operator==(const key &key, const char *value)
{
if (value != nullptr and *value != 0)
{
std::ostringstream s;
s << " == " << value;
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()));
}
return condition(new detail::key_equals_condition_impl({ key.m_item_tag, value }));
else
return condition(new detail::key_is_empty_condition_impl(key.m_item_tag));
}
......
......@@ -66,7 +66,7 @@ class datablock : public std::list<category>
const validator *get_validator() const;
bool is_valid() const;
void validate_links() const;
bool validate_links() const;
// --------------------------------------------------------------------
......
......@@ -79,13 +79,25 @@ class file : public std::list<datablock>
bool is_valid() const;
bool is_valid();
void validate_links() const;
bool validate_links() const;
void load_dictionary();
void load_dictionary(std::string_view name);
bool contains(std::string_view name) const;
datablock &front()
{
assert(not empty());
return std::list<datablock>::front();
}
const datablock &front() const
{
assert(not empty());
return std::list<datablock>::front();
}
datablock &operator[](std::string_view name);
const datablock &operator[](std::string_view name) const;
......
......@@ -59,10 +59,8 @@ class item
/// content a single character string with content \a value
item(std::string_view name, char value)
: m_name(name)
, m_value(m_buffer, 1)
, m_value({ value })
{
m_buffer[0] = value;
m_buffer[1] = 0;
}
/// \brief constructor for an item with name \a name and as
......@@ -75,13 +73,15 @@ class item
using namespace std;
using namespace cif;
auto r = to_chars(m_buffer, m_buffer + sizeof(m_buffer) - 1, value, chars_format::fixed, precision);
char buffer[32];
auto r = to_chars(buffer, buffer + sizeof(buffer) - 1, value, chars_format::fixed, precision);
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));
assert(r.ptr >= buffer and r.ptr < buffer + sizeof(buffer));
*r.ptr = 0;
m_value = std::string_view(m_buffer, r.ptr - m_buffer);
m_value.assign(buffer, r.ptr - buffer);
}
/// \brief constructor for an item with name \a name and as
......@@ -94,13 +94,15 @@ class item
using namespace std;
using namespace cif;
auto r = to_chars(m_buffer, m_buffer + sizeof(m_buffer) - 1, value, chars_format::general);
char buffer[32];
auto r = to_chars(buffer, buffer + sizeof(buffer) - 1, value, 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));
assert(r.ptr >= buffer and r.ptr < buffer + sizeof(buffer));
*r.ptr = 0;
m_value = std::string_view(m_buffer, r.ptr - m_buffer);
m_value.assign(buffer, r.ptr - buffer);
}
/// \brief constructor for an item with name \a name and as
......@@ -109,13 +111,15 @@ class item
item(const std::string_view name, const T &value)
: m_name(name)
{
auto r = std::to_chars(m_buffer, m_buffer + sizeof(m_buffer) - 1, value);
char buffer[32];
auto r = std::to_chars(buffer, buffer + sizeof(buffer) - 1, value);
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));
assert(r.ptr >= buffer and r.ptr < buffer + sizeof(buffer));
*r.ptr = 0;
m_value = std::string_view(m_buffer, r.ptr - m_buffer);
m_value.assign(buffer, r.ptr - buffer);
}
/// \brief constructor for an item with name \a name and as
......@@ -152,10 +156,17 @@ class item
/// \brief the length of the value string
size_t length() const { return m_value.length(); }
/// \brief support for structured binding
template<size_t N>
decltype(auto) get() const
{
if constexpr (N == 0) return name();
else if constexpr (N == 1) return value();
}
private:
std::string_view m_name;
std::string_view m_value;
char m_buffer[64]; // TODO: optimize this magic number, might be too large
std::string m_value;
};
// --------------------------------------------------------------------
......@@ -193,7 +204,7 @@ struct item_value
// By using std::string_view instead of c_str we obain a
// nice performance gain since we avoid many calls to strlen.
std::string_view text() const
constexpr inline std::string_view text() const
{
return { m_length >= kBufferSize ? m_data : m_local_data, m_length };
}
......@@ -289,9 +300,6 @@ struct item_handle
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 &row)
: m_column(column)
, m_row_handle(row)
......@@ -491,3 +499,21 @@ struct item_handle::item_value_as<T, std::enable_if_t<std::is_same_v<T, std::str
};
} // namespace cif
namespace std
{
template<> struct tuple_size<::cif::item>
: public std::integral_constant<std::size_t, 2> {};
template<> struct tuple_element<0, ::cif::item>
{
using type = decltype(std::declval<::cif::item>().name());
};
template<> struct tuple_element<1, ::cif::item>
{
using type = decltype(std::declval<::cif::item>().value());
};
}
\ No newline at end of file
......@@ -34,19 +34,6 @@
#include <format>
#endif
/*
To modify a structure, you will have to use actions.
The currently supported actions are:
// - Move atom to new location
- Remove atom
// - Add new atom that was formerly missing
// - Add alternate residue
-
*/
namespace cif::mm
{
......@@ -63,16 +50,23 @@ class atom
private:
struct atom_impl : public std::enable_shared_from_this<atom_impl>
{
atom_impl(datablock &db, std::string_view id, row_handle row)
atom_impl(datablock &db, std::string_view id)
: m_db(db)
, m_cat(db["atom_site"])
, m_id(id)
, m_row(row)
{
prefetch();
auto r = row();
if (r)
tie(m_location.m_x, m_location.m_y, m_location.m_z) = r.get("Cartn_x", "Cartn_y", "Cartn_z");
}
// constructor for a symmetry copy of an atom
atom_impl(const atom_impl &impl, const point &loc, const std::string &sym_op);
atom_impl(const atom_impl &impl, const point &loc, const std::string &sym_op)
: atom_impl(impl)
{
m_location = loc;
m_symop = sym_op;
}
atom_impl(const atom_impl &i) = default;
......@@ -84,95 +78,41 @@ class atom
int get_charge() const;
void moveTo(const point &p)
{
if (m_symop != "1_555")
throw std::runtime_error("Moving symmetry copy");
#if __cpp_lib_format
m_row.assign("Cartn_x", std::format("{:.3f}", p.getX()), false, false);
m_row.assign("Cartn_y", std::format("{:.3f}", p.getY()), false, false);
m_row.assign("Cartn_z", std::format("{:.3f}", p.getZ()), false, false);
#else
m_row.assign("Cartn_x", format("%.3f", p.m_x).str(), false, false);
m_row.assign("Cartn_y", format("%.3f", p.m_y).str(), false, false);
m_row.assign("Cartn_z", format("%.3f", p.m_z).str(), false, false);
#endif
m_location = p;
}
void moveTo(const point &p);
// const compound *compound() const;
std::string get_property(std::string_view name) const
std::string get_property(std::string_view name) const;
int get_property_int(std::string_view name) const;
float get_property_float(std::string_view name) const;
void set_property(const std::string_view name, const std::string &value);
row_handle row()
{
return m_row[name].as<std::string>();
// for (auto &&[tag, ref] : mCachedRefs)
// {
// if (tag == name)
// return ref.as<std::string>();
// }
// mCachedRefs.emplace_back(name, const_cast<Row &>(mRow)[name]);
// return std::get<1>(mCachedRefs.back()).as<std::string>();
return m_cat[{{"id", m_id}}];
}
int get_property_int(std::string_view name) const
const row_handle row() const
{
int result = 0;
if (not m_row[name].empty())
{
auto s = get_property(name);
std::from_chars_result r = std::from_chars(s.data(), s.data() + s.length(), result);
if (r.ec != std::errc() and VERBOSE > 0)
std::cerr << "Error converting " << s << " to number for property " << name << std::endl;
}
return result;
return m_cat[{{"id", m_id}}];
}
float get_property_float(std::string_view name) const
row_handle row_aniso()
{
float result = 0;
if (not m_row[name].empty())
{
auto s = get_property(name);
std::from_chars_result r = cif::from_chars(s.data(), s.data() + s.length(), result);
if (r.ec != std::errc() and VERBOSE > 0)
std::cerr << "Error converting " << s << " to number for property " << name << std::endl;
}
return result;
auto cat = m_db.get("atom_site_anisotrop");
return cat ? cat->find1(key("id") == m_id) : row_handle{};
}
void set_property(const std::string_view name, const std::string &value)
const row_handle row_aniso() const
{
m_row.assign(name, value, true, true);
auto cat = m_db.get("atom_site_anisotrop");
return cat ? cat->find1(key("id") == m_id) : row_handle{};
}
// const datablock &m_db;
// std::string mID;
// atom_type mType;
// std::string mAtomID;
// std::string mCompID;
// std::string m_asym_id;
// int m_seq_id;
// std::string mAltID;
// std::string m_auth_seq_id;
// point mLocation;
// row_handle mRow;
// // mutable std::vector<std::tuple<std::string, detail::ItemReference>> mCachedRefs;
// mutable const compound *mcompound = nullptr;
// bool mSymmetryCopy = false;
// bool mClone = false;
const datablock &m_db;
category &m_cat;
std::string m_id;
row_handle m_row;
point m_location;
std::string m_symop = "1_555";
};
......@@ -191,7 +131,7 @@ class atom
}
atom(datablock &db, row_handle &row)
: atom(std::make_shared<atom_impl>(db, row["id"].as<std::string>(), row))
: atom(std::make_shared<atom_impl>(db, row["id"].as<std::string>()))
{
}
......@@ -295,20 +235,27 @@ class atom
set_location(loc);
}
// // for direct access to underlying data, be careful!
// const row_handle getRow() const { return impl().mRow; }
// const row_handle getRowAniso() const;
// for direct access to underlying data, be careful!
const row_handle get_row() const { return impl().row(); }
const row_handle get_row_aniso() const { return impl().row_aniso(); }
// bool isSymmetryCopy() const { return impl().mSymmetryCopy; }
// std::string symmetry() const { return impl().mSymmetryOperator; }
// const compound &compound() const;
// bool is_water() const { return impl().mCompID == "HOH" or impl().mCompID == "H2O" or impl().mCompID == "WAT"; }
bool is_water() const
{
auto comp_id = get_label_comp_id();
return comp_id == "HOH" or comp_id == "H2O" or comp_id == "WAT";
}
int get_charge() const { return impl().get_charge(); }
// float uIso() const;
// bool getAnisoU(float anisou[6]) const { return impl().getAnisoU(anisou); }
// float occupancy() const;
float get_occupancy() const { return get_property_float("occupancy"); }
// specifications
......@@ -681,7 +628,10 @@ class sugar : public residue
size_t get_link_nr() const
{
return m_link ? std::stoi(m_link.get_auth_seq_id()) : 0;
size_t result = 0;
if (m_link)
result = m_link.get_property_int("auth_seq_id");
return result;
}
private:
......@@ -778,6 +728,8 @@ class structure
~structure() = default;
size_t get_model_nr() const { return m_model_nr; }
const std::vector<atom> &atoms() const { return m_atoms; }
// std::vector<atom> &atoms() { return m_atoms; }
......@@ -897,10 +849,10 @@ class structure
/// \param entity_id The entity ID of the new nonpoly
/// \param atoms The array of sets of item data containing the data for the atoms.
/// \return The newly create asym ID
std::string create_non_poly(const std::string &entity_id, std::vector<std::vector<item>> &atom_info);
std::string create_non_poly(const std::string &entity_id, std::vector<row_initializer> atoms);
/// \brief Create a new (sugar) branch with one first NAG containing atoms constructed from \a nag_atom_info
branch &create_branch(std::vector<std::vector<item>> &nag_atom_info);
/// \brief Create a new (sugar) branch with one first NAG containing atoms constructed from \a atoms
branch &create_branch(std::vector<row_initializer> atoms);
/// \brief Extend an existing (sugar) branch identified by \a asymID with one sugar containing atoms constructed from \a atom_info
///
......@@ -908,7 +860,7 @@ class structure
/// \param atom_info Array containing the info for the atoms to construct for the new sugar
/// \param link_sugar The sugar to link to, note: this is the sugar number (1 based)
/// \param link_atom The atom id of the atom linked in the sugar
branch &extend_branch(const std::string &asym_id, std::vector<std::vector<item>> &atom_info,
branch &extend_branch(const std::string &asym_id, std::vector<row_initializer> atom_info,
int link_sugar, const std::string &link_atom);
/// \brief Remove \a branch
......
/*-
* 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.
*/
#pragma once
#include <vector>
#include <string>
#include <tuple>
#include <cif++.hpp>
namespace cif
{
extern const int
kResidueNrWildcard,
kNoSeqNum;
struct TLSSelection;
typedef std::unique_ptr<TLSSelection> TLSSelectionPtr;
struct TLSResidue;
struct TLSSelection
{
virtual ~TLSSelection() {}
virtual void CollectResidues(cif::datablock& db, std::vector<TLSResidue>& residues, std::size_t indentLevel = 0) const = 0;
std::vector<std::tuple<std::string,int,int>> GetRanges(cif::datablock& db, bool pdbNamespace) const;
};
// Low level: get the selections
TLSSelectionPtr ParseSelectionDetails(const std::string& program, const std::string& selection);
}
/*-
* 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.
*/
#pragma once
#include <cif++.hpp>
namespace cif::pdb
{
/// \brief Just the HEADER, COMPND, SOURCE and AUTHOR lines
void write_header_lines(std::ostream &os, const datablock &data);
std::string get_HEADER_line(const datablock &data, std::string::size_type truncate_at = 127);
std::string get_COMPND_line(const datablock &data, std::string::size_type truncate_at = 127);
std::string get_SOURCE_line(const datablock &data, std::string::size_type truncate_at = 127);
std::string get_AUTHOR_line(const datablock &data, std::string::size_type truncate_at = 127);
} // namespace pdbx
/*-
* 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.
*/
#pragma once
#include <cif++.hpp>
namespace cif::pdb
{
file read(std::istream &is);
void write(std::ostream &os, const datablock &db);
inline void write(std::ostream &os, const file &f)
{
write(os, f.front());
}
}
\ No newline at end of file
/*-
* 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.
*/
#pragma once
#include <cif++.hpp>
namespace cif::pdb
{
// --------------------------------------------------------------------
struct PDBRecord
{
PDBRecord *mNext;
uint32_t mLineNr;
char mName[11];
size_t mVlen;
char mValue[1];
PDBRecord(uint32_t lineNr, const std::string &name, const std::string &value);
~PDBRecord();
void *operator new(size_t);
void *operator new(size_t size, size_t vLen);
void operator delete(void *p);
void operator delete(void *p, size_t vLen);
bool is(const char *name) const;
char vC(size_t column);
std::string vS(size_t columnFirst, size_t columnLast = std::numeric_limits<size_t>::max());
int vI(int columnFirst, int columnLast);
std::string vF(size_t columnFirst, size_t columnLast);
};
// --------------------------------------------------------------------
void ReadPDBFile(std::istream &pdbFile, file &cifFile);
} // namespace pdbx
\ No newline at end of file
/*-
* 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.
*/
#pragma once
#include <cif++/pdb/pdb2cif.hpp>
// --------------------------------------------------------------------
namespace cif::pdb
{
struct TemplateLine;
class Remark3Parser
{
public:
virtual ~Remark3Parser() {}
static bool parse(const std::string &expMethod, PDBRecord *r, cif::datablock &db);
virtual std::string program();
virtual std::string version();
protected:
Remark3Parser(const std::string &name, const std::string &expMethod, PDBRecord *r, cif::datablock &db,
const TemplateLine templatelines[], uint32_t templateLineCount, std::regex programVersion);
virtual float parse();
std::string nextLine();
bool match(const char *expr, int nextState);
void storeCapture(const char *category, std::initializer_list<const char *> items, bool createNew = false);
void storeRefineLsRestr(const char *type, std::initializer_list<const char *> values);
void updateRefineLsRestr(const char *type, std::initializer_list<const char *> values);
virtual void fixup() {}
std::string mName;
std::string mExpMethod;
PDBRecord *mRec;
cif::datablock mDb;
std::string mLine;
std::smatch mM;
uint32_t mState;
const TemplateLine *mTemplate;
uint32_t mTemplateCount;
std::regex mProgramVersion;
};
} // namespace pdbx
......@@ -484,7 +484,7 @@ struct point_type
}
#if HAVE_LIBCLIPPER
constexpr operator clipper::Coord_orth() const
operator clipper::Coord_orth() const
{
return clipper::Coord_orth(m_x, m_y, m_z);
}
......
......@@ -196,7 +196,7 @@ class row_handle
explicit operator bool() const
{
return m_category != nullptr and m_row != nullptr;
return not empty();
}
item_handle operator[](uint32_t column_ix)
......@@ -259,7 +259,12 @@ class row_handle
uint16_t add_column(std::string_view name);
operator row *()
row *get_row()
{
return m_row;
}
const row *get_row() const
{
return m_row;
}
......@@ -277,7 +282,7 @@ class row_handle
// --------------------------------------------------------------------
class row_initializer
class row_initializer : public std::vector<item>
{
public:
friend class category;
......@@ -289,20 +294,29 @@ class row_initializer
row_initializer &operator=(row_initializer &&) = default;
row_initializer(std::initializer_list<item> items)
: m_items(items)
: std::vector<item>(items)
{
}
template <typename ItemIter, std::enable_if_t<std::is_same_v<typename ItemIter::value_type, item>, int> = 0>
row_initializer(ItemIter b, ItemIter e)
: m_items(b, e)
: std::vector<item>(b, e)
{
}
row_initializer(row_handle rh);
private:
std::vector<item> m_items;
void set_value(std::string_view name, std::string_view value);
void set_value(const item &i)
{
set_value(i.name(), i.value());
}
void set_value_if_empty(std::string_view name, std::string_view value);
void set_value_if_empty(const item &i)
{
set_value_if_empty(i.name(), i.value());
}
};
} // namespace cif
\ No newline at end of file
......@@ -52,7 +52,7 @@ class row_comparator
for (auto k : cv->m_keys)
{
size_t ix = cat.get_column_ix(k);
size_t ix = cat.add_column(k);
auto iv = cv->get_validator_for_item(k);
if (iv == nullptr)
......@@ -96,6 +96,32 @@ class row_comparator
return d;
}
int operator()(const row_initializer &a, const row *b) const
{
assert(b);
row_handle rhb(m_category, *b);
int d = 0, i = 0;
for (auto &c : m_comparator)
{
size_t k;
compareFunc f;
std::tie(k, f) = c;
std::string_view ka = a[i++].value();
std::string_view kb = rhb[k].text();
d = f(ka, kb);
if (d != 0)
break;
}
return d;
}
private:
typedef std::function<int(std::string_view, std::string_view)> compareFunc;
typedef std::tuple<size_t, compareFunc> key_comparator;
......@@ -126,6 +152,7 @@ class category_index
}
row *find(row *k) const;
row *find_by_value(row_initializer k) const;
void insert(row *r);
void erase(row *r);
......@@ -331,6 +358,37 @@ row *category_index::find(row *k) const
return r ? r->m_row : nullptr;
}
row *category_index::find_by_value(row_initializer k) const
{
// sort the values in k first
row_initializer k2;
for (auto &f : m_category.key_field_indices())
{
auto fld = m_category.get_column_name(f);
auto ki = find_if(k.begin(), k.end(), [&fld](auto &i) { return i.name() == fld; });
if (ki == k.end())
k2.emplace_back(fld, "");
else
k2.emplace_back(*ki);
}
const entry *r = m_root;
while (r != nullptr)
{
int d = m_row_comparator(k2, r->m_row);
if (d < 0)
r = r->m_left;
else if (d > 0)
r = r->m_right;
else
break;
}
return r ? r->m_row : nullptr;
}
void category_index::insert(row *k)
{
m_root = insert(m_root, k);
......@@ -353,7 +411,10 @@ category_index::entry *category_index::insert(entry *h, row *v)
std::ostringstream os;
for (auto col : m_category.fields())
os << col << ": " << std::quoted(rh[col].text()) << "; ";
{
if (rh[col])
os << col << ": " << std::quoted(rh[col].text()) << "; ";
}
throw std::runtime_error("Duplicate Key violation, cat: " + m_category.name() + " values: " + os.str());
}
......@@ -426,7 +487,7 @@ void category_index::reconstruct()
m_root = nullptr;
for (auto r : m_category)
insert(r);
insert(r.get_row());
// maybe reconstruction can be done quicker by using the following commented code.
// however, I've not had the time to think of a way to set the red/black flag correctly in that case.
......@@ -756,10 +817,14 @@ bool category::is_valid() const
// check index?
if (m_index)
{
if (m_index->size() != size())
m_validator->report_error("size of index is not equal to size of category " + m_name, true);
// m_index->validate();
for (auto r : *this)
{
if (m_index->find(r) != r)
auto p = r.get_row();
if (m_index->find(p) != p)
m_validator->report_error("Key not found in index for category " + m_name, true);
}
}
......@@ -813,10 +878,12 @@ bool category::is_valid() const
return result;
}
void category::validate_links() const
bool category::validate_links() const
{
if (not m_validator)
return;
return false;
bool result = true;
for (auto &link : m_parent_links)
{
......@@ -825,6 +892,12 @@ void category::validate_links() const
if (parent == nullptr)
continue;
// this particular case should be skipped, that's because it is wrong:
// there are atoms that are not part of a polymer, and thus will have no
// parent in that category.
if (name() == "atom_site" and (parent->name() == "pdbx_poly_seq_scheme" or parent->name() == "entity_poly_seq"))
continue;
size_t missing = 0;
category first_missing_rows(name());
......@@ -843,13 +916,15 @@ void category::validate_links() const
if (missing)
{
result = false;
std::cerr << "Links for " << link.v->m_link_group_label << " are incomplete" << std::endl
<< " There are " << missing << " items in " << m_name << " that don't have matching parent items in " << parent->m_name << std::endl;
<< " There are " << missing << " items in " << m_name << " that don't have matching parent items in " << parent->m_name << std::endl;
if (VERBOSE)
{
std::cerr << "showing first " << first_missing_rows.size() << " rows" << std::endl
<< std::endl;
<< std::endl;
first_missing_rows.write(std::cerr, link.v->m_child_keys, false);
......@@ -857,6 +932,19 @@ void category::validate_links() const
}
}
}
return result;
}
// --------------------------------------------------------------------
row_handle category::operator[](const key_type &key)
{
if (m_index == nullptr)
throw std::logic_error("Category " + m_name + " does not have an index");
auto row = m_index->find_by_value(key);
return row != nullptr ? row_handle{ *this, *row } : row_handle{};
}
// --------------------------------------------------------------------
......@@ -898,6 +986,11 @@ condition category::get_children_condition(row_handle rh, const category &childC
condition result;
iset mandatoryChildFields;
auto childCatValidator = m_validator->get_validator_for_category(childCat.name());
if (childCatValidator != nullptr)
mandatoryChildFields = childCatValidator->m_mandatory_fields;
for (auto &link : m_validator->get_links_for_parent(m_name))
{
if (link->m_child_category != childCat.m_name)
......@@ -914,14 +1007,13 @@ condition category::get_children_condition(row_handle rh, const category &childC
if (parentValue.empty())
cond = std::move(cond) and key(childKey) == null;
else if (link->m_parent_keys.size() > 1 and not mandatoryChildFields.contains(childKey))
cond = std::move(cond) and (key(childKey) == parentValue.text() or key(childKey) == null);
else
cond = std::move(cond) and key(childKey) == parentValue.text();
}
if (result)
result = std::move(result) or std::move(cond);
else
result = std::move(cond);
result = std::move(result) or std::move(cond);
}
return result;
......@@ -1004,7 +1096,7 @@ std::vector<row_handle> category::get_linked(row_handle r, const category &cat)
category::iterator category::erase(iterator pos)
{
row_handle rh = *pos;
row *r = rh;
row *r = rh.get_row();
iterator result = ++pos;
iset keys;
......@@ -1137,9 +1229,14 @@ void category::erase_orphans(condition &&cond, category &parent)
continue;
if (VERBOSE > 1)
{
category c(m_name);
c.emplace(r);
std::cerr << "Removing orphaned record: " << std::endl
<< r << std::endl
<< c << std::endl
<< std::endl;
}
remove.emplace_back(r.m_row);
}
......@@ -1526,6 +1623,11 @@ category::iterator category::insert_impl(const_iterator pos, row *n)
if (n == nullptr)
throw std::runtime_error("Invalid pointer passed to insert");
// #ifndef NDEBUG
// if (m_validator)
// is_valid();
// #endif
try
{
// First, make sure all mandatory fields are supplied
......@@ -1606,57 +1708,62 @@ category::iterator category::insert_impl(const_iterator pos, row *n)
delete_row(n);
throw;
}
}
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);
// #ifndef NDEBUG
// if (m_validator)
// is_valid();
// #endif
}
// 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);
// }
void category::swap_item(size_t column_ix, row_handle &a, row_handle &b)
{
assert(this == a.m_category);
......@@ -1714,7 +1821,7 @@ void category::swap_item(size_t column_ix, row_handle &a, row_handle &b)
v->m_next = vb->m_next;
vb->m_next = nullptr;
if (rb->m_tail = vb)
if (rb->m_tail == vb)
rb->m_tail = v;
break;
......
......@@ -58,4 +58,81 @@ bool is_column_type_uchar(const category &cat, std::string_view col)
return result;
}
namespace detail
{
condition_impl *key_equals_condition_impl::prepare(const category &c)
{
m_item_ix = get_column_ix(c, m_item_tag);
m_icase = is_column_type_uchar(c, m_item_tag);
if (c.get_cat_validator() != nullptr and
c.key_field_indices().contains(m_item_ix) and
c.key_field_indices().size() == 1)
{
m_single_hit = c[{ { m_item_tag, m_value } }];
}
return this;
}
condition_impl *and_condition_impl::prepare(const category &c)
{
for (auto &sub : mSub)
sub = sub->prepare(c);
for (;;)
{
auto si = find_if(mSub.begin(), mSub.end(), [](condition_impl *sub) { return dynamic_cast<and_condition_impl *>(sub) != nullptr; });
if (si == mSub.end())
break;
and_condition_impl *sub_and = static_cast<and_condition_impl *>(*si);
mSub.erase(si);
mSub.insert(mSub.end(), sub_and->mSub.begin(), sub_and->mSub.end());
sub_and->mSub.clear();
delete sub_and;
}
return this;
}
condition_impl *or_condition_impl::prepare(const category &c)
{
condition_impl *result = this;
mA = mA->prepare(c);
mB = mB->prepare(c);
key_equals_condition_impl *equals = dynamic_cast<key_equals_condition_impl*>(mA);
key_is_empty_condition_impl *empty = dynamic_cast<key_is_empty_condition_impl*>(mB);
if (equals == nullptr and empty == nullptr)
{
equals = dynamic_cast<key_equals_condition_impl*>(mB);
empty = dynamic_cast<key_is_empty_condition_impl*>(mA);
}
if (equals != nullptr and empty != nullptr)
{
result = new detail::key_equals_or_empty_condition_impl(equals, empty);
result = result->prepare(c);
delete this;
}
return result;
}
} // namespace detail
void condition::prepare(const category &c)
{
if (m_impl)
m_impl = m_impl->prepare(c);
m_prepared = true;
}
} // namespace cif
......@@ -54,10 +54,14 @@ bool datablock::is_valid() const
return result;
}
void datablock::validate_links() const
bool datablock::validate_links() const
{
bool result = true;
for (auto &cat : *this)
cat.validate_links();
result = cat.validate_links() and result;
return result;
}
// --------------------------------------------------------------------
......@@ -70,7 +74,11 @@ category &datablock::operator[](std::string_view name)
if (i != end())
return *i;
emplace_back(name);
auto &cat = emplace_back(name);
if (m_validator)
cat.set_validator(m_validator, *this);
return back();
}
......
......@@ -48,6 +48,9 @@ bool file::is_valid() const
for (auto &d : *this)
result = d.is_valid() and result;
if (result)
result = validate_links();
return result;
}
......@@ -66,16 +69,23 @@ bool file::is_valid()
for (auto &d : *this)
result = d.is_valid() and result;
if (result)
result = validate_links();
return result;
}
void file::validate_links() const
bool file::validate_links() const
{
if (m_validator == nullptr)
std::runtime_error("No validator loaded explicitly, cannot continue");
bool result = true;
for (auto &db : *this)
db.validate_links();
result = db.validate_links() and result;
return result;
}
void file::load_dictionary()
......@@ -196,6 +206,9 @@ void file::save(const std::filesystem::path &p) const
void file::save(std::ostream &os) const
{
// if (not is_valid())
// std::cout << "File is not valid!" << std::endl;
for (auto &db : *this)
db.write(os);
}
......
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -327,7 +327,7 @@ std::tuple<double, point> quaternion_to_angle_axis(quaternion q)
point axis(q.get_b() / s, q.get_c() / s, q.get_d() / s);
return std::make_tuple(angle, axis);
return { angle, axis };
}
point center_points(std::vector<point> &Points)
......
......@@ -65,11 +65,31 @@ row_initializer::row_initializer(row_handle rh)
assert(rh.m_category);
assert(rh.m_row);
row *r = rh;
row *r = rh.get_row();
auto &cat = *rh.m_category;
for (auto i = r->m_head; i != nullptr; i = i->m_next)
m_items.emplace_back(cat.get_column_name(i->m_column_ix), i->text());
emplace_back(cat.get_column_name(i->m_column_ix), i->text());
}
void row_initializer::set_value(std::string_view name, std::string_view value)
{
for (auto &i : *this)
{
if (i.name() == name)
{
i.value(value);
return;
}
}
emplace_back(name, value);
}
void row_initializer::set_value_if_empty(std::string_view name, std::string_view value)
{
if (find_if(begin(), end(), [name](auto &i) { return i.name() == name; }) == end())
emplace_back(name, value);
}
} // namespace cif
\ No newline at end of file
data_REA
#
_chem_comp.id REA
_chem_comp.name "RETINOIC ACID"
_chem_comp.type NON-POLYMER
_chem_comp.pdbx_type HETAIN
_chem_comp.formula "C20 H28 O2"
_chem_comp.mon_nstd_parent_comp_id ?
_chem_comp.pdbx_synonyms ?
_chem_comp.pdbx_formal_charge 0
_chem_comp.pdbx_initial_date 1999-07-08
_chem_comp.pdbx_modified_date 2016-10-18
_chem_comp.pdbx_ambiguous_flag N
_chem_comp.pdbx_release_status REL
_chem_comp.pdbx_replaced_by ?
_chem_comp.pdbx_replaces 3KV
_chem_comp.formula_weight 300.435
_chem_comp.one_letter_code ?
_chem_comp.three_letter_code REA
_chem_comp.pdbx_model_coordinates_details ?
_chem_comp.pdbx_model_coordinates_missing_flag N
_chem_comp.pdbx_ideal_coordinates_details Corina
_chem_comp.pdbx_ideal_coordinates_missing_flag N
_chem_comp.pdbx_model_coordinates_db_code 1CBS
_chem_comp.pdbx_subcomponent_list ?
_chem_comp.pdbx_processing_site RCSB
#
loop_
_chem_comp_atom.comp_id
_chem_comp_atom.atom_id
_chem_comp_atom.alt_atom_id
_chem_comp_atom.type_symbol
_chem_comp_atom.charge
_chem_comp_atom.pdbx_align
_chem_comp_atom.pdbx_aromatic_flag
_chem_comp_atom.pdbx_leaving_atom_flag
_chem_comp_atom.pdbx_stereo_config
_chem_comp_atom.model_Cartn_x
_chem_comp_atom.model_Cartn_y
_chem_comp_atom.model_Cartn_z
_chem_comp_atom.pdbx_model_Cartn_x_ideal
_chem_comp_atom.pdbx_model_Cartn_y_ideal
_chem_comp_atom.pdbx_model_Cartn_z_ideal
_chem_comp_atom.pdbx_component_atom_id
_chem_comp_atom.pdbx_component_comp_id
_chem_comp_atom.pdbx_ordinal
REA C1 C1 C 0 1 N N N 21.972 29.831 16.739 -4.684 0.932 -0.497 C1 REA 1
REA C2 C2 C 0 1 N N N 20.921 30.524 15.841 -5.837 0.190 -1.176 C2 REA 2
REA C3 C3 C 0 1 N N N 20.245 29.635 14.848 -6.441 -0.798 -0.171 C3 REA 3
REA C4 C4 C 0 1 N N N 19.555 28.479 15.488 -5.418 -1.903 0.100 C4 REA 4
REA C5 C5 C 0 1 N N N 20.389 27.812 16.587 -4.082 -1.301 0.429 C5 REA 5
REA C6 C6 C 0 1 N N N 21.425 28.446 17.218 -3.756 -0.048 0.161 C6 REA 6
REA C7 C7 C 0 1 N N N 22.242 27.851 18.297 -2.457 0.396 0.516 C7 REA 7
REA C8 C8 C 0 1 N N N 21.868 26.977 19.240 -1.363 -0.229 0.007 C8 REA 8
REA C9 C9 C 0 1 N N N 22.705 26.434 20.286 -0.076 0.257 0.298 C9 REA 9
REA C10 C10 C 0 1 N N N 22.159 25.536 21.131 1.022 -0.370 -0.213 C10 REA 10
REA C11 C11 C 0 1 N N N 22.875 24.924 22.234 2.306 0.115 0.077 C11 REA 11
REA C12 C12 C 0 1 N N N 22.237 24.026 22.990 3.405 -0.513 -0.435 C12 REA 12
REA C13 C13 C 0 1 N N N 22.856 23.377 24.125 4.689 -0.028 -0.144 C13 REA 13
REA C14 C14 C 0 1 N N N 22.135 22.473 24.834 5.787 -0.655 -0.656 C14 REA 14
REA C15 C15 C 0 1 N N N 22.563 21.710 26.016 7.077 -0.265 -0.244 C15 REA 15
REA C16 C16 C 0 1 N N N 22.238 30.737 17.948 -5.246 1.886 0.559 C16 REA 16
REA C17 C17 C 0 1 N N N 23.292 29.620 15.948 -3.911 1.737 -1.544 C17 REA 17
REA C18 C18 C 0 1 N N N 19.791 26.449 16.947 -3.056 -2.175 1.103 C18 REA 18
REA C19 C19 C 0 1 N N N 24.181 26.841 20.385 0.090 1.471 1.175 C19 REA 19
REA C20 C20 C 0 1 N N N 24.303 23.747 24.489 4.855 1.186 0.733 C20 REA 20
REA O1 O1 O 0 1 N N N 23.640 21.075 25.978 7.210 0.553 0.648 O1 REA 21
REA O2 O2 O 0 1 N N N 21.840 21.712 27.037 8.166 -0.798 -0.840 O2 REA 22
REA H21 H21 H 0 1 N N N 20.147 30.955 16.494 -6.598 0.905 -1.490 H21 REA 23
REA H22 H22 H 0 1 N N N 21.425 31.330 15.288 -5.462 -0.353 -2.044 H22 REA 24
REA H31 H31 H 0 1 N N N 19.501 30.227 14.295 -6.673 -0.278 0.759 H31 REA 25
REA H32 H32 H 0 1 N N N 21.001 29.250 14.148 -7.349 -1.234 -0.586 H32 REA 26
REA H41 H41 H 0 1 N N N 18.613 28.835 15.931 -5.756 -2.511 0.938 H41 REA 27
REA H42 H42 H 0 1 N N N 19.335 27.730 14.713 -5.322 -2.531 -0.786 H42 REA 28
REA H7 H7 H 0 1 N N N 23.276 28.162 18.329 -2.337 1.230 1.191 H7 REA 29
REA H8 H8 H 0 1 N N N 20.840 26.645 19.217 -1.482 -1.100 -0.622 H8 REA 30
REA H10 H10 H 0 1 N N N 21.127 25.256 20.977 0.903 -1.241 -0.842 H10 REA 31
REA H11 H11 H 0 1 N N N 23.902 25.189 22.440 2.425 0.985 0.706 H11 REA 32
REA H12 H12 H 0 1 N N N 21.216 23.774 22.743 3.286 -1.383 -1.063 H12 REA 33
REA H14 H14 H 0 1 N N N 21.127 22.292 24.490 5.667 -1.451 -1.376 H14 REA 34
REA H161 H161 H 0 0 N N N 22.984 30.265 18.604 -5.802 1.316 1.303 H161 REA 35
REA H162 H162 H 0 0 N N N 22.618 31.709 17.601 -4.426 2.415 1.044 H162 REA 36
REA H163 H163 H 0 0 N N N 21.302 30.887 18.506 -5.911 2.605 0.081 H163 REA 37
REA H171 H171 H 0 0 N N N 24.033 29.127 16.595 -4.598 2.394 -2.077 H171 REA 38
REA H172 H172 H 0 0 N N N 23.095 28.989 15.069 -3.146 2.335 -1.050 H172 REA 39
REA H173 H173 H 0 0 N N N 23.683 30.595 15.620 -3.439 1.054 -2.251 H173 REA 40
REA H181 H181 H 0 0 N N N 20.397 25.979 17.736 -3.448 -3.187 1.201 H181 REA 41
REA H182 H182 H 0 0 N N N 18.761 26.584 17.308 -2.145 -2.194 0.503 H182 REA 42
REA H183 H183 H 0 0 N N N 19.786 25.804 16.056 -2.831 -1.775 2.092 H183 REA 43
REA H191 H191 H 0 0 N N N 24.647 26.327 21.238 0.171 1.159 2.216 H191 REA 44
REA H192 H192 H 0 0 N N N 24.702 26.559 19.458 0.993 2.008 0.885 H192 REA 45
REA H193 H193 H 0 0 N N N 24.252 27.929 20.529 -0.774 2.125 1.058 H193 REA 46
REA H201 H201 H 0 0 N N N 24.620 23.168 25.369 5.026 0.871 1.762 H201 REA 47
REA H202 H202 H 0 0 N N N 24.965 23.516 23.641 5.707 1.771 0.386 H202 REA 48
REA H203 H203 H 0 0 N N N 24.360 24.822 24.717 3.952 1.795 0.685 H203 REA 49
REA HO2 HO2 H 0 1 N N N 22.244 21.180 27.713 9.006 -0.469 -0.490 HO2 REA 50
#
loop_
_chem_comp_bond.comp_id
_chem_comp_bond.atom_id_1
_chem_comp_bond.atom_id_2
_chem_comp_bond.value_order
_chem_comp_bond.pdbx_aromatic_flag
_chem_comp_bond.pdbx_stereo_config
_chem_comp_bond.pdbx_ordinal
REA C1 C2 SING N N 1
REA C1 C6 SING N N 2
REA C1 C16 SING N N 3
REA C1 C17 SING N N 4
REA C2 C3 SING N N 5
REA C2 H21 SING N N 6
REA C2 H22 SING N N 7
REA C3 C4 SING N N 8
REA C3 H31 SING N N 9
REA C3 H32 SING N N 10
REA C4 C5 SING N N 11
REA C4 H41 SING N N 12
REA C4 H42 SING N N 13
REA C5 C6 DOUB N N 14
REA C5 C18 SING N N 15
REA C6 C7 SING N N 16
REA C7 C8 DOUB N E 17
REA C7 H7 SING N N 18
REA C8 C9 SING N N 19
REA C8 H8 SING N N 20
REA C9 C10 DOUB N E 21
REA C9 C19 SING N N 22
REA C10 C11 SING N N 23
REA C10 H10 SING N N 24
REA C11 C12 DOUB N E 25
REA C11 H11 SING N N 26
REA C12 C13 SING N N 27
REA C12 H12 SING N N 28
REA C13 C14 DOUB N E 29
REA C13 C20 SING N N 30
REA C14 C15 SING N N 31
REA C14 H14 SING N N 32
REA C15 O1 DOUB N N 33
REA C15 O2 SING N N 34
REA C16 H161 SING N N 35
REA C16 H162 SING N N 36
REA C16 H163 SING N N 37
REA C17 H171 SING N N 38
REA C17 H172 SING N N 39
REA C17 H173 SING N N 40
REA C18 H181 SING N N 41
REA C18 H182 SING N N 42
REA C18 H183 SING N N 43
REA C19 H191 SING N N 44
REA C19 H192 SING N N 45
REA C19 H193 SING N N 46
REA C20 H201 SING N N 47
REA C20 H202 SING N N 48
REA C20 H203 SING N N 49
REA O2 HO2 SING N N 50
#
loop_
_pdbx_chem_comp_descriptor.comp_id
_pdbx_chem_comp_descriptor.type
_pdbx_chem_comp_descriptor.program
_pdbx_chem_comp_descriptor.program_version
_pdbx_chem_comp_descriptor.descriptor
REA SMILES ACDLabs 12.01 "C1(CCCC(=C1\C=C\C(=C\C=C\C(=C\C(=O)O)C)C)C)(C)C"
REA InChI InChI 1.03 "InChI=1S/C20H28O2/c1-15(8-6-9-16(2)14-19(21)22)11-12-18-17(3)10-7-13-20(18,4)5/h6,8-9,11-12,14H,7,10,13H2,1-5H3,(H,21,22)/b9-6+,12-11+,15-8+,16-14+"
REA InChIKey InChI 1.03 SHGAZHPCJJPHSC-YCNIQYBTSA-N
REA SMILES_CANONICAL CACTVS 3.385 "CC1=C(\C=C\C(C)=C\C=C\C(C)=C\C(O)=O)C(C)(C)CCC1"
REA SMILES CACTVS 3.385 "CC1=C(C=CC(C)=CC=CC(C)=CC(O)=O)C(C)(C)CCC1"
REA SMILES_CANONICAL "OpenEye OEToolkits" 1.7.6 "CC1=C(C(CCC1)(C)C)/C=C/C(=C/C=C/C(=C/C(=O)O)/C)/C"
REA SMILES "OpenEye OEToolkits" 1.7.6 "CC1=C(C(CCC1)(C)C)C=CC(=CC=CC(=CC(=O)O)C)C"
#
loop_
_pdbx_chem_comp_identifier.comp_id
_pdbx_chem_comp_identifier.type
_pdbx_chem_comp_identifier.program
_pdbx_chem_comp_identifier.program_version
_pdbx_chem_comp_identifier.identifier
REA "SYSTEMATIC NAME" ACDLabs 12.01 "retinoic acid"
REA "SYSTEMATIC NAME" "OpenEye OEToolkits" 1.7.6 "(2E,4E,6E,8E)-3,7-dimethyl-9-(2,6,6-trimethylcyclohexen-1-yl)nona-2,4,6,8-tetraenoic acid"
#
loop_
_pdbx_chem_comp_audit.comp_id
_pdbx_chem_comp_audit.action_type
_pdbx_chem_comp_audit.date
_pdbx_chem_comp_audit.processing_site
REA "Create component" 1999-07-08 RCSB
REA "Modify descriptor" 2011-06-04 RCSB
REA "Other modification" 2016-10-18 RCSB
#
data_RXA
#
_chem_comp.id RXA
_chem_comp.name "RENAMED RETINOIC ACID"
_chem_comp.type NON-POLYMER
_chem_comp.pdbx_type HETAIN
_chem_comp.formula "C20 H28 O2"
_chem_comp.mon_nstd_parent_comp_id ?
_chem_comp.pdbx_synonyms ?
_chem_comp.pdbx_formal_charge 0
_chem_comp.pdbx_initial_date 1999-07-08
_chem_comp.pdbx_modified_date 2016-10-18
_chem_comp.pdbx_ambiguous_flag N
_chem_comp.pdbx_release_status REL
_chem_comp.pdbx_replaced_by ?
_chem_comp.pdbx_replaces 3KV
_chem_comp.formula_weight 300.435
_chem_comp.one_letter_code ?
_chem_comp.three_letter_code RXA
_chem_comp.pdbx_model_coordinates_details ?
_chem_comp.pdbx_model_coordinates_missing_flag N
_chem_comp.pdbx_ideal_coordinates_details Corina
_chem_comp.pdbx_ideal_coordinates_missing_flag N
_chem_comp.pdbx_model_coordinates_db_code 1CBS
_chem_comp.pdbx_subcomponent_list ?
_chem_comp.pdbx_processing_site RCSB
#
loop_
_chem_comp_atom.comp_id
_chem_comp_atom.atom_id
_chem_comp_atom.alt_atom_id
_chem_comp_atom.type_symbol
_chem_comp_atom.charge
_chem_comp_atom.pdbx_align
_chem_comp_atom.pdbx_aromatic_flag
_chem_comp_atom.pdbx_leaving_atom_flag
_chem_comp_atom.pdbx_stereo_config
_chem_comp_atom.model_Cartn_x
_chem_comp_atom.model_Cartn_y
_chem_comp_atom.model_Cartn_z
_chem_comp_atom.pdbx_model_Cartn_x_ideal
_chem_comp_atom.pdbx_model_Cartn_y_ideal
_chem_comp_atom.pdbx_model_Cartn_z_ideal
_chem_comp_atom.pdbx_component_atom_id
_chem_comp_atom.pdbx_component_comp_id
_chem_comp_atom.pdbx_ordinal
RXA C1 C1 C 0 1 N N N 21.972 29.831 16.739 -4.684 0.932 -0.497 C1 RXA 1
RXA C2 C2 C 0 1 N N N 20.921 30.524 15.841 -5.837 0.190 -1.176 C2 RXA 2
RXA C3 C3 C 0 1 N N N 20.245 29.635 14.848 -6.441 -0.798 -0.171 C3 RXA 3
RXA C4 C4 C 0 1 N N N 19.555 28.479 15.488 -5.418 -1.903 0.100 C4 RXA 4
RXA C5 C5 C 0 1 N N N 20.389 27.812 16.587 -4.082 -1.301 0.429 C5 RXA 5
RXA C6 C6 C 0 1 N N N 21.425 28.446 17.218 -3.756 -0.048 0.161 C6 RXA 6
RXA C7 C7 C 0 1 N N N 22.242 27.851 18.297 -2.457 0.396 0.516 C7 RXA 7
RXA C8 C8 C 0 1 N N N 21.868 26.977 19.240 -1.363 -0.229 0.007 C8 RXA 8
RXA C9 C9 C 0 1 N N N 22.705 26.434 20.286 -0.076 0.257 0.298 C9 RXA 9
RXA C10 C10 C 0 1 N N N 22.159 25.536 21.131 1.022 -0.370 -0.213 C10 RXA 10
RXA C11 C11 C 0 1 N N N 22.875 24.924 22.234 2.306 0.115 0.077 C11 RXA 11
RXA C12 C12 C 0 1 N N N 22.237 24.026 22.990 3.405 -0.513 -0.435 C12 RXA 12
RXA C13 C13 C 0 1 N N N 22.856 23.377 24.125 4.689 -0.028 -0.144 C13 RXA 13
RXA C14 C14 C 0 1 N N N 22.135 22.473 24.834 5.787 -0.655 -0.656 C14 RXA 14
RXA C15 C15 C 0 1 N N N 22.563 21.710 26.016 7.077 -0.265 -0.244 C15 RXA 15
RXA C16 C16 C 0 1 N N N 22.238 30.737 17.948 -5.246 1.886 0.559 C16 RXA 16
RXA C17 C17 C 0 1 N N N 23.292 29.620 15.948 -3.911 1.737 -1.544 C17 RXA 17
RXA C18 C18 C 0 1 N N N 19.791 26.449 16.947 -3.056 -2.175 1.103 C18 RXA 18
RXA C19 C19 C 0 1 N N N 24.181 26.841 20.385 0.090 1.471 1.175 C19 RXA 19
RXA C20 C20 C 0 1 N N N 24.303 23.747 24.489 4.855 1.186 0.733 C20 RXA 20
RXA O1 O1 O 0 1 N N N 23.640 21.075 25.978 7.210 0.553 0.648 O1 RXA 21
RXA O2 O2 O 0 1 N N N 21.840 21.712 27.037 8.166 -0.798 -0.840 O2 RXA 22
RXA H21 H21 H 0 1 N N N 20.147 30.955 16.494 -6.598 0.905 -1.490 H21 RXA 23
RXA H22 H22 H 0 1 N N N 21.425 31.330 15.288 -5.462 -0.353 -2.044 H22 RXA 24
RXA H31 H31 H 0 1 N N N 19.501 30.227 14.295 -6.673 -0.278 0.759 H31 RXA 25
RXA H32 H32 H 0 1 N N N 21.001 29.250 14.148 -7.349 -1.234 -0.586 H32 RXA 26
RXA H41 H41 H 0 1 N N N 18.613 28.835 15.931 -5.756 -2.511 0.938 H41 RXA 27
RXA H42 H42 H 0 1 N N N 19.335 27.730 14.713 -5.322 -2.531 -0.786 H42 RXA 28
RXA H7 H7 H 0 1 N N N 23.276 28.162 18.329 -2.337 1.230 1.191 H7 RXA 29
RXA H8 H8 H 0 1 N N N 20.840 26.645 19.217 -1.482 -1.100 -0.622 H8 RXA 30
RXA H10 H10 H 0 1 N N N 21.127 25.256 20.977 0.903 -1.241 -0.842 H10 RXA 31
RXA H11 H11 H 0 1 N N N 23.902 25.189 22.440 2.425 0.985 0.706 H11 RXA 32
RXA H12 H12 H 0 1 N N N 21.216 23.774 22.743 3.286 -1.383 -1.063 H12 RXA 33
RXA H14 H14 H 0 1 N N N 21.127 22.292 24.490 5.667 -1.451 -1.376 H14 RXA 34
RXA H161 H161 H 0 0 N N N 22.984 30.265 18.604 -5.802 1.316 1.303 H161 RXA 35
RXA H162 H162 H 0 0 N N N 22.618 31.709 17.601 -4.426 2.415 1.044 H162 RXA 36
RXA H163 H163 H 0 0 N N N 21.302 30.887 18.506 -5.911 2.605 0.081 H163 RXA 37
RXA H171 H171 H 0 0 N N N 24.033 29.127 16.595 -4.598 2.394 -2.077 H171 RXA 38
RXA H172 H172 H 0 0 N N N 23.095 28.989 15.069 -3.146 2.335 -1.050 H172 RXA 39
RXA H173 H173 H 0 0 N N N 23.683 30.595 15.620 -3.439 1.054 -2.251 H173 RXA 40
RXA H181 H181 H 0 0 N N N 20.397 25.979 17.736 -3.448 -3.187 1.201 H181 RXA 41
RXA H182 H182 H 0 0 N N N 18.761 26.584 17.308 -2.145 -2.194 0.503 H182 RXA 42
RXA H183 H183 H 0 0 N N N 19.786 25.804 16.056 -2.831 -1.775 2.092 H183 RXA 43
RXA H191 H191 H 0 0 N N N 24.647 26.327 21.238 0.171 1.159 2.216 H191 RXA 44
RXA H192 H192 H 0 0 N N N 24.702 26.559 19.458 0.993 2.008 0.885 H192 RXA 45
RXA H193 H193 H 0 0 N N N 24.252 27.929 20.529 -0.774 2.125 1.058 H193 RXA 46
RXA H201 H201 H 0 0 N N N 24.620 23.168 25.369 5.026 0.871 1.762 H201 RXA 47
RXA H202 H202 H 0 0 N N N 24.965 23.516 23.641 5.707 1.771 0.386 H202 RXA 48
RXA H203 H203 H 0 0 N N N 24.360 24.822 24.717 3.952 1.795 0.685 H203 RXA 49
RXA HO2 HO2 H 0 1 N N N 22.244 21.180 27.713 9.006 -0.469 -0.490 HO2 RXA 50
#
loop_
_chem_comp_bond.comp_id
_chem_comp_bond.atom_id_1
_chem_comp_bond.atom_id_2
_chem_comp_bond.value_order
_chem_comp_bond.pdbx_aromatic_flag
_chem_comp_bond.pdbx_stereo_config
_chem_comp_bond.pdbx_ordinal
RXA C1 C2 SING N N 1
RXA C1 C6 SING N N 2
RXA C1 C16 SING N N 3
RXA C1 C17 SING N N 4
RXA C2 C3 SING N N 5
RXA C2 H21 SING N N 6
RXA C2 H22 SING N N 7
RXA C3 C4 SING N N 8
RXA C3 H31 SING N N 9
RXA C3 H32 SING N N 10
RXA C4 C5 SING N N 11
RXA C4 H41 SING N N 12
RXA C4 H42 SING N N 13
RXA C5 C6 DOUB N N 14
RXA C5 C18 SING N N 15
RXA C6 C7 SING N N 16
RXA C7 C8 DOUB N E 17
RXA C7 H7 SING N N 18
RXA C8 C9 SING N N 19
RXA C8 H8 SING N N 20
RXA C9 C10 DOUB N E 21
RXA C9 C19 SING N N 22
RXA C10 C11 SING N N 23
RXA C10 H10 SING N N 24
RXA C11 C12 DOUB N E 25
RXA C11 H11 SING N N 26
RXA C12 C13 SING N N 27
RXA C12 H12 SING N N 28
RXA C13 C14 DOUB N E 29
RXA C13 C20 SING N N 30
RXA C14 C15 SING N N 31
RXA C14 H14 SING N N 32
RXA C15 O1 DOUB N N 33
RXA C15 O2 SING N N 34
RXA C16 H161 SING N N 35
RXA C16 H162 SING N N 36
RXA C16 H163 SING N N 37
RXA C17 H171 SING N N 38
RXA C17 H172 SING N N 39
RXA C17 H173 SING N N 40
RXA C18 H181 SING N N 41
RXA C18 H182 SING N N 42
RXA C18 H183 SING N N 43
RXA C19 H191 SING N N 44
RXA C19 H192 SING N N 45
RXA C19 H193 SING N N 46
RXA C20 H201 SING N N 47
RXA C20 H202 SING N N 48
RXA C20 H203 SING N N 49
RXA O2 HO2 SING N N 50
#
loop_
_pdbx_chem_comp_descriptor.comp_id
_pdbx_chem_comp_descriptor.type
_pdbx_chem_comp_descriptor.program
_pdbx_chem_comp_descriptor.program_version
_pdbx_chem_comp_descriptor.descriptor
RXA SMILES ACDLabs 12.01 "C1(CCCC(=C1\C=C\C(=C\C=C\C(=C\C(=O)O)C)C)C)(C)C"
RXA InChI InChI 1.03 "InChI=1S/C20H28O2/c1-15(8-6-9-16(2)14-19(21)22)11-12-18-17(3)10-7-13-20(18,4)5/h6,8-9,11-12,14H,7,10,13H2,1-5H3,(H,21,22)/b9-6+,12-11+,15-8+,16-14+"
RXA InChIKey InChI 1.03 SHGAZHPCJJPHSC-YCNIQYBTSA-N
RXA SMILES_CANONICAL CACTVS 3.385 "CC1=C(\C=C\C(C)=C\C=C\C(C)=C\C(O)=O)C(C)(C)CCC1"
RXA SMILES CACTVS 3.385 "CC1=C(C=CC(C)=CC=CC(C)=CC(O)=O)C(C)(C)CCC1"
RXA SMILES_CANONICAL "OpenEye OEToolkits" 1.7.6 "CC1=C(C(CCC1)(C)C)/C=C/C(=C/C=C/C(=C/C(=O)O)/C)/C"
RXA SMILES "OpenEye OEToolkits" 1.7.6 "CC1=C(C(CCC1)(C)C)C=CC(=CC=CC(=CC(=O)O)C)C"
#
loop_
_pdbx_chem_comp_identifier.comp_id
_pdbx_chem_comp_identifier.type
_pdbx_chem_comp_identifier.program
_pdbx_chem_comp_identifier.program_version
_pdbx_chem_comp_identifier.identifier
RXA "SYSTEMATIC NAME" ACDLabs 12.01 "retinoic acid"
RXA "SYSTEMATIC NAME" "OpenEye OEToolkits" 1.7.6 "(2E,4E,6E,8E)-3,7-dimethyl-9-(2,6,6-trimethylcyclohexen-1-yl)nona-2,4,6,8-tetraenoic acid"
#
loop_
_pdbx_chem_comp_audit.comp_id
_pdbx_chem_comp_audit.action_type
_pdbx_chem_comp_audit.date
_pdbx_chem_comp_audit.processing_site
RXA "Create component" 1999-07-08 RCSB
RXA "Modify descriptor" 2011-06-04 RCSB
RXA "Other modification" 2016-10-18 RCSB
#
#
data_comp_list
loop_
_chem_comp.id
_chem_comp.three_letter_code
_chem_comp.name
_chem_comp.group
_chem_comp.number_atoms_all
_chem_comp.number_atoms_nh
_chem_comp.desc_level
UN_ UN_ UN_NINE L-peptide 13 6 .
#
data_comp_UN_
#
loop_
_chem_comp_atom.comp_id
_chem_comp_atom.atom_id
_chem_comp_atom.type_symbol
_chem_comp_atom.type_energy
_chem_comp_atom.charge
_chem_comp_atom.x
_chem_comp_atom.y
_chem_comp_atom.z
UN_ N N NT3 1 0.227 -1.259 0.452
UN_ H H H 0 0.069 -1.019 1.421
UN_ H2 H H 0 1.104 -1.640 0.356
UN_ H3 H H 0 -0.424 -1.909 0.174
UN_ CA C CH1 0 0.103 -0.030 -0.392
UN_ HA H H 0 0.160 -0.299 -1.339
UN_ CB C CH3 0 -1.244 0.625 -0.159
UN_ HB3 H H 0 -1.857 -0.018 0.234
UN_ HB2 H H 0 -1.605 0.932 -1.008
UN_ HB1 H H 0 -1.150 1.385 0.442
UN_ C C C 0 1.270 0.922 -0.094
UN_ O O O 0 2.008 1.323 -0.994
UN_ OXT O OC -1 1.498 1.305 1.054
loop_
_chem_comp_tree.comp_id
_chem_comp_tree.atom_id
_chem_comp_tree.atom_back
_chem_comp_tree.atom_forward
_chem_comp_tree.connect_type
UN_ N n/a CA START
UN_ H N . .
UN_ H2 N . .
UN_ H3 N . .
UN_ CA N C .
UN_ HA CA . .
UN_ CB CA HB3 .
UN_ HB1 CB . .
UN_ HB2 CB . .
UN_ HB3 CB . .
UN_ C CA . END
UN_ O C . .
UN_ OXT C . .
loop_
_chem_comp_bond.comp_id
_chem_comp_bond.atom_id_1
_chem_comp_bond.atom_id_2
_chem_comp_bond.type
_chem_comp_bond.aromatic
_chem_comp_bond.value_dist
_chem_comp_bond.value_dist_esd
UN_ CB CA SINGLE n 1.509 0.014
UN_ CA C SINGLE n 1.533 0.011
UN_ C O DOUBLE n 1.247 0.019
UN_ C OXT SINGLE n 1.247 0.019
UN_ CA N SINGLE n 1.482 0.010
UN_ CB HB3 SINGLE n 0.972 0.015
UN_ CB HB2 SINGLE n 0.972 0.015
UN_ CB HB1 SINGLE n 0.972 0.015
UN_ CA HA SINGLE n 0.986 0.020
UN_ N H SINGLE n 0.911 0.020
UN_ N H2 SINGLE n 0.911 0.020
UN_ N H3 SINGLE n 0.911 0.020
loop_
_chem_comp_angle.comp_id
_chem_comp_angle.atom_id_1
_chem_comp_angle.atom_id_2
_chem_comp_angle.atom_id_3
_chem_comp_angle.value_angle
_chem_comp_angle.value_angle_esd
UN_ CA CB HB3 109.546 1.50
UN_ CA CB HB2 109.546 1.50
UN_ CA CB HB1 109.546 1.50
UN_ HB3 CB HB2 109.386 1.50
UN_ HB3 CB HB1 109.386 1.50
UN_ HB2 CB HB1 109.386 1.50
UN_ CB CA C 111.490 1.50
UN_ CB CA N 109.912 1.50
UN_ CB CA HA 108.878 1.50
UN_ C CA N 109.627 1.50
UN_ C CA HA 108.541 1.50
UN_ N CA HA 108.529 1.50
UN_ CA C O 117.159 1.57
UN_ CA C OXT 117.159 1.57
UN_ O C OXT 125.683 1.50
UN_ CA N H 109.643 1.50
UN_ CA N H2 109.643 1.50
UN_ CA N H3 109.643 1.50
UN_ H N H2 109.028 2.41
UN_ H N H3 109.028 2.41
UN_ H2 N H3 109.028 2.41
loop_
_chem_comp_tor.comp_id
_chem_comp_tor.id
_chem_comp_tor.atom_id_1
_chem_comp_tor.atom_id_2
_chem_comp_tor.atom_id_3
_chem_comp_tor.atom_id_4
_chem_comp_tor.value_angle
_chem_comp_tor.value_angle_esd
_chem_comp_tor.period
UN_ hh1 N CA CB HB3 60.000 15.000 3
UN_ sp2_sp3_1 O C CA CB 0.000 10.00 6
UN_ sp3_sp3_10 CB CA N H 180.000 10.00 3
loop_
_chem_comp_chir.comp_id
_chem_comp_chir.id
_chem_comp_chir.atom_id_centre
_chem_comp_chir.atom_id_1
_chem_comp_chir.atom_id_2
_chem_comp_chir.atom_id_3
_chem_comp_chir.volume_sign
UN_ chir_1 CA N C CB positive
loop_
_chem_comp_plane_atom.comp_id
_chem_comp_plane_atom.plane_id
_chem_comp_plane_atom.atom_id
_chem_comp_plane_atom.dist_esd
UN_ plan-1 C 0.020
UN_ plan-1 CA 0.020
UN_ plan-1 O 0.020
UN_ plan-1 OXT 0.020
loop_
_pdbx_chem_comp_descriptor.comp_id
_pdbx_chem_comp_descriptor.type
_pdbx_chem_comp_descriptor.program
_pdbx_chem_comp_descriptor.program_version
_pdbx_chem_comp_descriptor.descriptor
UN_ SMILES ACDLabs 10.04 "O=C(O)C(N)C"
UN_ SMILES_CANONICAL CACTVS 3.341 "C[C@H](N)C(O)=O"
UN_ SMILES CACTVS 3.341 "C[CH](N)C(O)=O"
UN_ SMILES_CANONICAL "OpenEye OEToolkits" 1.5.0 "C[C@@H](C(=O)O)N"
UN_ SMILES "OpenEye OEToolkits" 1.5.0 "CC(C(=O)O)N"
UN_ InChI InChI 1.03 "InChI=1S/C3H7NO2/c1-2(4)3(5)6/h2H,4H2,1H3,(H,5,6)/t2-/m0/s1"
UN_ InChIKey InChI 1.03 QNAYBMKLOCPYGJ-REOHCLBHSA-N
UN_ ? acedrg 195 "dictionary generator"
UN_ ? acedrg_database 11 "data source"
UN_ ? rdkit 2017.03.2 "Chemoinformatics tool"
UN_ ? refmac5 5.8.0189 "optimization tool"
......@@ -87,6 +87,7 @@ BOOST_AUTO_TEST_CASE(create_nonpoly_1)
auto atoms = R"(
data_HEM
loop_
_atom_site.id
_atom_site.group_PDB
_atom_site.type_symbol
_atom_site.label_atom_id
......@@ -98,13 +99,15 @@ _atom_site.Cartn_z
_atom_site.occupancy
_atom_site.B_iso_or_equiv
_atom_site.pdbx_formal_charge
HETATM C CHA . ? -5.248 39.769 -0.250 1.00 7.67 ?
HETATM C CHB . ? -3.774 36.790 3.280 1.00 7.05 ?
HETATM C CHC . ? -2.879 33.328 0.013 1.00 7.69 ?
HETATM C CHD . ? -4.342 36.262 -3.536 1.00 8.00 ?
1 HETATM C CHA . ? -5.248 39.769 -0.250 1.00 7.67 ?
2 HETATM C CHB . ? -3.774 36.790 3.280 1.00 7.05 ?
3 HETATM C CHC . ? -2.879 33.328 0.013 1.00 7.69 ?
4 HETATM C CHD . ? -4.342 36.262 -3.536 1.00 8.00 ?
# that's enough to test with
)"_cf;
atoms.load_dictionary("mmcif_pdbx");
auto &hem_data = atoms["HEM"];
auto &atom_site = hem_data["atom_site"];
......@@ -177,6 +180,7 @@ _struct_asym.pdbx_blank_PDB_chainid_flag N
_struct_asym.pdbx_modified N
_struct_asym.details ?
#
_atom_type.symbol C
)"_cf;
expected.load_dictionary("mmcif_pdbx.dic");
......
#include "../include/cif++/Cif++.hpp"
#include "../include/cif++/PDB2Cif.hpp"
#include "../include/cif++/Structure.hpp"
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2021 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++.hpp>
#include <iostream>
#include <fstream>
......@@ -22,16 +46,21 @@ int main(int argc, char* argv[])
if (std::filesystem::exists(testdir / ".." / "rsrc" / "mmcif_pdbx.dic"))
cif::add_file_resource("mmcif_pdbx.dic", testdir / ".." / "rsrc" / "mmcif_pdbx.dic");
mmcif::CompoundFactory::instance().pushDictionary(testdir / "REA.cif");
mmcif::CompoundFactory::instance().pushDictionary(testdir / "RXA.cif");
cif::compound_factory::instance().push_dictionary(testdir / "REA.cif");
cif::compound_factory::instance().push_dictionary(testdir / "RXA.cif");
mmcif::file f(testdir / ".."/"examples"/"1cbs.cif.gz");
mmcif::Structure structure(f);
cif::file f(testdir / ".."/"examples"/"1cbs.cif.gz");
cif::mm::structure structure(f);
auto &res = structure.getResidue("B");
auto &res = structure.get_residue("B");
structure.change_residue(res, "RXA", {});
structure.cleanupEmptyCategories();
structure.cleanup_empty_categories();
f.save(std::cout);
if (not f.is_valid())
throw std::runtime_error("Invalid");
f.save(std::cout);
}
......
......@@ -29,8 +29,7 @@
#include <stdexcept>
#include <cif++/cif.hpp>
#include <cif++/structure/Structure.hpp>
#include <cif++.hpp>
// --------------------------------------------------------------------
......@@ -66,7 +65,7 @@ bool init_unit_test()
// initialize CCD location
cif::add_file_resource("components.cif", gTestDir / ".." / "data" / "ccd-subset.cif");
mmcif::CompoundFactory::instance().pushDictionary(gTestDir / "HEM.cif");
cif::compound_factory::instance().push_dictionary(gTestDir / "HEM.cif");
return true;
}
......@@ -78,10 +77,10 @@ BOOST_AUTO_TEST_CASE(sugar_name_1)
using namespace cif::literals;
const std::filesystem::path example(gTestDir / "1juh.cif.gz");
mmcif::file file(example.string());
mmcif::Structure s(file);
cif::file file(example.string());
cif::mm::structure s(file);
auto &db = s.datablock();
auto &db = s.get_datablock();
auto &entity = db["entity"];
auto &branches = s.branches();
......@@ -90,7 +89,7 @@ BOOST_AUTO_TEST_CASE(sugar_name_1)
for (auto &branch : branches)
{
auto entityID = branch.front().entityID();
auto entityID = branch.front().get_entity_id();
auto name = entity.find1<std::string>("id"_key == entityID, "pdbx_description");
BOOST_CHECK_EQUAL(branch.name(), name);
......@@ -104,20 +103,23 @@ BOOST_AUTO_TEST_CASE(create_sugar_1)
using namespace cif::literals;
const std::filesystem::path example(gTestDir / "1juh.cif.gz");
mmcif::file file(example.string());
mmcif::Structure s(file);
cif::file file(example.string());
cif::mm::structure s(file);
// collect atoms from asym L first
auto &NAG = s.getResidue("L");
auto &NAG = s.get_residue("L");
auto nagAtoms = NAG.atoms();
std::vector<std::vector<cif::Item>> ai;
std::vector<cif::row_initializer> ai;
auto &db = s.datablock();
auto &db = s.get_datablock();
auto &as = db["atom_site"];
// NOTE, row_initializer does not actually hold the data, so copy it first
// before it gets destroyed by remove_residue
for (auto r : as.find("label_asym_id"_key == "L"))
ai.emplace_back(r.begin(), r.end());
auto &ri = ai.emplace_back(r);
s.remove_residue(NAG);
......@@ -127,6 +129,10 @@ BOOST_AUTO_TEST_CASE(create_sugar_1)
BOOST_CHECK_EQUAL(branch.size(), 1);
BOOST_CHECK_EQUAL(branch[0].atoms().size(), nagAtoms.size());
BOOST_CHECK(file.is_valid());
file.save(gTestDir / "test-create_sugar_1.cif");
}
// --------------------------------------------------------------------
......@@ -136,36 +142,40 @@ BOOST_AUTO_TEST_CASE(create_sugar_2)
using namespace cif::literals;
const std::filesystem::path example(gTestDir / "1juh.cif.gz");
mmcif::file file(example.string());
mmcif::Structure s(file);
cif::file file(example.string());
cif::mm::structure s(file);
// Get branch for H
auto &bH = s.getBranchByAsymID("H");
auto &bH = s.get_branch_by_asym_id("H");
BOOST_CHECK_EQUAL(bH.size(), 2);
std::vector<std::vector<cif::Item>> ai[2];
std::vector<cif::row_initializer> ai[2];
auto &db = s.datablock();
auto &db = s.get_datablock();
auto &as = db["atom_site"];
for (size_t i = 0; i < 2; ++i)
{
for (auto r : as.find("label_asym_id"_key == "H" and "auth_seq_id"_key == i + 1))
ai[i].emplace_back(r.begin(), r.end());
auto &ri = ai[i].emplace_back(r);
}
s.remove_branch(bH);
BOOST_CHECK(file.is_valid());
auto &bN = s.create_branch(ai[0]);
s.extend_branch(bN.asymID(), ai[1], 1, "O4");
s.extend_branch(bN.get_asym_id(), ai[1], 1, "O4");
BOOST_CHECK_EQUAL(bN.name(), "2-acetamido-2-deoxy-beta-D-glucopyranose-(1-4)-2-acetamido-2-deoxy-beta-D-glucopyranose");
BOOST_CHECK_EQUAL(bN.size(), 2);
BOOST_CHECK(file.is_valid());
file.save(gTestDir / "test-create_sugar_2.cif");
BOOST_CHECK_NO_THROW(mmcif::Structure s2(file));
BOOST_CHECK_NO_THROW(cif::mm::structure s2(file));
}
// --------------------------------------------------------------------
......@@ -175,11 +185,11 @@ BOOST_AUTO_TEST_CASE(delete_sugar_1)
using namespace cif::literals;
const std::filesystem::path example(gTestDir / "1juh.cif.gz");
mmcif::file file(example.string());
mmcif::Structure s(file);
cif::file file(example.string());
cif::mm::structure s(file);
// Get branch for H
auto &bG = s.getBranchByAsymID("G");
auto &bG = s.get_branch_by_asym_id("G");
BOOST_CHECK_EQUAL(bG.size(), 4);
......@@ -187,12 +197,14 @@ BOOST_AUTO_TEST_CASE(delete_sugar_1)
BOOST_CHECK_EQUAL(bG.size(), 1);
auto &bN = s.getBranchByAsymID("G");
auto &bN = s.get_branch_by_asym_id("G");
BOOST_CHECK_EQUAL(bN.name(), "2-acetamido-2-deoxy-beta-D-glucopyranose");
BOOST_CHECK_EQUAL(bN.size(), 1);
file.save(gTestDir / "test-create_sugar_3.cif");
BOOST_CHECK(file.is_valid());
// file.save(gTestDir / "test-create_sugar_3.cif");
BOOST_CHECK_NO_THROW(mmcif::Structure s2(file));
BOOST_CHECK_NO_THROW(cif::mm::structure s2(file));
}
......@@ -142,13 +142,17 @@ BOOST_AUTO_TEST_CASE(item_1)
BOOST_CHECK_EQUAL(i2.value(), ci2.value());
BOOST_CHECK_EQUAL(i3.value(), ci3.value());
item mi1(std::move(i1));
item mi2(std::move(i2));
item mi3(std::move(i3));
item mi1(std::move(ci1));
item mi2(std::move(ci2));
item mi3(std::move(ci3));
BOOST_CHECK_EQUAL(i1.value(), mi1.value());
BOOST_CHECK_EQUAL(i2.value(), mi2.value());
BOOST_CHECK_EQUAL(i3.value(), mi3.value());
BOOST_CHECK(ci1.empty());
BOOST_CHECK(ci2.empty());
BOOST_CHECK(ci3.empty());
}
// --------------------------------------------------------------------
......@@ -1037,12 +1041,12 @@ _cat_2.desc
cat1.erase(cif::key("id") == 10);
BOOST_CHECK_EQUAL(cat1.size(), 2);
BOOST_CHECK_EQUAL(cat2.size(), 3); // TODO: Is this really what we want?
BOOST_CHECK_EQUAL(cat2.size(), 2); // TODO: Is this really what we want?
cat1.erase(cif::key("id") == 20);
BOOST_CHECK_EQUAL(cat1.size(), 1);
BOOST_CHECK_EQUAL(cat2.size(), 2); // TODO: Is this really what we want?
BOOST_CHECK_EQUAL(cat2.size(), 1); // TODO: Is this really what we want?
}
// --------------------------------------------------------------------
......@@ -1514,8 +1518,6 @@ _cat_2.parent_id3
// --------------------------------------------------------------------
// --------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(d6)
{
const char dict[] = R"(
......@@ -2859,4 +2861,112 @@ _cat_1.name
auto &audit_conform = f2.front()["audit_conform"];
BOOST_CHECK_EQUAL(audit_conform.front()["dict_name"].as<std::string>(), "test_dict.dic");
BOOST_CHECK_EQUAL(audit_conform.front()["dict_version"].as<float>(), 1.0);
}
\ No newline at end of file
}
// --------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(ix_op_1)
{
const char dict[] = R"(
data_test_dict.dic
_datablock.id test_dict.dic
_datablock.description
;
A test dictionary
;
_dictionary.title test_dict.dic
_dictionary.datablock_id test_dict.dic
_dictionary.version 1.0
loop_
_item_type_list.code
_item_type_list.primitive_code
_item_type_list.construct
code char
'[][_,.;:"&<>()/\{}'`~!@#$%A-Za-z0-9*|+-]*'
text char
'[][ \n\t()_,.;:"&<>/\{}'`~!@#$%?+=*A-Za-z0-9|^-]*'
int numb
'[+-]?[0-9]+'
save_cat_1
_category.description 'A simple test category'
_category.id cat_1
_category.mandatory_code yes
loop_
_category_key.name '_cat_1.id'
'_cat_1.id_2'
save_
save__cat_1.id
_item.name '_cat_1.id'
_item.category_id cat_1
_item.mandatory_code yes
_item_type.code int
save_
save__cat_1.id_2
_item.name '_cat_1.id_2'
_item.category_id cat_1
_item.mandatory_code no
_item_type.code int
save_
)";
struct membuf : public std::streambuf
{
membuf(char *text, size_t length)
{
this->setg(text, text, text + length);
}
} buffer(const_cast<char *>(dict), sizeof(dict) - 1);
std::istream is_dict(&buffer);
auto validator = cif::parse_dictionary("test", is_dict);
cif::file f;
f.set_validator(&validator);
// --------------------------------------------------------------------
const char data[] = R"(
data_test
loop_
_cat_1.id
_cat_1.id_2
1 10
2 20
3 ?
)";
// --------------------------------------------------------------------
struct data_membuf : public std::streambuf
{
data_membuf(char *text, size_t length)
{
this->setg(text, text, text + length);
}
} data_buffer(const_cast<char *>(data), sizeof(data) - 1);
std::istream is_data(&data_buffer);
f.load(is_data);
auto &cat1 = f.front()["cat_1"];
using key_type = cif::category::key_type;
using test_tuple_type = std::tuple<key_type,bool>;
test_tuple_type TESTS[] = {
{ {{"id", 1}, {"id_2", 10}}, true },
{ {{"id_2", 10}, {"id", 1}}, true },
{ {{"id", 1}, {"id_2", 20}}, false },
{ {{"id", 3} }, true },
};
for (const auto &[key, test] : TESTS)
BOOST_CHECK_EQUAL((bool)cat1[key], test);
}
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