Compare commits

..

37 Commits

Author SHA1 Message Date
Maarten L. Hekkelman
9dc5d11829 newer version string code, this should be final 2023-08-16 11:26:20 +02:00
Maarten L. Hekkelman
8565e1b408 Better version string 2023-08-15 13:27:10 +02:00
Maarten L. Hekkelman
bfc7133786 fix config
better version string implementation
2023-08-15 09:49:04 +02:00
Maarten L. Hekkelman
15a49f1bb4 Fix uncompressing concatenated gzip files 2023-08-04 09:51:11 +02:00
Maarten L. Hekkelman
db1dff16fe update changelog 2023-08-03 10:20:40 +02:00
Maarten L. Hekkelman
8d7d9d3a31 Fix for PDB files that do not terminate their last line with a new line character 2023-08-03 10:19:12 +02:00
Maarten L. Hekkelman
078bf8a559 stricter code 2023-07-31 10:48:47 +02:00
Maarten L. Hekkelman
1f314a5e9b removing compiler warnings on MSVC 2023-07-19 15:49:26 +02:00
Maarten L. Hekkelman
0adb50ac01 Add dependency on Eigen3 in config 2023-07-19 14:21:43 +02:00
Maarten L. Hekkelman
d91707cd06 Link to Eigen3 2023-07-19 14:11:22 +02:00
Maarten L. Hekkelman
c0e7ee4eeb small stuff 2023-07-18 15:25:44 +02:00
Pino Toscano
c143a7223e build: fix installation of cron script on GNU/Hurd (#46)
Use the same Linux paths, as the cron implementations available on
the Hurd as usually the same as Linux.
2023-07-16 12:01:17 +02:00
Maarten L. Hekkelman
2c951ba146 prevent downloading components.cif if it already exists 2023-06-20 13:47:13 +02:00
Maarten L. Hekkelman
660aadcd9c conditional include <compare> 2023-06-20 11:11:00 +02:00
Maarten L. Hekkelman
91d6adb980 Version bump 2023-06-20 09:48:27 +02:00
Maarten L. Hekkelman
b79ddd55c5 Update readme 2023-06-20 09:45:46 +02:00
Maarten L. Hekkelman
0ca645c634 right align number, if there was a dictionary loaded containing the required information 2023-06-20 08:48:40 +02:00
Maarten L. Hekkelman
676c0c8dc8 Added include compare for spaceship operator 2023-06-20 08:48:08 +02:00
Maarten L. Hekkelman
5c366ad9b1 - remove three_letter_code for CCP4 dictionaries
- fix test for equality of compound ID's, they are case insensitive you know
2023-06-13 11:42:39 +02:00
Maarten L. Hekkelman
836aed6ea9 Fix includes to contain <cstdint> 2023-06-08 13:15:43 +02:00
Maarten L. Hekkelman
50df250415 Merge branch 'develop' into trunk 2023-06-08 10:12:03 +02:00
Maarten L. Hekkelman
2409fc5b7b update changelog, version bump 2023-06-08 10:10:49 +02:00
Maarten L. Hekkelman
8a1184a24c Fix cif_id_for_number 2023-06-07 19:11:20 +02:00
Maarten L. Hekkelman
d2fbc54765 New cache location 2023-06-07 14:07:27 +02:00
Maarten L. Hekkelman
1bcb26ba75 extend validator
faster unique_id
2023-06-07 13:08:36 +02:00
Maarten L. Hekkelman
32f4749d84 faster cif parser 2023-06-07 11:19:35 +02:00
Maarten L. Hekkelman
da12be879a progress_bar consuming too much time 2023-06-07 09:15:17 +02:00
Maarten L. Hekkelman
94a38ad4e8 Merge branch 'develop' of github.com:PDB-REDO/libcifpp into develop 2023-06-06 14:31:26 +02:00
Maarten L. Hekkelman
20ef79a172 for c++17, limited version of std::string_view 2023-06-06 14:30:11 +02:00
Maarten L. Hekkelman
92bf25476e Speed improvements 2023-06-06 14:12:21 +02:00
Maarten L. Hekkelman
b55e074dd7 reserve some token buffer space 2023-06-06 09:33:31 +02:00
Maarten L. Hekkelman
7b654a837d with reserved words automaton 2023-06-06 09:22:55 +02:00
Maarten L. Hekkelman
ae9d247d22 optimised the parser a bit 2023-06-05 13:43:31 +02:00
Maarten L. Hekkelman
16b7deafe8 Better is_unquoted_string test 2023-06-02 17:09:57 +02:00
Maarten L. Hekkelman
f2cfe28458 Update README 2023-05-31 15:56:50 +02:00
Maarten L. Hekkelman
2e8a52949e Update example and README 2023-05-31 15:54:53 +02:00
Maarten L. Hekkelman
441e142767 Update readme 2023-05-31 15:42:54 +02:00
29 changed files with 1347 additions and 857 deletions

View File

@@ -25,7 +25,7 @@
cmake_minimum_required(VERSION 3.16)
# set the project name
project(cifpp VERSION 5.0.9 LANGUAGES CXX)
project(libcifpp VERSION 5.1.2 LANGUAGES CXX)
list(PREPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
@@ -98,33 +98,33 @@ if(BUILD_FOR_CCP4)
endif()
endif()
if(WIN32)
if(${CMAKE_SYSTEM_VERSION} GREATER_EQUAL 10) # Windows 10
add_definitions(-D _WIN32_WINNT=0x0A00)
elseif(${CMAKE_SYSTEM_VERSION} EQUAL 6.3) # Windows 8.1
add_definitions(-D _WIN32_WINNT=0x0603)
elseif(${CMAKE_SYSTEM_VERSION} EQUAL 6.2) # Windows 8
add_definitions(-D _WIN32_WINNT=0x0602)
elseif(${CMAKE_SYSTEM_VERSION} EQUAL 6.1) # Windows 7
add_definitions(-D _WIN32_WINNT=0x0601)
elseif(${CMAKE_SYSTEM_VERSION} EQUAL 6.0) # Windows Vista
add_definitions(-D _WIN32_WINNT=0x0600)
else() # Windows XP (5.1)
add_definitions(-D _WIN32_WINNT=0x0501)
endif()
add_definitions(-DNOMINMAX)
endif()
if(MSVC)
# make msvc standards compliant...
add_compile_options(/permissive-)
# make msvc standards compliant...
add_compile_options(/permissive-)
macro(get_WIN32_WINNT version)
if(CMAKE_SYSTEM_VERSION)
set(ver ${CMAKE_SYSTEM_VERSION})
string(REGEX MATCH "^([0-9]+).([0-9])" ver ${ver})
string(REGEX MATCH "^([0-9]+)" verMajor ${ver})
# Check for Windows 10, b/c we'll need to convert to hex 'A'.
if("${verMajor}" MATCHES "10")
set(verMajor "A")
string(REGEX REPLACE "^([0-9]+)" ${verMajor} ver ${ver})
endif()
# Remove all remaining '.' characters.
string(REPLACE "." "" ver ${ver})
# Prepend each digit with a zero.
string(REGEX REPLACE "([0-9A-Z])" "0\\1" ver ${ver})
set(${version} "0x${ver}")
endif()
endmacro()
get_WIN32_WINNT(ver)
add_definitions(-D_WIN32_WINNT=${ver})
if(BUILD_SHARED_LIBS)
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL")
else()
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
endif()
endif()
# Libraries
@@ -197,7 +197,7 @@ endif()
# Create a revision file, containing the current git version info
include(VersionString)
write_version_header(${PROJECT_SOURCE_DIR}/src/ "LibCIFPP")
write_version_header(${PROJECT_SOURCE_DIR}/src/ LIB_NAME "LibCIFPP")
# SymOp data table
if(CIFPP_RECREATE_SYMOP_DATA)
@@ -292,7 +292,7 @@ target_include_directories(cifpp
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
)
target_link_libraries(cifpp PUBLIC Threads::Threads ZLIB::ZLIB ${CIFPP_REQUIRED_LIBRARIES})
target_link_libraries(cifpp PUBLIC Threads::Threads ZLIB::ZLIB Eigen3::Eigen ${CIFPP_REQUIRED_LIBRARIES})
if(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
target_link_options(cifpp PRIVATE -undefined dynamic_lookup)
@@ -307,18 +307,7 @@ if(CIFPP_DOWNLOAD_CCD)
file(MAKE_DIRECTORY ${PROJECT_SOURCE_DIR}/data/)
endif()
find_program(GUNZIP gunzip)
if(GUNZIP)
file(DOWNLOAD ftp://ftp.wwpdb.org/pub/pdb/data/monomers/components.cif.gz ${COMPONENTS_CIF}.gz
SHOW_PROGRESS)
add_custom_command(OUTPUT ${COMPONENTS_CIF}
COMMAND ${GUNZIP} ${COMPONENTS_CIF}.gz
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/data/)
else()
file(DOWNLOAD ftp://ftp.wwpdb.org/pub/pdb/data/monomers/components.cif ${COMPONENTS_CIF}
SHOW_PROGRESS)
endif()
file(DOWNLOAD https://ftp.wwpdb.org/pub/pdb/data/monomers/components.cif ${COMPONENTS_CIF} SHOW_PROGRESS)
endif()
add_custom_target(COMPONENTS ALL DEPENDS ${COMPONENTS_CIF})
@@ -382,6 +371,16 @@ install(FILES
DESTINATION ${CIFPP_DATA_DIR}
)
if(${CIFPP_CACHE_DIR})
install(FILES
${PROJECT_SOURCE_DIR}/rsrc/mmcif_ddl.dic
${PROJECT_SOURCE_DIR}/rsrc/mmcif_pdbx.dic
${PROJECT_SOURCE_DIR}/rsrc/mmcif_ma.dic
${COMPONENTS_CIF}
DESTINATION ${CIFPP_CACHE_DIR}
)
endif()
set(CONFIG_TEMPLATE_FILE ${PROJECT_SOURCE_DIR}/cmake/cifppConfig.cmake.in)
configure_package_config_file(
@@ -459,7 +458,7 @@ endif()
# Optionally install the update scripts for CCD and dictionary files
if(CIFPP_INSTALL_UPDATE_SCRIPT)
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR ${CMAKE_SYSTEM_NAME} STREQUAL "GNU")
set(CIFPP_CRON_DIR "${CIFPP_ETC_DIR}/cron.weekly")
elseif(UNIX) # assume all others are like FreeBSD...
set(CIFPP_CRON_DIR "${CIFPP_ETC_DIR}/periodic/weekly")

View File

@@ -3,18 +3,85 @@ libcifpp
This library contains code to work with mmCIF and PDB files.
Synopsis
--------
```c++
// A simple program counting residues with an OXT atom
#include <filesystem>
#include <iostream>
#include <cif++.hpp>
namespace fs = std::filesystem;
int main(int argc, char *argv[])
{
if (argc != 2)
exit(1);
// Read file, can be PDB or mmCIF and can even be compressed with gzip.
cif::file file = cif::pdb::read(argv[1]);
if (file.empty())
{
std::cerr << "Empty file" << std::endl;
exit(1);
}
// Take the first datablock in the file
auto &db = file.front();
// Use the atom_site category
auto &atom_site = db["atom_site"];
// Count the atoms with atom-id "OXT"
auto n = atom_site.count(cif::key("label_atom_id") == "OXT");
std::cout << "File contains " << atom_site.size() << " atoms of which "
<< n << (n == 1 ? " is" : " are") << " OXT" << std::endl
<< "residues with an OXT are:" << std::endl;
// Loop over all atoms with atom-id "OXT" and print out some info.
// That info is extracted using structured binding in C++
for (const auto &[asym, comp, seqnr] :
atom_site.find<std::string, std::string, int>(
cif::key("label_atom_id") == "OXT",
"label_asym_id", "label_comp_id", "label_seq_id"))
{
std::cout << asym << ' ' << comp << ' ' << seqnr << std::endl;
}
return 0;
}
```
Requirements
------------
The code for this library was written in C++17. You therefore need a
recent compiler to build it. For the development gcc 9.3 and clang 9.0
recent compiler to build it. For the development gcc 9.4 and clang 9.0
have been used as well as MSVC version 2019.
Other requirements are:
- [mrc](https://github.com/mhekkel/mrc), a resource compiler that
allows including data files into the executable making them easier to
install. Strictly this is optional, but at the expense of functionality.
install. Strictly speaking this is optional, but at the expense of
functionality.
- [libeigen](https://eigen.tuxfamily.org/index.php?title=Main_Page), a
library to do amongst others matrix calculations. This usually can be
installed using your package manager, in Debian/Ubuntu it is called
`libeigen3-dev`
- zlib, the development version of this library. On Debian/Ubuntu this
is the package `zlib1g-dev`.
- [boost](https://www.boost.org). The boost libraries are only needed if
you want to build the testing code.
When building using MS Visual Studio, you will also need [libzeep](https://github.com/mhekkel/libzeep)
since MSVC does not yet provide a C++ template required by libcifpp.
Building
--------
@@ -26,7 +93,7 @@ On linux e.g. you would issue the following commands to build and install
libcifpp in your `$HOME/.local` folder:
```bash
git clone https://github.com/PDB-REDO/libcifpp.git
git clone https://github.com/PDB-REDO/libcifpp.git --recurse-submodules
cd libcifpp
cmake -S . -B build -DCMAKE_INSTALL_PREFIX=$HOME/.local -DCMAKE_BUILD_TYPE=Release
cmake --build build

View File

@@ -1,3 +1,21 @@
Version 5.1.2
- New version string code
- Added check for Eigen3 in cifppConfig.cmake
Version 5.1.1
- Added missing include <compare> in symmetry.hpp
- Added empty() to matrix
- Fix for parsing PDB files with a last line that does not end with
a new line character.
Version 5.1
- New parser, optimised for speed
- Fix in unique ID generator
Version 5.0.10
- Fix in progress_bar, was using too much CPU
- Optimised mmCIF parser
Version 5.0.9
- Fix in dihedral angle calculations
- Added create_water to model

View File

@@ -1,284 +0,0 @@
# - Returns a version string from Git
#
# These functions force a re-configure on each git commit so that you can
# trust the values of the variables in your build system.
#
# get_git_head_revision(<refspecvar> <hashvar> [ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR])
#
# Returns the refspec and sha hash of the current head revision
#
# git_describe(<var> [<additional arguments to git describe> ...])
#
# Returns the results of git describe on the source tree, and adjusting
# the output so that it tests false if an error occurs.
#
# git_describe_working_tree(<var> [<additional arguments to git describe> ...])
#
# Returns the results of git describe on the working tree (--dirty option),
# and adjusting the output so that it tests false if an error occurs.
#
# git_get_exact_tag(<var> [<additional arguments to git describe> ...])
#
# Returns the results of git describe --exact-match on the source tree,
# and adjusting the output so that it tests false if there was no exact
# matching tag.
#
# git_local_changes(<var>)
#
# Returns either "CLEAN" or "DIRTY" with respect to uncommitted changes.
# Uses the return code of "git diff-index --quiet HEAD --".
# Does not regard untracked files.
#
# Requires CMake 2.6 or newer (uses the 'function' command)
#
# Original Author:
# 2009-2020 Ryan Pavlik <ryan.pavlik@gmail.com> <abiryan@ryand.net>
# http://academic.cleardefinition.com
#
# Copyright 2009-2013, Iowa State University.
# Copyright 2013-2020, Ryan Pavlik
# Copyright 2013-2020, Contributors
# SPDX-License-Identifier: BSL-1.0
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or copy at
# http://www.boost.org/LICENSE_1_0.txt)
if(__get_git_revision_description)
return()
endif()
set(__get_git_revision_description YES)
# We must run the following at "include" time, not at function call time,
# to find the path to this module rather than the path to a calling list file
get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH)
# Function _git_find_closest_git_dir finds the next closest .git directory
# that is part of any directory in the path defined by _start_dir.
# The result is returned in the parent scope variable whose name is passed
# as variable _git_dir_var. If no .git directory can be found, the
# function returns an empty string via _git_dir_var.
#
# Example: Given a path C:/bla/foo/bar and assuming C:/bla/.git exists and
# neither foo nor bar contain a file/directory .git. This wil return
# C:/bla/.git
#
function(_git_find_closest_git_dir _start_dir _git_dir_var)
set(cur_dir "${_start_dir}")
set(git_dir "${_start_dir}/.git")
while(NOT EXISTS "${git_dir}")
# .git dir not found, search parent directories
set(git_previous_parent "${cur_dir}")
get_filename_component(cur_dir "${cur_dir}" DIRECTORY)
if(cur_dir STREQUAL git_previous_parent)
# We have reached the root directory, we are not in git
set(${_git_dir_var}
""
PARENT_SCOPE)
return()
endif()
set(git_dir "${cur_dir}/.git")
endwhile()
set(${_git_dir_var}
"${git_dir}"
PARENT_SCOPE)
endfunction()
function(get_git_head_revision _refspecvar _hashvar)
_git_find_closest_git_dir("${CMAKE_CURRENT_SOURCE_DIR}" GIT_DIR)
if("${ARGN}" STREQUAL "ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR")
set(ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR TRUE)
else()
set(ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR FALSE)
endif()
if(NOT "${GIT_DIR}" STREQUAL "")
file(RELATIVE_PATH _relative_to_source_dir "${CMAKE_SOURCE_DIR}"
"${GIT_DIR}")
if("${_relative_to_source_dir}" MATCHES "[.][.]" AND NOT ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR)
# We've gone above the CMake root dir.
set(GIT_DIR "")
endif()
endif()
if("${GIT_DIR}" STREQUAL "")
set(${_refspecvar}
"GITDIR-NOTFOUND"
PARENT_SCOPE)
set(${_hashvar}
"GITDIR-NOTFOUND"
PARENT_SCOPE)
return()
endif()
# Check if the current source dir is a git submodule or a worktree.
# In both cases .git is a file instead of a directory.
#
if(NOT IS_DIRECTORY ${GIT_DIR})
# The following git command will return a non empty string that
# points to the super project working tree if the current
# source dir is inside a git submodule.
# Otherwise the command will return an empty string.
#
execute_process(
COMMAND "${GIT_EXECUTABLE}" rev-parse
--show-superproject-working-tree
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
OUTPUT_VARIABLE out
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
if(NOT "${out}" STREQUAL "")
# If out is empty, GIT_DIR/CMAKE_CURRENT_SOURCE_DIR is in a submodule
file(READ ${GIT_DIR} submodule)
string(REGEX REPLACE "gitdir: (.*)$" "\\1" GIT_DIR_RELATIVE
${submodule})
string(STRIP ${GIT_DIR_RELATIVE} GIT_DIR_RELATIVE)
get_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH)
get_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE}
ABSOLUTE)
set(HEAD_SOURCE_FILE "${GIT_DIR}/HEAD")
else()
# GIT_DIR/CMAKE_CURRENT_SOURCE_DIR is in a worktree
file(READ ${GIT_DIR} worktree_ref)
# The .git directory contains a path to the worktree information directory
# inside the parent git repo of the worktree.
#
string(REGEX REPLACE "gitdir: (.*)$" "\\1" git_worktree_dir
${worktree_ref})
string(STRIP ${git_worktree_dir} git_worktree_dir)
_git_find_closest_git_dir("${git_worktree_dir}" GIT_DIR)
set(HEAD_SOURCE_FILE "${git_worktree_dir}/HEAD")
endif()
else()
set(HEAD_SOURCE_FILE "${GIT_DIR}/HEAD")
endif()
set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data")
if(NOT EXISTS "${GIT_DATA}")
file(MAKE_DIRECTORY "${GIT_DATA}")
endif()
if(NOT EXISTS "${HEAD_SOURCE_FILE}")
return()
endif()
set(HEAD_FILE "${GIT_DATA}/HEAD")
configure_file("${HEAD_SOURCE_FILE}" "${HEAD_FILE}" COPYONLY)
configure_file("${_gitdescmoddir}/GetGitRevisionDescription.cmake.in"
"${GIT_DATA}/grabRef.cmake" @ONLY)
include("${GIT_DATA}/grabRef.cmake")
set(${_refspecvar}
"${HEAD_REF}"
PARENT_SCOPE)
set(${_hashvar}
"${HEAD_HASH}"
PARENT_SCOPE)
endfunction()
function(git_describe _var)
if(NOT GIT_FOUND)
find_package(Git QUIET)
endif()
get_git_head_revision(refspec hash)
if(NOT GIT_FOUND)
set(${_var}
"GIT-NOTFOUND"
PARENT_SCOPE)
return()
endif()
if(NOT hash)
set(${_var}
"HEAD-HASH-NOTFOUND"
PARENT_SCOPE)
return()
endif()
# TODO sanitize
#if((${ARGN}" MATCHES "&&") OR
# (ARGN MATCHES "||") OR
# (ARGN MATCHES "\\;"))
# message("Please report the following error to the project!")
# message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}")
#endif()
#message(STATUS "Arguments to execute_process: ${ARGN}")
execute_process(
COMMAND "${GIT_EXECUTABLE}" describe --tags --always ${hash} ${ARGN}
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
RESULT_VARIABLE res
OUTPUT_VARIABLE out
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
if(NOT res EQUAL 0)
set(out "${out}-${res}-NOTFOUND")
endif()
set(${_var}
"${out}"
PARENT_SCOPE)
endfunction()
function(git_describe_working_tree _var)
if(NOT GIT_FOUND)
find_package(Git QUIET)
endif()
if(NOT GIT_FOUND)
set(${_var}
"GIT-NOTFOUND"
PARENT_SCOPE)
return()
endif()
execute_process(
COMMAND "${GIT_EXECUTABLE}" describe --dirty ${ARGN}
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
RESULT_VARIABLE res
OUTPUT_VARIABLE out
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
if(NOT res EQUAL 0)
set(out "${out}-${res}-NOTFOUND")
endif()
set(${_var}
"${out}"
PARENT_SCOPE)
endfunction()
function(git_get_exact_tag _var)
git_describe(out --exact-match ${ARGN})
set(${_var}
"${out}"
PARENT_SCOPE)
endfunction()
function(git_local_changes _var)
if(NOT GIT_FOUND)
find_package(Git QUIET)
endif()
get_git_head_revision(refspec hash)
if(NOT GIT_FOUND)
set(${_var}
"GIT-NOTFOUND"
PARENT_SCOPE)
return()
endif()
if(NOT hash)
set(${_var}
"HEAD-HASH-NOTFOUND"
PARENT_SCOPE)
return()
endif()
execute_process(
COMMAND "${GIT_EXECUTABLE}" diff-index --quiet HEAD --
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
RESULT_VARIABLE res
OUTPUT_VARIABLE out
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
if(res EQUAL 0)
set(${_var}
"CLEAN"
PARENT_SCOPE)
else()
set(${_var}
"DIRTY"
PARENT_SCOPE)
endif()
endfunction()

View File

@@ -1,43 +0,0 @@
#
# Internal file for GetGitRevisionDescription.cmake
#
# Requires CMake 2.6 or newer (uses the 'function' command)
#
# Original Author:
# 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
# http://academic.cleardefinition.com
# Iowa State University HCI Graduate Program/VRAC
#
# Copyright 2009-2012, Iowa State University
# Copyright 2011-2015, Contributors
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or copy at
# http://www.boost.org/LICENSE_1_0.txt)
# SPDX-License-Identifier: BSL-1.0
set(HEAD_HASH)
file(READ "@HEAD_FILE@" HEAD_CONTENTS LIMIT 1024)
string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS)
if(HEAD_CONTENTS MATCHES "ref")
# named branch
string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}")
if(EXISTS "@GIT_DIR@/${HEAD_REF}")
configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY)
else()
configure_file("@GIT_DIR@/packed-refs" "@GIT_DATA@/packed-refs" COPYONLY)
file(READ "@GIT_DATA@/packed-refs" PACKED_REFS)
if(${PACKED_REFS} MATCHES "([0-9a-z]*) ${HEAD_REF}")
set(HEAD_HASH "${CMAKE_MATCH_1}")
endif()
endif()
else()
# detached HEAD
configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY)
endif()
if(NOT HEAD_HASH)
file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024)
string(STRIP "${HEAD_HASH}" HEAD_HASH)
endif()

View File

@@ -1,6 +1,6 @@
# SPDX-License-Identifier: BSD-2-Clause
# Copyright (c) 2021 NKI/AVL, Netherlands Cancer Institute
# Copyright (c) 2021-2023 Maarten L. Hekkelman
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
@@ -22,60 +22,374 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# This cmake extension writes out a revision.hpp file in a specified directory.
# The file will contain a C++ inline function that can be used to write out
# version information.
cmake_minimum_required(VERSION 3.15)
# We want the revision.hpp file to be updated whenever the status of the
# git repository changes. Use the same technique as in GetGitRevisionDescription.cmake
# from https://github.com/rpavlik/cmake-modules
#[=======================================================================[.rst:
.. command:: write_version_header
Write a file named revision.hpp containing version info::
write_version_header(<destdir>
[FILE_NAME <file-name>]
[LIB_NAME <library-name>]
)
This command will generate the code to write a file name
revision.hpp in the directory ``<destdir>``.
``FILE_NAME``
Specify the name of the file to create, default is ``revision.hpp``.
``LIB_NAME``
Specify the library name which will be used as a prefix part for the
variables contained in the revision file.
#]=======================================================================]
# First locate a .git file or directory.
function(_get_git_dir _start_dir _variable)
set(cur_dir "${_start_dir}")
set(git_dir "${_start_dir}/.git")
while(NOT EXISTS "${git_dir}")
# .git dir not found, search parent directories
set(prev_dir "${cur_dir}")
get_filename_component(cur_dir "${cur_dir}" DIRECTORY)
if(cur_dir STREQUAL prev_dir OR cur_dir STREQUAL ${_start_dir})
# we are not in git since we either hit root or
# the ${_start_dir} which should be the top
set(${_variable} "" PARENT_SCOPE)
return()
endif()
set(git_dir "${cur_dir}/.git")
endwhile()
set(${_variable} "${git_dir}" PARENT_SCOPE)
endfunction()
# Locate the git refspec hash and load the hash
# This code locates the file containing the git refspec/hash
# and loads it. Doing it this way assures that each time the git
# repository changes the revision.hpp file gets out of date.
function(_get_git_hash _data_dir _variable)
# Be pessimistic
set(_variable "" PARENT_SCOPE)
# Load git package if needed
if(NOT GIT_FOUND)
find_package(Git QUIET)
endif()
# And fail if not found
if(NOT GIT_FOUND)
return()
endif()
# Locate the nearest .git file or directory
_get_git_dir(${CMAKE_CURRENT_SOURCE_DIR} GIT_DIR)
# And fail if not found
if("${GIT_DIR}" STREQUAL "")
return()
endif()
# Check if the current source dir is a git submodule or a worktree.
# In both cases .git is a file instead of a directory.
#
if(IS_DIRECTORY ${GIT_DIR})
set(HEAD_SOURCE_FILE "${GIT_DIR}/HEAD")
else()
# The following git command will return a non empty string that
# points to the super project working tree if the current
# source dir is inside a git submodule.
# Otherwise the command will return an empty string.
#
execute_process(
COMMAND "${GIT_EXECUTABLE}" rev-parse
--show-superproject-working-tree
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
OUTPUT_VARIABLE out
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
if(NOT "${out}" STREQUAL "")
# If out is not empty, GIT_DIR/CMAKE_CURRENT_SOURCE_DIR is in a submodule
file(READ ${GIT_DIR} submodule)
string(REGEX REPLACE "gitdir: (.*)$" "\\1" GIT_DIR_RELATIVE
${submodule})
string(STRIP ${GIT_DIR_RELATIVE} GIT_DIR_RELATIVE)
get_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH)
get_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE}
ABSOLUTE)
set(HEAD_SOURCE_FILE "${GIT_DIR}/HEAD")
else()
# GIT_DIR/CMAKE_CURRENT_SOURCE_DIR is in a worktree
file(READ ${GIT_DIR} worktree_ref)
# The .git directory contains a path to the worktree information directory
# inside the parent git repo of the worktree.
#
string(REGEX REPLACE "gitdir: (.*)$" "\\1" git_worktree_dir
${worktree_ref})
string(STRIP ${git_worktree_dir} git_worktree_dir)
_get_git_dir("${git_worktree_dir}" GIT_DIR)
set(HEAD_SOURCE_FILE "${git_worktree_dir}/HEAD")
endif()
endif()
# Fail if the 'head' file was not found
if(NOT EXISTS "${HEAD_SOURCE_FILE}")
return()
endif()
# Make a copy of the head file
set(HEAD_FILE "${_data_dir}/HEAD")
configure_file("${HEAD_SOURCE_FILE}" "${HEAD_FILE}" COPYONLY)
# Now we create a cmake file that will read the contents of this
# head file in the appropriate way
file(WRITE "${_data_dir}/grab-ref.cmake.in" [[
set(HEAD_HASH)
file(READ "@HEAD_FILE@" HEAD_CONTENTS LIMIT 1024)
string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS)
if(HEAD_CONTENTS MATCHES "ref")
# named branch
string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}")
if(EXISTS "@GIT_DIR@/${HEAD_REF}")
configure_file("@GIT_DIR@/${HEAD_REF}" "@VERSION_STRING_DATA@/head-ref" COPYONLY)
else()
configure_file("@GIT_DIR@/packed-refs" "@VERSION_STRING_DATA@/packed-refs" COPYONLY)
file(READ "@VERSION_STRING_DATA@/packed-refs" PACKED_REFS)
if(${PACKED_REFS} MATCHES "([0-9a-z]*) ${HEAD_REF}")
set(HEAD_HASH "${CMAKE_MATCH_1}")
endif()
endif()
else()
# detached HEAD
configure_file("@GIT_DIR@/HEAD" "@VERSION_STRING_DATA@/head-ref" COPYONLY)
endif()
if(NOT HEAD_HASH)
file(READ "@VERSION_STRING_DATA@/head-ref" HEAD_HASH LIMIT 1024)
string(STRIP "${HEAD_HASH}" HEAD_HASH)
endif()
]])
configure_file("${VERSION_STRING_DATA}/grab-ref.cmake.in"
"${VERSION_STRING_DATA}/grab-ref.cmake" @ONLY)
# Include the aforementioned file, this will define
# the HEAD_HASH variable we're looking for
include("${VERSION_STRING_DATA}/grab-ref.cmake")
set(${_variable} "${HEAD_HASH}" PARENT_SCOPE)
endfunction()
# Create a revision file, containing the current git version info, if any
function(write_version_header dir)
set(flags )
set(options LIB_NAME FILE_NAME)
set(sources )
cmake_parse_arguments(VERSION_STRING_OPTION "${flags}" "${options}" "${sources}" ${ARGN})
# parameter check
if(NOT IS_DIRECTORY ${dir})
message(FATAL_ERROR "First parameter to write_version_header should be a directory where the final revision.hpp file will be placed")
endif()
include(GetGitRevisionDescription)
if(NOT(GIT-NOTFOUND OR HEAD-HASH-NOTFOUND))
git_describe_working_tree(BUILD_VERSION_STRING --match=build --dirty)
if(BUILD_VERSION_STRING MATCHES "build-([0-9]+)-g([0-9a-f]+)(-dirty)?")
set(BUILD_GIT_TAGREF "${CMAKE_MATCH_2}")
if(CMAKE_MATCH_3)
set(BUILD_VERSION_STRING "${CMAKE_MATCH_1}*")
else()
set(BUILD_VERSION_STRING "${CMAKE_MATCH_1}")
endif()
endif()
if(VERSION_STRING_OPTION_FILE_NAME)
set(file_name "${VERSION_STRING_OPTION_FILE_NAME}")
else()
message(WARNING "no git info available, cannot update version string")
set(file_name "revision.hpp")
endif()
string(TIMESTAMP BUILD_DATE_TIME "%Y-%m-%dT%H:%M:%SZ" UTC)
# Where to store intermediate files
set(VERSION_STRING_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/VersionString")
if(NOT EXISTS "${VERSION_STRING_DATA}")
file(MAKE_DIRECTORY "${VERSION_STRING_DATA}")
endif()
if(ARGC GREATER 1)
set(VAR_PREFIX "${ARGV1}")
# Load the git hash using the wizzard-like code above.
_get_git_hash("${VERSION_STRING_DATA}" GIT_HASH)
# If git was found, fetch the git description string
if(GIT_HASH)
execute_process(
COMMAND "${GIT_EXECUTABLE}" describe --dirty --match=build
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
RESULT_VARIABLE res
OUTPUT_VARIABLE out
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
if(res EQUAL 0)
set(REVISION_STRING "${out}")
endif()
endif()
file(WRITE "${PROJECT_BINARY_DIR}/revision.hpp.in" [[// Generated revision file
# Check the revision string, if it matches we fill in the required info
if(REVISION_STRING MATCHES "build-([0-9]+)-g([0-9a-f]+)(-dirty)?")
set(BUILD_NUMBER ${CMAKE_MATCH_1})
if(CMAKE_MATCH_3)
set(REVISION_GIT_TAGREF "${CMAKE_MATCH_2}*")
else()
set(REVISION_GIT_TAGREF "${CMAKE_MATCH_2}")
endif()
string(TIMESTAMP REVISION_DATE_TIME "%Y-%m-%dT%H:%M:%SZ" UTC)
else()
set(REVISION_GIT_TAGREF "")
set(BUILD_NUMBER 0)
set(REVISION_DATE_TIME "")
endif()
if(VERSION_STRING_OPTION_LIB_NAME)
set(VAR_PREFIX "${VERSION_STRING_OPTION_LIB_NAME}")
set(IDENT_PREFIX "${VERSION_STRING_OPTION_LIB_NAME}_")
else()
set(VAR_PREFIX "")
set(IDENT_PREFIX "")
endif()
# And finally, write out the header file
file(WRITE "${VERSION_STRING_DATA}/${file_name}.in" [[// This file was generated by VersionString.cmake
#pragma once
#include <ostream>
const char k@VAR_PREFIX@ProjectName[] = "@PROJECT_NAME@";
const char k@VAR_PREFIX@VersionNumber[] = "@PROJECT_VERSION@";
const char k@VAR_PREFIX@VersionGitTag[] = "@BUILD_GIT_TAGREF@";
const char k@VAR_PREFIX@BuildInfo[] = "@BUILD_VERSION_STRING@";
const char k@VAR_PREFIX@BuildDate[] = "@BUILD_DATE_TIME@";
constexpr const char k@VAR_PREFIX@ProjectName[] = "@PROJECT_NAME@";
constexpr const char k@VAR_PREFIX@VersionNumber[] = "@PROJECT_VERSION@";
constexpr int k@VAR_PREFIX@BuildNumber = @BUILD_NUMBER@;
constexpr const char k@VAR_PREFIX@RevisionGitTag[] = "@REVISION_GIT_TAGREF@";
constexpr const char k@VAR_PREFIX@RevisionDate[] = "@REVISION_DATE_TIME@";
#ifndef VERSION_INFO_DEFINED
#define VERSION_INFO_DEFINED 1
namespace version_info_v1
{
class version_info_base
{
public:
static void write(std::ostream &os, bool verbose)
{
auto &s_head = head();
if (s_head != nullptr)
write(s_head, os, verbose);
}
protected:
version_info_base(const char *name, const char *version, int build_number, const char *git_tag, const char *revision_date)
: m_name(name)
, m_version(version)
, m_build_number(build_number)
, m_git_tag(git_tag)
, m_revision_date(revision_date)
{
auto &s_head = head();
m_next = s_head;
s_head = this;
}
static void write(const version_info_base *inst, std::ostream &os, bool verbose)
{
if (inst->m_next)
{
write(inst->m_next, os, verbose);
if (not verbose)
return;
os << '-' << std::endl;
}
os << inst->m_name << " version " << inst->m_version << std::endl;
if (verbose)
{
if (inst->m_build_number != 0)
{
os << "build: " << inst->m_build_number << ' ' << inst->m_revision_date << std::endl;
if (inst->m_git_tag[0] != 0)
os << "git tag: " << inst->m_git_tag << std::endl;
}
}
}
using version_info_ptr = version_info_base *;
static version_info_ptr &head()
{
static version_info_ptr s_head = nullptr;
return s_head;
}
const char *m_name;
const char *m_version;
int m_build_number;
const char *m_git_tag;
const char *m_revision_date;
version_info_base *m_next = nullptr;
};
template<typename T>
class version_info : public version_info_base
{
public:
using implementation_type = T;
version_info(const char *name, const char *version, int build_number, const char *git_tag, const char *revision_date)
: version_info_base(name, version, build_number, git_tag, revision_date)
{
}
struct register_object
{
register_object()
{
static implementation_type s_instance;
}
};
template<register_object&> struct reference_object;
static register_object s_registered_object;
static reference_object<s_registered_object> s_referenced_object;
};
template<typename T> typename version_info<T>::register_object version_info<T>::s_registered_object;
}
inline void write_version_string(std::ostream &os, bool verbose)
{
os << k@VAR_PREFIX@ProjectName << " version " << k@VAR_PREFIX@VersionNumber << std::endl;
if (verbose)
{
os << "build: " << k@VAR_PREFIX@BuildInfo << ' ' << k@VAR_PREFIX@BuildDate << std::endl;
if (k@VAR_PREFIX@VersionGitTag[0] != 0)
os << "git tag: " << k@VAR_PREFIX@VersionGitTag << std::endl;
}
version_info_v1::version_info_base::write(os, verbose);
}
#endif
class version_info_@IDENT_PREFIX@impl : public version_info_v1::version_info<version_info_@IDENT_PREFIX@impl>
{
public:
version_info_@IDENT_PREFIX@impl()
: version_info(k@VAR_PREFIX@ProjectName, k@VAR_PREFIX@VersionNumber, k@VAR_PREFIX@BuildNumber, k@VAR_PREFIX@RevisionGitTag, k@VAR_PREFIX@RevisionDate)
{
}
};
]])
configure_file("${PROJECT_BINARY_DIR}/revision.hpp.in" "${dir}/revision.hpp" @ONLY)
configure_file("${VERSION_STRING_DATA}/${file_name}.in" "${dir}/${file_name}" @ONLY)
endfunction()

View File

@@ -1,16 +1,20 @@
@PACKAGE_INIT@
include("${CMAKE_CURRENT_LIST_DIR}/cifppTargets.cmake")
# Note that this set_and_check needs te be executed before
# find_dependency of Eigen3, otherwise the path is
# not found....
set_and_check(CIFPP_SHARE_DIR "@PACKAGE_CIFPP_DATA_DIR@")
include(CMakeFindDependencyMacro)
find_dependency(Threads)
find_dependency(ZLIB REQUIRED)
find_dependency(Eigen3 REQUIRED)
if(MSVC)
find_dependency(zeep REQUIRED)
endif()
INCLUDE("${CMAKE_CURRENT_LIST_DIR}/cifppTargets.cmake")
set_and_check(CIFPP_SHARE_DIR "@PACKAGE_CIFPP_DATA_DIR@")
check_required_components(cifpp)

View File

@@ -1,24 +1,32 @@
#include <iostream>
#include <filesystem>
#include <iostream>
#include <cif++.hpp>
namespace fs = std::filesystem;
int main()
int main(int argc, char *argv[])
{
cif::file file;
file.load("1cbs.cif.gz");
if (argc != 2)
exit(1);
auto& db = file.front();
cif::file file = cif::pdb::read(argv[1]);
if (file.empty())
{
std::cerr << "Empty file" << std::endl;
exit(1);
}
auto &db = file.front();
auto &atom_site = db["atom_site"];
auto n = atom_site.find(cif::key("label_atom_id") == "OXT").size();
std::cout << "File contains " << atom_site.size() << " atoms of which " << n << (n == 1 ? " is" : " are") << " OXT" << std::endl
<< "residues with an OXT are:" << std::endl;
for (const auto& [asym, comp, seqnr]: atom_site.find<std::string,std::string,int>(
cif::key("label_atom_id") == "OXT", "label_asym_id", "label_comp_id", "label_seq_id"))
<< "residues with an OXT are:" << std::endl;
for (const auto &[asym, comp, seqnr] : atom_site.find<std::string, std::string, int>(
cif::key("label_atom_id") == "OXT", "label_asym_id", "label_comp_id", "label_seq_id"))
{
std::cout << asym << ' ' << comp << ' ' << seqnr << std::endl;
}

View File

@@ -32,5 +32,6 @@ namespace cif
{
validator parse_dictionary(std::string_view name, std::istream &is);
void extend_dictionary(validator &v, std::istream &is);
} // namespace cif

View File

@@ -246,10 +246,13 @@ class basic_igzip_streambuf : public basic_streambuf<CharT, Traits>
zstream.avail_in = static_cast<uInt>(this->m_upstream->sgetn(m_in_buffer.data(), m_in_buffer.size()));
}
if (zstream.avail_in == 0)
break;
int err = ::inflate(&zstream, Z_SYNC_FLUSH);
std::streamsize n = kBufferByteSize - zstream.avail_out;
if (err == Z_STREAM_END or (err == Z_OK and n > 0))
if (n > 0)
{
this->setg(
m_out_buffer.data(),
@@ -258,6 +261,9 @@ class basic_igzip_streambuf : public basic_streambuf<CharT, Traits>
break;
}
if (err == Z_STREAM_END and zstream.avail_in > 0)
err = ::inflateReset2(&zstream, 47);
if (err < Z_OK)
break;
}

View File

@@ -44,22 +44,24 @@ template <typename M>
class matrix_expression
{
public:
constexpr uint32_t dim_m() const { return static_cast<const M &>(*this).dim_m(); }
constexpr uint32_t dim_n() const { return static_cast<const M &>(*this).dim_n(); }
constexpr size_t dim_m() const { return static_cast<const M &>(*this).dim_m(); }
constexpr size_t dim_n() const { return static_cast<const M &>(*this).dim_n(); }
constexpr auto &operator()(uint32_t i, uint32_t j)
constexpr bool empty() const { return dim_m() == 0 or dim_n() == 0; }
constexpr auto &operator()(size_t i, size_t j)
{
return static_cast<M &>(*this).operator()(i, j);
}
constexpr auto operator()(uint32_t i, uint32_t j) const
constexpr auto operator()(size_t i, size_t j) const
{
return static_cast<const M &>(*this).operator()(i, j);
}
void swap_row(uint32_t r1, uint32_t r2)
void swap_row(size_t r1, size_t r2)
{
for (uint32_t c = 0; c < dim_m(); ++c)
for (size_t c = 0; c < dim_m(); ++c)
{
auto v = operator()(r1, c);
operator()(r1, c) = operator()(r2, c);
@@ -67,9 +69,9 @@ class matrix_expression
}
}
void swap_col(uint32_t c1, uint32_t c2)
void swap_col(size_t c1, size_t c2)
{
for (uint32_t r = 0; r < dim_n(); ++r)
for (size_t r = 0; r < dim_n(); ++r)
{
auto &a = operator()(r, c1);
auto &b = operator()(r, c2);
@@ -120,9 +122,9 @@ class matrix : public matrix_expression<matrix<F>>
, m_n(m.dim_n())
, m_data(m_m * m_n)
{
for (uint32_t i = 0; i < m_m; ++i)
for (size_t i = 0; i < m_m; ++i)
{
for (uint32_t j = 0; j < m_n; ++j)
for (size_t j = 0; j < m_n; ++j)
operator()(i, j) = m(i, j);
}
}
@@ -178,9 +180,9 @@ class matrix_fixed : public matrix_expression<matrix_fixed<F, M, N>>
matrix_fixed(const M2 &m)
{
assert(M == m.dim_m() and N == m.dim_n());
for (uint32_t i = 0; i < M; ++i)
for (size_t i = 0; i < M; ++i)
{
for (uint32_t j = 0; j < N; ++j)
for (size_t j = 0; j < N; ++j)
operator()(i, j) = m(i, j);
}
}
@@ -242,7 +244,7 @@ class symmetric_matrix : public matrix_expression<symmetric_matrix<F>>
public:
using value_type = F;
symmetric_matrix(uint32_t n, value_type v = 0)
symmetric_matrix(size_t n, value_type v = 0)
: m_n(n)
, m_data((m_n * (m_n + 1)) / 2)
{
@@ -255,17 +257,17 @@ class symmetric_matrix : public matrix_expression<symmetric_matrix<F>>
symmetric_matrix &operator=(symmetric_matrix &&m) = default;
symmetric_matrix &operator=(const symmetric_matrix &m) = default;
constexpr uint32_t dim_m() const { return m_n; }
constexpr uint32_t dim_n() const { return m_n; }
constexpr size_t dim_m() const { return m_n; }
constexpr size_t dim_n() const { return m_n; }
constexpr value_type operator()(uint32_t i, uint32_t j) const
constexpr value_type operator()(size_t i, size_t j) const
{
return i < j
? m_data[(j * (j + 1)) / 2 + i]
: m_data[(i * (i + 1)) / 2 + j];
}
constexpr value_type &operator()(uint32_t i, uint32_t j)
constexpr value_type &operator()(size_t i, size_t j)
{
if (i > j)
std::swap(i, j);
@@ -274,7 +276,7 @@ class symmetric_matrix : public matrix_expression<symmetric_matrix<F>>
}
private:
uint32_t m_n;
size_t m_n;
std::vector<value_type> m_data;
};
@@ -296,17 +298,17 @@ class symmetric_matrix_fixed : public matrix_expression<symmetric_matrix_fixed<F
symmetric_matrix_fixed &operator=(symmetric_matrix_fixed &&m) = default;
symmetric_matrix_fixed &operator=(const symmetric_matrix_fixed &m) = default;
constexpr uint32_t dim_m() const { return M; }
constexpr uint32_t dim_n() const { return M; }
constexpr size_t dim_m() const { return M; }
constexpr size_t dim_n() const { return M; }
constexpr value_type operator()(uint32_t i, uint32_t j) const
constexpr value_type operator()(size_t i, size_t j) const
{
return i < j
? m_data[(j * (j + 1)) / 2 + i]
: m_data[(i * (i + 1)) / 2 + j];
}
constexpr value_type &operator()(uint32_t i, uint32_t j)
constexpr value_type &operator()(size_t i, size_t j)
{
if (i > j)
std::swap(i, j);
@@ -332,21 +334,21 @@ class identity_matrix : public matrix_expression<identity_matrix<F>>
public:
using value_type = F;
identity_matrix(uint32_t n)
identity_matrix(size_t n)
: m_n(n)
{
}
constexpr uint32_t dim_m() const { return m_n; }
constexpr uint32_t dim_n() const { return m_n; }
constexpr size_t dim_m() const { return m_n; }
constexpr size_t dim_n() const { return m_n; }
constexpr value_type operator()(uint32_t i, uint32_t j) const
constexpr value_type operator()(size_t i, size_t j) const
{
return i == j ? 1 : 0;
return static_cast<value_type>(i == j ? 1 : 0);
}
private:
uint32_t m_n;
size_t m_n;
};
// --------------------------------------------------------------------
@@ -364,10 +366,10 @@ class matrix_subtraction : public matrix_expression<matrix_subtraction<M1, M2>>
assert(m_m1.dim_n() == m_m2.dim_n());
}
constexpr uint32_t dim_m() const { return m_m1.dim_m(); }
constexpr uint32_t dim_n() const { return m_m1.dim_n(); }
constexpr size_t dim_m() const { return m_m1.dim_m(); }
constexpr size_t dim_n() const { return m_m1.dim_n(); }
constexpr auto operator()(uint32_t i, uint32_t j) const
constexpr auto operator()(size_t i, size_t j) const
{
return m_m1(i, j) - m_m2(i, j);
}
@@ -394,16 +396,16 @@ class matrix_matrix_multiplication : public matrix_expression<matrix_matrix_mult
assert(m1.dim_m() == m2.dim_n());
}
constexpr uint32_t dim_m() const { return m_m1.dim_m(); }
constexpr uint32_t dim_n() const { return m_m1.dim_n(); }
constexpr size_t dim_m() const { return m_m1.dim_m(); }
constexpr size_t dim_n() const { return m_m1.dim_n(); }
constexpr auto operator()(uint32_t i, uint32_t j) const
constexpr auto operator()(size_t i, size_t j) const
{
using value_type = decltype(m_m1(0, 0));
value_type result = {};
for (uint32_t k = 0; k < m_m1.dim_m(); ++k)
for (size_t k = 0; k < m_m1.dim_m(); ++k)
result += m_m1(i, k) * m_m2(k, j);
return result;
@@ -426,10 +428,10 @@ class matrix_scalar_multiplication : public matrix_expression<matrix_scalar_mult
{
}
constexpr uint32_t dim_m() const { return m_m.dim_m(); }
constexpr uint32_t dim_n() const { return m_m.dim_n(); }
constexpr size_t dim_m() const { return m_m.dim_m(); }
constexpr size_t dim_n() const { return m_m.dim_n(); }
constexpr auto operator()(uint32_t i, uint32_t j) const
constexpr auto operator()(size_t i, size_t j) const
{
return m_m(i, j) * m_v;
}
@@ -498,10 +500,10 @@ class matrix_cofactors : public matrix_expression<matrix_cofactors<M>>
{
}
constexpr uint32_t dim_m() const { return m_m.dim_m(); }
constexpr uint32_t dim_n() const { return m_m.dim_n(); }
constexpr size_t dim_m() const { return m_m.dim_m(); }
constexpr size_t dim_n() const { return m_m.dim_n(); }
constexpr auto operator()(uint32_t i, uint32_t j) const
constexpr auto operator()(size_t i, size_t j) const
{
const size_t ixs[4][3] = {
{ 1, 2, 3 },

View File

@@ -29,7 +29,6 @@
#include "cif++/row.hpp"
#include <map>
#include <regex>
namespace cif
{
@@ -54,8 +53,6 @@ class sac_parser
public:
using datablock_index = std::map<std::string, std::size_t>;
sac_parser(std::istream &is, bool init = true);
virtual ~sac_parser() = default;
enum CharTraitsMask : uint8_t
@@ -66,9 +63,14 @@ class sac_parser
kAnyPrintMask = 1 << 3
};
static bool is_white(int ch)
static constexpr bool is_space(int ch)
{
return std::isspace(ch) or ch == '#';
return ch == ' ' or ch == '\t' or ch == '\r' or ch == '\n';
}
static constexpr bool is_white(int ch)
{
return is_space(ch) or ch == '#';
}
static constexpr bool is_ordinary(int ch)
@@ -92,26 +94,7 @@ class sac_parser
(ch >= 0x20 and ch <= 0x7f and (kCharTraitsTable[ch - 0x20] & kAnyPrintMask) != 0);
}
static bool is_unquoted_string(std::string_view text)
{
bool result = text.empty() or is_ordinary(text.front());
if (result)
{
for (auto ch : text)
{
if (is_non_blank(ch))
continue;
result = false;
break;
}
}
static const std::regex kReservedRx(R"(loop_|stop_|global_|data_\S+|save_\S+)", std::regex_constants::icase);
// but be careful it does not contain e.g. stop_
return result and not std::regex_match(text.begin(), text.end(), kReservedRx);
}
static bool is_unquoted_string(std::string_view text);
protected:
static constexpr uint8_t kCharTraitsTable[128] = {
@@ -133,7 +116,8 @@ class sac_parser
DATA,
LOOP,
GLOBAL,
SAVE,
SAVE_,
SAVE_NAME,
STOP,
Tag,
Value
@@ -148,7 +132,8 @@ class sac_parser
case CIFToken::DATA: return "DATA";
case CIFToken::LOOP: return "LOOP";
case CIFToken::GLOBAL: return "GLOBAL";
case CIFToken::SAVE: return "SAVE";
case CIFToken::SAVE_: return "SAVE";
case CIFToken::SAVE_NAME: return "SAVE+name";
case CIFToken::STOP: return "STOP";
case CIFToken::Tag: return "Tag";
case CIFToken::Value: return "Value";
@@ -156,41 +141,13 @@ class sac_parser
}
}
enum class CIFValue
{
Int,
Float,
Numeric,
String,
TextField,
Inapplicable,
Unknown
};
static constexpr const char *get_value_name(CIFValue type)
{
switch (type)
{
case CIFValue::Int: return "Int";
case CIFValue::Float: return "Float";
case CIFValue::Numeric: return "Numeric";
case CIFValue::String: return "String";
case CIFValue::TextField: return "TextField";
case CIFValue::Inapplicable: return "Inapplicable";
case CIFValue::Unknown: return "Unknown";
default: return "Invalid type parameter";
}
}
// get_next_char takes a char from the buffer, or if it is empty
// from the istream. This function also does carriage/linefeed
// translation.
// get_next_char takes the next character from the istream.
// This function also does carriage/linefeed translation.
int get_next_char();
// Put the last read character back into the istream
void retract();
int restart(int start);
CIFToken get_next_token();
void match(CIFToken token);
@@ -205,6 +162,9 @@ class sac_parser
void parse_file();
protected:
sac_parser(std::istream &is, bool init = true);
void parse_global();
void parse_datablock();
@@ -227,13 +187,14 @@ class sac_parser
// production methods, these are pure virtual here
virtual void produce_datablock(const std::string &name) = 0;
virtual void produce_category(const std::string &name) = 0;
virtual void produce_datablock(std::string_view name) = 0;
virtual void produce_category(std::string_view name) = 0;
virtual void produce_row() = 0;
virtual void produce_item(const std::string &category, const std::string &item, const std::string &value) = 0;
virtual void produce_item(std::string_view category, std::string_view item, std::string_view value) = 0;
protected:
enum State
enum class State
{
Start,
White,
@@ -246,23 +207,21 @@ class sac_parser
UnquotedString,
Tag,
TextField,
Float = 100,
Int = 110,
Value = 300,
DATA,
SAVE
TextFieldNL,
Reserved,
Value
};
std::streambuf &m_source;
// Parser state
bool m_validate;
uint32_t m_line_nr;
bool m_bol;
CIFToken m_lookahead;
std::string m_token_value;
CIFValue mTokenType;
std::vector<int> m_buffer; // retract buffer, used to be a stack<char>
// token buffer
std::vector<char> m_token_buffer;
std::string_view m_token_value;
};
// --------------------------------------------------------------------
@@ -276,13 +235,13 @@ class parser : public sac_parser
{
}
void produce_datablock(const std::string &name) override;
void produce_datablock(std::string_view name) override;
void produce_category(const std::string &name) override;
void produce_category(std::string_view name) override;
void produce_row() override;
void produce_item(const std::string &category, const std::string &item, const std::string &value) override;
void produce_item(std::string_view category, std::string_view item, std::string_view value) override;
protected:
file &m_file;

View File

@@ -31,6 +31,7 @@
#include <array>
#include <cmath>
#include <complex>
#include <cstdint>
#include <functional>
#include <valarray>

View File

@@ -34,6 +34,10 @@
#include <cstdint>
#include <string>
#if defined(__cpp_impl_three_way_comparison)
#include <compare>
#endif
/// \file cif++/symmetry.hpp
/// This file contains code to do symmetry operations based on the
/// operations as specified in the International Tables.
@@ -180,7 +184,7 @@ class datablock;
class cell;
class spacegroup;
class rtop;
class sym_op;
struct sym_op;
/// @brief A class that encapsulates the symmetry operations as used in PDB files, i.e. a rotational number and a translation vector

View File

@@ -34,7 +34,7 @@
#define STDOUT_FILENO 1
#endif
#if _MSC_VER
#if _WIN32
#include <io.h>
#define isatty _isatty
#else
@@ -56,7 +56,6 @@ extern CIFPP_EXPORT int VERBOSE;
// the git 'build' number
std::string get_version_nr();
// std::string get_version_date();
// --------------------------------------------------------------------
// Code helping with terminal i/o

View File

@@ -228,8 +228,9 @@ class validator_factory
const validator &operator[](std::string_view dictionary_name);
const validator &construct_validator(std::string_view name, std::istream &is);
private:
void construct_validator(std::string_view name, std::istream &is);
// --------------------------------------------------------------------

View File

@@ -670,9 +670,13 @@ void category::set_validator(const validator *v, datablock &db)
if (missing.empty())
m_index = new category_index(this);
else if (VERBOSE > 0)
std::cerr << "Cannot construct index since the key field" << (missing.size() > 1 ? "s" : "") << " "
<< cif::join(missing, ", ") + " in " + m_name + " " + (missing.size() == 1 ? "is" : "are") << " missing" << std::endl;
else
{
std::ostringstream msg;
msg << "Cannot construct index since the key field" << (missing.size() > 1 ? "s" : "") << " "
<< cif::join(missing, ", ") << " in " << m_name << " " << (missing.size() == 1 ? "is" : "are") << " missing" << std::endl;
throw std::runtime_error(msg.str());
}
}
}
else
@@ -1227,23 +1231,37 @@ std::string category::get_unique_id(std::function<std::string(int)> generator)
{
using namespace cif::literals;
std::string id_tag = "id";
if (m_cat_validator != nullptr and m_cat_validator->m_keys.size() == 1)
id_tag = m_cat_validator->m_keys.front();
// calling size() often is a waste of resources
if (m_last_unique_num == 0)
m_last_unique_num = static_cast<uint32_t>(size());
for (;;)
std::string result = generator(static_cast<int>(m_last_unique_num++));
std::string id_tag = "id";
if (m_cat_validator != nullptr and m_cat_validator->m_keys.size() == 1)
{
std::string result = generator(static_cast<int>(m_last_unique_num++));
if (exists(key(id_tag) == result))
continue;
return result;
if (m_index == nullptr and m_cat_validator != nullptr)
m_index = new category_index(this);
for (;;)
{
if (m_index->find_by_value({{ id_tag, result }}) == nullptr)
break;
result = generator(static_cast<int>(m_last_unique_num++));
}
}
else
{
for (;;)
{
if (not exists(key(id_tag) == result))
break;
result = generator(static_cast<int>(m_last_unique_num++));
}
}
return result;
}
void category::update_value(const std::vector<row_handle> &rows, std::string_view tag, std::string_view value)
@@ -1694,8 +1712,7 @@ void category::reorder_by_index()
namespace detail
{
size_t write_value(std::ostream &os, std::string_view value, size_t offset, size_t width)
size_t write_value(std::ostream &os, std::string_view value, size_t offset, size_t width, bool right_aligned)
{
if (value.find('\n') != std::string::npos or width == 0 or value.length() > 132) // write as text field
{
@@ -1719,17 +1736,33 @@ namespace detail
}
else if (sac_parser::is_unquoted_string(value))
{
if (right_aligned)
{
if (value.length() < width)
{
os << std::string(width - value.length() - 1, ' ');
offset += width;
}
else
offset += value.length() + 1;
}
os << value;
if (value.length() < width)
{
os << std::string(width - value.length(), ' ');
offset += width;
}
if (right_aligned)
os << ' ';
else
{
os << ' ';
offset += value.length() + 1;
if (value.length() < width)
{
os << std::string(width - value.length(), ' ');
offset += width;
}
else
{
os << ' ';
offset += value.length() + 1;
}
}
}
else
@@ -1823,6 +1856,19 @@ void category::write(std::ostream &os, const std::vector<uint16_t> &order, bool
// If the first Row has a next, we need a loop_
bool needLoop = (m_head->m_next != nullptr);
std::vector<bool> right_aligned(m_columns.size(), false);
if (m_cat_validator != nullptr)
{
for (auto cix : order)
{
auto &col = m_columns[cix];
right_aligned[cix] = col.m_validator != nullptr and
col.m_validator->m_type != nullptr and
col.m_validator->m_type->m_primitive_type == cif::DDL_PrimitiveType::Numb;
}
}
if (needLoop)
{
os << "loop_" << '\n';
@@ -1891,7 +1937,7 @@ void category::write(std::ostream &os, const std::vector<uint16_t> &order, bool
offset = 0;
}
offset = detail::write_value(os, s, offset, w);
offset = detail::write_value(os, s, offset, w, right_aligned[cix]);
if (offset > 132)
{
@@ -1919,6 +1965,30 @@ void category::write(std::ostream &os, const std::vector<uint16_t> &order, bool
l += 3;
size_t width = 1;
for (auto cix : order)
{
if (not right_aligned[cix])
continue;
std::string_view s;
auto iv = m_head->get(cix);
if (iv != nullptr)
s = iv->text();
if (s.empty())
s = "?";
size_t l2 = s.length();
if (not sac_parser::is_unquoted_string(s))
l2 += 2;
if (width < l2)
width = l2;
}
for (uint16_t cix : order)
{
auto &col = m_columns[cix];
@@ -1943,7 +2013,7 @@ void category::write(std::ostream &os, const std::vector<uint16_t> &order, bool
offset = 0;
}
if (detail::write_value(os, s, offset, 1) != 0)
if (detail::write_value(os, s, offset, width, s.empty() or right_aligned[cix]) != 0)
os << '\n';
}
}

View File

@@ -313,7 +313,7 @@ class compound_factory_impl : public std::enable_shared_from_this<compound_facto
{
for (auto cmp : impl->m_compounds)
{
if (cmp->id() == id)
if (iequals(cmp->id(), id))
{
result = cmp;
break;
@@ -582,12 +582,12 @@ CCP4_compound_factory_impl::CCP4_compound_factory_impl(const fs::path &clibd_mon
auto &chemComps = m_file["comp_list"]["chem_comp"];
for (const auto &[group, threeLetterCode] : chemComps.rows<std::string, std::string>("group", "three_letter_code"))
for (const auto &[group, comp_id] : chemComps.rows<std::string, std::string>("group", "id"))
{
if (std::regex_match(group, peptideRx))
m_known_peptides.insert(threeLetterCode);
m_known_peptides.insert(comp_id);
else if (cif::iequals(group, "DNA") or cif::iequals(group, "RNA"))
m_known_bases.insert(threeLetterCode);
m_known_bases.insert(comp_id);
}
}
@@ -597,7 +597,7 @@ compound *CCP4_compound_factory_impl::create(const std::string &id)
auto &cat = m_file["comp_list"]["chem_comp"];
auto rs = cat.find(cif::key("three_letter_code") == id);
auto rs = cat.find(cif::key("id") == id);
if (rs.size() == 1)
{

View File

@@ -117,7 +117,7 @@ class dictionary_parser : public parser
if (not m_collected_item_types)
m_collected_item_types = collect_item_types();
std::string saveFrameName = m_token_value;
std::string saveFrameName { m_token_value };
if (saveFrameName.empty())
error("Invalid save frame, should contain more than just 'save_' here");
@@ -127,7 +127,7 @@ class dictionary_parser : public parser
datablock dict(m_token_value);
datablock::iterator cat = dict.end();
match(CIFToken::SAVE);
match(CIFToken::SAVE_NAME);
while (m_lookahead == CIFToken::LOOP or m_lookahead == CIFToken::Tag)
{
if (m_lookahead == CIFToken::LOOP)
@@ -183,7 +183,7 @@ class dictionary_parser : public parser
}
}
match(CIFToken::SAVE);
match(CIFToken::SAVE_);
if (isCategorySaveFrame)
{
@@ -481,4 +481,11 @@ validator parse_dictionary(std::string_view name, std::istream &is)
return result;
}
} // namespace cif
void extend_dictionary(validator &v, std::istream &is)
{
file f;
dictionary_parser p(v, is, f);
p.load_dictionary();
}
} // namespace cif

View File

@@ -32,7 +32,6 @@
#include <cassert>
#include <iostream>
#include <map>
#include <regex>
#include <stack>
namespace cif
@@ -40,13 +39,152 @@ namespace cif
// --------------------------------------------------------------------
class reserved_words_automaton
{
public:
reserved_words_automaton() {}
enum move_result
{
undefined,
no_keyword,
data,
global,
loop,
save,
save_plus,
stop
};
constexpr bool finished() const
{
return m_state <= 0;
}
constexpr bool matched() const
{
return m_state < 0;
}
constexpr move_result move(int ch)
{
move_result result = undefined;
switch (m_state)
{
case 0:
break;
case -1: // data_
if (sac_parser::is_non_blank(ch))
m_seen_trailing_chars = true;
else if (m_seen_trailing_chars)
result = data;
else
result = no_keyword;
break;
case -2: // global_
result = sac_parser::is_non_blank(ch) ? no_keyword : global;
break;
case -3: // loop_
result = sac_parser::is_non_blank(ch) ? no_keyword : loop;
break;
case -4: // save_
if (sac_parser::is_non_blank(ch))
m_seen_trailing_chars = true;
else if (m_seen_trailing_chars)
result = save_plus;
else
result = save;
break;
case -5: // stop_
result = sac_parser::is_non_blank(ch) ? no_keyword : stop;
break;
default:
assert(m_state > 0 and m_state < NODE_COUNT);
for (;;)
{
if (s_dag[m_state].ch == (ch & ~0x20))
{
m_state = s_dag[m_state].next_match;
break;
}
m_state = s_dag[m_state].next_nomatch;
if (m_state == 0)
{
result = no_keyword;
break;
}
}
break;
}
if (result != undefined)
m_state = 0;
return result;
}
private:
static constexpr struct node
{
int16_t ch;
int8_t next_match;
int8_t next_nomatch;
} s_dag[] = {
{ 0 },
{ 'D', 5, 2 },
{ 'G', 9, 3 },
{ 'L', 15, 4 },
{ 'S', 19, 0 },
{ 'A', 6, 0 },
{ 'T', 7, 0 },
{ 'A', 8, 0 },
{ '_', -1, 0 },
{ 'L', 10, 0 },
{ 'O', 11, 0 },
{ 'B', 12, 0 },
{ 'A', 13, 0 },
{ 'L', 14, 0 },
{ '_', -2, 0 },
{ 'O', 16, 0},
{ 'O', 17, 0 },
{ 'P', 18, 0 },
{ '_', -3, 0 },
{ 'A', 21, 20 },
{ 'T', 24, 0 },
{ 'V', 22, 0 },
{ 'E', 23, 0 },
{ '_', -4, 0 },
{ 'O', 25, 0 },
{ 'P', 26, 0 },
{ '_', -5, 0 },
};
static constexpr int NODE_COUNT = sizeof(s_dag) / sizeof(node);
int m_state = 1;
bool m_seen_trailing_chars = false;
};
// --------------------------------------------------------------------
sac_parser::sac_parser(std::istream &is, bool init)
: m_source(*is.rdbuf())
{
m_token_buffer.reserve(8192);
if (is.rdbuf() == nullptr)
throw std::runtime_error("Attempt to read from uninitialised stream");
m_validate = true;
m_line_nr = 1;
m_bol = true;
@@ -54,45 +192,54 @@ sac_parser::sac_parser(std::istream &is, bool init)
m_lookahead = get_next_token();
}
bool sac_parser::is_unquoted_string(std::string_view text)
{
bool result = text.empty() or is_ordinary(text.front());
if (result)
{
reserved_words_automaton automaton;
for (char ch : text)
{
if (not is_non_blank(ch))
{
result = false;
break;
}
automaton.move(ch);
}
if (automaton.matched())
result = false;
}
return result;
}
// get_next_char takes a char from the buffer, or if it is empty
// from the istream. This function also does carriage/linefeed
// translation.
int sac_parser::get_next_char()
{
int result = std::char_traits<char>::eof();
if (m_buffer.empty())
result = m_source.sbumpc();
else
{
result = m_buffer.back();
m_buffer.pop_back();
}
// very simple CR/LF translation into LF
if (result == '\r')
{
int lookahead = m_source.sbumpc();
if (lookahead != '\n')
m_buffer.push_back(lookahead);
result = '\n';
}
int result = m_source.sbumpc();
if (result == std::char_traits<char>::eof())
m_token_value.push_back(0);
m_token_buffer.push_back(0);
else
m_token_value.push_back(std::char_traits<char>::to_char_type(result));
if (result == '\n')
++m_line_nr;
if (VERBOSE >= 6)
{
std::cerr << "get_next_char => ";
if (iscntrl(result) or not isprint(result))
std::cerr << int(result) << std::endl;
else
std::cerr << char(result) << std::endl;
if (result == '\r')
{
if (m_source.sgetc() == '\n')
m_source.sbumpc();
++m_line_nr;
result = '\n';
}
else if (result == '\n')
++m_line_nr;
m_token_buffer.push_back(std::char_traits<char>::to_char_type(result));
}
return result;
@@ -100,44 +247,22 @@ int sac_parser::get_next_char()
void sac_parser::retract()
{
assert(not m_token_value.empty());
assert(not m_token_buffer.empty());
char ch = m_token_value.back();
char ch = m_token_buffer.back();
if (ch == '\n')
--m_line_nr;
m_buffer.push_back(ch == 0 ? std::char_traits<char>::eof() : std::char_traits<char>::to_int_type(ch));
m_token_value.pop_back();
}
int sac_parser::restart(int start)
{
int result = 0;
while (not m_token_value.empty())
retract();
switch (start)
if (ch != 0)
{
case State::Start:
result = State::Float;
break;
// since we always putback at most a single character,
// the test below should never fail.
case State::Float:
result = State::Int;
break;
case State::Int:
result = State::Value;
break;
default:
error("Invalid state in SacParser");
if (m_source.sputbackc(ch) == std::char_traits<char>::eof())
throw std::runtime_error("putback failure");
}
m_bol = false;
return result;
m_token_buffer.pop_back();
}
sac_parser::CIFToken sac_parser::get_next_token()
@@ -146,11 +271,13 @@ sac_parser::CIFToken sac_parser::get_next_token()
CIFToken result = CIFToken::Unknown;
int quoteChar = 0;
int state = State::Start, start = State::Start;
State state = State::Start;
m_bol = false;
m_token_value.clear();
mTokenType = CIFValue::Unknown;
m_token_buffer.clear();
m_token_value = {};
reserved_words_automaton dag;
while (result == CIFToken::Unknown)
{
@@ -174,23 +301,27 @@ sac_parser::CIFToken sac_parser::get_next_token()
state = State::Tag;
else if (ch == ';' and m_bol)
state = State::TextField;
else if (ch == '?')
state = State::QuestionMark;
else if (ch == '\'' or ch == '"')
{
quoteChar = ch;
state = State::QuotedString;
}
else if (dag.move(ch) == reserved_words_automaton::undefined)
state = State::Reserved;
else
state = start = restart(start);
state = State::Value;
break;
case State::White:
if (ch == kEOF)
result = CIFToken::Eof;
else if (not isspace(ch))
else if (not is_space(ch))
{
state = State::Start;
retract();
m_token_value.clear();
m_token_buffer.clear();
}
else
m_bol = (ch == '\n');
@@ -201,38 +332,40 @@ sac_parser::CIFToken sac_parser::get_next_token()
{
state = State::Start;
m_bol = true;
m_token_value.clear();
m_token_buffer.clear();
}
else if (ch == kEOF)
result = CIFToken::Eof;
else if (not is_any_print(ch))
error("invalid character in comment");
break;
case State::QuestionMark:
if (not is_non_blank(ch))
{
retract();
result = CIFToken::Value;
}
else
state = State::Value;
break;
case State::TextField:
if (ch == '\n')
state = State::TextField + 1;
state = State::TextFieldNL;
else if (ch == kEOF)
error("unterminated textfield");
// else if (ch == '\\')
// state = State::Esc;
else if (not is_any_print(ch) and cif::VERBOSE > 2)
warning("invalid character in text field '" + std::string({static_cast<char>(ch)}) + "' (" + std::to_string((int)ch) + ")");
break;
// case State::Esc:
// if (ch == '\n')
// break;
case State::TextField + 1:
case State::TextFieldNL:
if (is_text_lead(ch) or ch == ' ' or ch == '\t')
state = State::TextField;
else if (ch == ';')
{
assert(m_token_value.length() >= 2);
m_token_value = m_token_value.substr(1, m_token_value.length() - 3);
mTokenType = CIFValue::TextField;
assert(m_token_buffer.size() >= 2);
m_token_value = std::string_view(m_token_buffer.data() + 1, m_token_buffer.size() - 3);
result = CIFToken::Value;
}
else if (ch == kEOF)
@@ -255,12 +388,10 @@ sac_parser::CIFToken sac_parser::get_next_token()
{
retract();
result = CIFToken::Value;
mTokenType = CIFValue::String;
if (m_token_value.length() < 2)
if (m_token_buffer.size() < 2)
error("Invalid quoted string token");
m_token_value = m_token_value.substr(1, m_token_value.length() - 2);
m_token_value = std::string_view(m_token_buffer.data() + 1, m_token_buffer.size() - 2);
}
else if (ch == quoteChar)
;
@@ -277,149 +408,68 @@ sac_parser::CIFToken sac_parser::get_next_token()
{
retract();
result = CIFToken::Tag;
m_token_value = std::string_view(m_token_buffer.data(), m_token_buffer.size());
}
break;
case State::Float:
if (ch == '+' or ch == '-')
case State::Reserved:
switch (dag.move(ch))
{
state = State::Float + 1;
case reserved_words_automaton::undefined:
break;
case reserved_words_automaton::no_keyword:
if (not is_non_blank(ch))
{
retract();
result = CIFToken::Value;
m_token_value = std::string_view(m_token_buffer.data(), m_token_buffer.size());
}
else
state = State::Value;
break;
case reserved_words_automaton::data:
retract();
m_token_value = std::string_view(m_token_buffer.data() + 5, m_token_buffer.size() - 5);
result = CIFToken::DATA;
break;
case reserved_words_automaton::global:
retract();
result = CIFToken::GLOBAL;
break;
case reserved_words_automaton::loop:
retract();
result = CIFToken::LOOP;
break;
case reserved_words_automaton::save:
retract();
result = CIFToken::SAVE_;
break;
case reserved_words_automaton::save_plus:
retract();
m_token_value = std::string_view(m_token_buffer.data() + 5, m_token_buffer.size() - 5);
result = CIFToken::SAVE_NAME;
break;
case reserved_words_automaton::stop:
retract();
result = CIFToken::STOP;
break;
}
else if (isdigit(ch))
state = State::Float + 1;
else
state = start = restart(start);
break;
case State::Float + 1:
// if (ch == '(') // numeric???
// mState = State::NumericSuffix;
// else
if (ch == '.')
state = State::Float + 2;
else if (tolower(ch) == 'e')
state = State::Float + 3;
else if (is_white(ch) or ch == kEOF)
{
retract();
result = CIFToken::Value;
mTokenType = CIFValue::Int;
}
else
state = start = restart(start);
break;
// parsed '.'
case State::Float + 2:
if (tolower(ch) == 'e')
state = State::Float + 3;
else if (is_white(ch) or ch == kEOF)
{
retract();
result = CIFToken::Value;
mTokenType = CIFValue::Float;
}
else
state = start = restart(start);
break;
// parsed 'e'
case State::Float + 3:
if (ch == '-' or ch == '+')
state = State::Float + 4;
else if (isdigit(ch))
state = State::Float + 5;
else
state = start = restart(start);
break;
case State::Float + 4:
if (isdigit(ch))
state = State::Float + 5;
else
state = start = restart(start);
break;
case State::Float + 5:
if (is_white(ch) or ch == kEOF)
{
retract();
result = CIFToken::Value;
mTokenType = CIFValue::Float;
}
else
state = start = restart(start);
break;
case State::Int:
if (isdigit(ch) or ch == '+' or ch == '-')
state = State::Int + 1;
else
state = start = restart(start);
break;
case State::Int + 1:
if (is_white(ch) or ch == kEOF)
{
retract();
result = CIFToken::Value;
mTokenType = CIFValue::Int;
}
else
state = start = restart(start);
break;
case State::Value:
if (ch == '_')
{
std::string s = to_lower_copy(m_token_value);
if (s == "data_")
{
state = State::DATA;
continue;
}
if (s == "save_")
{
state = State::SAVE;
continue;
}
}
if (result == CIFToken::Unknown and not is_non_blank(ch))
{
retract();
result = CIFToken::Value;
if (m_token_value == ".")
mTokenType = CIFValue::Inapplicable;
else if (iequals(m_token_value, "global_"))
result = CIFToken::GLOBAL;
else if (iequals(m_token_value, "stop_"))
result = CIFToken::STOP;
else if (iequals(m_token_value, "loop_"))
result = CIFToken::LOOP;
else if (m_token_value == "?")
{
mTokenType = CIFValue::Unknown;
m_token_value.clear();
}
}
break;
case State::DATA:
case State::SAVE:
if (not is_non_blank(ch))
{
retract();
if (state == State::DATA)
result = CIFToken::DATA;
else
result = CIFToken::SAVE;
m_token_value.erase(m_token_value.begin(), m_token_value.begin() + 5);
result = CIFToken::Value;
m_token_value = std::string_view(m_token_buffer.data(), m_token_buffer.size());
break;
}
break;
@@ -433,8 +483,6 @@ sac_parser::CIFToken sac_parser::get_next_token()
if (VERBOSE >= 5)
{
std::cerr << get_token_name(result);
if (mTokenType != CIFValue::Unknown)
std::cerr << ' ' << get_value_name(mTokenType);
if (result != CIFToken::Eof)
std::cerr << " " << std::quoted(m_token_value);
std::cerr << std::endl;
@@ -506,7 +554,7 @@ bool sac_parser::parse_single_datablock(const std::string &datablock)
break;
case string_quote:
if (std::isspace(ch))
if (is_space(ch))
state = start;
else
state = string;
@@ -518,7 +566,7 @@ bool sac_parser::parse_single_datablock(const std::string &datablock)
break;
case data:
if (isspace(ch) and dblk[si] == 0)
if (is_space(ch) and dblk[si] == 0)
found = true;
else if (dblk[si++] != ch)
state = start;
@@ -596,7 +644,7 @@ sac_parser::datablock_index sac_parser::index_datablocks()
break;
case string_quote:
if (std::isspace(ch))
if (is_space(ch))
state = start;
else
state = string;
@@ -620,7 +668,7 @@ sac_parser::datablock_index sac_parser::index_datablocks()
case data_name:
if (is_non_blank(ch))
datablock.insert(datablock.end(), char(ch));
else if (isspace(ch))
else if (is_space(ch))
{
if (not datablock.empty())
index[datablock] = m_source.pubseekoff(0, std::ios_base::cur, std::ios_base::in);
@@ -696,7 +744,7 @@ void sac_parser::parse_datablock()
static const std::string kUnitializedCategory("<invalid>");
std::string cat = kUnitializedCategory; // intial value acts as a guard for empty category names
while (m_lookahead == CIFToken::LOOP or m_lookahead == CIFToken::Tag or m_lookahead == CIFToken::SAVE)
while (m_lookahead == CIFToken::LOOP or m_lookahead == CIFToken::Tag or m_lookahead == CIFToken::SAVE_NAME)
{
switch (m_lookahead)
{
@@ -761,7 +809,7 @@ void sac_parser::parse_datablock()
break;
}
case CIFToken::SAVE:
case CIFToken::SAVE_NAME:
parse_save_frame();
break;
@@ -779,7 +827,7 @@ void sac_parser::parse_save_frame()
// --------------------------------------------------------------------
void parser::produce_datablock(const std::string &name)
void parser::produce_datablock(std::string_view name)
{
if (VERBOSE >= 4)
std::cerr << "producing data_" << name << std::endl;
@@ -788,7 +836,7 @@ void parser::produce_datablock(const std::string &name)
m_datablock = &(*iter);
}
void parser::produce_category(const std::string &name)
void parser::produce_category(std::string_view name)
{
if (VERBOSE >= 4)
std::cerr << "producing category " << name << std::endl;
@@ -810,7 +858,7 @@ void parser::produce_row()
// m_row.lineNr(m_line_nr);
}
void parser::produce_item(const std::string &category, const std::string &item, const std::string &value)
void parser::produce_item(std::string_view category, std::string_view item, std::string_view value)
{
if (VERBOSE >= 4)
std::cerr << "producing _" << category << '.' << item << " -> " << value << std::endl;
@@ -821,4 +869,4 @@ void parser::produce_item(const std::string &category, const std::string &item,
m_row[item] = m_token_value;
}
} // namespace cif
} // namespace cif

View File

@@ -1170,6 +1170,8 @@ void PDBFileParser::PreParseInput(std::istream &is)
std::string value;
if (lookahead.length() > 6)
value = cif::trim_right_copy(lookahead.substr(6));
lookahead.clear();
uint32_t curLineNr = lineNr;
getline(is, lookahead);

View File

@@ -61,7 +61,7 @@ quaternion_type<T> normalize(quaternion_type<T> q)
quaternion construct_from_angle_axis(float angle, point axis)
{
angle = (angle * kPI / 180) / 2;
angle = static_cast<float>((angle * kPI / 180) / 2);
auto s = std::sin(angle);
auto c = std::cos(angle);
@@ -119,7 +119,7 @@ point center_points(std::vector<point> &Points)
}
quaternion construct_for_dihedral_angle(point p1, point p2, point p3, point p4,
float angle, float esd)
float angle, float /*esd*/)
{
p1 -= p3;
p2 -= p3;

View File

@@ -70,12 +70,12 @@ void cell::init()
m_orthogonal = identity_matrix(3);
m_orthogonal(0, 0) = m_a;
m_orthogonal(0, 1) = m_b * std::cos(gamma);
m_orthogonal(0, 2) = m_c * std::cos(beta);
m_orthogonal(1, 1) = m_b * std::sin(gamma);
m_orthogonal(1, 2) = -m_c * std::sin(beta) * std::cos(alpha_star);
m_orthogonal(2, 2) = m_c * std::sin(beta) * std::sin(alpha_star);
m_orthogonal(0, 0) = static_cast<float>(m_a);
m_orthogonal(0, 1) = static_cast<float>(m_b * std::cos(gamma));
m_orthogonal(0, 2) = static_cast<float>(m_c * std::cos(beta));
m_orthogonal(1, 1) = static_cast<float>(m_b * std::sin(gamma));
m_orthogonal(1, 2) = static_cast<float>(-m_c * std::sin(beta) * std::cos(alpha_star));
m_orthogonal(2, 2) = static_cast<float>(m_c * std::sin(beta) * std::sin(alpha_star));
m_fractional = inverse(m_orthogonal);
}
@@ -90,7 +90,7 @@ sym_op::sym_op(std::string_view s)
int rnri = 256; // default to unexisting number
auto r = std::from_chars(b, e, rnri);
m_nr = rnri;
m_nr = static_cast<uint8_t>(rnri);
m_ta = r.ptr[1] - '0';
m_tb = r.ptr[2] - '0';
m_tc = r.ptr[3] - '0';
@@ -121,21 +121,21 @@ transformation::transformation(const symop_data &data)
{
const auto &d = data.data();
m_rotation(0, 0) = d[0];
m_rotation(0, 1) = d[1];
m_rotation(0, 2) = d[2];
m_rotation(1, 0) = d[3];
m_rotation(1, 1) = d[4];
m_rotation(1, 2) = d[5];
m_rotation(2, 0) = d[6];
m_rotation(2, 1) = d[7];
m_rotation(2, 2) = d[8];
m_rotation(0, 0) = static_cast<float>(d[0]);
m_rotation(0, 1) = static_cast<float>(d[1]);
m_rotation(0, 2) = static_cast<float>(d[2]);
m_rotation(1, 0) = static_cast<float>(d[3]);
m_rotation(1, 1) = static_cast<float>(d[4]);
m_rotation(1, 2) = static_cast<float>(d[5]);
m_rotation(2, 0) = static_cast<float>(d[6]);
m_rotation(2, 1) = static_cast<float>(d[7]);
m_rotation(2, 2) = static_cast<float>(d[8]);
try_create_quaternion();
m_translation.m_x = d[9] == 0 ? 0 : 1.0 * d[9] / d[10];
m_translation.m_y = d[11] == 0 ? 0 : 1.0 * d[11] / d[12];
m_translation.m_z = d[13] == 0 ? 0 : 1.0 * d[13] / d[14];
m_translation.m_x = static_cast<float>(d[9] == 0 ? 0 : 1.0 * d[9] / d[10]);
m_translation.m_y = static_cast<float>(d[11] == 0 ? 0 : 1.0 * d[11] / d[12]);
m_translation.m_z = static_cast<float>(d[13] == 0 ? 0 : 1.0 * d[13] / d[14]);
}
transformation::transformation(const matrix3x3<float> &r, const cif::point &t)
@@ -461,7 +461,7 @@ std::tuple<float,point,sym_op> crystal::closest_symmetry_copy(point a, point b)
for (size_t i = 0; i < m_spacegroup.size(); ++i)
{
sym_op s(i + 1);
sym_op s(static_cast<uint8_t>(i + 1));
auto &t = m_spacegroup[i];
auto fsb = t(fb);

View File

@@ -236,28 +236,19 @@ std::string cif_id_for_number(int number)
{
std::string result;
if (number >= 26 * 26 * 26)
result = 'L' + std::to_string(number);
else
do
{
if (number >= 26 * 26)
{
int v = number / (26 * 26);
result += char('A' - 1 + v);
number %= (26 * 26);
}
int r = number % 26;
result += static_cast<char>('A' + r);
if (number >= 26)
{
int v = number / 26;
result += char('A' - 1 + v);
number %= 26;
}
result += char('A' + number);
number = (number - r) / 26 - 1;
}
while (number >= 0);
std::reverse(result.begin(), result.end());
assert(not result.empty());
return result;
}

View File

@@ -40,11 +40,10 @@
#include <iostream>
#include <map>
#include <mutex>
#include <regex>
#include <sstream>
#include <thread>
#if not defined(_MSC_VER)
#if not defined(_WIN32)
#include <sys/ioctl.h>
#include <termios.h>
#endif
@@ -69,7 +68,7 @@ std::string get_version_nr()
// --------------------------------------------------------------------
#ifdef _MSC_VER
#ifdef _WIN32
}
#include <Windows.h>
#include <libloaderapi.h>
@@ -161,6 +160,8 @@ struct progress_bar_impl
void print_progress();
void print_done();
using time_point = std::chrono::time_point<std::chrono::system_clock>;
int64_t m_max_value;
std::atomic<int64_t> m_consumed;
int64_t m_last_consumed = 0;
@@ -168,8 +169,8 @@ struct progress_bar_impl
std::string m_action, m_message;
std::mutex m_mutex;
std::thread m_thread;
std::chrono::time_point<std::chrono::system_clock>
m_start = std::chrono::system_clock::now();
time_point m_start = std::chrono::system_clock::now();
time_point m_last = std::chrono::system_clock::now();
bool m_stop = false;
};
@@ -192,7 +193,9 @@ void progress_bar_impl::run()
{
while (not m_stop)
{
if (std::chrono::system_clock::now() - m_start < 2s)
auto now = std::chrono::system_clock::now();
if (now - m_start < 2s or now - m_last < 100ms)
{
std::this_thread::sleep_for(10ms);
continue;
@@ -201,11 +204,12 @@ void progress_bar_impl::run()
std::lock_guard lock(m_mutex);
if (not printedAny and isatty(STDOUT_FILENO))
std::cout << "\e[?25l";
std::cout << "\x1b[?25l";
print_progress();
printedAny = true;
m_last = std::chrono::system_clock::now();
}
}
catch (...)
@@ -216,7 +220,7 @@ void progress_bar_impl::run()
{
print_done();
if (isatty(STDOUT_FILENO))
std::cout << "\e[?25h";
std::cout << "\x1b[?25h";
}
}
@@ -407,11 +411,19 @@ struct rsrc_imp
};
} // namespace mrsrc
#if _MSC_VER
#if _WIN32
extern "C" CIFPP_EXPORT const mrsrc::rsrc_imp *gResourceIndexDefault[1] = {};
extern "C" CIFPP_EXPORT const char *gResourceDataDefault[1] = {};
extern "C" CIFPP_EXPORT const char *gResourceNameDefault[1] = {};
#if __MINGW32__
extern "C" __attribute__((weak, alias("gResourceIndexDefault"))) const mrsrc::rsrc_imp gResourceIndex[];
extern "C" __attribute__((weak, alias("gResourceDataDefault"))) const char gResourceData[];
extern "C" __attribute__((weak, alias("gResourceNameDefault"))) const char gResourceName[];
#else
extern "C" const mrsrc::rsrc_imp *gResourceIndexDefault[1] = {};
extern "C" const char *gResourceDataDefault[1] = {};
extern "C" const char *gResourceNameDefault[1] = {};
extern "C" const mrsrc::rsrc_imp gResourceIndex[];
extern "C" const char gResourceData[];
@@ -421,6 +433,8 @@ extern "C" const char gResourceName[];
#pragma comment(linker, "/alternatename:gResourceData=gResourceDataDefault")
#pragma comment(linker, "/alternatename:gResourceName=gResourceNameDefault")
#endif
#else
extern const __attribute__((weak)) mrsrc::rsrc_imp gResourceIndex[];
extern const __attribute__((weak)) char gResourceData[];

View File

@@ -491,9 +491,9 @@ const validator &validator_factory::operator[](std::string_view dictionary_name)
}
}
void validator_factory::construct_validator(std::string_view name, std::istream &is)
const validator &validator_factory::construct_validator(std::string_view name, std::istream &is)
{
m_validators.emplace_back(parse_dictionary(name, is));
return m_validators.emplace_back(parse_dictionary(name, is));
}
} // namespace cif

187
test/REA_v2.cif Normal file
View File

@@ -0,0 +1,187 @@
data_REA_v2
#
_chem_comp.id REA_v2
_chem_comp.name "RETINOIC ACID"
_chem_comp.type NON-POLYMER
_chem_comp.pdbx_type HETAIN
_chem_comp.formula "C20 H28 O2"
_chem_comp.mon_nstd_parent_comp_id ?
_chem_comp.pdbx_synonyms ?
_chem_comp.pdbx_formal_charge 0
_chem_comp.pdbx_initial_date 1999-07-08
_chem_comp.pdbx_modified_date 2016-10-18
_chem_comp.pdbx_ambiguous_flag N
_chem_comp.pdbx_release_status REL
_chem_comp.pdbx_replaced_by ?
_chem_comp.pdbx_replaces 3KV
_chem_comp.formula_weight 300.435
_chem_comp.one_letter_code ?
_chem_comp.pdbx_model_coordinates_details ?
_chem_comp.pdbx_model_coordinates_missing_flag N
_chem_comp.pdbx_ideal_coordinates_details Corina
_chem_comp.pdbx_ideal_coordinates_missing_flag N
_chem_comp.pdbx_model_coordinates_db_code 1CBS
_chem_comp.pdbx_subcomponent_list ?
_chem_comp.pdbx_processing_site RCSB
#
loop_
_chem_comp_atom.comp_id
_chem_comp_atom.atom_id
_chem_comp_atom.alt_atom_id
_chem_comp_atom.type_symbol
_chem_comp_atom.charge
_chem_comp_atom.pdbx_align
_chem_comp_atom.pdbx_aromatic_flag
_chem_comp_atom.pdbx_leaving_atom_flag
_chem_comp_atom.pdbx_stereo_config
_chem_comp_atom.model_Cartn_x
_chem_comp_atom.model_Cartn_y
_chem_comp_atom.model_Cartn_z
_chem_comp_atom.pdbx_model_Cartn_x_ideal
_chem_comp_atom.pdbx_model_Cartn_y_ideal
_chem_comp_atom.pdbx_model_Cartn_z_ideal
_chem_comp_atom.pdbx_component_atom_id
_chem_comp_atom.pdbx_component_comp_id
_chem_comp_atom.pdbx_ordinal
REA_v2 C1 C1 C 0 1 N N N 21.972 29.831 16.739 -4.684 0.932 -0.497 C1 REA_v2 1
REA_v2 C2 C2 C 0 1 N N N 20.921 30.524 15.841 -5.837 0.190 -1.176 C2 REA_v2 2
REA_v2 C3 C3 C 0 1 N N N 20.245 29.635 14.848 -6.441 -0.798 -0.171 C3 REA_v2 3
REA_v2 C4 C4 C 0 1 N N N 19.555 28.479 15.488 -5.418 -1.903 0.100 C4 REA_v2 4
REA_v2 C5 C5 C 0 1 N N N 20.389 27.812 16.587 -4.082 -1.301 0.429 C5 REA_v2 5
REA_v2 C6 C6 C 0 1 N N N 21.425 28.446 17.218 -3.756 -0.048 0.161 C6 REA_v2 6
REA_v2 C7 C7 C 0 1 N N N 22.242 27.851 18.297 -2.457 0.396 0.516 C7 REA_v2 7
REA_v2 C8 C8 C 0 1 N N N 21.868 26.977 19.240 -1.363 -0.229 0.007 C8 REA_v2 8
REA_v2 C9 C9 C 0 1 N N N 22.705 26.434 20.286 -0.076 0.257 0.298 C9 REA_v2 9
REA_v2 C10 C10 C 0 1 N N N 22.159 25.536 21.131 1.022 -0.370 -0.213 C10 REA_v2 10
REA_v2 C11 C11 C 0 1 N N N 22.875 24.924 22.234 2.306 0.115 0.077 C11 REA_v2 11
REA_v2 C12 C12 C 0 1 N N N 22.237 24.026 22.990 3.405 -0.513 -0.435 C12 REA_v2 12
REA_v2 C13 C13 C 0 1 N N N 22.856 23.377 24.125 4.689 -0.028 -0.144 C13 REA_v2 13
REA_v2 C14 C14 C 0 1 N N N 22.135 22.473 24.834 5.787 -0.655 -0.656 C14 REA_v2 14
REA_v2 C15 C15 C 0 1 N N N 22.563 21.710 26.016 7.077 -0.265 -0.244 C15 REA_v2 15
REA_v2 C16 C16 C 0 1 N N N 22.238 30.737 17.948 -5.246 1.886 0.559 C16 REA_v2 16
REA_v2 C17 C17 C 0 1 N N N 23.292 29.620 15.948 -3.911 1.737 -1.544 C17 REA_v2 17
REA_v2 C18 C18 C 0 1 N N N 19.791 26.449 16.947 -3.056 -2.175 1.103 C18 REA_v2 18
REA_v2 C19 C19 C 0 1 N N N 24.181 26.841 20.385 0.090 1.471 1.175 C19 REA_v2 19
REA_v2 C20 C20 C 0 1 N N N 24.303 23.747 24.489 4.855 1.186 0.733 C20 REA_v2 20
REA_v2 O1 O1 O 0 1 N N N 23.640 21.075 25.978 7.210 0.553 0.648 O1 REA_v2 21
REA_v2 O2 O2 O 0 1 N N N 21.840 21.712 27.037 8.166 -0.798 -0.840 O2 REA_v2 22
REA_v2 H21 H21 H 0 1 N N N 20.147 30.955 16.494 -6.598 0.905 -1.490 H21 REA_v2 23
REA_v2 H22 H22 H 0 1 N N N 21.425 31.330 15.288 -5.462 -0.353 -2.044 H22 REA_v2 24
REA_v2 H31 H31 H 0 1 N N N 19.501 30.227 14.295 -6.673 -0.278 0.759 H31 REA_v2 25
REA_v2 H32 H32 H 0 1 N N N 21.001 29.250 14.148 -7.349 -1.234 -0.586 H32 REA_v2 26
REA_v2 H41 H41 H 0 1 N N N 18.613 28.835 15.931 -5.756 -2.511 0.938 H41 REA_v2 27
REA_v2 H42 H42 H 0 1 N N N 19.335 27.730 14.713 -5.322 -2.531 -0.786 H42 REA_v2 28
REA_v2 H7 H7 H 0 1 N N N 23.276 28.162 18.329 -2.337 1.230 1.191 H7 REA_v2 29
REA_v2 H8 H8 H 0 1 N N N 20.840 26.645 19.217 -1.482 -1.100 -0.622 H8 REA_v2 30
REA_v2 H10 H10 H 0 1 N N N 21.127 25.256 20.977 0.903 -1.241 -0.842 H10 REA_v2 31
REA_v2 H11 H11 H 0 1 N N N 23.902 25.189 22.440 2.425 0.985 0.706 H11 REA_v2 32
REA_v2 H12 H12 H 0 1 N N N 21.216 23.774 22.743 3.286 -1.383 -1.063 H12 REA_v2 33
REA_v2 H14 H14 H 0 1 N N N 21.127 22.292 24.490 5.667 -1.451 -1.376 H14 REA_v2 34
REA_v2 H161 H161 H 0 0 N N N 22.984 30.265 18.604 -5.802 1.316 1.303 H161 REA_v2 35
REA_v2 H162 H162 H 0 0 N N N 22.618 31.709 17.601 -4.426 2.415 1.044 H162 REA_v2 36
REA_v2 H163 H163 H 0 0 N N N 21.302 30.887 18.506 -5.911 2.605 0.081 H163 REA_v2 37
REA_v2 H171 H171 H 0 0 N N N 24.033 29.127 16.595 -4.598 2.394 -2.077 H171 REA_v2 38
REA_v2 H172 H172 H 0 0 N N N 23.095 28.989 15.069 -3.146 2.335 -1.050 H172 REA_v2 39
REA_v2 H173 H173 H 0 0 N N N 23.683 30.595 15.620 -3.439 1.054 -2.251 H173 REA_v2 40
REA_v2 H181 H181 H 0 0 N N N 20.397 25.979 17.736 -3.448 -3.187 1.201 H181 REA_v2 41
REA_v2 H182 H182 H 0 0 N N N 18.761 26.584 17.308 -2.145 -2.194 0.503 H182 REA_v2 42
REA_v2 H183 H183 H 0 0 N N N 19.786 25.804 16.056 -2.831 -1.775 2.092 H183 REA_v2 43
REA_v2 H191 H191 H 0 0 N N N 24.647 26.327 21.238 0.171 1.159 2.216 H191 REA_v2 44
REA_v2 H192 H192 H 0 0 N N N 24.702 26.559 19.458 0.993 2.008 0.885 H192 REA_v2 45
REA_v2 H193 H193 H 0 0 N N N 24.252 27.929 20.529 -0.774 2.125 1.058 H193 REA_v2 46
REA_v2 H201 H201 H 0 0 N N N 24.620 23.168 25.369 5.026 0.871 1.762 H201 REA_v2 47
REA_v2 H202 H202 H 0 0 N N N 24.965 23.516 23.641 5.707 1.771 0.386 H202 REA_v2 48
REA_v2 H203 H203 H 0 0 N N N 24.360 24.822 24.717 3.952 1.795 0.685 H203 REA_v2 49
REA_v2 HO2 HO2 H 0 1 N N N 22.244 21.180 27.713 9.006 -0.469 -0.490 HO2 REA_v2 50
#
loop_
_chem_comp_bond.comp_id
_chem_comp_bond.atom_id_1
_chem_comp_bond.atom_id_2
_chem_comp_bond.value_order
_chem_comp_bond.pdbx_aromatic_flag
_chem_comp_bond.pdbx_stereo_config
_chem_comp_bond.pdbx_ordinal
REA_v2 C1 C2 SING N N 1
REA_v2 C1 C6 SING N N 2
REA_v2 C1 C16 SING N N 3
REA_v2 C1 C17 SING N N 4
REA_v2 C2 C3 SING N N 5
REA_v2 C2 H21 SING N N 6
REA_v2 C2 H22 SING N N 7
REA_v2 C3 C4 SING N N 8
REA_v2 C3 H31 SING N N 9
REA_v2 C3 H32 SING N N 10
REA_v2 C4 C5 SING N N 11
REA_v2 C4 H41 SING N N 12
REA_v2 C4 H42 SING N N 13
REA_v2 C5 C6 DOUB N N 14
REA_v2 C5 C18 SING N N 15
REA_v2 C6 C7 SING N N 16
REA_v2 C7 C8 DOUB N E 17
REA_v2 C7 H7 SING N N 18
REA_v2 C8 C9 SING N N 19
REA_v2 C8 H8 SING N N 20
REA_v2 C9 C10 DOUB N E 21
REA_v2 C9 C19 SING N N 22
REA_v2 C10 C11 SING N N 23
REA_v2 C10 H10 SING N N 24
REA_v2 C11 C12 DOUB N E 25
REA_v2 C11 H11 SING N N 26
REA_v2 C12 C13 SING N N 27
REA_v2 C12 H12 SING N N 28
REA_v2 C13 C14 DOUB N E 29
REA_v2 C13 C20 SING N N 30
REA_v2 C14 C15 SING N N 31
REA_v2 C14 H14 SING N N 32
REA_v2 C15 O1 DOUB N N 33
REA_v2 C15 O2 SING N N 34
REA_v2 C16 H161 SING N N 35
REA_v2 C16 H162 SING N N 36
REA_v2 C16 H163 SING N N 37
REA_v2 C17 H171 SING N N 38
REA_v2 C17 H172 SING N N 39
REA_v2 C17 H173 SING N N 40
REA_v2 C18 H181 SING N N 41
REA_v2 C18 H182 SING N N 42
REA_v2 C18 H183 SING N N 43
REA_v2 C19 H191 SING N N 44
REA_v2 C19 H192 SING N N 45
REA_v2 C19 H193 SING N N 46
REA_v2 C20 H201 SING N N 47
REA_v2 C20 H202 SING N N 48
REA_v2 C20 H203 SING N N 49
REA_v2 O2 HO2 SING N N 50
#
loop_
_pdbx_chem_comp_descriptor.comp_id
_pdbx_chem_comp_descriptor.type
_pdbx_chem_comp_descriptor.program
_pdbx_chem_comp_descriptor.program_version
_pdbx_chem_comp_descriptor.descriptor
REA_v2 SMILES ACDLabs 12.01 "C1(CCCC(=C1\C=C\C(=C\C=C\C(=C\C(=O)O)C)C)C)(C)C"
REA_v2 InChI InChI 1.03 "InChI=1S/C20H28O2/c1-15(8-6-9-16(2)14-19(21)22)11-12-18-17(3)10-7-13-20(18,4)5/h6,8-9,11-12,14H,7,10,13H2,1-5H3,(H,21,22)/b9-6+,12-11+,15-8+,16-14+"
REA_v2 InChIKey InChI 1.03 SHGAZHPCJJPHSC-YCNIQYBTSA-N
REA_v2 SMILES_CANONICAL CACTVS 3.385 "CC1=C(\C=C\C(C)=C\C=C\C(C)=C\C(O)=O)C(C)(C)CCC1"
REA_v2 SMILES CACTVS 3.385 "CC1=C(C=CC(C)=CC=CC(C)=CC(O)=O)C(C)(C)CCC1"
REA_v2 SMILES_CANONICAL "OpenEye OEToolkits" 1.7.6 "CC1=C(C(CCC1)(C)C)/C=C/C(=C/C=C/C(=C/C(=O)O)/C)/C"
REA_v2 SMILES "OpenEye OEToolkits" 1.7.6 "CC1=C(C(CCC1)(C)C)C=CC(=CC=CC(=CC(=O)O)C)C"
#
loop_
_pdbx_chem_comp_identifier.comp_id
_pdbx_chem_comp_identifier.type
_pdbx_chem_comp_identifier.program
_pdbx_chem_comp_identifier.program_version
_pdbx_chem_comp_identifier.identifier
REA_v2 "SYSTEMATIC NAME" ACDLabs 12.01 "retinoic acid"
REA_v2 "SYSTEMATIC NAME" "OpenEye OEToolkits" 1.7.6 "(2E,4E,6E,8E)-3,7-dimethyl-9-(2,6,6-trimethylcyclohexen-1-yl)nona-2,4,6,8-tetraenoic acid"
#
loop_
_pdbx_chem_comp_audit.comp_id
_pdbx_chem_comp_audit.action_type
_pdbx_chem_comp_audit.date
_pdbx_chem_comp_audit.processing_site
REA_v2 "CREA_v2te component" 1999-07-08 RCSB
REA_v2 "Modify descriptor" 2011-06-04 RCSB
REA_v2 "Other modification" 2016-10-18 RCSB
#

39
test/io-test.cpp Normal file
View File

@@ -0,0 +1,39 @@
#include <cif++.hpp>
class dummy_parser : public cif::sac_parser
{
public:
dummy_parser(std::istream &is)
: sac_parser(is)
{
}
void produce_datablock(std::string_view name) override
{
}
void produce_category(std::string_view name) override
{
}
void produce_row() override
{
}
void produce_item(std::string_view category, std::string_view item, std::string_view value) override
{
}
};
int main()
{
cif::gzio::ifstream in("/srv/data/pdb/mmCIF/gl/8glv.cif.gz");
dummy_parser parser(in);
parser.parse_file();
// cif::file f("/srv/data/pdb/mmCIF/gl/8glv.cif.gz");
return 0;
}

View File

@@ -75,6 +75,30 @@ bool init_unit_test()
// --------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(id_1)
{
BOOST_TEST(cif::cif_id_for_number(0) == "A");
BOOST_TEST(cif::cif_id_for_number(25) == "Z");
BOOST_TEST(cif::cif_id_for_number(26) == "AA");
BOOST_TEST(cif::cif_id_for_number(26 + 1) == "AB");
BOOST_TEST(cif::cif_id_for_number(26 + 26 * 26 - 1) == "ZZ");
BOOST_TEST(cif::cif_id_for_number(26 + 26 * 26) == "AAA");
BOOST_TEST(cif::cif_id_for_number(26 + 26 * 26 + 1) == "AAB");
std::set<std::string> testset;
for (int i = 0; i < 100000; ++i)
{
std::string id = cif::cif_id_for_number(i);
BOOST_TEST(testset.count(id) == 0);
testset.insert(id);
}
BOOST_TEST(testset.size() == 100000);
}
// --------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(cc_1)
{
std::tuple<std::string_view, float, char> tests[] = {
@@ -2357,8 +2381,6 @@ _test.text ??
BOOST_AUTO_TEST_CASE(output_test_1)
{
cif::VERBOSE = 5;
auto data1 = R"(
data_Q
loop_
@@ -2863,7 +2885,7 @@ save__cat_1.name
std::istream is_dict(&buffer);
auto validator = cif::parse_dictionary("test_dict.dic", is_dict);
auto &validator = cif::validator_factory::instance().construct_validator("test_dict.dic", is_dict);
cif::file f;
f.set_validator(&validator);
@@ -2901,8 +2923,6 @@ _cat_1.name
ss << f;
cif::file f2(ss);
f2.set_validator(&validator);
BOOST_ASSERT(f2.is_valid());
auto &audit_conform = f2.front()["audit_conform"];
@@ -3130,4 +3150,60 @@ _test.value
v = test.find1<std::optional<float>>("id"_key == 4, "value");
BOOST_CHECK(v.has_value() == false);
}
}
// --------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(compound_test_1)
{
cif::compound_factory::instance().push_dictionary(gTestDir / "REA_v2.cif");
auto compound = cif::compound_factory::instance().create("REA_v2");
BOOST_ASSERT(compound != nullptr);
BOOST_CHECK(compound->id() == "REA_v2");
}
// --------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(pdb_parser_test_1)
{
char k1CBS[] = R"(HEADER RETINOIC-ACID TRANSPORT 28-SEP-94 1CBS
TITLE CRYSTAL STRUCTURE OF CELLULAR RETINOIC-ACID-BINDING
TITLE 2 PROTEINS I AND II IN COMPLEX WITH ALL-TRANS-RETINOIC ACID
TITLE 3 AND A SYNTHETIC RETINOID
COMPND MOL_ID: 1;
COMPND 2 MOLECULE: CELLULAR RETINOIC ACID BINDING PROTEIN TYPE II;
COMPND 3 CHAIN: A;
COMPND 4 ENGINEERED: YES
SOURCE MOL_ID: 1;
SOURCE 2 ORGANISM_SCIENTIFIC: HOMO SAPIENS;
SOURCE 3 ORGANISM_COMMON: HUMAN;
SOURCE 4 ORGANISM_TAXID: 9606;
SOURCE 5 CELL_LINE: BL21;
SOURCE 6 GENE: HUMAN CRABP-II;
SOURCE 7 EXPRESSION_SYSTEM: ESCHERICHIA COLI BL21(DE3);
SOURCE 8 EXPRESSION_SYSTEM_TAXID: 469008;
SOURCE 9 EXPRESSION_SYSTEM_STRAIN: BL21 (DE3);
SOURCE 10 EXPRESSION_SYSTEM_PLASMID: PET-3A
KEYWDS RETINOIC-ACID TRANSPORT
EXPDTA X-RAY DIFFRACTION
AUTHOR G.J.KLEYWEGT,T.BERGFORS,T.A.JONES
ATOM 1 N PRO A 1 16.979 13.301 44.555 1.00 30.05 N
ATOM 2 CA PRO A 1 18.150 13.525 43.680 1.00 28.82 C
ATOM 3 C PRO A 1 18.656 14.966 43.784 1.00 26.59 C
ATOM 4 O PRO A 1 17.890 15.889 44.078 1.00 26.84 O
ATOM 5 CB PRO A 1 17.678 13.270 42.255 1.00 29.24 C
ATOM 6 CG PRO A 1 16.248 13.734 42.347 1.00 29.29 C
ATOM 7 CD PRO A 1 15.762 13.216 43.724 1.00 30.71 C)";
struct membuf : public std::streambuf
{
membuf(char *text, size_t length)
{
this->setg(text, text, text + length);
}
} buffer(k1CBS, sizeof(k1CBS) - 1);
std::istream is(&buffer);
auto f = cif::pdb::read(is);
}