Compare commits

...

35 Commits

Author SHA1 Message Date
Maarten L. Hekkelman
da8a72a8aa Merge branch 'develop' into trunk 2024-03-06 16:50:33 +01:00
Maarten L. Hekkelman
ac497932b5 Fix loading embedded restraint data 2024-03-06 16:50:12 +01:00
Maarten L. Hekkelman
9927b5061a Merge branch 'develop' of github.com:PDB-REDO/libcifpp into develop 2024-03-06 16:21:15 +01:00
Maarten L. Hekkelman
cedaab9642 load compound info from appended restraint info 2024-03-06 16:20:43 +01:00
Maarten L. Hekkelman
50bf2145ec Merge branch 'develop' into trunk 2024-03-06 15:54:56 +01:00
Maarten L. Hekkelman
dc77729f50 update changelog 2024-03-06 15:48:17 +01:00
Maarten L. Hekkelman
e3330d667a formatting 2024-03-06 13:22:00 +01:00
Maarten L. Hekkelman
9822f397a1 update libcifpp makefile 2024-03-06 12:58:50 +01:00
Maarten L. Hekkelman
a3b5ce9959 loading extra compound info changed
cif::file constructors
2024-03-06 12:33:58 +01:00
Maarten L. Hekkelman
9eb06e929a fixes in iterators 2024-03-05 15:52:36 +01:00
Maarten L. Hekkelman
629e06d647 write uncoloured text 2024-03-05 15:22:05 +01:00
Maarten L. Hekkelman
51ccb92184 small changes in constructors 2024-03-05 13:41:05 +01:00
Maarten L. Hekkelman
3cd27f13fd calculate formula_weight when missing 2024-03-05 13:02:31 +01:00
Maarten L. Hekkelman
ae668530c0 do not install files if they are not downloaded 2024-03-05 11:40:33 +01:00
Maarten L. Hekkelman
4a8b1c056c do not install files if they are not downloaded 2024-03-05 11:39:45 +01:00
Maarten L. Hekkelman
d7a5e598bc Merge branch 'develop' of github.com:pdb-redo/libcifpp into develop 2024-03-05 11:33:25 +01:00
Maarten L. Hekkelman
3f1ee32cc6 better trim 2024-03-05 11:33:19 +01:00
Maarten L. Hekkelman
725d6ead98 stupid typo 2024-02-29 14:56:45 +01:00
Maarten L. Hekkelman
baf70579de version bump 2024-02-27 15:23:51 +01:00
Maarten L. Hekkelman
cd28ab58a3 typo in error message 2024-02-27 14:40:56 +01:00
Maarten L. Hekkelman
a78fa0a81d reconstruction fixes 2024-02-27 13:36:45 +01:00
Maarten L. Hekkelman
82130be5f5 oops 2024-02-27 13:29:38 +01:00
Maarten L. Hekkelman
510ce62dfb reconstruction fixes 2024-02-27 13:24:53 +01:00
Maarten L. Hekkelman
93375a5087 Develop (#54)
* - renamed exists to contains
- fix compare for ints where item is empty

* - checking and optionally dropping ndb_poly_seq_scheme
- fix in iterator_proxy

* formatting data in reconstruction

* Version bump

* Attempt to get code compiling on macOS

* attempt 2 to build on macOS

* Added remove column

* Added rename_column
Added item_alias
Rename columns in reconstruct

* macOS...

* Fixed serious bug in emplace of both datablock and file.

* renaming field and column to item

* replace tag with item or item_name

* Fix validate pdbx

* version bump

* atom_site_anisotrop check

* - changed compound::is_known_peptide/is_know_base
- Add audit_conform only if file is really valid
- Added reconstruction code for PDBx

* pdb2cif work

* gcc diagnostics and clipper

* Fixing pdb2cif, and sequence checking

* work around bug in old gcc

* fix reconstruct sequence

* formatting

* some small optimisations

* Fix url in compound message

* Fix operator= for item_handle

* Fix operator= for item_handle

* new update_value in category

* test builds faster now

* Use Catch2 version 3 if installed

* catch22
2024-02-17 16:03:14 +01:00
Maarten L. Hekkelman
be738e7fb1 catch22 2024-02-17 15:37:53 +01:00
Maarten L. Hekkelman
9c78131df3 Use Catch2 version 3 if installed 2024-02-17 15:20:11 +01:00
Maarten L. Hekkelman
d94f6f4d19 test builds faster now 2024-02-05 13:01:28 +01:00
Maarten L. Hekkelman
9a3eced350 new update_value in category 2024-01-31 16:20:49 +01:00
Maarten L. Hekkelman
2fed7a76fb Fix operator= for item_handle 2024-01-30 16:51:12 +01:00
Maarten L. Hekkelman
f02e59df1b Fix operator= for item_handle 2024-01-30 16:40:02 +01:00
Maarten L. Hekkelman
04147a2fe9 Fix url in compound message 2024-01-30 16:39:32 +01:00
Maarten L. Hekkelman
0e83bc31dc some small optimisations 2024-01-30 16:29:22 +01:00
Maarten L. Hekkelman
75a5f7960f formatting 2024-01-30 11:12:29 +01:00
Maarten L. Hekkelman
3f93c27b07 fix reconstruct sequence 2024-01-29 17:40:24 +01:00
Maarten L. Hekkelman
ab781d4516 work around bug in old gcc 2024-01-29 16:33:53 +01:00
31 changed files with 805 additions and 586 deletions

View File

@@ -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)
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 ${project_sources} ${project_headers}
${PROJECT_SOURCE_DIR}/src/symop_table_data.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)
FILE "cifpp-targets.cmake"
DESTINATION lib/cmake/cifpp)
install(
DIRECTORY include/cif++
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
COMPONENT Devel)
install(
FILES include/cif++.hpp
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
COMPONENT Devel)
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
@@ -546,56 +540,7 @@ if(NOT PROJECT_IS_TOP_LEVEL)
endif()
if(BUILD_TESTING)
# We're using the older version 2 of Catch2
FetchContent_Declare(
Catch2
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
GIT_TAG v2.13.9)
FetchContent_MakeAvailable(Catch2)
list(
APPEND
CIFPP_tests
unit-v2
unit-3d
format
model
rename-compound
sugar
spinner
reconstruction
validate-pdbx)
foreach(CIFPP_TEST IN LISTS CIFPP_tests)
set(CIFPP_TEST "${CIFPP_TEST}-test")
set(CIFPP_TEST_SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/test/${CIFPP_TEST}.cpp")
add_executable(
${CIFPP_TEST} ${CIFPP_TEST_SOURCE}
"${CMAKE_CURRENT_SOURCE_DIR}/test/test-main.cpp")
target_link_libraries(${CIFPP_TEST} PRIVATE Threads::Threads cifpp::cifpp
Catch2::Catch2)
target_include_directories(${CIFPP_TEST} PRIVATE "${EIGEN_INCLUDE_DIR}")
if(MSVC)
# Specify unwind semantics so that MSVC knowns how to handle exceptions
target_compile_options(${CIFPP_TEST} PRIVATE /EHsc)
endif()
add_custom_target(
"run-${CIFPP_TEST}"
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/Run${CIFPP_TEST}.touch ${CIFPP_TEST})
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Run${CIFPP_TEST}.touch
COMMAND $<TARGET_FILE:${CIFPP_TEST}> --data-dir
${CMAKE_CURRENT_SOURCE_DIR}/test)
add_test(NAME ${CIFPP_TEST} COMMAND $<TARGET_FILE:${CIFPP_TEST}> --data-dir
${CMAKE_CURRENT_SOURCE_DIR}/test)
endforeach()
add_subdirectory(test)
endif()
# Optionally install the update scripts for CCD and dictionary files

