Commit 7c5f1ba8 by Maarten L. Hekkelman

Merge branch 'trunk' into develop

parents e7c34cc1 72fd03a6
[submodule "gxrio"]
path = gxrio
url = https://github.com/mhekkel/gxrio.git
......@@ -25,7 +25,7 @@
cmake_minimum_required(VERSION 3.16)
# set the project name
project(cifpp VERSION 5.0.2 LANGUAGES CXX)
project(cifpp VERSION 5.0.6 LANGUAGES CXX)
list(PREPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
......@@ -299,18 +299,16 @@ if(CIFPP_DOWNLOAD_CCD)
add_custom_target(COMPONENTS ALL DEPENDS ${COMPONENTS_CIF})
endif()
# Installation directories
set(CIFPP_DATA_DIR "${CMAKE_INSTALL_FULL_DATADIR}/libcifpp")
target_compile_definitions(cifpp PUBLIC DATA_DIR="${CIFPP_DATA_DIR}")
if(UNIX)
set(CIFPP_CACHE_DIR "/var/cache/libcifpp" CACHE STRING "The cache directory to use")
set(CIFPP_CACHE_DIR "${CMAKE_INSTALL_FULL_LOCALSTATEDIR}/cache/libcifpp")
target_compile_definitions(cifpp PUBLIC CACHE_DIR="${CIFPP_CACHE_DIR}")
endif()
set(INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_INCLUDEDIR})
set(LIBRARY_INSTALL_DIR ${CMAKE_INSTALL_LIBDIR})
set(SHARE_INSTALL_DIR ${CMAKE_INSTALL_DATADIR}/libcifpp)
set(CIFPP_DATA_DIR "${CMAKE_INSTALL_PREFIX}/${SHARE_INSTALL_DIR}" CACHE STRING "The directory containing the provided data files")
target_compile_definitions(cifpp PUBLIC DATA_DIR="${CIFPP_DATA_DIR}")
set(CIFPP_ETC_DIR "${CMAKE_INSTALL_FULL_SYSCONFDIR}")
endif()
# Install rules
install(TARGETS cifpp
......@@ -359,7 +357,7 @@ configure_package_config_file(
${CONFIG_TEMPLATE_FILE}
${CMAKE_CURRENT_BINARY_DIR}/cifpp/cifppConfig.cmake
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/cifpp
PATH_VARS INCLUDE_INSTALL_DIR LIBRARY_INSTALL_DIR SHARE_INSTALL_DIR
PATH_VARS CIFPP_DATA_DIR
)
install(FILES
......@@ -429,11 +427,15 @@ if(ENABLE_TESTING)
endforeach()
endif()
message("Will install in ${CMAKE_INSTALL_PREFIX}")
# Optionally install the update scripts for CCD and dictionary files
if(CIFPP_INSTALL_UPDATE_SCRIPT)
set(CIFPP_CRON_DIR "$ENV{DESTDIR}/etc/cron.weekly")
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
set(CIFPP_CRON_DIR "${CIFPP_ETC_DIR}/cron.weekly")
elseif(UNIX) # assume all others are like FreeBSD...
set(CIFPP_CRON_DIR "${CIFPP_ETC_DIR}/periodic/weekly")
else()
message(FATAL_ERROR "Don't know where to install the update script")
endif()
configure_file(${PROJECT_SOURCE_DIR}/tools/update-libcifpp-data.in update-libcifpp-data @ONLY)
install(
......@@ -443,15 +445,15 @@ if(CIFPP_INSTALL_UPDATE_SCRIPT)
)
install(DIRECTORY DESTINATION ${CIFPP_CACHE_DIR})
install(DIRECTORY DESTINATION "$ENV{DESTDIR}/etc/libcifpp/cache-update.d")
install(DIRECTORY DESTINATION "${CIFPP_ETC_DIR}/libcifpp/cache-update.d")
# a config to, to make it complete
if(NOT EXISTS "$ENV{DESTDIR}/etc/libcifpp.conf")
if(NOT EXISTS "${CIFPP_ETC_DIR}/libcifpp.conf")
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/libcifpp.conf [[# Uncomment the next line to enable automatic updates
# update=true
]])
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libcifpp.conf DESTINATION "$ENV{DESTDIR}/etc")
install(CODE "message(\"A configuration file has been written to $ENV{DESTDIR}/etc/libcifpp.conf, please edit this file to enable automatic updates\")")
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libcifpp.conf DESTINATION "${CIFPP_ETC_DIR}")
install(CODE "message(\"A configuration file has been written to ${CIFPP_ETC_DIR}/libcifpp.conf, please edit this file to enable automatic updates\")")
endif()
target_compile_definitions(cifpp PUBLIC CACHE_DIR="${CIFPP_CACHE_DIR}")
......@@ -462,7 +464,7 @@ set(CPACK_SOURCE_TGZ ON)
set(CPACK_SOURCE_TBZ2 OFF)
set(CPACK_SOURCE_TXZ OFF)
set(CPACK_SOURCE_TZ OFF)
set(CPACK_SOURCE_IGNORE_FILES "/data/components.cif;/build;/.vscode;/.git;/regex")
set(CPACK_SOURCE_IGNORE_FILES "/data/components.cif;/build;/.vscode;/.git")
set(CPACK_PACKAGE_FILE_NAME "${PROJECT_NAME}-${PROJECT_VERSION}")
set(CPACK_SOURCE_PACKAGE_FILE_NAME ${CPACK_PACKAGE_FILE_NAME})
include(CPack)
Version 5.0.6
- Fix file::contains, using iequals
Version 5.0.5
- Fix code to work on 32 bit machines
Version 5.0.4
- Revert removal of CIFPP_SHARE_DIR export
Version 5.0.3
- Fix installation of libcifpp into the correct locations
Version 5.0.2
- Fix export of CISPEP records in PDB format
- Better support for exporting package_source
......
......@@ -4,12 +4,9 @@ include(CMakeFindDependencyMacro)
find_dependency(Threads)
find_dependency(ZLIB REQUIRED)
find_dependency(LibLZMA REQUIRED)
INCLUDE("${CMAKE_CURRENT_LIST_DIR}/cifppTargets.cmake")
set_and_check(CIFPP_INCLUDE_DIR "@PACKAGE_INCLUDE_INSTALL_DIR@")
set_and_check(CIFPP_LIBRARY_DIR "@PACKAGE_LIBRARY_INSTALL_DIR@")
set_and_check(CIFPP_SHARE_DIR "@PACKAGE_SHARE_INSTALL_DIR@")
set_and_check(CIFPP_SHARE_DIR "@PACKAGE_CIFPP_DATA_DIR@")
check_required_components(cifpp)
......@@ -38,3 +38,4 @@
#include <cif++/model.hpp>
#include <cif++/pdb/io.hpp>
#include <cif++/gzio.hpp>
\ No newline at end of file
......@@ -57,6 +57,8 @@ namespace detail
virtual bool test(row_handle) const = 0;
virtual void str(std::ostream &) const = 0;
virtual std::optional<row_handle> single() const { return {}; };
virtual bool equals(const condition_impl *rhs) const { return false; }
};
struct all_condition_impl : public condition_impl
......@@ -145,7 +147,6 @@ class condition
}
private:
void optimise(condition_impl *&impl);
condition_impl *m_impl;
......@@ -193,9 +194,7 @@ namespace detail
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;
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
......@@ -208,6 +207,19 @@ namespace detail
return m_single_hit;
}
virtual bool equals(const condition_impl *rhs) const override
{
if (typeid(*rhs) == typeid(key_equals_condition_impl))
{
auto ri = static_cast<const key_equals_condition_impl *>(rhs);
if (m_single_hit.has_value() or ri->m_single_hit.has_value())
return m_single_hit == ri->m_single_hit;
else
return m_item_ix == ri->m_item_ix and m_value == ri->m_value;
}
return this == rhs;
}
std::string m_item_tag;
uint16_t m_item_ix = 0;
bool m_icase = false;
......@@ -244,7 +256,7 @@ namespace detail
void str(std::ostream &os) const override
{
os << m_item_tag << (m_icase ? "^ " : " ") << " == " << m_value << " OR " << m_item_tag << " IS NULL";
os << '(' << m_item_tag << (m_icase ? "^ " : " ") << " == " << m_value << " OR " << m_item_tag << " IS NULL)";
}
virtual std::optional<row_handle> single() const override
......@@ -252,12 +264,25 @@ namespace detail
return m_single_hit;
}
virtual bool equals(const condition_impl *rhs) const override
{
if (typeid(*rhs) == typeid(key_equals_or_empty_condition_impl))
{
auto ri = static_cast<const key_equals_or_empty_condition_impl *>(rhs);
if (m_single_hit.has_value() or ri->m_single_hit.has_value())
return m_single_hit == ri->m_single_hit;
else
return m_item_ix == ri->m_item_ix and m_value == ri->m_value;
}
return this == rhs;
}
std::string m_item_tag;
uint16_t m_item_ix = 0;
std::string m_value;
bool m_icase = false;
std::optional<row_handle> m_single_hit;
};
};
struct key_compare_condition_impl : public condition_impl
{
......@@ -409,29 +434,53 @@ namespace detail
// case they make up an indexed tuple.
struct and_condition_impl : public condition_impl
{
and_condition_impl() = default;
and_condition_impl(condition &&a, condition &&b)
{
mSub.emplace_back(std::exchange(a.m_impl, nullptr));
mSub.emplace_back(std::exchange(b.m_impl, nullptr));
if (typeid(*a.m_impl) == typeid(*this))
{
and_condition_impl *ai = static_cast<and_condition_impl *>(a.m_impl);
std::swap(m_sub, ai->m_sub);
m_sub.emplace_back(std::exchange(b.m_impl, nullptr));
}
else if (typeid(*b.m_impl) == typeid(*this))
{
and_condition_impl *bi = static_cast<and_condition_impl *>(b.m_impl);
std::swap(m_sub, bi->m_sub);
m_sub.emplace_back(std::exchange(a.m_impl, nullptr));
}
else
{
m_sub.emplace_back(std::exchange(a.m_impl, nullptr));
m_sub.emplace_back(std::exchange(b.m_impl, nullptr));
}
}
~and_condition_impl()
{
for (auto sub : mSub)
for (auto sub : m_sub)
delete sub;
}
condition_impl *prepare(const category &c) override;
condition_impl *prepare(const category &c) override
{
for (auto &sub : m_sub)
sub = sub->prepare(c);
return this;
}
bool test(row_handle r) const override
{
bool result = true;
for (auto sub : mSub)
for (auto sub : m_sub)
{
if (sub->test(r))
continue;
result = false;
break;
}
......@@ -444,7 +493,7 @@ namespace detail
os << '(';
bool first = true;
for (auto sub : mSub)
for (auto sub : m_sub)
{
if (first)
first = false;
......@@ -461,7 +510,7 @@ namespace detail
{
std::optional<row_handle> result;
for (auto sub : mSub)
for (auto sub : m_sub)
{
auto s = sub->single();
......@@ -470,7 +519,7 @@ namespace detail
result = s;
continue;
}
if (s == result)
continue;
......@@ -481,56 +530,100 @@ namespace detail
return result;
}
std::vector<condition_impl *> mSub;
static condition_impl *combine_equal(std::vector<and_condition_impl *> &subs, or_condition_impl *oc);
std::vector<condition_impl *> m_sub;
};
struct or_condition_impl : public condition_impl
{
or_condition_impl(condition &&a, condition &&b)
: mA(nullptr)
, mB(nullptr)
{
std::swap(mA, a.m_impl);
std::swap(mB, b.m_impl);
if (typeid(*a.m_impl) == typeid(*this))
{
or_condition_impl *ai = static_cast<or_condition_impl *>(a.m_impl);
std::swap(m_sub, ai->m_sub);
m_sub.emplace_back(std::exchange(b.m_impl, nullptr));
}
else if (typeid(*b.m_impl) == typeid(*this))
{
or_condition_impl *bi = static_cast<or_condition_impl *>(b.m_impl);
std::swap(m_sub, bi->m_sub);
m_sub.emplace_back(std::exchange(a.m_impl, nullptr));
}
else
{
m_sub.emplace_back(std::exchange(a.m_impl, nullptr));
m_sub.emplace_back(std::exchange(b.m_impl, nullptr));
}
}
~or_condition_impl()
{
delete mA;
delete mB;
for (auto sub : m_sub)
delete sub;
}
condition_impl *prepare(const category &c) override;
bool test(row_handle r) const override
{
return mA->test(r) or mB->test(r);
bool result = false;
for (auto sub : m_sub)
{
if (not sub->test(r))
continue;
result = true;
break;
}
return result;
}
void str(std::ostream &os) const override
{
bool first = true;
os << '(';
mA->str(os);
os << ") OR (";
mB->str(os);
for (auto sub : m_sub)
{
if (first)
first = false;
else
os << " OR ";
sub->str(os);
}
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;
std::optional<row_handle> result;
for (auto sub : m_sub)
{
auto s = sub->single();
if (not result.has_value())
{
result = s;
continue;
}
if (s == result)
continue;
return sa;
result.reset();
break;
}
return result;
}
condition_impl *mA;
condition_impl *mB;
std::vector<condition_impl *> m_sub;
};
struct not_condition_impl : public condition_impl
......@@ -569,7 +662,7 @@ namespace detail
} // namespace detail
inline condition operator&&(condition &&a, condition &&b)
inline condition operator and(condition &&a, condition &&b)
{
if (a.m_impl and b.m_impl)
return condition(new detail::and_condition_impl(std::move(a), std::move(b)));
......@@ -578,12 +671,35 @@ inline condition operator&&(condition &&a, condition &&b)
return condition(std::move(b));
}
inline condition operator||(condition &&a, condition &&b)
inline condition operator or(condition &&a, condition &&b)
{
if (a.m_impl and b.m_impl)
{
if (typeid(*a.m_impl) == typeid(detail::key_equals_condition_impl) and
typeid(*b.m_impl) == typeid(detail::key_is_empty_condition_impl))
{
auto ci = static_cast<detail::key_equals_condition_impl *>(a.m_impl);
auto ce = static_cast<detail::key_is_empty_condition_impl *>(b.m_impl);
if (ci->m_item_tag == ce->m_item_tag)
return condition(new detail::key_equals_or_empty_condition_impl(ci));
}
else if (typeid(*b.m_impl) == typeid(detail::key_equals_condition_impl) and
typeid(*a.m_impl) == typeid(detail::key_is_empty_condition_impl))
{
auto ci = static_cast<detail::key_equals_condition_impl *>(b.m_impl);
auto ce = static_cast<detail::key_is_empty_condition_impl *>(a.m_impl);
if (ci->m_item_tag == ce->m_item_tag)
return condition(new detail::key_equals_or_empty_condition_impl(ci));
}
return condition(new detail::or_condition_impl(std::move(a), std::move(b)));
}
if (a.m_impl)
return condition(std::move(a));
return condition(std::move(b));
}
......@@ -706,7 +822,7 @@ inline condition operator==(const key &key, const empty_type &)
return condition(new detail::key_is_empty_condition_impl(key.m_item_tag));
}
inline condition operator !(condition &&rhs)
inline condition operator not(condition &&rhs)
{
return condition(new detail::not_condition_impl(std::move(rhs)));
}
......
......@@ -26,8 +26,8 @@
/// whether to use a compressions/decompression algorithm is
/// based on the extension of the \a filename argument.
// This is a stripped down version of the gzio library from
// https://github.com/mhekkel/gzio.git
// This is a stripped down version of the gxrio library from
// https://github.com/mhekkel/gxrio.git
// Most notably, the lzma support has been removed since getting
// that to work in Windows proved to be too much work.
......@@ -128,15 +128,15 @@ class basic_igzip_streambuf : public basic_streambuf<CharT, Traits>
std::swap(m_zstream, rhs.m_zstream);
std::swap(m_gzheader, rhs.m_gzheader);
auto p = std::copy(rhs.gptr(), rhs.egptr(), m_out_buffer.begin());
this->setg(m_out_buffer.data(), m_out_buffer.data() + m_out_buffer.size(), p);
auto p = std::copy(rhs.gptr(), rhs.egptr(), m_out_buffer.data());
this->setg(m_out_buffer.data(), m_out_buffer.data(), p);
if (m_zstream and m_zstream->avail_in > 0)
{
auto next_in_offset = m_zstream->next_in - rhs.m_in_buffer.data();
std::copy(rhs.m_in_buffer.begin() + next_in_offset,
rhs.m_in_buffer.begin() + next_in_offset + m_zstream->avail_in,
m_in_buffer.begin());
std::copy(rhs.m_in_buffer.data() + next_in_offset,
rhs.m_in_buffer.data() + next_in_offset + m_zstream->avail_in,
m_in_buffer.data());
m_zstream->next_in = m_in_buffer.data();
}
}
......@@ -151,15 +151,15 @@ class basic_igzip_streambuf : public basic_streambuf<CharT, Traits>
std::swap(m_zstream, rhs.m_zstream);
std::swap(m_gzheader, rhs.m_gzheader);
auto p = std::copy(rhs.gptr(), rhs.egptr(), m_out_buffer.begin());
this->setg(m_out_buffer.data(), m_out_buffer.data() + m_out_buffer.size(), p);
auto p = std::copy(rhs.gptr(), rhs.egptr(), m_out_buffer.data());
this->setg(m_out_buffer.data(), m_out_buffer.data(), p);
if (m_zstream and m_zstream->avail_in > 0)
{
auto next_in_offset = m_zstream->next_in - reinterpret_cast<unsigned char *>(rhs.m_in_buffer.data());
std::copy(rhs.m_in_buffer.begin() + next_in_offset,
rhs.m_in_buffer.begin() + next_in_offset + m_zstream->avail_in,
m_in_buffer.begin());
std::copy(rhs.m_in_buffer.data() + next_in_offset,
rhs.m_in_buffer.data() + next_in_offset + m_zstream->avail_in,
m_in_buffer.data());
m_zstream->next_in = reinterpret_cast<unsigned char *>(m_in_buffer.data());
}
......
......@@ -194,6 +194,7 @@ struct item_value
/// \brief constructor
item_value(std::string_view text)
: m_length(text.length())
, m_storage(0)
{
if (m_length >= kBufferSize)
{
......@@ -210,7 +211,7 @@ struct item_value
item_value(item_value &&rhs)
: m_length(std::exchange(rhs.m_length, 0))
, m_data(std::exchange(rhs.m_data, nullptr))
, m_storage(std::exchange(rhs.m_storage, 0))
{
}
......@@ -219,7 +220,7 @@ struct item_value
if (this != &rhs)
{
m_length = std::exchange(rhs.m_length, m_length);
m_data = std::exchange(rhs.m_data, m_data);
m_storage = std::exchange(rhs.m_storage, m_storage);
}
return *this;
}
......@@ -228,7 +229,7 @@ struct item_value
{
if (m_length >= kBufferSize)
delete[] m_data;
m_data = nullptr;
m_storage = 0;
m_length = 0;
}
......@@ -245,6 +246,7 @@ struct item_value
{
char m_local_data[8];
char *m_data;
uint64_t m_storage;
};
static constexpr size_t kBufferSize = sizeof(m_local_data);
......@@ -257,9 +259,6 @@ struct item_value
}
};
// static_assert(sizeof(item_value) == 24, "sizeof(item_value) should be 24 bytes");
static_assert(sizeof(item_value) == 16, "sizeof(item_value) should be 16 bytes");
// --------------------------------------------------------------------
// Transient object to access stored data
......
......@@ -101,13 +101,13 @@ class atom
row_handle row_aniso()
{
auto cat = m_db.get("atom_site_anisotrop");
return cat ? cat->find1(key("id") == m_id) : row_handle{};
return cat ? cat->operator[]({ {"id", m_id} }) : row_handle{};
}
const row_handle row_aniso() const
{
auto cat = m_db.get("atom_site_anisotrop");
return cat ? cat->find1(key("id") == m_id) : row_handle{};
return cat ? cat->operator[]({ {"id", m_id} }) : row_handle{};
}
const datablock &m_db;
......
......@@ -27,6 +27,7 @@
#pragma once
#include <map>
#include <regex>
#include <cif++/row.hpp>
......@@ -93,23 +94,23 @@ class sac_parser
static bool is_unquoted_string(std::string_view text)
{
auto s = text.begin();
bool result = is_ordinary(text.front());
bool result = is_ordinary(*s++);
while (result and s != text.end())
{
result = is_non_blank(*s);
++s;
}
// but be careful it does not contain e.g. stop_
if (result)
{
static const std::regex reservedRx(R"((^(?:data|save)|.*(?:loop|stop|global))_.+)", std::regex_constants::icase);
result = not std::regex_match(text.begin(), text.end(), reservedRx);
for (auto ch : text)
{
if (is_non_blank(ch))
continue;
result = false;
break;
}
}
return result;
static const std::regex kReservedRx(R"(loop_|stop_|global_|data_\S+|save_\S+)", std::regex_constants::icase);
// but be careful it does not contain e.g. stop_
return result and not std::regex_match(text.begin(), text.end(), kReservedRx);
}
protected:
......
......@@ -8,6 +8,6 @@ Name: libcifpp
Description: C++ library for the manipulation of mmCIF files.
Version: @PACKAGE_VERSION@
Requires.private: zlib, liblzma
Requires.private: zlib
Libs: -L${libdir} -lcifpp
Cflags: -I${includedir} -pthread
......@@ -1142,10 +1142,6 @@ category::iterator category::erase(iterator pos)
row *r = rh.get_row();
iterator result = ++pos;
iset keys;
if (m_cat_validator)
keys = iset(m_cat_validator->m_keys.begin(), m_cat_validator->m_keys.end());
if (m_head == nullptr)
throw std::runtime_error("erase");
......@@ -1174,7 +1170,7 @@ category::iterator category::erase(iterator pos)
// in mmcif_pdbx.dic dictionary.
//
// For each link group in _pdbx_item_linked_group_list
// a std::set of keys from one category is mapped to another.
// a set of keys from one category is mapped to another.
// If all values in a child are the same as the specified parent ones
// the child is removed as well, recursively of course.
......@@ -1198,25 +1194,29 @@ category::iterator category::erase(iterator pos)
return result;
}
size_t category::erase(condition &&cond)
template<typename T>
class save_value
{
size_t result = 0;
cond.prepare(*this);
public:
save_value(T &v, const T nv = {})
: m_v(v)
, m_sv(std::exchange(m_v, nv))
{
}
auto ri = begin();
while (ri != end())
~save_value()
{
if (cond(*ri))
{
ri = erase(ri);
++result;
}
else
++ri;
m_v = m_sv;
}
return result;
private:
T &m_v;
const T m_sv;
};
size_t category::erase(condition &&cond)
{
return erase(std::move(cond), {});
}
size_t category::erase(condition &&cond, std::function<void(row_handle)> &&visit)
......@@ -1225,12 +1225,26 @@ size_t category::erase(condition &&cond, std::function<void(row_handle)> &&visit
cond.prepare(*this);
std::map<category *, condition> potential_orphans;
auto ri = begin();
while (ri != end())
{
if (cond(*ri))
{
visit(*ri);
if (visit)
visit(*ri);
for (auto &&[childCat, link] : m_child_links)
{
auto cond = get_children_condition(*ri, *childCat);
if (not cond)
continue;
potential_orphans[childCat] = std::move(potential_orphans[childCat]) or std::move(cond);
}
save_value sv(m_validator);
ri = erase(ri);
++result;
}
......@@ -1238,6 +1252,9 @@ size_t category::erase(condition &&cond, std::function<void(row_handle)> &&visit
++ri;
}
for (auto &&[childCat, condition] : potential_orphans)
childCat->erase_orphans(std::move(condition), *this);
return result;
}
......
......@@ -76,53 +76,82 @@ namespace detail
return this;
}
condition_impl *and_condition_impl::prepare(const category &c)
bool found_in_range(condition_impl *c, std::vector<and_condition_impl *>::iterator b, std::vector<and_condition_impl *>::iterator e)
{
for (auto &sub : mSub)
sub = sub->prepare(c);
bool result = true;
for (;;)
for (auto s = b; s != e; ++s)
{
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);
auto &cs = (*s)->m_sub;
mSub.insert(mSub.end(), sub_and->mSub.begin(), sub_and->mSub.end());
sub_and->mSub.clear();
delete sub_and;
if (find_if(cs.begin(), cs.end(), [c](const condition_impl *i) { return i->equals(c); }) == cs.end())
{
result = false;
break;
}
}
return this;
return result;
}
condition_impl *or_condition_impl::prepare(const category &c)
condition_impl *and_condition_impl::combine_equal(std::vector<and_condition_impl *> &subs, or_condition_impl *oc)
{
condition_impl *result = this;
and_condition_impl *and_result = nullptr;
mA = mA->prepare(c);
mB = mB->prepare(c);
auto first = subs.front();
auto &fc = first->m_sub;
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);
for (auto c : fc)
{
if (not found_in_range(c, subs.begin() + 1, subs.end()))
continue;
if (and_result == nullptr)
and_result = new and_condition_impl();
and_result->m_sub.push_back(c);
fc.erase(remove(fc.begin(), fc.end(), c), fc.end());
for (auto sub : subs)
{
auto &ssub = sub->m_sub;
for (auto sc : ssub)
{
if (not sc->equals(c))
continue;
ssub.erase(remove(ssub.begin(), ssub.end(), sc), ssub.end());
delete sc;
break;
}
}
}
if (equals == nullptr and empty == nullptr)
if (and_result != nullptr)
{
equals = dynamic_cast<key_equals_condition_impl*>(mB);
empty = dynamic_cast<key_is_empty_condition_impl*>(mA);
and_result->m_sub.push_back(oc);
return and_result;
}
if (equals != nullptr and empty != nullptr and equals->m_item_tag == empty->m_item_tag)
return oc;
}
condition_impl *or_condition_impl::prepare(const category &c)
{
std::vector<and_condition_impl *> and_conditions;
for (auto &sub : m_sub)
{
result = new detail::key_equals_or_empty_condition_impl(equals);
result = result->prepare(c);
delete this;
sub = sub->prepare(c);
if (typeid(*sub) == typeid(and_condition_impl))
and_conditions.push_back(static_cast<and_condition_impl *>(sub));
}
return result;
if (and_conditions.size() == m_sub.size())
return and_condition_impl::combine_equal(and_conditions, this);
return this;
}
} // namespace detail
......
......@@ -125,7 +125,7 @@ void file::load_dictionary(std::string_view name)
bool file::contains(std::string_view name) const
{
return std::find_if(begin(), end(), [name](const datablock &db) { return db.name() == name; }) != end();
return std::find_if(begin(), end(), [name](const datablock &db) { return iequals(db.name(), name); }) != end();
}
datablock &file::operator[](std::string_view name)
......
......@@ -1688,7 +1688,10 @@ atom &structure::emplace_atom(atom &&atom)
R = i - 1;
}
m_atom_index.insert(m_atom_index.begin() + R + 1, m_atoms.size());
if (R == -1) // msvc...
m_atom_index.insert(m_atom_index.begin(), m_atoms.size());
else
m_atom_index.insert(m_atom_index.begin() + R + 1, m_atoms.size());
// make sure the atom_type is known
auto &atom_type = m_db["atom_type"];
......
......@@ -380,18 +380,13 @@ sac_parser::CIFToken sac_parser::get_next_token()
{
std::string s = to_lower_copy(m_token_value);
if (s == "global_")
result = CIFToken::GLOBAL;
else if (s == "stop_")
result = CIFToken::STOP;
else if (s == "loop_")
result = CIFToken::LOOP;
else if (s == "data_")
if (s == "data_")
{
state = State::DATA;
continue;
}
else if (s == "save_")
if (s == "save_")
{
state = State::SAVE;
continue;
......@@ -405,6 +400,12 @@ sac_parser::CIFToken sac_parser::get_next_token()
if (m_token_value == ".")
mTokenType = CIFValue::Inapplicable;
else if (iequals(m_token_value, "global_"))
result = CIFToken::GLOBAL;
else if (iequals(m_token_value, "stop_"))
result = CIFToken::STOP;
else if (iequals(m_token_value, "loop_"))
result = CIFToken::LOOP;
else if (m_token_value == "?")
{
mTokenType = CIFValue::Unknown;
......@@ -786,6 +787,9 @@ void sac_parser::parse_save_frame()
void parser::produce_datablock(const std::string &name)
{
if (VERBOSE >= 4)
std::cerr << "producing data_" << name << std::endl;
const auto &[iter, ignore] = m_file.emplace(name);
m_datablock = &(*iter);
}
......@@ -801,7 +805,7 @@ void parser::produce_category(const std::string &name)
void parser::produce_row()
{
if (VERBOSE >= 4)
if (VERBOSE >= 4 and m_category != nullptr)
std::cerr << "producing row for category " << m_category->name() << std::endl;
if (m_category == nullptr)
......
......@@ -6102,13 +6102,6 @@ int PDBFileParser::PDBChain::AlignResToSeqRes()
switch (tb(x, y))
{
case -1:
// if (cif::VERBOSE > 0)
// std::cerr << "A residue found in the ATOM records "
// << "(" << ry[y].mMonID << " @ " << mDbref.chainID << ":" << ry[y].mSeqNum
// << ((ry[y].mIcode == ' ' or ry[y].mIcode == 0) ? "" : std::string{ ry[y].mIcode }) << ")"
// << " was not found in the SEQRES records" << std::endl;
// --y;
throw std::runtime_error("A residue found in the ATOM records (" + ry[y].mMonID +
" @ " + std::string{ mDbref.chainID } + ":" + std::to_string(ry[y].mSeqNum) +
((ry[y].mIcode == ' ' or ry[y].mIcode == 0) ? "" : std::string{ ry[y].mIcode }) +
......@@ -6123,10 +6116,11 @@ int PDBFileParser::PDBChain::AlignResToSeqRes()
break;
case 0:
if (cif::VERBOSE > 3 and rx[x].mMonID != ry[y].mMonID)
std::cerr << "Warning, unaligned residues at " << x << "/" << y << "(" << rx[x].mMonID << '/' << ry[y].mMonID << ')' << std::endl;
else if (cif::VERBOSE > 4)
std::cerr << rx[x].mMonID << " -> " << ry[y].mMonID << " (" << ry[y].mSeqNum << ')' << std::endl;
if (rx[x].mMonID != ry[y].mMonID)
{
std::cerr << "Warning, unaligned residues at " << x << "/" << y << "(" << rx[x].mMonID << '/' << ry[y].mMonID << ") SEQRES does not agree with ATOM records" << std::endl;
rx[x].mMonID = ry[y].mMonID;
}
rx[x].mSeqNum = ry[y].mSeqNum;
rx[x].mIcode = ry[y].mIcode;
......@@ -6211,7 +6205,16 @@ file read(std::istream &is)
if (ch == 'h' or ch == 'H')
ReadPDBFile(is, result);
else
result.load(is);
{
try
{
result.load(is);
}
catch (const std::exception &ex)
{
std::throw_with_nested(std::runtime_error("Since the file did not start with a valid PDB HEADER line mmCIF was assumed, but that failed."));
}
}
}
// Must be a PDB like file, right?
......
......@@ -320,7 +320,7 @@ struct tls_selection_not : public tls_selection
for (auto &r : residues)
r.selected = not r.selected;
if (cif::VERBOSE)
if (cif::VERBOSE > 0)
{
std::cout << std::string(indentLevel * 2, ' ') << "NOT" << std::endl;
dump_selection(residues, indentLevel);
......@@ -339,7 +339,7 @@ struct tls_selection_all : public tls_selection
for (auto &r : residues)
r.selected = true;
if (cif::VERBOSE)
if (cif::VERBOSE > 0)
{
std::cout << std::string(indentLevel * 2, ' ') << "ALL" << std::endl;
dump_selection(residues, indentLevel);
......@@ -361,7 +361,7 @@ struct tls_selection_chain : public tls_selection_all
for (auto &r : residues)
r.selected = allChains or r.chainID == m_chain;
if (cif::VERBOSE)
if (cif::VERBOSE > 0)
{
std::cout << std::string(indentLevel * 2, ' ') << "CHAIN " << m_chain << std::endl;
dump_selection(residues, indentLevel);
......@@ -384,7 +384,7 @@ struct tls_selection_res_id : public tls_selection_all
for (auto &r : residues)
r.selected = r.seqNr == m_seq_nr and r.iCode == m_icode;
if (cif::VERBOSE)
if (cif::VERBOSE > 0)
{
std::cout << std::string(indentLevel * 2, ' ') << "ResID " << m_seq_nr << (m_icode ? std::string{ m_icode } : "") << std::endl;
dump_selection(residues, indentLevel);
......@@ -411,7 +411,7 @@ struct tls_selection_range_seq : public tls_selection_all
(r.seqNr <= m_last or m_last == kResidueNrWildcard));
}
if (cif::VERBOSE)
if (cif::VERBOSE > 0)
{
std::cout << std::string(indentLevel * 2, ' ') << "Range " << m_first << ':' << m_last << std::endl;
dump_selection(residues, indentLevel);
......@@ -461,7 +461,7 @@ struct tls_selection_range_id : public tls_selection_all
}
}
if (cif::VERBOSE)
if (cif::VERBOSE > 0)
{
std::cout << std::string(indentLevel * 2, ' ') << "Through " << m_first << ':' << m_last << std::endl;
dump_selection(residues, indentLevel);
......@@ -502,7 +502,7 @@ struct tls_selection_union : public tls_selection
for (auto ai = a.begin(), bi = b.begin(), ri = residues.begin(); ri != residues.end(); ++ai, ++bi, ++ri)
ri->selected = ai->selected or bi->selected;
if (cif::VERBOSE)
if (cif::VERBOSE > 0)
{
std::cout << std::string(indentLevel * 2, ' ') << "Union" << std::endl;
dump_selection(residues, indentLevel);
......@@ -543,7 +543,7 @@ struct tls_selection_intersection : public tls_selection
for (auto ai = a.begin(), bi = b.begin(), ri = residues.begin(); ri != residues.end(); ++ai, ++bi, ++ri)
ri->selected = ai->selected and bi->selected;
if (cif::VERBOSE)
if (cif::VERBOSE > 0)
{
std::cout << std::string(indentLevel * 2, ' ') << "Intersection" << std::endl;
dump_selection(residues, indentLevel);
......@@ -567,7 +567,7 @@ struct tls_selection_by_name : public tls_selection_all
for (auto &r : residues)
r.selected = r.name == m_name;
if (cif::VERBOSE)
if (cif::VERBOSE > 0)
{
std::cout << std::string(indentLevel * 2, ' ') << "Name " << m_name << std::endl;
dump_selection(residues, indentLevel);
......@@ -595,7 +595,7 @@ struct tls_selection_by_element : public tls_selection_all
for (auto &r : residues)
r.selected = iequals(r.name, m_element);
if (cif::VERBOSE)
if (cif::VERBOSE > 0)
{
std::cout << std::string(indentLevel * 2, ' ') << "Element " << m_element << std::endl;
dump_selection(residues, indentLevel);
......@@ -1404,7 +1404,7 @@ std::tuple<std::string, int> TLSSelectionParserImplBuster::ParseAtom()
match(':');
std::string atom = m_value_s;
if (cif::VERBOSE)
if (cif::VERBOSE > 0)
std::cerr << "Warning: ignoring atom ID '" << atom << "' in TLS selection" << std::endl;
match(bt_IDENT);
......@@ -1958,14 +1958,14 @@ std::unique_ptr<tls_selection> parse_tls_selection_details(const std::string &pr
if (not result)
{
if (cif::VERBOSE)
if (cif::VERBOSE > 0)
std::cerr << "Falling back to old BUSTER" << std::endl;
result = busterOld.Parse(selection);
}
if (not result)
{
if (cif::VERBOSE)
if (cif::VERBOSE > 0)
std::cerr << "Falling back to PHENIX" << std::endl;
result = phenix.Parse(selection);
}
......@@ -1976,35 +1976,35 @@ std::unique_ptr<tls_selection> parse_tls_selection_details(const std::string &pr
if (not result)
{
if (cif::VERBOSE)
if (cif::VERBOSE > 0)
std::cerr << "Falling back to BUSTER" << std::endl;
result = buster.Parse(selection);
}
if (not result)
{
if (cif::VERBOSE)
if (cif::VERBOSE > 0)
std::cerr << "Falling back to old BUSTER" << std::endl;
result = busterOld.Parse(selection);
}
}
else
{
if (cif::VERBOSE)
if (cif::VERBOSE > 0)
std::cerr << "No known program specified, trying PHENIX" << std::endl;
result = phenix.Parse(selection);
if (not result)
{
if (cif::VERBOSE)
if (cif::VERBOSE > 0)
std::cerr << "Falling back to BUSTER" << std::endl;
result = buster.Parse(selection);
}
if (not result)
{
if (cif::VERBOSE)
if (cif::VERBOSE > 0)
std::cerr << "Falling back to old BUSTER" << std::endl;
result = busterOld.Parse(selection);
}
......
......@@ -87,17 +87,17 @@ class Matrix : public MatrixExpression<Matrix>
Matrix &operator=(Matrix &&m) = default;
Matrix &operator=(const Matrix &m) = default;
uint32_t dim_m() const { return m_m; }
uint32_t dim_n() const { return m_n; }
size_t dim_m() const { return m_m; }
size_t dim_n() const { return m_n; }
double operator()(uint32_t i, uint32_t j) const
double operator()(size_t i, size_t j) const
{
assert(i < m_m);
assert(j < m_n);
return m_data[i * m_n + j];
}
double &operator()(uint32_t i, uint32_t j)
double &operator()(size_t i, size_t j)
{
assert(i < m_m);
assert(j < m_n);
......@@ -105,7 +105,7 @@ class Matrix : public MatrixExpression<Matrix>
}
private:
uint32_t m_m = 0, m_n = 0;
size_t m_m = 0, m_n = 0;
std::vector<double> m_data;
};
......@@ -522,15 +522,17 @@ quaternion align_points(const std::vector<point> &pa, const std::vector<point> &
point nudge(point p, float offset)
{
static const float kPI_f = static_cast<float>(kPI);
static std::random_device rd;
static std::mt19937_64 rng(rd());
std::uniform_real_distribution<float> randomAngle(0, 2 * kPI);
std::normal_distribution<> randomOffset(0, offset);
std::uniform_real_distribution<float> randomAngle(0, 2 * kPI_f);
std::normal_distribution<float> randomOffset(0, offset);
float theta = randomAngle(rng);
float phi1 = randomAngle(rng) - kPI;
float phi2 = randomAngle(rng) - kPI;
float phi1 = randomAngle(rng) - kPI_f;
float phi2 = randomAngle(rng) - kPI_f;
quaternion q = spherical(1.0f, theta, phi1, phi2);
......
......@@ -124,7 +124,8 @@ std::string get_executable_path()
{
using namespace std::literals;
char path[PATH_MAX] = "";
// This used to be PATH_MAX, but lets simply assume 1024 is enough...
char path[1024] = "";
if (readlink("/proc/self/exe", path, sizeof(path)) == -1)
throw std::runtime_error("could not get exe path "s + strerror(errno));
return {path};
......
......@@ -58,6 +58,12 @@ bool init_unit_test()
// not a test, just initialize test dir
if (boost::unit_test::framework::master_test_suite().argc == 2)
gTestDir = boost::unit_test::framework::master_test_suite().argv[1];
else
{
while (not gTestDir.empty() and not std::filesystem::exists(gTestDir / "test"))
gTestDir = gTestDir.parent_path();
gTestDir /= "test";
}
// do this now, avoids the need for installing
cif::add_file_resource("mmcif_pdbx.dic", gTestDir / ".." / "rsrc" / "mmcif_pdbx.dic");
......
......@@ -39,6 +39,12 @@ int main(int argc, char* argv[])
if (argc == 3)
testdir = argv[2];
else
{
while (not testdir.empty() and not std::filesystem::exists(testdir / "test"))
testdir = testdir.parent_path();
testdir /= "test";
}
if (std::filesystem::exists(testdir / ".." / "data" / "ccd-subset.cif"))
cif::add_file_resource("components.cif", testdir / ".." / "data" / "ccd-subset.cif");
......
......@@ -2322,14 +2322,16 @@ _test.text ??
BOOST_AUTO_TEST_CASE(output_test_1)
{
cif::VERBOSE = 5;
auto data1 = R"(
data_Q
loop_
_test.text
"stop_the_crap"
stop_the_crap
'and stop_ this too'
'data_dinges'
'blablaglobal_bla'
blablaglobal_bla
boo.data_.whatever
'data_.whatever'
'stop_'
......@@ -2346,7 +2348,7 @@ boo.data_.whatever
const char *s;
bool q;
} kS[] = {
{ "stop_the_crap", false },
{ "stop_the_crap", true },
{ "and stop_ this too", false },
{ "data_dinges", false },
{ "blablaglobal_bla", true },
......
#!/bin/bash
#!/bin/sh
set -e
......@@ -7,8 +7,8 @@ if [ "$EUID" -ne 0 ]
exit
fi
if [ -f /etc/libcifpp.conf ] ; then
. /etc/libcifpp.conf
if [ -f "@CIFPP_ETC_DIR@/libcifpp.conf" ] ; then
. "@CIFPP_ETC_DIR@/libcifpp.conf"
fi
# check to see if we're supposed to run at all
......@@ -17,7 +17,7 @@ if [ "$update" != "true" ] ; then
fi
# if cache directory doesn't exist, exit.
if ! [ -d @CIFPP_CACHE_DIR@ ]; then
if ! [ -d "@CIFPP_CACHE_DIR@" ]; then
exit
fi
......@@ -46,10 +46,10 @@ fetch_dictionary () {
fetch_dictionary "@CIFPP_CACHE_DIR@/mmcif_pdbx.dic" "https://mmcif.wwpdb.org/dictionaries/ascii/mmcif_pdbx_v50.dic.gz"
fetch_dictionary "@CIFPP_CACHE_DIR@/components.cif" "ftp://ftp.wwpdb.org/pub/pdb/data/monomers/components.cif.gz"
# notify subscribers
wget -O"@CIFPP_CACHE_DIR@/mmcif_ma.dic" "https://github.com/ihmwg/ModelCIF/raw/master/dist/mmcif_ma.dic"
if [ -d /etc/libcifpp/cache-update.d ] && [ -x /bin/run-parts ]; then
run-parts --arg "@CIFPP_CACHE_DIR@" -- /etc/libcifpp/cache-update.d
fi
# notify subscribers, will fail on FreeBSD
wget -O/var/cache/libcifpp/mmcif_ma.dic "https://github.com/ihmwg/ModelCIF/raw/master/dist/mmcif_ma.dic"
if [ -d "@CIFPP_ETC_DIR@/libcifpp/cache-update.d" ] && [ -x /bin/run-parts ]; then
run-parts --arg "@CIFPP_CACHE_DIR@" -- "@CIFPP_ETC_DIR@/libcifpp/cache-update.d"
fi
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