Commit 50bf2145 by Maarten L. Hekkelman

Merge branch 'develop' into trunk

parents 93375a50 dc77729f
......@@ -27,7 +27,7 @@ cmake_minimum_required(VERSION 3.16)
# set the project name
project(
libcifpp
VERSION 7.0.0
VERSION 7.0.1
LANGUAGES CXX)
list(PREPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
......@@ -304,34 +304,45 @@ set(project_sources
)
set(project_headers
${PROJECT_SOURCE_DIR}/include/cif++.hpp
${PROJECT_SOURCE_DIR}/include/cif++/utilities.hpp
${PROJECT_SOURCE_DIR}/include/cif++/item.hpp
${PROJECT_SOURCE_DIR}/include/cif++/datablock.hpp
${PROJECT_SOURCE_DIR}/include/cif++/file.hpp
${PROJECT_SOURCE_DIR}/include/cif++/validate.hpp
${PROJECT_SOURCE_DIR}/include/cif++/iterator.hpp
${PROJECT_SOURCE_DIR}/include/cif++/parser.hpp
${PROJECT_SOURCE_DIR}/include/cif++/forward_decl.hpp
${PROJECT_SOURCE_DIR}/include/cif++/dictionary_parser.hpp
${PROJECT_SOURCE_DIR}/include/cif++/condition.hpp
${PROJECT_SOURCE_DIR}/include/cif++/category.hpp
${PROJECT_SOURCE_DIR}/include/cif++/row.hpp
${PROJECT_SOURCE_DIR}/include/cif++/atom_type.hpp
${PROJECT_SOURCE_DIR}/include/cif++/compound.hpp
${PROJECT_SOURCE_DIR}/include/cif++/point.hpp
${PROJECT_SOURCE_DIR}/include/cif++/symmetry.hpp
${PROJECT_SOURCE_DIR}/include/cif++/model.hpp
${PROJECT_SOURCE_DIR}/include/cif++/pdb.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/tls.hpp)
add_library(cifpp ${project_sources} ${project_headers}
${PROJECT_SOURCE_DIR}/src/symop_table_data.hpp)
include/cif++.hpp
include/cif++/utilities.hpp
include/cif++/item.hpp
include/cif++/datablock.hpp
include/cif++/file.hpp
include/cif++/validate.hpp
include/cif++/iterator.hpp
include/cif++/parser.hpp
include/cif++/forward_decl.hpp
include/cif++/dictionary_parser.hpp
include/cif++/condition.hpp
include/cif++/category.hpp
include/cif++/row.hpp
include/cif++/atom_type.hpp
include/cif++/compound.hpp
include/cif++/point.hpp
include/cif++/symmetry.hpp
include/cif++/model.hpp
include/cif++/pdb.hpp
include/cif++/pdb/cif2pdb.hpp
include/cif++/pdb/io.hpp
include/cif++/pdb/pdb2cif.hpp
include/cif++/pdb/tls.hpp)
add_library(cifpp STATIC)
add_library(cifpp::cifpp ALIAS cifpp)
target_sources(cifpp
PRIVATE ${project_sources}
${PROJECT_SOURCE_DIR}/src/symop_table_data.hpp
PUBLIC
FILE_SET cifpp_headers TYPE HEADERS
BASE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/include
FILES ${project_headers}
)
# The code now really requires C++20
target_compile_features(cifpp PUBLIC cxx_std_20)
set(CMAKE_DEBUG_POSTFIX d)
set_target_properties(cifpp PROPERTIES DEBUG_POSTFIX "d")
......@@ -452,14 +463,9 @@ else()
endif()
# Install rules
install(
TARGETS cifpp
EXPORT cifpp-targets
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
INCLUDES
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
install(TARGETS cifpp
EXPORT cifpp
FILE_SET cifpp_headers DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
if(MSVC AND BUILD_SHARED_LIBS)
install(
......@@ -479,23 +485,12 @@ if(OLD_CONFIG_FILES)
install(CODE "file(REMOVE ${OLD_CONFIG_FILES})")
endif()
install(
EXPORT cifpp-targets
FILE "cifpp-targets.cmake"
install(EXPORT cifpp
NAMESPACE cifpp::
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/cifpp)
install(
DIRECTORY include/cif++
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
COMPONENT Devel)
install(
FILES include/cif++.hpp
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
COMPONENT Devel)
FILE "cifpp-targets.cmake"
DESTINATION lib/cmake/cifpp)
if(CIFPP_DATA_DIR)
if(CIFPP_DATA_DIR AND CIFPP_DOWNLOAD_CCD)
install(
FILES ${PROJECT_SOURCE_DIR}/rsrc/mmcif_ddl.dic
${PROJECT_SOURCE_DIR}/rsrc/mmcif_pdbx.dic
......@@ -503,7 +498,7 @@ if(CIFPP_DATA_DIR)
DESTINATION ${CIFPP_DATA_DIR})
endif()
if(CIFPP_CACHE_DIR)
if(CIFPP_CACHE_DIR AND CIFPP_DOWNLOAD_CCD)
install(
FILES ${PROJECT_SOURCE_DIR}/rsrc/mmcif_ddl.dic
${PROJECT_SOURCE_DIR}/rsrc/mmcif_pdbx.dic
......@@ -515,14 +510,13 @@ set(CONFIG_TEMPLATE_FILE ${PROJECT_SOURCE_DIR}/cmake/cifpp-config.cmake.in)
configure_package_config_file(
${CONFIG_TEMPLATE_FILE} ${CMAKE_CURRENT_BINARY_DIR}/cifpp/cifpp-config.cmake
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/cifpp
INSTALL_DESTINATION lib/cmake/cifpp
PATH_VARS CIFPP_DATA_DIR)
install(
FILES "${CMAKE_CURRENT_BINARY_DIR}/cifpp/cifpp-config.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/cifpp/cifpp-config-version.cmake"
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/cifpp
COMPONENT Devel)
DESTINATION lib/cmake/cifpp)
set_target_properties(
cifpp
......
Version 7.0.1
- Various reconstruction fixes
- category order in output fixed
- better implementation of constructors for file, datablock and category
- small optimisation in iterator
Version 7.0.0
- Renaming many methods and parameters to be more
consistent with the mmCIF dictionaries.
......
......@@ -141,31 +141,39 @@ class category
/// \endcond
category() = default; ///< Default constructor
category(std::string_view name); ///< Constructor taking a \a name
category(const category &rhs); ///< Copy constructor
category(category &&rhs); ///< Move constructor
category &operator=(const category &rhs); ///< Copy assignement operator
category &operator=(category &&rhs); ///< Move assignement operator
category() = default; ///< Default constructor
category(std::string_view name); ///< Constructor taking a \a name
category(const category &rhs); ///< Copy constructor
category(category &&rhs) noexcept ///< Move constructor
{
swap(*this, rhs);
}
category &operator=(category rhs) ///< assignement operator
{
swap(*this, rhs);
return *this;
}
/// @brief Destructor
/// @note Please note that the destructor is not virtual. It is assumed that
/// you will not derive from this class.
~category();
friend void swap(category &a, category &b) noexcept;
// --------------------------------------------------------------------
const std::string &name() const { return m_name; } ///< Returns the name of the category
[[deprecated("use key_items instead")]]
iset key_fields() const; ///< Returns the cif::iset of key item names. Retrieved from the @ref category_validator for this category
[[deprecated("use key_items instead")]] iset key_fields() const; ///< Returns the cif::iset of key item names. Retrieved from the @ref category_validator for this category
iset key_items() const; ///< Returns the cif::iset of key item names. Retrieved from the @ref category_validator for this category
iset key_items() const; ///< Returns the cif::iset of key item names. Retrieved from the @ref category_validator for this category
[[deprecated("use key_item_indices instead")]]
std::set<uint16_t> key_field_indices() const; ///< Returns a set of indices for the key items.
[[deprecated("use key_item_indices instead")]] std::set<uint16_t> key_field_indices() const; ///< Returns a set of indices for the key items.
std::set<uint16_t> key_item_indices() const; ///< Returns a set of indices for the key items.
std::set<uint16_t> key_item_indices() const; ///< Returns a set of indices for the key items.
/// @brief Set the validator for this category to @a v
/// @param v The category_validator to assign. A nullptr value is allowed.
......@@ -1010,7 +1018,8 @@ class category
void update_value(const std::vector<row_handle> &rows, std::string_view item_name, std::string_view value)
{
update_value(rows, item_name, [value](std::string_view) { return value; });
update_value(rows, item_name, [value](std::string_view)
{ return value; });
}
// --------------------------------------------------------------------
......@@ -1018,8 +1027,7 @@ class category
// the old function names are here as deprecated variants.
/// \brief Return the index number for \a column_name
[[deprecated("Use get_item_ix instead")]]
uint16_t get_column_ix(std::string_view column_name) const
[[deprecated("Use get_item_ix instead")]] uint16_t get_column_ix(std::string_view column_name) const
{
return get_item_ix(column_name);
}
......@@ -1027,8 +1035,7 @@ class category
/// @brief Return the name for column with index @a ix
/// @param ix The index number
/// @return The name of the column
[[deprecated("use get_item_name instead")]]
std::string_view get_column_name(uint16_t ix) const
[[deprecated("use get_item_name instead")]] std::string_view get_column_name(uint16_t ix) const
{
return get_item_name(ix);
}
......@@ -1036,8 +1043,7 @@ class category
/// @brief Make sure a item with name @a item_name is known and return its index number
/// @param item_name The name of the item
/// @return The index number of the item
[[deprecated("use add_item instead")]]
uint16_t add_column(std::string_view item_name)
[[deprecated("use add_item instead")]] uint16_t add_column(std::string_view item_name)
{
return add_item(item_name);
}
......@@ -1045,15 +1051,13 @@ class category
/** @brief Remove column name @a colum_name
* @param column_name The column to be removed
*/
[[deprecated("use remove_item instead")]]
void remove_column(std::string_view column_name)
[[deprecated("use remove_item instead")]] void remove_column(std::string_view column_name)
{
remove_item(column_name);
}
/** @brief Rename column @a from_name to @a to_name */
[[deprecated("use rename_item instead")]]
void rename_column(std::string_view from_name, std::string_view to_name)
[[deprecated("use rename_item instead")]] void rename_column(std::string_view from_name, std::string_view to_name)
{
rename_item(from_name, to_name);
}
......@@ -1061,15 +1065,13 @@ class category
/// @brief Return whether a column with name @a name exists in this category
/// @param name The name of the column
/// @return True if the column exists
[[deprecated("use has_item instead")]]
bool has_column(std::string_view name) const
[[deprecated("use has_item instead")]] bool has_column(std::string_view name) const
{
return has_item(name);
}
/// @brief Return the cif::iset of columns in this category
[[deprecated("use get_items instead")]]
iset get_columns() const
[[deprecated("use get_items instead")]] iset get_columns() const
{
return get_items();
}
......@@ -1125,7 +1127,7 @@ class category
{
item_validator = m_cat_validator->get_validator_for_item(item_name);
if (item_validator == nullptr)
m_validator->report_error( validation_error::item_not_allowed_in_category, m_name, item_name, false);
m_validator->report_error(validation_error::item_not_allowed_in_category, m_name, item_name, false);
}
m_items.emplace_back(item_name, item_validator);
......@@ -1169,8 +1171,7 @@ class category
/// This function returns effectively the list of fully qualified item
/// names, that is category_name + '.' + item_name for each item
[[deprecated("use get_item_order instead")]]
std::vector<std::string> get_tag_order() const
[[deprecated("use get_item_order instead")]] std::vector<std::string> get_tag_order() const
{
return get_item_order();
}
......
......@@ -61,12 +61,26 @@ class datablock : public std::list<category>
/** @cond */
datablock(const datablock &);
datablock(datablock &&) = default;
datablock &operator=(const datablock &);
datablock &operator=(datablock &&) = default;
datablock(datablock &&db) noexcept
{
swap_(*this, db);
}
datablock &operator=(datablock db)
{
swap_(*this, db);
return *this;
}
/** @endcond */
friend void swap_(datablock &a, datablock &b) noexcept
{
std::swap(a.m_name, b.m_name);
std::swap(a.m_validator, b.m_validator);
std::swap(static_cast<std::list<category>&>(a), static_cast<std::list<category>&>(b));
}
// --------------------------------------------------------------------
/**
......
......@@ -100,10 +100,22 @@ class file : public std::list<datablock>
}
/** @cond */
file(const file &) = default;
file(file &&) = default;
file &operator=(const file &) = default;
file &operator=(file &&) = default;
file(const file &rhs)
: std::list<datablock>(rhs)
{
}
file(file &&rhs)
{
this->swap(rhs);
}
file &operator=(file f)
{
this->swap(f);
return *this;
}
/** @endcond */
/**
......
......@@ -288,19 +288,16 @@ struct item_value
}
/** @cond */
item_value(item_value &&rhs)
item_value(item_value &&rhs) noexcept
: m_length(std::exchange(rhs.m_length, 0))
, m_storage(std::exchange(rhs.m_storage, 0))
{
}
item_value &operator=(item_value &&rhs)
item_value &operator=(item_value &&rhs) noexcept
{
if (this != &rhs)
{
m_length = std::exchange(rhs.m_length, m_length);
m_storage = std::exchange(rhs.m_storage, m_storage);
}
std::swap(m_length, rhs.m_length);
std::swap(m_storage, rhs.m_storage);
return *this;
}
......
......@@ -49,7 +49,7 @@ namespace cif
/**
* @brief Implementation of an iterator that can return
* multiple values in a tuple. Of course, that tuple can
* then used in structured binding to receive the values
* then be used in structured binding to receive the values
* in a for loop e.g.
*
* @tparam Category The category for this iterator
......@@ -84,11 +84,11 @@ class iterator_impl
iterator_impl() = default;
iterator_impl(const iterator_impl &rhs) = default;
iterator_impl(iterator_impl &&rhs) = default;
template <typename C2, typename... T2s>
iterator_impl(const iterator_impl<C2, T2s...> &rhs)
: m_category(rhs.m_category)
, m_current(rhs.m_current)
: m_current(const_cast<row_handle&>(rhs.m_current))
, m_value(rhs.m_value)
, m_item_ix(rhs.m_item_ix)
{
......@@ -96,8 +96,7 @@ class iterator_impl
template <typename IRowType>
iterator_impl(iterator_impl<IRowType, Ts...> &rhs)
: m_category(rhs.m_category)
, m_current(const_cast<row_type *>(rhs.m_current))
: m_current(const_cast<row_handle&>(rhs.m_current))
, m_value(rhs.m_value)
, m_item_ix(rhs.m_item_ix)
{
......@@ -106,19 +105,17 @@ class iterator_impl
template <typename IRowType>
iterator_impl(const iterator_impl<IRowType> &rhs, const std::array<uint16_t, N> &cix)
: m_category(rhs.m_category)
, m_current(rhs.m_current)
: m_current(const_cast<row_handle&>(rhs.m_current))
, m_item_ix(cix)
{
m_value = get(std::make_index_sequence<N>());
}
iterator_impl &operator=(const iterator_impl &i)
iterator_impl &operator=(iterator_impl i)
{
m_category = i.m_category;
m_current = i.m_current;
m_item_ix = i.m_item_ix;
m_value = i.m_value;
std::swap(m_current, i.m_current);
std::swap(m_item_ix, i.m_item_ix);
std::swap(m_value, i.m_value);
return *this;
}
......@@ -136,18 +133,18 @@ class iterator_impl
operator const row_handle() const
{
return { *m_category, *m_current };
return m_current;
}
operator row_handle()
{
return { *m_category, *m_current };
return m_current;
}
iterator_impl &operator++()
{
if (m_current != nullptr)
m_current = m_current->m_next;
if (m_current)
m_current.m_row = m_current.m_row->m_next;
m_value = get(std::make_index_sequence<N>());
......@@ -182,17 +179,10 @@ class iterator_impl
template <size_t... Is>
tuple_type get(std::index_sequence<Is...>) const
{
if (m_current != nullptr)
{
row_handle rh{ *m_category, *m_current };
return tuple_type{ rh[m_item_ix[Is]].template as<Ts>()... };
}
return {};
return m_current ? tuple_type{ m_current[m_item_ix[Is]].template as<Ts>()... } : tuple_type{};
}
category_type *m_category = nullptr;
row_type *m_current = nullptr;
row_handle m_current;
value_type m_value;
std::array<uint16_t, N> m_item_ix;
};
......@@ -219,37 +209,34 @@ class iterator_impl<Category>
using iterator_category = std::forward_iterator_tag;
using value_type = row_handle;
using difference_type = std::ptrdiff_t;
using pointer = row_handle;
using reference = row_handle;
using pointer = value_type *;
using reference = value_type &;
iterator_impl() = default;
iterator_impl(const iterator_impl &rhs) = default;
iterator_impl(iterator_impl &&rhs) = default;
template <typename C2>
iterator_impl(const iterator_impl<C2> &rhs)
: m_category(rhs.m_category)
, m_current(const_cast<row_type *>(rhs.m_current))
: m_current(const_cast<row_handle &>(rhs.m_current))
{
}
iterator_impl(Category &cat, row *current)
: m_category(const_cast<category_type *>(&cat))
, m_current(current)
: m_current(cat, *current)
{
}
template <typename IRowType>
iterator_impl(const iterator_impl<IRowType> &rhs, const std::array<uint16_t, 0> &)
: m_category(rhs.m_category)
, m_current(rhs.m_current)
: m_current(const_cast<row_handle &>(rhs.m_current))
{
}
iterator_impl &operator=(const iterator_impl &i)
iterator_impl &operator=(iterator_impl i)
{
m_category = i.m_category;
m_current = i.m_current;
std::swap(m_current, i.m_current);
return *this;
}
......@@ -257,7 +244,7 @@ class iterator_impl<Category>
reference operator*()
{
return { *m_category, *m_current };
return m_current;
}
pointer operator->()
......@@ -267,18 +254,18 @@ class iterator_impl<Category>
operator const row_handle() const
{
return { *m_category, *m_current };
return m_current;
}
operator row_handle()
{
return { *m_category, *m_current };
return m_current;
}
iterator_impl &operator++()
{
if (m_current != nullptr)
m_current = m_current->m_next;
if (m_current)
m_current.m_row = m_current.m_row->m_next;
return *this;
}
......@@ -308,8 +295,7 @@ class iterator_impl<Category>
/** @endcond */
private:
category_type *m_category = nullptr;
row_type *m_current = nullptr;
row_handle m_current;
};
/**
......@@ -342,11 +328,11 @@ class iterator_impl<Category, T>
iterator_impl() = default;
iterator_impl(const iterator_impl &rhs) = default;
iterator_impl(iterator_impl &&rhs) = default;
template <typename C2, typename T2>
iterator_impl(const iterator_impl<C2, T2> &rhs)
: m_category(rhs.m_category)
, m_current(rhs.m_current)
: m_current(rhs.m_current)
, m_value(rhs.m_value)
, m_item_ix(rhs.m_item_ix)
{
......@@ -354,29 +340,26 @@ class iterator_impl<Category, T>
template <typename IRowType>
iterator_impl(iterator_impl<IRowType, T> &rhs)
: m_category(rhs.m_category)
, m_current(const_cast<row_type *>(rhs.m_current))
: m_current(const_cast<row_handle&>(rhs.m_current))
, m_value(rhs.m_value)
, m_item_ix(rhs.m_item_ix)
{
m_value = get(m_current);
m_value = get();
}
template <typename IRowType>
iterator_impl(const iterator_impl<IRowType> &rhs, const std::array<uint16_t, 1> &cix)
: m_category(rhs.m_category)
, m_current(rhs.m_current)
: m_current(const_cast<row_handle&>(rhs.m_current))
, m_item_ix(cix[0])
{
m_value = get();
}
iterator_impl &operator=(const iterator_impl &i)
iterator_impl &operator=(iterator_impl i)
{
m_category = i.m_category;
m_current = i.m_current;
m_item_ix = i.m_item_ix;
m_value = i.m_value;
std::swap(m_current, i.m_current);
std::swap(m_item_ix, i.m_item_ix);
std::swap(m_value, i.m_value);
return *this;
}
......@@ -394,18 +377,18 @@ class iterator_impl<Category, T>
operator const row_handle() const
{
return { *m_category, *m_current };
return m_current;
}
operator row_handle()
{
return { *m_category, *m_current };
return m_current;
}
iterator_impl &operator++()
{
if (m_current != nullptr)
m_current = m_current->m_next;
if (m_current)
m_current.m_row = m_current.m_row->m_next;
m_value = get();
......@@ -439,17 +422,10 @@ class iterator_impl<Category, T>
private:
value_type get() const
{
if (m_current != nullptr)
{
row_handle rh{ *m_category, *m_current };
return rh[m_item_ix].template as<T>();
}
return {};
return m_current ? m_current[m_item_ix].template as<value_type>() : value_type{};
}
category_type *m_category = nullptr;
row_type *m_current = nullptr;
row_handle m_current;
value_type m_value;
uint16_t m_item_ix;
};
......
......@@ -208,6 +208,7 @@ class row_handle
friend class category;
friend class category_index;
friend class row_initializer;
template <typename, typename...> friend class iterator_impl;
row_handle() = default;
......
......@@ -113,16 +113,12 @@ namespace colour
/**
* @brief Struct for delimited strings.
*/
template <typename StringType>
struct coloured_string_t
{
static_assert(std::is_reference_v<StringType> or std::is_pointer_v<StringType>,
"String type must be pointer or reference");
/**
* @brief Construct a new coloured string t object
*/
coloured_string_t(StringType s, colour_type fc, colour_type bc, style_type st)
coloured_string_t(std::string_view s, colour_type fc, colour_type bc, style_type st)
: m_str(s)
, m_fore_colour(static_cast<int>(fc) + 30)
, m_back_colour(static_cast<int>(bc) + 40)
......@@ -152,12 +148,14 @@ namespace colour
<< cs.m_str
<< "\033[0m";
}
else
os << cs.m_str;
return os;
}
/// @cond
StringType m_str;
std::string_view m_str;
int m_fore_colour, m_back_colour;
int m_style;
/// @endcond
......@@ -191,39 +189,13 @@ namespace colour
* @param st Text style to use
*/
template <typename char_type>
inline auto coloured(const char_type *str,
colour::colour_type fg, colour::colour_type bg = colour::colour_type::none,
colour::style_type st = colour::style_type::regular)
{
return colour::detail::coloured_string_t<const char_type *>(str, fg, bg, st);
}
/// @brief Manipulator for coloured strings.
template <typename char_type, typename traits_type, typename allocator_type>
inline auto coloured(const std::basic_string<char_type, traits_type, allocator_type> &str,
colour::colour_type fg, colour::colour_type bg = colour::colour_type::none,
colour::style_type st = colour::style_type::regular)
{
return colour::detail::coloured_string_t<const std::basic_string<char_type, traits_type, allocator_type> &>(str, fg, bg, st);
}
/// @brief Manipulator for coloured strings.
template <typename char_type, typename traits_type, typename allocator_type>
inline auto coloured(std::basic_string<char_type, traits_type, allocator_type> &str,
colour::colour_type fg, colour::colour_type bg = colour::colour_type::none,
colour::style_type st = colour::style_type::regular)
{
return colour::detail::coloured_string_t<std::basic_string<char_type, traits_type, allocator_type> &>(str, fg, bg, st);
}
/// @brief Manipulator for coloured strings.
template <typename char_type, typename traits_type>
inline auto coloured(std::basic_string_view<char_type, traits_type> &str,
template <typename T>
requires std::is_assignable_v<std::string_view, T>
inline auto coloured(T str,
colour::colour_type fg, colour::colour_type bg = colour::colour_type::none,
colour::style_type st = colour::style_type::regular)
{
return colour::detail::coloured_string_t<std::basic_string_view<char_type, traits_type> &>(str, fg, bg, st);
return colour::detail::coloured_string_t(str, fg, bg, st);
}
// --------------------------------------------------------------------
......
......@@ -120,7 +120,7 @@ class validation_category_impl : public std::error_category
case validation_error::missing_key_items:
return "An index could not be constructed due to missing key items";
case validation_error::item_not_allowed_in_category:
return "Requested item allowed in category according to dictionary";
return "Requested item not allowed in category according to dictionary";
case validation_error::empty_file:
return "The file contains no datablocks";
case validation_error::empty_datablock:
......
......@@ -521,71 +521,18 @@ category::category(const category &rhs)
m_index = new category_index(*this);
}
category::category(category &&rhs)
: m_name(std::move(rhs.m_name))
, m_items(std::move(rhs.m_items))
, m_validator(rhs.m_validator)
, m_cat_validator(rhs.m_cat_validator)
, m_parent_links(std::move(rhs.m_parent_links))
, m_child_links(std::move(rhs.m_child_links))
, m_cascade(rhs.m_cascade)
, m_index(rhs.m_index)
, m_head(rhs.m_head)
, m_tail(rhs.m_tail)
{
rhs.m_head = nullptr;
rhs.m_tail = nullptr;
rhs.m_index = nullptr;
}
category &category::operator=(const category &rhs)
{
if (this != &rhs)
{
if (not empty())
clear();
m_name = rhs.m_name;
m_items = rhs.m_items;
m_cascade = rhs.m_cascade;
m_validator = nullptr;
m_cat_validator = nullptr;
delete m_index;
m_index = nullptr;
for (auto r = rhs.m_head; r != nullptr; r = r->m_next)
insert_impl(cend(), clone_row(*r));
m_validator = rhs.m_validator;
m_cat_validator = rhs.m_cat_validator;
if (m_cat_validator != nullptr and m_index == nullptr)
m_index = new category_index(*this);
}
return *this;
}
category &category::operator=(category &&rhs)
void swap(category &a, category &b) noexcept
{
if (this != &rhs)
{
m_name = std::move(rhs.m_name);
m_items = std::move(rhs.m_items);
m_cascade = rhs.m_cascade;
m_validator = rhs.m_validator;
m_cat_validator = rhs.m_cat_validator;
m_parent_links = rhs.m_parent_links;
m_child_links = rhs.m_child_links;
std::swap(m_index, rhs.m_index);
std::swap(m_head, rhs.m_head);
std::swap(m_tail, rhs.m_tail);
}
return *this;
std::swap(a.m_name, b.m_name);
std::swap(a.m_items, b.m_items);
std::swap(a.m_validator, b.m_validator);
std::swap(a.m_cat_validator, b.m_cat_validator);
std::swap(a.m_parent_links, b.m_parent_links);
std::swap(a.m_child_links, b.m_child_links);
std::swap(a.m_cascade, b.m_cascade);
std::swap(a.m_index, b.m_index);
std::swap(a.m_head, b.m_head);
std::swap(a.m_tail, b.m_tail);
}
category::~category()
......@@ -1712,7 +1659,7 @@ category::iterator category::insert_impl(const_iterator pos, row *n)
m_index->insert(*this, n);
// insert at end, most often this is the case
if (pos.m_current == nullptr)
if (pos.m_current.m_row == nullptr)
{
if (m_head == nullptr)
m_tail = m_head = n;
......@@ -1723,7 +1670,7 @@ category::iterator category::insert_impl(const_iterator pos, row *n)
{
assert(m_head != nullptr);
if (pos.m_current == m_head)
if (pos.m_current.m_row == m_head)
m_head = n->m_next = m_head;
else
n = n->m_next = m_head->m_next;
......
......@@ -550,7 +550,7 @@ class local_compound_factory_impl : public compound_factory_impl
compound *create(const std::string &id) override;
private:
const cif::file &m_local_file;
cif::file m_local_file;
};
compound *local_compound_factory_impl::create(const std::string &id)
......@@ -559,11 +559,19 @@ compound *local_compound_factory_impl::create(const std::string &id)
for (auto &db : m_local_file)
{
if (db.name() == "comp_" + id)
if (db.name() == id)
{
cif::datablock db_copy(db);
result = new compound(db_copy, 1);
try
{
result = new compound(db_copy, 1);
}
catch (const std::exception &ex)
{
std::throw_with_nested(std::runtime_error("Error loading compound " + id));
}
std::shared_lock lock(mMutex);
m_compounds.push_back(result);
......
......@@ -38,21 +38,6 @@ datablock::datablock(const datablock &db)
cat.update_links(*this);
}
datablock &datablock::operator=(const datablock &db)
{
if (this != &db)
{
std::list<category>::operator=(db);
m_name = db.m_name;
m_validator = db.m_validator;
for (auto &cat : *this)
cat.update_links(*this);
}
return *this;
}
void datablock::set_validator(const validator *v)
{
m_validator = v;
......@@ -282,7 +267,11 @@ void datablock::write(std::ostream &os) const
cat_order_t cat_order;
for (auto &cat : *this)
{
if (cat.name() == "entry" or cat.name() == "audit_conform")
continue;
cat_order.emplace_back(cat.name(), -1, false);
}
for (auto i = cat_order.begin(); i != cat_order.end(); ++i)
calculate_cat_order(cat_order, i, *m_validator);
......@@ -292,25 +281,18 @@ void datablock::write(std::ostream &os) const
const auto &[cat_a, count_a, on_stack_a] = a;
const auto &[cat_b, count_b, on_stack_b] = b;
int d = 0;
if (cat_a == "audit_conform")
d = -1;
else if (cat_b == "audit_conform")
d = 1;
else if (cat_a == "entry")
d = -1;
else if (cat_b == "entry")
d = 1;
else
{
d = std::get<1>(a) - std::get<1>(b);
if (d == 0)
d = cat_b.compare(cat_a);
}
int d = std::get<1>(a) - std::get<1>(b);
if (d == 0)
d = cat_b.compare(cat_a);
return d < 0; });
if (auto entry = get("entry"); entry != nullptr)
entry->write(os);
if (auto audit_conform = get("audit_conform"); audit_conform != nullptr)
audit_conform->write(os);
for (auto &&[cat, count, on_stack] : cat_order)
get(cat)->write(os);
}
......@@ -320,20 +302,13 @@ void datablock::write(std::ostream &os) const
// and if it exists, _AND_ we have a Validator, write out the
// audit_conform record.
for (auto &cat : *this)
{
if (cat.name() != "entry")
continue;
cat.write(os);
break;
}
if (auto entry = get("entry"); entry != nullptr)
entry->write(os);
// If the dictionary declares an audit_conform category, put it in,
// but only if it does not exist already!
if (get("audit_conform"))
get("audit_conform")->write(os);
if (auto audit_conform = get("audit_conform"); audit_conform != nullptr)
audit_conform->write(os);
for (auto &cat : *this)
{
......@@ -348,7 +323,7 @@ void datablock::write(std::ostream &os, const std::vector<std::string> &item_nam
os << "data_" << m_name << '\n'
<< "# \n";
std::vector<std::string> cat_order;
std::vector<std::string> cat_order{ "entry", "audit_conform" };
for (auto &o : item_name_order)
{
std::string cat_name, item_name;
......
......@@ -4669,47 +4669,6 @@ void PDBFileParser::ConstructEntities()
}
}
}
// Finish by calculating the formula_weight for each entity
for (auto entity : *getCategory("entity"))
{
auto entity_id = entity["id"].as<std::string>();
float formula_weight = 0;
if (entity["type"] == "polymer")
{
int n = 0;
for (std::string comp_id : getCategory("pdbx_poly_seq_scheme")->find<std::string>(cif::key("entity_id") == entity_id, "mon_id"))
{
auto compound = cif::compound_factory::instance().create(comp_id);
assert(compound);
if (not compound)
throw std::runtime_error("missing information for compound " + comp_id);
formula_weight += compound->formula_weight();
++n;
}
formula_weight -= (n - 1) * 18.015;
}
else if (entity["type"] == "water")
formula_weight = 18.015;
else
{
auto comp_id = getCategory("pdbx_nonpoly_scheme")->find_first<std::optional<std::string>>(cif::key("entity_id") == entity_id, "mon_id");
if (comp_id.has_value())
{
auto compound = cif::compound_factory::instance().create(*comp_id);
assert(compound);
if (not compound)
throw std::runtime_error("missing information for compound " + *comp_id);
formula_weight = compound->formula_weight();
}
}
if (formula_weight > 0)
entity.assign({ { "formula_weight", formula_weight, 3 } });
}
}
void PDBFileParser::ConstructSugarTrees(int &asymNr)
......@@ -6454,11 +6413,11 @@ file read(std::istream &is)
{
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."));
}
// Since we're using the cif::pdb way of reading the file, the data may need
// reconstruction
reconstruct_pdbx(result);
}
// Since we're using the cif::pdb way of reading the file, the data may need
// reconstruction
reconstruct_pdbx(result);
}
// Must be a PDB like file, right?
......
......@@ -92,6 +92,70 @@ condition get_condition(residue_key_type &k)
// --------------------------------------------------------------------
void checkEntities(datablock &db)
{
using namespace cif::literals;
auto &cf = cif::compound_factory::instance();
for (auto entity : db["entity"].find("formula_weight"_key == null or "formula_weight"_key == 0))
{
const auto &[entity_id, type] = entity.get<std::string, std::string>("id", "type");
float formula_weight = 0;
if (type == "polymer")
{
int n = 0;
for (std::string comp_id : db["pdbx_poly_seq_scheme"].find<std::string>("entity_id"_key == entity_id, "mon_id"))
{
auto compound = cf.create(comp_id);
assert(compound);
if (not compound)
throw std::runtime_error("missing information for compound " + comp_id);
formula_weight += compound->formula_weight();
++n;
}
formula_weight -= (n - 1) * 18.015;
}
else if (type == "water")
formula_weight = 18.015;
else if (type == "branched")
{
int n = 0;
for (std::string comp_id : db["pdbx_entity_branch_list"].find<std::string>("entity_id"_key == entity_id, "comp_id"))
{
auto compound = cf.create(comp_id);
assert(compound);
if (not compound)
throw std::runtime_error("missing information for compound " + comp_id);
formula_weight += compound->formula_weight();
++n;
}
formula_weight -= (n - 1) * 18.015;
}
else if (type == "non-polymer")
{
auto comp_id = db["pdbx_nonpoly_scheme"].find_first<std::optional<std::string>>("entity_id"_key == entity_id, "mon_id");
if (comp_id.has_value())
{
auto compound = cf.create(*comp_id);
assert(compound);
if (not compound)
throw std::runtime_error("missing information for compound " + *comp_id);
formula_weight = compound->formula_weight();
}
}
if (formula_weight > 0)
entity.assign({ { "formula_weight", formula_weight, 3 } });
}
}
void createEntityIDs(datablock &db)
{
// Suppose the file does not have entity ID's. We have to make up some
......@@ -386,12 +450,16 @@ void checkAtomRecords(datablock &db)
auto chem_comp_entry = chem_comp.find_first("id"_key == comp_id);
std::optional<bool> non_std;
if (cf.is_monomer(comp_id))
non_std = cf.is_std_monomer(comp_id);
if (not chem_comp_entry)
{
chem_comp.emplace({ //
{ "id", comp_id },
{ "type", compound->type() },
{ "mon_nstd_flag", cf.is_std_monomer(comp_id) ? "y" : "n" },
{ "mon_nstd_flag", non_std },
{ "name", compound->name() },
{ "formula", compound->formula() },
{ "formula_weight", compound->formula_weight() } });
......@@ -402,8 +470,8 @@ void checkAtomRecords(datablock &db)
if (not chem_comp_entry["type"])
items.emplace_back(item{ "type", compound->type() });
if (not chem_comp_entry["mon_nstd_flag"])
items.emplace_back(item{ "mon_nstd_flag", cf.is_std_monomer(comp_id) ? "y" : "n" });
if (not chem_comp_entry["mon_nstd_flag"] and non_std.has_value())
items.emplace_back(item{ "mon_nstd_flag", non_std });
if (not chem_comp_entry["name"])
items.emplace_back(item{ "name", compound->name() });
if (not chem_comp_entry["formula"])
......@@ -420,15 +488,13 @@ void checkAtomRecords(datablock &db)
int seq_id = get_seq_id(k);
if (row["label_seq_id"].empty())
if (row["label_seq_id"].empty() and cf.is_monomer(comp_id))
row["label_seq_id"] = std::to_string(seq_id);
if (row["label_atom_id"].empty())
row["label_atom_id"] = row["auth_atom_id"].text();
if (row["label_asym_id"].empty())
row["label_asym_id"] = row["auth_asym_id"].text();
if (row["label_seq_id"].empty())
row["label_seq_id"] = row["auth_seq_id"].text();
if (row["label_comp_id"].empty())
row["label_comp_id"] = row["auth_comp_id"].text();
if (row["label_atom_id"].empty())
......@@ -517,7 +583,7 @@ void checkAtomAnisotropRecords(datablock &db)
{
if (cif::VERBOSE and std::exchange(warnReplaceTypeSymbol, false))
std::clog << "Replacing type_symbol in atom_site_anisotrop record(s)\n";
row["type_symbol"] != parent["type_symbol"].text();
row["type_symbol"] = parent["type_symbol"].text();
}
if (row["pdbx_auth_alt_id"].empty())
......@@ -1263,6 +1329,9 @@ bool reconstruct_pdbx(file &file, std::string_view dictionary)
if (db.get("entity") == nullptr)
createEntity(db);
// fill in missing formula_weight, e.g.
checkEntities(db);
if (db.get("pdbx_poly_seq_scheme") == nullptr)
createPdbxPolySeqScheme(db);
......
......@@ -190,22 +190,41 @@ std::string trim_left_copy(std::string_view s)
void trim_left(std::string &s)
{
auto b = s.begin();
while (b != s.end())
auto in = s.begin(), out = s.begin();
while (in != s.end() and std::isspace(*in))
++in;
if (in == s.end())
s.clear();
else if (in != out)
{
if (not std::isspace(*b))
break;
b = std::next(b);
while (in != s.end())
*out++ = *in++;
s.erase(out, s.end());
}
s.erase(s.begin(), b);
}
void trim(std::string &s)
{
trim_right(s);
trim_left(s);
auto in = s.begin(), out = s.begin(), end = s.end();
while (end != s.begin() and std::isspace(*(end - 1)))
--end;
while (in != end and std::isspace(*in))
++in;
if (in == end)
s.clear();
else if (in != out)
{
while (in != end)
*out++ = *in++;
s.erase(out, s.end());
}
else if (end != s.end())
s.erase(end, s.end());
}
std::string trim_copy(std::string_view s)
......
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