View File

@@ -1,3 +1,9 @@
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.

View File

@@ -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.
@@ -964,6 +972,32 @@ class category
// --------------------------------------------------------------------
using value_provider_type = std::function<std::string_view(std::string_view)>;
/// \brief Update a single item named @a item_name in the rows that match
/// \a cond to values provided by a callback function \a value_provider
/// making sure the linked categories are updated according to the link.
/// That means, child categories are updated if the links are absolute
/// and unique. If they are not, the child category rows are split.
void update_value(condition &&cond, std::string_view item_name,
value_provider_type &&value_provider)
{
auto rs = find(std::move(cond));
std::vector<row_handle> rows;
std::copy(rs.begin(), rs.end(), std::back_inserter(rows));
update_value(rows, item_name, std::move(value_provider));
}
/// \brief Update a single item named @a item_name in the rows \a rows
/// to values provided by a callback function \a value_provider
/// making sure the linked categories are updated according to the link.
/// That means, child categories are updated if the links are absolute
/// and unique. If they are not, the child category rows are split.
void update_value(const std::vector<row_handle> &rows, std::string_view item_name,
value_provider_type &&value_provider);
/// \brief Update a single item named @a item_name in the rows that match \a cond to value \a value
/// making sure the linked categories are updated according to the link.
/// That means, child categories are updated if the links are absolute
@@ -982,15 +1016,18 @@ class category
/// That means, child categories are updated if the links are absolute
/// and unique. If they are not, the child category rows are split.
void update_value(const std::vector<row_handle> &rows, std::string_view item_name, std::string_view value);
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; });
}
// --------------------------------------------------------------------
// Naming used to be very inconsistent. For backward compatibility,
// 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);
}
@@ -998,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);
}
@@ -1007,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);
}
@@ -1016,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);
}
@@ -1032,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();
}
@@ -1096,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);
@@ -1140,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();
}

View File

@@ -370,7 +370,7 @@ namespace detail
{
key_equals_condition_impl(item &&i)
: m_item_name(i.name())
, m_value(i.value())
, m_value(std::forward<item>(i).value())
{
}

View File

@@ -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));
}
// --------------------------------------------------------------------
/**

View File

@@ -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 */
/**

View File

@@ -120,8 +120,6 @@ class item
if (r.ec != std::errc())
throw std::runtime_error("Could not format number");
assert(r.ptr >= buffer and r.ptr < buffer + sizeof(buffer));
*r.ptr = 0;
m_value.assign(buffer, r.ptr - buffer);
}
@@ -141,8 +139,6 @@ class item
if (r.ec != std::errc())
throw std::runtime_error("Could not format number");
assert(r.ptr >= buffer and r.ptr < buffer + sizeof(buffer));
*r.ptr = 0;
m_value.assign(buffer, r.ptr - buffer);
}
@@ -158,8 +154,6 @@ class item
if (r.ec != std::errc())
throw std::runtime_error("Could not format number");
assert(r.ptr >= buffer and r.ptr < buffer + sizeof(buffer));
*r.ptr = 0;
m_value.assign(buffer, r.ptr - buffer);
}
@@ -174,12 +168,21 @@ class item
/// \brief constructor for an item with name \a name and as
/// content value \a value
item(const std::string_view name, const std::string_view value)
item(const std::string_view name, std::string_view value)
: m_name(name)
, m_value(value)
{
}
/// \brief constructor for an item with name \a name and as
/// content value \a value
template<typename T, std::enable_if_t<std::is_same_v<T, std::string>, int> = 0>
item(const std::string_view name, T &&value)
: m_name(name)
, m_value(std::move(value))
{
}
/// \brief constructor for an item with name \a name and as
/// content the optional value \a value
template <typename T>
@@ -219,7 +222,8 @@ class item
/** @endcond */
std::string_view name() const { return m_name; } ///< Return the name of the item
std::string_view value() const { return m_value; } ///< Return the value of the item
std::string_view value() const & { return m_value; } ///< Return the value of the item
std::string value() const && { return std::move(m_value); } ///< Return the value of the item
/// \brief replace the content of the stored value with \a v
void value(std::string_view v) { m_value = v; }
@@ -284,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;
}
@@ -363,8 +364,35 @@ struct item_handle
template <typename T>
item_handle &operator=(const T &value)
{
item v{ "", value };
assign_value(v);
assign_value(item{ "", value }.value());
return *this;
}
/**
* @brief Assign value @a value to the item referenced
*
* @tparam T Type of the value
* @param value The value
* @return reference to this item_handle
*/
template <typename T>
item_handle &operator=(T &&value)
{
assign_value(item{ "", std::move(value) }.value());
return *this;
}
/**
* @brief Assign value @a value to the item referenced
*
* @tparam T Type of the value
* @param value The value
* @return reference to this item_handle
*/
template <size_t N>
item_handle &operator=(const char (&value)[N])
{
assign_value(item{ "", std::move(value) }.value());
return *this;
}
@@ -508,7 +536,7 @@ struct item_handle
uint16_t m_item_ix;
row_handle &m_row_handle;
void assign_value(const item &value);
void assign_value(std::string_view value);
};
// So sad that older gcc implementations of from_chars did not support floats yet...

View File

@@ -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;
};

View File

@@ -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;

View File

@@ -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,
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<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,
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);
}
// --------------------------------------------------------------------

View File

@@ -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:

View File

@@ -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)
void swap(category &a, category &b) noexcept
{
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)
{
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()
@@ -1339,7 +1286,8 @@ std::string category::get_unique_value(std::string_view item_name)
return result;
}
void category::update_value(const std::vector<row_handle> &rows, std::string_view item_name, std::string_view value)
void category::update_value(const std::vector<row_handle> &rows, std::string_view item_name,
value_provider_type &&value_provider)
{
using namespace std::literals;
@@ -1352,40 +1300,29 @@ void category::update_value(const std::vector<row_handle> &rows, std::string_vie
auto &col = m_items[colIx];
// this is expensive, but better throw early on
// check the value
if (col.m_validator)
{
std::error_code ec;
col.m_validator->validate_value(value, ec);
if (ec)
throw validation_exception(ec, m_name, item_name);
}
// first some sanity checks, what was the old value and is it the same for all rows?
std::string oldValue{ rows.front()[item_name].text() };
for (auto row : rows)
{
if (oldValue != row[item_name].text())
for (auto row : rows)
{
std::ostringstream os;
std::string value{ value_provider(row[item_name].text()) };
os << "Inconsistent old values in update_value, trying to set " << std::quoted(value)
<< " as value for item " << item_name << " in category " << m_name;
throw std::runtime_error(os.str());
std::error_code ec;
col.m_validator->validate_value(value, ec);
if (ec)
throw validation_exception(ec, m_name, item_name);
}
}
if (oldValue == value) // no need to do anything
return;
// update rows, but do not cascade
for (auto row : rows)
row.assign(colIx, value, false);
// see if we need to update any child categories that depend on this value
// update and see if we need to update any child categories that depend on this value
for (auto parent : rows)
{
std::string oldValue{ parent[item_name].text() };
std::string value{ value_provider(oldValue) };
parent.assign(colIx, value, false);
for (auto &&[childCat, linked] : m_child_links)
{
if (std::find(linked->m_parent_keys.begin(), linked->m_parent_keys.end(), item_name) == linked->m_parent_keys.end())
@@ -1722,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;
@@ -1733,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;

View File

@@ -545,12 +545,29 @@ class local_compound_factory_impl : public compound_factory_impl
: compound_factory_impl(next)
, m_local_file(file)
{
const std::regex peptideRx("(?:[lmp]-)?peptide", std::regex::icase);
for (const auto &[id, name, threeLetterCode, group] :
file["comp_list"]["chem_comp"].rows<std::string, std::string, std::string, std::string>("id", "name", "three_letter_code", "group"))
{
auto &rdb = m_local_file["comp_" + id];
if (rdb.empty())
{
std::cerr << "Missing data in restraint file for id " + id + '\n';
continue;
}
construct_compound(rdb, id, name, threeLetterCode, group);
}
}
compound *create(const std::string &id) override;
private:
const cif::file &m_local_file;
compound *construct_compound(const datablock &db, const std::string &id, const std::string &name, const std::string &three_letter_code, const std::string &group);
cif::file m_local_file;
};
compound *local_compound_factory_impl::create(const std::string &id)
@@ -561,12 +578,21 @@ compound *local_compound_factory_impl::create(const std::string &id)
{
if (db.name() == "comp_" + id)
{
cif::datablock db_copy(db);
auto chem_comp = db.get("chem_comp");
if (not chem_comp)
break;
result = new compound(db_copy, 1);
try
{
const auto &[id, name, threeLetterCode, group] =
chem_comp->front().get<std::string, std::string, std::string, std::string>("id", "name", "three_letter_code", "group");
std::shared_lock lock(mMutex);
m_compounds.push_back(result);
result = construct_compound(db, id, name, threeLetterCode, group);
}
catch (const std::exception &ex)
{
std::throw_with_nested(std::runtime_error("Error loading compound " + id));
}
break;
}
@@ -575,6 +601,100 @@ compound *local_compound_factory_impl::create(const std::string &id)
return result;
}
compound *local_compound_factory_impl::construct_compound(const datablock &rdb, const std::string &id,
const std::string &name, const std::string &three_letter_code, const std::string &group)
{
cif::datablock db(id);
float formula_weight = 0;
int formal_charge = 0;
std::map<std::string,size_t> formula_data;
for (size_t ord = 1; const auto &[atom_id, type_symbol, type, charge, x, y, z] :
rdb["chem_comp_atom"].rows<std::string, std::string, std::string, int, float, float, float>(
"atom_id", "type_symbol", "type", "charge", "x", "y", "z"))
{
auto atom = cif::atom_type_traits(type_symbol);
formula_weight += atom.weight();
formula_data[type_symbol] += 1;
db["chem_comp_atom"].emplace({
{ "comp_id", id },
{ "atom_id", atom_id },
{ "type_symbol", type_symbol },
{ "charge", charge },
{ "model_Cartn_x", x, 3 },
{ "model_Cartn_y", y, 3 },
{ "model_Cartn_z", z, 3 },
{ "pdbx_ordinal", ord++ }
});
formal_charge += charge;
}
for (size_t ord = 1; const auto &[atom_id_1, atom_id_2, type, aromatic] :
rdb["chem_comp_bond"].rows<std::string, std::string, std::string, bool>("atom_id_1", "atom_id_2", "type", "aromatic"))
{
std::string value_order("SING");
if (cif::iequals(type, "single") or cif::iequals(type, "sing"))
value_order = "SING";
else if (cif::iequals(type, "double") or cif::iequals(type, "doub"))
value_order = "DOUB";
else if (cif::iequals(type, "triple") or cif::iequals(type, "trip"))
value_order = "TRIP";
db["chem_comp_bond"].emplace({
{ "comp_id", id },
{ "atom_id_1", atom_id_1 },
{ "atom_id_2", atom_id_2 },
{ "value_order", value_order },
{ "pdbx_aromatic_flag", aromatic },
// TODO: fetch stereo_config info from chem_comp_chir
{ "pdbx_ordinal", ord++ }
});
}
db.emplace_back(rdb["pdbx_chem_comp_descriptor"]);
std::string formula;
for (bool first = true; const auto &[symbol, count]: formula_data)
{
if (std::exchange(first, false))
formula += ' ';
formula += symbol;
if (count > 1)
formula += std::to_string(count);
}
std::string type;
if (cif::iequals(group, "peptide") or cif::iequals(group, "l-peptide") or cif::iequals(group, "l-peptide linking"))
type = "L-PEPTIDE LINKING";
else if (cif::iequals(group, "dna"))
type = "DNA LINKING";
else if (cif::iequals(group, "rna"))
type = "RNA LINKING";
else
type = "NON-POLYMER";
db["chem_comp"].emplace({
{ "id", id },
{ "name", name },
{ "type", type },
{ "formula", formula },
{ "pdbx_formal_charge", formal_charge },
{ "formula_weight", formula_weight },
{ "three_letter_code", three_letter_code }
});
std::shared_lock lock(mMutex);
auto result = new compound(db);
m_compounds.push_back(result);
return result;
}
// --------------------------------------------------------------------
std::unique_ptr<compound_factory> compound_factory::s_instance;
@@ -757,8 +877,8 @@ void compound_factory::report_missing_compound(std::string_view compound_id)
<< "update=true\n\n"
<< "If you do not have a working cron script, you can manually update the files\n"
<< "in /var/cache/libcifpp using the following commands:\n\n"
<< "curl -o " << CACHE_DIR << "/components.cif https://files.wwpdb.org/pub/pdb/data/monomers/components.cif.gz\n"
<< "curl -o " << CACHE_DIR << "/mmcif_pdbx.dic https://mmcif.wwpdb.org/dictionaries/ascii/mmcif_pdbx_v50.dic.gz\n"
<< "curl -o " << CACHE_DIR << "/components.cif https://files.wwpdb.org/pub/pdb/data/monomers/components.cif\n"
<< "curl -o " << CACHE_DIR << "/mmcif_pdbx.dic https://mmcif.wwpdb.org/dictionaries/ascii/mmcif_pdbx_v50.dic\n"
<< "curl -o " << CACHE_DIR << "/mmcif_ma.dic https://github.com/ihmwg/ModelCIF/raw/master/dist/mmcif_ma.dic\n\n";
#endif

View File

@@ -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;

View File

@@ -52,10 +52,10 @@ std::string_view item_handle::text() const
return {};
}
void item_handle::assign_value(const item &v)
void item_handle::assign_value(std::string_view value)
{
assert(not m_row_handle.empty());
m_row_handle.assign(m_item_ix, v.value(), true);
m_row_handle.assign(m_item_ix, value, true);
}
void item_handle::swap(item_handle &b)

View File

@@ -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?

View File

@@ -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
@@ -325,7 +389,7 @@ void checkChemCompRecords(datablock &db)
items.emplace_back(item{ "formula_weight", compound->formula_weight() });
if (not items.empty())
chem_comp_entry.assign(std::move(items));
chem_comp_entry.assign(items);
}
}
}
@@ -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"])
@@ -412,7 +480,7 @@ void checkAtomRecords(datablock &db)
items.emplace_back(item{ "formula_weight", compound->formula_weight() });
if (not items.empty())
chem_comp_entry.assign(std::move(items));
chem_comp_entry.assign(items);
}
if (is_peptide and not has_seq_id(k))
@@ -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())
@@ -705,7 +771,11 @@ void createEntityPoly(datablock &db)
if (cf.is_base(comp_id))
{
c_type = "polydeoxyribonucleotide";
letter = letter_can = compound_factory::kBaseMap.at(comp_id);
letter_can = compound_factory::kBaseMap.at(comp_id);
if (comp_id.length() == 1)
letter = letter_can;
else
letter = '(' + letter_can + ')';
}
else if (cf.is_peptide(comp_id))
{
@@ -1259,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);

View File

@@ -35,24 +35,24 @@ namespace cif
// --------------------------------------------------------------------
// This really makes a difference, having our own tolower routines
const uint8_t kCharToLowerMap[256] =
{
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff};
const uint8_t kCharToLowerMap[256] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
};
// --------------------------------------------------------------------
@@ -171,7 +171,7 @@ std::string trim_right_copy(std::string_view s)
e = pe;
}
return {s.begin(), e};
return { s.begin(), e };
}
std::string trim_left_copy(std::string_view s)
@@ -185,27 +185,46 @@ std::string trim_left_copy(std::string_view s)
b = std::next(b);
}
return {b, s.end()};
return { b, s.end() };
}
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)
@@ -220,14 +239,14 @@ std::tuple<std::string, std::string> split_item_name(std::string_view item_name)
if (item_name.empty())
throw std::runtime_error("empty item_name");
if (item_name[0] != '_')
throw std::runtime_error("item_name '" + std::string { item_name } + "' does not start with underscore");
throw std::runtime_error("item_name '" + std::string{ item_name } + "' does not start with underscore");
auto s = item_name.find('.');
if (s == std::string::npos)
// throw std::runtime_error("item_name does not contain dot (" + std::string{ item_name } + ')');
return std::tuple<std::string, std::string>{ "", item_name.substr(1) };
else
return std::tuple<std::string, std::string>{item_name.substr(1, s - 1), item_name.substr(s + 1)};
return std::tuple<std::string, std::string>{ item_name.substr(1, s - 1), item_name.substr(s + 1) };
}
// --------------------------------------------------------------------
@@ -242,8 +261,7 @@ std::string cif_id_for_number(int number)
result += static_cast<char>('A' + r);
number = (number - r) / 26 - 1;
}
while (number >= 0);
} while (number >= 0);
std::reverse(result.begin(), result.end());
@@ -298,29 +316,29 @@ enum LineBreakClass
kLBC_Unknown
};
const LineBreakClass kASCII_LBTable[128] =
{
kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark,
kLBC_CombiningMark, kLBC_BreakAfter, kLBC_LineFeed, kLBC_MandatoryBreak, kLBC_MandatoryBreak, kLBC_CarriageReturn, kLBC_CombiningMark, kLBC_CombiningMark,
kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark,
kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark,
kLBC_Space, kLBC_Exlamation, kLBC_Quotation, kLBC_Alphabetic, kLBC_PrefixNumeric, kLBC_PostfixNumeric, kLBC_Alphabetic, kLBC_Quotation,
kLBC_OpenPunctuation, kLBC_CloseParenthesis, kLBC_Alphabetic, kLBC_PrefixNumeric,
const LineBreakClass kASCII_LBTable[128] = {
kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark,
kLBC_CombiningMark, kLBC_BreakAfter, kLBC_LineFeed, kLBC_MandatoryBreak, kLBC_MandatoryBreak, kLBC_CarriageReturn, kLBC_CombiningMark, kLBC_CombiningMark,
kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark,
kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark, kLBC_CombiningMark,
kLBC_Space, kLBC_Exlamation, kLBC_Quotation, kLBC_Alphabetic, kLBC_PrefixNumeric, kLBC_PostfixNumeric, kLBC_Alphabetic, kLBC_Quotation,
kLBC_OpenPunctuation, kLBC_CloseParenthesis, kLBC_Alphabetic, kLBC_PrefixNumeric,
// comma treated differently here, it is not a numeric separator in PDB
kLBC_SymbolAllowingBreakAfter /* kLBC_InfixNumericSeparator */,
// comma treated differently here, it is not a numeric separator in PDB
kLBC_SymbolAllowingBreakAfter /* kLBC_InfixNumericSeparator */,
kLBC_Hyphen, kLBC_InfixNumericSeparator, kLBC_SymbolAllowingBreakAfter,
kLBC_Numeric, kLBC_Numeric, kLBC_Numeric, kLBC_Numeric, kLBC_Numeric, kLBC_Numeric, kLBC_Numeric, kLBC_Numeric,
kLBC_Numeric, kLBC_Numeric, kLBC_InfixNumericSeparator, kLBC_InfixNumericSeparator, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Exlamation,
kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic,
kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic,
kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic,
kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_OpenPunctuation, kLBC_PrefixNumeric, kLBC_CloseParenthesis, kLBC_Alphabetic, kLBC_Alphabetic,
kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic,
kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic,
kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic,
kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_OpenPunctuation, kLBC_BreakAfter, kLBC_ClosePunctuation, kLBC_Alphabetic, kLBC_CombiningMark};
kLBC_Hyphen, kLBC_InfixNumericSeparator, kLBC_SymbolAllowingBreakAfter,
kLBC_Numeric, kLBC_Numeric, kLBC_Numeric, kLBC_Numeric, kLBC_Numeric, kLBC_Numeric, kLBC_Numeric, kLBC_Numeric,
kLBC_Numeric, kLBC_Numeric, kLBC_InfixNumericSeparator, kLBC_InfixNumericSeparator, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Exlamation,
kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic,
kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic,
kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic,
kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_OpenPunctuation, kLBC_PrefixNumeric, kLBC_CloseParenthesis, kLBC_Alphabetic, kLBC_Alphabetic,
kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic,
kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic,
kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic,
kLBC_Alphabetic, kLBC_Alphabetic, kLBC_Alphabetic, kLBC_OpenPunctuation, kLBC_BreakAfter, kLBC_ClosePunctuation, kLBC_Alphabetic, kLBC_CombiningMark
};
std::string::const_iterator nextLineBreak(std::string::const_iterator text, std::string::const_iterator end)
{
@@ -338,33 +356,33 @@ std::string::const_iterator nextLineBreak(std::string::const_iterator text, std:
const breakAction brkTable[27][27] = {
// OP CL CP QU GL NS EX SY IS PR PO NU AL ID IN HY BA BB B2 ZW CM WJ H2 H3 JL JV JT
/* OP */ {PBK, PBK, PBK, PBK, PBK, PBK, PBK, PBK, PBK, PBK, PBK, PBK, PBK, PBK, PBK, PBK, PBK, PBK, PBK, PBK, CPB, PBK, PBK, PBK, PBK, PBK, PBK},
/* CL */ {DBK, PBK, PBK, IBK, IBK, PBK, PBK, PBK, PBK, IBK, IBK, DBK, DBK, DBK, DBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, DBK},
/* CP */ {DBK, PBK, PBK, IBK, IBK, PBK, PBK, PBK, PBK, IBK, IBK, IBK, IBK, DBK, DBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, DBK},
/* QU */ {PBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, PBK, CIB, PBK, IBK, IBK, IBK, IBK, IBK},
/* GL */ {IBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, PBK, CIB, PBK, IBK, IBK, IBK, IBK, IBK},
/* NS */ {DBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, DBK, DBK, DBK, DBK, DBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, DBK},
/* EX */ {DBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, DBK, DBK, DBK, DBK, DBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, DBK},
/* SY */ {DBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, DBK, IBK, DBK, DBK, DBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, DBK},
/* IS */ {DBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, DBK, IBK, IBK, DBK, DBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, DBK},
/* PR */ {IBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, DBK, IBK, IBK, IBK, DBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, IBK, IBK, IBK, IBK, IBK},
/* PO */ {IBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, DBK, IBK, IBK, DBK, DBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, DBK},
/* NU */ {DBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, IBK, IBK, IBK, IBK, DBK, IBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, DBK},
/* AL */ {DBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, DBK, IBK, IBK, DBK, IBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, DBK},
/* ID */ {DBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, IBK, DBK, DBK, DBK, IBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, DBK},
/* IN */ {DBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, DBK, DBK, DBK, DBK, IBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, DBK},
/* HY */ {DBK, PBK, PBK, IBK, DBK, IBK, PBK, PBK, PBK, DBK, DBK, IBK, DBK, DBK, DBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, DBK},
/* BA */ {DBK, PBK, PBK, IBK, DBK, IBK, PBK, PBK, PBK, DBK, DBK, DBK, DBK, DBK, DBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, DBK},
/* BB */ {IBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, PBK, CIB, PBK, IBK, IBK, IBK, IBK, IBK},
/* B2 */ {DBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, DBK, DBK, DBK, DBK, DBK, IBK, IBK, DBK, PBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, DBK},
/* ZW */ {DBK, DBK, DBK, DBK, DBK, DBK, DBK, DBK, DBK, DBK, DBK, DBK, DBK, DBK, DBK, DBK, DBK, DBK, DBK, PBK, DBK, DBK, DBK, DBK, DBK, DBK, DBK},
/* CM */ {DBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, DBK, IBK, IBK, DBK, IBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, DBK},
/* WJ */ {IBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, PBK, CIB, PBK, IBK, IBK, IBK, IBK, IBK},
/* H2 */ {DBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, IBK, DBK, DBK, DBK, IBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, IBK, IBK},
/* H3 */ {DBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, IBK, DBK, DBK, DBK, IBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, IBK},
/* JL */ {DBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, IBK, DBK, DBK, DBK, IBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, IBK, IBK, IBK, IBK, DBK},
/* JV */ {DBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, IBK, DBK, DBK, DBK, IBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, IBK, IBK},
/* JT */ {DBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, IBK, DBK, DBK, DBK, IBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, IBK},
/* OP */ { PBK, PBK, PBK, PBK, PBK, PBK, PBK, PBK, PBK, PBK, PBK, PBK, PBK, PBK, PBK, PBK, PBK, PBK, PBK, PBK, CPB, PBK, PBK, PBK, PBK, PBK, PBK },
/* CL */ { DBK, PBK, PBK, IBK, IBK, PBK, PBK, PBK, PBK, IBK, IBK, DBK, DBK, DBK, DBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, DBK },
/* CP */ { DBK, PBK, PBK, IBK, IBK, PBK, PBK, PBK, PBK, IBK, IBK, IBK, IBK, DBK, DBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, DBK },
/* QU */ { PBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, PBK, CIB, PBK, IBK, IBK, IBK, IBK, IBK },
/* GL */ { IBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, PBK, CIB, PBK, IBK, IBK, IBK, IBK, IBK },
/* NS */ { DBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, DBK, DBK, DBK, DBK, DBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, DBK },
/* EX */ { DBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, DBK, DBK, DBK, DBK, DBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, DBK },
/* SY */ { DBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, DBK, IBK, DBK, DBK, DBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, DBK },
/* IS */ { DBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, DBK, IBK, IBK, DBK, DBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, DBK },
/* PR */ { IBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, DBK, IBK, IBK, IBK, DBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, IBK, IBK, IBK, IBK, IBK },
/* PO */ { IBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, DBK, IBK, IBK, DBK, DBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, DBK },
/* NU */ { DBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, IBK, IBK, IBK, IBK, DBK, IBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, DBK },
/* AL */ { DBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, DBK, IBK, IBK, DBK, IBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, DBK },
/* ID */ { DBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, IBK, DBK, DBK, DBK, IBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, DBK },
/* IN */ { DBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, DBK, DBK, DBK, DBK, IBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, DBK },
/* HY */ { DBK, PBK, PBK, IBK, DBK, IBK, PBK, PBK, PBK, DBK, DBK, IBK, DBK, DBK, DBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, DBK },
/* BA */ { DBK, PBK, PBK, IBK, DBK, IBK, PBK, PBK, PBK, DBK, DBK, DBK, DBK, DBK, DBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, DBK },
/* BB */ { IBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, PBK, CIB, PBK, IBK, IBK, IBK, IBK, IBK },
/* B2 */ { DBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, DBK, DBK, DBK, DBK, DBK, IBK, IBK, DBK, PBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, DBK },
/* ZW */ { DBK, DBK, DBK, DBK, DBK, DBK, DBK, DBK, DBK, DBK, DBK, DBK, DBK, DBK, DBK, DBK, DBK, DBK, DBK, PBK, DBK, DBK, DBK, DBK, DBK, DBK, DBK },
/* CM */ { DBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, DBK, IBK, IBK, DBK, IBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, DBK },
/* WJ */ { IBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, IBK, PBK, CIB, PBK, IBK, IBK, IBK, IBK, IBK },
/* H2 */ { DBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, IBK, DBK, DBK, DBK, IBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, IBK, IBK },
/* H3 */ { DBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, IBK, DBK, DBK, DBK, IBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, IBK },
/* JL */ { DBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, IBK, DBK, DBK, DBK, IBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, IBK, IBK, IBK, IBK, DBK },
/* JV */ { DBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, IBK, DBK, DBK, DBK, IBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, IBK, IBK },
/* JT */ { DBK, PBK, PBK, IBK, IBK, IBK, PBK, PBK, PBK, DBK, IBK, DBK, DBK, DBK, IBK, IBK, IBK, DBK, DBK, PBK, CIB, PBK, DBK, DBK, DBK, DBK, IBK },
};
uint8_t ch = static_cast<uint8_t>(*text);
@@ -418,7 +436,7 @@ std::string::const_iterator nextLineBreak(std::string::const_iterator text, std:
std::vector<std::string> wrapLine(const std::string &text, size_t width)
{
std::vector<std::string> result;
std::vector<size_t> offsets = {0};
std::vector<size_t> offsets = { 0 };
auto b = text.begin();
while (b != text.end())

View File

@@ -55,14 +55,12 @@ validation_exception::validation_exception(std::error_code ec)
}
validation_exception::validation_exception(std::error_code ec, std::string_view category)
: runtime_error(
(std::ostringstream{} << ec.message() << "; category: " << std::quoted(category)).str())
: runtime_error((ec.message() + "; category: ").append(category))
{
}
validation_exception::validation_exception(std::error_code ec, std::string_view category, std::string_view item)
: runtime_error(
(std::ostringstream{} << ec.message() << "; category: " << std::quoted(category) << "; item: " << std::quoted(item)).str())
: runtime_error((ec.message() + "; category: ").append(category).append("; item: ").append(item))
{
}
@@ -81,7 +79,7 @@ struct regex_impl : public regex
DDL_PrimitiveType map_to_primitive_type(std::string_view s, std::error_code &ec) noexcept
{
ec = {};
DDL_PrimitiveType result;
DDL_PrimitiveType result = DDL_PrimitiveType::Char;
if (iequals(s, "char"))
result = DDL_PrimitiveType::Char;
else if (iequals(s, "uchar"))

72
test/CMakeLists.txt Normal file
View File

@@ -0,0 +1,72 @@
# We're using the older version 2 of Catch2
find_package(Catch2 QUIET)
if(NOT Catch2_FOUND)
FetchContent_Declare(
Catch2
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
GIT_TAG v2.13.9)
FetchContent_MakeAvailable(Catch2)
set(Catch2_VERSION "2.13.9")
endif()
list(
APPEND
CIFPP_tests
unit-v2
unit-3d
format
model
rename-compound
sugar
spinner
reconstruction
validate-pdbx)
add_library(test-main OBJECT "${CMAKE_CURRENT_SOURCE_DIR}/test-main.cpp")
target_link_libraries(test-main cifpp::cifpp Catch2::Catch2)
if(${Catch2_VERSION} VERSION_GREATER_EQUAL 3.0.0)
target_compile_definitions(test-main PUBLIC CATCH22=0)
else()
target_compile_definitions(test-main PUBLIC CATCH22=1)
endif()
foreach(CIFPP_TEST IN LISTS CIFPP_tests)
set(CIFPP_TEST "${CIFPP_TEST}-test")
set(CIFPP_TEST_SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/${CIFPP_TEST}.cpp")
add_executable(
${CIFPP_TEST} ${CIFPP_TEST_SOURCE} $<TARGET_OBJECTS:test-main>)
if(${Catch2_VERSION} VERSION_GREATER_EQUAL 3.0.0)
target_compile_definitions(${CIFPP_TEST} PUBLIC CATCH22=0)
else()
target_compile_definitions(${CIFPP_TEST} PUBLIC CATCH22=1)
endif()
target_link_libraries(${CIFPP_TEST} PRIVATE Threads::Threads cifpp::cifpp
Catch2::Catch2)
target_include_directories(${CIFPP_TEST} PRIVATE "${EIGEN_INCLUDE_DIR}")
if(MSVC)
# Specify unwind semantics so that MSVC knowns how to handle exceptions
target_compile_options(${CIFPP_TEST} PRIVATE /EHsc)
endif()
add_custom_target(
"run-${CIFPP_TEST}"
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/Run${CIFPP_TEST}.touch ${CIFPP_TEST})
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Run${CIFPP_TEST}.touch
COMMAND $<TARGET_FILE:${CIFPP_TEST}> --data-dir
${CMAKE_CURRENT_SOURCE_DIR})
add_test(NAME ${CIFPP_TEST} COMMAND $<TARGET_FILE:${CIFPP_TEST}> --data-dir
${CMAKE_CURRENT_SOURCE_DIR})
endforeach()

View File

@@ -24,7 +24,8 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <catch2/catch.hpp>
#include "test-main.hpp"
#include <stdexcept>

View File

@@ -26,8 +26,6 @@
#include "test-main.hpp"
#include <catch2/catch.hpp>
#include <stdexcept>
#include <cif++.hpp>

View File

@@ -28,8 +28,6 @@
#include <cif++.hpp>
#include <catch2/catch.hpp>
#include <iostream>
#include <fstream>

View File

@@ -28,8 +28,6 @@
#include <cif++.hpp>
#include <catch2/catch.hpp>
#include <iostream>
#include <fstream>

View File

@@ -1,6 +1,32 @@
#include "cif++/utilities.hpp"
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2024 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 <catch2/catch.hpp>
#include "test-main.hpp"
#include "cif++/utilities.hpp"
#include <random>
#include <thread>

View File

@@ -26,8 +26,6 @@
#include "test-main.hpp"
#include <catch2/catch.hpp>
#include <stdexcept>
#include <cif++.hpp>

View File

@@ -1,10 +1,9 @@
#define CATCH_CONFIG_RUNNER 1
#include "test-main.hpp"
#include <cif++.hpp>
#define CATCH_CONFIG_RUNNER
#include <catch2/catch.hpp>
std::filesystem::path gTestDir = std::filesystem::current_path();
int main(int argc, char *argv[])
@@ -12,7 +11,13 @@ int main(int argc, char *argv[])
Catch::Session session; // There must be exactly one instance
// Build a new parser on top of Catch2's
#if CATCH22
using namespace Catch::clara;
#else
// Build a new parser on top of Catch2's
using namespace Catch::Clara;
#endif
auto cli = session.cli() // Get Catch2's command line parser
| Opt(gTestDir, "data-dir") // bind variable to a new option, with a hint string
["-D"]["--data-dir"] // the option names it will respond to

View File

@@ -1,3 +1,37 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2024 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
#if CATCH22
#include <catch2/catch.hpp>
#else
#include <catch2/catch_all.hpp>
#endif
#include <filesystem>
extern std::filesystem::path gTestDir;

View File

@@ -26,8 +26,6 @@
#include "test-main.hpp"
#include <catch2/catch.hpp>
#include <stdexcept>
#include <cif++.hpp>

View File

@@ -26,8 +26,6 @@
#include "test-main.hpp"
#include <catch2/catch.hpp>
#include <cif++.hpp>
#include "cif++/dictionary_parser.hpp"
@@ -746,27 +744,51 @@ _cat_2.desc
std::istream is_data(&data_buffer);
f.load(is_data);
auto &cat1 = f.front()["cat_1"];
auto &cat2 = f.front()["cat_2"];
SECTION("one")
{
auto &cat1 = f.front()["cat_1"];
auto &cat2 = f.front()["cat_2"];
REQUIRE(cat1.size() == 3);
REQUIRE(cat2.size() == 3);
REQUIRE(cat1.size() == 3);
REQUIRE(cat2.size() == 3);
cat1.erase(cif::key("id") == 1);
cat1.erase(cif::key("id") == 1);
REQUIRE(cat1.size() == 2);
REQUIRE(cat2.size() == 1);
REQUIRE(cat1.size() == 2);
REQUIRE(cat2.size() == 1);
// REQUIRE_THROWS_AS(cat2.emplace({
// { "id", 4 },
// { "parent_id", 4 },
// { "desc", "moet fout gaan" }
// }), std::exception);
// REQUIRE_THROWS_AS(cat2.emplace({
// { "id", 4 },
// { "parent_id", 4 },
// { "desc", "moet fout gaan" }
// }), std::exception);
REQUIRE_THROWS_AS(cat2.emplace({ { "id", "vijf" }, // <- invalid value
{ "parent_id", 2 },
{ "desc", "moet fout gaan" } }),
std::exception);
REQUIRE_THROWS_AS(cat2.emplace({ { "id", "vijf" }, // <- invalid value
{ "parent_id", 2 },
{ "desc", "moet fout gaan" } }),
std::exception);
}
// SECTION("two")
// {
// auto &cat1 = f.front()["cat_1"];
// auto &cat2 = f.front()["cat_2"];
// cat1.update_value(cif::all(), "id", [](std::string_view v) -> std::string
// {
// int vi;
// auto [ec, ptr] = std::from_chars(v.data(), v.data() + v.length(), vi);
// return std::to_string(vi + 1);
// });
// REQUIRE(cat1.find1<std::string>(cif::key("id") == 2, "name") == "Aap");
// REQUIRE(cat1.find1<std::string>(cif::key("id") == 3, "name") == "Noot");
// REQUIRE(cat1.find1<std::string>(cif::key("id") == 4, "name") == "Mies");
// REQUIRE(cat2.find1<int>(cif::key("id") == 1, "parent_id") == 2);
// REQUIRE(cat2.find1<int>(cif::key("id") == 2, "parent_id") == 2);
// REQUIRE(cat2.find1<int>(cif::key("id") == 3, "parent_id") == 3);
// }
}
// --------------------------------------------------------------------
@@ -3486,4 +3508,11 @@ TEST_CASE("pdb2cif_formula_weight")
fw = a.front()["entity"].find1<float>(cif::key("id") == 3, "formula_weight");
CHECK(fw == 18.015f);
}
// --------------------------------------------------------------------
TEST_CASE("update_values_with_provider")
{
}

View File

@@ -26,8 +26,6 @@
#include "test-main.hpp"
#include <catch2/catch.hpp>
#include <cif++.hpp>
#include <stdexcept>