mirror of
https://github.com/PDB-REDO/libcifpp.git
synced 2026-06-05 14:34:21 +08:00
Compare commits
3 Commits
v10.0.4
...
combined-v
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
228e90a515 | ||
|
|
04c4ecc265 | ||
|
|
3ce3630b50 |
@@ -1,22 +0,0 @@
|
||||
BasedOnStyle: LLVM
|
||||
UseTab: AlignWithSpaces
|
||||
IndentWidth: 4
|
||||
TabWidth: 4
|
||||
BreakBeforeBraces: Allman
|
||||
ColumnLimit: 0
|
||||
NamespaceIndentation: Inner
|
||||
FixNamespaceComments: true
|
||||
AccessModifierOffset: -2
|
||||
AllowShortCaseLabelsOnASingleLine: true
|
||||
IndentCaseLabels: true
|
||||
BreakConstructorInitializers: BeforeComma
|
||||
BraceWrapping:
|
||||
BeforeLambdaBody: false
|
||||
AlignAfterOpenBracket: DontAlign
|
||||
Cpp11BracedListStyle: false
|
||||
IncludeBlocks: Regroup
|
||||
LambdaBodyIndentation: Signature
|
||||
AllowShortLambdasOnASingleLine: Inline
|
||||
EmptyLineBeforeAccessModifier: LogicalBlock
|
||||
IndentPPDirectives: AfterHash
|
||||
PPIndentWidth: 1
|
||||
18
.clang-tidy
18
.clang-tidy
@@ -1,18 +0,0 @@
|
||||
Checks: '-*,
|
||||
bugprone-*,
|
||||
-bugprone-easily-swappable-parameters,
|
||||
cert-*,
|
||||
modernize*,
|
||||
-modernize-use-trailing-return-type,
|
||||
-modernize-avoid-c-arrays,
|
||||
-modernize-use-designated-initializers,
|
||||
performance
|
||||
'
|
||||
|
||||
# HeaderFilterRegex: '.*'
|
||||
ExcludeHeaderFilterRegex: 'Eigen|Eigen/Eigenvalues|eigen3/Eigen/Eigenvalues|sqlite3.h'
|
||||
CheckOptions:
|
||||
- key: bugprone-narrowing-conversions.WarnOnIntegerNarrowingConversion
|
||||
value: false
|
||||
- key: bugprone-narrowing-conversions.WarnOnIntegerToFloatingPointNarrowingConversion
|
||||
value: false
|
||||
6
.github/workflows/build-documentation.yml
vendored
6
.github/workflows/build-documentation.yml
vendored
@@ -19,7 +19,7 @@ jobs:
|
||||
docs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v1
|
||||
|
||||
- name: Set reusable strings
|
||||
# Turn repeated input strings (such as the build output directory) into step outputs. These step outputs can be used throughout the workflow file.
|
||||
@@ -47,7 +47,7 @@ jobs:
|
||||
ls -l ${{ steps.strings.outputs.build-output-dir }}/docs/sphinx
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-pages-artifact@v3
|
||||
uses: actions/upload-pages-artifact@v2
|
||||
with:
|
||||
path: ${{ steps.strings.outputs.build-output-dir }}/docs/sphinx
|
||||
|
||||
@@ -62,4 +62,4 @@ jobs:
|
||||
steps:
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v4
|
||||
uses: actions/deploy-pages@v2
|
||||
|
||||
7
.github/workflows/cmake-multi-platform.yml
vendored
7
.github/workflows/cmake-multi-platform.yml
vendored
@@ -33,18 +33,13 @@ jobs:
|
||||
|
||||
- name: Install dependencies Ubuntu
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
run: sudo apt-get update && sudo apt-get install mrc catch2 libsqlite3-dev
|
||||
run: sudo apt-get update && sudo apt-get install mrc
|
||||
|
||||
- name: Install dependencies Window
|
||||
if: matrix.os == 'windows-latest'
|
||||
run: ./tools/depends.cmd
|
||||
shell: cmd
|
||||
|
||||
- name: Install Catch2 macOS
|
||||
if: matrix.os == 'macos-latest'
|
||||
run: >
|
||||
brew install catch2 fast_float
|
||||
|
||||
- name: Configure CMake
|
||||
run: >
|
||||
cmake -B ${{ steps.strings.outputs.build-output-dir }}
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -13,6 +13,3 @@ docs/api
|
||||
docs/conf.py
|
||||
build_ci/
|
||||
data/components.cif
|
||||
perf.data*
|
||||
.cache/
|
||||
|
||||
|
||||
22
.readthedocs.yaml
Normal file
22
.readthedocs.yaml
Normal file
@@ -0,0 +1,22 @@
|
||||
version: 2
|
||||
|
||||
build:
|
||||
os: ubuntu-22.04
|
||||
tools:
|
||||
python: "3.11"
|
||||
apt_packages:
|
||||
- doxygen
|
||||
- cmake
|
||||
jobs:
|
||||
pre_build:
|
||||
- cmake -S . -B build -DBUILD_DOCUMENTATION=ON
|
||||
- cmake --build build --target Doxygen
|
||||
|
||||
# Build from the docs/ directory with Sphinx
|
||||
sphinx:
|
||||
configuration: docs/conf.py
|
||||
|
||||
# Explicitly set the version of Python and its requirements
|
||||
python:
|
||||
install:
|
||||
- requirements: docs/requirements.txt
|
||||
755
CMakeLists.txt
755
CMakeLists.txt
@@ -24,178 +24,208 @@
|
||||
|
||||
cmake_minimum_required(VERSION 3.23)
|
||||
|
||||
cmake_policy(SET CMP0135 NEW)
|
||||
|
||||
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR AND NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
||||
set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE)
|
||||
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
|
||||
endif()
|
||||
|
||||
# set the project name
|
||||
project(
|
||||
libcifpp
|
||||
VERSION 10.0.4
|
||||
LANGUAGES CXX C)
|
||||
libcifpp
|
||||
VERSION 8.0.0
|
||||
LANGUAGES CXX)
|
||||
|
||||
list(PREPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
||||
|
||||
include(FindAtomic)
|
||||
include(CheckFunctionExists)
|
||||
include(CheckIncludeFiles)
|
||||
include(CheckLibraryExists)
|
||||
include(CMakePackageConfigHelpers)
|
||||
include(CheckCXXSourceCompiles)
|
||||
include(GenerateExportHeader)
|
||||
include(CTest)
|
||||
include(ExternalProject)
|
||||
include(FetchContent)
|
||||
include(VersionString)
|
||||
include(ExternalProject)
|
||||
|
||||
# FindBoost, take care of it now.
|
||||
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.30)
|
||||
cmake_policy(SET CMP0167 NEW)
|
||||
endif()
|
||||
|
||||
# When building with ninja-multiconfig, build both debug and release by default
|
||||
if(CMAKE_GENERATOR STREQUAL "Ninja Multi-Config")
|
||||
set(CMAKE_CROSS_CONFIGS "Debug;Release")
|
||||
set(CMAKE_DEFAULT_CONFIGS "Debug;Release")
|
||||
set(CMAKE_CROSS_CONFIGS "Debug;Release")
|
||||
set(CMAKE_DEFAULT_CONFIGS "Debug;Release")
|
||||
endif()
|
||||
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
set(CMAKE_CXX_FLAGS
|
||||
"${CMAKE_CXX_FLAGS} -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers"
|
||||
)
|
||||
set(CMAKE_CXX_FLAGS
|
||||
"${CMAKE_CXX_FLAGS} -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers"
|
||||
)
|
||||
elseif(MSVC)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
|
||||
endif()
|
||||
|
||||
# Build documentation?
|
||||
set(BUILD_DOCUMENTATION OFF CACHE BOOL "Build the documentation")
|
||||
|
||||
# Build examples?
|
||||
set(BUILD_EXAMPLES ON CACHE BOOL "Build the example applications")
|
||||
option(BUILD_DOCUMENTATION "Build the documentation" OFF)
|
||||
|
||||
# Optionally build a version to be installed inside CCP4
|
||||
set(BUILD_FOR_CCP4 OFF CACHE BOOL "Build a version to be installed in CCP4")
|
||||
|
||||
# Create the cql/sqlite interface
|
||||
set(BUILD_SQLITE_INTERFACE ON CACHE BOOL "Build the sqlite interface")
|
||||
option(BUILD_FOR_CCP4 "Build a version to be installed in CCP4")
|
||||
|
||||
# Building shared libraries?
|
||||
if(NOT (BUILD_FOR_CCP4 AND WIN32))
|
||||
set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build a shared library instead of a static one")
|
||||
if(NOT(BUILD_FOR_CCP4 AND WIN32))
|
||||
option(BUILD_SHARED_LIBS "Build a shared library instead of a static one" OFF)
|
||||
endif()
|
||||
|
||||
if(PROJECT_IS_TOP_LEVEL AND NOT BUILD_FOR_CCP4)
|
||||
# Lots of code depend on the availability of the components.cif file
|
||||
set(CIFPP_DOWNLOAD_CCD ON CACHE BOOL "Download the CCD file components.cif during installation")
|
||||
# Lots of code depend on the availability of the components.cif file
|
||||
option(CIFPP_DOWNLOAD_CCD
|
||||
"Download the CCD file components.cif during installation" ON)
|
||||
|
||||
# An optional cron script can be installed to keep the data files up-to-date
|
||||
if(UNIX AND NOT APPLE)
|
||||
set(CIFPP_INSTALL_UPDATE_SCRIPT ON CACHE BOOL "Install the script to update CCD and dictionary files")
|
||||
endif()
|
||||
# An optional cron script can be installed to keep the data files up-to-date
|
||||
if(UNIX AND NOT APPLE)
|
||||
option(CIFPP_INSTALL_UPDATE_SCRIPT
|
||||
"Install the script to update CCD and dictionary files" ON)
|
||||
endif()
|
||||
else()
|
||||
unset(CIFPP_DOWNLOAD_CCD)
|
||||
unset(CIFPP_INSTALL_UPDATE_SCRIPT)
|
||||
unset(CIFPP_DOWNLOAD_CCD)
|
||||
unset(CIFPP_INSTALL_UPDATE_SCRIPT)
|
||||
endif()
|
||||
|
||||
# When CCP4 is sourced in the environment, we can recreate the symmetry
|
||||
# operations table
|
||||
if(EXISTS "$ENV{CCP4}/lib/data/syminfo.lib")
|
||||
set(CIFPP_RECREATE_SYMOP_DATA ON CACHE BOOL "Recreate SymOp data table in case it is out of date")
|
||||
option(CIFPP_RECREATE_SYMOP_DATA
|
||||
"Recreate SymOp data table in case it is out of date" ON)
|
||||
endif()
|
||||
|
||||
# CCP4 build
|
||||
if(BUILD_FOR_CCP4)
|
||||
if("$ENV{CCP4}" STREQUAL "" OR NOT EXISTS $ENV{CCP4})
|
||||
message(FATAL_ERROR "cifpp: A CCP4 built was requested but CCP4 was not sourced")
|
||||
else()
|
||||
list(PREPEND CMAKE_MODULE_PATH "$ENV{CCP4}")
|
||||
list(PREPEND CMAKE_PREFIX_PATH "$ENV{CCP4}")
|
||||
set(CMAKE_INSTALL_PREFIX "$ENV{CCP4}")
|
||||
if("$ENV{CCP4}" STREQUAL "" OR NOT EXISTS $ENV{CCP4})
|
||||
message(FATAL_ERROR "A CCP4 built was requested but CCP4 was not sourced")
|
||||
else()
|
||||
list(PREPEND CMAKE_MODULE_PATH "$ENV{CCP4}")
|
||||
list(PREPEND CMAKE_PREFIX_PATH "$ENV{CCP4}")
|
||||
set(CMAKE_INSTALL_PREFIX "$ENV{CCP4}")
|
||||
|
||||
if(WIN32)
|
||||
set(BUILD_SHARED_LIBS ON)
|
||||
endif()
|
||||
endif()
|
||||
if(WIN32)
|
||||
set(BUILD_SHARED_LIBS ON)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Now include the GNUInstallDirs module
|
||||
include(GNUInstallDirs)
|
||||
|
||||
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()
|
||||
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()
|
||||
|
||||
# We do not want to write an export file for all our symbols...
|
||||
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
|
||||
# Man, this is 2024 we're living in...
|
||||
add_definitions(-DNOMINMAX)
|
||||
|
||||
# We do not want to write an export file for all our symbols...
|
||||
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
# make msvc standards compliant...
|
||||
add_compile_options(/permissive- /bigobj)
|
||||
add_link_options(/NODEFAULTLIB:library)
|
||||
# make msvc standards compliant...
|
||||
add_compile_options(/permissive- /bigobj)
|
||||
add_link_options(/NODEFAULTLIB:library)
|
||||
|
||||
# This is dubious...
|
||||
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
|
||||
|
||||
# Start by finding out if std:regex is usable. Note that the current
|
||||
# implementation in GCC is not acceptable, it crashes on long lines. The
|
||||
# implementation in libc++ (clang) and MSVC seem to be OK.
|
||||
check_cxx_source_compiles(
|
||||
"
|
||||
#include <iostream>
|
||||
#ifndef __GLIBCXX__
|
||||
#error
|
||||
#endif
|
||||
int main(int argc, char *argv[]) { return 0; }"
|
||||
GXX_LIBSTDCPP)
|
||||
|
||||
if(GXX_LIBSTDCPP)
|
||||
message(
|
||||
STATUS "Testing for known regex bug, since you're using GNU libstdc++")
|
||||
|
||||
try_run(STD_REGEX_RUNNING STD_REGEX_COMPILING
|
||||
${CMAKE_CURRENT_BINARY_DIR}/test
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/cmake/test-rx.cpp)
|
||||
|
||||
if(STD_REGEX_RUNNING STREQUAL FAILED_TO_RUN)
|
||||
message(
|
||||
STATUS
|
||||
"You are probably trying to compile using the g++ standard library which contains a crashing std::regex implementation. Will use boost::regex instead"
|
||||
)
|
||||
|
||||
find_package(Boost 1.80 QUIET COMPONENTS regex)
|
||||
|
||||
if(NOT Boost_FOUND)
|
||||
set(BOOST_REGEX_STANDALONE ON)
|
||||
|
||||
FetchContent_Declare(
|
||||
boost-rx
|
||||
GIT_REPOSITORY https://github.com/boostorg/regex
|
||||
GIT_TAG boost-1.83.0)
|
||||
|
||||
FetchContent_MakeAvailable(boost-rx)
|
||||
endif()
|
||||
|
||||
set(BOOST_REGEX ON)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
# Avoid linking the shared library of zlib. Search ZLIB_ROOT first if it is
|
||||
# set.
|
||||
if(ZLIB_ROOT)
|
||||
set(_ZLIB_SEARCH_ROOT PATHS ${ZLIB_ROOT} NO_DEFAULT_PATH)
|
||||
list(APPEND _ZLIB_SEARCHES _ZLIB_SEARCH_ROOT)
|
||||
endif()
|
||||
# Avoid linking the shared library of zlib Search ZLIB_ROOT first if it is
|
||||
# set.
|
||||
if(ZLIB_ROOT)
|
||||
set(_ZLIB_SEARCH_ROOT PATHS ${ZLIB_ROOT} NO_DEFAULT_PATH)
|
||||
list(APPEND _ZLIB_SEARCHES _ZLIB_SEARCH_ROOT)
|
||||
endif()
|
||||
|
||||
# Normal search.
|
||||
set(_ZLIB_x86 "(x86)")
|
||||
set(_ZLIB_SEARCH_NORMAL
|
||||
PATHS "[HKEY_LOCAL_MACHINE\\SOFTWARE\\GnuWin32\\Zlib;InstallPath]"
|
||||
"$ENV{ProgramFiles}/zlib" "$ENV{ProgramFiles${_ZLIB_x86}}/zlib")
|
||||
unset(_ZLIB_x86)
|
||||
list(APPEND _ZLIB_SEARCHES _ZLIB_SEARCH_NORMAL)
|
||||
# Normal search.
|
||||
set(_ZLIB_x86 "(x86)")
|
||||
set(_ZLIB_SEARCH_NORMAL
|
||||
PATHS "[HKEY_LOCAL_MACHINE\\SOFTWARE\\GnuWin32\\Zlib;InstallPath]"
|
||||
"$ENV{ProgramFiles}/zlib" "$ENV{ProgramFiles${_ZLIB_x86}}/zlib")
|
||||
unset(_ZLIB_x86)
|
||||
list(APPEND _ZLIB_SEARCHES _ZLIB_SEARCH_NORMAL)
|
||||
|
||||
if(BUILD_FOR_CCP4)
|
||||
list(PREPEND _ZLIB_SEARCHES "$ENV{CCP4}/lib")
|
||||
endif()
|
||||
if(BUILD_FOR_CCP4)
|
||||
list(PREPEND _ZLIB_SEARCHES "$ENV{CCP4}/lib")
|
||||
endif()
|
||||
|
||||
foreach(search ${_ZLIB_SEARCHES})
|
||||
find_library(
|
||||
ZLIB_LIBRARY
|
||||
NAMES zlibstatic NAMES_PER_DIR ${${search}}
|
||||
PATH_SUFFIXES lib)
|
||||
endforeach()
|
||||
foreach(search ${_ZLIB_SEARCHES})
|
||||
find_library(
|
||||
ZLIB_LIBRARY
|
||||
NAMES zlibstatic NAMES_PER_DIR ${${search}}
|
||||
PATH_SUFFIXES lib)
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
# Using fast_float for float parsing, but only if needed
|
||||
try_compile(STD_CHARCONV_COMPILING
|
||||
SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/cmake/test-charconv.cpp
|
||||
CXX_STANDARD 20
|
||||
CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
if(NOT STD_CHARCONV_COMPILING)
|
||||
message(NOTICE "libcifpp: Using fast_float for std::from_chars")
|
||||
find_package(FastFloat 8.0 REQUIRED CONFIG)
|
||||
endif()
|
||||
|
||||
find_package(Threads)
|
||||
find_package(ZLIB QUIET)
|
||||
find_package(Threads)
|
||||
|
||||
if(NOT ZLIB_FOUND)
|
||||
message(FATAL_ERROR "cifpp: The zlib development files were not found you this system, please install them and try again (hint: on debian/ubuntu use apt-get install zlib1g-dev)")
|
||||
endif()
|
||||
|
||||
include(FindPkgConfig)
|
||||
|
||||
if(PKG_CONFIG_FOUND)
|
||||
pkg_check_modules(PCRE2 IMPORTED_TARGET libpcre2-8)
|
||||
endif()
|
||||
|
||||
if(NOT PCRE2_FOUND)
|
||||
add_subdirectory(pcre2-simple)
|
||||
message(FATAL_ERROR "The zlib development files were not found you this system, please install them and try again (hint: on debian/ubuntu use apt-get install zlib1g-dev)")
|
||||
endif()
|
||||
|
||||
# Using Eigen3 is a bit of a thing. We don't want to build it completely since
|
||||
@@ -204,375 +234,354 @@ endif()
|
||||
find_package(Eigen3 3.4 QUIET)
|
||||
|
||||
if(Eigen3_FOUND AND TARGET Eigen3::Eigen)
|
||||
get_target_property(EIGEN_INCLUDE_DIR Eigen3::Eigen
|
||||
INTERFACE_INCLUDE_DIRECTORIES)
|
||||
get_target_property(EIGEN_INCLUDE_DIR Eigen3::Eigen
|
||||
INTERFACE_INCLUDE_DIRECTORIES)
|
||||
else()
|
||||
# Use ExternalProject since FetchContent always tries to install the result...
|
||||
ExternalProject_Add(my-eigen3
|
||||
URL https://gitlab.com/libeigen/eigen/-/archive/3.4.0/eigen-3.4.0.zip
|
||||
DOWNLOAD_EXTRACT_TIMESTAMP TRUE
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND "")
|
||||
|
||||
ExternalProject_Get_Property(my-eigen3 SOURCE_DIR)
|
||||
set(EIGEN_INCLUDE_DIR ${SOURCE_DIR})
|
||||
# Use ExternalProject since FetchContent always tries to install the result...
|
||||
ExternalProject_Add(my-eigen3
|
||||
GIT_REPOSITORY https://gitlab.com/libeigen/eigen.git
|
||||
GIT_TAG 3.4.0
|
||||
INSTALL_COMMAND "")
|
||||
|
||||
ExternalProject_Get_Property(my-eigen3 SOURCE_DIR)
|
||||
set(EIGEN_INCLUDE_DIR ${SOURCE_DIR})
|
||||
endif()
|
||||
|
||||
message(STATUS "Eigen include dir is ${EIGEN_INCLUDE_DIR}")
|
||||
|
||||
# Create a revision file, containing the current git version info
|
||||
include(VersionString)
|
||||
write_version_header(${CMAKE_CURRENT_SOURCE_DIR}/src/ LIB_NAME "LibCIFPP")
|
||||
|
||||
# SymOp data table
|
||||
if(CIFPP_RECREATE_SYMOP_DATA)
|
||||
# The tool to create the table
|
||||
add_executable(symop-map-generator
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/symop-map-generator.cpp")
|
||||
# The tool to create the table
|
||||
add_executable(symop-map-generator
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/symop-map-generator.cpp")
|
||||
|
||||
target_compile_features(symop-map-generator PUBLIC cxx_std_20)
|
||||
target_compile_features(symop-map-generator PUBLIC cxx_std_20)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/src/symop_table_data.hpp
|
||||
COMMAND
|
||||
$<TARGET_FILE:symop-map-generator> $ENV{CLIBD}/syminfo.lib
|
||||
$ENV{CLIBD}/symop.lib ${CMAKE_CURRENT_SOURCE_DIR}/src/symop_table_data.hpp)
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/src/symop_table_data.hpp
|
||||
COMMAND
|
||||
$<TARGET_FILE:symop-map-generator> $ENV{CLIBD}/syminfo.lib
|
||||
$ENV{CLIBD}/symop.lib ${CMAKE_CURRENT_SOURCE_DIR}/src/symop_table_data.hpp)
|
||||
|
||||
add_custom_target(
|
||||
OUTPUT
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/symop_table_data.hpp
|
||||
DEPENDS symop-map-generator "$ENV{CLIBD}/syminfo.lib"
|
||||
"$ENV{CLIBD}/symop.lib")
|
||||
add_custom_target(
|
||||
OUTPUT
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/symop_table_data.hpp
|
||||
DEPENDS symop-map-generator "$ENV{CLIBD}/syminfo.lib"
|
||||
"$ENV{CLIBD}/symop.lib")
|
||||
endif()
|
||||
|
||||
# Create a revision file, containing the current git version info
|
||||
write_version_header("${CMAKE_CURRENT_SOURCE_DIR}/src/" LIB_NAME "LibCIFPP")
|
||||
# Sources
|
||||
set(project_sources
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/category.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/condition.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/datablock.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/dictionary_parser.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/file.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/item.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/parser.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/row.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/validate.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/text.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/utilities.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/atom_type.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/compound.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/point.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/symmetry.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/model.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/pdb/cif2pdb.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/pdb/pdb2cif.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/pdb/pdb_record.hpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/pdb/pdb2cif_remark_3.hpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/pdb/pdb2cif_remark_3.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/pdb/reconstruct.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/pdb/validate-pdbx.cpp
|
||||
)
|
||||
|
||||
set(project_headers
|
||||
include/cif++.hpp
|
||||
include/cif++/atom_type.hpp
|
||||
include/cif++/category.hpp
|
||||
include/cif++/compound.hpp
|
||||
include/cif++/condition.hpp
|
||||
include/cif++/datablock.hpp
|
||||
include/cif++/dictionary_parser.hpp
|
||||
include/cif++/exports.hpp
|
||||
include/cif++/file.hpp
|
||||
include/cif++/format.hpp
|
||||
include/cif++/forward_decl.hpp
|
||||
include/cif++/gzio.hpp
|
||||
include/cif++/item.hpp
|
||||
include/cif++/iterator.hpp
|
||||
include/cif++/matrix.hpp
|
||||
include/cif++/model.hpp
|
||||
include/cif++/parser.hpp
|
||||
include/cif++/pdb/cif2pdb.hpp
|
||||
include/cif++/pdb.hpp
|
||||
include/cif++/pdb/io.hpp
|
||||
include/cif++/pdb/pdb2cif.hpp
|
||||
include/cif++/pdb/tls.hpp
|
||||
include/cif++/point.hpp
|
||||
include/cif++/row.hpp
|
||||
include/cif++/symmetry.hpp
|
||||
include/cif++/text.hpp
|
||||
include/cif++/utilities.hpp
|
||||
include/cif++/validate.hpp
|
||||
)
|
||||
|
||||
add_library(cifpp)
|
||||
add_library(cifpp::cifpp ALIAS cifpp)
|
||||
|
||||
# Sources
|
||||
list(APPEND project_sources
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/category.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/condition.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/datablock.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/dictionary_parser.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/file.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/item.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/parser.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/row.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/validate.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/text.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/utilities.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/atom_type.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/compound.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/point.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/symmetry.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/model.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/pdb/cif2pdb.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/pdb/pdb2cif.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/pdb/pdb_record.hpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/pdb/pdb2cif_remark_3.hpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/pdb/pdb2cif_remark_3.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/pdb/reconstruct.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/pdb/validate-pdbx.cpp
|
||||
)
|
||||
|
||||
list(APPEND project_headers
|
||||
include/cif++.hpp
|
||||
include/cif++/cif++.hpp
|
||||
include/cif++/atom_type.hpp
|
||||
include/cif++/category.hpp
|
||||
include/cif++/compound.hpp
|
||||
include/cif++/condition.hpp
|
||||
include/cif++/datablock.hpp
|
||||
include/cif++/dictionary_parser.hpp
|
||||
include/cif++/exports.hpp
|
||||
include/cif++/file.hpp
|
||||
include/cif++/format.hpp
|
||||
include/cif++/gzio.hpp
|
||||
include/cif++/item.hpp
|
||||
include/cif++/iterator.hpp
|
||||
include/cif++/matrix.hpp
|
||||
include/cif++/model.hpp
|
||||
include/cif++/parser.hpp
|
||||
include/cif++/pdb.hpp
|
||||
include/cif++/point.hpp
|
||||
include/cif++/row.hpp
|
||||
include/cif++/symmetry.hpp
|
||||
include/cif++/text.hpp
|
||||
include/cif++/utilities.hpp
|
||||
include/cif++/validate.hpp
|
||||
)
|
||||
|
||||
if(BUILD_SQLITE_INTERFACE)
|
||||
find_package(SQLite3 QUIET)
|
||||
if(SQLite3_FOUND)
|
||||
target_link_libraries(cifpp PRIVATE SQLite::SQLite3)
|
||||
else()
|
||||
FetchContent_Populate(SQLite3
|
||||
URL https://sqlite.org/2025/sqlite-amalgamation-3510100.zip
|
||||
URL_HASH SHA3_256=856b52ffe7383d779bb86a0ed1ddc19c41b0e5751fa14ce6312f27534e629b64
|
||||
EXCLUDE_FROM_ALL)
|
||||
|
||||
list(APPEND project_sources $<BUILD_INTERFACE:${sqlite3_SOURCE_DIR}>/sqlite3.c)
|
||||
target_include_directories(cifpp PRIVATE $<BUILD_INTERFACE:${sqlite3_SOURCE_DIR}>)
|
||||
endif()
|
||||
|
||||
list(APPEND project_sources ${CMAKE_CURRENT_SOURCE_DIR}/src/cql.cpp)
|
||||
list(APPEND project_headers include/cif++/cql.hpp)
|
||||
endif()
|
||||
|
||||
if(TARGET my-eigen3)
|
||||
add_dependencies(cifpp my-eigen3)
|
||||
add_dependencies(cifpp my-eigen3)
|
||||
endif()
|
||||
|
||||
target_sources(cifpp
|
||||
PRIVATE ${project_sources}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/symop_table_data.hpp
|
||||
PUBLIC
|
||||
FILE_SET cifpp_headers TYPE HEADERS
|
||||
BASE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||
FILES ${project_headers}
|
||||
PRIVATE ${project_sources}
|
||||
${CMAKE_CURRENT_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_23)
|
||||
target_compile_features(cifpp PUBLIC cxx_std_20)
|
||||
|
||||
set(CMAKE_DEBUG_POSTFIX d)
|
||||
set_target_properties(cifpp PROPERTIES DEBUG_POSTFIX "d")
|
||||
|
||||
generate_export_header(cifpp EXPORT_FILE_NAME
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/cif++/exports.hpp)
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/cif++/exports.hpp)
|
||||
|
||||
if(BOOST_REGEX)
|
||||
target_compile_definitions(cifpp PRIVATE USE_BOOST_REGEX=1
|
||||
BOOST_REGEX_STANDALONE=1)
|
||||
get_target_property(BOOST_REGEX_INCLUDE_DIR Boost::regex
|
||||
INTERFACE_INCLUDE_DIRECTORIES)
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
target_compile_definitions(cifpp PUBLIC NOMINMAX=1)
|
||||
target_compile_definitions(cifpp PUBLIC NOMINMAX=1)
|
||||
endif()
|
||||
|
||||
set_target_properties(cifpp PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
target_include_directories(
|
||||
cifpp
|
||||
PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
|
||||
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
|
||||
PRIVATE "${EIGEN_INCLUDE_DIR}")
|
||||
cifpp
|
||||
PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
|
||||
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
|
||||
PRIVATE "${BOOST_REGEX_INCLUDE_DIR}" "${EIGEN_INCLUDE_DIR}")
|
||||
|
||||
target_link_libraries(cifpp
|
||||
PUBLIC Threads::Threads ZLIB::ZLIB $<$<TARGET_EXISTS:std::atomic>:std::atomic>)
|
||||
|
||||
if(PCRE2_FOUND)
|
||||
target_include_directories(cifpp PRIVATE ${PCRE2_INCLUDE_DIRS})
|
||||
target_link_libraries(cifpp PRIVATE ${PCRE2_LINK_LIBRARIES})
|
||||
else()
|
||||
target_link_libraries(cifpp PRIVATE $<BUILD_INTERFACE:pcre2s>)
|
||||
endif()
|
||||
|
||||
if(NOT STD_CHARCONV_COMPILING)
|
||||
get_target_property(FF_INC_DIR FastFloat::fast_float INTERFACE_INCLUDE_DIRECTORIES)
|
||||
target_include_directories(cifpp PRIVATE ${FF_INC_DIR})
|
||||
target_compile_definitions(cifpp PRIVATE USE_FAST_FLOAT)
|
||||
endif()
|
||||
target_link_libraries(cifpp PUBLIC Threads::Threads ZLIB::ZLIB $<$<TARGET_EXISTS:std::atomic>:std::atomic>)
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
|
||||
target_link_options(cifpp PRIVATE -undefined dynamic_lookup)
|
||||
target_link_options(cifpp PRIVATE -undefined dynamic_lookup)
|
||||
endif(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
|
||||
|
||||
if(CIFPP_DOWNLOAD_CCD)
|
||||
# download the components.cif file from CCD
|
||||
set(COMPONENTS_CIF ${CMAKE_CURRENT_SOURCE_DIR}/rsrc/components.cif)
|
||||
# download the components.cif file from CCD
|
||||
set(COMPONENTS_CIF ${CMAKE_CURRENT_SOURCE_DIR}/rsrc/components.cif)
|
||||
|
||||
if(EXISTS ${COMPONENTS_CIF})
|
||||
file(SIZE ${COMPONENTS_CIF} CCD_FILE_SIZE)
|
||||
if(EXISTS ${COMPONENTS_CIF})
|
||||
file(SIZE ${COMPONENTS_CIF} CCD_FILE_SIZE)
|
||||
|
||||
if(CCD_FILE_SIZE EQUAL 0)
|
||||
message(STATUS "cifpp: Removing empty ${COMPONENTS_CIF} file")
|
||||
file(REMOVE "${COMPONENTS_CIF}")
|
||||
endif()
|
||||
endif()
|
||||
if(CCD_FILE_SIZE EQUAL 0)
|
||||
message(STATUS "Removing empty ${COMPONENTS_CIF} file")
|
||||
file(REMOVE "${COMPONENTS_CIF}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT EXISTS ${COMPONENTS_CIF})
|
||||
# Since the file(DOWNLOAD) command in cmake does not use compression, we try
|
||||
# to download the gzipped version and decompress it ourselves.
|
||||
find_program(GUNZIP gunzip)
|
||||
if(NOT EXISTS ${COMPONENTS_CIF})
|
||||
# Since the file(DOWNLOAD) command in cmake does not use compression, we try
|
||||
# to download the gzipped version and decompress it ourselves.
|
||||
find_program(GUNZIP gunzip)
|
||||
|
||||
if(WIN32 OR GUNZIP STREQUAL "GUNZIP-NOTFOUND")
|
||||
file(
|
||||
DOWNLOAD https://files.wwpdb.org/pub/pdb/data/monomers/components.cif
|
||||
${COMPONENTS_CIF}
|
||||
SHOW_PROGRESS
|
||||
STATUS CCD_FETCH_STATUS)
|
||||
else()
|
||||
if(NOT EXISTS "${COMPONENTS_CIF}.gz")
|
||||
file(
|
||||
DOWNLOAD
|
||||
https://files.wwpdb.org/pub/pdb/data/monomers/components.cif.gz
|
||||
${COMPONENTS_CIF}.gz
|
||||
SHOW_PROGRESS
|
||||
STATUS CCD_FETCH_STATUS)
|
||||
endif()
|
||||
if(WIN32 OR GUNZIP STREQUAL "GUNZIP-NOTFOUND")
|
||||
file(
|
||||
DOWNLOAD https://files.wwpdb.org/pub/pdb/data/monomers/components.cif
|
||||
${COMPONENTS_CIF}
|
||||
SHOW_PROGRESS
|
||||
STATUS CCD_FETCH_STATUS)
|
||||
else()
|
||||
if(NOT EXISTS "${COMPONENTS_CIF}.gz")
|
||||
file(
|
||||
DOWNLOAD
|
||||
https://files.wwpdb.org/pub/pdb/data/monomers/components.cif.gz
|
||||
${COMPONENTS_CIF}.gz
|
||||
SHOW_PROGRESS
|
||||
STATUS CCD_FETCH_STATUS)
|
||||
endif()
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${COMPONENTS_CIF}
|
||||
COMMAND "${GUNZIP}" ${COMPONENTS_CIF}.gz
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/rsrc/)
|
||||
add_custom_command(
|
||||
OUTPUT ${COMPONENTS_CIF}
|
||||
COMMAND "${GUNZIP}" ${COMPONENTS_CIF}.gz
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/rsrc/)
|
||||
|
||||
add_custom_target(COMPONENTS ALL DEPENDS ${COMPONENTS_CIF})
|
||||
endif()
|
||||
add_custom_target(COMPONENTS ALL DEPENDS ${COMPONENTS_CIF})
|
||||
endif()
|
||||
|
||||
# Do not continue if downloading went wrong
|
||||
list(POP_FRONT CCD_FETCH_STATUS CCD_FETCH_STATUS_CODE)
|
||||
# Do not continue if downloading went wrong
|
||||
list(POP_FRONT CCD_FETCH_STATUS CCD_FETCH_STATUS_CODE)
|
||||
|
||||
if(CCD_FETCH_STATUS_CODE)
|
||||
message(
|
||||
FATAL_ERROR "cifpp: Error trying to download CCD file: ${CCD_FETCH_STATUS}")
|
||||
endif()
|
||||
endif()
|
||||
if(CCD_FETCH_STATUS_CODE)
|
||||
message(
|
||||
FATAL_ERROR "Error trying to download CCD file: ${CCD_FETCH_STATUS}")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Installation directories
|
||||
if(BUILD_FOR_CCP4)
|
||||
set(CIFPP_DATA_DIR
|
||||
"$ENV{CCP4}/share/libcifpp"
|
||||
CACHE PATH "Directory where dictionary and other static data is stored")
|
||||
set(CIFPP_DATA_DIR
|
||||
"$ENV{CCP4}/share/libcifpp"
|
||||
CACHE PATH "Directory where dictionary and other static data is stored")
|
||||
else()
|
||||
set(CIFPP_DATA_DIR
|
||||
"${CMAKE_INSTALL_FULL_DATADIR}/libcifpp"
|
||||
CACHE PATH "Directory where dictionary and other static data is stored")
|
||||
set(CIFPP_DATA_DIR
|
||||
"${CMAKE_INSTALL_FULL_DATADIR}/libcifpp"
|
||||
CACHE PATH "Directory where dictionary and other static data is stored")
|
||||
endif()
|
||||
|
||||
if(CIFPP_DATA_DIR)
|
||||
target_compile_definitions(cifpp PUBLIC DATA_DIR="${CIFPP_DATA_DIR}")
|
||||
set_target_properties(cifpp PROPERTIES CIFPP_DATA_DIR ${CIFPP_DATA_DIR})
|
||||
target_compile_definitions(cifpp PUBLIC DATA_DIR="${CIFPP_DATA_DIR}")
|
||||
set_target_properties(cifpp PROPERTIES CIFPP_DATA_DIR ${CIFPP_DATA_DIR})
|
||||
endif()
|
||||
|
||||
if(NOT PROJECT_IS_TOP_LEVEL)
|
||||
set(CIFPP_SHARE_DIR ${CIFPP_DATA_DIR} PARENT_SCOPE)
|
||||
set(CIFPP_SHARE_DIR ${CIFPP_DATA_DIR} PARENT_SCOPE)
|
||||
endif()
|
||||
|
||||
if(UNIX AND NOT BUILD_FOR_CCP4)
|
||||
if("${CMAKE_INSTALL_PREFIX}" STREQUAL "/usr/local")
|
||||
set(CIFPP_CACHE_DIR
|
||||
"/var/cache/libcifpp"
|
||||
CACHE PATH "The directory where downloaded data files are stored")
|
||||
else()
|
||||
set(CIFPP_CACHE_DIR
|
||||
"${CMAKE_INSTALL_FULL_LOCALSTATEDIR}/cache/libcifpp"
|
||||
CACHE PATH "The directory where downloaded data files are stored")
|
||||
endif()
|
||||
if("${CMAKE_INSTALL_PREFIX}" STREQUAL "/usr/local")
|
||||
set(CIFPP_CACHE_DIR
|
||||
"/var/cache/libcifpp"
|
||||
CACHE PATH "The directory where downloaded data files are stored")
|
||||
else()
|
||||
set(CIFPP_CACHE_DIR
|
||||
"${CMAKE_INSTALL_FULL_LOCALSTATEDIR}/cache/libcifpp"
|
||||
CACHE PATH "The directory where downloaded data files are stored")
|
||||
endif()
|
||||
|
||||
target_compile_definitions(cifpp PUBLIC CACHE_DIR="${CIFPP_CACHE_DIR}")
|
||||
target_compile_definitions(cifpp PUBLIC CACHE_DIR="${CIFPP_CACHE_DIR}")
|
||||
|
||||
set(CIFPP_ETC_DIR
|
||||
"${CMAKE_INSTALL_FULL_SYSCONFDIR}"
|
||||
CACHE PATH "The directory where the update configuration file is stored")
|
||||
set(CIFPP_ETC_DIR
|
||||
"${CMAKE_INSTALL_FULL_SYSCONFDIR}"
|
||||
CACHE PATH "The directory where the update configuration file is stored")
|
||||
else()
|
||||
unset(CIFPP_CACHE_DIR)
|
||||
unset(CIFPP_CACHE_DIR)
|
||||
endif()
|
||||
|
||||
# Install rules
|
||||
install(TARGETS cifpp
|
||||
EXPORT cifpp
|
||||
FILE_SET cifpp_headers DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
EXPORT cifpp
|
||||
FILE_SET cifpp_headers DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
|
||||
if(MSVC AND BUILD_SHARED_LIBS)
|
||||
install(
|
||||
FILES $<TARGET_PDB_FILE:cifpp>
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
OPTIONAL)
|
||||
install(
|
||||
FILES $<TARGET_PDB_FILE:cifpp>
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
OPTIONAL)
|
||||
endif()
|
||||
|
||||
# Clean up old config files (with old names)
|
||||
file(GLOB OLD_CONFIG_FILES
|
||||
${CMAKE_INSTALL_FULL_LIBDIR}/cmake/cifpp/cifppConfig*.cmake
|
||||
${CMAKE_INSTALL_FULL_LIBDIR}/cmake/cifpp/cifppTargets*.cmake)
|
||||
${CMAKE_INSTALL_FULL_LIBDIR}/cmake/cifpp/cifppConfig*.cmake
|
||||
${CMAKE_INSTALL_FULL_LIBDIR}/cmake/cifpp/cifppTargets*.cmake)
|
||||
|
||||
if(OLD_CONFIG_FILES)
|
||||
message(
|
||||
STATUS "cifpp: Installation will remove old config files: ${OLD_CONFIG_FILES}")
|
||||
install(CODE "file(REMOVE ${OLD_CONFIG_FILES})")
|
||||
message(
|
||||
STATUS "Installation will remove old config files: ${OLD_CONFIG_FILES}")
|
||||
install(CODE "file(REMOVE ${OLD_CONFIG_FILES})")
|
||||
endif()
|
||||
|
||||
install(EXPORT cifpp
|
||||
NAMESPACE cifpp::
|
||||
FILE "cifpp-targets.cmake"
|
||||
DESTINATION lib/cmake/cifpp)
|
||||
NAMESPACE cifpp::
|
||||
FILE "cifpp-targets.cmake"
|
||||
DESTINATION lib/cmake/cifpp)
|
||||
|
||||
install(
|
||||
FILES ${CMAKE_CURRENT_SOURCE_DIR}/rsrc/mmcif_ddl.dic
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rsrc/mmcif_pdbx.dic
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rsrc/mmcif_ma.dic
|
||||
DESTINATION ${CMAKE_INSTALL_DATADIR}/libcifpp)
|
||||
FILES ${CMAKE_CURRENT_SOURCE_DIR}/rsrc/mmcif_ddl.dic
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rsrc/mmcif_pdbx.dic
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rsrc/mmcif_ma.dic
|
||||
DESTINATION ${CMAKE_INSTALL_DATADIR}/libcifpp)
|
||||
|
||||
if(CIFPP_DATA_DIR AND CIFPP_DOWNLOAD_CCD)
|
||||
install(FILES ${COMPONENTS_CIF}
|
||||
DESTINATION ${CMAKE_INSTALL_DATADIR}/libcifpp)
|
||||
install(FILES ${COMPONENTS_CIF}
|
||||
DESTINATION ${CMAKE_INSTALL_DATADIR}/libcifpp)
|
||||
endif()
|
||||
|
||||
set(CONFIG_TEMPLATE_FILE ${CMAKE_CURRENT_SOURCE_DIR}/cmake/cifpp-config.cmake.in)
|
||||
|
||||
configure_package_config_file(
|
||||
${CONFIG_TEMPLATE_FILE} ${CMAKE_CURRENT_BINARY_DIR}/cifpp/cifpp-config.cmake
|
||||
INSTALL_DESTINATION lib/cmake/cifpp
|
||||
PATH_VARS CIFPP_DATA_DIR)
|
||||
${CONFIG_TEMPLATE_FILE} ${CMAKE_CURRENT_BINARY_DIR}/cifpp/cifpp-config.cmake
|
||||
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 lib/cmake/cifpp)
|
||||
FILES "${CMAKE_CURRENT_BINARY_DIR}/cifpp/cifpp-config.cmake"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/cifpp/cifpp-config-version.cmake"
|
||||
DESTINATION lib/cmake/cifpp)
|
||||
|
||||
set_target_properties(
|
||||
cifpp
|
||||
PROPERTIES VERSION ${PROJECT_VERSION}
|
||||
SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}"
|
||||
INTERFACE_cifpp_MAJOR_VERSION ${PROJECT_VERSION_MAJOR})
|
||||
cifpp
|
||||
PROPERTIES VERSION ${PROJECT_VERSION}
|
||||
SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}"
|
||||
INTERFACE_cifpp_MAJOR_VERSION ${PROJECT_VERSION_MAJOR})
|
||||
|
||||
set_property(
|
||||
TARGET cifpp
|
||||
APPEND
|
||||
PROPERTY COMPATIBLE_INTERFACE_STRING cifpp_MAJOR_VERSION)
|
||||
TARGET cifpp
|
||||
APPEND
|
||||
PROPERTY COMPATIBLE_INTERFACE_STRING cifpp_MAJOR_VERSION)
|
||||
|
||||
write_basic_package_version_file(
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/cifpp/cifpp-config-version.cmake"
|
||||
VERSION ${PROJECT_VERSION}
|
||||
COMPATIBILITY AnyNewerVersion)
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/cifpp/cifpp-config-version.cmake"
|
||||
VERSION ${PROJECT_VERSION}
|
||||
COMPATIBILITY AnyNewerVersion)
|
||||
|
||||
if(BUILD_TESTING AND PROJECT_IS_TOP_LEVEL)
|
||||
add_subdirectory(test)
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
|
||||
# Optionally install the update scripts for CCD and dictionary files
|
||||
if(CIFPP_INSTALL_UPDATE_SCRIPT)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/tools/update-libcifpp-data.in
|
||||
update-libcifpp-data @ONLY)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/tools/update-libcifpp-data.in
|
||||
update-libcifpp-data @ONLY)
|
||||
|
||||
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR
|
||||
${CMAKE_SYSTEM_NAME} STREQUAL "GNU" OR
|
||||
${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
|
||||
install(
|
||||
FILES ${CMAKE_CURRENT_BINARY_DIR}/update-libcifpp-data
|
||||
DESTINATION ${CMAKE_INSTALL_SYSCONFDIR}/cron.weekly
|
||||
PERMISSIONS OWNER_EXECUTE OWNER_READ GROUP_EXECUTE GROUP_READ WORLD_EXECUTE
|
||||
WORLD_READ)
|
||||
else()
|
||||
message(FATAL_ERROR "cifpp: Don't know where to install the update script")
|
||||
endif()
|
||||
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR
|
||||
${CMAKE_SYSTEM_NAME} STREQUAL "GNU" OR
|
||||
${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
|
||||
install(
|
||||
FILES ${CMAKE_CURRENT_BINARY_DIR}/update-libcifpp-data
|
||||
DESTINATION ${CMAKE_INSTALL_SYSCONFDIR}/cron.weekly
|
||||
PERMISSIONS OWNER_EXECUTE OWNER_READ GROUP_EXECUTE GROUP_READ WORLD_EXECUTE
|
||||
WORLD_READ)
|
||||
else()
|
||||
message(FATAL_ERROR "Don't know where to install the update script")
|
||||
endif()
|
||||
|
||||
# a config file, to make it complete
|
||||
# install(DIRECTORY DESTINATION "${CMAKE_INSTALL_LOCALSTATEDIR}/libcifpp")
|
||||
if(NOT EXISTS "${CMAKE_INSTALL_SYSCONFDIR}/libcifpp.conf")
|
||||
file(
|
||||
WRITE ${CMAKE_CURRENT_BINARY_DIR}/libcifpp.conf
|
||||
[[# Uncomment the next line to enable automatic updates
|
||||
# a config file, to make it complete
|
||||
# install(DIRECTORY DESTINATION "${CMAKE_INSTALL_LOCALSTATEDIR}/libcifpp")
|
||||
if(NOT EXISTS "${CMAKE_INSTALL_SYSCONFDIR}/libcifpp.conf")
|
||||
file(
|
||||
WRITE ${CMAKE_CURRENT_BINARY_DIR}/libcifpp.conf
|
||||
[[# Uncomment the next line to enable automatic updates
|
||||
# update=true
|
||||
]])
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libcifpp.conf
|
||||
DESTINATION ${CMAKE_INSTALL_SYSCONFDIR})
|
||||
install(
|
||||
CODE "message(\"cifpp: A configuration file has been written to ${CIFPP_ETC_DIR}/libcifpp.conf, please edit this file to enable automatic updates\")"
|
||||
)
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libcifpp.conf
|
||||
DESTINATION ${CMAKE_INSTALL_SYSCONFDIR})
|
||||
install(
|
||||
CODE "message(\"A configuration file has been written to ${CIFPP_ETC_DIR}/libcifpp.conf, please edit this file to enable automatic updates\")"
|
||||
)
|
||||
|
||||
install(DIRECTORY DESTINATION ${CMAKE_INSTALL_SYSCONFDIR}/libcifpp/cache-update.d)
|
||||
endif()
|
||||
install(DIRECTORY DESTINATION ${CMAKE_INSTALL_SYSCONFDIR}/libcifpp/cache-update.d)
|
||||
endif()
|
||||
|
||||
target_compile_definitions(cifpp PUBLIC CACHE_DIR="${CIFPP_CACHE_DIR}")
|
||||
target_compile_definitions(cifpp PUBLIC CACHE_DIR="${CIFPP_CACHE_DIR}")
|
||||
endif()
|
||||
|
||||
if(BUILD_DOCUMENTATION)
|
||||
add_subdirectory(docs)
|
||||
endif()
|
||||
|
||||
if(BUILD_EXAMPLES)
|
||||
add_subdirectory(examples)
|
||||
add_subdirectory(docs)
|
||||
endif()
|
||||
|
||||
14
README.md
14
README.md
@@ -32,13 +32,15 @@ The documentation can be found at [github.io](https://pdb-redo.github.io/libcifp
|
||||
|
||||
## Synopsis
|
||||
|
||||
```cpp
|
||||
```c++
|
||||
// A simple program counting residues with an OXT atom
|
||||
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
|
||||
#include <cif++/cif++.hpp>
|
||||
#include <cif++.hpp>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
@@ -115,8 +117,12 @@ Other libraries you might want to install beforehand are:
|
||||
`libeigen3-dev`
|
||||
- [zlib](https://github.com/madler/zlib), the development version of this
|
||||
library. On Debian/Ubuntu this is the package `zlib1g-dev`.
|
||||
- [pcre2](https://www.pcre.org/), the Perl Compatible Regular Expression
|
||||
library. On Debian/Ubuntu this is the package `libpcre2-dev`.
|
||||
- [boost](https://www.boost.org), in Debian/Ubuntu this is `libboost-dev`.
|
||||
|
||||
The Boost libraries are only needed in case you are using GCC due to a long
|
||||
standing bug in GNU's implementation of std::regex. It simply crashes
|
||||
on the regular expressions used in the mmcif_pdbx dictionary and so
|
||||
we use the boost regex implementation instead.
|
||||
|
||||
### Building
|
||||
|
||||
|
||||
71
changelog
71
changelog
@@ -1,73 +1,3 @@
|
||||
Version 10.0.4
|
||||
- Fixed find_by_value in the index of a category,
|
||||
avoid swapping columns in the search keys
|
||||
|
||||
Version 10.0.3
|
||||
- Clear pdbx_nonpoly_scheme before filling it in reconstruction
|
||||
- Changed handling of numbers with a preceding plus character,
|
||||
these are now stored as strings to avoid inadvertently
|
||||
mutilating phone numbers.
|
||||
|
||||
Version 10.0.2
|
||||
- Fixed regression in reconstruction introduced in 10.0.1
|
||||
- Fixed symmetry operations
|
||||
- Added validation for pdbx_item_enumeration as well as
|
||||
case-sensitive checks for enumerations when needed.
|
||||
|
||||
Version 10.0.1
|
||||
- Fixed some regressions, like assigning to items.
|
||||
- At emplace time (in category) values that are
|
||||
in the wrong type according to a dictionary
|
||||
will be converted/casted. May fail of course.
|
||||
|
||||
Version 10.0.0
|
||||
- Major rewrite of the internal storage of values.
|
||||
Used to be strings only, now there are several
|
||||
basic types.
|
||||
- Modernised code and cleaned up warnings using lint
|
||||
tools
|
||||
|
||||
Version 9.0.6
|
||||
- Various small fixes
|
||||
Version 10.0.0
|
||||
- Added a SQLite interface.
|
||||
|
||||
Version 9.0.5
|
||||
- Added exists to compound_factory
|
||||
- Added sub_matrix, fix and extend determinant calculation
|
||||
- Added yet another structure::create_non_poly
|
||||
- Remove revision.hpp file in make clean (new VersionString.cmake)
|
||||
|
||||
Version 9.0.4
|
||||
- Fix various stopping and reconstruction errors
|
||||
|
||||
Version 9.0.3
|
||||
- Reconstruction fixed when some entity ids are missing
|
||||
|
||||
Version 9.0.2
|
||||
- Fix code that reconstructs sequences, could throw a map::at
|
||||
- Many optimisations in validation and reconstruction code.
|
||||
|
||||
Version 9.0.1
|
||||
- Use pcre2 from pkg-config if available, if not
|
||||
build a version from the original code.
|
||||
|
||||
Version 9.0.0
|
||||
- Rename fields of cif::mm::polymer to match the naming
|
||||
in mmcif_pdbx.dic. Also, related, fix building mm::structure
|
||||
using the correct mapping between atom_site and residues.
|
||||
- _atom_site.auth_alt_id does not exist, it should be
|
||||
_atom_site.pdbx_auth_alt_id of course.
|
||||
- Added a more lightweight fixup for mmcif_pdbx files
|
||||
that lack certain categories.
|
||||
|
||||
Version 8.0.1
|
||||
- Fix cif::mm::structure::cleanup_empty_categories, removed too much
|
||||
- Add default value for B_iso_or_equiv in residue::create_new_atom
|
||||
- Reconstruct some branch records in bare pdbx files
|
||||
- Fix parsing PDB files (bug due to missing validator in dest. cat.)
|
||||
- Do not fail conversion of PDB files when compound info is missing
|
||||
|
||||
Version 8.0.0
|
||||
- A dictionary is for a datablock and a file can have
|
||||
datablocks with differing dictionaries.
|
||||
@@ -77,7 +7,6 @@ Version 7.0.10
|
||||
- Replace code creating quaternions from rotation matrices
|
||||
that might sometimes give incorrect results. Or at least,
|
||||
the test code failed on this particular kind of code. Sometimes.
|
||||
- Fix reconstruction to build pdbx_nonpoly_scheme
|
||||
|
||||
Version 7.0.9
|
||||
- Using cif::file::load_dictionary it is now possible to
|
||||
|
||||
@@ -1,27 +1,3 @@
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
#
|
||||
# Copyright (c) 2026 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.
|
||||
|
||||
# Simple check to see if we need a library for std::atomic
|
||||
|
||||
if(TARGET std::atomic)
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
#
|
||||
# Copyright (c) 2026 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.
|
||||
#
|
||||
# The problem is, find_package(PCRE2) does not work
|
||||
# and using pkg-config results in linking to a shared library
|
||||
# causing all kinds of trouble later on
|
||||
|
||||
find_path(PCRE2_INCLUDEDIR NAMES pcre2.h HINTS "C:/Program Files (x86)/PCRE2/include" REQUIRED)
|
||||
find_library(PCRE2_LIBRARY NAMES pcre2-8-static libpcre2-8.a HINTS "C:/Program Files (x86)/PCRE2/lib" REQUIRED)
|
||||
|
||||
add_library(pcre2-8 IMPORTED STATIC)
|
||||
target_include_directories(pcre2-8 INTERFACE ${PCRE2_INCLUDEDIR})
|
||||
target_compile_definitions(pcre2-8 INTERFACE PCRE2_STATIC)
|
||||
set_target_properties(pcre2-8 PROPERTIES IMPORTED_LOCATION ${PCRE2_LIBRARY})
|
||||
set_target_properties(pcre2-8 PROPERTIES IMPORTED_IMPLIB ${PCRE2_LIBRARY})
|
||||
@@ -1,29 +1,4 @@
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
#
|
||||
# Copyright (c) 2026 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.
|
||||
#
|
||||
#Look for an executable called sphinx-build
|
||||
|
||||
find_program(SPHINX_EXECUTABLE
|
||||
NAMES sphinx-build
|
||||
DOC "Path to sphinx-build executable")
|
||||
|
||||
@@ -238,7 +238,7 @@ function(write_version_header dir)
|
||||
if(res EQUAL 0)
|
||||
set(REVISION_STRING "${out}")
|
||||
else()
|
||||
message(STATUS "Git hash not found, does this project have a 'build' tag?")
|
||||
message(STATUS "Git hash not found, does this project has a 'build' tag?")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "Git hash not found")
|
||||
|
||||
@@ -8,6 +8,5 @@ include(CMakeFindDependencyMacro)
|
||||
|
||||
find_dependency(Threads)
|
||||
find_dependency(ZLIB REQUIRED)
|
||||
find_dependency(SQLite3 REQUIRED)
|
||||
|
||||
check_required_components(cifpp)
|
||||
|
||||
@@ -36,8 +36,7 @@ class version_info_base
|
||||
}
|
||||
|
||||
protected:
|
||||
version_info_base(const char *name, const char *version, int build_number,
|
||||
const char *git_tag, const char *revision_date, bool is_main) noexcept
|
||||
version_info_base(const char *name, const char *version, int build_number, const char *git_tag, const char *revision_date, bool is_main)
|
||||
: m_name(name)
|
||||
, m_version(version)
|
||||
, m_build_number(build_number)
|
||||
@@ -71,13 +70,13 @@ class version_info_base
|
||||
|
||||
using version_info_ptr = version_info_base *;
|
||||
|
||||
static version_info_ptr ®istered_main() noexcept
|
||||
static version_info_ptr ®istered_main()
|
||||
{
|
||||
static version_info_ptr s_main = nullptr;
|
||||
return s_main;
|
||||
}
|
||||
|
||||
static version_info_ptr ®istered_libraries() noexcept
|
||||
static version_info_ptr ®istered_libraries()
|
||||
{
|
||||
static version_info_ptr s_head = nullptr;
|
||||
return s_head;
|
||||
@@ -97,9 +96,7 @@ class version_info : public version_info_base
|
||||
public:
|
||||
using implementation_type = T;
|
||||
|
||||
// NOLINTNEXTLINE
|
||||
version_info(const char *name, const char *version, int build_number,
|
||||
const char *git_tag, const char *revision_date, bool is_main) noexcept
|
||||
version_info(const char *name, const char *version, int build_number, const char *git_tag, const char *revision_date, bool is_main)
|
||||
: version_info_base(name, version, build_number, git_tag, revision_date, is_main)
|
||||
{
|
||||
}
|
||||
@@ -117,9 +114,8 @@ inline void write_version_string(std::ostream &os, bool verbose)
|
||||
const class version_info_@IDENT_PREFIX@impl : public version_info_v1_1::version_info<version_info_@IDENT_PREFIX@impl>
|
||||
{
|
||||
public:
|
||||
version_info_@IDENT_PREFIX@impl() noexcept
|
||||
: version_info(k@VAR_PREFIX@ProjectName, k@VAR_PREFIX@VersionNumber,
|
||||
k@VAR_PREFIX@BuildNumber, k@VAR_PREFIX@RevisionGitTag, k@VAR_PREFIX@RevisionDate, @BOOL_IS_MAIN@)
|
||||
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, @BOOL_IS_MAIN@)
|
||||
{
|
||||
}
|
||||
} s_version_info_@IDENT_PREFIX@instance;
|
||||
|
||||
18
cmake/test-rx.cpp
Normal file
18
cmake/test-rx.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
// See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86164
|
||||
|
||||
#include <iostream>
|
||||
#include <regex>
|
||||
|
||||
int main()
|
||||
{
|
||||
std::string s(100'000, '*');
|
||||
std::smatch m;
|
||||
std::regex r("^(.*?)$");
|
||||
|
||||
std::regex_search(s, m, r);
|
||||
|
||||
std::cout << s.substr(0, 10) << '\n';
|
||||
std::cout << m.str(1).substr(0, 10) << '\n';
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,27 +1,3 @@
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
#
|
||||
# Copyright (c) 2026 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.
|
||||
|
||||
find_package(Doxygen REQUIRED)
|
||||
find_package(Sphinx REQUIRED)
|
||||
|
||||
@@ -40,35 +16,33 @@ set(DOXYFILE_OUT ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile)
|
||||
configure_file(${DOXYFILE_IN} ${DOXYFILE_OUT} @ONLY)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${DOXYGEN_OUTPUT_DIR}
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${DOXYGEN_OUTPUT_DIR})
|
||||
OUTPUT ${DOXYGEN_OUTPUT_DIR}
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${DOXYGEN_OUTPUT_DIR})
|
||||
|
||||
add_custom_command(OUTPUT ${DOXYGEN_INDEX_FILE}
|
||||
DEPENDS ${CIFPP_PUBLIC_HEADERS} ${DOXYGEN_OUTPUT_DIR} ${DOXYFILE_OUT}
|
||||
COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYFILE_OUT}
|
||||
MAIN_DEPENDENCY ${DOXYFILE_OUT} ${DOXYFILE_IN}
|
||||
COMMENT "Generating docs")
|
||||
BYPRODUCTS ${DOXYGEN_OUTPUT_DIR}
|
||||
DEPENDS ${DOXYGEN_OUTPUT_DIR} ${CIFPP_PUBLIC_HEADERS} ${DOXYFILE_OUT}
|
||||
COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYFILE_OUT}
|
||||
MAIN_DEPENDENCY ${DOXYFILE_OUT} ${DOXYFILE_IN}
|
||||
COMMENT "Generating docs")
|
||||
|
||||
add_custom_target("Doxygen-${PROJECT_NAME}" ALL DEPENDS ${DOXYGEN_INDEX_FILE})
|
||||
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/conf.py.in ${CMAKE_CURRENT_SOURCE_DIR}/conf.py @ONLY)
|
||||
|
||||
set(SPHINX_SOURCE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
set(SPHINX_BUILD ${CMAKE_CURRENT_BINARY_DIR}/sphinx)
|
||||
|
||||
add_custom_target("Sphinx-cifpp" ALL
|
||||
COMMAND ${SPHINX_EXECUTABLE} -b html
|
||||
-Dbreathe_projects.cifpp=${DOXYGEN_OUTPUT_DIR}
|
||||
${SPHINX_SOURCE} ${SPHINX_BUILD}
|
||||
DEPENDS ${DOXYGEN_INDEX_FILE}
|
||||
BYPRODUCTS ${CMAKE_CURRENT_SOURCE_DIR}/api
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
COMMENT "Generating documentation with Sphinx")
|
||||
add_custom_target("Sphinx-${PROJECT_NAME}" ALL
|
||||
COMMAND ${SPHINX_EXECUTABLE} -b html
|
||||
-Dbreathe_projects.${PROJECT_NAME}=${DOXYGEN_OUTPUT_DIR}
|
||||
${SPHINX_SOURCE} ${SPHINX_BUILD}
|
||||
DEPENDS ${DOXYGEN_INDEX_FILE}
|
||||
BYPRODUCTS ${CMAKE_CURRENT_SOURCE_DIR}/api
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
COMMENT "Generating documentation with Sphinx")
|
||||
|
||||
set_property(TARGET Sphinx-cifpp APPEND PROPERTY ADDITIONAL_CLEAN_FILES
|
||||
${DOXYGEN_OUTPUT_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/api)
|
||||
|
||||
install(
|
||||
DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/sphinx/
|
||||
DESTINATION ${CMAKE_INSTALL_DOCDIR}
|
||||
PATTERN .doctrees EXCLUDE
|
||||
PATTERN .buildinfo EXCLUDE)
|
||||
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/sphinx/
|
||||
DESTINATION ${CMAKE_INSTALL_DOCDIR}
|
||||
PATTERN .doctrees EXCLUDE
|
||||
PATTERN .buildinfo EXCLUDE)
|
||||
|
||||
@@ -1,67 +1,10 @@
|
||||
# EXCLUDE_SYMBOLS = cif::detail::*, std*
|
||||
EXCLUDE_SYMBOLS = cif::detail::*, std*
|
||||
FILE_PATTERNS = *.hpp
|
||||
STRIP_FROM_PATH = @DOXYGEN_INPUT_DIR@
|
||||
RECURSIVE = YES
|
||||
GENERATE_XML = YES
|
||||
GENERATE_LATEX = NO
|
||||
MACRO_EXPANSION = YES
|
||||
PREDEFINED += and=&& or=|| not=! CIFPP_EXPORT= HAVE_LIBCLIPPER=1
|
||||
GENERATE_HTML = NO
|
||||
GENERATE_TODOLIST = NO
|
||||
INPUT = @DOXYGEN_INPUT_DIR@
|
||||
|
||||
|
||||
# # Doxyfile
|
||||
|
||||
# PROJECT_NAME = "libcifpp"
|
||||
# PROJECT_BRIEF = "C++ library for using mmCIF files"
|
||||
|
||||
# GENERATE_LATEX = NO
|
||||
|
||||
# EXTRACT_ALL = YES
|
||||
# EXTRACT_STATIC = YES
|
||||
# HIDE_UNDOC_CLASSES = NO
|
||||
# SHOW_NAMESPACES = YES
|
||||
# EXTRACT_TEMPLATE_PARAMS = YES
|
||||
|
||||
# CREATE_SUBDIRS = NO
|
||||
# INLINE_GROPUED_CLASSES = YES
|
||||
# INLINE_SIMPLE_STRUCTS = YES
|
||||
|
||||
# NUM_PROC_THREADS = 0
|
||||
|
||||
# EXTRACT_LOCAL_CLASSES = NO
|
||||
# HIDE_IN_BODY_DOCS = YES
|
||||
|
||||
# SHOW_HEADERFILE = NO
|
||||
|
||||
# INPUT = @DOXYGEN_INPUT_DIR@/c++
|
||||
# RECURSIVE = YES
|
||||
# EXAMPLE_PATH = @DOXYGEN_INPUT_DIR@/../examples
|
||||
|
||||
# EXAMPLE_PATTERNS = *.cpp
|
||||
|
||||
# # USE_MDFILE_AS_MAINPAGE = ../README.md
|
||||
|
||||
# ENABLE_PREPROCESSING = YES
|
||||
# MACRO_EXPANSION = YES
|
||||
# INCLUDE_PATH = @DOXYGEN_INPUT_DIR@
|
||||
# INCLUDE_FILE_PATTERNS = *.hpp
|
||||
|
||||
# SKIP_FUNCTION_MACROS = NO
|
||||
|
||||
# # CLANG_ASSISTED_PARSING = YES
|
||||
# # CLANG_ADD_INC_PATHS = YES
|
||||
# # CLANG_OPTIONS = -O0 -std=c++23
|
||||
|
||||
# # GENERATE_HTML = YES
|
||||
# # GENERATE_TREEVIEW = YES
|
||||
|
||||
# GENERATE_XML = YES
|
||||
|
||||
# # EXCLUDE_SYMBOLS = cif::detail::*, std*
|
||||
# # # FILE_PATTERNS = *.hpp
|
||||
# # STRIP_FROM_PATH = @DOXYGEN_INPUT_DIR@
|
||||
# # PREDEFINED += and=&& or=|| not=! CIFPP_EXPORT= HAVE_LIBCLIPPER=1
|
||||
# # GENERATE_HTML = NO
|
||||
# # GENERATE_TODOLIST = NO
|
||||
|
||||
@@ -7,7 +7,7 @@ Reading a file is as simple as:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
#include <cif++/cif++.hpp>
|
||||
#include <cif++.hpp>
|
||||
|
||||
cif::file f("/path/to/file.cif");
|
||||
|
||||
@@ -76,7 +76,7 @@ Categories contain rows of data and each row has fields or items. Referencing a
|
||||
auto rh = atom_site.front();
|
||||
|
||||
// Get the label_atom_id value from this row handle as a std::string
|
||||
std::string atom_id = rh["label_atom_id"].get<std::string>();
|
||||
std::string atom_id = rh["label_atom_id"].as<std::string>();
|
||||
|
||||
// Get the x, y and z coordinates using structered binding
|
||||
const auto &[x, y, z] = rh.get<float,float,float>("Cartn_x", "Cartn_y", "Cartn_z");
|
||||
@@ -214,10 +214,10 @@ A simple case:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
#include <cif++/cif++.hpp>
|
||||
#include <cif++.hpp>
|
||||
|
||||
cif::file f("1cbs.cif.gz");
|
||||
f.load_dictionary("mmcif_pdbx.dic");
|
||||
f.load_dictionary("mmcif_pdbx");
|
||||
|
||||
if (not f.is_valid())
|
||||
std::cout << "This file is not valid\n";
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
# Configuration file
|
||||
|
||||
project = '@PROJECT_NAME@'
|
||||
copyright = '2026, Maarten L. Hekkelman'
|
||||
copyright = '2023, Maarten L. Hekkelman'
|
||||
author = 'Maarten L. Hekkelman'
|
||||
release = '@PROJECT_VERSION@'
|
||||
|
||||
@@ -14,7 +12,7 @@ extensions = [
|
||||
]
|
||||
|
||||
breathe_projects = {
|
||||
"@PROJECT_NAME@": "@DOXYGEN_OUTPUT_DIR@"
|
||||
"@PROJECT_NAME@": "../build/docs/xml"
|
||||
}
|
||||
|
||||
myst_enable_extensions = [ "colon_fence" ]
|
||||
@@ -62,7 +60,7 @@ html_static_path = ['_static']
|
||||
html_theme_options = {
|
||||
}
|
||||
|
||||
# cpp_index_common_prefix = [
|
||||
# 'cif::'
|
||||
# ]
|
||||
cpp_index_common_prefix = [
|
||||
'cif::'
|
||||
]
|
||||
|
||||
|
||||
33
docs/cql.rst
33
docs/cql.rst
@@ -1,33 +0,0 @@
|
||||
CQL
|
||||
===
|
||||
|
||||
The structure of cif files (even of STAR files, from which this format is derived) looks suspiciously like a relational database. When you consider categories to be tables and items to be columns you're almost there. The only problem is linking tables, in common cif files this is done based on multiple columns and the rules are a bit fuzzy allowing for empty columns to still match related columns that do have a value.
|
||||
|
||||
An early version of the tool *mmCQL* contained a SQL like language interpreter to SELECT and UPDATE values in cif files. This functionality has been expanded by implementing a full SQL interface using the `SQLite <https://sqlite.org>`_ library. Libcifpp categories are exposed as virtual tables in a SQLite environment and can be queried and manipulated using SQL syntax.
|
||||
|
||||
The current limitation is that CREATE TABLE and ALTER TABLE are not supported yet. Since SQLite has no way of supporting this, we will have to write a preprocessor to intercept these statements. That's on the to-do list.
|
||||
|
||||
The new *mmcql* tools in `cif-tools <https://github.com/PDB-REDO/cif-tools>`_ uses this new backend and is a command line application you can use similar to the *sqlite* or e.g. *psql* tools for regular SQLite files and postgresql databanks respectively.
|
||||
|
||||
Synopsis
|
||||
--------
|
||||
|
||||
.. literalinclude:: ../examples/example-cql.cpp
|
||||
:language: c++
|
||||
:start-at: #include <cif++/cif++.hpp>
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
To start using CQL, you will first have to create a :cpp:class:`connection` to a :cpp:class:`cif::cql::datablock`. Using this connection you can create a :cpp:class:`transaction`. And with the transaction can execute SQL statements using :cpp:func:`cif::cql::transaction::exec`. Or you can use the :cpp:func:`cif::cql::transaction::stream` function to directly pull values from the result.
|
||||
|
||||
The result of :cpp:func:`cif::cql::transaction::exec` is a :cpp:class:`cif::cql::result` class which uses a :cpp:class:`cif::category` as storage class.
|
||||
|
||||
Implementation Details
|
||||
----------------------
|
||||
|
||||
When the datablock contains a validator (i.e. you loaded a dictionary) the SQL engine knows about all possible items/columns that are allowed. It also knows about links/relations between categories, just like the regular libcifpp query mechanism. So, updating and deleting will cascade automatically.
|
||||
|
||||
Another point is data types. cif files can have numbers, strings or NULL values. Same goes for SQLite. However, when a file was loaded without a dictionary, the type of an item is dependent on its content. If something was parsed as being a number, the type will be numeric. If however, the file does contain a dictionary/validator, the type is determined by this dictionary. So, even if it looks like a number, it still might be a string internally. Good example is the ID field in atom_site, or the auth_seq_id/auth_seq_num fields. In the WHERE clause this may have unexpected results, so you may have to fall back to using `CAST <https://sqlite.org/lang_expr.html#castexpr>`_.
|
||||
|
||||
The API for this functionality is a bit new, there may be room for improvement. Ideas are welcome.
|
||||
@@ -27,7 +27,7 @@ Using *libcifpp* is easy, if you are familiar with modern C++:
|
||||
|
||||
.. literalinclude:: ../README.md
|
||||
:language: c++
|
||||
:start-after: ```cpp
|
||||
:start-after: ```c++
|
||||
:end-before: ```
|
||||
|
||||
.. toctree::
|
||||
@@ -38,7 +38,6 @@ Using *libcifpp* is easy, if you are familiar with modern C++:
|
||||
basics.rst
|
||||
compound.rst
|
||||
model.rst
|
||||
cql.rst
|
||||
resources.rst
|
||||
symmetry.rst
|
||||
bitsandpieces.rst
|
||||
|
||||
Binary file not shown.
@@ -1,36 +1,7 @@
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
#
|
||||
# Copyright (c) 2026 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.
|
||||
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
project(cifpp_example LANGUAGES CXX)
|
||||
|
||||
if(PROJECT_IS_TOP_LEVEL AND NOT (TARGET cifpp OR cifpp_FOUND))
|
||||
find_package(cifpp REQUIRED)
|
||||
endif()
|
||||
find_package(cifpp REQUIRED)
|
||||
|
||||
add_executable(example example.cpp)
|
||||
target_link_libraries(example cifpp::cifpp)
|
||||
|
||||
add_executable(example-cql example-cql.cpp)
|
||||
target_link_libraries(example-cql cifpp::cifpp)
|
||||
target_link_libraries(example cifpp::cifpp)
|
||||
@@ -1,33 +1,9 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2026 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 <filesystem>
|
||||
#include <iostream>
|
||||
|
||||
#include <cif++/cif++.hpp>
|
||||
#include <cif++.hpp>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
|
||||
@@ -26,8 +26,16 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#warning "Using this file is deprecated, use #include <cif++/cif++.hpp> instead"
|
||||
#include "cif++/utilities.hpp"
|
||||
#include "cif++/file.hpp"
|
||||
#include "cif++/parser.hpp"
|
||||
#include "cif++/format.hpp"
|
||||
|
||||
// IWYU pragma: begin_exports
|
||||
#include "cif++/cif++.hpp"
|
||||
// IWYU pragma: end_exports
|
||||
#include "cif++/compound.hpp"
|
||||
#include "cif++/point.hpp"
|
||||
#include "cif++/symmetry.hpp"
|
||||
|
||||
#include "cif++/model.hpp"
|
||||
|
||||
#include "cif++/pdb.hpp"
|
||||
#include "cif++/gzio.hpp"
|
||||
@@ -33,7 +33,6 @@
|
||||
|
||||
#include "cif++/exports.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <stdexcept>
|
||||
@@ -236,7 +235,7 @@ struct atom_type_info
|
||||
|
||||
/// Array containing all known radii for this element. A value of kNA is
|
||||
/// stored for unknown values
|
||||
std::array<float, kRadiusTypeCount> radii;
|
||||
float radii[kRadiusTypeCount];
|
||||
};
|
||||
|
||||
/// Array of atom_type_info struct for each of the defined elements in atom_type
|
||||
@@ -257,12 +256,12 @@ class atom_type_traits
|
||||
/// Constructor based on the element as a string in \a symbol
|
||||
atom_type_traits(const std::string &symbol);
|
||||
|
||||
[[nodiscard]] atom_type type() const { return m_info->type; } ///< Returns the atom_type
|
||||
[[nodiscard]] std::string name() const { return m_info->name; } ///< Returns the name of the element
|
||||
[[nodiscard]] std::string symbol() const { return m_info->symbol; } ///< Returns the symbol of the element
|
||||
[[nodiscard]] float weight() const { return m_info->weight; } ///< Returns the average weight of the element
|
||||
atom_type type() const { return m_info->type; } ///< Returns the atom_type
|
||||
std::string name() const { return m_info->name; } ///< Returns the name of the element
|
||||
std::string symbol() const { return m_info->symbol; } ///< Returns the symbol of the element
|
||||
float weight() const { return m_info->weight; } ///< Returns the average weight of the element
|
||||
|
||||
[[nodiscard]] bool is_metal() const { return m_info->metal; } ///< Returns true if the element is a metal
|
||||
bool is_metal() const { return m_info->metal; } ///< Returns true if the element is a metal
|
||||
|
||||
/// Return true if the symbol in \a symbol actually exists in the list of known elements in atom_type
|
||||
static bool is_element(const std::string &symbol);
|
||||
@@ -273,7 +272,7 @@ class atom_type_traits
|
||||
/// @brief Return the radius for the element, use \a type to select which radius to return
|
||||
/// @param type The selector for which radius to return
|
||||
/// @return The requested radius or kNA if not known (or applicable)
|
||||
[[nodiscard]] float radius(radius_type type = radius_type::single_bond) const
|
||||
float radius(radius_type type = radius_type::single_bond) const
|
||||
{
|
||||
if (type >= radius_type::type_count)
|
||||
throw std::invalid_argument("invalid radius requested");
|
||||
@@ -284,20 +283,20 @@ class atom_type_traits
|
||||
///
|
||||
/// \param charge The charge of the ion
|
||||
/// \return The radius of the ion
|
||||
[[nodiscard]] float crystal_ionic_radius(int charge) const;
|
||||
float crystal_ionic_radius(int charge) const;
|
||||
|
||||
/// \brief Return the radius for a charged version of this atom in a non-solid environment
|
||||
///
|
||||
/// \param charge The charge of the ion
|
||||
/// \return The radius of the ion
|
||||
[[nodiscard]] float effective_ionic_radius(int charge) const;
|
||||
float effective_ionic_radius(int charge) const;
|
||||
|
||||
/// \brief Return the radius for a charged version of this atom, returns the effective radius by default
|
||||
///
|
||||
/// \param charge The charge of the ion
|
||||
/// \param type The requested ion radius type
|
||||
/// \return The radius of the ion
|
||||
[[nodiscard]] float ionic_radius(int charge, ionic_radius_type type = ionic_radius_type::effective) const
|
||||
float ionic_radius(int charge, ionic_radius_type type = ionic_radius_type::effective) const
|
||||
{
|
||||
return type == ionic_radius_type::effective ? effective_ionic_radius(charge) : crystal_ionic_radius(charge);
|
||||
}
|
||||
@@ -322,16 +321,16 @@ class atom_type_traits
|
||||
///
|
||||
/// @param charge The charge for which the structure values should be returned, use kWSKFVal to return the *Cval* and *Siva* values
|
||||
/// @return The scattering factors as a SFData struct
|
||||
[[nodiscard]] const SFData &wksf(int charge = 0) const;
|
||||
const SFData &wksf(int charge = 0) const;
|
||||
|
||||
/// @brief Return the electron scattering factor values for the element
|
||||
///
|
||||
/// @return The scattering factors as a SFData struct
|
||||
[[nodiscard]] const SFData &elsf() const;
|
||||
const SFData &elsf() const;
|
||||
|
||||
/// Clipper doesn't like atoms with charges that do not have a scattering factor. And
|
||||
/// rightly so, but we need to know in advance if this is the case
|
||||
[[nodiscard]] bool has_sf(int charge) const;
|
||||
bool has_sf(int charge) const;
|
||||
|
||||
private:
|
||||
const struct atom_type_info *m_info;
|
||||
|
||||
@@ -26,31 +26,15 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cif++/forward_decl.hpp"
|
||||
|
||||
#include "cif++/condition.hpp"
|
||||
#include "cif++/item.hpp"
|
||||
#include "cif++/iterator.hpp"
|
||||
#include "cif++/row.hpp"
|
||||
#include "cif++/text.hpp"
|
||||
#include "cif++/validate.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <iosfwd>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <ranges>
|
||||
#include <set>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
|
||||
/** \file category.hpp
|
||||
* Documentation for the cif::category class
|
||||
@@ -67,12 +51,6 @@
|
||||
namespace cif
|
||||
{
|
||||
|
||||
class datablock;
|
||||
class validator;
|
||||
struct category_validator;
|
||||
struct item_validator;
|
||||
struct link_validator;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// special exceptions
|
||||
|
||||
@@ -100,14 +78,13 @@ class missing_key_error : public std::runtime_error
|
||||
/**
|
||||
* @brief Construct a new duplicate key error object
|
||||
*/
|
||||
missing_key_error(const std::string &msg, std::string key)
|
||||
missing_key_error(const std::string &msg, const std::string &key)
|
||||
: std::runtime_error(msg)
|
||||
, m_key(std::move(key))
|
||||
, m_key(key)
|
||||
{
|
||||
}
|
||||
|
||||
/// Return the name of the key that was missing
|
||||
[[nodiscard]] const std::string &get_key() const noexcept { return m_key; }
|
||||
const std::string &get_key() const noexcept { return m_key; }
|
||||
|
||||
private:
|
||||
std::string m_key;
|
||||
@@ -121,12 +98,22 @@ class multiple_results_error : public std::runtime_error
|
||||
/**
|
||||
* @brief Construct a new multiple results error object
|
||||
*/
|
||||
multiple_results_error() // NOLINT
|
||||
multiple_results_error()
|
||||
: std::runtime_error("query should have returned exactly one row")
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// These should be moved elsewhere, one day.
|
||||
|
||||
/// \cond
|
||||
template <typename _Tp>
|
||||
inline constexpr bool is_optional_v = false;
|
||||
template <typename _Tp>
|
||||
inline constexpr bool is_optional_v<std::optional<_Tp>> = true;
|
||||
/// \endcond
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/// The class category is a sequence container for rows of data values.
|
||||
@@ -143,41 +130,27 @@ class category
|
||||
|
||||
friend class row_handle;
|
||||
|
||||
template <bool, typename...>
|
||||
friend class iterator_impl_base;
|
||||
template <typename, typename...>
|
||||
friend class iterator_impl;
|
||||
|
||||
using value_type = row_handle;
|
||||
using reference = row_handle;
|
||||
using const_reference = const_row_handle;
|
||||
using iterator = iterator_impl<>;
|
||||
using const_iterator = const_iterator_impl<>;
|
||||
|
||||
static_assert(std::input_iterator<iterator>);
|
||||
static_assert(std::input_iterator<const_iterator>);
|
||||
using reference = value_type;
|
||||
using const_reference = const value_type;
|
||||
using iterator = iterator_impl<category>;
|
||||
using const_iterator = iterator_impl<const category>;
|
||||
|
||||
/// \endcond
|
||||
|
||||
category() = default; ///< Default constructor
|
||||
category(std::string_view name); ///< Constructor taking a \a name
|
||||
|
||||
/// @brief Constructor creating a category named @a name and filled with @a rows
|
||||
/// @param name Name for the new category
|
||||
/// @param rows The data stored in the category
|
||||
category(std::string_view name, row_initializer &&rows)
|
||||
: category(name)
|
||||
{
|
||||
emplace(std::forward<row_initializer>(rows));
|
||||
}
|
||||
|
||||
category(const category &rhs); ///< Copy constructor
|
||||
category(const category &rhs); ///< Copy constructor
|
||||
|
||||
category(category &&rhs) noexcept ///< Move constructor
|
||||
{
|
||||
swap(*this, rhs);
|
||||
}
|
||||
|
||||
/// Assignment operator
|
||||
category &operator=(category rhs)
|
||||
category &operator=(category rhs) ///< assignement operator
|
||||
{
|
||||
swap(*this, rhs);
|
||||
return *this;
|
||||
@@ -188,46 +161,24 @@ class category
|
||||
/// you will not derive from this class.
|
||||
~category();
|
||||
|
||||
/// Swap two categories
|
||||
friend void swap(category &a, category &b) noexcept;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
[[nodiscard]] const std::string &name() const { return m_name; } ///< Returns the name of the category
|
||||
const std::string &name() const { return m_name; } ///< Returns the name of the category
|
||||
|
||||
/// \brief Rename category to @a new_name
|
||||
void name(std::string_view new_name)
|
||||
{
|
||||
m_name = new_name;
|
||||
m_dirty = true;
|
||||
}
|
||||
[[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
|
||||
|
||||
/// \brief Return true if the category has been modified since last open/save
|
||||
[[nodiscard]] constexpr bool is_dirty() const
|
||||
{
|
||||
return m_dirty;
|
||||
}
|
||||
iset key_items() const; ///< Returns the cif::iset of key item names. Retrieved from the @ref category_validator for this category
|
||||
|
||||
/// \brief Mark the category as modified according to @a dirty
|
||||
void set_dirty(bool dirty)
|
||||
{
|
||||
m_dirty = dirty;
|
||||
}
|
||||
[[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_items instead")]] [[nodiscard]] iset key_fields() const; ///< Returns the cif::iset of key item names. Retrieved from the @ref category_validator for this category
|
||||
|
||||
[[nodiscard]] 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")]] [[nodiscard]] std::set<uint16_t> key_field_indices() const; ///< Returns a set of indices for the key items.
|
||||
|
||||
[[nodiscard]] 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.
|
||||
/// @param db The enclosing @ref datablock
|
||||
void set_validator(const validator *v, datablock &db);
|
||||
void set_validator(const validator_base *v, datablock &db);
|
||||
|
||||
/// @brief Update the links in this category
|
||||
/// @param db The enclosing @ref datablock
|
||||
@@ -235,15 +186,15 @@ class category
|
||||
|
||||
/// @brief Return the global @ref validator for the data
|
||||
/// @return The @ref validator or nullptr if not assigned
|
||||
[[nodiscard]] const validator *get_validator() const { return m_validator; }
|
||||
const validator_base *get_validator() const { return m_validator; }
|
||||
|
||||
/// @brief Return the category validator for this category
|
||||
/// @return The @ref category_validator or nullptr if not assigned
|
||||
[[nodiscard]] const category_validator *get_cat_validator() const { return m_cat_validator; }
|
||||
const category_validator *get_cat_validator() const { return m_cat_validator; }
|
||||
|
||||
/// @brief Validate the data stored using the assigned @ref category_validator
|
||||
/// @return Returns true is all validations pass
|
||||
[[nodiscard]] bool is_valid() const;
|
||||
bool is_valid() const;
|
||||
|
||||
/// @brief Validate links, that means, values in this category should have an
|
||||
/// accompanying value in parent categories.
|
||||
@@ -256,12 +207,7 @@ class category
|
||||
/// parent in those categories.
|
||||
///
|
||||
/// @return Returns true is all validations pass
|
||||
[[nodiscard]] bool validate_links() const;
|
||||
|
||||
/**
|
||||
* @brief Strip removes items from this category that are invalid according to the assigned validator
|
||||
*/
|
||||
void strip();
|
||||
bool validate_links() const;
|
||||
|
||||
/// @brief Equality operator, returns true if @a rhs is equal to this
|
||||
/// @param rhs The object to compare with
|
||||
@@ -283,17 +229,15 @@ class category
|
||||
/// the category is empty.
|
||||
reference front()
|
||||
{
|
||||
assert(size() > 0);
|
||||
return { *this, *m_head };
|
||||
}
|
||||
|
||||
/// @brief Return a const reference to the first row in this category.
|
||||
/// @return const reference to the first row in this category. The result is undefined if
|
||||
/// the category is empty.
|
||||
[[nodiscard]] const_reference front() const
|
||||
const_reference front() const
|
||||
{
|
||||
assert(size() > 0);
|
||||
return { *this, *m_head };
|
||||
return { const_cast<category &>(*this), const_cast<row &>(*m_head) };
|
||||
}
|
||||
|
||||
/// @brief Return a reference to the last row in this category.
|
||||
@@ -301,17 +245,15 @@ class category
|
||||
/// the category is empty.
|
||||
reference back()
|
||||
{
|
||||
assert(size() > 0);
|
||||
return { *this, *m_tail };
|
||||
}
|
||||
|
||||
/// @brief Return a const reference to the last row in this category.
|
||||
/// @return const reference to the last row in this category. The result is undefined if
|
||||
/// the category is empty.
|
||||
[[nodiscard]] const_reference back() const
|
||||
const_reference back() const
|
||||
{
|
||||
assert(size() > 0);
|
||||
return { *this, *m_tail };
|
||||
return { const_cast<category &>(*this), const_cast<row &>(*m_tail) };
|
||||
}
|
||||
|
||||
/// Return an iterator to the first row
|
||||
@@ -327,43 +269,43 @@ class category
|
||||
}
|
||||
|
||||
/// Return a const iterator to the first row
|
||||
[[nodiscard]] const_iterator begin() const
|
||||
const_iterator begin() const
|
||||
{
|
||||
return { *this, m_head };
|
||||
}
|
||||
|
||||
/// Return a const iterator pointing past the last row
|
||||
[[nodiscard]] const_iterator end() const
|
||||
const_iterator end() const
|
||||
{
|
||||
return { *this, nullptr };
|
||||
}
|
||||
|
||||
/// Return a const iterator to the first row
|
||||
[[nodiscard]] const_iterator cbegin() const
|
||||
const_iterator cbegin() const
|
||||
{
|
||||
return { *this, m_head };
|
||||
}
|
||||
|
||||
/// Return an iterator pointing past the last row
|
||||
[[nodiscard]] const_iterator cend() const
|
||||
const_iterator cend() const
|
||||
{
|
||||
return { *this, nullptr };
|
||||
}
|
||||
|
||||
/// Return a count of the rows in this container
|
||||
[[nodiscard]] std::size_t size() const
|
||||
std::size_t size() const
|
||||
{
|
||||
return std::distance(cbegin(), cend());
|
||||
}
|
||||
|
||||
/// Return the theoretical maximum number or rows that can be stored
|
||||
[[nodiscard]] std::size_t max_size() const
|
||||
std::size_t max_size() const
|
||||
{
|
||||
return std::numeric_limits<std::size_t>::max(); // this is a bit optimistic, I guess
|
||||
}
|
||||
|
||||
/// Return true if the category is empty
|
||||
[[nodiscard]] bool empty() const
|
||||
bool empty() const
|
||||
{
|
||||
return m_head == nullptr;
|
||||
}
|
||||
@@ -371,26 +313,21 @@ class category
|
||||
// --------------------------------------------------------------------
|
||||
// A category can have a key, as defined by the validator/dictionary
|
||||
|
||||
/// @brief The type of an element of the key_type
|
||||
struct key_element_type
|
||||
{
|
||||
std::string name; ///< Name of the item
|
||||
item_value value; ///< Value to be found
|
||||
bool may_be_null = false; ///< If true, value should be same or empty
|
||||
};
|
||||
|
||||
/// @brief The key type
|
||||
using key_type = std::vector<key_element_type>;
|
||||
using key_type = row_initializer;
|
||||
|
||||
/// @brief Return a row_handle for the row specified by \a key
|
||||
/// @param key The value for the key, items specified in the dictionary should have a value
|
||||
/// @return The row found in the index, or an undefined row_handle
|
||||
row_handle operator[](const key_type &key);
|
||||
|
||||
/// @brief Return a const_row_handle for the row specified by \a key
|
||||
/// @brief Return a const row_handle for the row specified by \a key
|
||||
/// @param key The value for the key, items specified in the dictionary should have a value
|
||||
/// @return The row found in the index, or an undefined row_handle
|
||||
const_row_handle operator[](const key_type &key) const;
|
||||
const row_handle operator[](const key_type &key) const
|
||||
{
|
||||
return const_cast<category *>(this)->operator[](key);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
@@ -406,10 +343,10 @@ class category
|
||||
/// @param names The names for the items requested
|
||||
|
||||
template <typename... Ts, typename... Ns>
|
||||
[[nodiscard]] const_iterator_proxy<Ts...> rows(Ns... names) const
|
||||
iterator_proxy<const category, Ts...> rows(Ns... names) const
|
||||
{
|
||||
static_assert(sizeof...(Ts) == sizeof...(Ns), "The number of item names should be equal to the number of types to return");
|
||||
return const_iterator_proxy<Ts...>(*this, begin(), { names... });
|
||||
return iterator_proxy<const category, Ts...>(*this, begin(), { names... });
|
||||
}
|
||||
|
||||
/// @brief Return a special iterator for all rows in this category.
|
||||
@@ -429,10 +366,10 @@ class category
|
||||
/// @param names The names for the items requested
|
||||
|
||||
template <typename... Ts, typename... Ns>
|
||||
iterator_proxy<Ts...> rows(Ns... names)
|
||||
iterator_proxy<category, Ts...> rows(Ns... names)
|
||||
{
|
||||
static_assert(sizeof...(Ts) == sizeof...(Ns), "The number of item names should be equal to the number of types to return");
|
||||
return iterator_proxy<Ts...>(*this, begin(), { names... });
|
||||
return iterator_proxy<category, Ts...>(*this, begin(), { names... });
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
@@ -448,7 +385,7 @@ class category
|
||||
/// @return A special iterator that loops over all elements that match. The iterator can be dereferenced
|
||||
/// to a @ref row_handle
|
||||
|
||||
conditional_iterator_proxy<> find(condition &&cond)
|
||||
conditional_iterator_proxy<category> find(condition &&cond)
|
||||
{
|
||||
return find(begin(), std::move(cond));
|
||||
}
|
||||
@@ -461,7 +398,7 @@ class category
|
||||
/// @return A special iterator that loops over all elements that match. The iterator can be dereferenced
|
||||
/// to a @ref row_handle
|
||||
|
||||
conditional_iterator_proxy<> find(iterator pos, condition &&cond)
|
||||
conditional_iterator_proxy<category> find(iterator pos, condition &&cond)
|
||||
{
|
||||
return { *this, pos, std::move(cond) };
|
||||
}
|
||||
@@ -472,7 +409,7 @@ class category
|
||||
/// @return A special iterator that loops over all elements that match. The iterator can be dereferenced
|
||||
/// to a const @ref row_handle
|
||||
|
||||
const_conditional_iterator_proxy<> find(condition &&cond) const
|
||||
conditional_iterator_proxy<const category> find(condition &&cond) const
|
||||
{
|
||||
return find(cbegin(), std::move(cond));
|
||||
}
|
||||
@@ -485,9 +422,9 @@ class category
|
||||
/// @return A special iterator that loops over all elements that match. The iterator can be dereferenced
|
||||
/// to a const @ref row_handle
|
||||
|
||||
const_conditional_iterator_proxy<> find(const_iterator pos, condition &&cond) const
|
||||
conditional_iterator_proxy<const category> find(const_iterator pos, condition &&cond) const
|
||||
{
|
||||
return const_conditional_iterator_proxy<>{ *this, pos, std::move(cond) };
|
||||
return conditional_iterator_proxy<const category>{ *this, pos, std::move(cond) };
|
||||
}
|
||||
|
||||
/// @brief Return a special iterator to loop over all rows that conform to @a cond. The resulting
|
||||
@@ -504,10 +441,10 @@ class category
|
||||
/// @return A special iterator that loops over all elements that match.
|
||||
|
||||
template <typename... Ts, typename... Ns>
|
||||
conditional_iterator_proxy<Ts...> find(condition &&cond, Ns... names)
|
||||
conditional_iterator_proxy<category, Ts...> find(condition &&cond, Ns... names)
|
||||
{
|
||||
static_assert(sizeof...(Ts) == sizeof...(Ns), "The number of item names should be equal to the number of types to return");
|
||||
return find<Ts...>(begin(), std::move(cond), std::forward<Ns>(names)...);
|
||||
return find<Ts...>(cbegin(), std::move(cond), std::forward<Ns>(names)...);
|
||||
}
|
||||
|
||||
/// @brief Return a special const iterator to loop over all rows that conform to @a cond. The resulting
|
||||
@@ -519,7 +456,7 @@ class category
|
||||
/// @return A special iterator that loops over all elements that match.
|
||||
|
||||
template <typename... Ts, typename... Ns>
|
||||
const_conditional_iterator_proxy<Ts...> find(condition &&cond, Ns... names) const
|
||||
conditional_iterator_proxy<const category, Ts...> find(condition &&cond, Ns... names) const
|
||||
{
|
||||
static_assert(sizeof...(Ts) == sizeof...(Ns), "The number of item names should be equal to the number of types to return");
|
||||
return find<Ts...>(cbegin(), std::move(cond), std::forward<Ns>(names)...);
|
||||
@@ -535,7 +472,7 @@ class category
|
||||
/// @return A special iterator that loops over all elements that match.
|
||||
|
||||
template <typename... Ts, typename... Ns>
|
||||
conditional_iterator_proxy<Ts...> find(iterator pos, condition &&cond, Ns... names)
|
||||
conditional_iterator_proxy<category, Ts...> find(const_iterator pos, condition &&cond, Ns... names)
|
||||
{
|
||||
static_assert(sizeof...(Ts) == sizeof...(Ns), "The number of item names should be equal to the number of types to return");
|
||||
return { *this, pos, std::move(cond), std::forward<Ns>(names)... };
|
||||
@@ -551,7 +488,7 @@ class category
|
||||
/// @return A special iterator that loops over all elements that match.
|
||||
|
||||
template <typename... Ts, typename... Ns>
|
||||
const_conditional_iterator_proxy<Ts...> find(const_iterator pos, condition &&cond, Ns... names) const
|
||||
conditional_iterator_proxy<const category, Ts...> find(const_iterator pos, condition &&cond, Ns... names) const
|
||||
{
|
||||
static_assert(sizeof...(Ts) == sizeof...(Ns), "The number of item names should be equal to the number of types to return");
|
||||
return { *this, pos, std::move(cond), std::forward<Ns>(names)... };
|
||||
@@ -588,7 +525,7 @@ class category
|
||||
/// there are is not exactly one row matching @a cond
|
||||
/// @param cond The condition to search for
|
||||
/// @return Row handle to the row found
|
||||
const_row_handle find1(condition &&cond) const
|
||||
const row_handle find1(condition &&cond) const
|
||||
{
|
||||
return find1(cbegin(), std::move(cond));
|
||||
}
|
||||
@@ -598,7 +535,7 @@ class category
|
||||
/// @param pos The position to start the search
|
||||
/// @param cond The condition to search for
|
||||
/// @return Row handle to the row found
|
||||
const_row_handle find1(const_iterator pos, condition &&cond) const
|
||||
const row_handle find1(const_iterator pos, condition &&cond) const
|
||||
{
|
||||
auto h = find(pos, std::move(cond));
|
||||
|
||||
@@ -616,30 +553,10 @@ class category
|
||||
/// @return The value found
|
||||
template <typename T>
|
||||
T find1(condition &&cond, std::string_view item) const
|
||||
requires(not is_optional_v<T>)
|
||||
{
|
||||
return find1<T>(cbegin(), std::move(cond), item);
|
||||
}
|
||||
|
||||
/// @brief Return value for the item named @a item for the single row that
|
||||
/// matches @a cond. Throws @a multiple_results_error if there are is not exactly one row
|
||||
/// @tparam The type to use for the result
|
||||
/// @param cond The condition to search for
|
||||
/// @param item The name of the item to return the value for
|
||||
/// @return The value found
|
||||
|
||||
template <typename T>
|
||||
T find1(condition &&cond, std::string_view item) const
|
||||
requires(is_optional_v<T>)
|
||||
{
|
||||
auto h = find<typename T::value_type>(cbegin(), std::move(cond), item);
|
||||
|
||||
if (h.size() == 1)
|
||||
return *h.begin();
|
||||
|
||||
return T{};
|
||||
}
|
||||
|
||||
/// @brief Return value for the item named @a item for the single row that
|
||||
/// matches @a cond when starting to search at @a pos.
|
||||
/// Throws @a multiple_results_error if there are is not exactly one row
|
||||
@@ -648,9 +565,8 @@ class category
|
||||
/// @param cond The condition to search for
|
||||
/// @param item The name of the item to return the value for
|
||||
/// @return The value found
|
||||
template <typename T>
|
||||
template <typename T, std::enable_if_t<not is_optional_v<T>, int> = 0>
|
||||
T find1(const_iterator pos, condition &&cond, std::string_view item) const
|
||||
requires(not is_optional_v<T>)
|
||||
{
|
||||
auto h = find<T>(pos, std::move(cond), item);
|
||||
|
||||
@@ -668,9 +584,8 @@ class category
|
||||
/// @param cond The condition to search for
|
||||
/// @param item The name of the item to return the value for
|
||||
/// @return The value found, can be empty if no row matches the condition
|
||||
template <typename T>
|
||||
template <typename T, std::enable_if_t<is_optional_v<T>, int> = 0>
|
||||
T find1(const_iterator pos, condition &&cond, std::string_view item) const
|
||||
requires(is_optional_v<T>)
|
||||
{
|
||||
auto h = find<typename T::value_type>(pos, std::move(cond), item);
|
||||
|
||||
@@ -678,7 +593,7 @@ class category
|
||||
throw multiple_results_error();
|
||||
|
||||
if (h.empty())
|
||||
return std::nullopt;
|
||||
return {};
|
||||
|
||||
return *h.begin();
|
||||
}
|
||||
@@ -743,7 +658,7 @@ class category
|
||||
/// @brief Return a const row handle to the first row that matches @a cond
|
||||
/// @param cond The condition to search for
|
||||
/// @return The const handle to the row that matches or an empty row_handle
|
||||
const_row_handle find_first(condition &&cond) const
|
||||
const row_handle find_first(condition &&cond) const
|
||||
{
|
||||
return find_first(cbegin(), std::move(cond));
|
||||
}
|
||||
@@ -752,11 +667,11 @@ class category
|
||||
/// @param pos The location to start searching
|
||||
/// @param cond The condition to search for
|
||||
/// @return The const handle to the row that matches or an empty row_handle
|
||||
const_row_handle find_first(const_iterator pos, condition &&cond) const
|
||||
const row_handle find_first(const_iterator pos, condition &&cond) const
|
||||
{
|
||||
auto h = find(pos, std::move(cond));
|
||||
|
||||
return h.empty() ? const_row_handle{} : *h.begin();
|
||||
return h.empty() ? row_handle{} : *h.begin();
|
||||
}
|
||||
|
||||
/// @brief Return the value for item @a item for the first row that matches condition @a cond
|
||||
@@ -821,9 +736,8 @@ class category
|
||||
/// @param item The item to use for the value
|
||||
/// @param cond The condition to search for
|
||||
/// @return The value found or the minimal value for the type
|
||||
template <typename T>
|
||||
template <typename T, std::enable_if_t<std::is_arithmetic_v<T>, int> = 0>
|
||||
T find_max(std::string_view item, condition &&cond) const
|
||||
requires(std::is_arithmetic_v<T>)
|
||||
{
|
||||
T result = std::numeric_limits<T>::min();
|
||||
|
||||
@@ -840,9 +754,8 @@ class category
|
||||
/// @tparam The type of the value to return
|
||||
/// @param item The item to use for the value
|
||||
/// @return The value found or the minimal value for the type
|
||||
template <typename T>
|
||||
[[nodiscard]] T find_max(std::string_view item) const
|
||||
requires(std::is_arithmetic_v<T>)
|
||||
template <typename T, std::enable_if_t<std::is_arithmetic_v<T>, int> = 0>
|
||||
T find_max(std::string_view item) const
|
||||
{
|
||||
return find_max<T>(item, all());
|
||||
}
|
||||
@@ -852,9 +765,8 @@ class category
|
||||
/// @param item The item to use for the value
|
||||
/// @param cond The condition to search for
|
||||
/// @return The value found or the maximum value for the type
|
||||
template <typename T>
|
||||
[[nodiscard]] T find_min(std::string_view item, condition &&cond) const
|
||||
requires(std::is_arithmetic_v<T>)
|
||||
template <typename T, std::enable_if_t<std::is_arithmetic_v<T>, int> = 0>
|
||||
T find_min(std::string_view item, condition &&cond) const
|
||||
{
|
||||
T result = std::numeric_limits<T>::max();
|
||||
|
||||
@@ -871,9 +783,8 @@ class category
|
||||
/// @tparam The type of the value to return
|
||||
/// @param item The item to use for the value
|
||||
/// @return The value found or the maximum value for the type
|
||||
template <typename T>
|
||||
[[nodiscard]] T find_min(std::string_view item) const
|
||||
requires(std::is_arithmetic_v<T>)
|
||||
template <typename T, std::enable_if_t<std::is_arithmetic_v<T>, int> = 0>
|
||||
T find_min(std::string_view item) const
|
||||
{
|
||||
return find_min<T>(item, all());
|
||||
}
|
||||
@@ -893,8 +804,10 @@ class category
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
if (cond and cond.prepare(*this))
|
||||
if (cond)
|
||||
{
|
||||
cond.prepare(*this);
|
||||
|
||||
auto sh = cond.single();
|
||||
|
||||
if (sh.has_value() and *sh)
|
||||
@@ -922,8 +835,10 @@ class category
|
||||
{
|
||||
std::size_t result = 0;
|
||||
|
||||
if (cond and cond.prepare(*this))
|
||||
if (cond)
|
||||
{
|
||||
cond.prepare(*this);
|
||||
|
||||
auto sh = cond.single();
|
||||
|
||||
if (sh.has_value() and *sh)
|
||||
@@ -945,38 +860,36 @@ class category
|
||||
|
||||
/// Using the relations defined in the validator, return whether the row
|
||||
/// in @a r has any children in other categories
|
||||
[[nodiscard]] bool has_children(const_row_handle r) const;
|
||||
bool has_children(row_handle r) const;
|
||||
|
||||
/// Using the relations defined in the validator, return whether the row
|
||||
/// in @a r has any parents in other categories
|
||||
[[nodiscard]] bool has_parents(const_row_handle r) const;
|
||||
bool has_parents(row_handle r) const;
|
||||
|
||||
/// Using the relations defined in the validator, return the row handles
|
||||
/// for all rows in @a childCat that are linked to row @a r
|
||||
[[nodiscard]] std::vector<const_row_handle> get_children(const_row_handle r, const category &childCat) const;
|
||||
std::vector<row_handle> get_children(row_handle r, const category &childCat) const;
|
||||
|
||||
/// Using the relations defined in the validator, return the row handles
|
||||
/// for all rows in @a parentCat that are linked to row @a r
|
||||
[[nodiscard]] std::vector<const_row_handle> get_parents(const_row_handle r, const category &parentCat) const;
|
||||
std::vector<row_handle> get_parents(row_handle r, const category &parentCat) const;
|
||||
|
||||
/// Using the relations defined in the validator, return the row handles
|
||||
/// for all rows in @a cat that are in any way linked to row @a r
|
||||
[[nodiscard]] std::vector<const_row_handle> get_linked(const_row_handle r, const category &cat) const;
|
||||
|
||||
/// Using the relations defined in the validator, return the row handles
|
||||
/// for all rows in @a childCat that are linked to row @a r
|
||||
[[nodiscard]] std::vector<row_handle> get_children(row_handle r, category &childCat);
|
||||
|
||||
/// Using the relations defined in the validator, return the row handles
|
||||
/// for all rows in @a parentCat that are linked to row @a r
|
||||
[[nodiscard]] std::vector<row_handle> get_parents(row_handle r, category &parentCat);
|
||||
|
||||
/// Using the relations defined in the validator, return the row handles
|
||||
/// for all rows in @a cat that are in any way linked to row @a r
|
||||
[[nodiscard]] std::vector<row_handle> get_linked(row_handle r, category &cat);
|
||||
std::vector<row_handle> get_linked(row_handle r, const category &cat) const;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
// void insert(const_iterator pos, const row_initializer &row)
|
||||
// {
|
||||
// insert_impl(pos, row);
|
||||
// }
|
||||
|
||||
// void insert(const_iterator pos, row_initializer &&row)
|
||||
// {
|
||||
// insert_impl(pos, std::move(row));
|
||||
// }
|
||||
|
||||
/// Erase the row pointed to by @a pos and return the iterator to the
|
||||
/// row following pos.
|
||||
iterator erase(iterator pos);
|
||||
@@ -1008,8 +921,8 @@ class category
|
||||
}
|
||||
|
||||
/// @brief Create a new row and emplace the values in the range @a b to @a e in it
|
||||
/// @param b Iterator to the beginning of the range of item_values
|
||||
/// @param e Iterator to the end of the range of item_values
|
||||
/// @param b Iterator to the beginning of the range of @ref item_value
|
||||
/// @param e Iterator to the end of the range of @ref item_value
|
||||
/// @return iterator to the newly created row
|
||||
template <typename ItemIter>
|
||||
iterator emplace(ItemIter b, ItemIter e)
|
||||
@@ -1021,7 +934,7 @@ class category
|
||||
for (auto i = b; i != e; ++i)
|
||||
{
|
||||
// item_value *new_item = this->create_item(*i);
|
||||
r->set(add_item(i->name()), i->value());
|
||||
r->append(add_item(i->name()), { i->value() });
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
@@ -1034,13 +947,6 @@ class category
|
||||
return insert_impl(cend(), r);
|
||||
}
|
||||
|
||||
/// Create rows with the content of the data in [ @a b, to @a e)
|
||||
void emplace(const_iterator b, const_iterator e)
|
||||
{
|
||||
while (b != e)
|
||||
emplace(*b++);
|
||||
}
|
||||
|
||||
/// @brief Completely erase all rows contained in this category
|
||||
void clear();
|
||||
|
||||
@@ -1066,9 +972,7 @@ class category
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/// The type for a function that provides a value to insert based on a
|
||||
/// value that is the default or the previous value
|
||||
using value_provider_type = std::function<item_value(const item_value &)>;
|
||||
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
|
||||
@@ -1081,7 +985,6 @@ class category
|
||||
{
|
||||
auto rs = find(std::move(cond));
|
||||
std::vector<row_handle> rows;
|
||||
// NOLINTNEXTLINE
|
||||
std::copy(rs.begin(), rs.end(), std::back_inserter(rows));
|
||||
update_value(rows, item_name, std::move(value_provider));
|
||||
}
|
||||
@@ -1100,11 +1003,10 @@ 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(condition &&cond, std::string_view item_name, const item_value &value)
|
||||
void update_value(condition &&cond, std::string_view item_name, std::string_view value)
|
||||
{
|
||||
auto rs = find(std::move(cond));
|
||||
std::vector<row_handle> rows;
|
||||
// NOLINTNEXTLINE
|
||||
std::copy(rs.begin(), rs.end(), std::back_inserter(rows));
|
||||
update_value(rows, item_name, value);
|
||||
}
|
||||
@@ -1114,21 +1016,93 @@ 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, const item_value &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](const item_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
|
||||
{
|
||||
return get_item_ix(column_name);
|
||||
}
|
||||
|
||||
/// @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
|
||||
{
|
||||
return get_item_name(ix);
|
||||
}
|
||||
|
||||
/// @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)
|
||||
{
|
||||
return add_item(item_name);
|
||||
}
|
||||
|
||||
/** @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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
rename_item(from_name, to_name);
|
||||
}
|
||||
|
||||
/// @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
|
||||
{
|
||||
return has_item(name);
|
||||
}
|
||||
|
||||
/// @brief Return the cif::iset of columns in this category
|
||||
[[deprecated("use get_items instead")]] iset get_columns() const
|
||||
{
|
||||
return get_items();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
/// \brief Return the index number for \a item_name
|
||||
|
||||
[[nodiscard]] uint16_t get_item_ix(std::string_view item_name) const;
|
||||
uint16_t get_item_ix(std::string_view item_name) const
|
||||
{
|
||||
uint16_t result;
|
||||
|
||||
for (result = 0; result < m_items.size(); ++result)
|
||||
{
|
||||
if (iequals(item_name, m_items[result].m_name))
|
||||
break;
|
||||
}
|
||||
|
||||
if (VERBOSE > 0 and result == m_items.size() and m_cat_validator != nullptr) // validate the name, if it is known at all (since it was not found)
|
||||
{
|
||||
auto iv = m_cat_validator->get_validator_for_item(item_name);
|
||||
if (iv == nullptr)
|
||||
std::cerr << "Invalid name used '" << item_name << "' is not a known item in " + m_name << '\n';
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// @brief Return the name for item with index @a ix
|
||||
/// @param ix The index number
|
||||
/// @return The name of the item
|
||||
[[nodiscard]] const std::string &get_item_name(uint16_t ix) const
|
||||
std::string_view get_item_name(uint16_t ix) const
|
||||
{
|
||||
if (ix >= m_items.size())
|
||||
throw std::out_of_range("item index is out of range");
|
||||
@@ -1139,35 +1113,47 @@ 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
|
||||
uint16_t add_item(std::string_view item_name);
|
||||
uint16_t add_item(std::string_view item_name)
|
||||
{
|
||||
using namespace std::literals;
|
||||
|
||||
uint16_t result = get_item_ix(item_name);
|
||||
|
||||
if (result == m_items.size())
|
||||
{
|
||||
const item_validator *item_validator = nullptr;
|
||||
|
||||
if (m_cat_validator != nullptr)
|
||||
{
|
||||
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_items.emplace_back(item_name, item_validator);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/** @brief Remove item name @a colum_name
|
||||
* @param item_name The item to be removed
|
||||
*/
|
||||
void remove_item(std::string_view item_name);
|
||||
|
||||
/// \brief Drop items in this category that contain empty values in all rows.
|
||||
void drop_empty_items();
|
||||
|
||||
/** @brief Rename item @a from_name to @a to_name */
|
||||
void rename_item(std::string_view from_name, std::string_view to_name);
|
||||
|
||||
/// @brief Return whether a item with name @a name exists in this category
|
||||
/// @param name The name of the item
|
||||
/// @return True if the item exists
|
||||
[[nodiscard]] bool has_item(std::string_view name) const
|
||||
bool has_item(std::string_view name) const
|
||||
{
|
||||
return get_item_ix(name) < m_items.size();
|
||||
}
|
||||
|
||||
/// @brief Return the items in this category
|
||||
[[nodiscard]] std::vector<std::string> get_items() const;
|
||||
|
||||
/// @brief Return the number of items (colums) in this category
|
||||
[[nodiscard]] constexpr uint16_t get_item_count() const noexcept
|
||||
{
|
||||
return m_items.size();
|
||||
}
|
||||
/// @brief Return the cif::iset of items in this category
|
||||
iset get_items() const;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
@@ -1182,55 +1168,31 @@ class category
|
||||
void reorder_by_index();
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/// This function returns effectively the list of fully qualified item
|
||||
/// names, that is category_name + '.' + item_name for each item
|
||||
[[nodiscard]] std::vector<std::string> get_item_order() const;
|
||||
[[deprecated("use get_item_order instead")]] std::vector<std::string> get_tag_order() const
|
||||
{
|
||||
return get_item_order();
|
||||
}
|
||||
|
||||
/// This function returns effectively the list of fully qualified item
|
||||
/// names, that is category_name + '.' + item_name for each item
|
||||
std::vector<std::string> get_item_order() const;
|
||||
|
||||
/// Write the contents of the category to the std::ostream @a os
|
||||
void write(std::ostream &os) const;
|
||||
|
||||
/// \brief Various supported output formats
|
||||
enum class output_format
|
||||
{
|
||||
cif, // Output in mmCIF format
|
||||
csv, // comma separated values
|
||||
tsv, // tab separated values
|
||||
list, // values delimited by a '|' character
|
||||
column, // output in columns
|
||||
markdown, //
|
||||
table, // ascii art table
|
||||
box, // table with unicode line characters
|
||||
};
|
||||
|
||||
/// @brief
|
||||
/// @brief Write the contents of the category to the std::ostream @a os and
|
||||
/// use @a order as the order of the items. If @a addMissingItems is
|
||||
/// false, items that do not contain any value will be suppressed. Use this version
|
||||
/// to write out
|
||||
/// @param os The std::ostream to write to
|
||||
/// @param fmt The format to use
|
||||
/// @param order The order in which the items should appear
|
||||
/// @param addMissingItems When false, empty items are suppressed from the output
|
||||
void write(std::ostream &os, output_format fmt,
|
||||
const std::vector<std::string> &order, bool addMissingItems = true);
|
||||
|
||||
/// @brief Write the contents of the category to the std::ostream @a os and
|
||||
/// use @a order as the order of the items. If @a addMissingItems is
|
||||
/// false, items that do not contain any value will be suppressed
|
||||
/// @param os The std::ostream to write to
|
||||
/// @param order The order in which the items should appear
|
||||
/// @param addMissingItems When false, empty items are suppressed from the output
|
||||
void write(std::ostream &os, const std::vector<std::string> &order, bool addMissingItems = true)
|
||||
{
|
||||
write(os, output_format::cif, order, addMissingItems);
|
||||
}
|
||||
void write(std::ostream &os, const std::vector<std::string> &order, bool addMissingItems = true);
|
||||
|
||||
private:
|
||||
void write_cif(std::ostream &os, const std::vector<uint16_t> &order, bool includeEmptyItems) const;
|
||||
void write_delimited(std::ostream &os, const std::vector<uint16_t> &order, bool includeEmptyItems,
|
||||
std::string_view delimiter, bool aligned, bool header) const;
|
||||
void write_markdown(std::ostream &os, const std::vector<uint16_t> &order, bool includeEmptyItems) const;
|
||||
void write_table(std::ostream &os, const std::vector<uint16_t> &order, bool includeEmptyItems, bool ascii) const;
|
||||
void write(std::ostream &os, const std::vector<uint16_t> &order, bool includeEmptyItems) const;
|
||||
|
||||
public:
|
||||
/// friend function to make it possible to do:
|
||||
@@ -1244,13 +1206,13 @@ class category
|
||||
}
|
||||
|
||||
private:
|
||||
void update_value(row *row, uint16_t item, item_value value, bool updateLinked, bool validate = true);
|
||||
void update_value(row *row, uint16_t item, std::string_view value, bool updateLinked, bool validate = true);
|
||||
|
||||
void erase_orphans(condition &&cond, category &parent);
|
||||
|
||||
using allocator_type = std::allocator<void>;
|
||||
|
||||
[[nodiscard]] constexpr allocator_type get_allocator() const
|
||||
constexpr allocator_type get_allocator() const
|
||||
{
|
||||
return {};
|
||||
}
|
||||
@@ -1279,8 +1241,6 @@ class category
|
||||
|
||||
void delete_row(row *r);
|
||||
|
||||
iterator erase(iterator pos, bool cascade);
|
||||
|
||||
row_handle create_copy(row_handle r);
|
||||
|
||||
struct item_entry
|
||||
@@ -1303,7 +1263,7 @@ class category
|
||||
{
|
||||
}
|
||||
|
||||
// TODO: NEED TO FIX THIS! (but what was it that needs to be fixed?)
|
||||
// TODO: NEED TO FIX THIS!
|
||||
category *linked;
|
||||
const link_validator *v;
|
||||
};
|
||||
@@ -1314,8 +1274,8 @@ class category
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
[[nodiscard]] condition get_parents_condition(const_row_handle rh, const category &parentCat) const;
|
||||
[[nodiscard]] condition get_children_condition(const_row_handle rh, const category &childCat) const;
|
||||
condition get_parents_condition(row_handle rh, const category &parentCat) const;
|
||||
condition get_children_condition(row_handle rh, const category &childCat) const;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
@@ -1325,16 +1285,13 @@ class category
|
||||
|
||||
std::string m_name;
|
||||
std::vector<item_entry> m_items;
|
||||
const validator *m_validator = nullptr;
|
||||
const validator_base *m_validator = nullptr;
|
||||
const category_validator *m_cat_validator = nullptr;
|
||||
std::vector<link> m_parent_links, m_child_links;
|
||||
bool m_cascade = true;
|
||||
uint32_t m_last_unique_num = 0;
|
||||
class category_index *m_index = nullptr;
|
||||
row *m_head = nullptr, *m_tail = nullptr;
|
||||
|
||||
bool m_dirty = false; // Keep track of modifications
|
||||
};
|
||||
|
||||
static_assert(std::ranges::input_range<category>);
|
||||
|
||||
} // namespace cif
|
||||
|
||||
@@ -26,16 +26,15 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cif++/atom_type.hpp"
|
||||
#include "cif++/datablock.hpp"
|
||||
#include "cif++/exports.hpp"
|
||||
#include "cif++/point.hpp"
|
||||
#include "cif++/utilities.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <filesystem>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <set>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
/// \file compound.hpp
|
||||
@@ -54,10 +53,9 @@ namespace cif
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
class compound;
|
||||
struct compound_atom;
|
||||
class compound_factory_impl;
|
||||
class datablock;
|
||||
class file;
|
||||
enum atom_type : uint8_t;
|
||||
|
||||
/// \brief The bond type or bond order as defined in the CCD, possible values taken from the mmcif_pdbx file
|
||||
enum class bond_type
|
||||
@@ -118,7 +116,7 @@ struct compound_atom
|
||||
z; ///< The z component of the coordinates for each atom specified as orthogonal angstroms.
|
||||
|
||||
/// Return the location of the atom as a point
|
||||
[[nodiscard]] point get_location() const
|
||||
point get_location() const
|
||||
{
|
||||
return { x, y, z };
|
||||
}
|
||||
@@ -148,44 +146,41 @@ class compound
|
||||
public:
|
||||
// accessors
|
||||
|
||||
[[nodiscard]] std::string id() const { return m_id; } ///< Return the alphanumeric code for the chemical component.
|
||||
[[nodiscard]] std::string name() const { return m_name; } ///< Return the name of the chemical component.
|
||||
[[nodiscard]] std::string type() const { return m_type; } ///< Return the type of monomer.
|
||||
[[nodiscard]] std::string formula() const { return m_formula; } ///< Return the chemical formula of the chemical component.
|
||||
[[nodiscard]] float formula_weight() const { return m_formula_weight; } ///< Return the formula mass of the chemical component in Daltons.
|
||||
[[nodiscard]] int formal_charge() const { return m_formal_charge; } ///< Return the formal charge on the chemical component.
|
||||
std::string id() const { return m_id; } ///< Return the alphanumeric code for the chemical component.
|
||||
std::string name() const { return m_name; } ///< Return the name of the chemical component.
|
||||
std::string type() const { return m_type; } ///< Return the type of monomer.
|
||||
std::string formula() const { return m_formula; } ///< Return the chemical formula of the chemical component.
|
||||
float formula_weight() const { return m_formula_weight; } ///< Return the formula mass of the chemical component in Daltons.
|
||||
int formal_charge() const { return m_formal_charge; } ///< Return the formal charge on the chemical component.
|
||||
|
||||
[[nodiscard]] const std::vector<compound_atom> &atoms() const { return m_atoms; } ///< Return the list of atoms for this compound
|
||||
[[nodiscard]] const std::vector<compound_bond> &bonds() const { return m_bonds; } ///< Return the list of bonds for this compound
|
||||
const std::vector<compound_atom> &atoms() const { return m_atoms; } ///< Return the list of atoms for this compound
|
||||
const std::vector<compound_bond> &bonds() const { return m_bonds; } ///< Return the list of bonds for this compound
|
||||
|
||||
[[nodiscard]] compound_atom get_atom_by_atom_id(const std::string &atom_id) const; ///< Return the atom with id @a atom_id
|
||||
compound_atom get_atom_by_atom_id(const std::string &atom_id) const; ///< Return the atom with id @a atom_id
|
||||
|
||||
[[nodiscard]] bool atoms_bonded(const std::string &atomId_1, const std::string &atomId_2) const; ///< Return true if @a atomId_1 is bonded to @a atomId_2
|
||||
[[nodiscard]] float bond_length(const std::string &atomId_1, const std::string &atomId_2) const; ///< Return the bond length between @a atomId_1 and @a atomId_2
|
||||
bool atoms_bonded(const std::string &atomId_1, const std::string &atomId_2) const; ///< Return true if @a atomId_1 is bonded to @a atomId_2
|
||||
float bond_length(const std::string &atomId_1, const std::string &atomId_2) const; ///< Return the bond length between @a atomId_1 and @a atomId_2
|
||||
|
||||
[[nodiscard]] bool is_water() const ///< Return if the compound is actually a water
|
||||
bool is_water() const ///< Return if the compound is actually a water
|
||||
{
|
||||
return m_id == "HOH" or m_id == "H2O" or m_id == "WAT";
|
||||
}
|
||||
|
||||
/** \brief Return whether this compound has a type of either 'peptide linking' or 'L-peptide linking' */
|
||||
[[nodiscard]] bool is_peptide() const;
|
||||
bool is_peptide() const;
|
||||
|
||||
/** \brief Return whether this compound has a type of either 'DNA linking' or 'RNA linking' */
|
||||
[[nodiscard]] bool is_base() const;
|
||||
bool is_base() const;
|
||||
|
||||
/// Return the one letter code to use in a canonical sequence. If unknown the value '\0' is returned
|
||||
[[nodiscard]] char one_letter_code() const { return m_one_letter_code; };
|
||||
|
||||
/// Return the parent id code in case a parent is specified (e.g. MET for MSE)
|
||||
[[nodiscard]] std::string parent_id() const { return m_parent_id; };
|
||||
char one_letter_code() const { return m_one_letter_code; }; ///< Return the one letter code to use in a canonical sequence. If unknown the value '\0' is returned
|
||||
std::string parent_id() const { return m_parent_id; }; ///< Return the parent id code in case a parent is specified (e.g. MET for MSE)
|
||||
|
||||
private:
|
||||
friend class compound_factory_impl;
|
||||
friend class local_compound_factory_impl;
|
||||
|
||||
compound(datablock &db);
|
||||
|
||||
compound(cif::datablock &db);
|
||||
|
||||
std::string m_id;
|
||||
std::string m_name;
|
||||
std::string m_type;
|
||||
@@ -206,9 +201,6 @@ class compound
|
||||
class compound_factory
|
||||
{
|
||||
public:
|
||||
compound_factory(const compound_factory &) = delete;
|
||||
compound_factory &operator=(const compound_factory &) = delete;
|
||||
|
||||
/// \brief Initialise a singleton instance.
|
||||
///
|
||||
/// If you have a multithreaded application and want to have different
|
||||
@@ -251,44 +243,38 @@ class compound_factory
|
||||
|
||||
/// Return whether @a res_name is a valid and known peptide
|
||||
[[deprecated("use is_peptide or is_std_peptide instead)")]]
|
||||
[[nodiscard]] bool
|
||||
is_known_peptide(const std::string &res_name) const;
|
||||
bool is_known_peptide(const std::string &res_name) const;
|
||||
|
||||
/// Return whether @a res_name is a valid and known base
|
||||
[[deprecated("use is_base or is_std_base instead)")]]
|
||||
[[nodiscard]] bool
|
||||
is_known_base(const std::string &res_name) const;
|
||||
bool is_known_base(const std::string &res_name) const;
|
||||
|
||||
/// Return whether @a res_name is a peptide
|
||||
[[nodiscard]] bool is_peptide(std::string_view res_name) const;
|
||||
bool is_peptide(std::string_view res_name) const;
|
||||
|
||||
/// Return whether @a res_name is a base
|
||||
[[nodiscard]] bool is_base(std::string_view res_name) const;
|
||||
bool is_base(std::string_view res_name) const;
|
||||
|
||||
/// Return whether @a res_name is one of the standard peptides
|
||||
[[nodiscard]] bool is_std_peptide(std::string_view res_name) const;
|
||||
bool is_std_peptide(std::string_view res_name) const;
|
||||
|
||||
/// Return whether @a res_name is one of the standard bases
|
||||
[[nodiscard]] bool is_std_base(std::string_view res_name) const;
|
||||
bool is_std_base(std::string_view res_name) const;
|
||||
|
||||
/// Return whether @a res_name is a monomer (either base or peptide)
|
||||
[[nodiscard]] bool is_monomer(std::string_view res_name) const;
|
||||
bool is_monomer(std::string_view res_name) const;
|
||||
|
||||
/// Return whether @a res_name is one of the standard bases or peptides
|
||||
[[nodiscard]] bool is_std_monomer(std::string_view res_name) const
|
||||
bool is_std_monomer(std::string_view res_name) const
|
||||
{
|
||||
return is_std_base(res_name) or is_std_peptide(res_name);
|
||||
}
|
||||
|
||||
/// Return whether @a res_name is water
|
||||
[[nodiscard]] bool is_water(std::string_view res_name) const
|
||||
bool is_water(std::string_view res_name) const
|
||||
{
|
||||
return res_name == "HOH" or res_name == "H2O" or res_name == "WAT";
|
||||
}
|
||||
|
||||
/// Return whether @a res_name already exists, without creating it.
|
||||
[[nodiscard]] bool exists(std::string_view res_name) const;
|
||||
|
||||
/// \brief Create the compound object for \a id
|
||||
///
|
||||
/// This will create the compound instance for \a id if it doesn't exist already.
|
||||
@@ -297,32 +283,24 @@ class compound_factory
|
||||
/// \result The compound, or nullptr if it could not be created (missing info)
|
||||
const compound *create(std::string_view id);
|
||||
|
||||
~compound_factory() = default;
|
||||
~compound_factory();
|
||||
|
||||
CIFPP_EXPORT static const std::map<std::string, char> kAAMap, ///< Globally accessible static list of the default amino acids
|
||||
kBaseMap; ///< Globally accessible static list of the default bases
|
||||
|
||||
/// Print out a message for a missing compound
|
||||
void report_missing_compound(std::string_view compound_id);
|
||||
|
||||
/// Return a flag indicating if we need to print out a report
|
||||
[[nodiscard]] bool get_report_missing() const { return m_report_missing; }
|
||||
|
||||
/// Set a flag indicating if we need to print out a report
|
||||
void set_report_missing(bool report)
|
||||
{
|
||||
m_report_missing = report;
|
||||
}
|
||||
|
||||
private:
|
||||
compound_factory();
|
||||
|
||||
compound_factory(const compound_factory &) = delete;
|
||||
compound_factory &operator=(const compound_factory &) = delete;
|
||||
|
||||
static std::unique_ptr<compound_factory> s_instance;
|
||||
static thread_local std::unique_ptr<compound_factory> tl_instance;
|
||||
static bool s_use_thread_local_instance;
|
||||
|
||||
std::shared_ptr<compound_factory_impl> m_impl;
|
||||
bool m_report_missing = true;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
@@ -345,15 +323,14 @@ class compound_factory
|
||||
class compound_source
|
||||
{
|
||||
public:
|
||||
/// Constructor
|
||||
compound_source(const file &file)
|
||||
compound_source(const cif::file &file)
|
||||
{
|
||||
compound_factory::instance().push_dictionary(file);
|
||||
cif::compound_factory::instance().push_dictionary(file);
|
||||
}
|
||||
|
||||
~compound_source()
|
||||
{
|
||||
compound_factory::instance().pop_dictionary();
|
||||
cif::compound_factory::instance().pop_dictionary();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,507 +0,0 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2025 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
|
||||
|
||||
/**
|
||||
* @file cql.hpp
|
||||
*
|
||||
* This file contains code to access stored data as if it were
|
||||
* a relation database. The underlying code uses SQLite as engine.
|
||||
* categories are exposed as virtual tables.
|
||||
*/
|
||||
|
||||
#include "cif++/category.hpp"
|
||||
#include "cif++/item.hpp"
|
||||
#include "cif++/iterator.hpp"
|
||||
#include "cif++/row.hpp"
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <ostream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
namespace cif::cql
|
||||
{
|
||||
|
||||
class connection;
|
||||
struct result_impl;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/// Reference to a field in the result set
|
||||
class field_ref final
|
||||
{
|
||||
public:
|
||||
/// The name of the field
|
||||
[[nodiscard]] std::string_view name() const &
|
||||
{
|
||||
return m_row.get_category().get_item_name(m_index);
|
||||
}
|
||||
|
||||
/// The index number of the field
|
||||
[[nodiscard]] constexpr size_t num() const noexcept
|
||||
{
|
||||
return m_index;
|
||||
}
|
||||
|
||||
/** Return the contents of this item as type @tparam T */
|
||||
template <typename T = std::string>
|
||||
[[nodiscard]] auto get() const -> T
|
||||
{
|
||||
return m_row[m_index].get<T>();
|
||||
}
|
||||
|
||||
/// Returns true if the field contains NULL
|
||||
[[nodiscard]] bool is_null() const
|
||||
{
|
||||
return m_row[m_index].is_null();
|
||||
}
|
||||
|
||||
/** Return the contents of this item as type @tparam T or, if not
|
||||
* set, use @a dv as the default value.
|
||||
*/
|
||||
template <typename T>
|
||||
auto value_or(const T &dv) const
|
||||
{
|
||||
return m_row[m_index].value_or(dv);
|
||||
}
|
||||
|
||||
/// Constructor
|
||||
field_ref(const_row_handle rh, uint16_t col, std::shared_ptr<result_impl> result_impl)
|
||||
: m_row(std::move(rh))
|
||||
, m_index(col)
|
||||
, m_result_impl(std::move(result_impl))
|
||||
{
|
||||
}
|
||||
|
||||
/// Copy constructor
|
||||
field_ref(const field_ref &) = default;
|
||||
/// Move constructor
|
||||
field_ref(field_ref &&) = default;
|
||||
|
||||
/// Copy assignment
|
||||
field_ref &operator=(const field_ref &) = default;
|
||||
/// Move assignment
|
||||
field_ref &operator=(field_ref &&) = default;
|
||||
|
||||
private:
|
||||
const_row_handle m_row;
|
||||
uint16_t m_index;
|
||||
|
||||
std::shared_ptr<result_impl> m_result_impl;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/// A reference to a row in the result set
|
||||
class row_ref final
|
||||
{
|
||||
public:
|
||||
/// Iterator for the items in this row
|
||||
class const_field_iterator
|
||||
{
|
||||
public:
|
||||
friend class result;
|
||||
|
||||
/// @cond
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using value_type = const field_ref;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = value_type *;
|
||||
using reference = value_type &;
|
||||
|
||||
const_field_iterator(const const_field_iterator &) = default;
|
||||
const_field_iterator(const_field_iterator &&) = default;
|
||||
|
||||
const_field_iterator &operator=(const const_field_iterator &) = default;
|
||||
const_field_iterator &operator=(const_field_iterator &&) = default;
|
||||
|
||||
reference operator*()
|
||||
{
|
||||
return m_current;
|
||||
}
|
||||
|
||||
pointer operator->()
|
||||
{
|
||||
return &m_current;
|
||||
}
|
||||
|
||||
const_field_iterator &operator++()
|
||||
{
|
||||
if (m_row)
|
||||
{
|
||||
++m_col;
|
||||
m_current = field_ref(m_row, m_col, m_result_impl);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
const_field_iterator operator++(int)
|
||||
{
|
||||
const_field_iterator result(*this);
|
||||
this->operator++();
|
||||
return result;
|
||||
}
|
||||
|
||||
bool operator==(const const_field_iterator &rhs) const
|
||||
{
|
||||
return m_row == rhs.m_row and m_col == rhs.m_col;
|
||||
}
|
||||
|
||||
bool operator!=(const const_field_iterator &rhs) const
|
||||
{
|
||||
return m_row != rhs.m_row or m_col != rhs.m_col;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class row_ref;
|
||||
|
||||
const_field_iterator(const_row_handle row, uint16_t column, std::shared_ptr<result_impl> result_impl)
|
||||
: m_row(std::move(row))
|
||||
, m_col(column)
|
||||
, m_current(m_row, m_col, result_impl)
|
||||
, m_result_impl(result_impl)
|
||||
{
|
||||
}
|
||||
|
||||
const_row_handle m_row;
|
||||
uint16_t m_col;
|
||||
field_ref m_current;
|
||||
|
||||
std::shared_ptr<result_impl> m_result_impl;
|
||||
|
||||
/// @endcond
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
row_ref() = default;
|
||||
|
||||
/// Constructor
|
||||
row_ref(const_row_handle rh, std::shared_ptr<result_impl> result_impl)
|
||||
: m_row(std::move(rh))
|
||||
, m_result_impl(std::move(result_impl))
|
||||
{
|
||||
}
|
||||
|
||||
/// @cond
|
||||
row_ref(const row_ref &) = default;
|
||||
row_ref &operator=(const row_ref &) = default;
|
||||
/// @endcond
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
[[nodiscard]] const_field_iterator begin() const noexcept { return { m_row, 0, m_result_impl }; } ///< Return begin field iterator
|
||||
[[nodiscard]] const_field_iterator cbegin() const noexcept { return { m_row, 0, m_result_impl }; } ///< Return cbegin field iterator
|
||||
[[nodiscard]] const_field_iterator end() const noexcept { return { m_row, static_cast<uint16_t>(size()), m_result_impl }; } ///< Return end field iterator
|
||||
[[nodiscard]] const_field_iterator cend() const noexcept { return { m_row, static_cast<uint16_t>(size()), m_result_impl }; } ///< Return cend field iterator
|
||||
|
||||
[[nodiscard]] field_ref front() const noexcept { return { m_row, 0, m_result_impl }; } ///< return reference to front field
|
||||
[[nodiscard]] field_ref back() const noexcept { return { m_row, static_cast<uint16_t>(size() - 1), m_result_impl }; } ///< return reference to back field
|
||||
|
||||
[[nodiscard]] size_t size() const noexcept; ///< return number of items in the row
|
||||
[[nodiscard]] bool empty() const noexcept { return size() == 0; } ///< return if the row contains no items at all
|
||||
|
||||
[[nodiscard]] field_ref operator[](uint16_t index) const noexcept { return { m_row, index, m_result_impl }; } ///< access field by index
|
||||
[[nodiscard]] field_ref operator[](std::string_view name) const; ///< access field by name
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/// @cond
|
||||
bool operator==(const row_ref &rhs) const { return m_row == rhs.m_row; }
|
||||
bool operator!=(const row_ref &rhs) const { return m_row != rhs.m_row; }
|
||||
|
||||
private:
|
||||
const_row_handle m_row;
|
||||
std::shared_ptr<result_impl> m_result_impl;
|
||||
|
||||
/// @endcond
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/// The result set, containing the result of a query
|
||||
class result
|
||||
{
|
||||
public:
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/// iterator to the rows in the result set
|
||||
class iterator
|
||||
{
|
||||
public:
|
||||
friend class view;
|
||||
|
||||
/// @cond
|
||||
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using value_type = const row_ref;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = value_type *;
|
||||
using reference = value_type &;
|
||||
|
||||
// const_row_iterator() = default;
|
||||
|
||||
iterator(std::shared_ptr<result_impl> result_impl, category::const_iterator cat_iter)
|
||||
: m_iter(std::move(cat_iter))
|
||||
, m_current(*m_iter, result_impl)
|
||||
, m_result_impl(result_impl)
|
||||
{
|
||||
}
|
||||
|
||||
iterator(const iterator &) = default;
|
||||
iterator(iterator &&) = default;
|
||||
|
||||
// const_row_iterator &operator=(const const_row_iterator &) = default;
|
||||
// const_row_iterator &operator=(const_row_iterator &&) = default;
|
||||
|
||||
reference operator*()
|
||||
{
|
||||
return m_current;
|
||||
}
|
||||
|
||||
pointer operator->()
|
||||
{
|
||||
return &m_current;
|
||||
}
|
||||
|
||||
iterator &operator++()
|
||||
{
|
||||
++m_iter;
|
||||
m_current = { *m_iter, m_result_impl };
|
||||
return *this;
|
||||
}
|
||||
|
||||
iterator operator++(int)
|
||||
{
|
||||
iterator result(*this);
|
||||
this->operator++();
|
||||
return result;
|
||||
}
|
||||
|
||||
bool operator==(const iterator &rhs) const
|
||||
{
|
||||
return m_result_impl == rhs.m_result_impl and m_iter == rhs.m_iter;
|
||||
}
|
||||
|
||||
bool operator!=(const iterator &rhs) const
|
||||
{
|
||||
return m_result_impl != rhs.m_result_impl or m_iter != rhs.m_iter;
|
||||
}
|
||||
|
||||
private:
|
||||
category::const_iterator m_iter;
|
||||
row_ref m_current;
|
||||
std::shared_ptr<result_impl> m_result_impl;
|
||||
|
||||
/// @endcond
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/// @cond
|
||||
result() = delete;
|
||||
result(result const &rhs) noexcept = default;
|
||||
result(result &&rhs) noexcept = default;
|
||||
result &operator=(result const &rhs) noexcept = default;
|
||||
result &operator=(result &&rhs) noexcept = default;
|
||||
|
||||
result(category &&data, const std::string &query = "");
|
||||
|
||||
~result() = default;
|
||||
/// @endcond
|
||||
|
||||
/// Return the row if and only if the result set contains exactly one row, throws otherwise
|
||||
[[nodiscard]] row_ref one_row() const
|
||||
{
|
||||
if (size() != 1)
|
||||
throw std::runtime_error("Expected one row");
|
||||
return front();
|
||||
}
|
||||
|
||||
/// Return the row if and only if the result set contains exactly one row,
|
||||
/// and this row also contains only one field, throws otherwise
|
||||
[[nodiscard]] field_ref one_field() const
|
||||
{
|
||||
expect_columns(1);
|
||||
|
||||
if (size() != 1)
|
||||
throw std::runtime_error("Expected one row");
|
||||
|
||||
return one_row().front();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/// @cond
|
||||
[[nodiscard]] iterator begin() const noexcept;
|
||||
[[nodiscard]] iterator cbegin() const noexcept;
|
||||
|
||||
[[nodiscard]] iterator end() const noexcept;
|
||||
[[nodiscard]] iterator cend() const noexcept;
|
||||
|
||||
[[nodiscard]] row_ref front() const;
|
||||
[[nodiscard]] row_ref back() const;
|
||||
|
||||
[[nodiscard]] size_t size() const noexcept;
|
||||
[[nodiscard]] bool empty() const noexcept { return size() == 0; }
|
||||
/// @endcond
|
||||
|
||||
/// Return the number of colums/fields in each row
|
||||
[[nodiscard]] size_t column_count() const;
|
||||
|
||||
/// Return the result set as a cif::category
|
||||
[[nodiscard]] category &get_category() const;
|
||||
|
||||
/// Test to see if the result set contains at least the number of fields/columns
|
||||
/// but only when not empty
|
||||
void expect_columns(size_t cols) const
|
||||
{
|
||||
if (auto actual = column_count(); size() > 0 and cols != actual)
|
||||
throw std::runtime_error("Unexpected number of columns");
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/// Print out the result set, for debugging mostly
|
||||
friend std::ostream &operator<<(std::ostream &os, const result &r)
|
||||
{
|
||||
os << r.get_category();
|
||||
return os;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class transaction;
|
||||
friend class SelectStatement;
|
||||
|
||||
std::shared_ptr<result_impl> m_impl;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/// Helper class to allow access to the data as a stream
|
||||
template <typename... Ts>
|
||||
class cql_iterator_proxy : public cif::iterator_proxy<Ts...>
|
||||
{
|
||||
public:
|
||||
/// Constructor
|
||||
cql_iterator_proxy(result &&res)
|
||||
: cif::iterator_proxy<Ts...>(res.get_category())
|
||||
, m_result(std::forward<result>(res))
|
||||
{
|
||||
m_result.expect_columns(cif::iterator_proxy<Ts...>::N);
|
||||
}
|
||||
|
||||
private:
|
||||
result m_result;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/// Transaction class.
|
||||
/// At construction, this class starts a transaction on the connection
|
||||
/// and at exit an automatic rollback is done, unless commit was called.
|
||||
class transaction final
|
||||
{
|
||||
public:
|
||||
/// Constructor
|
||||
transaction(connection &conn);
|
||||
|
||||
/// @cond
|
||||
~transaction();
|
||||
|
||||
transaction(const transaction &) = delete;
|
||||
transaction &operator=(const transaction &) = delete;
|
||||
/// @endcond
|
||||
|
||||
/// \brief Execute the sql in @a query returning an iterable result
|
||||
result exec(std::string query);
|
||||
|
||||
/// \brief Execute the sql in @a query returning an iterable result.
|
||||
/// Updates @a tail with what remains after the first statement in @a query
|
||||
result exec(std::string query, std::string &tail);
|
||||
|
||||
/// Execute the sql in @a sql and return the result as a stream
|
||||
template <typename... Ts>
|
||||
cql_iterator_proxy<Ts...> stream(const std::string &sql)
|
||||
{
|
||||
return cql_iterator_proxy<Ts...>{ exec(sql) };
|
||||
}
|
||||
|
||||
/// Commit the result of the operations
|
||||
void commit();
|
||||
|
||||
/// Rollback the result of the operations, the underlying data is
|
||||
/// restored to the state before the construction of this transaction.
|
||||
void rollback();
|
||||
|
||||
private:
|
||||
connection &m_conn;
|
||||
bool m_transaction_active = false;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/// This connection class creates a SQLite environment with the data in
|
||||
/// the provided datablock as tables.
|
||||
class connection final
|
||||
{
|
||||
public:
|
||||
/// Constructor
|
||||
connection(datablock &db);
|
||||
|
||||
/// Destructor
|
||||
~connection();
|
||||
|
||||
friend class transaction;
|
||||
|
||||
/// \brief Return true if the string @a sql contains a complete statement.
|
||||
[[nodiscard]] bool is_complete_statement(const std::string &sql) const;
|
||||
|
||||
/// \brief Execute the sql in @a query returning an iterable result
|
||||
result exec(std::string query);
|
||||
|
||||
/// \brief Execute the sql in @a query returning an iterable result.
|
||||
/// Updates @a tail with what remains after the first statement in @a query
|
||||
result exec(std::string query, std::string &tail);
|
||||
|
||||
/// \brief Return true if the underlying data was modified by any query.
|
||||
[[nodiscard]] bool is_modified() const;
|
||||
|
||||
private:
|
||||
struct connection_impl *m_impl;
|
||||
};
|
||||
|
||||
} // namespace cif::cql
|
||||
@@ -27,14 +27,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "cif++/category.hpp"
|
||||
|
||||
#include <iosfwd>
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "cif++/forward_decl.hpp"
|
||||
|
||||
/** \file datablock.hpp
|
||||
* Each valid mmCIF file contains at least one @ref cif::datablock.
|
||||
@@ -44,13 +37,11 @@
|
||||
namespace cif
|
||||
{
|
||||
|
||||
class validator;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief A datablock is a list of category objects with some additional features
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
class datablock : public std::list<category>
|
||||
@@ -60,7 +51,7 @@ class datablock : public std::list<category>
|
||||
|
||||
/**
|
||||
* @brief Construct a new datablock object with name @a name
|
||||
*
|
||||
*
|
||||
* @param name The name for the new datablock
|
||||
*/
|
||||
datablock(std::string_view name)
|
||||
@@ -83,12 +74,11 @@ class datablock : public std::list<category>
|
||||
}
|
||||
/** @endcond */
|
||||
|
||||
/// Swap two datablocks
|
||||
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));
|
||||
std::swap(static_cast<std::list<category>&>(a), static_cast<std::list<category>&>(b));
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
@@ -96,11 +86,11 @@ class datablock : public std::list<category>
|
||||
/**
|
||||
* @brief Return the name of this datablock
|
||||
*/
|
||||
[[nodiscard]] const std::string &name() const { return m_name; }
|
||||
const std::string &name() const { return m_name; }
|
||||
|
||||
/**
|
||||
* @brief Set the name of this datablock to @a name
|
||||
*
|
||||
*
|
||||
* @param name The new name
|
||||
*/
|
||||
void set_name(std::string_view name)
|
||||
@@ -110,61 +100,63 @@ class datablock : public std::list<category>
|
||||
|
||||
/**
|
||||
* @brief Attempt to load the dictionary specified in audit_conform category
|
||||
*
|
||||
*
|
||||
*/
|
||||
void load_dictionary();
|
||||
|
||||
/**
|
||||
* @brief Attempt to load the dictionary @a dict
|
||||
*
|
||||
* @brief Load the dictionary named @a dict_name
|
||||
*
|
||||
* @param dict_name
|
||||
*/
|
||||
void load_dictionary(std::string_view dict);
|
||||
void load_dictionary(std::string_view dict_name);
|
||||
|
||||
/**
|
||||
* @brief Set the validator object to @a v
|
||||
*
|
||||
*
|
||||
* @param v The new validator object, may be null
|
||||
*/
|
||||
void set_validator(const validator *v);
|
||||
void set_validator(const validator_base *v);
|
||||
|
||||
/**
|
||||
* @brief Get the validator object
|
||||
*
|
||||
*
|
||||
* @return const validator* The validator or nullptr if there is none
|
||||
*/
|
||||
[[nodiscard]] const validator *get_validator() const;
|
||||
const validator_base *get_validator() const;
|
||||
|
||||
/**
|
||||
* @brief Validates the content of this datablock and all its content
|
||||
*
|
||||
*
|
||||
* @return true If the content is valid
|
||||
* @return false If the content is not valid
|
||||
*/
|
||||
[[nodiscard]] bool is_valid() const;
|
||||
bool is_valid() const;
|
||||
|
||||
/**
|
||||
* @brief Validates the content of this datablock and all its content
|
||||
* and updates or removes the audit_conform category to match the result.
|
||||
*
|
||||
* @return true If the content is valid
|
||||
* @return false If the content is not valid
|
||||
*/
|
||||
bool is_valid();
|
||||
|
||||
/**
|
||||
* @brief Validates all contained data for valid links between parents and children
|
||||
* as defined in the validator
|
||||
*
|
||||
*
|
||||
* @return true If all links are valid
|
||||
* @return false If all links are not valid
|
||||
*/
|
||||
[[nodiscard]] bool validate_links() const;
|
||||
|
||||
/**
|
||||
* @brief Strip removes all categories and items that are invalid according
|
||||
* to the assigned validator. Will also add a valid audit_conform block.
|
||||
*
|
||||
* @return true if the remaining datablock is valid
|
||||
*/
|
||||
bool strip();
|
||||
bool validate_links() const;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Return the category named @a name, will create a new and empty
|
||||
* category named @a name if it does not exist.
|
||||
*
|
||||
*
|
||||
* @param name The name of the category to return
|
||||
* @return category& Reference to the named category
|
||||
*/
|
||||
@@ -173,7 +165,7 @@ class datablock : public std::list<category>
|
||||
/**
|
||||
* @brief Return the const category named @a name, will return a reference
|
||||
* to a static empty category if it was not found.
|
||||
*
|
||||
*
|
||||
* @param name The name of the category to return
|
||||
* @return category& Reference to the named category
|
||||
*/
|
||||
@@ -182,7 +174,7 @@ class datablock : public std::list<category>
|
||||
/**
|
||||
* @brief Return a pointer to the category named @a name or nullptr if
|
||||
* it does not exist.
|
||||
*
|
||||
*
|
||||
* @param name The name of the category
|
||||
* @return category* Pointer to the category found or nullptr
|
||||
*/
|
||||
@@ -191,26 +183,18 @@ class datablock : public std::list<category>
|
||||
/**
|
||||
* @brief Return a pointer to the category named @a name or nullptr if
|
||||
* it does not exist.
|
||||
*
|
||||
*
|
||||
* @param name The name of the category
|
||||
* @return category* Pointer to the category found or nullptr
|
||||
*/
|
||||
[[nodiscard]] const category *get(std::string_view name) const;
|
||||
|
||||
/**
|
||||
* @brief Return true if this datablock contains a non-empty category
|
||||
*/
|
||||
[[nodiscard]] bool contains(std::string_view name) const
|
||||
{
|
||||
return get(name) != nullptr;
|
||||
}
|
||||
const category *get(std::string_view name) const;
|
||||
|
||||
/**
|
||||
* @brief Tries to find a category with name @a name and will create a
|
||||
* new one if it is not found. The result is a tuple of an iterator
|
||||
* pointing to the category and a boolean indicating whether the category
|
||||
* was created or not.
|
||||
*
|
||||
*
|
||||
* @param name The name for the category
|
||||
* @return std::tuple<iterator, bool> A tuple containing an iterator pointing
|
||||
* at the category and a boolean indicating whether the category was newly
|
||||
@@ -221,7 +205,16 @@ class datablock : public std::list<category>
|
||||
/**
|
||||
* @brief Get the preferred order of the categories when writing them
|
||||
*/
|
||||
[[nodiscard]] std::vector<std::string> get_item_order() const;
|
||||
[[deprecated("use get_item_order instead")]]
|
||||
std::vector<std::string> get_tag_order() const
|
||||
{
|
||||
return get_item_order();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the preferred order of the categories when writing them
|
||||
*/
|
||||
std::vector<std::string> get_item_order() const;
|
||||
|
||||
/**
|
||||
* @brief Write out the contents to @a os
|
||||
@@ -251,7 +244,7 @@ class datablock : public std::list<category>
|
||||
|
||||
private:
|
||||
std::string m_name;
|
||||
const validator *m_validator = nullptr;
|
||||
const validator_base *m_validator = nullptr;
|
||||
};
|
||||
|
||||
} // namespace cif
|
||||
} // namespace cif
|
||||
@@ -27,7 +27,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "cif++/validate.hpp"
|
||||
#include <iosfwd>
|
||||
|
||||
/**
|
||||
* @file validate.hpp
|
||||
@@ -38,11 +37,9 @@
|
||||
namespace cif
|
||||
{
|
||||
|
||||
class validator;
|
||||
|
||||
/**
|
||||
* @brief Parse the contents of @a is and place content in validator @a v
|
||||
* @brief Parse the contents of @a is and create a new validator object with name @a name
|
||||
*/
|
||||
void parse_dictionary(validator &v, std::istream &is);
|
||||
validator parse_dictionary(std::string_view name, std::istream &is);
|
||||
|
||||
} // namespace cif
|
||||
|
||||
@@ -26,26 +26,21 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cif++/datablock.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <filesystem>
|
||||
#include <istream>
|
||||
#include <list>
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
|
||||
#include "cif++/datablock.hpp"
|
||||
#include "cif++/parser.hpp"
|
||||
|
||||
/** \file file.hpp
|
||||
*
|
||||
*
|
||||
* The file class defined here encapsulates the contents of an mmCIF file
|
||||
* It is mainly a list of @ref cif::datablock objects
|
||||
*
|
||||
*
|
||||
* The class file has methods to load dictionaries. These dictionaries are
|
||||
* loaded from resources (if available) or from disk from several locations.
|
||||
*
|
||||
*
|
||||
* See the documentation on load_resource() in file: utilities.hpp for more
|
||||
* information on how data is loaded.
|
||||
* information on how data is loaded.
|
||||
*/
|
||||
|
||||
namespace cif
|
||||
@@ -55,7 +50,7 @@ namespace cif
|
||||
|
||||
/**
|
||||
* @brief The class file is actually a list of datablock objects
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
class file : public std::list<datablock>
|
||||
@@ -65,7 +60,7 @@ class file : public std::list<datablock>
|
||||
|
||||
/**
|
||||
* @brief Construct a new file object using the data in the file @a p as content
|
||||
*
|
||||
*
|
||||
* @param p Path to a file containing the data to load
|
||||
*/
|
||||
explicit file(const std::filesystem::path &p)
|
||||
@@ -75,7 +70,7 @@ class file : public std::list<datablock>
|
||||
|
||||
/**
|
||||
* @brief Construct a new file object using the data in the std::istream @a is
|
||||
*
|
||||
*
|
||||
* @param is The istream containing the data to load
|
||||
*/
|
||||
explicit file(std::istream &is)
|
||||
@@ -86,7 +81,7 @@ class file : public std::list<datablock>
|
||||
/**
|
||||
* @brief Construct a new file object with data in the constant string defined
|
||||
* by @a data and @a length
|
||||
*
|
||||
*
|
||||
* @param data The pointer to the character string with data to load
|
||||
* @param length The length of the data
|
||||
*/
|
||||
@@ -105,7 +100,7 @@ class file : public std::list<datablock>
|
||||
}
|
||||
|
||||
/** @cond */
|
||||
file(const file &rhs) // NOLINT
|
||||
file(const file &rhs)
|
||||
: std::list<datablock>(rhs)
|
||||
{
|
||||
}
|
||||
@@ -125,23 +120,23 @@ class file : public std::list<datablock>
|
||||
|
||||
/**
|
||||
* @brief Validate the content and return true if everything was valid.
|
||||
*
|
||||
*
|
||||
* Will throw an exception if there is no validator defined.
|
||||
*
|
||||
*
|
||||
* If each category was valid, validate_links will also be called.
|
||||
*
|
||||
*
|
||||
* @return true If the content is valid
|
||||
* @return false If the content is not valid
|
||||
*/
|
||||
[[nodiscard]] bool is_valid() const;
|
||||
bool is_valid() const;
|
||||
|
||||
/**
|
||||
* @brief Validate the content and return true if everything was valid.
|
||||
*
|
||||
*
|
||||
* Will attempt to load the referenced dictionary if none was specified.
|
||||
*
|
||||
*
|
||||
* If each category was valid, validate_links will also be called.
|
||||
*
|
||||
*
|
||||
* @return true If the content is valid
|
||||
* @return false If the content is not valid
|
||||
*/
|
||||
@@ -149,18 +144,18 @@ class file : public std::list<datablock>
|
||||
|
||||
/**
|
||||
* @brief Validate the links for all datablocks contained.
|
||||
*
|
||||
*
|
||||
* Will throw an exception if no validator was specified.
|
||||
*
|
||||
*
|
||||
* @return true If all links were valid
|
||||
* @return false If all links were not valid
|
||||
*/
|
||||
[[nodiscard]] bool validate_links() const;
|
||||
bool validate_links() const;
|
||||
|
||||
/**
|
||||
* @brief Return true if a datablock with the name @a name is part of this file
|
||||
*/
|
||||
[[nodiscard]] bool contains(std::string_view name) const;
|
||||
bool contains(std::string_view name) const;
|
||||
|
||||
/**
|
||||
* @brief return a reference to the first datablock in the file
|
||||
@@ -174,7 +169,7 @@ class file : public std::list<datablock>
|
||||
/**
|
||||
* @brief return a const reference to the first datablock in the file
|
||||
*/
|
||||
[[nodiscard]] const datablock &front() const
|
||||
const datablock &front() const
|
||||
{
|
||||
assert(not empty());
|
||||
return std::list<datablock>::front();
|
||||
@@ -195,7 +190,7 @@ class file : public std::list<datablock>
|
||||
* new one if it is not found. The result is a tuple of an iterator
|
||||
* pointing to the datablock and a boolean indicating whether the datablock
|
||||
* was created or not.
|
||||
*
|
||||
*
|
||||
* @param name The name for the datablock
|
||||
* @return std::tuple<iterator, bool> A tuple containing an iterator pointing
|
||||
* at the datablock and a boolean indicating whether the datablock was newly
|
||||
@@ -209,6 +204,18 @@ class file : public std::list<datablock>
|
||||
/** Load the data from @a is */
|
||||
void load(std::istream &is);
|
||||
|
||||
/** Load the data from the file specified by @a p using validator @a v */
|
||||
void load(const std::filesystem::path &p, const validator_base &v);
|
||||
|
||||
/** Load the data from @a is using validator @a v */
|
||||
void load(std::istream &is, const validator_base &v);
|
||||
|
||||
/** Load the data from the file specified by @a p using a validator constructed from dictionary @a dict */
|
||||
void load(const std::filesystem::path &p, std::string_view dict);
|
||||
|
||||
/** Load the data from @a is using a validator constructed from dictionary @a dict */
|
||||
void load(std::istream &is, std::string_view dict);
|
||||
|
||||
/** Save the data to the file specified by @a p */
|
||||
void save(const std::filesystem::path &p) const;
|
||||
|
||||
@@ -225,4 +232,4 @@ class file : public std::list<datablock>
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace cif
|
||||
} // namespace cif
|
||||
@@ -26,18 +26,139 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ostream>
|
||||
#include <streambuf>
|
||||
|
||||
#include <string>
|
||||
|
||||
/** \file format.hpp
|
||||
*
|
||||
* Now using std::format instead of a home grown rip off
|
||||
* File containing a basic reimplementation of boost::format
|
||||
* but then a bit more simplistic. Still this allowed me to move my code
|
||||
* from using boost::format to something without external dependency easily.
|
||||
*/
|
||||
|
||||
namespace cif
|
||||
{
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template <typename T>
|
||||
struct to_varg
|
||||
{
|
||||
using type = T;
|
||||
|
||||
to_varg(const T &v)
|
||||
: m_value(v)
|
||||
{
|
||||
}
|
||||
|
||||
type operator*() { return m_value; }
|
||||
|
||||
T m_value;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct to_varg<const char *>
|
||||
{
|
||||
using type = const char *;
|
||||
|
||||
to_varg(const char *v)
|
||||
: m_value(v)
|
||||
{
|
||||
}
|
||||
|
||||
type operator*() { return m_value.c_str(); }
|
||||
|
||||
std::string m_value;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct to_varg<std::string>
|
||||
{
|
||||
using type = const char *;
|
||||
|
||||
to_varg(const std::string &v)
|
||||
: m_value(v)
|
||||
{
|
||||
}
|
||||
|
||||
type operator*() { return m_value.c_str(); }
|
||||
|
||||
std::string m_value;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
/** @cond */
|
||||
|
||||
template <typename... Args>
|
||||
class format_plus_arg
|
||||
{
|
||||
public:
|
||||
using args_vector_type = std::tuple<detail::to_varg<Args>...>;
|
||||
using vargs_vector_type = std::tuple<typename detail::to_varg<Args>::type...>;
|
||||
|
||||
format_plus_arg(const format_plus_arg &) = delete;
|
||||
format_plus_arg &operator=(const format_plus_arg &) = delete;
|
||||
|
||||
|
||||
format_plus_arg(std::string_view fmt, Args... args)
|
||||
: m_fmt(fmt)
|
||||
, m_args(std::forward<Args>(args)...)
|
||||
{
|
||||
auto ix = std::make_index_sequence<sizeof...(Args)>();
|
||||
copy_vargs(ix);
|
||||
}
|
||||
|
||||
std::string str()
|
||||
{
|
||||
char buffer[1024];
|
||||
std::string::size_type r = std::apply(snprintf, std::tuple_cat(std::make_tuple(buffer, sizeof(buffer), m_fmt.c_str()), m_vargs));
|
||||
return { buffer, r };
|
||||
}
|
||||
|
||||
friend std::ostream &operator<<(std::ostream &os, const format_plus_arg &f)
|
||||
{
|
||||
char buffer[1024];
|
||||
std::string::size_type r = std::apply(snprintf, std::tuple_cat(std::make_tuple(buffer, sizeof(buffer), f.m_fmt.c_str()), f.m_vargs));
|
||||
os.write(buffer, r);
|
||||
return os;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
template <std::size_t... I>
|
||||
void copy_vargs(std::index_sequence<I...>)
|
||||
{
|
||||
((std::get<I>(m_vargs) = *std::get<I>(m_args)), ...);
|
||||
}
|
||||
|
||||
std::string m_fmt;
|
||||
args_vector_type m_args;
|
||||
vargs_vector_type m_vargs;
|
||||
};
|
||||
|
||||
/** @endcond */
|
||||
|
||||
/**
|
||||
* @brief A simplistic reimplementation of boost::format, in fact it is
|
||||
* actually a way to call the C function snprintf to format the arguments
|
||||
* in @a args into the format string @a fmt
|
||||
*
|
||||
* The string in @a fmt should thus be a C style format string.
|
||||
*
|
||||
* TODO: Move to C++23 style of printing.
|
||||
*
|
||||
* @tparam Args The types of the arguments
|
||||
* @param fmt The format string
|
||||
* @param args The arguments
|
||||
* @return An object that can be written out to a std::ostream using operator<<
|
||||
*/
|
||||
|
||||
template <typename... Args>
|
||||
constexpr auto format(std::string_view fmt, Args... args)
|
||||
{
|
||||
return format_plus_arg(fmt, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
/// A streambuf that fills out lines with spaces up until a specified width
|
||||
|
||||
@@ -67,7 +188,7 @@ class fill_out_streambuf : public std::streambuf
|
||||
|
||||
/** @cond */
|
||||
|
||||
~fill_out_streambuf() override
|
||||
~fill_out_streambuf()
|
||||
{
|
||||
m_os.rdbuf(m_upstream);
|
||||
}
|
||||
@@ -80,7 +201,8 @@ class fill_out_streambuf : public std::streambuf
|
||||
* wide as the requested width.
|
||||
*/
|
||||
|
||||
int_type overflow(int_type ic = traits_type::eof()) override
|
||||
virtual int_type
|
||||
overflow(int_type ic = traits_type::eof())
|
||||
{
|
||||
char ch = traits_type::to_char_type(ic);
|
||||
|
||||
@@ -110,10 +232,10 @@ class fill_out_streambuf : public std::streambuf
|
||||
}
|
||||
|
||||
/** Return the upstream streambuf */
|
||||
[[nodiscard]] std::streambuf *get_upstream() const { return m_upstream; }
|
||||
std::streambuf *get_upstream() const { return m_upstream; }
|
||||
|
||||
/** Return how many lines have been written */
|
||||
[[nodiscard]] int get_line_count() const { return m_line_count; }
|
||||
int get_line_count() const { return m_line_count; }
|
||||
|
||||
private:
|
||||
std::ostream &m_os;
|
||||
|
||||
@@ -26,28 +26,28 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
// IWYU pragma: begin_exports
|
||||
#include "cif++/atom_type.hpp"
|
||||
#include "cif++/category.hpp"
|
||||
#include "cif++/compound.hpp"
|
||||
#include "cif++/condition.hpp"
|
||||
#include "cif++/cql.hpp"
|
||||
#include "cif++/datablock.hpp"
|
||||
#include "cif++/dictionary_parser.hpp"
|
||||
#include "cif++/exports.hpp"
|
||||
#include "cif++/file.hpp"
|
||||
#include "cif++/format.hpp"
|
||||
#include "cif++/gzio.hpp"
|
||||
#include "cif++/item.hpp"
|
||||
#include "cif++/iterator.hpp"
|
||||
#include "cif++/matrix.hpp"
|
||||
#include "cif++/model.hpp"
|
||||
#include "cif++/parser.hpp"
|
||||
#include "cif++/pdb.hpp"
|
||||
#include "cif++/point.hpp"
|
||||
#include "cif++/row.hpp"
|
||||
#include "cif++/symmetry.hpp"
|
||||
#include "cif++/text.hpp"
|
||||
#include "cif++/utilities.hpp"
|
||||
#include "cif++/validate.hpp"
|
||||
// IWYU pragma: end_exports
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* @file forward_decl.hpp
|
||||
*
|
||||
* File containing only forward declarations
|
||||
*
|
||||
*/
|
||||
|
||||
namespace cif
|
||||
{
|
||||
|
||||
class category;
|
||||
class datablock;
|
||||
class file;
|
||||
class parser;
|
||||
|
||||
class row;
|
||||
class row_handle;
|
||||
|
||||
class item;
|
||||
struct item_handle;
|
||||
|
||||
} // namespace cif
|
||||
@@ -1,33 +1,7 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2025 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
Original code comes from libgxrio at https://github.com/mhekkel/gxrio
|
||||
This is a stripped down version.
|
||||
*/
|
||||
// Copyright Maarten L. Hekkelman, 2022
|
||||
// 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)
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -209,7 +183,7 @@ class basic_igzip_streambuf : public basic_streambuf<CharT, Traits>
|
||||
return *this;
|
||||
}
|
||||
|
||||
~basic_igzip_streambuf() override
|
||||
~basic_igzip_streambuf()
|
||||
{
|
||||
close();
|
||||
}
|
||||
@@ -245,8 +219,8 @@ class basic_igzip_streambuf : public basic_streambuf<CharT, Traits>
|
||||
|
||||
close();
|
||||
|
||||
m_zstream = std::make_unique<z_stream_s>();
|
||||
m_gzheader = std::make_unique<gz_header_s>();
|
||||
m_zstream.reset(new z_stream_s);
|
||||
m_gzheader.reset(new gz_header_s);
|
||||
|
||||
auto &zstream = *m_zstream.get();
|
||||
zstream = z_stream_s{};
|
||||
@@ -396,7 +370,7 @@ class basic_ogzip_streambuf : public basic_streambuf<CharT, Traits>
|
||||
return *this;
|
||||
}
|
||||
|
||||
~basic_ogzip_streambuf() override
|
||||
~basic_ogzip_streambuf()
|
||||
{
|
||||
close();
|
||||
}
|
||||
@@ -431,8 +405,8 @@ class basic_ogzip_streambuf : public basic_streambuf<CharT, Traits>
|
||||
|
||||
close();
|
||||
|
||||
m_zstream = std::make_unique<z_stream_s>();
|
||||
m_gzheader = std::make_unique<gz_header_s>();
|
||||
m_zstream.reset(new z_stream_s);
|
||||
m_gzheader.reset(new gz_header_s);
|
||||
|
||||
auto &zstream = *m_zstream.get();
|
||||
zstream = z_stream_s{};
|
||||
@@ -658,7 +632,7 @@ class basic_ifstream : public basic_istream<CharT, Traits>
|
||||
/// \brief Default constructor, does not open a file since none is specified
|
||||
basic_ifstream() = default;
|
||||
|
||||
~basic_ifstream() override
|
||||
~basic_ifstream()
|
||||
{
|
||||
close();
|
||||
}
|
||||
@@ -774,7 +748,7 @@ class basic_ifstream : public basic_istream<CharT, Traits>
|
||||
/// \brief Return true if the file is open
|
||||
/// \return m_filebuf.is_open()
|
||||
|
||||
[[nodiscard]] bool is_open() const
|
||||
bool is_open() const
|
||||
{
|
||||
return m_filebuf.is_open();
|
||||
}
|
||||
@@ -922,7 +896,7 @@ class basic_ofstream : public basic_ostream<CharT, Traits>
|
||||
|
||||
basic_ofstream() = default;
|
||||
|
||||
~basic_ofstream() override
|
||||
~basic_ofstream()
|
||||
{
|
||||
close();
|
||||
}
|
||||
@@ -1054,7 +1028,7 @@ class basic_ofstream : public basic_ostream<CharT, Traits>
|
||||
/// \brief Return true if the file is open
|
||||
/// \return m_filebuf.is_open()
|
||||
|
||||
[[nodiscard]] bool is_open() const
|
||||
bool is_open() const
|
||||
{
|
||||
return m_filebuf.is_open();
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -26,13 +26,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cif++/condition.hpp"
|
||||
#include "cif++/row.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <numeric>
|
||||
#include <type_traits>
|
||||
|
||||
/**
|
||||
* @file iterator.hpp
|
||||
@@ -48,8 +44,6 @@
|
||||
namespace cif
|
||||
{
|
||||
|
||||
class category;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
@@ -61,13 +55,13 @@ class category;
|
||||
* @tparam Category The category for this iterator
|
||||
* @tparam Ts The types this iterator can be dereferenced to
|
||||
*/
|
||||
template <bool Const, typename... Ts>
|
||||
class iterator_impl_base
|
||||
template <typename Category, typename... Ts>
|
||||
class iterator_impl
|
||||
{
|
||||
public:
|
||||
/** @cond */
|
||||
template <bool, typename...>
|
||||
friend class iterator_impl_base;
|
||||
template <typename, typename...>
|
||||
friend class iterator_impl;
|
||||
|
||||
friend class category;
|
||||
/** @endcond */
|
||||
@@ -76,47 +70,48 @@ class iterator_impl_base
|
||||
static constexpr std::size_t N = sizeof...(Ts);
|
||||
|
||||
/** @cond */
|
||||
using category_type = std::remove_cv_t<Category>;
|
||||
using row_type = std::conditional_t<std::is_const_v<Category>, const row, row>;
|
||||
|
||||
using tuple_type = std::tuple<Ts...>;
|
||||
|
||||
using row_handle_type = std::conditional_t<Const, const_row_handle, row_handle>;
|
||||
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using value_type = std::conditional_t<Const, const tuple_type, tuple_type>;
|
||||
using value_type = tuple_type;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = value_type *;
|
||||
using reference = value_type &;
|
||||
|
||||
iterator_impl_base() = default;
|
||||
iterator_impl() = default;
|
||||
|
||||
iterator_impl_base(const iterator_impl_base &rhs) = default;
|
||||
iterator_impl_base(iterator_impl_base &&rhs) = default;
|
||||
iterator_impl(const iterator_impl &rhs) = default;
|
||||
iterator_impl(iterator_impl &&rhs) = default;
|
||||
|
||||
template <bool C, typename... T2s>
|
||||
iterator_impl_base(const iterator_impl_base<C, T2s...> &rhs)
|
||||
: m_current(rhs.m_current)
|
||||
template <typename C2, typename... T2s>
|
||||
iterator_impl(const iterator_impl<C2, T2s...> &rhs)
|
||||
: m_current(const_cast<row_handle&>(rhs.m_current))
|
||||
, m_value(rhs.m_value)
|
||||
, m_item_ix(rhs.m_item_ix)
|
||||
{
|
||||
}
|
||||
|
||||
template <bool C>
|
||||
iterator_impl_base(iterator_impl_base<C, Ts...> &rhs)
|
||||
: m_current(rhs.m_current)
|
||||
template <typename IRowType>
|
||||
iterator_impl(iterator_impl<IRowType, Ts...> &rhs)
|
||||
: m_current(const_cast<row_handle&>(rhs.m_current))
|
||||
, m_value(rhs.m_value)
|
||||
, m_item_ix(rhs.m_item_ix)
|
||||
{
|
||||
m_value = get(std::make_index_sequence<N>());
|
||||
}
|
||||
|
||||
template <bool C>
|
||||
iterator_impl_base(const iterator_impl_base<C> &rhs, const std::array<uint16_t, N> &cix)
|
||||
: m_current(rhs.m_current)
|
||||
template <typename IRowType>
|
||||
iterator_impl(const iterator_impl<IRowType> &rhs, const std::array<uint16_t, N> &cix)
|
||||
: m_current(const_cast<row_handle&>(rhs.m_current))
|
||||
, m_item_ix(cix)
|
||||
{
|
||||
m_value = get(std::make_index_sequence<N>());
|
||||
}
|
||||
|
||||
iterator_impl_base &operator=(iterator_impl_base i)
|
||||
iterator_impl &operator=(iterator_impl i)
|
||||
{
|
||||
std::swap(m_current, i.m_current);
|
||||
std::swap(m_item_ix, i.m_item_ix);
|
||||
@@ -124,39 +119,29 @@ class iterator_impl_base
|
||||
return *this;
|
||||
}
|
||||
|
||||
virtual ~iterator_impl_base() = default;
|
||||
virtual ~iterator_impl() = default;
|
||||
|
||||
auto operator*()
|
||||
reference operator*()
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
auto operator*() const
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
auto operator->()
|
||||
pointer operator->()
|
||||
{
|
||||
return &m_value;
|
||||
}
|
||||
|
||||
auto operator->() const
|
||||
{
|
||||
return &m_value;
|
||||
}
|
||||
|
||||
operator const_row_handle() const
|
||||
operator const row_handle() const
|
||||
{
|
||||
return m_current;
|
||||
}
|
||||
|
||||
operator row_handle_type()
|
||||
operator row_handle()
|
||||
{
|
||||
return m_current;
|
||||
}
|
||||
|
||||
iterator_impl_base &operator++()
|
||||
iterator_impl &operator++()
|
||||
{
|
||||
if (m_current)
|
||||
m_current.m_row = m_current.m_row->m_next;
|
||||
@@ -166,24 +151,24 @@ class iterator_impl_base
|
||||
return *this;
|
||||
}
|
||||
|
||||
iterator_impl_base operator++(int)
|
||||
iterator_impl operator++(int)
|
||||
{
|
||||
iterator_impl_base result(*this);
|
||||
iterator_impl result(*this);
|
||||
this->operator++();
|
||||
return result;
|
||||
}
|
||||
|
||||
bool operator==(const iterator_impl_base &rhs) const { return m_current == rhs.m_current; }
|
||||
bool operator!=(const iterator_impl_base &rhs) const { return m_current != rhs.m_current; }
|
||||
bool operator==(const iterator_impl &rhs) const { return m_current == rhs.m_current; }
|
||||
bool operator!=(const iterator_impl &rhs) const { return m_current != rhs.m_current; }
|
||||
|
||||
template <bool C, typename... ITs>
|
||||
bool operator==(const iterator_impl_base<C, ITs...> &rhs) const
|
||||
template <typename IRowType, typename... ITs>
|
||||
bool operator==(const iterator_impl<IRowType, ITs...> &rhs) const
|
||||
{
|
||||
return m_current == rhs.m_current;
|
||||
}
|
||||
|
||||
template <bool C, typename... ITs>
|
||||
bool operator!=(const iterator_impl_base<C, ITs...> &rhs) const
|
||||
template <typename IRowType, typename... ITs>
|
||||
bool operator!=(const iterator_impl<IRowType, ITs...> &rhs) const
|
||||
{
|
||||
return m_current != rhs.m_current;
|
||||
}
|
||||
@@ -192,13 +177,13 @@ class iterator_impl_base
|
||||
|
||||
private:
|
||||
template <std::size_t... Is>
|
||||
[[nodiscard]] tuple_type get(std::index_sequence<Is...>) const
|
||||
tuple_type get(std::index_sequence<Is...>) const
|
||||
{
|
||||
return m_current ? tuple_type{ m_current[m_item_ix[Is]].template get<Ts>()... } : tuple_type{};
|
||||
return m_current ? tuple_type{ m_current[m_item_ix[Is]].template as<Ts>()... } : tuple_type{};
|
||||
}
|
||||
|
||||
row_handle_type m_current;
|
||||
tuple_type m_value;
|
||||
row_handle m_current;
|
||||
value_type m_value;
|
||||
std::array<uint16_t, N> m_item_ix;
|
||||
};
|
||||
|
||||
@@ -208,94 +193,76 @@ class iterator_impl_base
|
||||
*
|
||||
* @tparam Category The category for this iterator
|
||||
*/
|
||||
template <bool Const>
|
||||
class iterator_impl_base<Const>
|
||||
template <typename Category>
|
||||
class iterator_impl<Category>
|
||||
{
|
||||
public:
|
||||
/** @cond */
|
||||
|
||||
template <bool, typename...>
|
||||
friend class iterator_impl_base;
|
||||
template <typename, typename...>
|
||||
friend class iterator_impl;
|
||||
|
||||
friend class category;
|
||||
|
||||
using category_type = std::conditional_t<Const, const category, category>;
|
||||
using row_type = std::conditional_t<Const, const row, row>;
|
||||
using row_handle_type = std::conditional_t<Const, const_row_handle, row_handle>;
|
||||
using category_type = std::remove_cv_t<Category>;
|
||||
using row_type = std::conditional_t<std::is_const_v<Category>, const row, row>;
|
||||
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
|
||||
using value_type = std::conditional_t<Const, const_row_handle, row_handle>;
|
||||
using value_type = row_handle;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = value_type *;
|
||||
using reference = value_type &;
|
||||
|
||||
iterator_impl_base() = default;
|
||||
iterator_impl() = default;
|
||||
|
||||
iterator_impl_base(const iterator_impl_base &rhs) = default;
|
||||
iterator_impl_base(iterator_impl_base &&rhs) = default;
|
||||
iterator_impl(const iterator_impl &rhs) = default;
|
||||
iterator_impl(iterator_impl &&rhs) = default;
|
||||
|
||||
template <bool C>
|
||||
iterator_impl_base(const iterator_impl_base<C> &rhs)
|
||||
: m_current(rhs.m_current)
|
||||
template <typename C2>
|
||||
iterator_impl(const iterator_impl<C2> &rhs)
|
||||
: m_current(const_cast<row_handle &>(rhs.m_current))
|
||||
{
|
||||
}
|
||||
|
||||
iterator_impl_base(const category_type &cat, const row_type *current)
|
||||
: m_current(const_cast<category &>(cat), const_cast<row_type &>(*current))
|
||||
iterator_impl(Category &cat, row *current)
|
||||
: m_current(cat, *current)
|
||||
{
|
||||
}
|
||||
|
||||
template <bool C>
|
||||
iterator_impl_base(const iterator_impl_base<C> &rhs, const std::array<uint16_t, 0> &)
|
||||
: m_current(rhs.m_current)
|
||||
template <typename IRowType>
|
||||
iterator_impl(const iterator_impl<IRowType> &rhs, const std::array<uint16_t, 0> &)
|
||||
: m_current(const_cast<row_handle &>(rhs.m_current))
|
||||
{
|
||||
}
|
||||
|
||||
iterator_impl_base &operator=(iterator_impl_base i)
|
||||
iterator_impl &operator=(iterator_impl i)
|
||||
{
|
||||
std::swap(m_current, i.m_current);
|
||||
return *this;
|
||||
}
|
||||
|
||||
virtual ~iterator_impl_base() = default;
|
||||
virtual ~iterator_impl() = default;
|
||||
|
||||
auto operator*()
|
||||
reference operator*()
|
||||
{
|
||||
return m_current;
|
||||
}
|
||||
|
||||
auto operator*() const
|
||||
{
|
||||
return m_current;
|
||||
}
|
||||
|
||||
auto operator->()
|
||||
pointer operator->()
|
||||
{
|
||||
return &m_current;
|
||||
}
|
||||
|
||||
auto operator->() const
|
||||
{
|
||||
return &m_current;
|
||||
}
|
||||
|
||||
operator const_row_handle() const
|
||||
operator const row_handle() const
|
||||
{
|
||||
return m_current;
|
||||
}
|
||||
|
||||
operator row_handle_type()
|
||||
operator row_handle()
|
||||
{
|
||||
return m_current;
|
||||
}
|
||||
|
||||
[[nodiscard]] int64_t row_id() const
|
||||
{
|
||||
return reinterpret_cast<int64_t>(m_current.m_row);
|
||||
}
|
||||
|
||||
iterator_impl_base &operator++()
|
||||
iterator_impl &operator++()
|
||||
{
|
||||
if (m_current)
|
||||
m_current.m_row = m_current.m_row->m_next;
|
||||
@@ -303,24 +270,24 @@ class iterator_impl_base<Const>
|
||||
return *this;
|
||||
}
|
||||
|
||||
iterator_impl_base operator++(int)
|
||||
iterator_impl operator++(int)
|
||||
{
|
||||
iterator_impl_base result(*this);
|
||||
iterator_impl result(*this);
|
||||
this->operator++();
|
||||
return result;
|
||||
}
|
||||
|
||||
bool operator==(const iterator_impl_base &rhs) const { return m_current == rhs.m_current; }
|
||||
bool operator!=(const iterator_impl_base &rhs) const { return m_current != rhs.m_current; }
|
||||
bool operator==(const iterator_impl &rhs) const { return m_current == rhs.m_current; }
|
||||
bool operator!=(const iterator_impl &rhs) const { return m_current != rhs.m_current; }
|
||||
|
||||
template <bool C, typename... ITs>
|
||||
bool operator==(const iterator_impl_base<C, ITs...> &rhs) const
|
||||
template <typename IRowType, typename... ITs>
|
||||
bool operator==(const iterator_impl<IRowType, ITs...> &rhs) const
|
||||
{
|
||||
return m_current == rhs.m_current;
|
||||
}
|
||||
|
||||
template <bool C, typename... ITs>
|
||||
bool operator!=(const iterator_impl_base<C, ITs...> &rhs) const
|
||||
template <typename IRowType, typename... ITs>
|
||||
bool operator!=(const iterator_impl<IRowType, ITs...> &rhs) const
|
||||
{
|
||||
return m_current != rhs.m_current;
|
||||
}
|
||||
@@ -328,7 +295,7 @@ class iterator_impl_base<Const>
|
||||
/** @endcond */
|
||||
|
||||
private:
|
||||
row_handle_type m_current;
|
||||
row_handle m_current;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -339,18 +306,18 @@ class iterator_impl_base<Const>
|
||||
* @tparam T The type this iterator can be dereferenced to
|
||||
*/
|
||||
|
||||
template <bool Const, typename T>
|
||||
class iterator_impl_base<Const, T>
|
||||
template <typename Category, typename T>
|
||||
class iterator_impl<Category, T>
|
||||
{
|
||||
public:
|
||||
/** @cond */
|
||||
template <bool, typename...>
|
||||
friend class iterator_impl_base;
|
||||
template <typename, typename...>
|
||||
friend class iterator_impl;
|
||||
|
||||
friend class category;
|
||||
|
||||
using category_type = std::conditional_t<Const, const category, category>;
|
||||
using row_handle_type = std::conditional_t<Const, const_row_handle, row_handle>;
|
||||
using category_type = std::remove_cv_t<Category>;
|
||||
using row_type = std::conditional_t<std::is_const_v<Category>, const row, row>;
|
||||
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using value_type = T;
|
||||
@@ -358,37 +325,37 @@ class iterator_impl_base<Const, T>
|
||||
using pointer = value_type *;
|
||||
using reference = value_type &;
|
||||
|
||||
iterator_impl_base() = default;
|
||||
iterator_impl() = default;
|
||||
|
||||
iterator_impl_base(const iterator_impl_base &rhs) = default;
|
||||
iterator_impl_base(iterator_impl_base &&rhs) = default;
|
||||
iterator_impl(const iterator_impl &rhs) = default;
|
||||
iterator_impl(iterator_impl &&rhs) = default;
|
||||
|
||||
template <bool C, typename T2>
|
||||
iterator_impl_base(const iterator_impl_base<C, T2> &rhs)
|
||||
template <typename C2, typename T2>
|
||||
iterator_impl(const iterator_impl<C2, T2> &rhs)
|
||||
: m_current(rhs.m_current)
|
||||
, m_value(rhs.m_value)
|
||||
, m_item_ix(rhs.m_item_ix)
|
||||
{
|
||||
}
|
||||
|
||||
template <bool C>
|
||||
iterator_impl_base(iterator_impl_base<C, T> &rhs)
|
||||
: m_current(rhs.m_current)
|
||||
template <typename IRowType>
|
||||
iterator_impl(iterator_impl<IRowType, T> &rhs)
|
||||
: m_current(const_cast<row_handle&>(rhs.m_current))
|
||||
, m_value(rhs.m_value)
|
||||
, m_item_ix(rhs.m_item_ix)
|
||||
{
|
||||
m_value = get();
|
||||
}
|
||||
|
||||
template <bool C>
|
||||
iterator_impl_base(const iterator_impl_base<C> &rhs, const std::array<uint16_t, 1> &cix)
|
||||
: m_current(rhs.m_current)
|
||||
template <typename IRowType>
|
||||
iterator_impl(const iterator_impl<IRowType> &rhs, const std::array<uint16_t, 1> &cix)
|
||||
: m_current(const_cast<row_handle&>(rhs.m_current))
|
||||
, m_item_ix(cix[0])
|
||||
{
|
||||
m_value = get();
|
||||
}
|
||||
|
||||
iterator_impl_base &operator=(iterator_impl_base i)
|
||||
iterator_impl &operator=(iterator_impl i)
|
||||
{
|
||||
std::swap(m_current, i.m_current);
|
||||
std::swap(m_item_ix, i.m_item_ix);
|
||||
@@ -396,39 +363,29 @@ class iterator_impl_base<Const, T>
|
||||
return *this;
|
||||
}
|
||||
|
||||
virtual ~iterator_impl_base() = default;
|
||||
virtual ~iterator_impl() = default;
|
||||
|
||||
auto operator*()
|
||||
reference operator*()
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
auto operator*() const
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
auto operator->()
|
||||
pointer operator->()
|
||||
{
|
||||
return &m_value;
|
||||
}
|
||||
|
||||
auto operator->() const
|
||||
{
|
||||
return &m_value;
|
||||
}
|
||||
|
||||
operator const_row_handle() const
|
||||
operator const row_handle() const
|
||||
{
|
||||
return m_current;
|
||||
}
|
||||
|
||||
operator row_handle_type()
|
||||
operator row_handle()
|
||||
{
|
||||
return m_current;
|
||||
}
|
||||
|
||||
iterator_impl_base &operator++()
|
||||
iterator_impl &operator++()
|
||||
{
|
||||
if (m_current)
|
||||
m_current.m_row = m_current.m_row->m_next;
|
||||
@@ -438,24 +395,24 @@ class iterator_impl_base<Const, T>
|
||||
return *this;
|
||||
}
|
||||
|
||||
iterator_impl_base operator++(int)
|
||||
iterator_impl operator++(int)
|
||||
{
|
||||
iterator_impl_base result(*this);
|
||||
iterator_impl result(*this);
|
||||
this->operator++();
|
||||
return result;
|
||||
}
|
||||
|
||||
bool operator==(const iterator_impl_base &rhs) const { return m_current == rhs.m_current; }
|
||||
bool operator!=(const iterator_impl_base &rhs) const { return m_current != rhs.m_current; }
|
||||
bool operator==(const iterator_impl &rhs) const { return m_current == rhs.m_current; }
|
||||
bool operator!=(const iterator_impl &rhs) const { return m_current != rhs.m_current; }
|
||||
|
||||
template <bool C, typename... ITs>
|
||||
bool operator==(const iterator_impl_base<C, ITs...> &rhs) const
|
||||
template <typename IRowType, typename... ITs>
|
||||
bool operator==(const iterator_impl<IRowType, ITs...> &rhs) const
|
||||
{
|
||||
return m_current == rhs.m_current;
|
||||
}
|
||||
|
||||
template <bool C, typename... ITs>
|
||||
bool operator!=(const iterator_impl_base<C, ITs...> &rhs) const
|
||||
template <typename IRowType, typename... ITs>
|
||||
bool operator!=(const iterator_impl<IRowType, ITs...> &rhs) const
|
||||
{
|
||||
return m_current != rhs.m_current;
|
||||
}
|
||||
@@ -463,26 +420,16 @@ class iterator_impl_base<Const, T>
|
||||
/** @endcond */
|
||||
|
||||
private:
|
||||
[[nodiscard]] value_type get() const
|
||||
value_type get() const
|
||||
{
|
||||
return m_current ? m_current[m_item_ix].template get<value_type>() : value_type{};
|
||||
return m_current ? m_current[m_item_ix].template as<value_type>() : value_type{};
|
||||
}
|
||||
|
||||
row_handle_type m_current;
|
||||
row_handle m_current;
|
||||
value_type m_value;
|
||||
uint16_t m_item_ix;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/// A non-const version of iterator_impl
|
||||
template<typename ... Ts>
|
||||
using iterator_impl = iterator_impl_base<false, Ts...>;
|
||||
|
||||
/// A const version of iterator_impl
|
||||
template<typename ... Ts>
|
||||
using const_iterator_impl = iterator_impl_base<true, Ts...>;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// iterator proxy
|
||||
|
||||
@@ -498,42 +445,43 @@ using const_iterator_impl = iterator_impl_base<true, Ts...>;
|
||||
* @tparam Ts The types the iterators return. See class: iterator
|
||||
*/
|
||||
|
||||
template <bool Const, typename... Ts>
|
||||
class iterator_proxy_base
|
||||
template <typename Category, typename... Ts>
|
||||
class iterator_proxy
|
||||
{
|
||||
public:
|
||||
/** @cond */
|
||||
static constexpr const std::size_t N = sizeof...(Ts);
|
||||
|
||||
using category_type = std::conditional_t<Const, const category, category>;
|
||||
using category_type = Category;
|
||||
using row_type = std::conditional_t<std::is_const_v<category_type>, const row, row>;
|
||||
|
||||
using iterator = iterator_impl_base<Const, Ts...>;
|
||||
using row_iterator = iterator_impl_base<Const>;
|
||||
using iterator = iterator_impl<category_type, Ts...>;
|
||||
using row_iterator = iterator_impl<category_type>;
|
||||
|
||||
iterator_proxy_base(category_type &cat, row_iterator pos, char const *const items[N]);
|
||||
iterator_proxy_base(category_type &cat, row_iterator pos, std::initializer_list<char const *> items); // NOLINT(modernize-pass-by-value)
|
||||
iterator_proxy(category_type &cat, row_iterator pos, char const *const items[N]);
|
||||
iterator_proxy(category_type &cat, row_iterator pos, std::initializer_list<char const *> items);
|
||||
|
||||
iterator_proxy_base(iterator_proxy_base &&p);
|
||||
iterator_proxy_base &operator=(iterator_proxy_base &&p);
|
||||
iterator_proxy(iterator_proxy &&p);
|
||||
iterator_proxy &operator=(iterator_proxy &&p);
|
||||
|
||||
iterator_proxy_base(const iterator_proxy_base &) = delete;
|
||||
iterator_proxy_base &operator=(const iterator_proxy_base &) = delete;
|
||||
iterator_proxy(const iterator_proxy &) = delete;
|
||||
iterator_proxy &operator=(const iterator_proxy &) = delete;
|
||||
/** @endcond */
|
||||
|
||||
[[nodiscard]] iterator begin() const { return iterator(m_begin, m_item_ix); } ///< Return the iterator pointing to the first row
|
||||
[[nodiscard]] iterator end() const { return iterator(m_end, m_item_ix); } ///< Return the iterator pointing past the last row
|
||||
iterator begin() const { return iterator(m_begin, m_item_ix); } ///< Return the iterator pointing to the first row
|
||||
iterator end() const { return iterator(m_end, m_item_ix); } ///< Return the iterator pointing past the last row
|
||||
|
||||
[[nodiscard]] bool empty() const { return m_begin == m_end; } ///< Return true if the range is empty
|
||||
bool empty() const { return m_begin == m_end; } ///< Return true if the range is empty
|
||||
explicit operator bool() const { return not empty(); } ///< Easy way to detect if the range is empty
|
||||
[[nodiscard]] std::size_t size() const { return std::distance(begin(), end()); } ///< Return size of the range
|
||||
std::size_t size() const { return std::distance(begin(), end()); } ///< Return size of the range
|
||||
|
||||
// row front() { return *begin(); }
|
||||
// row back() { return *(std::prev(end())); }
|
||||
|
||||
[[nodiscard]] category_type &get_category() const { return *m_category; } ///< Return the category the iterator belong to
|
||||
category_type &category() const { return *m_category; } ///< Return the category the iterator belong to
|
||||
|
||||
/** swap */
|
||||
void swap(iterator_proxy_base &rhs)
|
||||
void swap(iterator_proxy &rhs)
|
||||
{
|
||||
std::swap(m_category, rhs.m_category);
|
||||
std::swap(m_begin, rhs.m_begin);
|
||||
@@ -541,27 +489,12 @@ class iterator_proxy_base
|
||||
std::swap(m_item_ix, rhs.m_item_ix);
|
||||
}
|
||||
|
||||
protected:
|
||||
/// @cond
|
||||
iterator_proxy_base(category_type &cat);
|
||||
/// @endcond
|
||||
|
||||
private:
|
||||
category_type *m_category;
|
||||
row_iterator m_begin, m_end;
|
||||
std::array<uint16_t, N> m_item_ix;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/// A non-const version of iterator_proxy_base
|
||||
template <typename... Ts>
|
||||
using iterator_proxy = iterator_proxy_base<false, Ts...>;
|
||||
|
||||
/// A const version of iterator_proxy_base
|
||||
template <typename... Ts>
|
||||
using const_iterator_proxy = iterator_proxy_base<true, Ts...>;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// conditional iterator proxy
|
||||
|
||||
@@ -571,54 +504,44 @@ using const_iterator_proxy = iterator_proxy_base<true, Ts...>;
|
||||
* In the case of an conditional_iterator_proxy a cif::condition is used
|
||||
* to filter out only those rows that match the condition.
|
||||
*
|
||||
* @tparam category_type The category the iterators belong to
|
||||
* @tparam CategoryType The category the iterators belong to
|
||||
* @tparam Ts The types to which the iterators can be dereferenced
|
||||
*/
|
||||
template <bool Const, typename... Ts>
|
||||
class conditional_iterator_proxy_base
|
||||
template <typename CategoryType, typename... Ts>
|
||||
class conditional_iterator_proxy
|
||||
{
|
||||
public:
|
||||
/** @cond */
|
||||
static constexpr const std::size_t N = sizeof...(Ts);
|
||||
|
||||
using category_type = std::conditional_t<Const, const category, category>;
|
||||
using base_iterator = iterator_impl_base<Const, Ts...>;
|
||||
using category_type = std::remove_cv_t<CategoryType>;
|
||||
|
||||
using base_iterator = iterator_impl<CategoryType, Ts...>;
|
||||
using value_type = typename base_iterator::value_type;
|
||||
using row_iterator = iterator_impl_base<Const>;
|
||||
using row_type = typename base_iterator::row_type;
|
||||
using row_iterator = iterator_impl<CategoryType>;
|
||||
|
||||
class conditional_iterator_impl
|
||||
{
|
||||
public:
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using value_type = conditional_iterator_proxy_base::value_type;
|
||||
using value_type = conditional_iterator_proxy::value_type;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = value_type *;
|
||||
using reference = value_type;
|
||||
|
||||
conditional_iterator_impl() = default;
|
||||
conditional_iterator_impl(category_type &cat, row_iterator pos, const condition &cond, const std::array<uint16_t, N> &cix);
|
||||
conditional_iterator_impl(CategoryType &cat, row_iterator pos, const condition &cond, const std::array<uint16_t, N> &cix);
|
||||
conditional_iterator_impl(const conditional_iterator_impl &i) = default;
|
||||
conditional_iterator_impl &operator=(const conditional_iterator_impl &i) = default;
|
||||
|
||||
virtual ~conditional_iterator_impl() = default;
|
||||
|
||||
auto operator*()
|
||||
reference operator*()
|
||||
{
|
||||
return *m_begin;
|
||||
}
|
||||
|
||||
auto operator*() const
|
||||
{
|
||||
return *m_begin;
|
||||
}
|
||||
|
||||
auto operator->()
|
||||
{
|
||||
m_current = *m_begin;
|
||||
return &m_current;
|
||||
}
|
||||
|
||||
auto operator->() const
|
||||
pointer operator->()
|
||||
{
|
||||
m_current = *m_begin;
|
||||
return &m_current;
|
||||
@@ -651,16 +574,16 @@ class conditional_iterator_proxy_base
|
||||
bool operator==(const row_iterator &rhs) const { return m_begin == rhs; }
|
||||
bool operator!=(const row_iterator &rhs) const { return m_begin != rhs; }
|
||||
|
||||
template <bool C, typename... ITs>
|
||||
bool operator==(const iterator_impl_base<C, ITs...> &rhs) const { return m_begin == rhs; }
|
||||
template <typename IRowType, typename... ITs>
|
||||
bool operator==(const iterator_impl<IRowType, ITs...> &rhs) const { return m_begin == rhs; }
|
||||
|
||||
template <bool C, typename... ITs>
|
||||
bool operator!=(const iterator_impl_base<C, ITs...> &rhs) const { return m_begin != rhs; }
|
||||
template <typename IRowType, typename... ITs>
|
||||
bool operator!=(const iterator_impl<IRowType, ITs...> &rhs) const { return m_begin != rhs; }
|
||||
|
||||
private:
|
||||
category_type *m_cat = nullptr;
|
||||
CategoryType *m_cat;
|
||||
base_iterator m_begin, m_end;
|
||||
std::remove_cv_t<value_type> m_current;
|
||||
value_type m_current;
|
||||
const condition *m_condition;
|
||||
};
|
||||
|
||||
@@ -668,42 +591,33 @@ class conditional_iterator_proxy_base
|
||||
using reference = typename iterator::reference;
|
||||
|
||||
template <typename... Ns>
|
||||
conditional_iterator_proxy_base(category_type &cat, row_iterator pos, condition &&cond, Ns... names); // NOLINT(modernize-pass-by-value)
|
||||
conditional_iterator_proxy(CategoryType &cat, row_iterator pos, condition &&cond, Ns... names);
|
||||
|
||||
conditional_iterator_proxy_base(conditional_iterator_proxy_base &&p)
|
||||
{
|
||||
swap(*this, p);
|
||||
}
|
||||
conditional_iterator_proxy(conditional_iterator_proxy &&p);
|
||||
conditional_iterator_proxy &operator=(conditional_iterator_proxy &&p);
|
||||
|
||||
conditional_iterator_proxy_base &operator=(conditional_iterator_proxy_base &&p)
|
||||
{
|
||||
swap(*this, p);
|
||||
return *this;
|
||||
}
|
||||
|
||||
conditional_iterator_proxy_base(const conditional_iterator_proxy_base &) = delete;
|
||||
conditional_iterator_proxy_base &operator=(const conditional_iterator_proxy_base &) = delete;
|
||||
conditional_iterator_proxy(const conditional_iterator_proxy &) = delete;
|
||||
conditional_iterator_proxy &operator=(const conditional_iterator_proxy &) = delete;
|
||||
|
||||
/** @endcond */
|
||||
|
||||
[[nodiscard]] iterator begin() const; ///< Return the iterator pointing to the first row
|
||||
[[nodiscard]] iterator end() const; ///< Return the iterator pointing past the last row
|
||||
iterator begin() const; ///< Return the iterator pointing to the first row
|
||||
iterator end() const; ///< Return the iterator pointing past the last row
|
||||
|
||||
[[nodiscard]] bool empty() const; ///< Return true if the range is empty
|
||||
bool empty() const; ///< Return true if the range is empty
|
||||
explicit operator bool() const { return not empty(); } ///< Easy way to detect if the range is empty
|
||||
[[nodiscard]] std::size_t size() const { return std::distance(begin(), end()); } ///< Return size of the range
|
||||
std::size_t size() const { return std::distance(begin(), end()); } ///< Return size of the range
|
||||
|
||||
auto front() { return *begin(); } ///< Return reference to the first row
|
||||
row_handle front() { return *begin(); } ///< Return reference to the first row
|
||||
// row_handle back() { return *begin(); }
|
||||
|
||||
[[nodiscard]] category_type &get_category() const { return *m_cat; } ///< Category the iterators belong to
|
||||
CategoryType &category() const { return *m_cat; } ///< Category the iterators belong to
|
||||
|
||||
/** swap */
|
||||
template <bool C2, typename ... T2s>
|
||||
friend void swap(conditional_iterator_proxy_base<C2, T2s...> &lhs, conditional_iterator_proxy_base<C2, T2s...> &rhs);
|
||||
void swap(conditional_iterator_proxy &rhs);
|
||||
|
||||
private:
|
||||
category_type *m_cat;
|
||||
CategoryType *m_cat;
|
||||
condition m_condition;
|
||||
row_iterator mCBegin, mCEnd;
|
||||
std::array<uint16_t, N> mCix;
|
||||
@@ -711,19 +625,9 @@ class conditional_iterator_proxy_base
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/// A non-const version of conditional_iterator_proxy_base
|
||||
template <typename... Ts>
|
||||
using conditional_iterator_proxy = conditional_iterator_proxy_base<false, Ts...>;
|
||||
|
||||
/// A const version of conditional_iterator_proxy_base
|
||||
template <typename... Ts>
|
||||
using const_conditional_iterator_proxy = conditional_iterator_proxy_base<true, Ts...>;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/** @cond */
|
||||
template <bool Const, typename... Ts>
|
||||
iterator_proxy_base<Const, Ts...>::iterator_proxy_base(category_type &cat, row_iterator pos, char const *const items[N])
|
||||
template <typename Category, typename... Ts>
|
||||
iterator_proxy<Category, Ts...>::iterator_proxy(Category &cat, row_iterator pos, char const *const items[N])
|
||||
: m_category(&cat)
|
||||
, m_begin(pos)
|
||||
, m_end(cat.end())
|
||||
@@ -732,8 +636,8 @@ iterator_proxy_base<Const, Ts...>::iterator_proxy_base(category_type &cat, row_i
|
||||
m_item_ix[i] = m_category->get_item_ix(items[i]);
|
||||
}
|
||||
|
||||
template <bool Const, typename... Ts>
|
||||
iterator_proxy_base<Const, Ts...>::iterator_proxy_base(category_type &cat, row_iterator pos, std::initializer_list<char const *> items)
|
||||
template <typename Category, typename... Ts>
|
||||
iterator_proxy<Category, Ts...>::iterator_proxy(Category &cat, row_iterator pos, std::initializer_list<char const *> items)
|
||||
: m_category(&cat)
|
||||
, m_begin(pos)
|
||||
, m_end(cat.end())
|
||||
@@ -745,20 +649,11 @@ iterator_proxy_base<Const, Ts...>::iterator_proxy_base(category_type &cat, row_i
|
||||
m_item_ix[i++] = m_category->get_item_ix(item);
|
||||
}
|
||||
|
||||
template <bool Const, typename... Ts>
|
||||
iterator_proxy_base<Const, Ts...>::iterator_proxy_base(category_type &cat)
|
||||
: m_category(&cat)
|
||||
, m_begin(cat.begin())
|
||||
, m_end(cat.end())
|
||||
{
|
||||
std::iota(m_item_ix.begin(), m_item_ix.end(), 0);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
template <bool Const, typename... Ts>
|
||||
conditional_iterator_proxy_base<Const, Ts...>::conditional_iterator_impl::conditional_iterator_impl(
|
||||
category_type &cat, row_iterator pos, const condition &cond, const std::array<uint16_t, N> &cix)
|
||||
template <typename Category, typename... Ts>
|
||||
conditional_iterator_proxy<Category, Ts...>::conditional_iterator_impl::conditional_iterator_impl(
|
||||
Category &cat, row_iterator pos, const condition &cond, const std::array<uint16_t, N> &cix)
|
||||
: m_cat(&cat)
|
||||
, m_begin(pos, cix)
|
||||
, m_end(cat.end(), cix)
|
||||
@@ -766,13 +661,23 @@ conditional_iterator_proxy_base<Const, Ts...>::conditional_iterator_impl::condit
|
||||
{
|
||||
if (m_condition == nullptr or m_condition->empty())
|
||||
m_begin = m_end;
|
||||
else
|
||||
m_current = *m_begin;
|
||||
}
|
||||
|
||||
template <bool Const, typename... Ts>
|
||||
template <typename Category, typename... Ts>
|
||||
conditional_iterator_proxy<Category, Ts...>::conditional_iterator_proxy(conditional_iterator_proxy &&p)
|
||||
: m_cat(nullptr)
|
||||
, mCBegin(p.mCBegin)
|
||||
, mCEnd(p.mCEnd)
|
||||
, mCix(p.mCix)
|
||||
{
|
||||
std::swap(m_cat, p.m_cat);
|
||||
std::swap(mCix, p.mCix);
|
||||
m_condition.swap(p.m_condition);
|
||||
}
|
||||
|
||||
template <typename Category, typename... Ts>
|
||||
template <typename... Ns>
|
||||
conditional_iterator_proxy_base<Const, Ts...>::conditional_iterator_proxy_base(category_type &cat, row_iterator pos, condition &&cond, Ns... names)
|
||||
conditional_iterator_proxy<Category, Ts...>::conditional_iterator_proxy(Category &cat, row_iterator pos, condition &&cond, Ns... names)
|
||||
: m_cat(&cat)
|
||||
, m_condition(std::move(cond))
|
||||
, mCBegin(pos)
|
||||
@@ -780,8 +685,10 @@ conditional_iterator_proxy_base<Const, Ts...>::conditional_iterator_proxy_base(c
|
||||
{
|
||||
static_assert(sizeof...(Ts) == sizeof...(Ns), "Number of item names should be equal to number of requested value types");
|
||||
|
||||
if (m_condition and m_condition.prepare(cat))
|
||||
if (m_condition)
|
||||
{
|
||||
m_condition.prepare(cat);
|
||||
|
||||
while (mCBegin != mCEnd and not m_condition(*mCBegin))
|
||||
++mCBegin;
|
||||
}
|
||||
@@ -792,39 +699,41 @@ conditional_iterator_proxy_base<Const, Ts...>::conditional_iterator_proxy_base(c
|
||||
((mCix[i++] = m_cat->get_item_ix(names)), ...);
|
||||
}
|
||||
|
||||
template <bool Const, typename... Ts>
|
||||
auto conditional_iterator_proxy_base<Const, Ts...>::begin() const -> iterator
|
||||
template <typename Category, typename... Ts>
|
||||
conditional_iterator_proxy<Category, Ts...> &conditional_iterator_proxy<Category, Ts...>::operator=(conditional_iterator_proxy &&p)
|
||||
{
|
||||
return iterator{ *m_cat, mCBegin, m_condition, mCix };
|
||||
swap(p);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <bool Const, typename... Ts>
|
||||
auto conditional_iterator_proxy_base<Const, Ts...>::end() const -> iterator
|
||||
template <typename Category, typename... Ts>
|
||||
typename conditional_iterator_proxy<Category, Ts...>::iterator conditional_iterator_proxy<Category, Ts...>::begin() const
|
||||
{
|
||||
return iterator{ *m_cat, mCEnd, m_condition, mCix };
|
||||
return iterator(*m_cat, mCBegin, m_condition, mCix);
|
||||
}
|
||||
|
||||
template <bool Const, typename... Ts>
|
||||
bool conditional_iterator_proxy_base<Const, Ts...>::empty() const
|
||||
template <typename Category, typename... Ts>
|
||||
typename conditional_iterator_proxy<Category, Ts...>::iterator conditional_iterator_proxy<Category, Ts...>::end() const
|
||||
{
|
||||
return iterator(*m_cat, mCEnd, m_condition, mCix);
|
||||
}
|
||||
|
||||
template <typename Category, typename... Ts>
|
||||
bool conditional_iterator_proxy<Category, Ts...>::empty() const
|
||||
{
|
||||
return mCBegin == mCEnd;
|
||||
}
|
||||
|
||||
template <bool Const, typename... Ts>
|
||||
void swap(conditional_iterator_proxy_base<Const, Ts...> &lhs, conditional_iterator_proxy_base<Const, Ts...> &rhs)
|
||||
template <typename Category, typename... Ts>
|
||||
void conditional_iterator_proxy<Category, Ts...>::swap(conditional_iterator_proxy &rhs)
|
||||
{
|
||||
std::swap(lhs.m_cat, rhs.m_cat);
|
||||
std::swap(lhs.m_condition, rhs.m_condition);
|
||||
std::swap(lhs.mCBegin, rhs.mCBegin);
|
||||
std::swap(lhs.mCEnd, rhs.mCEnd);
|
||||
std::swap(lhs.mCix, rhs.mCix);
|
||||
std::swap(m_cat, rhs.m_cat);
|
||||
m_condition.swap(rhs.m_condition);
|
||||
std::swap(mCBegin, rhs.mCBegin);
|
||||
std::swap(mCEnd, rhs.mCEnd);
|
||||
std::swap(mCix, rhs.mCix);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
// template <bool Const, typename... Ts>
|
||||
|
||||
|
||||
/** @endcond */
|
||||
|
||||
} // namespace cif
|
||||
} // namespace cif
|
||||
@@ -29,17 +29,19 @@
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <ostream>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* @file matrix.hpp
|
||||
*
|
||||
*
|
||||
* Some basic matrix operations and classes to hold matrices.
|
||||
*
|
||||
*
|
||||
* We're using expression templates for optimal performance.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
namespace cif
|
||||
@@ -50,26 +52,26 @@ namespace cif
|
||||
/**
|
||||
* @brief Base for the matrix expression templates
|
||||
* This all uses the Curiously recurring template pattern
|
||||
*
|
||||
*
|
||||
* @tparam M The type of the derived class
|
||||
*/
|
||||
template <typename M>
|
||||
class matrix_expression // NOLINT(bugprone-crtp-constructor-accessibility)
|
||||
class matrix_expression
|
||||
{
|
||||
public:
|
||||
[[nodiscard]] constexpr std::size_t dim_m() const { return static_cast<const M &>(*this).dim_m(); } ///< Return the size (dimension) in direction m
|
||||
[[nodiscard]] constexpr std::size_t dim_n() const { return static_cast<const M &>(*this).dim_n(); } ///< Return the size (dimension) in direction n
|
||||
constexpr std::size_t dim_m() const { return static_cast<const M &>(*this).dim_m(); } ///< Return the size (dimension) in direction m
|
||||
constexpr std::size_t dim_n() const { return static_cast<const M &>(*this).dim_n(); } ///< Return the size (dimension) in direction n
|
||||
|
||||
[[nodiscard]] constexpr bool empty() const { return dim_m() == 0 or dim_n() == 0; } ///< Convenient way to test for empty matrices
|
||||
constexpr bool empty() const { return dim_m() == 0 or dim_n() == 0; } ///< Convenient way to test for empty matrices
|
||||
|
||||
/** Return a reference to element [ @a i, @a j ] */
|
||||
[[nodiscard]] constexpr auto &operator()(std::size_t i, std::size_t j)
|
||||
constexpr auto &operator()(std::size_t i, std::size_t j)
|
||||
{
|
||||
return static_cast<M &>(*this).operator()(i, j);
|
||||
}
|
||||
|
||||
/** Return the value of element [ @a i, @a j ] */
|
||||
[[nodiscard]] constexpr auto operator()(std::size_t i, std::size_t j) const
|
||||
constexpr auto operator()(std::size_t i, std::size_t j) const
|
||||
{
|
||||
return static_cast<const M &>(*this).operator()(i, j);
|
||||
}
|
||||
@@ -122,33 +124,15 @@ class matrix_expression // NOLINT(bugprone-crtp-constructor-accessibility)
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
/// compare two matrices
|
||||
template <typename M2>
|
||||
constexpr bool operator==(const matrix_expression<M2> &m) const
|
||||
{
|
||||
bool same = false;
|
||||
if (dim_m() == m.dim_m() and dim_n() == m.dim_n())
|
||||
{
|
||||
same = true;
|
||||
for (std::size_t i = 0; same and i < m.dim_m(); ++i)
|
||||
{
|
||||
for (std::size_t j = 0; same and j < m.dim_n(); ++j)
|
||||
same = operator()(i, j) == m(i, j);
|
||||
}
|
||||
}
|
||||
|
||||
return same;
|
||||
}
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Storage class implementation of matrix_expression.
|
||||
*
|
||||
*
|
||||
* @tparam F The type of the stored values
|
||||
*
|
||||
*
|
||||
* matrix is m x n, addressing i,j is 0 <= i < m and 0 <= j < n
|
||||
* element m i,j is mapped to [i * n + j] and thus storage is row major
|
||||
*/
|
||||
@@ -162,7 +146,7 @@ class matrix : public matrix_expression<matrix<F>>
|
||||
|
||||
/**
|
||||
* @brief Copy construct a new matrix object using @a m
|
||||
*
|
||||
*
|
||||
* @tparam M2 Type of @a m
|
||||
* @param m The matrix expression to copy values from
|
||||
*/
|
||||
@@ -182,7 +166,7 @@ class matrix : public matrix_expression<matrix<F>>
|
||||
/**
|
||||
* @brief Construct a new matrix object with dimension @a m and @a n
|
||||
* setting the values to @a v
|
||||
*
|
||||
*
|
||||
* @param m Requested dimension M
|
||||
* @param n Requested dimension N
|
||||
* @param v Value to store in each element
|
||||
@@ -203,11 +187,11 @@ class matrix : public matrix_expression<matrix<F>>
|
||||
matrix &operator=(const matrix &m) = default;
|
||||
/** @endcond */
|
||||
|
||||
[[nodiscard]] constexpr std::size_t dim_m() const { return m_m; } ///< Return dimension m
|
||||
[[nodiscard]] constexpr std::size_t dim_n() const { return m_n; } ///< Return dimension n
|
||||
constexpr std::size_t dim_m() const { return m_m; } ///< Return dimension m
|
||||
constexpr std::size_t dim_n() const { return m_n; } ///< Return dimension n
|
||||
|
||||
/** Return the value of element [ @a i, @a j ] */
|
||||
[[nodiscard]] constexpr value_type operator()(std::size_t i, std::size_t j) const
|
||||
constexpr value_type operator()(std::size_t i, std::size_t j) const
|
||||
{
|
||||
assert(i < m_m);
|
||||
assert(j < m_n);
|
||||
@@ -215,7 +199,7 @@ class matrix : public matrix_expression<matrix<F>>
|
||||
}
|
||||
|
||||
/** Return a reference to element [ @a i, @a j ] */
|
||||
[[nodiscard]] constexpr value_type &operator()(std::size_t i, std::size_t j)
|
||||
constexpr value_type &operator()(std::size_t i, std::size_t j)
|
||||
{
|
||||
assert(i < m_m);
|
||||
assert(j < m_n);
|
||||
@@ -233,9 +217,9 @@ class matrix : public matrix_expression<matrix<F>>
|
||||
/**
|
||||
* @brief Storage class implementation of matrix_expression
|
||||
* with compile time fixed size.
|
||||
*
|
||||
*
|
||||
* @tparam F The type of the stored values
|
||||
*
|
||||
*
|
||||
* matrix is m x n, addressing i,j is 0 <= i < m and 0 <= j < n
|
||||
* element m i,j is mapped to [i * n + j] and thus storage is row major
|
||||
*/
|
||||
@@ -282,18 +266,18 @@ class matrix_fixed : public matrix_expression<matrix_fixed<F, M, N>>
|
||||
/** @endcond */
|
||||
|
||||
/** Store the values in @a a in the matrix */
|
||||
template <std::size_t... Ixs>
|
||||
matrix_fixed &fill(const F (&a)[kSize], std::index_sequence<Ixs...>)
|
||||
template<std::size_t... Ixs>
|
||||
matrix_fixed& fill(const F (&a)[kSize], std::index_sequence<Ixs...>)
|
||||
{
|
||||
m_data = { a[Ixs]... };
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr std::size_t dim_m() const { return M; } ///< Return dimension m
|
||||
[[nodiscard]] constexpr std::size_t dim_n() const { return N; } ///< Return dimension n
|
||||
constexpr std::size_t dim_m() const { return M; } ///< Return dimension m
|
||||
constexpr std::size_t dim_n() const { return N; } ///< Return dimension n
|
||||
|
||||
/** Return the value of element [ @a i, @a j ] */
|
||||
[[nodiscard]] constexpr value_type operator()(std::size_t i, std::size_t j) const
|
||||
constexpr value_type operator()(std::size_t i, std::size_t j) const
|
||||
{
|
||||
assert(i < M);
|
||||
assert(j < N);
|
||||
@@ -301,7 +285,7 @@ class matrix_fixed : public matrix_expression<matrix_fixed<F, M, N>>
|
||||
}
|
||||
|
||||
/** Return a reference to element [ @a i, @a j ] */
|
||||
[[nodiscard]] constexpr value_type &operator()(std::size_t i, std::size_t j)
|
||||
constexpr value_type &operator()(std::size_t i, std::size_t j)
|
||||
{
|
||||
assert(i < M);
|
||||
assert(j < N);
|
||||
@@ -324,9 +308,9 @@ using matrix4x4 = matrix_fixed<F, 4, 4>;
|
||||
|
||||
/**
|
||||
* @brief Storage class implementation of symmetric matrix_expression
|
||||
*
|
||||
*
|
||||
* @tparam F The type of the stored values
|
||||
*
|
||||
*
|
||||
* matrix is m x n, addressing i,j is 0 <= i < m and 0 <= j < n
|
||||
* element m i,j is mapped to [i * n + j] and thus storage is row major
|
||||
*/
|
||||
@@ -353,11 +337,11 @@ class symmetric_matrix : public matrix_expression<symmetric_matrix<F>>
|
||||
symmetric_matrix &operator=(const symmetric_matrix &m) = default;
|
||||
/** @endcond */
|
||||
|
||||
[[nodiscard]] constexpr std::size_t dim_m() const { return m_n; } ///< Return dimension m
|
||||
[[nodiscard]] constexpr std::size_t dim_n() const { return m_n; } ///< Return dimension n
|
||||
constexpr std::size_t dim_m() const { return m_n; } ///< Return dimension m
|
||||
constexpr std::size_t dim_n() const { return m_n; } ///< Return dimension n
|
||||
|
||||
/** Return the value of element [ @a i, @a j ] */
|
||||
[[nodiscard]] constexpr value_type operator()(std::size_t i, std::size_t j) const
|
||||
constexpr value_type operator()(std::size_t i, std::size_t j) const
|
||||
{
|
||||
return i < j
|
||||
? m_data[(j * (j + 1)) / 2 + i]
|
||||
@@ -365,7 +349,7 @@ class symmetric_matrix : public matrix_expression<symmetric_matrix<F>>
|
||||
}
|
||||
|
||||
/** Return a reference to element [ @a i, @a j ] */
|
||||
[[nodiscard]] constexpr value_type &operator()(std::size_t i, std::size_t j)
|
||||
constexpr value_type &operator()(std::size_t i, std::size_t j)
|
||||
{
|
||||
if (i > j)
|
||||
std::swap(i, j);
|
||||
@@ -383,9 +367,9 @@ class symmetric_matrix : public matrix_expression<symmetric_matrix<F>>
|
||||
/**
|
||||
* @brief Storage class implementation of symmetric matrix_expression
|
||||
* with compile time fixed size.
|
||||
*
|
||||
*
|
||||
* @tparam F The type of the stored values
|
||||
*
|
||||
*
|
||||
* matrix is m x n, addressing i,j is 0 <= i < m and 0 <= j < n
|
||||
* element m i,j is mapped to [i * n + j] and thus storage is row major
|
||||
*/
|
||||
@@ -409,11 +393,11 @@ class symmetric_matrix_fixed : public matrix_expression<symmetric_matrix_fixed<F
|
||||
symmetric_matrix_fixed &operator=(const symmetric_matrix_fixed &m) = default;
|
||||
/** @endcond */
|
||||
|
||||
[[nodiscard]] constexpr std::size_t dim_m() const { return M; } ///< Return dimension m
|
||||
[[nodiscard]] constexpr std::size_t dim_n() const { return M; } ///< Return dimension n
|
||||
constexpr std::size_t dim_m() const { return M; } ///< Return dimension m
|
||||
constexpr std::size_t dim_n() const { return M; } ///< Return dimension n
|
||||
|
||||
/** Return the value of element [ @a i, @a j ] */
|
||||
[[nodiscard]] constexpr value_type operator()(std::size_t i, std::size_t j) const
|
||||
constexpr value_type operator()(std::size_t i, std::size_t j) const
|
||||
{
|
||||
return i < j
|
||||
? m_data[(j * (j + 1)) / 2 + i]
|
||||
@@ -421,7 +405,7 @@ class symmetric_matrix_fixed : public matrix_expression<symmetric_matrix_fixed<F
|
||||
}
|
||||
|
||||
/** Return a reference to element [ @a i, @a j ] */
|
||||
[[nodiscard]] constexpr value_type &operator()(std::size_t i, std::size_t j)
|
||||
constexpr value_type &operator()(std::size_t i, std::size_t j)
|
||||
{
|
||||
if (i > j)
|
||||
std::swap(i, j);
|
||||
@@ -443,38 +427,12 @@ using symmetric_matrix4x4 = symmetric_matrix_fixed<F, 4>;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/// A transposed matrix view
|
||||
|
||||
template <typename M>
|
||||
class transposed_matrix : public cif::matrix_expression<transposed_matrix<M>>
|
||||
{
|
||||
public:
|
||||
transposed_matrix(const M &m)
|
||||
: m_m(m)
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr std::size_t dim_m() const { return m_m.dim_n(); } ///< Return dimension m
|
||||
[[nodiscard]] constexpr std::size_t dim_n() const { return m_m.dim_m(); } ///< Return dimension n
|
||||
|
||||
/** Access to the value of element [ @a i, @a j ] */
|
||||
[[nodiscard]] constexpr auto operator()(std::size_t i, std::size_t j) const
|
||||
{
|
||||
return m_m(j, i);
|
||||
}
|
||||
|
||||
private:
|
||||
const M &m_m;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief implementation of symmetric matrix_expression with a value
|
||||
* of 1 for the diagonal values and 0 for all the others.
|
||||
*
|
||||
*
|
||||
* @tparam F The type of the stored values
|
||||
*
|
||||
*
|
||||
* matrix is m x n, addressing i,j is 0 <= i < m and 0 <= j < n
|
||||
* element m i,j is mapped to [i * n + j] and thus storage is row major
|
||||
*/
|
||||
@@ -491,11 +449,11 @@ class identity_matrix : public matrix_expression<identity_matrix<F>>
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr std::size_t dim_m() const { return m_n; } ///< Return dimension m
|
||||
[[nodiscard]] constexpr std::size_t dim_n() const { return m_n; } ///< Return dimension n
|
||||
constexpr std::size_t dim_m() const { return m_n; } ///< Return dimension m
|
||||
constexpr std::size_t dim_n() const { return m_n; } ///< Return dimension n
|
||||
|
||||
/** Return the value of element [ @a i, @a j ] */
|
||||
[[nodiscard]] constexpr value_type operator()(std::size_t i, std::size_t j) const
|
||||
constexpr value_type operator()(std::size_t i, std::size_t j) const
|
||||
{
|
||||
return static_cast<value_type>(i == j ? 1 : 0);
|
||||
}
|
||||
@@ -509,7 +467,7 @@ class identity_matrix : public matrix_expression<identity_matrix<F>>
|
||||
|
||||
/**
|
||||
* @brief Implementation of a substraction operation as a matrix expression
|
||||
*
|
||||
*
|
||||
* @tparam M1 Type of matrix 1
|
||||
* @tparam M2 Type of matrix 2
|
||||
*/
|
||||
@@ -526,11 +484,11 @@ class matrix_subtraction : public matrix_expression<matrix_subtraction<M1, M2>>
|
||||
assert(m_m1.dim_n() == m_m2.dim_n());
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr std::size_t dim_m() const { return m_m1.dim_m(); } ///< Return dimension m
|
||||
[[nodiscard]] constexpr std::size_t dim_n() const { return m_m1.dim_n(); } ///< Return dimension n
|
||||
constexpr std::size_t dim_m() const { return m_m1.dim_m(); } ///< Return dimension m
|
||||
constexpr std::size_t dim_n() const { return m_m1.dim_n(); } ///< Return dimension n
|
||||
|
||||
/** Access to the value of element [ @a i, @a j ] */
|
||||
[[nodiscard]] constexpr auto operator()(std::size_t i, std::size_t j) const
|
||||
constexpr auto operator()(std::size_t i, std::size_t j) const
|
||||
{
|
||||
return m_m1(i, j) - m_m2(i, j);
|
||||
}
|
||||
@@ -549,7 +507,7 @@ auto operator-(const matrix_expression<M1> &m1, const matrix_expression<M2> &m2)
|
||||
|
||||
/**
|
||||
* @brief Implementation of a multiplication operation as a matrix expression
|
||||
*
|
||||
*
|
||||
* @tparam M1 Type of matrix 1
|
||||
* @tparam M2 Type of matrix 2
|
||||
*/
|
||||
@@ -562,20 +520,20 @@ class matrix_matrix_multiplication : public matrix_expression<matrix_matrix_mult
|
||||
: m_m1(m1)
|
||||
, m_m2(m2)
|
||||
{
|
||||
assert(m1.dim_n() == m2.dim_m());
|
||||
assert(m1.dim_m() == m2.dim_n());
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr std::size_t dim_m() const { return m_m1.dim_m(); } ///< Return dimension m
|
||||
[[nodiscard]] constexpr std::size_t dim_n() const { return m_m1.dim_n(); } ///< Return dimension n
|
||||
constexpr std::size_t dim_m() const { return m_m1.dim_m(); } ///< Return dimension m
|
||||
constexpr std::size_t dim_n() const { return m_m1.dim_n(); } ///< Return dimension n
|
||||
|
||||
/** Access to the value of element [ @a i, @a j ] */
|
||||
[[nodiscard]] constexpr auto operator()(std::size_t i, std::size_t j) const
|
||||
constexpr auto operator()(std::size_t i, std::size_t j) const
|
||||
{
|
||||
using value_type = decltype(m_m1(0, 0));
|
||||
|
||||
value_type result = {};
|
||||
|
||||
for (std::size_t k = 0; k < m_m1.dim_n(); ++k)
|
||||
for (std::size_t k = 0; k < m_m1.dim_m(); ++k)
|
||||
result += m_m1(i, k) * m_m2(k, j);
|
||||
|
||||
return result;
|
||||
@@ -588,7 +546,7 @@ class matrix_matrix_multiplication : public matrix_expression<matrix_matrix_mult
|
||||
|
||||
/**
|
||||
* @brief Implementation of a multiplication operation of a matrix and a scalar value as a matrix expression
|
||||
*
|
||||
*
|
||||
* @tparam M1 Type of matrix
|
||||
* @tparam M2 Type of scalar value
|
||||
*/
|
||||
@@ -606,11 +564,11 @@ class matrix_scalar_multiplication : public matrix_expression<matrix_scalar_mult
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr std::size_t dim_m() const { return m_m.dim_m(); } ///< Return dimension m
|
||||
[[nodiscard]] constexpr std::size_t dim_n() const { return m_m.dim_n(); } ///< Return dimension n
|
||||
constexpr std::size_t dim_m() const { return m_m.dim_m(); } ///< Return dimension m
|
||||
constexpr std::size_t dim_n() const { return m_m.dim_n(); } ///< Return dimension n
|
||||
|
||||
/** Access to the value of element [ @a i, @a j ] */
|
||||
[[nodiscard]] constexpr auto operator()(std::size_t i, std::size_t j) const
|
||||
constexpr auto operator()(std::size_t i, std::size_t j) const
|
||||
{
|
||||
return m_m(i, j) * m_v;
|
||||
}
|
||||
@@ -621,56 +579,23 @@ class matrix_scalar_multiplication : public matrix_expression<matrix_scalar_mult
|
||||
};
|
||||
|
||||
/** First implementation of operator*, enabled if the second parameter is a scalar */
|
||||
template <typename M1, typename T>
|
||||
template <typename M1, typename T, std::enable_if_t<std::is_floating_point_v<T>, int> = 0>
|
||||
auto operator*(const matrix_expression<M1> &m, T v)
|
||||
requires(std::is_floating_point_v<T>)
|
||||
{
|
||||
return matrix_scalar_multiplication(m, v);
|
||||
}
|
||||
|
||||
/** First implementation of operator*, enabled if the second parameter is not a scalar and thus must be a matrix, right? */
|
||||
template <typename M1, typename M2>
|
||||
template <typename M1, typename M2, std::enable_if_t<not std::is_floating_point_v<M2>, int> = 0>
|
||||
auto operator*(const matrix_expression<M1> &m1, const matrix_expression<M2> &m2)
|
||||
requires(not std::is_floating_point_v<M2>)
|
||||
{
|
||||
return matrix_matrix_multiplication(m1, m2);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/// A sub-view on a matrix
|
||||
template <typename M2>
|
||||
class sub_matrix : public matrix_expression<sub_matrix<M2>>
|
||||
{
|
||||
public:
|
||||
/// Constructor
|
||||
sub_matrix(const M2 &m, int i, int j)
|
||||
: m_m(m)
|
||||
, m_i(i)
|
||||
, m_j(j)
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr std::size_t dim_m() const { return m_m.dim_m() - 1; } ///< Return dimension m
|
||||
[[nodiscard]] constexpr std::size_t dim_n() const { return m_m.dim_n() - 1; } ///< Return dimension n
|
||||
|
||||
/** Access to the value of element [ @a i, @a j ] */
|
||||
[[nodiscard]] constexpr auto operator()(std::size_t i, std::size_t j) const
|
||||
{
|
||||
return m_m(
|
||||
i >= m_i ? i + 1 : i,
|
||||
j >= m_j ? j + 1 : j);
|
||||
}
|
||||
|
||||
private:
|
||||
const M2 &m_m;
|
||||
std::size_t m_i, m_j;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/** Generic routine to calculate the determinant of a matrix
|
||||
*
|
||||
*
|
||||
* @note This is currently only implemented for fixed matrices of size 3x3
|
||||
*/
|
||||
template <typename M>
|
||||
@@ -680,25 +605,13 @@ auto determinant(const M &m);
|
||||
template <typename F = float>
|
||||
auto determinant(const matrix3x3<F> &m)
|
||||
{
|
||||
return (m(0, 0) * ((m(1, 1) * m(2, 2) - m(1, 2) * m(2, 1))) +
|
||||
m(0, 1) * ((m(1, 2) * m(2, 0) - m(1, 0) * m(2, 2))) +
|
||||
m(0, 2) * ((m(1, 0) * m(2, 1) - m(1, 1) * m(2, 0))));
|
||||
return (m(0, 0) * (m(1, 1) * m(2, 2) - m(1, 2) * m(2, 1)) +
|
||||
m(0, 1) * (m(1, 2) * m(2, 0) - m(1, 0) * m(2, 2)) +
|
||||
m(0, 2) * (m(1, 0) * m(2, 1) - m(1, 1) * m(2, 0)));
|
||||
}
|
||||
|
||||
/** Implementation of the determinant function for fixed size matrices of size 4x4 */
|
||||
template <typename F = float>
|
||||
F determinant(const matrix4x4<F> &m)
|
||||
{
|
||||
return m(0, 0) * determinant(matrix3x3<F>(sub_matrix<decltype(m)>(m, 0, 0))) -
|
||||
m(0, 1) * determinant(matrix3x3<F>(sub_matrix<decltype(m)>(m, 0, 1))) +
|
||||
m(0, 2) * determinant(matrix3x3<F>(sub_matrix<decltype(m)>(m, 0, 2))) -
|
||||
m(0, 3) * determinant(matrix3x3<F>(sub_matrix<decltype(m)>(m, 0, 3)));
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/** Generic routine to calculate the inverse of a matrix
|
||||
*
|
||||
*
|
||||
* @note This is currently only implemented for fixed matrices of size 3x3
|
||||
*/
|
||||
template <typename M>
|
||||
@@ -729,7 +642,7 @@ matrix3x3<F> inverse(const matrix3x3<F> &m)
|
||||
|
||||
/**
|
||||
* @brief Implementation of a cofactor calculation as a matrix expression
|
||||
*
|
||||
*
|
||||
* @tparam M Type of matrix
|
||||
*/
|
||||
template <typename M>
|
||||
@@ -742,11 +655,11 @@ class matrix_cofactors : public matrix_expression<matrix_cofactors<M>>
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr std::size_t dim_m() const { return m_m.dim_m(); } ///< Return dimension m
|
||||
[[nodiscard]] constexpr std::size_t dim_n() const { return m_m.dim_n(); } ///< Return dimension n
|
||||
constexpr std::size_t dim_m() const { return m_m.dim_m(); } ///< Return dimension m
|
||||
constexpr std::size_t dim_n() const { return m_m.dim_n(); } ///< Return dimension n
|
||||
|
||||
/** Access to the value of element [ @a i, @a j ] */
|
||||
[[nodiscard]] constexpr auto operator()(std::size_t i, std::size_t j) const
|
||||
constexpr auto operator()(std::size_t i, std::size_t j) const
|
||||
{
|
||||
const std::size_t ixs[4][3] = {
|
||||
{ 1, 2, 3 },
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -26,35 +26,20 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cif++/category.hpp"
|
||||
#include "cif++/datablock.hpp"
|
||||
#include "cif++/item.hpp"
|
||||
#include "cif++/row.hpp"
|
||||
#include "cif++/text.hpp"
|
||||
#include "cif++/utilities.hpp"
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* @file parser.hpp
|
||||
*
|
||||
*
|
||||
* This file contains the declaration of an mmCIF parser
|
||||
*/
|
||||
|
||||
namespace cif
|
||||
{
|
||||
|
||||
class category;
|
||||
class datablock;
|
||||
class file;
|
||||
class validator;
|
||||
class validator_base;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
@@ -72,14 +57,14 @@ class parse_error : public std::runtime_error
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief The sac_parser is a similar to SAX parsers (Simple API for XML,
|
||||
* @brief The sac_parser is a similar to SAX parsers (Simple API for XML,
|
||||
* in our case it is Simple API for CIF)
|
||||
*
|
||||
*
|
||||
* This is a hand crafted, optimised parser for reading cif files,
|
||||
* both cif 1.0 and cif 1.1 is supported. But version 2.0 is not.
|
||||
* That means that the content of files strictly contains only
|
||||
* ASCII characters. Anything else will generate an error.
|
||||
*
|
||||
*
|
||||
* This class is an abstract base class. Derived classes should
|
||||
* implement the produce_ methods.
|
||||
*/
|
||||
@@ -107,10 +92,10 @@ class sac_parser
|
||||
/// create a table with character properties.
|
||||
enum CharTraitsMask : uint8_t
|
||||
{
|
||||
kOrdinaryMask = 1 << 0, ///< The character is in the Ordinary class
|
||||
kNonBlankMask = 1 << 1, ///< The character is in the NonBlank class
|
||||
kTextLeadMask = 1 << 2, ///< The character is in the TextLead class
|
||||
kAnyPrintMask = 1 << 3 ///< The character is in the AnyPrint class
|
||||
kOrdinaryMask = 1 << 0, ///< The character is in the Ordinary class
|
||||
kNonBlankMask = 1 << 1, ///< The character is in the NonBlank class
|
||||
kTextLeadMask = 1 << 2, ///< The character is in the TextLead class
|
||||
kAnyPrintMask = 1 << 3 ///< The character is in the AnyPrint class
|
||||
};
|
||||
|
||||
/// \brief Return true if the character @a ch is a *space* character
|
||||
@@ -158,102 +143,12 @@ class sac_parser
|
||||
|
||||
static constexpr uint8_t kCharTraitsTable[128] = {
|
||||
// 0 1 2 3 4 5 6 7 8 9 a b c d e f
|
||||
14,
|
||||
15,
|
||||
14,
|
||||
14,
|
||||
14,
|
||||
15,
|
||||
15,
|
||||
14,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15, // 2
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
10,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15, // 3
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15, // 4
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
14,
|
||||
15,
|
||||
14,
|
||||
15,
|
||||
14, // 5
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15, // 6
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
0, // 7
|
||||
14, 15, 14, 14, 14, 15, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, // 2
|
||||
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 10, 15, 15, 15, 15, // 3
|
||||
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, // 4
|
||||
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, 15, 14, 15, 14, // 5
|
||||
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, // 6
|
||||
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, // 7
|
||||
};
|
||||
|
||||
enum class CIFToken
|
||||
@@ -269,40 +164,23 @@ class sac_parser
|
||||
SAVE_NAME,
|
||||
STOP,
|
||||
ITEM_NAME,
|
||||
|
||||
VALUE_INAPPLICABLE,
|
||||
VALUE_UNKNOWN,
|
||||
VALUE_NUMERIC_INTEGER,
|
||||
VALUE_NUMERIC_FLOAT,
|
||||
VALUE_CHARSTRING,
|
||||
VALUE_TEXTFIELD
|
||||
VALUE
|
||||
};
|
||||
|
||||
static constexpr const char *get_token_name(CIFToken token)
|
||||
{
|
||||
switch (token)
|
||||
{
|
||||
using enum CIFToken;
|
||||
|
||||
case UNKNOWN: return "Unknown";
|
||||
case END_OF_FILE: return "Eof";
|
||||
case DATA: return "DATA";
|
||||
case LOOP: return "LOOP";
|
||||
case GLOBAL: return "GLOBAL";
|
||||
case SAVE_: return "SAVE";
|
||||
case SAVE_NAME: return "SAVE+name";
|
||||
case STOP: return "STOP";
|
||||
case ITEM_NAME:
|
||||
return "Tag";
|
||||
// case VALUE: return "Value";
|
||||
|
||||
case VALUE_INAPPLICABLE: return "Inapplicable value";
|
||||
case VALUE_UNKNOWN: return "'Unknown' value (=null)";
|
||||
case VALUE_NUMERIC_INTEGER: return "Integer value";
|
||||
case VALUE_NUMERIC_FLOAT: return "Float value";
|
||||
case VALUE_CHARSTRING: return "Charstring value";
|
||||
case VALUE_TEXTFIELD: return "Textfield value";
|
||||
|
||||
case CIFToken::UNKNOWN: return "Unknown";
|
||||
case CIFToken::END_OF_FILE: return "Eof";
|
||||
case CIFToken::DATA: return "DATA";
|
||||
case CIFToken::LOOP: return "LOOP";
|
||||
case CIFToken::GLOBAL: return "GLOBAL";
|
||||
case CIFToken::SAVE_: return "SAVE";
|
||||
case CIFToken::SAVE_NAME: return "SAVE+name";
|
||||
case CIFToken::STOP: return "STOP";
|
||||
case CIFToken::ITEM_NAME: return "Tag";
|
||||
case CIFToken::VALUE: return "Value";
|
||||
default: return "Invalid token parameter";
|
||||
}
|
||||
}
|
||||
@@ -321,6 +199,7 @@ class sac_parser
|
||||
/** @endcond */
|
||||
|
||||
public:
|
||||
|
||||
/** \brief Parse only a single datablock in the string @a datablock
|
||||
* The start of the datablock is first located and then data
|
||||
* is parsed up until the next start of a datablock or the end of
|
||||
@@ -335,10 +214,10 @@ class sac_parser
|
||||
|
||||
/**
|
||||
* @brief Parse the datablock named @a datablock
|
||||
*
|
||||
*
|
||||
* This will first lookup the datablock's offset in the index @a index
|
||||
* and then start parsing from that location until the next datablock.
|
||||
*
|
||||
*
|
||||
* @param datablock Name of the datablock to parse
|
||||
* @param index The index created using index_datablocks
|
||||
* @return true If the datablock was found
|
||||
@@ -348,11 +227,12 @@ class sac_parser
|
||||
|
||||
/**
|
||||
* @brief Parse the file
|
||||
*
|
||||
*
|
||||
*/
|
||||
void parse_file();
|
||||
|
||||
protected:
|
||||
|
||||
/** @cond */
|
||||
|
||||
sac_parser(std::istream &is, bool init = true);
|
||||
@@ -365,7 +245,7 @@ class sac_parser
|
||||
|
||||
void error(const std::string &msg)
|
||||
{
|
||||
if (VERBOSE > 0)
|
||||
if (cif::VERBOSE > 0)
|
||||
std::cerr << "Error parsing mmCIF: " << msg << '\n';
|
||||
|
||||
throw parse_error(m_line_nr, msg);
|
||||
@@ -373,7 +253,7 @@ class sac_parser
|
||||
|
||||
void warning(const std::string &msg)
|
||||
{
|
||||
if (VERBOSE > 0)
|
||||
if (cif::VERBOSE > 0)
|
||||
std::cerr << "parser warning at line " << m_line_nr << ": " << msg << '\n';
|
||||
}
|
||||
|
||||
@@ -382,9 +262,10 @@ class sac_parser
|
||||
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(std::string_view category, std::string_view item, item_value value) = 0;
|
||||
virtual void produce_item(std::string_view category, std::string_view item, std::string_view value) = 0;
|
||||
|
||||
protected:
|
||||
|
||||
enum class State
|
||||
{
|
||||
Start,
|
||||
@@ -400,17 +281,7 @@ class sac_parser
|
||||
TextItem,
|
||||
TextItemNL,
|
||||
Reserved,
|
||||
Value,
|
||||
|
||||
TextItemBS,
|
||||
TextItemBS2,
|
||||
TextItemBSNL,
|
||||
|
||||
Numeric_Zero,
|
||||
Numeric_Integer,
|
||||
Numeric_Float,
|
||||
Numeric_Exponent1,
|
||||
Numeric_Exponent2
|
||||
Value
|
||||
};
|
||||
|
||||
std::streambuf &m_source;
|
||||
@@ -418,15 +289,11 @@ class sac_parser
|
||||
// Parser state
|
||||
uint32_t m_line_nr;
|
||||
bool m_bol;
|
||||
bool m_backslash_strings = false;
|
||||
CIFToken m_lookahead;
|
||||
|
||||
// token buffer
|
||||
std::vector<char> m_token_buffer;
|
||||
std::string_view m_token_value;
|
||||
int64_t m_token_value_int;
|
||||
double m_token_value_float;
|
||||
int m_float_precision;
|
||||
|
||||
/** @endcond */
|
||||
};
|
||||
@@ -435,7 +302,7 @@ class sac_parser
|
||||
|
||||
/**
|
||||
* @brief An actual implementation of a sac_parser generating data in a file
|
||||
*
|
||||
*
|
||||
* This parser will create the cif::file, cif::datablock and cif::category
|
||||
* objects required to contain all data
|
||||
*/
|
||||
@@ -443,7 +310,7 @@ class parser : public sac_parser
|
||||
{
|
||||
public:
|
||||
/// \brief constructor, generates data into @a file from @a is using validator @a v
|
||||
parser(std::istream &is, file &file, const validator *v)
|
||||
parser(std::istream &is, file &file, const validator_base *v)
|
||||
: sac_parser(is)
|
||||
, m_file(file)
|
||||
, m_validator(v)
|
||||
@@ -464,13 +331,13 @@ class parser : public sac_parser
|
||||
|
||||
void produce_row() override;
|
||||
|
||||
void produce_item(std::string_view category, std::string_view item, item_value value) override;
|
||||
void produce_item(std::string_view category, std::string_view item, std::string_view value) override;
|
||||
|
||||
protected:
|
||||
file &m_file;
|
||||
datablock *m_datablock = nullptr;
|
||||
category *m_category = nullptr;
|
||||
const validator *m_validator = nullptr;
|
||||
const validator_base *m_validator = nullptr;
|
||||
row_handle m_row;
|
||||
|
||||
/** @endcond */
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "cif++/file.hpp"
|
||||
#include "cif++/validate.hpp"
|
||||
|
||||
#include <system_error>
|
||||
|
||||
@@ -64,7 +63,7 @@ file read(std::istream &is);
|
||||
* @brief Read a file in legacy PDB format from std::istream @a is and
|
||||
* put the data into @a cifFile
|
||||
*/
|
||||
void read_pdb_file(std::istream &pdbFile, cif::file &cifFile);
|
||||
file read_pdb_file(std::istream &pdbFile);
|
||||
|
||||
// mmCIF to PDB
|
||||
|
||||
@@ -104,50 +103,16 @@ inline void write(const std::filesystem::path &p, const file &f)
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Quickly fix a PDB file that lacks some often needed categories
|
||||
*
|
||||
* This differs from reconstruct_pdbx which does a much more thorough job
|
||||
*
|
||||
* \param pdbx_file The cif::file that hopefully contains some valid data
|
||||
*/
|
||||
|
||||
void fixup_pdbx(file &pdbx_file);
|
||||
|
||||
/**
|
||||
* @brief Quickly fix a PDB file that lacks some often needed categories
|
||||
*
|
||||
* This differs from reconstruct_pdbx which does a much more thorough job
|
||||
*
|
||||
* \param pdbx_file The cif::file that hopefully contains some valid data
|
||||
* \param v The validator to use
|
||||
*/
|
||||
|
||||
void fixup_pdbx(file &pdbx_file, const validator &v);
|
||||
|
||||
/** \brief Reconstruct all missing categories for an assumed PDBx file.
|
||||
*
|
||||
* Some people believe that simply dumping some atom records is enough.
|
||||
*
|
||||
* This version uses the audit_conform information and falls back to
|
||||
* using mmcif_pdbx.dic if not specified.
|
||||
*
|
||||
* \param pdbx_file The cif::file that hopefully contains some valid data
|
||||
* \param file The cif::file that hopefully contains some valid data
|
||||
* \param dictionary The mmcif dictionary to use
|
||||
* \result Returns true if the resulting file is valid
|
||||
*/
|
||||
|
||||
bool reconstruct_pdbx(file &pdbx_file);
|
||||
|
||||
/** \brief Reconstruct all missing categories for an assumed PDBx file.
|
||||
*
|
||||
* Some people believe that simply dumping some atom records is enough.
|
||||
*
|
||||
* \param pdbx_file The cif::file that hopefully contains some valid data
|
||||
* \param v The validator to use
|
||||
* \result Returns true if the resulting file is valid
|
||||
*/
|
||||
|
||||
bool reconstruct_pdbx(file &pdbx_file, const validator &v);
|
||||
bool reconstruct_pdbx(file &pdbx_file, std::string_view dictionary = "mmcif_pdbx");
|
||||
|
||||
/** \brief This is an extension to cif::validator, use the logic in common
|
||||
* PDBx files to see if the file is internally consistent.
|
||||
@@ -160,29 +125,12 @@ bool reconstruct_pdbx(file &pdbx_file, const validator &v);
|
||||
*
|
||||
* This function throws a std::system_error in case of an error
|
||||
*
|
||||
* \param pdbx_file The input file
|
||||
* \param file The input file
|
||||
* \param dictionary The mmcif dictionary to use
|
||||
* \result Returns true if the file was valid and consistent
|
||||
*/
|
||||
|
||||
bool is_valid_pdbx_file(const file &pdbx_file);
|
||||
|
||||
/** \brief This is an extension to cif::validator, use the logic in common
|
||||
* PDBx files to see if the file is internally consistent.
|
||||
*
|
||||
* This function for now checks if the following categories are consistent:
|
||||
*
|
||||
* atom_site -> pdbx_poly_seq_scheme -> entity_poly_seq -> entity_poly -> entity
|
||||
*
|
||||
* Use the common \ref cif::VERBOSE flag to turn on diagnostic messages.
|
||||
*
|
||||
* This function throws a std::system_error in case of an error
|
||||
*
|
||||
* \param pdbx_file The input file
|
||||
* \param v The validator to use
|
||||
* \result Returns true if the file was valid and consistent
|
||||
*/
|
||||
|
||||
bool is_valid_pdbx_file(const file &pdbx_file, const validator &v);
|
||||
bool is_valid_pdbx_file(const file &pdbx_file, std::string_view dictionary = "mmcif_pdbx");
|
||||
|
||||
/** \brief This is an extension to cif::validator, use the logic in common
|
||||
* PDBx files to see if the file is internally consistent.
|
||||
@@ -196,8 +144,8 @@ bool is_valid_pdbx_file(const file &pdbx_file, const validator &v);
|
||||
* The dictionary is assumed to be specified in the file or to be the
|
||||
* default mmcif_pdbx.dic dictionary.
|
||||
*
|
||||
* \param pdbx_file The input file
|
||||
* \param ec In case of error, this will contain what went wrong
|
||||
* \param file The input file
|
||||
* \param ec The error_code in case something was wrong
|
||||
* \result Returns true if the file was valid and consistent
|
||||
*/
|
||||
|
||||
@@ -212,13 +160,13 @@ bool is_valid_pdbx_file(const file &pdbx_file, std::error_code &ec);
|
||||
*
|
||||
* Use the common \ref cif::VERBOSE flag to turn on diagnostic messages.
|
||||
*
|
||||
* \param pdbx_file The input file
|
||||
* \param v The validator to use
|
||||
* \param file The input file
|
||||
* \param dictionary The dictionary to use
|
||||
* \param ec The error_code in case something was wrong
|
||||
* \result Returns true if the file was valid and consistent
|
||||
*/
|
||||
|
||||
bool is_valid_pdbx_file(const file &pdbx_file, const validator &v,
|
||||
bool is_valid_pdbx_file(const file &pdbx_file, std::string_view dictionary,
|
||||
std::error_code &ec);
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2025 NKI/AVL, Netherlands Cancer Institute
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2020 NKI/AVL, Netherlands Cancer Institute
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
@@ -24,29 +24,10 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "test-main.hpp"
|
||||
#pragma once
|
||||
|
||||
#include <cif++/cif++.hpp>
|
||||
/// \file cif2pdb.hpp
|
||||
/// \deprecated This file is no longer used. Please use "cif++/pdb.hpp" instead
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#warning "Use of this file is deprecated, please use "cif++/pdb.hpp"
|
||||
|
||||
TEST_CASE("q-1")
|
||||
{
|
||||
using namespace cif::literals;
|
||||
|
||||
cif::compound_factory::instance().push_dictionary(gTestDir / "REA.cif");
|
||||
|
||||
cif::file a = cif::pdb::read(gTestDir / "pdb1cbs.ent.gz");
|
||||
auto &pdbx_poly_seq_scheme = a.front()["pdbx_poly_seq_scheme"];
|
||||
REQUIRE_FALSE(pdbx_poly_seq_scheme.empty());
|
||||
|
||||
SECTION("s-11")
|
||||
{
|
||||
CHECK(pdbx_poly_seq_scheme.count("asym_id"_key == "A") == 137);
|
||||
|
||||
CHECK(pdbx_poly_seq_scheme.count("asym_id"_key == "A" and "entity_id"_key == 1 and "seq_id"_key == 1 and "mon_id"_key == "PRO") == 1);
|
||||
|
||||
CHECK(pdbx_poly_seq_scheme.count("asym_id"_key == "A" and "entity_id"_key == 1 and "seq_id"_key == 1 and "mon_id"_key == "PRO" and "hetero"_key == false) == 1);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2026 NKI/AVL, Netherlands Cancer Institute
|
||||
* Copyright (c) 2022 NKI/AVL, Netherlands Cancer Institute
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -24,20 +24,9 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <charconv>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#pragma once
|
||||
|
||||
int main()
|
||||
{
|
||||
float v;
|
||||
char s[] = "1.0";
|
||||
/// \file io.hpp
|
||||
/// \deprecated This file is no longer used. Please use "cif++/pdb.hpp" instead
|
||||
|
||||
auto r = std::from_chars(s, s + strlen(s), v);
|
||||
|
||||
assert(r.ec == std::errc{});
|
||||
assert(r.ptr = s + strlen(s));
|
||||
assert(v == 1.0f);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#warning "Use of this file is deprecated, please use "cif++/pdb.hpp"
|
||||
@@ -1,17 +1,17 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2026 NKI/AVL, Netherlands Cancer Institute
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2020 NKI/AVL, Netherlands Cancer Institute
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
@@ -23,42 +23,10 @@
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <cif++/cif++.hpp>
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc != 2)
|
||||
{
|
||||
std::cerr << "Usage: example <inputfile>\n";
|
||||
exit(1);
|
||||
}
|
||||
#pragma once
|
||||
|
||||
cif::file file(argv[1]);
|
||||
/// \file pdb2cif.hpp
|
||||
/// \deprecated This file is no longer used. Please use "cif++/pdb.hpp" instead
|
||||
|
||||
if (file.empty())
|
||||
{
|
||||
std::cerr << "Empty file\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
auto &db = file.front();
|
||||
cif::cql::connection c(db);
|
||||
cif::cql::transaction tx(c);
|
||||
|
||||
auto N = tx.exec("SELECT COUNT(*) FROM atom_site").one_field().get<std::size_t>();
|
||||
auto M = tx.exec("SELECT COUNT(*) FROM atom_site WHERE label_atom_id = 'OXT'").one_field().get<std::size_t>();
|
||||
|
||||
std::cout << "File contains " << N << " atoms of which " << M << (M == 1 ? " is" : " are") << " OXT\n"
|
||||
<< "residues with an OXT are:\n";
|
||||
|
||||
for (const auto &[asym, comp, seqnr] : tx.stream<std::string, std::string, int>(
|
||||
"SELECT label_asym_id, label_comp_id, label_seq_id FROM atom_site WHERE label_atom_id = 'OXT'"))
|
||||
{
|
||||
std::cout << asym << ' ' << comp << ' ' << seqnr << '\n';
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#warning "Use of this file is deprecated, please use "cif++/pdb.hpp"
|
||||
32
include/cif++/pdb/tls.hpp
Normal file
32
include/cif++/pdb/tls.hpp
Normal file
@@ -0,0 +1,32 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2020 NKI/AVL, Netherlands Cancer Institute
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/// \file tls.hpp
|
||||
/// \deprecated This code has been moved to libpdb-redo
|
||||
|
||||
#warning "This code has been moved to libpdb-redo"
|
||||
@@ -30,26 +30,15 @@
|
||||
#include <cmath>
|
||||
#include <complex>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <format>
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
#include <numbers>
|
||||
#include <optional>
|
||||
#include <ostream>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <valarray>
|
||||
#include <vector>
|
||||
|
||||
#if __has_include(<clipper/core/coords.h>)
|
||||
# define HAVE_LIBCLIPPER 1
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wignored-qualifiers"
|
||||
# include <clipper/core/clipper_types.h>
|
||||
# include <clipper/core/coords.h>
|
||||
# pragma GCC diagnostic pop
|
||||
#define HAVE_LIBCLIPPER 1
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wignored-qualifiers"
|
||||
#include <clipper/core/coords.h>
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
/** \file point.hpp
|
||||
@@ -61,6 +50,12 @@
|
||||
namespace cif
|
||||
{
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/// \brief Our value for Pi
|
||||
const double
|
||||
kPI = 3.141592653589793238462643383279502884;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
/**
|
||||
* @brief A stripped down quaternion implementation, based on boost::math::quaternion
|
||||
@@ -122,13 +117,13 @@ class quaternion_type
|
||||
// accessors
|
||||
|
||||
/// \brief See class description, return the *real* part of the quaternion
|
||||
[[nodiscard]] constexpr value_type real() const
|
||||
constexpr value_type real() const
|
||||
{
|
||||
return a;
|
||||
}
|
||||
|
||||
/// \brief See class description, return the *unreal* part of the quaternion
|
||||
[[nodiscard]] constexpr quaternion_type unreal() const
|
||||
constexpr quaternion_type unreal() const
|
||||
{
|
||||
return { 0, b, c, d };
|
||||
}
|
||||
@@ -157,7 +152,15 @@ class quaternion_type
|
||||
}
|
||||
|
||||
/// \brief Assignment operator
|
||||
constexpr quaternion_type &operator=(quaternion_type const &rhs) = default;
|
||||
constexpr quaternion_type &operator=(quaternion_type const &rhs)
|
||||
{
|
||||
a = rhs.a;
|
||||
b = rhs.b;
|
||||
c = rhs.c;
|
||||
d = rhs.d;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// \brief Assignment operator that sets the *real* part to @a rhs and the *unreal* parts to zero
|
||||
constexpr quaternion_type &operator=(value_type const &rhs)
|
||||
@@ -270,10 +273,10 @@ class quaternion_type
|
||||
template <typename X>
|
||||
constexpr quaternion_type &operator*=(quaternion_type<X> const &rhs)
|
||||
{
|
||||
auto ar = static_cast<value_type>(rhs.a);
|
||||
auto br = static_cast<value_type>(rhs.b);
|
||||
auto cr = static_cast<value_type>(rhs.c);
|
||||
auto dr = static_cast<value_type>(rhs.d);
|
||||
value_type ar = static_cast<value_type>(rhs.a);
|
||||
value_type br = static_cast<value_type>(rhs.b);
|
||||
value_type cr = static_cast<value_type>(rhs.c);
|
||||
value_type dr = static_cast<value_type>(rhs.d);
|
||||
|
||||
quaternion_type result(a * ar - b * br - c * cr - d * dr, a * br + b * ar + c * dr - d * cr, a * cr - b * dr + c * ar + d * br, a * dr + b * cr - c * br + d * ar);
|
||||
swap(result);
|
||||
@@ -305,10 +308,10 @@ class quaternion_type
|
||||
template <typename X>
|
||||
constexpr quaternion_type &operator/=(quaternion_type<X> const &rhs)
|
||||
{
|
||||
auto ar = static_cast<value_type>(rhs.a);
|
||||
auto br = static_cast<value_type>(rhs.b);
|
||||
auto cr = static_cast<value_type>(rhs.c);
|
||||
auto dr = static_cast<value_type>(rhs.d);
|
||||
value_type ar = static_cast<value_type>(rhs.a);
|
||||
value_type br = static_cast<value_type>(rhs.b);
|
||||
value_type cr = static_cast<value_type>(rhs.c);
|
||||
value_type dr = static_cast<value_type>(rhs.d);
|
||||
|
||||
value_type denominator = ar * ar + br * br + cr * cr + dr * dr;
|
||||
quaternion_type result((+a * ar + b * br + c * cr + d * dr) / denominator, (-a * br + b * ar - c * dr + d * cr) / denominator, (-a * cr + b * dr + c * ar - d * br) / denominator, (-a * dr - b * cr + c * br + d * ar) / denominator);
|
||||
@@ -344,10 +347,10 @@ class quaternion_type
|
||||
return quaternion_type{ +q.a, -q.b, -q.c, -q.d };
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr value_type get_a() const { return a; } ///< Return part a
|
||||
[[nodiscard]] constexpr value_type get_b() const { return b; } ///< Return part b
|
||||
[[nodiscard]] constexpr value_type get_c() const { return c; } ///< Return part c
|
||||
[[nodiscard]] constexpr value_type get_d() const { return d; } ///< Return part d
|
||||
constexpr value_type get_a() const { return a; } ///< Return part a
|
||||
constexpr value_type get_b() const { return b; } ///< Return part b
|
||||
constexpr value_type get_c() const { return c; } ///< Return part c
|
||||
constexpr value_type get_d() const { return d; } ///< Return part d
|
||||
|
||||
/// \brief compare with @a rhs
|
||||
constexpr bool operator==(const quaternion_type &rhs) const
|
||||
@@ -362,18 +365,11 @@ class quaternion_type
|
||||
}
|
||||
|
||||
/// \brief test for all zero values
|
||||
constexpr explicit operator bool() const
|
||||
constexpr operator bool() const
|
||||
{
|
||||
return a != 0 or b != 0 or c != 0 or d != 0;
|
||||
}
|
||||
|
||||
/// \brief for debugging e.g.
|
||||
friend std::ostream &operator<<(std::ostream &os, const quaternion_type &rhs)
|
||||
{
|
||||
os << std::format("{{ a: {}, b: {}, c: {}, d: {} }}", rhs.a, rhs.b, rhs.c, rhs.d);
|
||||
return os;
|
||||
}
|
||||
|
||||
private:
|
||||
value_type a, b, c, d;
|
||||
};
|
||||
@@ -495,17 +491,17 @@ struct point_type
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr value_type &get_x() { return m_x; } ///< Get a reference to x
|
||||
[[nodiscard]] constexpr value_type get_x() const { return m_x; } ///< Get the value of x
|
||||
constexpr void set_x(value_type x) { m_x = x; } ///< Set the value of x to @a x
|
||||
constexpr value_type &get_x() { return m_x; } ///< Get a reference to x
|
||||
constexpr value_type get_x() const { return m_x; } ///< Get the value of x
|
||||
constexpr void set_x(value_type x) { m_x = x; } ///< Set the value of x to @a x
|
||||
|
||||
[[nodiscard]] constexpr value_type &get_y() { return m_y; } ///< Get a reference to y
|
||||
[[nodiscard]] constexpr value_type get_y() const { return m_y; } ///< Get the value of y
|
||||
constexpr void set_y(value_type y) { m_y = y; } ///< Set the value of y to @a y
|
||||
constexpr value_type &get_y() { return m_y; } ///< Get a reference to y
|
||||
constexpr value_type get_y() const { return m_y; } ///< Get the value of y
|
||||
constexpr void set_y(value_type y) { m_y = y; } ///< Set the value of y to @a y
|
||||
|
||||
[[nodiscard]] constexpr value_type &get_z() { return m_z; } ///< Get a reference to z
|
||||
[[nodiscard]] constexpr value_type get_z() const { return m_z; } ///< Get the value of z
|
||||
constexpr void set_z(value_type z) { m_z = z; } ///< Set the value of z to @a z
|
||||
constexpr value_type &get_z() { return m_z; } ///< Get a reference to z
|
||||
constexpr value_type get_z() const { return m_z; } ///< Get the value of z
|
||||
constexpr void set_z(value_type z) { m_z = z; } ///< Set the value of z to @a z
|
||||
|
||||
/// \brief add @a rhs
|
||||
constexpr point_type &operator+=(const point_type &rhs)
|
||||
@@ -686,13 +682,13 @@ struct point_type
|
||||
// consider point as a vector... perhaps I should rename point?
|
||||
|
||||
/// \brief looking at the point as if it is a vector, return the squared length
|
||||
[[nodiscard]] constexpr value_type length_sq() const
|
||||
constexpr value_type length_sq() const
|
||||
{
|
||||
return m_x * m_x + m_y * m_y + m_z * m_z;
|
||||
}
|
||||
|
||||
/// \brief looking at the point as if it is a vector, return the length
|
||||
[[nodiscard]] constexpr value_type length() const
|
||||
constexpr value_type length() const
|
||||
{
|
||||
return std::sqrt(length_sq());
|
||||
}
|
||||
@@ -747,55 +743,6 @@ inline constexpr auto cross_product(const point_type<F1> &a, const point_type<F2
|
||||
a.m_x * b.m_y - b.m_x * a.m_y);
|
||||
}
|
||||
|
||||
/// \brief return the squared norm of point @a p
|
||||
template <typename F>
|
||||
constexpr F norm_squared(const point_type<F> &p)
|
||||
{
|
||||
return p.m_x * p.m_x + p.m_y * p.m_y + p.m_z * p.m_z;
|
||||
}
|
||||
|
||||
/// \brief return the norm of point @a p
|
||||
template <typename F>
|
||||
constexpr point_type<F> norm(const point_type<F> &p)
|
||||
{
|
||||
return std::sqrt(norm_squared(p));
|
||||
}
|
||||
|
||||
/// \brief return the point where two lines intersect, or an empty value if they don't intersect at all
|
||||
template <typename F>
|
||||
std::optional<cif::point> line_line_intersection(const point_type<F> &p1,
|
||||
const point_type<F> &p2, const point_type<F> &p3, const point_type<F> &p4)
|
||||
{
|
||||
auto p13 = p1 - p3;
|
||||
auto p43 = p4 - p3;
|
||||
if (std::abs(p43.m_x) < std::numeric_limits<F>::epsilon() and std::abs(p43.m_y) < std::numeric_limits<F>::epsilon() and std::abs(p43.m_z) < std::numeric_limits<F>::epsilon())
|
||||
return std::nullopt;
|
||||
|
||||
auto p21 = p2 - p1;
|
||||
if (std::abs(p21.m_x) < std::numeric_limits<F>::epsilon() and std::abs(p21.m_y) < std::numeric_limits<F>::epsilon() and std::abs(p21.m_z) < std::numeric_limits<F>::epsilon())
|
||||
return std::nullopt;
|
||||
|
||||
auto d1343 = cif::dot_product(p43, p13);
|
||||
auto d4321 = cif::dot_product(p43, p21);
|
||||
auto d1321 = cif::dot_product(p13, p21);
|
||||
auto d4343 = cif::dot_product(p43, p43);
|
||||
auto d2121 = cif::dot_product(p21, p21);
|
||||
|
||||
auto denom = d2121 * d4343 - d4321 * d4321;
|
||||
if (std::abs(denom) < std::numeric_limits<F>::epsilon())
|
||||
return std::nullopt;
|
||||
|
||||
auto numer = d1343 * d4321 - d1321 * d4343;
|
||||
|
||||
auto mua = numer / denom;
|
||||
auto mub = (d1343 + d4321 * mua) / d4343;
|
||||
|
||||
auto pa = p1 + mua * p21;
|
||||
auto pb = p3 + mub * p43;
|
||||
|
||||
return { (pa + pb) / 2 };
|
||||
}
|
||||
|
||||
/// \brief return the angle in degrees between the vectors from point @a p2 to @a p1 and @a p2 to @a p3
|
||||
template <typename F>
|
||||
constexpr auto angle(const point_type<F> &p1, const point_type<F> &p2, const point_type<F> &p3)
|
||||
@@ -803,7 +750,7 @@ constexpr auto angle(const point_type<F> &p1, const point_type<F> &p2, const poi
|
||||
point_type<F> v1 = p1 - p2;
|
||||
point_type<F> v2 = p3 - p2;
|
||||
|
||||
return std::acos(dot_product(v1, v2) / (v1.length() * v2.length())) * 180 / std::numbers::pi_v<F>;
|
||||
return std::acos(dot_product(v1, v2) / (v1.length() * v2.length())) * 180 / kPI;
|
||||
}
|
||||
|
||||
/// \brief return the dihedral angle in degrees for the four points @a p1, @a p2, @a p3 and @a p4
|
||||
@@ -830,7 +777,7 @@ constexpr auto dihedral_angle(const point_type<F> &p1, const point_type<F> &p2,
|
||||
u = dot_product(p, x) / std::sqrt(u);
|
||||
v = dot_product(p, y) / std::sqrt(v);
|
||||
if (u != 0 or v != 0)
|
||||
result = std::atan2(v, u) * static_cast<F>(180 / std::numbers::pi_v<F>);
|
||||
result = std::atan2(v, u) * static_cast<F>(180 / kPI);
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -859,9 +806,6 @@ constexpr auto distance_point_to_line(const point_type<F> &l1, const point_type<
|
||||
return cross.length() / line.length();
|
||||
}
|
||||
|
||||
/// \brief return the smallest sphere around the points in @a pts
|
||||
std::tuple<point, float> smallest_sphere_around_points(std::vector<point> pts);
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
/**
|
||||
* @brief For e.g. simulated annealing, returns a new point that is moved in
|
||||
@@ -876,7 +820,7 @@ point nudge(point p, float offset);
|
||||
quaternion construct_from_angle_axis(float angle, point axis);
|
||||
|
||||
/// \brief Return a tuple of an angle and an axis for quaternion @a q
|
||||
std::tuple<float, point> quaternion_to_angle_axis(quaternion q);
|
||||
std::tuple<double, point> quaternion_to_angle_axis(quaternion q);
|
||||
|
||||
/// @brief Given four points and an angle, return the quaternion required to rotate
|
||||
/// point p4 along the p2-p3 axis and around point p3 to obtain the required within
|
||||
@@ -902,4 +846,74 @@ quaternion align_points(const std::vector<point> &a, const std::vector<point> &b
|
||||
/// \brief The RMSd for the points in \a a and \a b
|
||||
double RMSd(const std::vector<point> &a, const std::vector<point> &b);
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
/**
|
||||
* @brief Helper class to generate evenly divided points on a sphere
|
||||
*
|
||||
* We use a fibonacci sphere to calculate even distribution of the dots
|
||||
*
|
||||
* @tparam N The number of points on the sphere is 2 * N + 1
|
||||
*/
|
||||
template <int N>
|
||||
class spherical_dots
|
||||
{
|
||||
public:
|
||||
/// \brief the number of points
|
||||
constexpr static int P = 2 * N * 1;
|
||||
|
||||
/// \brief the *weight* of the fibonacci sphere
|
||||
constexpr static double W = (4 * kPI) / P;
|
||||
|
||||
/// \brief the internal storage type
|
||||
using array_type = typename std::array<point, P>;
|
||||
|
||||
/// \brief iterator type
|
||||
using iterator = typename array_type::const_iterator;
|
||||
|
||||
/// \brief singleton instance
|
||||
static spherical_dots &instance()
|
||||
{
|
||||
static spherical_dots sInstance;
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
/// \brief The number of points
|
||||
std::size_t size() const { return P; }
|
||||
|
||||
/// \brief Access a point by index
|
||||
const point operator[](uint32_t inIx) const { return m_points[inIx]; }
|
||||
|
||||
/// \brief iterator pointing to the first point
|
||||
iterator begin() const { return m_points.begin(); }
|
||||
|
||||
/// \brief iterator pointing past the last point
|
||||
iterator end() const { return m_points.end(); }
|
||||
|
||||
/// \brief return the *weight*,
|
||||
double weight() const { return W; }
|
||||
|
||||
spherical_dots()
|
||||
{
|
||||
const double
|
||||
kGoldenRatio = (1 + std::sqrt(5.0)) / 2;
|
||||
|
||||
auto p = m_points.begin();
|
||||
|
||||
for (int32_t i = -N; i <= N; ++i)
|
||||
{
|
||||
double lat = std::asin((2.0 * i) / P);
|
||||
double lon = std::fmod(i, kGoldenRatio) * 2 * kPI / kGoldenRatio;
|
||||
|
||||
p->m_x = std::sin(lon) * std::cos(lat);
|
||||
p->m_y = std::cos(lon) * std::cos(lat);
|
||||
p->m_z = std::sin(lat);
|
||||
|
||||
++p;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
array_type m_points;
|
||||
};
|
||||
|
||||
} // namespace cif
|
||||
|
||||
@@ -29,441 +29,66 @@
|
||||
#include "cif++/item.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <initializer_list>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* @file row.hpp
|
||||
*
|
||||
*
|
||||
* The class cif::row should be an opaque type. It is used to store the
|
||||
* internal data per row in a category. You should use cif::row_handle
|
||||
* to get access to the contents in a row.
|
||||
*
|
||||
*
|
||||
* One could think of rows as vectors of cif::item. But internally
|
||||
* that's not the case.
|
||||
*
|
||||
*
|
||||
* You can access the values of stored items by name or index.
|
||||
* The return value of operator[] is a reference to a cif::item_value object.
|
||||
*
|
||||
* The return value of operator[] is an cif::item_handle object.
|
||||
*
|
||||
* @code {.cpp}
|
||||
* cif::category &atom_site = my_db["atom_site"];
|
||||
* cif::row_handle rh = atom_site.front();
|
||||
*
|
||||
*
|
||||
* // by name:
|
||||
* std::string name = rh["label_atom_id"].get<std::string>();
|
||||
*
|
||||
* std::string name = rh["label_atom_id"].as<std::string>();
|
||||
*
|
||||
* // by index:
|
||||
* uint16_t ix = atom_site.get_item_ix("label_atom_id");
|
||||
* assert(rh[ix].get<std::string() == name);
|
||||
* assert(rh[ix].as<std::string() == name);
|
||||
* @endcode
|
||||
*
|
||||
*
|
||||
* There some template magic here to allow easy extracting of data
|
||||
* from rows. This can be done using cif::tie e.g.:
|
||||
*
|
||||
*
|
||||
* @code {.cpp}
|
||||
* std::string name;
|
||||
* float x, y, z;
|
||||
*
|
||||
*
|
||||
* cif::tie(name, x, y, z) = rh.get("label_atom_id", "cartn_x", "cartn_y", "cartn_z");
|
||||
* @endcode
|
||||
*
|
||||
*
|
||||
* However, a more modern way uses structured binding:
|
||||
*
|
||||
*
|
||||
* @code {.cpp}
|
||||
* const auto &[name, x, y, z] = rh.get<std::string,float,float,float>("label_atom_id", "cartn_x", "cartn_y", "cartn_z");
|
||||
* @endcode
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
namespace cif
|
||||
{
|
||||
|
||||
class category;
|
||||
|
||||
namespace cql
|
||||
{
|
||||
struct connection_impl;
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template <typename... C>
|
||||
struct get_row_result;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
/// \brief the row class, this one is not directly accessible from the outside
|
||||
|
||||
class row : public std::vector<item_value>
|
||||
{
|
||||
public:
|
||||
row() = default;
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Return the item_value pointer for item at index @a ix
|
||||
*/
|
||||
item_value *get(uint16_t ix)
|
||||
{
|
||||
if (ix >= size())
|
||||
resize(ix + 1);
|
||||
return &data()[ix];
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the const item_value pointer for item at index @a ix
|
||||
*/
|
||||
[[nodiscard]] const item_value *get(uint16_t ix) const
|
||||
{
|
||||
return ix < size() ? &data()[ix] : nullptr;
|
||||
}
|
||||
|
||||
void set(uint16_t ix, item_value v)
|
||||
{
|
||||
if (ix >= size())
|
||||
resize(ix + 1);
|
||||
operator[](ix) = std::move(v);
|
||||
}
|
||||
|
||||
friend class category;
|
||||
friend class category_index;
|
||||
|
||||
template <bool, typename...>
|
||||
friend class iterator_impl_base;
|
||||
|
||||
row *m_next = nullptr;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
/// \brief row_handle is the way to access data stored in rows
|
||||
|
||||
class row_handle
|
||||
{
|
||||
public:
|
||||
/** @cond */
|
||||
template <bool>
|
||||
friend struct item_handle_base;
|
||||
friend class category;
|
||||
friend class category_index;
|
||||
friend class row_initializer;
|
||||
friend class const_row_handle;
|
||||
|
||||
template <bool, typename...>
|
||||
friend class iterator_impl_base;
|
||||
|
||||
row_handle() = default;
|
||||
virtual ~row_handle() = default;
|
||||
|
||||
row_handle(const row_handle &) = default;
|
||||
row_handle(row_handle &&) = default;
|
||||
row_handle &operator=(const row_handle &) = default;
|
||||
row_handle &operator=(row_handle &&) = default;
|
||||
|
||||
/** @endcond */
|
||||
|
||||
/// \brief constructor taking a category @a cat and a row @a r
|
||||
row_handle(category &cat, row &r)
|
||||
: m_category(&cat)
|
||||
, m_row(&r)
|
||||
{
|
||||
}
|
||||
|
||||
/// \brief return the category this row belongs to
|
||||
[[nodiscard]] category &get_category() const
|
||||
{
|
||||
return *m_category;
|
||||
}
|
||||
|
||||
/// \brief return the row ID
|
||||
[[nodiscard]] int64_t row_id() const
|
||||
{
|
||||
return reinterpret_cast<int64_t>(m_row);
|
||||
}
|
||||
|
||||
/// \brief Return true if the row is empty or uninitialised
|
||||
[[nodiscard]] bool empty() const
|
||||
{
|
||||
return m_category == nullptr or m_row == nullptr;
|
||||
}
|
||||
|
||||
/// \brief convenience method to test for empty()
|
||||
explicit operator bool() const
|
||||
{
|
||||
return not empty();
|
||||
}
|
||||
|
||||
/// \brief return the count of the items
|
||||
[[nodiscard]] size_t size() const { return m_row->size(); }
|
||||
|
||||
/// \brief return a cif::item_handle to the item in item @a item_ix
|
||||
item_handle operator[](uint16_t item_ix)
|
||||
{
|
||||
return { *m_category, *m_row, item_ix };
|
||||
}
|
||||
|
||||
/// \brief return a cif::item_handle to the item in item @a item_ix
|
||||
const item_handle operator[](uint16_t item_ix) const
|
||||
{
|
||||
return { *m_category, *m_row, item_ix };
|
||||
}
|
||||
|
||||
/// \brief return a cif::item_handle to the item in the item named @a item_name
|
||||
item_handle operator[](std::string_view item_name)
|
||||
{
|
||||
return { *m_category, *m_row, add_item(item_name) };
|
||||
}
|
||||
|
||||
/// \brief return a cif::item_handle to the item in the item named @a item_name
|
||||
const item_handle operator[](std::string_view item_name) const
|
||||
{
|
||||
return { *m_category, *m_row, get_item_ix(item_name) };
|
||||
}
|
||||
|
||||
/// \brief assign each of the items named in @a values to their respective value
|
||||
void assign(const std::vector<item> &values, bool updateLinked = true)
|
||||
{
|
||||
for (auto &value : values)
|
||||
assign(value, updateLinked);
|
||||
}
|
||||
|
||||
/** \brief assign the value @a value to the item named @a name
|
||||
*
|
||||
* If updateLinked it true, linked records are updated as well.
|
||||
* That means that if item @a name is part of the link definition
|
||||
* and the link results in a linked record in another category
|
||||
* this record in the linked category is updated as well.
|
||||
*
|
||||
* If validate is true, which is default, the assigned value is
|
||||
* checked to see if it conforms to the rules defined in the dictionary
|
||||
*/
|
||||
|
||||
void assign(std::string_view name, item_value value, bool updateLinked, bool validate = true)
|
||||
{
|
||||
assign(add_item(name), std::move(value), updateLinked, validate);
|
||||
}
|
||||
|
||||
/** \brief assign the value @a value to item at index @a item
|
||||
*
|
||||
* If updateLinked it true, linked records are updated as well.
|
||||
* That means that if item @a item is part of the link definition
|
||||
* and the link results in a linked record in another category
|
||||
* this record in the linked category is updated as well.
|
||||
*
|
||||
* If validate is true, which is default, the assigned value is
|
||||
* checked to see if it conforms to the rules defined in the dictionary
|
||||
*/
|
||||
|
||||
void assign(uint16_t item, item_value value, bool updateLinked, bool validate = true);
|
||||
|
||||
/// \brief Return an object that can be used in combination with cif::tie
|
||||
/// to assign the values for the items @a items
|
||||
template <typename... C>
|
||||
[[nodiscard]] auto get(C... items) const
|
||||
{
|
||||
return detail::get_row_result<C...>(*this, { get_item_ix(items)... });
|
||||
}
|
||||
|
||||
/// \brief Return a tuple of values of types @a Ts for the items @a items
|
||||
template <typename... Ts, typename... C>
|
||||
std::tuple<Ts...> get(C... items) const
|
||||
requires(sizeof...(Ts) == sizeof...(C) and sizeof...(C) != 1)
|
||||
{
|
||||
return detail::get_row_result<Ts...>(*this, { get_item_ix(items)... });
|
||||
}
|
||||
|
||||
/// \brief Get the value of item @a item cast to type @a T
|
||||
template <typename T>
|
||||
[[nodiscard]] T get(std::string_view item) const
|
||||
{
|
||||
return operator[](get_item_ix(item)).template get<T>();
|
||||
}
|
||||
|
||||
/// \brief compare two rows
|
||||
bool operator==(const row_handle &rhs) const { return m_category == rhs.m_category and m_row == rhs.m_row; }
|
||||
|
||||
/// \brief compare two rows
|
||||
bool operator!=(const row_handle &rhs) const { return m_category != rhs.m_category or m_row != rhs.m_row; }
|
||||
|
||||
protected:
|
||||
/// Return the index number for the item named @a name
|
||||
[[nodiscard]] uint16_t get_item_ix(std::string_view name) const;
|
||||
|
||||
/// Return the name for the item with index number @a ix
|
||||
[[nodiscard]] std::string_view get_item_name(uint16_t ix) const;
|
||||
|
||||
friend cql::connection_impl;
|
||||
|
||||
/// Return the actual row
|
||||
[[nodiscard]] auto get_row() const
|
||||
{
|
||||
return m_row;
|
||||
}
|
||||
|
||||
category *m_category = nullptr; ///< The category
|
||||
row *m_row = nullptr; ///< The row
|
||||
|
||||
private:
|
||||
/// @cond
|
||||
uint16_t add_item(std::string_view name);
|
||||
|
||||
void assign(const item &i, bool updateLinked)
|
||||
{
|
||||
assign(i.name(), i.value(), updateLinked);
|
||||
}
|
||||
|
||||
/// @endcond
|
||||
};
|
||||
|
||||
/// A const version of row_handle.
|
||||
|
||||
class const_row_handle
|
||||
{
|
||||
public:
|
||||
/** @cond */
|
||||
template <bool>
|
||||
friend struct item_handle_base;
|
||||
friend class category;
|
||||
friend class category_index;
|
||||
friend class row_initializer;
|
||||
|
||||
template <bool, typename...>
|
||||
friend class iterator_impl_base;
|
||||
|
||||
const_row_handle() = default;
|
||||
virtual ~const_row_handle() = default;
|
||||
|
||||
const_row_handle(const const_row_handle &) = default;
|
||||
const_row_handle(const_row_handle &&) = default;
|
||||
const_row_handle &operator=(const const_row_handle &) = default;
|
||||
const_row_handle &operator=(const_row_handle &&) = default;
|
||||
|
||||
const_row_handle(row_handle rh)
|
||||
: m_category(rh.m_category)
|
||||
, m_row(rh.m_row)
|
||||
{
|
||||
}
|
||||
|
||||
/** @endcond */
|
||||
|
||||
/// \brief constructor taking a category @a cat and a row @a r
|
||||
const_row_handle(const category &cat, const row &r)
|
||||
: m_category(&cat)
|
||||
, m_row(&r)
|
||||
{
|
||||
}
|
||||
|
||||
/// \brief return the category this row belongs to
|
||||
[[nodiscard]] const category &get_category() const
|
||||
{
|
||||
return *m_category;
|
||||
}
|
||||
|
||||
/// \brief return the row ID
|
||||
[[nodiscard]] int64_t row_id() const
|
||||
{
|
||||
return reinterpret_cast<int64_t>(m_row);
|
||||
}
|
||||
|
||||
/// \brief Return true if the row is empty or uninitialised
|
||||
[[nodiscard]] bool empty() const
|
||||
{
|
||||
return m_category == nullptr or m_row == nullptr;
|
||||
}
|
||||
|
||||
/// \brief convenience method to test for empty()
|
||||
explicit operator bool() const
|
||||
{
|
||||
return not empty();
|
||||
}
|
||||
|
||||
/// \brief return the count of the items
|
||||
[[nodiscard]] size_t size() const { return m_row->size(); }
|
||||
|
||||
/// \brief return a cif::item_handle to the item in item @a item_ix
|
||||
const item_handle operator[](uint16_t item_ix) const
|
||||
{
|
||||
return { *m_category, *m_row, item_ix };
|
||||
}
|
||||
|
||||
/// \brief return a cif::item_handle to the item in the item named @a item_name
|
||||
const item_handle operator[](std::string_view item_name) const
|
||||
{
|
||||
return operator[](get_item_ix(item_name));
|
||||
}
|
||||
|
||||
/// \brief Return an object that can be used in combination with cif::tie
|
||||
/// to assign the values for the items @a items
|
||||
template <typename... C>
|
||||
[[nodiscard]] auto get(C... items) const
|
||||
{
|
||||
return detail::get_row_result<C...>(*this, { get_item_ix(items)... });
|
||||
}
|
||||
|
||||
/// \brief Return a tuple of values of types @a Ts for the items @a items
|
||||
template <typename... Ts, typename... C>
|
||||
std::tuple<Ts...> get(C... items) const
|
||||
requires(sizeof...(Ts) == sizeof...(C) and sizeof...(C) != 1)
|
||||
{
|
||||
return detail::get_row_result<Ts...>(*this, { get_item_ix(items)... });
|
||||
}
|
||||
|
||||
/// \brief Get the value of item @a item cast to type @a T
|
||||
template <typename T>
|
||||
[[nodiscard]] T get(std::string_view item) const
|
||||
{
|
||||
return operator[](get_item_ix(item)).template get<T>();
|
||||
}
|
||||
|
||||
/// \brief compare two rows
|
||||
// bool operator==(const const_row_handle &rhs) const { return m_category == rhs.m_category and m_row == rhs.m_row; }
|
||||
friend bool operator==(const_row_handle a, const_row_handle b)
|
||||
{
|
||||
return a.m_category == b.m_category and a.m_row == b.m_row;
|
||||
}
|
||||
|
||||
/// \brief compare two rows
|
||||
bool operator!=(const const_row_handle &rhs) const { return m_category != rhs.m_category or m_row != rhs.m_row; }
|
||||
|
||||
protected:
|
||||
/// Return the index number for the item named @a name
|
||||
[[nodiscard]] uint16_t get_item_ix(std::string_view name) const;
|
||||
|
||||
/// Return the name for the item with index number @a ix
|
||||
[[nodiscard]] std::string_view get_item_name(uint16_t ix) const;
|
||||
|
||||
friend cql::connection_impl;
|
||||
|
||||
/// Return the actual row
|
||||
[[nodiscard]] auto get_row() const
|
||||
{
|
||||
return m_row;
|
||||
}
|
||||
|
||||
const category *m_category = nullptr; ///< The category
|
||||
const row *m_row = nullptr; ///< The row
|
||||
};
|
||||
|
||||
namespace detail
|
||||
{
|
||||
/// @cond
|
||||
|
||||
/// some helper classes to help create tuple result types
|
||||
// some helper classes to help create tuple result types
|
||||
template <typename... C>
|
||||
struct get_row_result
|
||||
{
|
||||
static constexpr std::size_t N = sizeof...(C);
|
||||
|
||||
get_row_result(const_row_handle r, std::array<uint16_t, N> &&items)
|
||||
: m_row(std::move(r))
|
||||
get_row_result(const row_handle &r, std::array<uint16_t, N> &&items)
|
||||
: m_row(r)
|
||||
, m_items(std::move(items))
|
||||
{
|
||||
}
|
||||
@@ -473,20 +98,19 @@ namespace detail
|
||||
return m_row[m_items[ix]];
|
||||
}
|
||||
|
||||
template <typename... Ts>
|
||||
template <typename... Ts, std::enable_if_t<N == sizeof...(Ts), int> = 0>
|
||||
operator std::tuple<Ts...>() const
|
||||
requires(N == sizeof...(Ts))
|
||||
{
|
||||
return get<Ts...>(std::index_sequence_for<Ts...>{});
|
||||
}
|
||||
|
||||
template <typename... Ts, std::size_t... Is>
|
||||
[[nodiscard]] std::tuple<Ts...> get(std::index_sequence<Is...>) const
|
||||
std::tuple<Ts...> get(std::index_sequence<Is...>) const
|
||||
{
|
||||
return std::tuple<Ts...>{ m_row[m_items[Is]].template get<Ts>()... };
|
||||
return std::tuple<Ts...>{ m_row[m_items[Is]].template as<Ts>()... };
|
||||
}
|
||||
|
||||
const_row_handle m_row;
|
||||
const row_handle &m_row;
|
||||
std::array<uint16_t, N> m_items;
|
||||
};
|
||||
|
||||
@@ -507,7 +131,7 @@ namespace detail
|
||||
// of the row should be equal to the number of items in the tuple
|
||||
// you are trying to tie.
|
||||
|
||||
using RType = std::tuple<std::remove_reference_t<Ts>...>;
|
||||
using RType = std::tuple<typename std::remove_reference<Ts>::type...>;
|
||||
|
||||
m_value = static_cast<RType>(rr);
|
||||
}
|
||||
@@ -515,11 +139,9 @@ namespace detail
|
||||
std::tuple<Ts...> m_value;
|
||||
};
|
||||
|
||||
/// @endcond
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/// \brief similar to std::tie, assign values to each element in @a v from the
|
||||
/// \brief similar to std::tie, assign values to each element in @a v from the
|
||||
/// result of a get on a row_handle.
|
||||
template <typename... Ts>
|
||||
auto tie(Ts &...v)
|
||||
@@ -527,11 +149,229 @@ auto tie(Ts &...v)
|
||||
return detail::tie_wrap<Ts &...>(std::forward<Ts &>(v)...);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
/// \brief the row class, this one is not directly accessible from the outside
|
||||
|
||||
class row : public std::vector<item_value>
|
||||
{
|
||||
public:
|
||||
row() = default;
|
||||
|
||||
/**
|
||||
* @brief Return the item_value pointer for item at index @a ix
|
||||
*/
|
||||
item_value* get(uint16_t ix)
|
||||
{
|
||||
return ix < size() ? &data()[ix] : nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the const item_value pointer for item at index @a ix
|
||||
*/
|
||||
const item_value* get(uint16_t ix) const
|
||||
{
|
||||
return ix < size() ? &data()[ix] : nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class category;
|
||||
friend class category_index;
|
||||
|
||||
template <typename, typename...>
|
||||
friend class iterator_impl;
|
||||
|
||||
void append(uint16_t ix, item_value &&iv)
|
||||
{
|
||||
if (ix >= size())
|
||||
resize(ix + 1);
|
||||
|
||||
at(ix) = std::move(iv);
|
||||
}
|
||||
|
||||
void remove(uint16_t ix)
|
||||
{
|
||||
if (ix < size())
|
||||
at(ix) = item_value{};
|
||||
}
|
||||
|
||||
row *m_next = nullptr;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
/// \brief row_handle is the way to access data stored in rows
|
||||
|
||||
class row_handle
|
||||
{
|
||||
public:
|
||||
/** @cond */
|
||||
friend struct item_handle;
|
||||
friend class category;
|
||||
friend class category_index;
|
||||
friend class row_initializer;
|
||||
template <typename, typename...> friend class iterator_impl;
|
||||
|
||||
row_handle() = default;
|
||||
|
||||
row_handle(const row_handle &) = default;
|
||||
row_handle(row_handle &&) = default;
|
||||
|
||||
row_handle &operator=(const row_handle &) = default;
|
||||
row_handle &operator=(row_handle &&) = default;
|
||||
|
||||
/** @endcond */
|
||||
|
||||
/// \brief constructor taking a category @a cat and a row @a r
|
||||
row_handle(const category &cat, const row &r)
|
||||
: m_category(const_cast<category *>(&cat))
|
||||
, m_row(const_cast<row *>(&r))
|
||||
{
|
||||
}
|
||||
|
||||
/// \brief return the category this row belongs to
|
||||
const category &get_category() const
|
||||
{
|
||||
return *m_category;
|
||||
}
|
||||
|
||||
/// \brief Return true if the row is empty or uninitialised
|
||||
bool empty() const
|
||||
{
|
||||
return m_category == nullptr or m_row == nullptr;
|
||||
}
|
||||
|
||||
/// \brief convenience method to test for empty()
|
||||
explicit operator bool() const
|
||||
{
|
||||
return not empty();
|
||||
}
|
||||
|
||||
/// \brief return a cif::item_handle to the item in item @a item_ix
|
||||
item_handle operator[](uint16_t item_ix)
|
||||
{
|
||||
return empty() ? item_handle::s_null_item : item_handle(item_ix, *this);
|
||||
}
|
||||
|
||||
/// \brief return a const cif::item_handle to the item in item @a item_ix
|
||||
const item_handle operator[](uint16_t item_ix) const
|
||||
{
|
||||
return empty() ? item_handle::s_null_item : item_handle(item_ix, const_cast<row_handle &>(*this));
|
||||
}
|
||||
|
||||
/// \brief return a cif::item_handle to the item in the item named @a item_name
|
||||
item_handle operator[](std::string_view item_name)
|
||||
{
|
||||
return empty() ? item_handle::s_null_item : item_handle(add_item(item_name), *this);
|
||||
}
|
||||
|
||||
/// \brief return a const cif::item_handle to the item in the item named @a item_name
|
||||
const item_handle operator[](std::string_view item_name) const
|
||||
{
|
||||
return empty() ? item_handle::s_null_item : item_handle(get_item_ix(item_name), const_cast<row_handle &>(*this));
|
||||
}
|
||||
|
||||
/// \brief Return an object that can be used in combination with cif::tie
|
||||
/// to assign the values for the items @a items
|
||||
template <typename... C>
|
||||
auto get(C... items) const
|
||||
{
|
||||
return detail::get_row_result<C...>(*this, { get_item_ix(items)... });
|
||||
}
|
||||
|
||||
/// \brief Return a tuple of values of types @a Ts for the items @a items
|
||||
template <typename... Ts, typename... C, std::enable_if_t<sizeof...(Ts) == sizeof...(C) and sizeof...(C) != 1, int> = 0>
|
||||
std::tuple<Ts...> get(C... items) const
|
||||
{
|
||||
return detail::get_row_result<Ts...>(*this, { get_item_ix(items)... });
|
||||
}
|
||||
|
||||
/// \brief Get the value of item @a item cast to type @a T
|
||||
template <typename T>
|
||||
T get(const char *item) const
|
||||
{
|
||||
return operator[](get_item_ix(item)).template as<T>();
|
||||
}
|
||||
|
||||
/// \brief Get the value of item @a item cast to type @a T
|
||||
template <typename T>
|
||||
T get(std::string_view item) const
|
||||
{
|
||||
return operator[](get_item_ix(item)).template as<T>();
|
||||
}
|
||||
|
||||
/// \brief assign each of the items named in @a values to their respective value
|
||||
void assign(const std::vector<item> &values)
|
||||
{
|
||||
for (auto &value : values)
|
||||
assign(value, true);
|
||||
}
|
||||
|
||||
/** \brief assign the value @a value to the item named @a name
|
||||
*
|
||||
* If updateLinked it true, linked records are updated as well.
|
||||
* That means that if item @a name is part of the link definition
|
||||
* and the link results in a linked record in another category
|
||||
* this record in the linked category is updated as well.
|
||||
*
|
||||
* If validate is true, which is default, the assigned value is
|
||||
* checked to see if it conforms to the rules defined in the dictionary
|
||||
*/
|
||||
|
||||
void assign(std::string_view name, std::string_view value, bool updateLinked, bool validate = true)
|
||||
{
|
||||
assign(add_item(name), value, updateLinked, validate);
|
||||
}
|
||||
|
||||
/** \brief assign the value @a value to item at index @a item
|
||||
*
|
||||
* If updateLinked it true, linked records are updated as well.
|
||||
* That means that if item @a item is part of the link definition
|
||||
* and the link results in a linked record in another category
|
||||
* this record in the linked category is updated as well.
|
||||
*
|
||||
* If validate is true, which is default, the assigned value is
|
||||
* checked to see if it conforms to the rules defined in the dictionary
|
||||
*/
|
||||
|
||||
void assign(uint16_t item, std::string_view value, bool updateLinked, bool validate = true);
|
||||
|
||||
/// \brief compare two rows
|
||||
bool operator==(const row_handle &rhs) const { return m_category == rhs.m_category and m_row == rhs.m_row; }
|
||||
|
||||
/// \brief compare two rows
|
||||
bool operator!=(const row_handle &rhs) const { return m_category != rhs.m_category or m_row != rhs.m_row; }
|
||||
|
||||
private:
|
||||
uint16_t get_item_ix(std::string_view name) const;
|
||||
std::string_view get_item_name(uint16_t ix) const;
|
||||
|
||||
uint16_t add_item(std::string_view name);
|
||||
|
||||
row *get_row()
|
||||
{
|
||||
return m_row;
|
||||
}
|
||||
|
||||
const row *get_row() const
|
||||
{
|
||||
return m_row;
|
||||
}
|
||||
|
||||
void assign(const item &i, bool updateLinked)
|
||||
{
|
||||
assign(i.name(), i.value(), updateLinked);
|
||||
}
|
||||
|
||||
void swap(uint16_t item, row_handle &r);
|
||||
|
||||
category *m_category = nullptr;
|
||||
row *m_row = nullptr;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief The class row_initializer is a list of cif::item's.
|
||||
*
|
||||
*
|
||||
* This class is used to construct new rows, it allows to
|
||||
* group a list of item name and value pairs and pass it
|
||||
* in one go to the constructing function.
|
||||
@@ -557,24 +397,18 @@ class row_initializer : public std::vector<item>
|
||||
}
|
||||
|
||||
/// \brief constructor taking a range of items
|
||||
template <typename ItemIter>
|
||||
template <typename ItemIter, std::enable_if_t<std::is_same_v<typename ItemIter::value_type, item>, int> = 0>
|
||||
row_initializer(ItemIter b, ItemIter e)
|
||||
requires(std::is_constructible_v<item, typename ItemIter::value_type>)
|
||||
: std::vector<item>(b, e)
|
||||
{
|
||||
}
|
||||
|
||||
/// \brief constructor taking the values of an existing row
|
||||
row_initializer(row_handle rh)
|
||||
: cif::row_initializer(const_row_handle{ rh })
|
||||
{
|
||||
}
|
||||
row_initializer(row_handle rh);
|
||||
|
||||
/// Constructor
|
||||
row_initializer(const_row_handle rh);
|
||||
|
||||
/// \brief set the value for item name @a name to @a value
|
||||
void set_value(std::string name, item_value value);
|
||||
void set_value(std::string_view name, std::string_view value);
|
||||
|
||||
/// \brief set the value for item based on @a i
|
||||
void set_value(const item &i)
|
||||
@@ -583,19 +417,13 @@ class row_initializer : public std::vector<item>
|
||||
}
|
||||
|
||||
/// \brief set the value for item name @a name to @a value, but only if the item did not have a value already
|
||||
void set_value_if_empty(std::string name, item_value value);
|
||||
void set_value_if_empty(std::string_view name, std::string_view value);
|
||||
|
||||
/// \brief set the value for item @a i, but only if the item did not have a value already
|
||||
void set_value_if_empty(const item &i)
|
||||
{
|
||||
set_value_if_empty(i.name(), i.value());
|
||||
}
|
||||
|
||||
/// \brief enable emplace_back for more complex items (floats with precission)
|
||||
auto emplace_back(std::string name, item_value value)
|
||||
{
|
||||
return std::vector<item>::emplace_back(item(std::forward<std::string>(name), std::forward<item_value>(value)));
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace cif
|
||||
} // namespace cif
|
||||
@@ -35,7 +35,7 @@
|
||||
#include <string>
|
||||
|
||||
#if defined(__cpp_impl_three_way_comparison)
|
||||
# include <utility>
|
||||
#include <compare>
|
||||
#endif
|
||||
|
||||
/** \file cif++/symmetry.hpp
|
||||
@@ -95,7 +95,7 @@ extern CIFPP_EXPORT const std::size_t kNrOfSpaceGroups;
|
||||
struct symop_data
|
||||
{
|
||||
/// \brief constructor
|
||||
constexpr symop_data(const std::array<int, 15> &data) noexcept
|
||||
constexpr symop_data(const std::array<int, 15> &data)
|
||||
: m_packed((data[0] bitand 0x03ULL) << 34 bitor
|
||||
(data[1] bitand 0x03ULL) << 32 bitor
|
||||
(data[2] bitand 0x03ULL) << 30 bitor
|
||||
@@ -127,20 +127,20 @@ struct symop_data
|
||||
}
|
||||
|
||||
/// \brief return an int representing the value stored in the two bits at offset @a offset
|
||||
[[nodiscard]] inline constexpr int unpack3(int offset) const
|
||||
inline constexpr int unpack3(int offset) const
|
||||
{
|
||||
int result = static_cast<int>((m_packed >> offset) bitand 0x03);
|
||||
int result = (m_packed >> offset) bitand 0x03;
|
||||
return result == 3 ? -1 : result;
|
||||
}
|
||||
|
||||
/// \brief return an int representing the value stored in the three bits at offset @a offset
|
||||
[[nodiscard]] inline constexpr int unpack7(int offset) const
|
||||
inline constexpr int unpack7(int offset) const
|
||||
{
|
||||
return static_cast<int>((m_packed >> offset) bitand 0x07);
|
||||
return (m_packed >> offset) bitand 0x07;
|
||||
}
|
||||
|
||||
/// \brief return an array of 15 ints representing the values stored
|
||||
[[nodiscard]] constexpr std::array<int, 15> data() const
|
||||
constexpr std::array<int, 15> data() const
|
||||
{
|
||||
return {
|
||||
unpack3(34),
|
||||
@@ -182,16 +182,16 @@ struct symop_data
|
||||
struct symop_datablock
|
||||
{
|
||||
/// \brief constructor
|
||||
constexpr symop_datablock(int spacegroup, int rotational_number, const std::array<int, 15> &rt_data) noexcept
|
||||
constexpr symop_datablock(int spacegroup, int rotational_number, const std::array<int, 15> &rt_data)
|
||||
: m_v((spacegroup bitand 0xffffULL) << 48 bitor
|
||||
(rotational_number bitand 0xffULL) << 40 bitor
|
||||
symop_data(rt_data).m_packed)
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] int spacegroup() const { return m_v >> 48; } ///< Return the spacegroup
|
||||
[[nodiscard]] symop_data symop() const { return { m_v }; } ///< Return the symmetry operation
|
||||
[[nodiscard]] uint8_t rotational_number() const { return (m_v >> 40) bitand 0xff; } ///< Return the rotational_number
|
||||
uint16_t spacegroup() const { return m_v >> 48; } ///< Return the spacegroup
|
||||
symop_data symop() const { return symop_data(m_v); } ///< Return the symmetry operation
|
||||
uint8_t rotational_number() const { return (m_v >> 40) bitand 0xff; } ///< Return the rotational_number
|
||||
|
||||
private:
|
||||
uint64_t m_v;
|
||||
@@ -249,7 +249,7 @@ struct sym_op
|
||||
/** @endcond */
|
||||
|
||||
/// \brief return true if this sym_op is the identity operator
|
||||
[[nodiscard]] constexpr bool is_identity() const
|
||||
constexpr bool is_identity() const
|
||||
{
|
||||
return m_nr == 1 and m_ta == 5 and m_tb == 5 and m_tc == 5;
|
||||
}
|
||||
@@ -261,7 +261,7 @@ struct sym_op
|
||||
}
|
||||
|
||||
/// \brief return the content encoded in a string
|
||||
[[nodiscard]] std::string string() const;
|
||||
std::string string() const;
|
||||
|
||||
#if defined(__cpp_impl_three_way_comparison)
|
||||
/// \brief a default spaceship operator
|
||||
@@ -389,18 +389,18 @@ class cell
|
||||
/// \brief constructor that takes the appropriate values from the *cell* category in datablock @a db
|
||||
cell(const datablock &db);
|
||||
|
||||
[[nodiscard]] float get_a() const { return m_a; } ///< return dimension a
|
||||
[[nodiscard]] float get_b() const { return m_b; } ///< return dimension b
|
||||
[[nodiscard]] float get_c() const { return m_c; } ///< return dimension c
|
||||
float get_a() const { return m_a; } ///< return dimension a
|
||||
float get_b() const { return m_b; } ///< return dimension b
|
||||
float get_c() const { return m_c; } ///< return dimension c
|
||||
|
||||
[[nodiscard]] float get_alpha() const { return m_alpha; } ///< return angle alpha
|
||||
[[nodiscard]] float get_beta() const { return m_beta; } ///< return angle beta
|
||||
[[nodiscard]] float get_gamma() const { return m_gamma; } ///< return angle gamma
|
||||
float get_alpha() const { return m_alpha; } ///< return angle alpha
|
||||
float get_beta() const { return m_beta; } ///< return angle beta
|
||||
float get_gamma() const { return m_gamma; } ///< return angle gamma
|
||||
|
||||
[[nodiscard]] float get_volume() const; ///< return the calculated volume for this cell
|
||||
float get_volume() const; ///< return the calculated volume for this cell
|
||||
|
||||
[[nodiscard]] matrix3x3<float> get_orthogonal_matrix() const { return m_orthogonal; } ///< return the matrix to use to transform coordinates from fractional to orthogonal
|
||||
[[nodiscard]] matrix3x3<float> get_fractional_matrix() const { return m_fractional; } ///< return the matrix to use to transform coordinates from orthogonal to fractional
|
||||
matrix3x3<float> get_orthogonal_matrix() const { return m_orthogonal; } ///< return the matrix to use to transform coordinates from fractional to orthogonal
|
||||
matrix3x3<float> get_fractional_matrix() const { return m_fractional; } ///< return the matrix to use to transform coordinates from orthogonal to fractional
|
||||
|
||||
private:
|
||||
void init();
|
||||
@@ -448,8 +448,8 @@ class spacegroup : public std::vector<transformation>
|
||||
/// \brief constructor using the spacegroup number @a nr
|
||||
spacegroup(int nr);
|
||||
|
||||
[[nodiscard]] int get_nr() const { return m_nr; } ///< Return the nr
|
||||
[[nodiscard]] std::string get_name() const; ///< Return the name
|
||||
int get_nr() const { return m_nr; } ///< Return the nr
|
||||
std::string get_name() const; ///< Return the name
|
||||
|
||||
/** \brief perform a spacegroup operation on point @a pt using
|
||||
* cell @a c and sym_op @a symop
|
||||
@@ -460,7 +460,7 @@ class spacegroup : public std::vector<transformation>
|
||||
/** \brief perform an inverse spacegroup operation on point @a pt using
|
||||
* cell @a c and sym_op @a symop
|
||||
*/
|
||||
[[nodiscard]] point inverse(const point &pt, const cell &c, sym_op symop) const;
|
||||
point inverse(const point &pt, const cell &c, sym_op symop) const;
|
||||
|
||||
private:
|
||||
int m_nr;
|
||||
@@ -486,9 +486,9 @@ class crystal
|
||||
}
|
||||
|
||||
/// \brief constructor using cell @a c and spacegroup @a sg
|
||||
crystal(const cell &c, spacegroup sg)
|
||||
crystal(const cell &c, const spacegroup &sg)
|
||||
: m_cell(c)
|
||||
, m_spacegroup(std::move(sg))
|
||||
, m_spacegroup(sg)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -499,24 +499,24 @@ class crystal
|
||||
crystal &operator=(crystal &&) = default;
|
||||
/** @endcond */
|
||||
|
||||
[[nodiscard]] const cell &get_cell() const { return m_cell; } ///< Return the cell
|
||||
[[nodiscard]] const spacegroup &get_spacegroup() const { return m_spacegroup; } ///< Return the spacegroup
|
||||
const cell &get_cell() const { return m_cell; } ///< Return the cell
|
||||
const spacegroup &get_spacegroup() const { return m_spacegroup; } ///< Return the spacegroup
|
||||
|
||||
/// \brief Return the symmetry copy of point @a pt using symmetry operation @a symop
|
||||
[[nodiscard]] point symmetry_copy(const point &pt, sym_op symop) const
|
||||
point symmetry_copy(const point &pt, sym_op symop) const
|
||||
{
|
||||
return m_spacegroup(pt, m_cell, symop);
|
||||
}
|
||||
|
||||
/// \brief Return the symmetry copy of point @a pt using the inverse of symmetry operation @a symop
|
||||
[[nodiscard]] point inverse_symmetry_copy(const point &pt, sym_op symop) const
|
||||
point inverse_symmetry_copy(const point &pt, sym_op symop) const
|
||||
{
|
||||
return m_spacegroup.inverse(pt, m_cell, symop);
|
||||
}
|
||||
|
||||
/// \brief Return a tuple consisting of distance, new location and symmetry operation
|
||||
/// for the point @a b with respect to point @a a.
|
||||
[[nodiscard]] std::tuple<float, point, sym_op> closest_symmetry_copy(point a, point b) const;
|
||||
std::tuple<float, point, sym_op> closest_symmetry_copy(point a, point b) const;
|
||||
|
||||
private:
|
||||
cell m_cell;
|
||||
|
||||
@@ -29,27 +29,22 @@
|
||||
#include "cif++/exports.hpp"
|
||||
|
||||
#include <charconv>
|
||||
#include <cstddef>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#if __has_include(<experimental/type_traits>)
|
||||
|
||||
# include <experimental/type_traits>
|
||||
#include <experimental/type_traits>
|
||||
namespace std_experimental = std::experimental;
|
||||
|
||||
#else
|
||||
|
||||
// A quick hack to work around the missing is_detected in MSVC
|
||||
/// @cond
|
||||
namespace std_experimental
|
||||
{
|
||||
|
||||
@@ -74,7 +69,6 @@ using is_detected = typename detail::detector<void, Op, Args...>::value_t;
|
||||
template <template <class...> class Op, class... Args>
|
||||
const auto is_detected_v = is_detected<Op, Args...>::value;
|
||||
|
||||
/// @endcond
|
||||
} // namespace std_experimental
|
||||
|
||||
#endif
|
||||
@@ -94,16 +88,16 @@ namespace cif
|
||||
// our own case conversion routines.
|
||||
|
||||
/// \brief return whether string @a is equal to string @a b ignoring changes in character case
|
||||
bool iequals(std::string_view a, std::string_view b) noexcept;
|
||||
bool iequals(std::string_view a, std::string_view b);
|
||||
|
||||
/// \brief compare string @a is to string @a b ignoring changes in character case
|
||||
int icompare(std::string_view a, std::string_view b) noexcept;
|
||||
int icompare(std::string_view a, std::string_view b);
|
||||
|
||||
/// \brief return whether string @a is equal to string @a b ignoring changes in character case
|
||||
bool iequals(const char *a, const char *b) noexcept;
|
||||
bool iequals(const char *a, const char *b);
|
||||
|
||||
/// \brief compare string @a is to string @a b ignoring changes in character case
|
||||
int icompare(const char *a, const char *b) noexcept;
|
||||
int icompare(const char *a, const char *b);
|
||||
|
||||
/// \brief convert the string @a s to lower case in situ
|
||||
void to_lower(std::string &s);
|
||||
@@ -334,6 +328,7 @@ inline char tolower(int ch)
|
||||
[[deprecated("use split_item_name instead")]]
|
||||
std::tuple<std::string, std::string> split_tag_name(std::string_view item_name);
|
||||
|
||||
|
||||
/** \brief return a tuple consisting of the category and item name for @a item_name
|
||||
*
|
||||
* The category name is stripped of its leading underscore character.
|
||||
@@ -360,40 +355,279 @@ std::string cif_id_for_number(int number);
|
||||
std::vector<std::string> word_wrap(const std::string &text, std::size_t width);
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
/// \brief std::from_chars for floating point types.
|
||||
///
|
||||
/// These are optional, there's a selected_charconv class below that selects
|
||||
/// the best option to use based on support by the stl library.
|
||||
///
|
||||
/// I.e. that in case of GNU < 12 (or something) the cif implementation will
|
||||
/// be used, all other cases will use the stl version.
|
||||
|
||||
/// @cond
|
||||
// Code to select a version of from_chars that is implemented...
|
||||
template <typename FloatType, std::enable_if_t<std::is_floating_point_v<FloatType>, int> = 0>
|
||||
std::from_chars_result from_chars(const char *first, const char *last, FloatType &value)
|
||||
{
|
||||
std::from_chars_result result{ first, {} };
|
||||
|
||||
enum State
|
||||
{
|
||||
IntegerSign,
|
||||
Integer,
|
||||
Fraction,
|
||||
ExponentSign,
|
||||
Exponent
|
||||
} state = IntegerSign;
|
||||
int sign = 1;
|
||||
unsigned long long vi = 0;
|
||||
int fl = 0, tz = 0;
|
||||
int exponent_sign = 1;
|
||||
int exponent = 0;
|
||||
bool done = false;
|
||||
|
||||
while (not done and not (bool)result.ec)
|
||||
{
|
||||
char ch = result.ptr != last ? *result.ptr : 0;
|
||||
++result.ptr;
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case IntegerSign:
|
||||
if (ch == '-')
|
||||
{
|
||||
sign = -1;
|
||||
state = Integer;
|
||||
}
|
||||
else if (ch == '+')
|
||||
state = Integer;
|
||||
else if (ch >= '0' and ch <= '9')
|
||||
{
|
||||
vi = ch - '0';
|
||||
state = Integer;
|
||||
}
|
||||
else if (ch == '.')
|
||||
state = Fraction;
|
||||
else
|
||||
result.ec = std::errc::invalid_argument;
|
||||
break;
|
||||
|
||||
case Integer:
|
||||
if (ch >= '0' and ch <= '9')
|
||||
vi = 10 * vi + (ch - '0');
|
||||
else if (ch == 'e' or ch == 'E')
|
||||
state = ExponentSign;
|
||||
else if (ch == '.')
|
||||
state = Fraction;
|
||||
else
|
||||
{
|
||||
done = true;
|
||||
--result.ptr;
|
||||
}
|
||||
break;
|
||||
|
||||
case Fraction:
|
||||
if (ch >= '0' and ch <= '9')
|
||||
{
|
||||
vi = 10 * vi + (ch - '0');
|
||||
|
||||
if (ch == '0')
|
||||
tz += 1;
|
||||
else
|
||||
{
|
||||
fl += tz + 1;
|
||||
tz = 0;
|
||||
}
|
||||
}
|
||||
else if (ch == 'e' or ch == 'E')
|
||||
state = ExponentSign;
|
||||
else
|
||||
{
|
||||
done = true;
|
||||
--result.ptr;
|
||||
}
|
||||
break;
|
||||
|
||||
case ExponentSign:
|
||||
if (ch == '-')
|
||||
{
|
||||
exponent_sign = -1;
|
||||
state = Exponent;
|
||||
}
|
||||
else if (ch == '+')
|
||||
state = Exponent;
|
||||
else if (ch >= '0' and ch <= '9')
|
||||
{
|
||||
exponent = ch - '0';
|
||||
state = Exponent;
|
||||
}
|
||||
else
|
||||
result.ec = std::errc::invalid_argument;
|
||||
break;
|
||||
|
||||
case Exponent:
|
||||
if (ch >= '0' and ch <= '9')
|
||||
exponent = 10 * exponent + (ch - '0');
|
||||
else
|
||||
{
|
||||
done = true;
|
||||
--result.ptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (not (bool)result.ec)
|
||||
{
|
||||
while (tz-- > 0)
|
||||
vi /= 10;
|
||||
|
||||
long double v = std::pow(10, -fl) * vi * sign;
|
||||
if (exponent != 0)
|
||||
v *= std::pow(10, exponent * exponent_sign);
|
||||
|
||||
if (std::isnan(v))
|
||||
result.ec = std::errc::invalid_argument;
|
||||
else if (std::abs(v) > std::numeric_limits<FloatType>::max())
|
||||
result.ec = std::errc::result_out_of_range;
|
||||
|
||||
value = static_cast<FloatType>(v);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// \brief duplication of std::chars_format for deficient STL implementations
|
||||
enum class chars_format
|
||||
{
|
||||
scientific = 1,
|
||||
fixed = 2,
|
||||
// hex,
|
||||
general = fixed | scientific
|
||||
};
|
||||
|
||||
/// \brief a simplistic implementation of std::to_chars for old STL implementations
|
||||
template <typename FloatType, std::enable_if_t<std::is_floating_point_v<FloatType>, int> = 0>
|
||||
std::to_chars_result to_chars(char *first, char *last, FloatType &value, chars_format fmt)
|
||||
{
|
||||
int size = static_cast<int>(last - first);
|
||||
int r = 0;
|
||||
|
||||
switch (fmt)
|
||||
{
|
||||
case chars_format::scientific:
|
||||
if constexpr (std::is_same_v<FloatType, long double>)
|
||||
r = snprintf(first, last - first, "%le", value);
|
||||
else
|
||||
r = snprintf(first, last - first, "%e", value);
|
||||
break;
|
||||
|
||||
case chars_format::fixed:
|
||||
if constexpr (std::is_same_v<FloatType, long double>)
|
||||
r = snprintf(first, last - first, "%lf", value);
|
||||
else
|
||||
r = snprintf(first, last - first, "%f", value);
|
||||
break;
|
||||
|
||||
case chars_format::general:
|
||||
if constexpr (std::is_same_v<FloatType, long double>)
|
||||
r = snprintf(first, last - first, "%lg", value);
|
||||
else
|
||||
r = snprintf(first, last - first, "%g", value);
|
||||
break;
|
||||
}
|
||||
|
||||
std::to_chars_result result;
|
||||
if (r < 0 or r >= size)
|
||||
result = { first, std::errc::value_too_large };
|
||||
else
|
||||
result = { first + r, std::errc() };
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// \brief a simplistic implementation of std::to_chars for old STL implementations
|
||||
template <typename FloatType, std::enable_if_t<std::is_floating_point_v<FloatType>, int> = 0>
|
||||
std::to_chars_result to_chars(char *first, char *last, FloatType &value, chars_format fmt, int precision)
|
||||
{
|
||||
int size = static_cast<int>(last - first);
|
||||
int r = 0;
|
||||
|
||||
switch (fmt)
|
||||
{
|
||||
case chars_format::scientific:
|
||||
if constexpr (std::is_same_v<FloatType, long double>)
|
||||
r = snprintf(first, last - first, "%.*le", precision, value);
|
||||
else
|
||||
r = snprintf(first, last - first, "%.*e", precision, value);
|
||||
break;
|
||||
|
||||
case chars_format::fixed:
|
||||
if constexpr (std::is_same_v<FloatType, long double>)
|
||||
r = snprintf(first, last - first, "%.*lf", precision, value);
|
||||
else
|
||||
r = snprintf(first, last - first, "%.*f", precision, value);
|
||||
break;
|
||||
|
||||
case chars_format::general:
|
||||
if constexpr (std::is_same_v<FloatType, long double>)
|
||||
r = snprintf(first, last - first, "%.*lg", precision, value);
|
||||
else
|
||||
r = snprintf(first, last - first, "%.*g", precision, value);
|
||||
break;
|
||||
}
|
||||
|
||||
std::to_chars_result result;
|
||||
if (r < 0 or r >= size)
|
||||
result = { first, std::errc::value_too_large };
|
||||
else
|
||||
result = { first + r, std::errc() };
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// \brief class that uses our implementation of std::from_chars and std::to_chars
|
||||
template <typename T>
|
||||
using from_chars_function = decltype(std::from_chars(std::declval<const char *>(), std::declval<const char *>(), std::declval<T &>()));
|
||||
struct my_charconv
|
||||
{
|
||||
/// @brief Simply call our version of std::from_chars
|
||||
static std::from_chars_result from_chars(const char *a, const char *b, T &d)
|
||||
{
|
||||
return cif::from_chars(a, b, d);
|
||||
}
|
||||
|
||||
/// @brief Simply call our version of std::to_chars
|
||||
static std::to_chars_result to_chars(char *first, char *last, T &value, chars_format fmt)
|
||||
{
|
||||
return cif::to_chars(first, last, value, fmt);
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief class that uses the STL implementation of std::from_chars and std::to_chars
|
||||
template <typename T>
|
||||
struct std_charconv
|
||||
{
|
||||
/// @brief Simply call std::from_chars
|
||||
static std::from_chars_result from_chars(const char *a, const char *b, T &d)
|
||||
{
|
||||
return std::from_chars(a, b, d);
|
||||
}
|
||||
|
||||
/// @brief Simply call std::to_chars
|
||||
static std::to_chars_result to_chars(char *first, char *last, T &value, chars_format fmt)
|
||||
{
|
||||
return std::to_chars(first, last, value, fmt);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename = void>
|
||||
struct ff_charconv;
|
||||
|
||||
/// \brief helper to find a from_chars function
|
||||
template <typename T>
|
||||
struct ff_charconv<T, typename std::enable_if_t<std::is_floating_point_v<T>>>
|
||||
{
|
||||
static std::from_chars_result from_chars(const char *a, const char *b, T &v);
|
||||
};
|
||||
using from_chars_function = decltype(std::from_chars(std::declval<const char *>(), std::declval<const char *>(), std::declval<T &>()));
|
||||
|
||||
/**
|
||||
* @brief Helper to select the best implementation of charconv based on availability of the
|
||||
* function in the std:: namespace
|
||||
*
|
||||
* @tparam T The type for which we want to find a from_chars/to_chars function
|
||||
*/
|
||||
template <typename T>
|
||||
using charconv = typename std::conditional_t<std_experimental::is_detected_v<from_chars_function, T>, std_charconv<T>, ff_charconv<T>>;
|
||||
using selected_charconv = typename std::conditional_t<std_experimental::is_detected_v<from_chars_function, T>, std_charconv<T>, my_charconv<T>>;
|
||||
|
||||
template <typename T>
|
||||
constexpr auto from_chars(const char *s, const char *e, T &v)
|
||||
{
|
||||
return charconv<T>::from_chars(s, e, v);
|
||||
}
|
||||
|
||||
/// @endcond
|
||||
|
||||
} // namespace cif
|
||||
} // namespace cif
|
||||
@@ -28,44 +28,32 @@
|
||||
|
||||
#include "cif++/exports.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
|
||||
#ifndef STDOUT_FILENO
|
||||
/// @brief For systems that lack this value
|
||||
# define STDOUT_FILENO 1
|
||||
#define STDOUT_FILENO 1
|
||||
#endif
|
||||
|
||||
#ifndef STDERR_FILENO
|
||||
/// @brief For systems that lack this value
|
||||
# define STDERR_FILENO 2
|
||||
#define STDERR_FILENO 2
|
||||
#endif
|
||||
|
||||
#if _WIN32
|
||||
# include <io.h>
|
||||
# define isatty _isatty
|
||||
#include <io.h>
|
||||
#define isatty _isatty
|
||||
#else
|
||||
# include <unistd.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if _MSC_VER
|
||||
# pragma warning(disable : 4996) // unsafe function or variable (strcpy e.g.)
|
||||
# pragma warning(disable : 4068) // unknown pragma
|
||||
# pragma warning(disable : 4100) // unreferenced formal parameter
|
||||
# pragma warning(disable : 4101) // unreferenced local variable
|
||||
# pragma warning(disable : 4702) // unreachable code (too bad, this one. Happens in for loops)
|
||||
|
||||
// Truncation warnings: yes, perhaps, but I think they are okay
|
||||
# pragma warning(disable : 4244)
|
||||
# pragma warning(disable : 4267)
|
||||
# pragma warning(disable : 4305)
|
||||
|
||||
# define _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING 1
|
||||
#pragma warning(disable : 4996) // unsafe function or variable (strcpy e.g.)
|
||||
#pragma warning(disable : 4068) // unknown pragma
|
||||
#pragma warning(disable : 4100) // unreferenced formal parameter
|
||||
#pragma warning(disable : 4101) // unreferenced local variable
|
||||
#define _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING 1
|
||||
#endif
|
||||
|
||||
/** \file utilities.hpp
|
||||
@@ -87,10 +75,10 @@ namespace cif
|
||||
extern CIFPP_EXPORT int VERBOSE;
|
||||
|
||||
/// return the git 'build' number
|
||||
[[nodiscard]] std::string get_version_nr();
|
||||
std::string get_version_nr();
|
||||
|
||||
/// return the width of the current output terminal, or 80 if it cannot be determined
|
||||
[[nodiscard]] uint32_t get_terminal_width();
|
||||
uint32_t get_terminal_width();
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
@@ -99,7 +87,7 @@ namespace colour
|
||||
/// @brief The defined colours
|
||||
enum colour_type
|
||||
{
|
||||
black,
|
||||
black = 0,
|
||||
red,
|
||||
green,
|
||||
yellow,
|
||||
@@ -107,8 +95,7 @@ namespace colour
|
||||
magenta,
|
||||
cyan,
|
||||
white,
|
||||
_unused,
|
||||
none
|
||||
none = 9
|
||||
};
|
||||
|
||||
/// @brief The defined styles
|
||||
@@ -139,7 +126,6 @@ namespace colour
|
||||
{
|
||||
}
|
||||
|
||||
coloured_string_t(coloured_string_t &) = delete;
|
||||
coloured_string_t &operator=(coloured_string_t &) = delete;
|
||||
|
||||
/**
|
||||
@@ -149,7 +135,14 @@ namespace colour
|
||||
friend std::basic_ostream<char_type, traits_type> &operator<<(
|
||||
std::basic_ostream<char_type, traits_type> &os, const coloured_string_t &cs)
|
||||
{
|
||||
if ((os.rdbuf() == std::cout.rdbuf() and isatty(STDOUT_FILENO)) or (os.rdbuf() == std::cerr.rdbuf() and isatty(STDERR_FILENO)))
|
||||
bool use_colour = false;
|
||||
|
||||
if (os.rdbuf() == std::cout.rdbuf() and isatty(STDOUT_FILENO))
|
||||
use_colour = true;
|
||||
else if (os.rdbuf() == std::cerr.rdbuf() and isatty(STDERR_FILENO))
|
||||
use_colour = true;
|
||||
|
||||
if (use_colour)
|
||||
{
|
||||
os << "\033[" << cs.m_fore_colour << ';' << cs.m_style << ';' << cs.m_back_colour << 'm'
|
||||
<< cs.m_str
|
||||
@@ -173,7 +166,7 @@ namespace colour
|
||||
|
||||
/**
|
||||
* @brief Manipulator for coloured strings.
|
||||
*
|
||||
*
|
||||
* When writing out text to the terminal it is often useful to have
|
||||
* some of the text colourised. But only if the output is really a
|
||||
* terminal since colouring text is done using escape sequences
|
||||
@@ -210,51 +203,51 @@ inline auto coloured(T str,
|
||||
|
||||
/**
|
||||
* @brief A simple progress bar class for terminal based output
|
||||
*
|
||||
*
|
||||
* Using a progress bar is very convenient for the end user when
|
||||
* you have long running code. It gives feed back on how fast an
|
||||
* operation is performed and may give an indication how long it
|
||||
* will take before it is finished.
|
||||
*
|
||||
*
|
||||
* Using this cif::progress_bar implementation is straightforward:
|
||||
*
|
||||
*
|
||||
* @code {.cpp}
|
||||
* using namespace std::chrono_literals;
|
||||
*
|
||||
*
|
||||
* cif::progress_bar pb(10, "counting to ten");
|
||||
*
|
||||
*
|
||||
* for (int i = 1; i <= 10; ++i)
|
||||
* {
|
||||
* pb.consumed(1);
|
||||
* std::this_thread::sleep_for(1s);
|
||||
* }
|
||||
*
|
||||
*
|
||||
* @endcode
|
||||
*
|
||||
*
|
||||
* When the progress_bar is created, it first checks
|
||||
* to see if stdout is to a real TTY and if the VERBOSE
|
||||
* flag is not less than zero (quiet mode). If this passes
|
||||
* a thread is started that waits for updates.
|
||||
*
|
||||
*
|
||||
* The first two seconds, nothing is written to the screen
|
||||
* so if the work is finished within those two seconds
|
||||
* the screen stays clean.
|
||||
*
|
||||
*
|
||||
* After this time, a progress bar is printed that may look
|
||||
* like this:
|
||||
*
|
||||
*
|
||||
* @code
|
||||
* step 3 ========================-------------------------------- 40% ⢁
|
||||
* @endcode
|
||||
*
|
||||
*
|
||||
* The first characters contain the initial action name or
|
||||
* the message text if it was used afterwards.
|
||||
*
|
||||
*
|
||||
* The thermometer is made up with '=' and '-' characters.
|
||||
*
|
||||
*
|
||||
* A percentage is also shown and at the end there is a spinner
|
||||
* that gives feedback that the program is really still working.
|
||||
*
|
||||
*
|
||||
* The progress bar is removed if the max has been reached
|
||||
* or if the progress bar is destructed. If any output has
|
||||
* been generated, the initial action is printed out along
|
||||
@@ -264,16 +257,13 @@ inline auto coloured(T str,
|
||||
class progress_bar
|
||||
{
|
||||
public:
|
||||
progress_bar(const progress_bar &) = delete;
|
||||
progress_bar &operator=(const progress_bar &) = delete;
|
||||
|
||||
/**
|
||||
* @brief Construct a new progress bar object
|
||||
*
|
||||
*
|
||||
* Progress ranges from 0 (zero) to @a inMax
|
||||
*
|
||||
*
|
||||
* The action in @a inAction is used for display
|
||||
*
|
||||
*
|
||||
* @param inMax The maximum value
|
||||
* @param inAction The description of what is
|
||||
* going on
|
||||
@@ -283,7 +273,7 @@ class progress_bar
|
||||
|
||||
/**
|
||||
* @brief Destroy the progress bar object
|
||||
*
|
||||
*
|
||||
*/
|
||||
~progress_bar();
|
||||
|
||||
@@ -305,13 +295,11 @@ class progress_bar
|
||||
*/
|
||||
void message(const std::string &inMessage);
|
||||
|
||||
/**
|
||||
* @brief Flush the progress bar to the output stream
|
||||
*/
|
||||
void flush();
|
||||
|
||||
private:
|
||||
struct progress_bar_impl *m_impl = nullptr;
|
||||
progress_bar(const progress_bar &) = delete;
|
||||
progress_bar &operator=(const progress_bar &) = delete;
|
||||
|
||||
struct progress_bar_impl *m_impl;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
@@ -319,14 +307,14 @@ class progress_bar
|
||||
|
||||
/**
|
||||
* @brief Load a resource from disk or the compiled in resources
|
||||
*
|
||||
*
|
||||
* @verbatim embed:rst
|
||||
.. note::
|
||||
|
||||
See the :doc:`documentation on resources </resources>` for more information.
|
||||
|
||||
@endverbatim
|
||||
*
|
||||
*
|
||||
* @param name The named resource to load
|
||||
* @return std::unique_ptr<std::istream> A pointer to the std::istream or empty if not found
|
||||
*/
|
||||
@@ -335,14 +323,14 @@ std::unique_ptr<std::istream> load_resource(std::filesystem::path name);
|
||||
|
||||
/**
|
||||
* @brief Add a file specified by @a dataFile as the data for resource @a name
|
||||
*
|
||||
*
|
||||
* @verbatim embed:rst
|
||||
.. note::
|
||||
|
||||
See the :doc:`documentation on resources </resources>` for more information.
|
||||
|
||||
@endverbatim
|
||||
*
|
||||
*
|
||||
* @param name The name of the resource to specify
|
||||
* @param dataFile Path to a file containing the data
|
||||
*/
|
||||
@@ -351,7 +339,7 @@ void add_file_resource(const std::string &name, std::filesystem::path dataFile);
|
||||
|
||||
/**
|
||||
* @brief List all the file resources added with cif::add_file_resource.
|
||||
*
|
||||
*
|
||||
* @param os The std::ostream to write the directories to
|
||||
*/
|
||||
|
||||
@@ -360,7 +348,7 @@ void list_file_resources(std::ostream &os);
|
||||
/**
|
||||
* @brief Add a directory to the list of search directories. This list is
|
||||
* searched in a last-in-first-out order.
|
||||
*
|
||||
*
|
||||
* @verbatim embed:rst
|
||||
.. note::
|
||||
|
||||
@@ -373,7 +361,7 @@ void add_data_directory(std::filesystem::path dataDir);
|
||||
|
||||
/**
|
||||
* @brief List all the data directories, for error reporting on missing resources.
|
||||
*
|
||||
*
|
||||
* @param os The std::ostream to write the directories to
|
||||
*/
|
||||
|
||||
|
||||
@@ -26,23 +26,15 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cif++/category.hpp"
|
||||
#include "cif++/item.hpp"
|
||||
#include "cif++/text.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <iosfwd>
|
||||
#include <filesystem>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <system_error>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* @file validate.hpp
|
||||
@@ -72,8 +64,6 @@ enum class validation_error
|
||||
{
|
||||
value_does_not_match_rx = 1, /**< The value of an item does not conform to the regular expression specified for it */
|
||||
value_is_not_in_enumeration_list, /**< The value of an item is not in the list of values allowed */
|
||||
value_is_not_a_number, /**< The value is not a number */
|
||||
value_is_not_a_char_string, /**< The value is not a character string */
|
||||
not_a_known_primitive_type, /**< The type is not a known primitive type */
|
||||
undefined_category, /**< Category has no definition in the dictionary */
|
||||
unknown_item, /**< The item is not defined to be part of the category */
|
||||
@@ -99,7 +89,7 @@ class validation_category_impl : public std::error_category
|
||||
* @return const char*
|
||||
*/
|
||||
|
||||
[[nodiscard]] const char *name() const noexcept override
|
||||
const char *name() const noexcept override
|
||||
{
|
||||
return "cif::validation";
|
||||
}
|
||||
@@ -111,41 +101,35 @@ class validation_category_impl : public std::error_category
|
||||
* @return std::string
|
||||
*/
|
||||
|
||||
[[nodiscard]] std::string message(int ev) const override
|
||||
std::string message(int ev) const override
|
||||
{
|
||||
switch (static_cast<validation_error>(ev))
|
||||
{
|
||||
using enum validation_error;
|
||||
|
||||
case value_does_not_match_rx:
|
||||
case validation_error::value_does_not_match_rx:
|
||||
return "Value in item does not match regular expression";
|
||||
case value_is_not_in_enumeration_list:
|
||||
case validation_error::value_is_not_in_enumeration_list:
|
||||
return "Value is not in the enumerated list of valid values";
|
||||
case value_is_not_a_number:
|
||||
return "Value is not a number";
|
||||
case value_is_not_a_char_string:
|
||||
return "Value is not a character string";
|
||||
case not_a_known_primitive_type:
|
||||
case validation_error::not_a_known_primitive_type:
|
||||
return "The type is not a known primitive type";
|
||||
case undefined_category:
|
||||
case validation_error::undefined_category:
|
||||
return "Category has no definition in the dictionary";
|
||||
case unknown_item:
|
||||
case validation_error::unknown_item:
|
||||
return "Item is not defined to be part of the category";
|
||||
case incorrect_item_validator:
|
||||
case validation_error::incorrect_item_validator:
|
||||
return "Incorrectly specified validator for item";
|
||||
case missing_mandatory_items:
|
||||
case validation_error::missing_mandatory_items:
|
||||
return "Missing mandatory items";
|
||||
case missing_key_items:
|
||||
case validation_error::missing_key_items:
|
||||
return "An index could not be constructed due to missing key items";
|
||||
case item_not_allowed_in_category:
|
||||
case validation_error::item_not_allowed_in_category:
|
||||
return "Requested item not allowed in category according to dictionary";
|
||||
case empty_file:
|
||||
case validation_error::empty_file:
|
||||
return "The file contains no datablocks";
|
||||
case empty_datablock:
|
||||
case validation_error::empty_datablock:
|
||||
return "The datablock contains no categories";
|
||||
case empty_category:
|
||||
case validation_error::empty_category:
|
||||
return "The category is empty";
|
||||
case not_valid_pdbx:
|
||||
case validation_error::not_valid_pdbx:
|
||||
return "The file is not a valid PDBx file";
|
||||
|
||||
default:
|
||||
@@ -159,7 +143,7 @@ class validation_category_impl : public std::error_category
|
||||
*
|
||||
*/
|
||||
|
||||
[[nodiscard]] bool equivalent(const std::error_code & /*code*/, int /*condition*/) const noexcept override
|
||||
bool equivalent(const std::error_code & /*code*/, int /*condition*/) const noexcept override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -176,27 +160,21 @@ inline std::error_category &validation_category()
|
||||
return instance;
|
||||
}
|
||||
|
||||
/// Return a std::error_code for a validation error
|
||||
inline std::error_code make_error_code(validation_error e)
|
||||
{
|
||||
return { static_cast<int>(e), validation_category() };
|
||||
return std::error_code(static_cast<int>(e), validation_category());
|
||||
}
|
||||
|
||||
/// Return a std::error_condition for a validation error
|
||||
inline std::error_condition make_error_condition(validation_error e)
|
||||
{
|
||||
return { static_cast<int>(e), validation_category() };
|
||||
return std::error_condition(static_cast<int>(e), validation_category());
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/// Exception class for validation errors
|
||||
class validation_exception : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
// Constructors
|
||||
/// @cond
|
||||
|
||||
validation_exception(validation_error err)
|
||||
: validation_exception(make_error_code(err))
|
||||
{
|
||||
@@ -217,7 +195,6 @@ class validation_exception : public std::runtime_error
|
||||
validation_exception(std::error_code ec, std::string_view category);
|
||||
|
||||
validation_exception(std::error_code ec, std::string_view category, std::string_view item);
|
||||
/// @endcond
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
@@ -252,39 +229,37 @@ struct type_validator
|
||||
{
|
||||
std::string m_name; ///< The name of the type
|
||||
DDL_PrimitiveType m_primitive_type; ///< The primitive_type of the type
|
||||
std::shared_ptr<regex_impl> m_rx; ///< The regular expression for the type
|
||||
regex_impl *m_rx; ///< The regular expression for the type
|
||||
|
||||
type_validator() = delete;
|
||||
|
||||
/// @brief Constructor
|
||||
type_validator(std::string_view name, DDL_PrimitiveType type, std::string_view rx);
|
||||
|
||||
/// @brief Copy constructor
|
||||
type_validator(const type_validator &tv) = default;
|
||||
type_validator(const type_validator &) = delete;
|
||||
|
||||
/// @brief Move constructor
|
||||
/// @brief Copy constructor
|
||||
type_validator(type_validator &&rhs)
|
||||
: m_name(std::move(rhs.m_name))
|
||||
, m_primitive_type(rhs.m_primitive_type)
|
||||
{
|
||||
swap(*this, rhs);
|
||||
m_rx = std::exchange(rhs.m_rx, nullptr);
|
||||
}
|
||||
|
||||
type_validator &operator=(const type_validator &) = delete;
|
||||
|
||||
/// @brief Move constructor
|
||||
type_validator &operator=(type_validator rhs)
|
||||
type_validator &operator=(type_validator &&rhs)
|
||||
{
|
||||
swap(*this, rhs);
|
||||
m_name = std::move(rhs.m_name);
|
||||
m_primitive_type = rhs.m_primitive_type;
|
||||
m_rx = std::exchange(rhs.m_rx, nullptr);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// @brief Destructor
|
||||
~type_validator() = default;
|
||||
|
||||
/// Swap two type validators
|
||||
friend void swap(type_validator &a, type_validator &b)
|
||||
{
|
||||
std::swap(a.m_name, b.m_name);
|
||||
std::swap(a.m_primitive_type, b.m_primitive_type);
|
||||
std::swap(a.m_rx, b.m_rx);
|
||||
}
|
||||
~type_validator();
|
||||
|
||||
/// @brief Return the sorting order
|
||||
bool operator<(const type_validator &rhs) const
|
||||
@@ -296,7 +271,7 @@ struct type_validator
|
||||
/// primitive type of this type. A value of zero indicates the
|
||||
/// values are equal. Less than zero means @a a sorts before @a b
|
||||
/// and a value larger than zero likewise means the opposite
|
||||
[[nodiscard]] int compare(const item_value &a, const item_value &b) const;
|
||||
int compare(std::string_view a, std::string_view b) const;
|
||||
};
|
||||
|
||||
/** @brief Item alias, items can be renamed over time
|
||||
@@ -304,18 +279,14 @@ struct type_validator
|
||||
|
||||
struct item_alias
|
||||
{
|
||||
/// constructor
|
||||
item_alias(std::string alias_name, std::string dictionary, std::string version)
|
||||
: m_name(std::move(alias_name))
|
||||
, m_dict(std::move(dictionary))
|
||||
, m_vers(std::move(version))
|
||||
item_alias(const std::string &alias_name, const std::string &dictionary, const std::string &version)
|
||||
: m_name(alias_name)
|
||||
, m_dict(dictionary)
|
||||
, m_vers(version)
|
||||
{
|
||||
}
|
||||
|
||||
/// default copy constructor
|
||||
item_alias(const item_alias &) = default;
|
||||
|
||||
/// default copy assignment
|
||||
item_alias &operator=(const item_alias &) = default;
|
||||
|
||||
std::string m_name; ///< The alias_name
|
||||
@@ -334,13 +305,13 @@ struct item_alias
|
||||
*/
|
||||
struct item_validator
|
||||
{
|
||||
std::string m_item_name; ///< The item name
|
||||
bool m_mandatory; ///< Flag indicating this item is mandatory
|
||||
const type_validator *m_type; ///< The type for this item
|
||||
std::set<std::string> m_enums; ///< If filled, the set of allowed values
|
||||
std::string m_default; ///< If filled, a default value for this item
|
||||
std::string m_category; ///< The category this item_validator belongs to
|
||||
std::vector<item_alias> m_aliases; ///< The aliases for this item
|
||||
std::string m_item_name; ///< The item name
|
||||
bool m_mandatory; ///< Flag indicating this item is mandatory
|
||||
const type_validator *m_type; ///< The type for this item
|
||||
cif::iset m_enums; ///< If filled, the set of allowed values
|
||||
std::string m_default; ///< If filled, a default value for this item
|
||||
category_validator *m_category = nullptr; ///< The category_validator this item_validator belongs to
|
||||
std::vector<item_alias> m_aliases; ///< The aliases for this item
|
||||
|
||||
/// @brief Compare based on the name
|
||||
bool operator<(const item_validator &rhs) const
|
||||
@@ -354,13 +325,11 @@ struct item_validator
|
||||
return iequals(m_item_name, rhs.m_item_name);
|
||||
}
|
||||
|
||||
/// @brief Validate value @a value, throws if invalid
|
||||
void validate_value(const item_value &value) const;
|
||||
/// @brief Validate the value in @a value for this item
|
||||
/// Will throw a std::system_error exception if it fails
|
||||
void operator()(std::string_view value) const;
|
||||
|
||||
/// @brief Validate value @a value and return potential error in @a ec
|
||||
bool validate_value(const item_value &value, std::error_code &ec) const noexcept;
|
||||
|
||||
/// @brief Validate value @a value and return potential error in @a ec
|
||||
/// @brief A more gentle version of value validation
|
||||
bool validate_value(std::string_view value, std::error_code &ec) const noexcept;
|
||||
};
|
||||
|
||||
@@ -372,11 +341,11 @@ struct item_validator
|
||||
*/
|
||||
struct category_validator
|
||||
{
|
||||
std::string m_name; ///< The name of the category
|
||||
std::vector<std::string> m_keys; ///< The list of items that make up the key
|
||||
cif::iset m_groups; ///< The category groups this category belongs to
|
||||
cif::iset m_mandatory_items; ///< The mandatory items for this category
|
||||
std::vector<item_validator> m_item_validators; ///< The item validators for the items in this category
|
||||
std::string m_name; ///< The name of the category
|
||||
std::vector<std::string> m_keys; ///< The list of items that make up the key
|
||||
cif::iset m_groups; ///< The category groups this category belongs to
|
||||
cif::iset m_mandatory_items; ///< The mandatory items for this category
|
||||
std::set<item_validator> m_item_validators; ///< The item validators for the items in this category
|
||||
|
||||
/// @brief return true if this category sorts before @a rhs
|
||||
bool operator<(const category_validator &rhs) const
|
||||
@@ -388,10 +357,10 @@ struct category_validator
|
||||
void add_item_validator(item_validator &&v);
|
||||
|
||||
/// @brief Return the item_validator for item @a item_name, may return nullptr
|
||||
[[nodiscard]] const item_validator *get_validator_for_item(std::string_view item_name) const;
|
||||
const item_validator *get_validator_for_item(std::string_view item_name) const;
|
||||
|
||||
/// @brief Return the item_validator for an item that has as alias name @a item_name, may return nullptr
|
||||
[[nodiscard]] const item_validator *get_validator_for_aliased_item(std::string_view item_name) const;
|
||||
const item_validator *get_validator_for_aliased_item(std::string_view item_name) const;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -417,81 +386,32 @@ struct link_validator
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief The validator class combines all the link, category and item validator classes
|
||||
*
|
||||
*/
|
||||
class validator
|
||||
class validator_base
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new validator object
|
||||
*/
|
||||
validator()
|
||||
: m_audit_conform("audit_conform")
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a new validator object
|
||||
*
|
||||
* @param is The data to parse
|
||||
*/
|
||||
validator(std::istream &is)
|
||||
: m_audit_conform("audit_conform")
|
||||
{
|
||||
parse(is);
|
||||
}
|
||||
|
||||
/// @brief destructor
|
||||
~validator() = default;
|
||||
virtual ~validator_base() = default;
|
||||
|
||||
/// default copy constructor
|
||||
validator(const validator &rhs) = default;
|
||||
validator_base(const validator_base &rhs) = delete;
|
||||
validator_base &operator=(const validator_base &rhs) = delete;
|
||||
|
||||
/// @brief move constructor
|
||||
validator(validator &&rhs)
|
||||
{
|
||||
swap(*this, rhs);
|
||||
}
|
||||
validator_base(validator_base &&rhs) = default;
|
||||
|
||||
/// default copy assignment
|
||||
validator &operator=(validator rhs)
|
||||
{
|
||||
swap(*this, rhs);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// swap the two validators
|
||||
friend void swap(validator &a, validator &b) noexcept;
|
||||
|
||||
friend class dictionary_parser;
|
||||
friend class validator_factory;
|
||||
|
||||
/// @brief Parse dictionary in @a is and put content in this validator, optionally extending it
|
||||
/// @param is The stream containing a valid cif dictionary
|
||||
void parse(std::istream &is);
|
||||
|
||||
/// @brief Add type_validator @a v to the list of type validators
|
||||
void add_type_validator(type_validator &&v);
|
||||
/// @brief move assignment operator
|
||||
validator_base &operator=(validator_base &&rhs) = default;
|
||||
|
||||
/// @brief Return the type validator for @a type_code, may return nullptr
|
||||
[[nodiscard]] const type_validator *get_validator_for_type(std::string_view type_code) const;
|
||||
|
||||
/// @brief Add category_validator @a v to the list of category validators
|
||||
void add_category_validator(category_validator &&v);
|
||||
virtual const type_validator *get_validator_for_type(std::string_view type_code) const = 0;
|
||||
|
||||
/// @brief Return the category validator for @a category, may return nullptr
|
||||
[[nodiscard]] const category_validator *get_validator_for_category(std::string_view category) const;
|
||||
|
||||
/// @brief Add link_validator @a v to the list of link validators
|
||||
void add_link_validator(link_validator &&v);
|
||||
virtual const category_validator *get_validator_for_category(std::string_view category) const = 0;
|
||||
|
||||
/// @brief Return the list of link validators for which the parent is @a category
|
||||
[[nodiscard]] std::vector<const link_validator *> get_links_for_parent(std::string_view category) const;
|
||||
virtual std::vector<const link_validator *> get_links_for_parent(std::string_view category) const = 0;
|
||||
|
||||
/// @brief Return the list of link validators for which the child is @a category
|
||||
[[nodiscard]] std::vector<const link_validator *> get_links_for_child(std::string_view category) const;
|
||||
virtual std::vector<const link_validator *> get_links_for_child(std::string_view category) const = 0;
|
||||
|
||||
/// @brief Bottleneck function to report an error in validation
|
||||
void report_error(validation_error err, bool fatal = true) const
|
||||
@@ -502,48 +422,98 @@ class validator
|
||||
/// @brief Bottleneck function to report an error in validation
|
||||
void report_error(std::error_code ec, bool fatal = true) const;
|
||||
|
||||
/// @brief Bottleneck function to report an error in validation
|
||||
void report_error(validation_error err, std::string value, std::string_view category,
|
||||
std::string_view item, bool fatal = true) const
|
||||
{
|
||||
report_error(make_error_code(err), value, category, item, fatal);
|
||||
}
|
||||
|
||||
/// @brief Bottleneck function to report an error in validation
|
||||
void report_error(validation_error err, std::string_view category,
|
||||
std::string_view item, bool fatal = true) const
|
||||
{
|
||||
report_error(make_error_code(err), "", category, item, fatal);
|
||||
report_error(make_error_code(err), category, item, fatal);
|
||||
}
|
||||
|
||||
/// @brief Bottleneck function to report an error in validation
|
||||
void report_error(std::error_code ec, std::string_view category,
|
||||
std::string_view item, bool fatal = true) const
|
||||
{
|
||||
report_error(ec, "", category, item, fatal);
|
||||
}
|
||||
|
||||
/// @brief Bottleneck function to report an error in validation
|
||||
void report_error(std::error_code ec, std::string value, std::string_view category,
|
||||
std::string_view item, bool fatal = true) const;
|
||||
|
||||
/// @brief Write out the audit_conform data for this validator
|
||||
/// @param audit_conform
|
||||
void fill_audit_conform(category &audit_conform) const;
|
||||
const std::string &name() const { return m_name; } ///< Get the name of this validator
|
||||
const std::string &version() const { return m_version; } ///< Get the version of this validator
|
||||
bool is_strict() const { return m_strict; } ///< Get the strict flag of this validator
|
||||
|
||||
/// @brief Return true if this validator matches @a audit_conform
|
||||
[[nodiscard]] bool matches_audit_conform(const category &audit_conform) const;
|
||||
protected:
|
||||
/**
|
||||
* @brief Construct a new validator object
|
||||
*
|
||||
* @param name The name of the underlying dictionary
|
||||
*/
|
||||
validator_base(std::string_view name)
|
||||
: m_name(name)
|
||||
{
|
||||
}
|
||||
|
||||
/// @brief Add info
|
||||
void append_audit_conform(const std::string &name, const std::optional<std::string> &version);
|
||||
validator_base() = default;
|
||||
|
||||
std::string m_name;
|
||||
std::string m_version;
|
||||
bool m_strict = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The validator class combines all the link, category and item validator classes
|
||||
*
|
||||
*/
|
||||
class validator : public validator_base
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new validator object
|
||||
*
|
||||
* @param name The name of the underlying dictionary
|
||||
*/
|
||||
validator(std::string_view name)
|
||||
: validator_base(name)
|
||||
{
|
||||
}
|
||||
|
||||
/// @brief destructor
|
||||
~validator() = default;
|
||||
|
||||
validator(const validator &rhs) = delete;
|
||||
validator &operator=(const validator &rhs) = delete;
|
||||
|
||||
/// @brief move constructor
|
||||
validator(validator &&rhs) = default;
|
||||
|
||||
/// @brief move assignment operator
|
||||
validator &operator=(validator &&rhs) = default;
|
||||
|
||||
friend class dictionary_parser;
|
||||
|
||||
/// @brief Add type_validator @a v to the list of type validators
|
||||
void add_type_validator(type_validator &&v);
|
||||
|
||||
/// @brief Return the type validator for @a type_code, may return nullptr
|
||||
const type_validator *get_validator_for_type(std::string_view type_code) const override;
|
||||
|
||||
/// @brief Add category_validator @a v to the list of category validators
|
||||
void add_category_validator(category_validator &&v);
|
||||
|
||||
/// @brief Return the category validator for @a category, may return nullptr
|
||||
const category_validator *get_validator_for_category(std::string_view category) const override;
|
||||
|
||||
/// @brief Add link_validator @a v to the list of link validators
|
||||
void add_link_validator(link_validator &&v);
|
||||
|
||||
/// @brief Return the list of link validators for which the parent is @a category
|
||||
std::vector<const link_validator *> get_links_for_parent(std::string_view category) const override;
|
||||
|
||||
/// @brief Return the list of link validators for which the child is @a category
|
||||
std::vector<const link_validator *> get_links_for_child(std::string_view category) const override;
|
||||
|
||||
void set_name(const std::string &name) { m_name = name; } ///< Set the name of this validator
|
||||
void set_version(const std::string &version) { m_version = version; } ///< Set the version of this validator
|
||||
|
||||
private:
|
||||
// name is fully qualified here:
|
||||
[[nodiscard]] item_validator *get_validator_for_item(std::string_view name) const;
|
||||
item_validator *get_validator_for_item(std::string_view name) const;
|
||||
|
||||
category m_audit_conform;
|
||||
|
||||
bool m_strict = false;
|
||||
std::set<type_validator> m_type_validators;
|
||||
std::set<category_validator> m_category_validators;
|
||||
std::vector<link_validator> m_link_validators;
|
||||
@@ -551,6 +521,46 @@ class validator
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
class extended_validator : public validator_base
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new validator object
|
||||
*
|
||||
* @param name The name of the underlying dictionary
|
||||
* @param validators The validators this extended validator is composed off
|
||||
*/
|
||||
extended_validator(std::vector<const validator *> validators);
|
||||
|
||||
extended_validator(const extended_validator &rhs) = delete;
|
||||
extended_validator &operator=(const extended_validator &rhs) = delete;
|
||||
|
||||
/// @brief move constructor
|
||||
extended_validator(extended_validator &&rhs) = default;
|
||||
|
||||
/// @brief move assignment operator
|
||||
extended_validator &operator=(extended_validator &&rhs) = default;
|
||||
|
||||
/// @brief Return the type validator for @a type_code, may return nullptr
|
||||
virtual const type_validator *get_validator_for_type(std::string_view type_code) const override;
|
||||
|
||||
/// @brief Return the category validator for @a category, may return nullptr
|
||||
virtual const category_validator *get_validator_for_category(std::string_view category) const override;
|
||||
|
||||
/// @brief Return the list of link validators for which the parent is @a category
|
||||
virtual std::vector<const link_validator *> get_links_for_parent(std::string_view category) const override;
|
||||
|
||||
/// @brief Return the list of link validators for which the child is @a category
|
||||
virtual std::vector<const link_validator *> get_links_for_child(std::string_view category) const override;
|
||||
|
||||
protected:
|
||||
friend class validator_factory;
|
||||
|
||||
std::vector<const validator *> m_validators;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Validators are globally unique objects, use the validator_factory
|
||||
* class to construct them. This class is a singleton.
|
||||
@@ -562,53 +572,37 @@ class validator_factory
|
||||
/// @brief Return the singleton instance
|
||||
static validator_factory &instance();
|
||||
|
||||
/// @brief Return validator with info recorded in @a audit_conform
|
||||
const validator *get(const category &audit_conform);
|
||||
/// @brief Return the validator with name @a dictionary_name
|
||||
[[deprecated("use construct_validator(const category &audit_conform) instead")]]
|
||||
const validator_base &operator[](std::string_view dictionary_name);
|
||||
|
||||
/// @brief Return the single-file validator with name @a dictionary_name
|
||||
/// and the dictionary name may be a set of dictionaries separated by comma
|
||||
const validator *get(std::string_view dictionary_name);
|
||||
/// @brief Return a validator for the data contained in an audit_conform category
|
||||
const validator_base &construct_validator(const category &audit_conform);
|
||||
|
||||
/// @brief Return validator with info recorded in @a audit_conform
|
||||
const validator &operator[](const category &audit_conform);
|
||||
|
||||
/// @brief Return the single-file validator with name @a dictionary_name
|
||||
/// and the dictionary name may be a set of dictionaries separated by comma
|
||||
const validator &operator[](std::string_view dictionary_name);
|
||||
|
||||
/// @brief Return true if the version @a found is equal or higher than @a expected for dictionary @a name
|
||||
static bool check_version(std::string_view name, std::string_view expected, std::string_view found);
|
||||
|
||||
/// @brief Add validator @a v to the list of known validators
|
||||
const validator &add(validator &&v)
|
||||
{
|
||||
std::unique_lock lock(m_mutex);
|
||||
return m_validators.emplace_back(std::move(v));
|
||||
}
|
||||
|
||||
// #if __cplusplus >= 202302L
|
||||
// /// @brief Return validator with info recorded in @a audit_conform
|
||||
// static validator &operator[](const category &audit_conform)
|
||||
// {
|
||||
// return instance()[audit_conform];
|
||||
// }
|
||||
|
||||
// /// @brief Return the single-file validator with name @a dictionary_name
|
||||
// /// and the dictionary name may be a set of dictionaries separated by comma
|
||||
// static validator &operator[](std::string_view dict)
|
||||
// {
|
||||
// return instance()[dict];
|
||||
// }
|
||||
// #endif
|
||||
|
||||
private:
|
||||
validator_factory() = default;
|
||||
/// @brief Construct a new validator with name @a name from resource data with at least version @a version if specified
|
||||
const validator &construct_validator(std::string_view name,
|
||||
std::optional<std::string> version);
|
||||
|
||||
/// @brief Construct a new validator with name @a name from the data in @a is with at least version @a version if specified
|
||||
validator construct_validator(std::string_view name, std::optional<std::string> version);
|
||||
const validator &construct_validator(std::string_view name,
|
||||
std::optional<std::string> version, std::istream &is);
|
||||
|
||||
/// @brief Construct a new validator with name @a name from the data in @a is
|
||||
const validator &construct_validator(std::string_view name, std::istream &is)
|
||||
{
|
||||
return construct_validator(name, {}, is);
|
||||
}
|
||||
|
||||
private:
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
validator_factory() = default;
|
||||
|
||||
static bool check_version(std::string_view name, std::string_view expected, std::string_view found);
|
||||
|
||||
std::mutex m_mutex;
|
||||
std::list<validator> m_validators;
|
||||
std::list<extended_validator> m_extended_validators;
|
||||
};
|
||||
|
||||
} // namespace cif
|
||||
|
||||
@@ -1,316 +0,0 @@
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
#
|
||||
# Copyright (c) 2025 Maarten L. Hekkelman
|
||||
#
|
||||
# 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.
|
||||
|
||||
# A simplified wrapper CMakeLists.txt file for PCRE2
|
||||
#
|
||||
# This will generate an OBJECT library so it can be linked into another library
|
||||
|
||||
cmake_minimum_required(VERSION 3.25)
|
||||
|
||||
include(FetchContent)
|
||||
|
||||
project(pcre2s VERSION 1.0.0 LANGUAGES C CXX)
|
||||
|
||||
# The original code:
|
||||
|
||||
file(DOWNLOAD https://github.com/PCRE2Project/pcre2/releases/download/pcre2-10.46/pcre2-10.46.tar.gz
|
||||
${CMAKE_CURRENT_BINARY_DIR}/pcre2-code.tgz
|
||||
EXPECTED_HASH SHA256=8d28d7f2c3b970c3a4bf3776bcbb5adfc923183ce74bc8df1ebaad8c1985bd07)
|
||||
file(ARCHIVE_EXTRACT INPUT ${CMAKE_CURRENT_BINARY_DIR}/pcre2-code.tgz
|
||||
DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
|
||||
set(PCRE2_SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR}/pcre2-10.46)
|
||||
set(PCRE2_MAJOR 10)
|
||||
set(PCRE2_MINOR 46)
|
||||
set(PCRE2_VERSION "${PCRE2_MAJOR}.${PCRE2_MINOR}")
|
||||
set(PCRE2_DATE "2024-06-09")
|
||||
|
||||
# Some needed configuration options
|
||||
|
||||
# option(PCRE2_BUILD_PCRE2_8 "Build 8 bit PCRE2 library" ON)
|
||||
# option(PCRE2_BUILD_PCRE2_16 "Build 16 bit PCRE2 library" OFF)
|
||||
# option(PCRE2_BUILD_PCRE2_32 "Build 32 bit PCRE2 library" OFF)
|
||||
|
||||
option(PCRE2_STATIC_PIC "Build the static library with the option position independent code enabled." OFF)
|
||||
|
||||
set(PCRE2_NEWLINE "LF" CACHE STRING "What to recognize as a newline (one of CR, LF, CRLF, ANY, ANYCRLF, NUL)." FORCE)
|
||||
set_property(CACHE PCRE2_NEWLINE PROPERTY STRINGS "CR" "LF" "CRLF" "ANY" "ANYCRLF" "NUL")
|
||||
|
||||
set(PCRE2_LINK_SIZE "2" CACHE STRING "Internal link size (2, 3 or 4 allowed). See LINK_SIZE in config.h.in for details.")
|
||||
set_property(CACHE PCRE2_LINK_SIZE PROPERTY STRINGS "2" "3" "4")
|
||||
|
||||
set(PCRE2_PARENS_NEST_LIMIT "250" CACHE STRING "Default nested parentheses limit. See PARENS_NEST_LIMIT in config.h.in for details.")
|
||||
set(PCRE2_HEAP_LIMIT "20000000" CACHE STRING "Default limit on heap memory (kibibytes). See HEAP_LIMIT in config.h.in for details.")
|
||||
set(PCRE2_MAX_VARLOOKBEHIND "255" CACHE STRING "Default limit on variable lookbehinds.")
|
||||
set(PCRE2_MATCH_LIMIT "10000000" CACHE STRING "Default limit on internal looping. See MATCH_LIMIT in config.h.in for details.")
|
||||
set(PCRE2_MATCH_LIMIT_DEPTH "MATCH_LIMIT" CACHE STRING "Default limit on internal depth of search. See MATCH_LIMIT_DEPTH in config.h.in for details.")
|
||||
set(PCRE2GREP_BUFSIZE "20480" CACHE STRING "Buffer starting size parameter for pcre2grep. See PCRE2GREP_BUFSIZE in config.h.in for details.")
|
||||
set(PCRE2GREP_MAX_BUFSIZE "1048576" CACHE STRING "Buffer maximum size parameter for pcre2grep. See PCRE2GREP_MAX_BUFSIZE in config.h.in for details.")
|
||||
set(PCRE2_SUPPORT_JIT OFF CACHE BOOL "Enable support for Just-in-time compiling.")
|
||||
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES Linux|NetBSD)
|
||||
set(PCRE2_SUPPORT_JIT_SEALLOC OFF CACHE BOOL "Enable SELinux compatible execmem allocator in JIT (experimental).")
|
||||
else()
|
||||
set(PCRE2_SUPPORT_JIT_SEALLOC IGNORE)
|
||||
endif()
|
||||
|
||||
set(PCRE2GREP_SUPPORT_JIT ON CACHE BOOL "Enable use of Just-in-time compiling in pcre2grep.")
|
||||
set(PCRE2GREP_SUPPORT_CALLOUT ON CACHE BOOL "Enable callout string support in pcre2grep.")
|
||||
set(PCRE2GREP_SUPPORT_CALLOUT_FORK ON CACHE BOOL "Enable callout string fork support in pcre2grep.")
|
||||
set(PCRE2_SUPPORT_UNICODE ON CACHE BOOL "Enable support for Unicode and UTF-8/UTF-16/UTF-32 encoding.")
|
||||
set(PCRE2_SUPPORT_BSR_ANYCRLF OFF CACHE BOOL "ON=Backslash-R matches only LF CR and CRLF, OFF=Backslash-R matches all Unicode Linebreaks")
|
||||
set(PCRE2_NEVER_BACKSLASH_C OFF CACHE BOOL "If ON, backslash-C (upper case C) is locked out.")
|
||||
set(PCRE2_SUPPORT_VALGRIND OFF CACHE BOOL "Enable Valgrind support.")
|
||||
|
||||
if(MINGW)
|
||||
option(NON_STANDARD_LIB_PREFIX "ON=Shared libraries built in mingw will be named pcre2.dll, etc., instead of libpcre2.dll, etc." OFF)
|
||||
option(NON_STANDARD_LIB_SUFFIX "ON=Shared libraries built in mingw will be named libpcre2-0.dll, etc., instead of libpcre2.dll, etc." OFF)
|
||||
endif()
|
||||
|
||||
#
|
||||
|
||||
set(NEWLINE_DEFAULT "")
|
||||
|
||||
if(PCRE2_NEWLINE STREQUAL "CR")
|
||||
set(NEWLINE_DEFAULT "1")
|
||||
elseif(PCRE2_NEWLINE STREQUAL "LF")
|
||||
set(NEWLINE_DEFAULT "2")
|
||||
elseif(PCRE2_NEWLINE STREQUAL "CRLF")
|
||||
set(NEWLINE_DEFAULT "3")
|
||||
elseif(PCRE2_NEWLINE STREQUAL "ANY")
|
||||
set(NEWLINE_DEFAULT "4")
|
||||
elseif(PCRE2_NEWLINE STREQUAL "ANYCRLF")
|
||||
set(NEWLINE_DEFAULT "5")
|
||||
elseif(PCRE2_NEWLINE STREQUAL "NUL")
|
||||
set(NEWLINE_DEFAULT "6")
|
||||
else()
|
||||
message(FATAL_ERROR "The PCRE2_NEWLINE variable must be set to one of the following values: \"LF\", \"CR\", \"CRLF\", \"ANY\", \"ANYCRLF\".")
|
||||
endif()
|
||||
|
||||
# Some tests
|
||||
|
||||
include(CheckCSourceCompiles)
|
||||
include(CheckFunctionExists)
|
||||
include(CheckSymbolExists)
|
||||
include(CheckIncludeFile)
|
||||
|
||||
check_include_file(assert.h HAVE_ASSERT_H)
|
||||
check_include_file(dirent.h HAVE_DIRENT_H)
|
||||
check_include_file(sys/stat.h HAVE_SYS_STAT_H)
|
||||
check_include_file(sys/types.h HAVE_SYS_TYPES_H)
|
||||
check_include_file(unistd.h HAVE_UNISTD_H)
|
||||
check_include_file(windows.h HAVE_WINDOWS_H)
|
||||
|
||||
check_symbol_exists(bcopy "strings.h" HAVE_BCOPY)
|
||||
check_symbol_exists(memfd_create "sys/mman.h" HAVE_MEMFD_CREATE)
|
||||
check_symbol_exists(memmove "string.h" HAVE_MEMMOVE)
|
||||
check_symbol_exists(secure_getenv "stdlib.h" HAVE_SECURE_GETENV)
|
||||
check_symbol_exists(strerror "string.h" HAVE_STRERROR)
|
||||
|
||||
check_c_source_compiles(
|
||||
"int main(void) { char buf[128] __attribute__((uninitialized)); (void)buf; return 0; }"
|
||||
HAVE_ATTRIBUTE_UNINITIALIZED
|
||||
)
|
||||
|
||||
check_c_source_compiles(
|
||||
[=[
|
||||
extern __attribute__ ((visibility ("default"))) int f(void);
|
||||
int main(void) { return f(); }
|
||||
int f(void) { return 42; }
|
||||
]=]
|
||||
HAVE_VISIBILITY
|
||||
)
|
||||
|
||||
if(HAVE_VISIBILITY)
|
||||
set(PCRE2_EXPORT [=[__attribute__ ((visibility ("default")))]=])
|
||||
else()
|
||||
set(PCRE2_EXPORT)
|
||||
endif()
|
||||
|
||||
check_c_source_compiles("int main(void) { __assume(1); return 0; }" HAVE_BUILTIN_ASSUME)
|
||||
|
||||
check_c_source_compiles(
|
||||
[=[
|
||||
#include <stddef.h>
|
||||
int main(void) { int a,b; size_t m; __builtin_mul_overflow(a,b,&m); return 0; }
|
||||
]=]
|
||||
HAVE_BUILTIN_MUL_OVERFLOW
|
||||
)
|
||||
|
||||
check_c_source_compiles(
|
||||
"int main(int c, char *v[]) { if (c) __builtin_unreachable(); return (int)(*v[0]); }"
|
||||
HAVE_BUILTIN_UNREACHABLE
|
||||
)
|
||||
|
||||
# # Check whether Intel CET is enabled, and if so, adjust compiler flags. This
|
||||
# # code was written by PH, trying to imitate the logic from the autotools
|
||||
# # configuration.
|
||||
|
||||
# check_c_source_compiles(
|
||||
# [=[
|
||||
# #ifndef __CET__
|
||||
# #error CET is not enabled
|
||||
# #endif
|
||||
# int main() { return 0; }
|
||||
# ]=]
|
||||
# INTEL_CET_ENABLED
|
||||
# )
|
||||
|
||||
# if(INTEL_CET_ENABLED)
|
||||
# set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mshstk")
|
||||
# endif()
|
||||
|
||||
# Set up some dependencies first
|
||||
|
||||
configure_file(
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_chartables.c.dist
|
||||
${CMAKE_CURRENT_BINARY_DIR}/pcre2_chartables.c
|
||||
COPYONLY
|
||||
)
|
||||
|
||||
configure_file(
|
||||
${PCRE2_SOURCE_DIR}/config-cmake.h.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/interface/config.h
|
||||
@ONLY
|
||||
)
|
||||
|
||||
configure_file(
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2.h.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/interface/pcre2.h
|
||||
@ONLY
|
||||
)
|
||||
|
||||
# Define our library
|
||||
|
||||
list(APPEND PCRE2_HEADERS
|
||||
${CMAKE_CURRENT_BINARY_DIR}/interface/pcre2.h)
|
||||
|
||||
list(APPEND PCRE2_SOURCES
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_auto_possess.c
|
||||
${CMAKE_CURRENT_BINARY_DIR}/pcre2_chartables.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_chkdint.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_compile.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_compile_class.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_config.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_context.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_convert.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_dfa_match.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_error.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_extuni.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_find_bracket.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_jit_compile.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_maketables.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_match.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_match_data.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_newline.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_ord2utf.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_pattern_info.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_script_run.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_serialize.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_string_utils.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_study.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_substitute.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_substring.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_tables.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_ucd.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_valid_utf.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_xclass.c
|
||||
)
|
||||
|
||||
add_library(pcre2s OBJECT)
|
||||
|
||||
target_sources(pcre2s
|
||||
PRIVATE ${PCRE2_SOURCES}
|
||||
PUBLIC
|
||||
FILE_SET pcre2_headers TYPE HEADERS
|
||||
BASE_DIRS ${PCRE2_SOURCE_DIR}/include ${CMAKE_CURRENT_BINARY_DIR}/interface
|
||||
FILES ${PCRE2_HEADERS}
|
||||
)
|
||||
|
||||
target_compile_definitions(pcre2s PUBLIC PCRE2_CODE_UNIT_WIDTH=8 HAVE_CONFIG_H)
|
||||
if(NOT BUILD_SHARED_LIBS)
|
||||
target_compile_definitions(pcre2s PUBLIC PCRE2_STATIC)
|
||||
endif()
|
||||
|
||||
target_include_directories(pcre2s PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/interface ${PCRE2_SOURCE_DIR}/src)
|
||||
|
||||
if(PCRE2_STATIC_PIC)
|
||||
set_target_properties(pcre2s PROPERTIES POSITION_INDEPENDENT_CODE 1)
|
||||
endif()
|
||||
|
||||
# # Installation and config files
|
||||
|
||||
# include(CMakePackageConfigHelpers)
|
||||
# include(GenerateExportHeader)
|
||||
|
||||
# # Install rules
|
||||
# install(TARGETS pcre2s
|
||||
# EXPORT pcre2s
|
||||
# FILE_SET pcre2_headers DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
|
||||
# if(MSVC AND BUILD_SHARED_LIBS)
|
||||
# install(
|
||||
# FILES $<TARGET_PDB_FILE:pcre2s>
|
||||
# DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
# OPTIONAL)
|
||||
# endif()
|
||||
|
||||
# install(EXPORT pcre2s
|
||||
# NAMESPACE pcre2s::
|
||||
# FILE "pcre2s-targets.cmake"
|
||||
# DESTINATION lib/cmake/pcre2s)
|
||||
|
||||
# configure_package_config_file(
|
||||
# ${CMAKE_CURRENT_SOURCE_DIR}/pcre2s-config.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/pcre2s/pcre2s-config.cmake
|
||||
# INSTALL_DESTINATION lib/cmake/pcre2s)
|
||||
|
||||
# install(
|
||||
# FILES "${CMAKE_CURRENT_BINARY_DIR}/pcre2s/pcre2s-config.cmake"
|
||||
# "${CMAKE_CURRENT_BINARY_DIR}/pcre2s/pcre2s-config-version.cmake"
|
||||
# DESTINATION lib/cmake/pcre2s)
|
||||
|
||||
# set_target_properties(
|
||||
# pcre2s
|
||||
# PROPERTIES VERSION ${PCRE2_VERSION}
|
||||
# SOVERSION ${PCRE2_VERSION}
|
||||
# INTERFACE_pcre2s_MAJOR_VERSION ${PCRE2_MAJOR})
|
||||
|
||||
# set_property(
|
||||
# TARGET pcre2s
|
||||
# APPEND
|
||||
# PROPERTY COMPATIBLE_INTERFACE_STRING pcre2s_MAJOR_VERSION)
|
||||
|
||||
# write_basic_package_version_file(
|
||||
# "${CMAKE_CURRENT_BINARY_DIR}/pcre2s/pcre2s-config-version.cmake"
|
||||
# VERSION "${PCRE2_VERSION}"
|
||||
# COMPATIBILITY AnyNewerVersion)
|
||||
|
||||
# # Testing
|
||||
|
||||
# if(PROJECT_IS_TOP_LEVEL)
|
||||
# include(CTest)
|
||||
|
||||
# if(BUILD_TESTING)
|
||||
# add_subdirectory(test)
|
||||
# endif()
|
||||
# endif()
|
||||
4963
rsrc/mmcif_pdbx.dic
4963
rsrc/mmcif_pdbx.dic
File diff suppressed because it is too large
Load Diff
1691
src/atom_type.cpp
1691
src/atom_type.cpp
File diff suppressed because it is too large
Load Diff
1140
src/category.cpp
1140
src/category.cpp
File diff suppressed because it is too large
Load Diff
242
src/compound.cpp
242
src/compound.cpp
@@ -24,32 +24,19 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "cif++/compound.hpp"
|
||||
#include "cif++/cif++.hpp"
|
||||
#include "cif++.hpp"
|
||||
|
||||
#include <cstddef>
|
||||
#include <exception>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <ranges>
|
||||
#include <mutex>
|
||||
#include <numeric>
|
||||
#include <shared_mutex>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
namespace cif
|
||||
{
|
||||
using std::shared_ptr;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
@@ -57,32 +44,36 @@ std::string to_string(bond_type bondType)
|
||||
{
|
||||
switch (bondType)
|
||||
{
|
||||
using enum bond_type;
|
||||
|
||||
case sing: return "sing";
|
||||
case doub: return "doub";
|
||||
case trip: return "trip";
|
||||
case quad: return "quad";
|
||||
case arom: return "arom";
|
||||
case poly: return "poly";
|
||||
case delo: return "delo";
|
||||
case pi: return "pi";
|
||||
case bond_type::sing: return "sing";
|
||||
case bond_type::doub: return "doub";
|
||||
case bond_type::trip: return "trip";
|
||||
case bond_type::quad: return "quad";
|
||||
case bond_type::arom: return "arom";
|
||||
case bond_type::poly: return "poly";
|
||||
case bond_type::delo: return "delo";
|
||||
case bond_type::pi: return "pi";
|
||||
}
|
||||
throw std::invalid_argument("Invalid bondType");
|
||||
}
|
||||
|
||||
bond_type parse_bond_type_from_string(const std::string &bondType)
|
||||
{
|
||||
using enum bond_type;
|
||||
|
||||
if (cif::iequals(bondType, "sing")) return sing;
|
||||
if (cif::iequals(bondType, "doub")) return doub;
|
||||
if (cif::iequals(bondType, "trip")) return trip;
|
||||
if (cif::iequals(bondType, "quad")) return quad;
|
||||
if (cif::iequals(bondType, "arom")) return arom;
|
||||
if (cif::iequals(bondType, "poly")) return poly;
|
||||
if (cif::iequals(bondType, "delo")) return delo;
|
||||
if (cif::iequals(bondType, "pi")) return pi;
|
||||
if (cif::iequals(bondType, "sing"))
|
||||
return bond_type::sing;
|
||||
if (cif::iequals(bondType, "doub"))
|
||||
return bond_type::doub;
|
||||
if (cif::iequals(bondType, "trip"))
|
||||
return bond_type::trip;
|
||||
if (cif::iequals(bondType, "quad"))
|
||||
return bond_type::quad;
|
||||
if (cif::iequals(bondType, "arom"))
|
||||
return bond_type::arom;
|
||||
if (cif::iequals(bondType, "poly"))
|
||||
return bond_type::poly;
|
||||
if (cif::iequals(bondType, "delo"))
|
||||
return bond_type::delo;
|
||||
if (cif::iequals(bondType, "pi"))
|
||||
return bond_type::pi;
|
||||
throw std::invalid_argument("Invalid bondType: " + bondType);
|
||||
}
|
||||
|
||||
@@ -90,21 +81,21 @@ std::string to_string(stereo_config_type stereoConfig)
|
||||
{
|
||||
switch (stereoConfig)
|
||||
{
|
||||
using enum stereo_config_type;
|
||||
|
||||
case N: return "N";
|
||||
case R: return "R";
|
||||
case S: return "S";
|
||||
case stereo_config_type::N: return "N";
|
||||
case stereo_config_type::R: return "R";
|
||||
case stereo_config_type::S: return "S";
|
||||
}
|
||||
throw std::invalid_argument("Invalid stereoConfig");
|
||||
}
|
||||
|
||||
stereo_config_type parse_stereo_config_from_string(const std::string &stereoConfig)
|
||||
{
|
||||
using enum stereo_config_type;
|
||||
if (cif::iequals(stereoConfig, "N")) return N;
|
||||
if (cif::iequals(stereoConfig, "R")) return R;
|
||||
if (cif::iequals(stereoConfig, "S")) return S;
|
||||
if (cif::iequals(stereoConfig, "N"))
|
||||
return stereo_config_type::N;
|
||||
if (cif::iequals(stereoConfig, "R"))
|
||||
return stereo_config_type::R;
|
||||
if (cif::iequals(stereoConfig, "S"))
|
||||
return stereo_config_type::S;
|
||||
throw std::invalid_argument("Invalid stereoConfig: " + stereoConfig);
|
||||
}
|
||||
|
||||
@@ -149,7 +140,7 @@ compound::compound(cif::datablock &db)
|
||||
|
||||
cif::tie(m_id, m_name, m_type, m_formula, m_formula_weight, m_formal_charge, one_letter_code, m_parent_id) =
|
||||
chemComp.front().get("id", "name", "type", "formula", "formula_weight", "pdbx_formal_charge", "one_letter_code", "mon_nstd_parent_comp_id");
|
||||
|
||||
|
||||
if (one_letter_code.length() == 1)
|
||||
m_one_letter_code = one_letter_code.front();
|
||||
|
||||
@@ -161,21 +152,14 @@ compound::compound(cif::datablock &db)
|
||||
{
|
||||
compound_atom atom;
|
||||
std::string type_symbol, stereo_config;
|
||||
|
||||
std::string aromaticFlag, leavingAtomFlag;
|
||||
|
||||
cif::tie(atom.id, type_symbol, atom.charge, aromaticFlag, leavingAtomFlag, stereo_config, atom.x, atom.y, atom.z) =
|
||||
cif::tie(atom.id, type_symbol, atom.charge, atom.aromatic, atom.leaving_atom, stereo_config, atom.x, atom.y, atom.z) =
|
||||
row.get("atom_id", "type_symbol", "charge", "pdbx_aromatic_flag", "pdbx_leaving_atom_flag", "pdbx_stereo_config",
|
||||
"model_Cartn_x", "model_Cartn_y", "model_Cartn_z");
|
||||
|
||||
atom.aromatic = iequals(aromaticFlag, "Y");
|
||||
atom.leaving_atom = iequals(leavingAtomFlag, "Y");
|
||||
|
||||
atom.type_symbol = atom_type_traits(type_symbol).type();
|
||||
if (stereo_config.empty())
|
||||
atom.stereo_config = stereo_config_type::N;
|
||||
else
|
||||
atom.stereo_config = parse_stereo_config_from_string(stereo_config);
|
||||
atom.stereo_config = parse_stereo_config_from_string(stereo_config);
|
||||
m_atoms.push_back(std::move(atom));
|
||||
}
|
||||
|
||||
@@ -183,17 +167,12 @@ compound::compound(cif::datablock &db)
|
||||
for (auto row : chemCompBond)
|
||||
{
|
||||
compound_bond bond;
|
||||
std::string valueOrder, aromaticFlag, stereoConfigFlag;
|
||||
|
||||
cif::tie(bond.atom_id[0], bond.atom_id[1], valueOrder, aromaticFlag, stereoConfigFlag) = row.get("atom_id_1", "atom_id_2", "value_order", "pdbx_aromatic_flag", "pdbx_stereo_config");
|
||||
|
||||
bond.aromatic = iequals(aromaticFlag, "Y");
|
||||
bond.stereo_config = iequals(stereoConfigFlag, "Y");
|
||||
|
||||
std::string valueOrder;
|
||||
cif::tie(bond.atom_id[0], bond.atom_id[1], valueOrder, bond.aromatic, bond.stereo_config) = row.get("atom_id_1", "atom_id_2", "value_order", "pdbx_aromatic_flag", "pdbx_stereo_config");
|
||||
if (valueOrder.empty())
|
||||
bond.type = bond_type::sing;
|
||||
else
|
||||
bond.type = parse_bond_type_from_string(valueOrder);
|
||||
bond.type = parse_bond_type_from_string(valueOrder);
|
||||
m_bonds.push_back(std::move(bond));
|
||||
}
|
||||
}
|
||||
@@ -218,7 +197,7 @@ compound_atom compound::get_atom_by_atom_id(const std::string &atom_id) const
|
||||
|
||||
bool compound::atoms_bonded(const std::string &atomId_1, const std::string &atomId_2) const
|
||||
{
|
||||
auto i = std::ranges::find_if(m_bonds,
|
||||
auto i = find_if(m_bonds.begin(), m_bonds.end(),
|
||||
[&](const compound_bond &b)
|
||||
{
|
||||
return (b.atom_id[0] == atomId_1 and b.atom_id[1] == atomId_2) or (b.atom_id[0] == atomId_2 and b.atom_id[1] == atomId_1);
|
||||
@@ -229,7 +208,7 @@ bool compound::atoms_bonded(const std::string &atomId_1, const std::string &atom
|
||||
|
||||
float compound::bond_length(const std::string &atomId_1, const std::string &atomId_2) const
|
||||
{
|
||||
auto i = std::ranges::find_if(m_bonds,
|
||||
auto i = find_if(m_bonds.begin(), m_bonds.end(),
|
||||
[&](const compound_bond &b)
|
||||
{
|
||||
return (b.atom_id[0] == atomId_1 and b.atom_id[1] == atomId_2) or (b.atom_id[0] == atomId_2 and b.atom_id[1] == atomId_1);
|
||||
@@ -252,18 +231,18 @@ float compound::bond_length(const std::string &atomId_1, const std::string &atom
|
||||
|
||||
bool compound::is_peptide() const
|
||||
{
|
||||
return iequals(m_type, "l-peptide linking") or iequals(m_type, "peptide linking");
|
||||
return iequals(m_type, "l-peptide linking") or iequals(m_type, "peptide linking");
|
||||
}
|
||||
|
||||
bool compound::is_base() const
|
||||
{
|
||||
return iequals(m_type, "dna linking") or iequals(m_type, "rna linking");
|
||||
return iequals(m_type, "dna linking") or iequals(m_type, "rna linking");
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// known amino acids and bases
|
||||
|
||||
const std::map<std::string, char> compound_factory::kAAMap{ // NOLINT(bugprone-throwing-static-initialization,cert-err58-cpp)
|
||||
const std::map<std::string, char> compound_factory::kAAMap{
|
||||
{ "ALA", 'A' },
|
||||
{ "ARG", 'R' },
|
||||
{ "ASN", 'N' },
|
||||
@@ -288,7 +267,7 @@ const std::map<std::string, char> compound_factory::kAAMap{ // NOLINT(bugprone-t
|
||||
{ "ASX", 'B' }
|
||||
};
|
||||
|
||||
const std::map<std::string, char> compound_factory::kBaseMap{ // NOLINT(bugprone-throwing-static-initialization,cert-err58-cpp)
|
||||
const std::map<std::string, char> compound_factory::kBaseMap{
|
||||
{ "A", 'A' },
|
||||
{ "C", 'C' },
|
||||
{ "G", 'G' },
|
||||
@@ -306,40 +285,21 @@ const std::map<std::string, char> compound_factory::kBaseMap{ // NOLINT(bugprone
|
||||
class compound_factory_impl : public std::enable_shared_from_this<compound_factory_impl>
|
||||
{
|
||||
public:
|
||||
compound_factory_impl() = default;
|
||||
compound_factory_impl();
|
||||
compound_factory_impl(const fs::path &file, std::shared_ptr<compound_factory_impl> next);
|
||||
|
||||
virtual ~compound_factory_impl() // NOLINT(modernize-use-equals-default)
|
||||
virtual ~compound_factory_impl()
|
||||
{
|
||||
for (auto c : m_compounds)
|
||||
delete c;
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual bool exists_self(const std::string &id) const
|
||||
{
|
||||
if (m_missing.contains(id))
|
||||
return false;
|
||||
|
||||
if (std::ranges::find_if(m_compounds, [id](compound *c)
|
||||
{ return c->id() == id; }) != m_compounds.end())
|
||||
return true;
|
||||
|
||||
return m_next and m_next->exists_self(id);
|
||||
}
|
||||
|
||||
bool exists(std::string_view id)
|
||||
{
|
||||
std::shared_lock lock(mMutex);
|
||||
|
||||
return exists_self(std::string{ id });
|
||||
}
|
||||
|
||||
compound *get(std::string id)
|
||||
{
|
||||
std::shared_lock lock(mMutex);
|
||||
|
||||
compound *result = nullptr;
|
||||
|
||||
|
||||
for (auto impl = shared_from_this(); impl; impl = impl->m_next)
|
||||
{
|
||||
result = impl->create(id);
|
||||
@@ -381,8 +341,12 @@ class compound_factory_impl : public std::enable_shared_from_this<compound_facto
|
||||
std::shared_ptr<compound_factory_impl> m_next;
|
||||
};
|
||||
|
||||
compound_factory_impl::compound_factory_impl()
|
||||
{
|
||||
}
|
||||
|
||||
compound_factory_impl::compound_factory_impl(std::shared_ptr<compound_factory_impl> next)
|
||||
: m_next(std::move(next))
|
||||
: m_next(next)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -399,9 +363,7 @@ compound *compound_factory_impl::create(const std::string &id)
|
||||
if (m_missing.contains(id))
|
||||
return nullptr;
|
||||
|
||||
if (auto i = std::ranges::find_if(m_compounds, [id](compound *c)
|
||||
{ return c->id() == id; });
|
||||
i != m_compounds.end())
|
||||
if (auto i = find_if(m_compounds.begin(), m_compounds.end(), [id](compound *c) { return c->id() == id; }); i != m_compounds.end())
|
||||
return *i;
|
||||
|
||||
compound *result = nullptr;
|
||||
@@ -418,13 +380,13 @@ compound *compound_factory_impl::create(const std::string &id)
|
||||
}
|
||||
}
|
||||
else
|
||||
ccd = std::make_unique<std::ifstream>(m_file);
|
||||
ccd.reset(new std::ifstream(m_file));
|
||||
|
||||
cif::file file;
|
||||
|
||||
if (m_index.empty())
|
||||
{
|
||||
if (VERBOSE > 1)
|
||||
if (cif::VERBOSE > 1)
|
||||
{
|
||||
std::cout << "Creating component index "
|
||||
<< "...";
|
||||
@@ -434,7 +396,7 @@ compound *compound_factory_impl::create(const std::string &id)
|
||||
cif::parser parser(*ccd, file);
|
||||
m_index = parser.index_datablocks();
|
||||
|
||||
if (VERBOSE > 1)
|
||||
if (cif::VERBOSE > 1)
|
||||
std::cout << " done\n";
|
||||
|
||||
// reload the resource, perhaps this should be improved...
|
||||
@@ -445,10 +407,10 @@ compound *compound_factory_impl::create(const std::string &id)
|
||||
throw std::runtime_error("Could not locate the CCD components.cif file, please make sure the software is installed properly and/or use the update-libcifpp-data to fetch the data.");
|
||||
}
|
||||
else
|
||||
ccd = std::make_unique<std::ifstream>(m_file);
|
||||
ccd.reset(new std::ifstream(m_file));
|
||||
}
|
||||
|
||||
if (VERBOSE > 1)
|
||||
if (cif::VERBOSE > 1)
|
||||
{
|
||||
std::cout << "Loading component " << id << "...";
|
||||
std::cout.flush();
|
||||
@@ -457,7 +419,7 @@ compound *compound_factory_impl::create(const std::string &id)
|
||||
cif::parser parser(*ccd, file);
|
||||
parser.parse_single_datablock(id, m_index);
|
||||
|
||||
if (VERBOSE > 1)
|
||||
if (cif::VERBOSE > 1)
|
||||
std::cout << " done\n";
|
||||
|
||||
if (not file.empty())
|
||||
@@ -483,15 +445,16 @@ compound *compound_factory_impl::create(const std::string &id)
|
||||
class local_compound_factory_impl : public compound_factory_impl
|
||||
{
|
||||
public:
|
||||
local_compound_factory_impl(cif::file file, shared_ptr<compound_factory_impl> next)
|
||||
local_compound_factory_impl(const cif::file &file, std::shared_ptr<compound_factory_impl> next)
|
||||
: compound_factory_impl(next)
|
||||
, m_local_file(std::move(file))
|
||||
, m_local_file(file)
|
||||
{
|
||||
}
|
||||
|
||||
compound *create(const std::string &id) override;
|
||||
|
||||
private:
|
||||
|
||||
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;
|
||||
@@ -502,9 +465,7 @@ compound *local_compound_factory_impl::create(const std::string &id)
|
||||
if (m_missing.contains(id))
|
||||
return nullptr;
|
||||
|
||||
if (auto i = std::ranges::find_if(m_compounds, [id](compound *c)
|
||||
{ return c->id() == id; });
|
||||
i != m_compounds.end())
|
||||
if (auto i = find_if(m_compounds.begin(), m_compounds.end(), [id](compound *c) { return c->id() == id; }); i != m_compounds.end())
|
||||
return *i;
|
||||
|
||||
compound *result = nullptr;
|
||||
@@ -519,13 +480,10 @@ compound *local_compound_factory_impl::create(const std::string &id)
|
||||
|
||||
try
|
||||
{
|
||||
const auto &[id2, name, threeLetterCode, group] =
|
||||
const auto &[id, name, threeLetterCode, group] =
|
||||
chem_comp->front().get<std::string, std::string, std::string, std::string>("id", "name", "three_letter_code", "group");
|
||||
|
||||
if (id == id2)
|
||||
result = construct_compound(db, id, name, threeLetterCode, group);
|
||||
else
|
||||
throw std::runtime_error("Compound ID's don't match: id 1=" + id + ", id 2=" + id2);
|
||||
result = construct_compound(db, id, name, threeLetterCode, group);
|
||||
}
|
||||
catch (const std::exception &ex)
|
||||
{
|
||||
@@ -549,10 +507,12 @@ compound *local_compound_factory_impl::construct_compound(const datablock &rdb,
|
||||
|
||||
float formula_weight = 0;
|
||||
int formal_charge = 0;
|
||||
std::map<std::string, std::size_t> formula_data;
|
||||
std::map<std::string,std::size_t> formula_data;
|
||||
|
||||
for (std::size_t ord = 1; const auto &[atom_id, type_symbol, type, charge, x, y, z, xi, yi, zi] :
|
||||
rdb["chem_comp_atom"].rows<std::string, std::string, std::string, int, std::optional<float>, std::optional<float>, std::optional<float>, std::optional<float>, std::optional<float>, std::optional<float>>(
|
||||
rdb["chem_comp_atom"].rows<std::string, std::string, std::string, int,
|
||||
std::optional<float>, std::optional<float>, std::optional<float>,
|
||||
std::optional<float>, std::optional<float>, std::optional<float>>(
|
||||
"atom_id", "type_symbol", "type", "charge",
|
||||
"model_Cartn_x", "model_Cartn_y", "model_Cartn_z",
|
||||
"pdbx_model_Cartn_x_ideal", "pdbx_model_Cartn_y_ideal", "pdbx_model_Cartn_z_ideal"))
|
||||
@@ -562,20 +522,22 @@ compound *local_compound_factory_impl::construct_compound(const datablock &rdb,
|
||||
|
||||
formula_data[type_symbol] += 1;
|
||||
|
||||
db["chem_comp_atom"].emplace({ { "comp_id", id },
|
||||
db["chem_comp_atom"].emplace({
|
||||
{ "comp_id", id },
|
||||
{ "atom_id", atom_id },
|
||||
{ "type_symbol", type_symbol },
|
||||
{ "charge", charge },
|
||||
{ "model_Cartn_x", { x.has_value() ? x : xi , 3 } },
|
||||
{ "model_Cartn_y", { y.has_value() ? y : yi , 3 } },
|
||||
{ "model_Cartn_z", { z.has_value() ? z : zi , 3 } },
|
||||
{ "pdbx_ordinal", ord++ } });
|
||||
{ "model_Cartn_x", x.has_value() ? x : xi, 3 },
|
||||
{ "model_Cartn_y", y.has_value() ? y : yi, 3 },
|
||||
{ "model_Cartn_z", z.has_value() ? z : zi, 3 },
|
||||
{ "pdbx_ordinal", ord++ }
|
||||
});
|
||||
|
||||
formal_charge += charge;
|
||||
}
|
||||
|
||||
for (std::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, std::string>("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");
|
||||
|
||||
@@ -586,19 +548,21 @@ compound *local_compound_factory_impl::construct_compound(const datablock &rdb,
|
||||
else if (cif::iequals(type, "triple") or cif::iequals(type, "trip"))
|
||||
value_order = "TRIP";
|
||||
|
||||
db["chem_comp_bond"].emplace({ { "comp_id", id },
|
||||
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++ } });
|
||||
{ "pdbx_ordinal", ord++ }
|
||||
});
|
||||
}
|
||||
|
||||
db.emplace_back(rdb["pdbx_chem_comp_descriptor"]);
|
||||
|
||||
std::string formula;
|
||||
for (bool first = true; const auto &[symbol, count] : formula_data)
|
||||
for (bool first = true; const auto &[symbol, count]: formula_data)
|
||||
{
|
||||
if (std::exchange(first, false))
|
||||
formula += ' ';
|
||||
@@ -617,13 +581,15 @@ compound *local_compound_factory_impl::construct_compound(const datablock &rdb,
|
||||
else
|
||||
type = "NON-POLYMER";
|
||||
|
||||
db["chem_comp"].emplace({ { "id", id },
|
||||
db["chem_comp"].emplace({
|
||||
{ "id", id },
|
||||
{ "name", name },
|
||||
{ "type", type },
|
||||
{ "formula", formula },
|
||||
{ "pdbx_formal_charge", formal_charge },
|
||||
{ "formula_weight", { formula_weight, 3 } },
|
||||
{ "three_letter_code", three_letter_code } });
|
||||
{ "formula_weight", formula_weight },
|
||||
{ "three_letter_code", three_letter_code }
|
||||
});
|
||||
|
||||
std::shared_lock lock(mMutex);
|
||||
|
||||
@@ -649,10 +615,14 @@ compound_factory::compound_factory()
|
||||
auto ccd = cif::load_resource("components.cif");
|
||||
if (ccd)
|
||||
m_impl = std::make_shared<compound_factory_impl>();
|
||||
else if (VERBOSE > 0)
|
||||
else if (cif::VERBOSE > 0)
|
||||
std::cerr << "CCD components.cif resource was not found\n";
|
||||
}
|
||||
|
||||
compound_factory::~compound_factory()
|
||||
{
|
||||
}
|
||||
|
||||
compound_factory &compound_factory::instance()
|
||||
{
|
||||
if (s_use_thread_local_instance)
|
||||
@@ -684,7 +654,7 @@ void compound_factory::set_default_dictionary(const fs::path &inDictFile)
|
||||
|
||||
try
|
||||
{
|
||||
m_impl = std::make_shared<compound_factory_impl>(inDictFile, m_impl);
|
||||
m_impl.reset(new compound_factory_impl(inDictFile, m_impl));
|
||||
}
|
||||
catch (const std::exception &)
|
||||
{
|
||||
@@ -699,7 +669,7 @@ void compound_factory::push_dictionary(const fs::path &inDictFile)
|
||||
|
||||
try
|
||||
{
|
||||
m_impl = std::make_shared<compound_factory_impl>(inDictFile, m_impl);
|
||||
m_impl.reset(new compound_factory_impl(inDictFile, m_impl));
|
||||
}
|
||||
catch (const std::exception &)
|
||||
{
|
||||
@@ -711,7 +681,7 @@ void compound_factory::push_dictionary(const cif::file &inDictFile)
|
||||
{
|
||||
try
|
||||
{
|
||||
m_impl = std::make_shared<local_compound_factory_impl>(inDictFile, m_impl);
|
||||
m_impl.reset(new local_compound_factory_impl(inDictFile, m_impl));
|
||||
}
|
||||
catch (const std::exception &)
|
||||
{
|
||||
@@ -725,11 +695,6 @@ void compound_factory::pop_dictionary()
|
||||
m_impl = m_impl->next();
|
||||
}
|
||||
|
||||
bool compound_factory::exists(std::string_view id) const
|
||||
{
|
||||
return m_impl and m_impl->exists(id);
|
||||
}
|
||||
|
||||
const compound *compound_factory::create(std::string_view id)
|
||||
{
|
||||
auto result = m_impl ? m_impl->get(std::string{ id }) : nullptr;
|
||||
@@ -754,7 +719,7 @@ bool compound_factory::is_peptide(std::string_view res_name) const
|
||||
bool result = is_std_peptide(res_name);
|
||||
if (not result and m_impl)
|
||||
{
|
||||
auto compound = const_cast<compound_factory &>(*this).create(res_name);
|
||||
auto compound = const_cast<compound_factory&>(*this).create(res_name);
|
||||
result = compound != nullptr and compound->is_peptide();
|
||||
}
|
||||
return result;
|
||||
@@ -766,7 +731,7 @@ bool compound_factory::is_base(std::string_view res_name) const
|
||||
bool result = is_std_base(res_name);
|
||||
if (not result and m_impl)
|
||||
{
|
||||
auto compound = const_cast<compound_factory &>(*this).create(res_name);
|
||||
auto compound = const_cast<compound_factory&>(*this).create(res_name);
|
||||
result = compound != nullptr and compound->is_base();
|
||||
}
|
||||
return result;
|
||||
@@ -792,7 +757,8 @@ bool compound_factory::is_monomer(std::string_view res_name) const
|
||||
|
||||
void compound_factory::report_missing_compound(std::string_view compound_id)
|
||||
{
|
||||
if (std::exchange(m_report_missing, false))
|
||||
static bool s_reported = false;
|
||||
if (std::exchange(s_reported, true) == false)
|
||||
{
|
||||
using namespace cif::colour;
|
||||
|
||||
@@ -816,7 +782,7 @@ void compound_factory::report_missing_compound(std::string_view compound_id)
|
||||
<< "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\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://mmcif.wwpdb.org/dictionaries/ascii/mmcif_ma.dic\n\n";
|
||||
<< "curl -o " << CACHE_DIR << "/mmcif_ma.dic https://github.com/ihmwg/ModelCIF/raw/master/dist/mmcif_ma.dic\n\n";
|
||||
#endif
|
||||
|
||||
if (m_impl)
|
||||
|
||||
@@ -24,17 +24,8 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "cif++/cif++.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <typeinfo>
|
||||
#include <vector>
|
||||
#include "cif++/category.hpp"
|
||||
#include "cif++/condition.hpp"
|
||||
|
||||
namespace cif
|
||||
{
|
||||
@@ -44,13 +35,9 @@ iset get_category_items(const category &cat)
|
||||
return cat.key_items();
|
||||
}
|
||||
|
||||
std::optional<uint16_t> get_item_ix(const category &cat, std::string_view col)
|
||||
uint16_t get_item_ix(const category &cat, std::string_view col)
|
||||
{
|
||||
auto ix = cat.get_item_ix(col);
|
||||
std::optional<uint16_t> result;
|
||||
if (ix < cat.get_item_count())
|
||||
result = ix;
|
||||
return result;
|
||||
return cat.get_item_ix(col);
|
||||
}
|
||||
|
||||
bool is_item_type_uchar(const category &cat, std::string_view col)
|
||||
@@ -73,73 +60,34 @@ bool is_item_type_uchar(const category &cat, std::string_view col)
|
||||
|
||||
namespace detail
|
||||
{
|
||||
// // index lookup
|
||||
// struct index_lookup_condition_impl : public condition_impl
|
||||
// {
|
||||
// index_lookup_condition_impl(row_initializer &&key_values)
|
||||
// : m_key_values(std::move(key_values))
|
||||
// {
|
||||
// }
|
||||
//
|
||||
// condition_impl *prepare(const category &c) override
|
||||
// {
|
||||
// m_single_hit = c[m_key_values];
|
||||
// return this;
|
||||
// }
|
||||
//
|
||||
// bool test(const_row_handle r) const override
|
||||
// {
|
||||
// return m_single_hit == r;
|
||||
// }
|
||||
//
|
||||
// void str(std::ostream &os) const override
|
||||
// {
|
||||
// os << "index scan";
|
||||
// }
|
||||
//
|
||||
// virtual std::optional<row_handle> single() const override
|
||||
// {
|
||||
// return m_single_hit;
|
||||
// }
|
||||
//
|
||||
// virtual bool equals(const condition_impl *rhs) const override
|
||||
// {
|
||||
// if (typeid(*rhs) == typeid(index_lookup_condition_impl))
|
||||
// {
|
||||
// auto ri = static_cast<const index_lookup_condition_impl *>(rhs);
|
||||
// if (m_single_hit or ri->m_single_hit)
|
||||
// return m_single_hit == ri->m_single_hit;
|
||||
// else
|
||||
// // watch out, both m_item_ix might be the same while item_names might be diffent (in case they both do not exist in the category)
|
||||
// return m_key_values == ri->m_key_values;
|
||||
// }
|
||||
// return this == rhs;
|
||||
// }
|
||||
//
|
||||
// row_initializer m_key_values;
|
||||
// row_handle m_single_hit;
|
||||
// };
|
||||
|
||||
condition_impl *key_equals_condition_impl::prepare(const category &c)
|
||||
{
|
||||
condition_impl *result = nullptr;
|
||||
m_item_ix = c.get_item_ix(m_item_name);
|
||||
m_icase = is_item_type_uchar(c, m_item_name);
|
||||
|
||||
if (auto ix = get_item_ix(c, m_item_name); ix.has_value())
|
||||
if (c.get_cat_validator() != nullptr and
|
||||
c.key_item_indices().contains(m_item_ix) and
|
||||
c.key_item_indices().size() == 1)
|
||||
{
|
||||
m_item_ix = *ix;
|
||||
m_icase = is_item_type_uchar(c, m_item_name);
|
||||
|
||||
if (auto cv = c.get_cat_validator();
|
||||
cv != nullptr and cv->m_keys.size() == 1 and
|
||||
cv->m_keys.front() == m_item_name)
|
||||
{
|
||||
m_single_hit = c[{ { m_item_name, m_value } }];
|
||||
}
|
||||
|
||||
result = this;
|
||||
m_single_hit = c[{ { m_item_name, m_value } }];
|
||||
}
|
||||
|
||||
return result;
|
||||
return this;
|
||||
}
|
||||
|
||||
condition_impl *key_equals_number_condition_impl::prepare(const category &c)
|
||||
{
|
||||
m_item_ix = c.get_item_ix(m_item_name);
|
||||
|
||||
if (c.get_cat_validator() != nullptr and
|
||||
c.key_item_indices().contains(m_item_ix) and
|
||||
c.key_item_indices().size() == 1)
|
||||
{
|
||||
m_single_hit = c[{ { m_item_name, m_value } }];
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
bool found_in_range(condition_impl *c, std::vector<and_condition_impl *>::iterator b, std::vector<and_condition_impl *>::iterator e)
|
||||
@@ -150,8 +98,7 @@ namespace detail
|
||||
{
|
||||
auto &cs = (*s)->m_sub;
|
||||
|
||||
if (std::ranges::find_if(cs, [c](const condition_impl *i)
|
||||
{ return i->equals(c); }) == cs.end())
|
||||
if (find_if(cs.begin(), cs.end(), [c](const condition_impl *i) { return i->equals(c); }) == cs.end())
|
||||
{
|
||||
result = false;
|
||||
break;
|
||||
@@ -171,8 +118,7 @@ namespace detail
|
||||
for (size_t fc_i = 0; fc_i < fc.size();)
|
||||
{
|
||||
auto c = fc[fc_i];
|
||||
if (not found_in_range(c, subs.begin() + 1, subs.end()))
|
||||
{
|
||||
if (not found_in_range(c, subs.begin() + 1, subs.end())) {
|
||||
++fc_i;
|
||||
continue;
|
||||
}
|
||||
@@ -181,7 +127,7 @@ namespace detail
|
||||
and_result = new and_condition_impl();
|
||||
|
||||
and_result->m_sub.push_back(c);
|
||||
fc.erase(fc.begin() + static_cast<std::string::difference_type>(fc_i));
|
||||
fc.erase(fc.begin() + fc_i);
|
||||
|
||||
for (auto sub : subs)
|
||||
{
|
||||
@@ -190,13 +136,12 @@ namespace detail
|
||||
for (size_t ssub_i = 0; ssub_i < ssub.size();)
|
||||
{
|
||||
auto sc = ssub[ssub_i];
|
||||
if (not sc->equals(c))
|
||||
{
|
||||
if (not sc->equals(c)) {
|
||||
++ssub_i;
|
||||
continue;
|
||||
}
|
||||
|
||||
ssub.erase(ssub.begin() + static_cast<std::string::difference_type>(ssub_i));
|
||||
|
||||
ssub.erase(ssub.begin() + ssub_i);
|
||||
delete sc;
|
||||
break;
|
||||
}
|
||||
@@ -212,110 +157,31 @@ namespace detail
|
||||
return oc;
|
||||
}
|
||||
|
||||
condition_impl *and_condition_impl::prepare(const category &c)
|
||||
{
|
||||
for (auto &sub : m_sub)
|
||||
{
|
||||
if (sub->prepare(c) == nullptr)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (auto cv = c.get_cat_validator(); cv != nullptr)
|
||||
{
|
||||
// See if we can collapse a search part of this and_condition into a single index lookup
|
||||
|
||||
cif::iset keys{ cv->m_keys.begin(), cv->m_keys.end() };
|
||||
category::key_type lookup;
|
||||
std::vector<condition_impl *> subs;
|
||||
std::vector<std::string> may_be_empty;
|
||||
|
||||
for (auto &sub : m_sub)
|
||||
{
|
||||
if (auto s = dynamic_cast<const key_equals_condition_impl *>(sub); s != nullptr)
|
||||
{
|
||||
if (keys.contains(s->m_item_name))
|
||||
{
|
||||
lookup.emplace_back(s->m_item_name, s->m_value);
|
||||
subs.emplace_back(sub);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (auto s = dynamic_cast<const key_equals_or_empty_condition_impl *>(sub); s != nullptr)
|
||||
{
|
||||
if (keys.contains(s->m_item_name))
|
||||
{
|
||||
lookup.emplace_back(s->m_item_name, s->m_value, true);
|
||||
subs.emplace_back(sub);
|
||||
may_be_empty.emplace_back(s->m_item_name);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (lookup.size() == keys.size())
|
||||
{
|
||||
m_single = c[lookup];
|
||||
|
||||
for (auto s : subs)
|
||||
std::erase(m_sub, s);
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
bool and_condition_impl::test(const_row_handle r) const
|
||||
{
|
||||
bool result = true;
|
||||
|
||||
if (m_single.has_value() and *m_single != r)
|
||||
result = false;
|
||||
else
|
||||
{
|
||||
for (auto sub : m_sub)
|
||||
{
|
||||
if (sub->test(r))
|
||||
continue;
|
||||
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
condition_impl *or_condition_impl::prepare(const category &c)
|
||||
{
|
||||
std::vector<and_condition_impl *> and_conditions;
|
||||
|
||||
for (auto &sub : m_sub)
|
||||
{
|
||||
if (sub->prepare(c) == nullptr)
|
||||
{
|
||||
delete sub;
|
||||
sub = nullptr;
|
||||
continue;
|
||||
}
|
||||
|
||||
sub = sub->prepare(c);
|
||||
if (typeid(*sub) == typeid(and_condition_impl))
|
||||
and_conditions.push_back(static_cast<and_condition_impl *>(sub));
|
||||
}
|
||||
|
||||
std::erase(m_sub, nullptr);
|
||||
|
||||
if (not m_sub.empty() and and_conditions.size() == m_sub.size())
|
||||
if (and_conditions.size() == m_sub.size())
|
||||
return and_condition_impl::combine_equal(and_conditions, this);
|
||||
|
||||
return m_sub.empty() ? nullptr : this;
|
||||
return this;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
bool condition::prepare(const category &c)
|
||||
void condition::prepare(const category &c)
|
||||
{
|
||||
return m_impl and m_impl->prepare(c) != nullptr;
|
||||
if (m_impl)
|
||||
m_impl = m_impl->prepare(c);
|
||||
|
||||
m_prepared = true;
|
||||
}
|
||||
|
||||
} // namespace cif
|
||||
|
||||
1183
src/cql.cpp
1183
src/cql.cpp
File diff suppressed because it is too large
Load Diff
@@ -24,19 +24,7 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "cif++/cif++.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <exception>
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
#include <ranges>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
#include "cif++/datablock.hpp"
|
||||
|
||||
namespace cif
|
||||
{
|
||||
@@ -53,31 +41,15 @@ datablock::datablock(const datablock &db)
|
||||
void datablock::load_dictionary()
|
||||
{
|
||||
if (auto *audit_conform = get("audit_conform"); audit_conform and not audit_conform->empty())
|
||||
{
|
||||
try
|
||||
{
|
||||
set_validator(validator_factory::instance().get(*audit_conform));
|
||||
}
|
||||
catch (const std::exception &ex)
|
||||
{
|
||||
std::clog << ex.what() << '\n';
|
||||
}
|
||||
}
|
||||
set_validator(&validator_factory::instance().construct_validator(*audit_conform));
|
||||
}
|
||||
|
||||
void datablock::load_dictionary(std::string_view dict)
|
||||
void datablock::load_dictionary(std::string_view name)
|
||||
{
|
||||
try
|
||||
{
|
||||
set_validator(validator_factory::instance().get(dict));
|
||||
}
|
||||
catch (const std::exception &ex)
|
||||
{
|
||||
std::clog << ex.what() << '\n';
|
||||
}
|
||||
set_validator(&validator_factory::instance()[name]);
|
||||
}
|
||||
|
||||
void datablock::set_validator(const validator *v)
|
||||
void datablock::set_validator(const validator_base *v)
|
||||
{
|
||||
m_validator = v;
|
||||
|
||||
@@ -93,7 +65,7 @@ void datablock::set_validator(const validator *v)
|
||||
}
|
||||
}
|
||||
|
||||
const validator *datablock::get_validator() const
|
||||
const validator_base *datablock::get_validator() const
|
||||
{
|
||||
return m_validator;
|
||||
}
|
||||
@@ -110,6 +82,42 @@ bool datablock::is_valid() const
|
||||
return result;
|
||||
}
|
||||
|
||||
bool datablock::is_valid()
|
||||
{
|
||||
if (m_validator == nullptr)
|
||||
throw std::runtime_error("Validator not specified for datablock data_" + name());
|
||||
|
||||
bool result = true;
|
||||
for (auto &cat : *this)
|
||||
result = cat.is_valid() and result;
|
||||
|
||||
// Add or remove the audit_conform block here.
|
||||
if (result)
|
||||
{
|
||||
// If the dictionary declares an audit_conform category, put it in,
|
||||
// but only if it does not exist already!
|
||||
|
||||
if (m_validator->get_validator_for_category("audit_conform") != nullptr)
|
||||
{
|
||||
auto &audit_conform = operator[]("audit_conform");
|
||||
|
||||
audit_conform.clear();
|
||||
audit_conform.emplace({
|
||||
// clang-format off
|
||||
{ "dict_name", m_validator->name() },
|
||||
{ "dict_version", m_validator->version() }
|
||||
// clang-format on
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
erase(std::find_if(begin(), end(), [](category &cat)
|
||||
{ return cat.name() == "audit_conform"; }),
|
||||
end());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool datablock::validate_links() const
|
||||
{
|
||||
bool result = true;
|
||||
@@ -123,50 +131,11 @@ bool datablock::validate_links() const
|
||||
return result;
|
||||
}
|
||||
|
||||
bool datablock::strip()
|
||||
{
|
||||
bool result = true;
|
||||
|
||||
// remove all categories that have no validator
|
||||
std::erase_if(*this, [](category &c)
|
||||
{
|
||||
bool result = false;
|
||||
if (c.get_cat_validator() == nullptr)
|
||||
{
|
||||
if (VERBOSE > 0)
|
||||
std::clog << "Dropping category " << c.name() << '\n';
|
||||
result = true;
|
||||
}
|
||||
return result; });
|
||||
|
||||
// then strip the remaining categories
|
||||
for (auto &cat : *this)
|
||||
cat.strip();
|
||||
|
||||
// Add or remove the audit_conform block here.
|
||||
if (is_valid())
|
||||
{
|
||||
// If the dictionary declares an audit_conform category, put it in,
|
||||
// but only if it does not exist already!
|
||||
|
||||
if (auto audit_conform = get("audit_conform");
|
||||
audit_conform != nullptr and m_validator->get_validator_for_category("audit_conform") != nullptr)
|
||||
{
|
||||
audit_conform->clear();
|
||||
m_validator->fill_audit_conform(*audit_conform);
|
||||
}
|
||||
}
|
||||
else
|
||||
result = false;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
category &datablock::operator[](std::string_view name)
|
||||
{
|
||||
auto i = std::ranges::find_if(*this, [name](const category &c)
|
||||
auto i = std::find_if(begin(), end(), [name](const category &c)
|
||||
{ return iequals(c.name(), name); });
|
||||
|
||||
if (i != end())
|
||||
@@ -183,14 +152,14 @@ category &datablock::operator[](std::string_view name)
|
||||
const category &datablock::operator[](std::string_view name) const
|
||||
{
|
||||
static const category s_empty;
|
||||
auto i = std::ranges::find_if(*this, [name](const category &c)
|
||||
auto i = std::find_if(begin(), end(), [name](const category &c)
|
||||
{ return iequals(c.name(), name); });
|
||||
return i == end() ? s_empty : *i;
|
||||
}
|
||||
|
||||
category *datablock::get(std::string_view name)
|
||||
{
|
||||
auto i = std::ranges::find_if(*this, [name](const category &c)
|
||||
auto i = std::find_if(begin(), end(), [name](const category &c)
|
||||
{ return iequals(c.name(), name); });
|
||||
return i == end() ? nullptr : &*i;
|
||||
}
|
||||
@@ -236,7 +205,7 @@ std::vector<std::string> datablock::get_item_order() const
|
||||
std::vector<std::string> result;
|
||||
|
||||
// for entry and audit_conform on top
|
||||
auto ci = std::ranges::find_if(*this, [](const category &cat)
|
||||
auto ci = find_if(begin(), end(), [](const category &cat)
|
||||
{ return cat.name() == "entry"; });
|
||||
if (ci != end())
|
||||
{
|
||||
@@ -244,7 +213,7 @@ std::vector<std::string> datablock::get_item_order() const
|
||||
result.insert(result.end(), cto.begin(), cto.end());
|
||||
}
|
||||
|
||||
ci = std::ranges::find_if(*this, [](const category &cat)
|
||||
ci = find_if(begin(), end(), [](const category &cat)
|
||||
{ return cat.name() == "audit_conform"; });
|
||||
if (ci != end())
|
||||
{
|
||||
@@ -279,7 +248,7 @@ namespace
|
||||
return std::get<2>(*i);
|
||||
}
|
||||
|
||||
void calculate_cat_order(cat_order_t &cat_order, iter_t i, const validator &validator)
|
||||
void calculate_cat_order(cat_order_t &cat_order, iter_t i, const validator_base &validator)
|
||||
{
|
||||
if (i == cat_order.end() or get_count(i) >= 0)
|
||||
return;
|
||||
@@ -292,7 +261,7 @@ namespace
|
||||
|
||||
for (auto link : validator.get_links_for_child(cat))
|
||||
{
|
||||
auto ei = std::ranges::find_if(cat_order, [parent = link->m_parent_category](elem_t &a)
|
||||
auto ei = std::find_if(cat_order.begin(), cat_order.end(), [parent = link->m_parent_category](elem_t &a)
|
||||
{ return std::get<0>(a) == parent; });
|
||||
|
||||
if (ei == cat_order.end())
|
||||
@@ -329,7 +298,7 @@ void datablock::write(std::ostream &os) const
|
||||
for (auto i = cat_order.begin(); i != cat_order.end(); ++i)
|
||||
calculate_cat_order(cat_order, i, *m_validator);
|
||||
|
||||
std::ranges::sort(cat_order, [](const elem_t &a, const elem_t &b)
|
||||
std::sort(cat_order.begin(), cat_order.end(), [](const elem_t &a, const elem_t &b)
|
||||
{
|
||||
const auto &[cat_a, count_a, on_stack_a] = a;
|
||||
const auto &[cat_b, count_b, on_stack_b] = b;
|
||||
@@ -352,7 +321,7 @@ void datablock::write(std::ostream &os) const
|
||||
else
|
||||
{
|
||||
// mmcif support, sort of. First write the 'entry' Category
|
||||
// and if it exists, _AND_ we have a Validator, write out the
|
||||
// and if it exists, _AND_ we have a validator, write out the
|
||||
// audit_conform record.
|
||||
|
||||
if (auto entry = get("entry"); entry != nullptr)
|
||||
@@ -381,7 +350,7 @@ void datablock::write(std::ostream &os, const std::vector<std::string> &item_nam
|
||||
{
|
||||
std::string cat_name, item_name;
|
||||
std::tie(cat_name, item_name) = split_item_name(o);
|
||||
if (std::ranges::find_if(std::ranges::reverse_view(cat_order), [cat_name](const std::string &s) -> bool
|
||||
if (find_if(cat_order.rbegin(), cat_order.rend(), [cat_name](const std::string &s) -> bool
|
||||
{ return iequals(cat_name, s); }) == cat_order.rend())
|
||||
cat_order.push_back(cat_name);
|
||||
}
|
||||
@@ -408,7 +377,7 @@ void datablock::write(std::ostream &os, const std::vector<std::string> &item_nam
|
||||
// for any Category we missed in the catOrder
|
||||
for (auto &cat : *this)
|
||||
{
|
||||
if (std::ranges::find_if(cat_order, [&](const std::string &s) -> bool
|
||||
if (find_if(cat_order.begin(), cat_order.end(), [&](const std::string &s) -> bool
|
||||
{ return iequals(cat.name(), s); }) != cat_order.end())
|
||||
continue;
|
||||
|
||||
@@ -432,14 +401,14 @@ bool datablock::operator==(const datablock &rhs) const
|
||||
if (not cat.empty())
|
||||
catA.push_back(cat.name());
|
||||
}
|
||||
std::ranges::sort(catA);
|
||||
std::sort(catA.begin(), catA.end());
|
||||
|
||||
for (auto &cat : dbB)
|
||||
{
|
||||
if (not cat.empty())
|
||||
catB.push_back(cat.name());
|
||||
}
|
||||
std::ranges::sort(catB);
|
||||
std::sort(catB.begin(), catB.end());
|
||||
|
||||
// loop over categories twice, to group output
|
||||
// First iteration is to list missing categories.
|
||||
@@ -487,4 +456,4 @@ bool datablock::operator==(const datablock &rhs) const
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace cif
|
||||
} // namespace cif
|
||||
@@ -24,25 +24,10 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "cif++/cif++.hpp"
|
||||
#include "cif++/text.hpp"
|
||||
#include "cif++/validate.hpp"
|
||||
|
||||
#include <cstddef>
|
||||
#include <exception>
|
||||
#include <format>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <ranges>
|
||||
#include <set>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "cif++/condition.hpp"
|
||||
#include "cif++/dictionary_parser.hpp"
|
||||
#include "cif++/file.hpp"
|
||||
#include "cif++/parser.hpp"
|
||||
|
||||
namespace cif
|
||||
{
|
||||
@@ -61,7 +46,7 @@ class dictionary_parser : public parser
|
||||
void load_dictionary()
|
||||
{
|
||||
std::unique_ptr<datablock> dict;
|
||||
auto savedDatablock = std::exchange(m_datablock, nullptr);
|
||||
auto savedDatablock = m_datablock;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -75,7 +60,7 @@ class dictionary_parser : public parser
|
||||
|
||||
default:
|
||||
{
|
||||
dict = std::make_unique<datablock>(m_token_value); // dummy datablock, for constructing the validator only
|
||||
dict.reset(new datablock(m_token_value)); // dummy datablock, for constructing the validator only
|
||||
m_datablock = dict.get();
|
||||
|
||||
match(CIFToken::DATA);
|
||||
@@ -90,9 +75,6 @@ class dictionary_parser : public parser
|
||||
error(ex.what());
|
||||
}
|
||||
|
||||
if (m_datablock == nullptr)
|
||||
throw std::runtime_error("Dictionary file is empty?");
|
||||
|
||||
// store all validators
|
||||
for (auto &ic : mCategoryValidators)
|
||||
m_validator.add_category_validator(std::move(ic));
|
||||
@@ -105,19 +87,7 @@ class dictionary_parser : public parser
|
||||
error("Undefined category '" + iv.first);
|
||||
|
||||
for (auto &v : iv.second)
|
||||
{
|
||||
// enums, make lower case if needed
|
||||
auto tv = v.m_type;
|
||||
if (tv and tv->m_primitive_type == DDL_PrimitiveType::UChar)
|
||||
{
|
||||
std::set<std::string> es;
|
||||
for (auto &e : v.m_enums)
|
||||
es.emplace(cif::to_lower_copy(e));
|
||||
std::swap(es, v.m_enums);
|
||||
}
|
||||
|
||||
const_cast<category_validator *>(cv)->add_item_validator(std::move(v));
|
||||
}
|
||||
}
|
||||
|
||||
// check all item validators for having a typeValidator
|
||||
@@ -126,10 +96,14 @@ class dictionary_parser : public parser
|
||||
link_items();
|
||||
|
||||
// store meta information
|
||||
if (auto dictionary = m_datablock->get("dictionary"); dictionary != nullptr and not dictionary->empty())
|
||||
datablock::iterator info;
|
||||
bool is_new;
|
||||
std::tie(info, is_new) = m_datablock->emplace("dictionary");
|
||||
if (not is_new and not info->empty())
|
||||
{
|
||||
const auto &[name, version] = dictionary->front().get<std::string, std::optional<std::string>>("title", "version");
|
||||
m_validator.append_audit_conform(name, version);
|
||||
auto r = info->front();
|
||||
m_validator.set_name(r["title"].as<std::string>());
|
||||
m_validator.set_version(r["version"].as<std::string>());
|
||||
}
|
||||
|
||||
m_datablock = savedDatablock;
|
||||
@@ -143,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");
|
||||
@@ -151,7 +125,7 @@ class dictionary_parser : public parser
|
||||
bool isCategorySaveFrame = m_token_value[0] != '_';
|
||||
|
||||
datablock dict(m_token_value);
|
||||
auto cat = dict.end();
|
||||
datablock::iterator cat = dict.end();
|
||||
|
||||
match(CIFToken::SAVE_NAME);
|
||||
while (m_lookahead == CIFToken::LOOP or m_lookahead == CIFToken::ITEM_NAME)
|
||||
@@ -177,41 +151,15 @@ class dictionary_parser : public parser
|
||||
match(CIFToken::ITEM_NAME);
|
||||
}
|
||||
|
||||
while (m_lookahead >= CIFToken::VALUE_INAPPLICABLE)
|
||||
while (m_lookahead == CIFToken::VALUE)
|
||||
{
|
||||
cat->emplace({});
|
||||
auto row = cat->back();
|
||||
|
||||
for (auto item_name : item_names)
|
||||
{
|
||||
switch (m_lookahead)
|
||||
{
|
||||
using enum CIFToken;
|
||||
|
||||
case VALUE_INAPPLICABLE:
|
||||
row[item_name] = nullptr;
|
||||
match(VALUE_INAPPLICABLE);
|
||||
break;
|
||||
case VALUE_UNKNOWN:
|
||||
row[item_name] = item_value{ std::optional<std::string>{} };
|
||||
match(VALUE_UNKNOWN);
|
||||
break;
|
||||
case VALUE_NUMERIC_INTEGER:
|
||||
row[item_name] = m_token_value_int;
|
||||
match(VALUE_NUMERIC_INTEGER);
|
||||
break;
|
||||
case VALUE_NUMERIC_FLOAT:
|
||||
row[item_name] = m_token_value_float;
|
||||
match(VALUE_NUMERIC_FLOAT);
|
||||
break;
|
||||
case VALUE_CHARSTRING:
|
||||
case VALUE_TEXTFIELD:
|
||||
row[item_name] = m_token_value;
|
||||
match(m_lookahead);
|
||||
break;
|
||||
default:
|
||||
match(VALUE_CHARSTRING);
|
||||
}
|
||||
row[item_name] = m_token_value;
|
||||
match(CIFToken::VALUE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -229,35 +177,9 @@ class dictionary_parser : public parser
|
||||
|
||||
if (cat->empty())
|
||||
cat->emplace({});
|
||||
cat->back()[item_name] = m_token_value;
|
||||
|
||||
switch (m_lookahead)
|
||||
{
|
||||
using enum CIFToken;
|
||||
|
||||
case VALUE_INAPPLICABLE:
|
||||
cat->back()[item_name] = nullptr;
|
||||
match(VALUE_INAPPLICABLE);
|
||||
break;
|
||||
case VALUE_UNKNOWN:
|
||||
cat->back()[item_name] = item_value{ std::optional<std::string>{} };
|
||||
match(VALUE_UNKNOWN);
|
||||
break;
|
||||
case VALUE_NUMERIC_INTEGER:
|
||||
cat->back()[item_name] = m_token_value_int;
|
||||
match(VALUE_NUMERIC_INTEGER);
|
||||
break;
|
||||
case VALUE_NUMERIC_FLOAT:
|
||||
cat->back()[item_name] = m_token_value_float;
|
||||
match(VALUE_NUMERIC_FLOAT);
|
||||
break;
|
||||
case VALUE_CHARSTRING:
|
||||
case VALUE_TEXTFIELD:
|
||||
cat->back()[item_name] = m_token_value;
|
||||
match(m_lookahead);
|
||||
break;
|
||||
default:
|
||||
match(VALUE_CHARSTRING);
|
||||
}
|
||||
match(CIFToken::VALUE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -265,39 +187,32 @@ class dictionary_parser : public parser
|
||||
|
||||
if (isCategorySaveFrame)
|
||||
{
|
||||
auto category = dict["category"].front().get<std::string>("id");
|
||||
std::string category = dict["category"].front().get<std::string>("id");
|
||||
|
||||
std::vector<std::string> keys;
|
||||
for (auto k : dict["category_key"])
|
||||
keys.push_back(std::get<1>(split_item_name(k["name"].get<std::string>())));
|
||||
keys.push_back(std::get<1>(split_item_name(k["name"].as<std::string>())));
|
||||
|
||||
iset groups;
|
||||
for (auto g : dict["category_group"])
|
||||
groups.insert(g["id"].get<std::string>());
|
||||
groups.insert(g["id"].as<std::string>());
|
||||
|
||||
mCategoryValidators.push_back(category_validator{ category, keys, groups });
|
||||
}
|
||||
else
|
||||
{
|
||||
// if the type code is missing, this must be a pointer, just skip it
|
||||
std::optional<std::string> typeCode;
|
||||
|
||||
if (not dict["item_type"].empty())
|
||||
typeCode = dict["item_type"].front().get<std::optional<std::string>>("code");
|
||||
std::string typeCode = dict["item_type"].front().get<std::string>("code");
|
||||
|
||||
const type_validator *tv = nullptr;
|
||||
if (typeCode.has_value())
|
||||
tv = m_validator.get_validator_for_type(*typeCode);
|
||||
if (not(typeCode.empty() or typeCode == "?"))
|
||||
tv = m_validator.get_validator_for_type(typeCode);
|
||||
|
||||
std::set<std::string> ess;
|
||||
iset ess;
|
||||
for (auto e : dict["item_enumeration"])
|
||||
ess.insert(e["value"].get<std::string>());
|
||||
for (auto e : dict["pdbx_item_enumeration"])
|
||||
ess.insert(e["value"].get<std::string>());
|
||||
ess.insert(e["value"].as<std::string>());
|
||||
|
||||
std::string defaultValue;
|
||||
if (auto &cat = dict["item_default"]; not cat.empty())
|
||||
defaultValue = cat.front().get<std::string>("value");
|
||||
std::string defaultValue = dict["item_default"].front().get<std::string>("value");
|
||||
// bool defaultIsNull = false;
|
||||
// if (defaultValue.empty())
|
||||
// {
|
||||
@@ -311,7 +226,7 @@ class dictionary_parser : public parser
|
||||
|
||||
std::vector<item_alias> aliases;
|
||||
for (const auto &[alias_name, dictionary, version] :
|
||||
dict["item_aliases"].rows<std::string, std::string, std::string>("alias_name", "dictionary", "version"))
|
||||
dict["item_aliases"].rows<std::string,std::string,std::string>("alias_name", "dictionary", "version"))
|
||||
{
|
||||
aliases.emplace_back(alias_name, dictionary, version);
|
||||
}
|
||||
@@ -319,7 +234,8 @@ class dictionary_parser : public parser
|
||||
// collect the dict from our dataBlock and construct validators
|
||||
for (auto i : dict["item"])
|
||||
{
|
||||
auto &&[item, category, mandatory] = i.get<std::string, std::string, std::string>("name", "category_id", "mandatory_code");
|
||||
std::string item, category, mandatory;
|
||||
cif::tie(item, category, mandatory) = i.get("name", "category_id", "mandatory_code");
|
||||
|
||||
std::string cat_name, item_name;
|
||||
std::tie(cat_name, item_name) = split_item_name(item);
|
||||
@@ -334,9 +250,9 @@ class dictionary_parser : public parser
|
||||
|
||||
auto &ivs = mItemValidators[category];
|
||||
|
||||
auto vi = std::ranges::find(ivs, item_validator{ item_name });
|
||||
auto vi = find(ivs.begin(), ivs.end(), item_validator{ item_name });
|
||||
if (vi == ivs.end())
|
||||
ivs.push_back(item_validator{ item_name, iequals(mandatory, "yes"), tv, ess, defaultValue, cat_name, aliases });
|
||||
ivs.push_back(item_validator{ item_name, iequals(mandatory, "yes"), tv, ess, defaultValue, nullptr, std::move(aliases) });
|
||||
else
|
||||
{
|
||||
// need to update the itemValidator?
|
||||
@@ -375,7 +291,9 @@ class dictionary_parser : public parser
|
||||
|
||||
// collect the dict from our dataBlock and construct validators
|
||||
for (auto i : dict["item_linked"])
|
||||
mLinkedItems.emplace(i.get<std::string, std::string>("child_name", "parent_name"));
|
||||
{
|
||||
mLinkedItems.emplace(i.get<std::string,std::string>("child_name", "parent_name"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -420,7 +338,9 @@ class dictionary_parser : public parser
|
||||
|
||||
for (auto gl : linkedGroupList)
|
||||
{
|
||||
auto &&[child, parent, link_group_id] = gl.get<std::string, std::string, int>("child_name", "parent_name", "link_group_id");
|
||||
std::string child, parent;
|
||||
int link_group_id;
|
||||
cif::tie(child, parent, link_group_id) = gl.get("child_name", "parent_name", "link_group_id");
|
||||
|
||||
auto civ = m_validator.get_validator_for_item(child);
|
||||
if (civ == nullptr)
|
||||
@@ -430,11 +350,11 @@ class dictionary_parser : public parser
|
||||
if (piv == nullptr)
|
||||
error("in pdbx_item_linked_group_list, item '" + parent + "' is not specified");
|
||||
|
||||
key_type key{ piv->m_category, civ->m_category, link_group_id };
|
||||
key_type key{ piv->m_category->m_name, civ->m_category->m_name, link_group_id };
|
||||
if (not linkIndex.count(key))
|
||||
{
|
||||
linkIndex[key] = linkKeys.size();
|
||||
linkKeys.emplace_back();
|
||||
linkKeys.push_back({});
|
||||
}
|
||||
|
||||
std::size_t ix = linkIndex.at(key);
|
||||
@@ -458,11 +378,11 @@ class dictionary_parser : public parser
|
||||
if (piv == nullptr)
|
||||
error("in pdbx_item_linked_group_list, item '" + parent + "' is not specified");
|
||||
|
||||
key_type key{ piv->m_category, civ->m_category, 0 };
|
||||
key_type key{ piv->m_category->m_name, civ->m_category->m_name, 0 };
|
||||
if (not linkIndex.count(key))
|
||||
{
|
||||
linkIndex[key] = linkKeys.size();
|
||||
linkKeys.emplace_back();
|
||||
linkKeys.push_back({});
|
||||
}
|
||||
|
||||
std::size_t ix = linkIndex.at(key);
|
||||
@@ -483,39 +403,10 @@ class dictionary_parser : public parser
|
||||
// look up the label
|
||||
for (auto r : linkedGroup.find("category_id"_key == link.m_child_category and "link_group_id"_key == link.m_link_group_id))
|
||||
{
|
||||
link.m_link_group_label = r["label"].get<std::string>();
|
||||
link.m_link_group_label = r["label"].as<std::string>();
|
||||
break;
|
||||
}
|
||||
|
||||
// A last validation, link ends should both point to the same time
|
||||
|
||||
auto childCatValidator = m_validator.get_validator_for_category(link.m_child_category);
|
||||
auto parentCatValidator = m_validator.get_validator_for_category(link.m_parent_category);
|
||||
|
||||
if (childCatValidator == nullptr)
|
||||
throw std::runtime_error(std::format("Invalid dictionary, undefined category {} in link {}", link.m_child_category, link.m_link_group_id));
|
||||
if (parentCatValidator == nullptr)
|
||||
throw std::runtime_error(std::format("Invalid dictionary, undefined category {} in link {}", link.m_parent_category, link.m_link_group_id));
|
||||
|
||||
for (size_t ix = 0; ix < link.m_child_keys.size(); ++ix)
|
||||
{
|
||||
auto childItemValidator = childCatValidator->get_validator_for_item(link.m_child_keys[ix]);
|
||||
auto parentItemValidator = parentCatValidator->get_validator_for_item(link.m_parent_keys[ix]);
|
||||
|
||||
if (childItemValidator == nullptr)
|
||||
throw std::runtime_error(std::format("Invalid dictionary, in link group {} the item {} is not know in category {}",
|
||||
link.m_link_group_id, link.m_child_keys[ix], link.m_child_category));
|
||||
if (parentItemValidator == nullptr)
|
||||
throw std::runtime_error(std::format("Invalid dictionary, in link group {} the item {} is not know in category {}",
|
||||
link.m_link_group_id, link.m_parent_keys[ix], link.m_parent_category));
|
||||
|
||||
if (childItemValidator->m_type == nullptr)
|
||||
const_cast<item_validator *>(childItemValidator)->m_type = parentItemValidator->m_type;
|
||||
else if (childItemValidator->m_type != parentItemValidator->m_type)
|
||||
throw std::runtime_error(std::format("Invalid dictionary, in link group {} the items _{}.{}/_{}.{} do not have the same type",
|
||||
link.m_link_group_id, link.m_parent_category, link.m_parent_keys[ix], link.m_child_category, link.m_child_keys[ix]));
|
||||
}
|
||||
|
||||
m_validator.add_link_validator(std::move(link));
|
||||
}
|
||||
|
||||
@@ -525,7 +416,7 @@ class dictionary_parser : public parser
|
||||
{
|
||||
for (auto &iv : cv.m_item_validators)
|
||||
{
|
||||
if (iv.m_type == nullptr and VERBOSE >= 0)
|
||||
if (iv.m_type == nullptr and cif::VERBOSE >= 0)
|
||||
std::cerr << "Missing item_type for " << iv.m_item_name << '\n';
|
||||
}
|
||||
}
|
||||
@@ -586,11 +477,15 @@ class dictionary_parser : public parser
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
void parse_dictionary(validator &v, std::istream &is)
|
||||
validator parse_dictionary(std::string_view name, std::istream &is)
|
||||
{
|
||||
validator result(name);
|
||||
|
||||
file f;
|
||||
dictionary_parser p(v, is, f);
|
||||
dictionary_parser p(result, is, f);
|
||||
p.load_dictionary();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace cif
|
||||
|
||||
102
src/file.cpp
102
src/file.cpp
@@ -24,16 +24,8 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "cif++/cif++.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <exception>
|
||||
#include <filesystem>
|
||||
#include <istream>
|
||||
#include <list>
|
||||
#include <stdexcept>
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
#include "cif++/file.hpp"
|
||||
#include "cif++/gzio.hpp"
|
||||
|
||||
namespace cif
|
||||
{
|
||||
@@ -54,16 +46,8 @@ bool file::is_valid()
|
||||
{
|
||||
bool result = not empty();
|
||||
|
||||
for (bool first = true; auto &d : *this)
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
result = d.is_valid() and result;
|
||||
first = false;
|
||||
}
|
||||
else if (d.get_validator() != nullptr)
|
||||
result = d.is_valid() and result;
|
||||
}
|
||||
for (auto &d : *this)
|
||||
result = d.is_valid() and result;
|
||||
|
||||
if (result)
|
||||
result = validate_links();
|
||||
@@ -81,15 +65,51 @@ bool file::validate_links() const
|
||||
return result;
|
||||
}
|
||||
|
||||
// void file::load_dictionary()
|
||||
// {
|
||||
// if (not empty())
|
||||
// {
|
||||
// auto *audit_conform = front().get("audit_conform");
|
||||
// if (audit_conform and not audit_conform->empty())
|
||||
// {
|
||||
// std::string name = audit_conform->front().get<std::string>("dict_name");
|
||||
|
||||
// if (name == "mmcif_pdbx_v50")
|
||||
// name = "mmcif_pdbx.dic"; // we had a bug here in libcifpp...
|
||||
|
||||
// if (not name.empty())
|
||||
// {
|
||||
// try
|
||||
// {
|
||||
// load_dictionary(name);
|
||||
// }
|
||||
// catch (const std::exception &ex)
|
||||
// {
|
||||
// if (VERBOSE)
|
||||
// std::cerr << "Failed to load dictionary " << std::quoted(name) << ": " << ex.what() << '\n';
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// // if (not m_validator)
|
||||
// // load_dictionary("mmcif_pdbx.dic"); // TODO: maybe incorrect? Perhaps improve?
|
||||
// }
|
||||
|
||||
// void file::load_dictionary(std::string_view name)
|
||||
// {
|
||||
// set_validator(&validator_factory::instance()[name]);
|
||||
// }
|
||||
|
||||
bool file::contains(std::string_view name) const
|
||||
{
|
||||
return std::ranges::find_if(*this, [name](const datablock &db)
|
||||
return std::find_if(begin(), end(), [name](const datablock &db)
|
||||
{ return iequals(db.name(), name); }) != end();
|
||||
}
|
||||
|
||||
datablock &file::operator[](std::string_view name)
|
||||
{
|
||||
auto i = std::ranges::find_if(*this, [name](const datablock &c)
|
||||
auto i = std::find_if(begin(), end(), [name](const datablock &c)
|
||||
{ return iequals(c.name(), name); });
|
||||
|
||||
if (i != end())
|
||||
@@ -102,7 +122,7 @@ datablock &file::operator[](std::string_view name)
|
||||
const datablock &file::operator[](std::string_view name) const
|
||||
{
|
||||
static const datablock s_empty;
|
||||
auto i = std::ranges::find_if(*this, [name](const datablock &c)
|
||||
auto i = std::find_if(begin(), end(), [name](const datablock &c)
|
||||
{ return iequals(c.name(), name); });
|
||||
return i == end() ? s_empty : *i;
|
||||
}
|
||||
@@ -146,6 +166,40 @@ void file::load(const std::filesystem::path &p)
|
||||
}
|
||||
}
|
||||
|
||||
void file::load(const std::filesystem::path &p, std::string_view dict)
|
||||
{
|
||||
load(p, validator_factory::instance().operator[](dict));
|
||||
}
|
||||
|
||||
void file::load(std::istream &is, std::string_view dict)
|
||||
{
|
||||
load(is, validator_factory::instance().operator[](dict));
|
||||
}
|
||||
|
||||
void file::load(const std::filesystem::path &p, const validator_base &v)
|
||||
{
|
||||
gzio::ifstream in(p);
|
||||
if (not in.is_open())
|
||||
throw std::runtime_error("Could not open file '" + p.string() + '\'');
|
||||
|
||||
try
|
||||
{
|
||||
load(in, v);
|
||||
}
|
||||
catch (const std::exception &)
|
||||
{
|
||||
throw_with_nested(std::runtime_error("Error reading file '" + p.string() + '\''));
|
||||
}
|
||||
}
|
||||
|
||||
void file::load(std::istream &is, const validator_base &v)
|
||||
{
|
||||
parser p(is, *this);
|
||||
p.parse_file();
|
||||
for (auto &db : *this)
|
||||
db.set_validator(&v);
|
||||
}
|
||||
|
||||
void file::load(std::istream &is)
|
||||
{
|
||||
parser p(is, *this);
|
||||
@@ -167,4 +221,4 @@ void file::save(std::ostream &os) const
|
||||
db.write(os);
|
||||
}
|
||||
|
||||
} // namespace cif
|
||||
} // namespace cif
|
||||
268
src/item.cpp
268
src/item.cpp
@@ -24,275 +24,45 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "cif++/item.hpp"
|
||||
|
||||
#include "cif++/row.hpp"
|
||||
#include "cif++/text.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <charconv>
|
||||
#include <cmath>
|
||||
#include <compare>
|
||||
#include <cstdint>
|
||||
#include <ostream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <system_error>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace cif
|
||||
{
|
||||
|
||||
bool item_handle::empty() const
|
||||
const item_handle item_handle::s_null_item;
|
||||
row_handle s_null_row_handle;
|
||||
|
||||
item_handle::item_handle()
|
||||
: m_item_ix(std::numeric_limits<uint16_t>::max())
|
||||
, m_row_handle(s_null_row_handle)
|
||||
{
|
||||
return m_item_ix >= m_row.size() or m_row[m_item_ix].empty();
|
||||
}
|
||||
|
||||
item_value &item_handle::value()
|
||||
std::string_view item_handle::text() const
|
||||
{
|
||||
assert(m_item_ix < m_row.size());
|
||||
return m_row.operator[](m_item_ix);
|
||||
}
|
||||
|
||||
const item_value &item_handle::value() const
|
||||
{
|
||||
assert(m_item_ix < m_row.size());
|
||||
return m_row.operator[](m_item_ix);
|
||||
}
|
||||
|
||||
void swap(item_handle a, item_handle b) noexcept
|
||||
{
|
||||
item_value v(std::move(a.value()));
|
||||
a.value() = std::move(b.value());
|
||||
b.value() = std::move(v);
|
||||
}
|
||||
|
||||
void item_handle::set(item_value value, bool updateLinked)
|
||||
{
|
||||
row_handle rh{ m_category, m_row };
|
||||
rh.assign(m_item_ix, std::move(value), updateLinked);
|
||||
}
|
||||
|
||||
int item_value::compare(const item_value &b, bool ignore_case) const noexcept
|
||||
{
|
||||
int d = static_cast<int>(m_data.m_type) - static_cast<int>(b.m_data.m_type);
|
||||
|
||||
if (d == 0)
|
||||
if (not m_row_handle.empty())
|
||||
{
|
||||
switch (m_data.m_type)
|
||||
{
|
||||
using enum item_value_type;
|
||||
|
||||
case INT:
|
||||
d = m_data.m_value.m_integer - b.m_data.m_value.m_integer;
|
||||
break;
|
||||
case FLOAT:
|
||||
// stupid comparison based on chopped textual representation
|
||||
if (m_data.m_len > 0 or b.m_data.m_len > 0)
|
||||
{
|
||||
double fa = m_data.m_value.m_float;
|
||||
double fb = b.m_data.m_value.m_float;
|
||||
|
||||
auto delta = std::abs(fa - fb);
|
||||
if (delta == 0 or std::isnan(delta))
|
||||
d = 0;
|
||||
else if (m_data.m_len and b.m_data.m_len)
|
||||
{
|
||||
auto epsilon = std::pow(10.0f, -1.0f * std::min(m_data.m_len, b.m_data.m_len));
|
||||
if (delta > epsilon)
|
||||
d = fa < fb ? -1 : 1;
|
||||
else
|
||||
d = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto dp = (m_data.m_value.m_float <=> b.m_data.m_value.m_float);
|
||||
if (dp == std::partial_ordering::less)
|
||||
d = -1;
|
||||
else if (dp == std::partial_ordering::greater)
|
||||
d = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto dp = (m_data.m_value.m_float <=> b.m_data.m_value.m_float);
|
||||
if (dp == std::partial_ordering::less)
|
||||
d = -1;
|
||||
else if (dp == std::partial_ordering::greater)
|
||||
d = 1;
|
||||
}
|
||||
break;
|
||||
case TEXT:
|
||||
d = m_data.sv().compare(b.m_data.sv());
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
}
|
||||
else if (is_number() and b.is_number())
|
||||
{
|
||||
std::partial_ordering dp = std::partial_ordering::equivalent;
|
||||
|
||||
if (is_number_float())
|
||||
dp = m_data.m_value.m_float <=> b.m_data.m_value.m_integer;
|
||||
else /* if (is_number_int()) */
|
||||
dp = m_data.m_value.m_integer <=> b.m_data.m_value.m_float;
|
||||
|
||||
if (dp == std::partial_ordering::less)
|
||||
d = -1;
|
||||
else if (dp == std::partial_ordering::greater)
|
||||
d = 1;
|
||||
else
|
||||
d = 0;
|
||||
}
|
||||
else if (is_number_int() and b.is_string())
|
||||
d = str().compare(b.m_data.sv());
|
||||
else if (is_string() and b.is_number_int())
|
||||
d = m_data.sv().compare(b.str());
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
std::string item_value::str() const
|
||||
{
|
||||
switch (m_data.m_type)
|
||||
{
|
||||
using enum item_value_type;
|
||||
|
||||
case MISSING:
|
||||
return "?";
|
||||
|
||||
case INAPPLICABLE:
|
||||
return ".";
|
||||
|
||||
case TEXT:
|
||||
return std::string{ m_data.sv() };
|
||||
|
||||
case INT:
|
||||
{
|
||||
char s[32];
|
||||
std::to_chars_result r = std::to_chars(s, s + sizeof(s), m_data.m_value.m_integer);
|
||||
return r.ec == std::errc{} ? std::string{ s, r.ptr } : "*****";
|
||||
}
|
||||
|
||||
case FLOAT:
|
||||
{
|
||||
char s[32];
|
||||
|
||||
std::to_chars_result r;
|
||||
|
||||
if (m_data.m_len)
|
||||
{
|
||||
r = std::to_chars(s, s + sizeof(s), m_data.m_value.m_float, std::chars_format::fixed, m_data.m_len);
|
||||
if (r.ec != std::errc{})
|
||||
r = std::to_chars(s, s + sizeof(s), m_data.m_value.m_float);
|
||||
}
|
||||
else
|
||||
r = std::to_chars(s, s + sizeof(s), m_data.m_value.m_float);
|
||||
|
||||
return r.ec == std::errc{} ? std::string{ s, r.ptr } : "*****";
|
||||
}
|
||||
auto iv = m_row_handle.m_row->get(m_item_ix);
|
||||
if (iv != nullptr)
|
||||
return iv->text();
|
||||
}
|
||||
|
||||
std::unreachable();
|
||||
return {};
|
||||
}
|
||||
|
||||
// void const_item_handle::assign_value(const item_value &value)
|
||||
// {
|
||||
// assert(not m_row_handle.empty());
|
||||
// m_row_handle.assign(m_item_ix, value, true);
|
||||
// }
|
||||
|
||||
std::ostream &operator<<(std::ostream &os, const item_value &v)
|
||||
void item_handle::assign_value(std::string_view value)
|
||||
{
|
||||
switch (v.type())
|
||||
{
|
||||
using enum item_value_type;
|
||||
|
||||
case INT: os << v.m_data.m_value.m_integer; break;
|
||||
case FLOAT: os << v.m_data.m_value.m_float; break;
|
||||
case TEXT: os << v.m_data.sv(); break;
|
||||
case MISSING: os << '?'; break;
|
||||
case INAPPLICABLE: os << '.'; break;
|
||||
default: os.setstate(std::ios::failbit);
|
||||
}
|
||||
|
||||
return os;
|
||||
assert(not m_row_handle.empty());
|
||||
m_row_handle.assign(m_item_ix, value, true);
|
||||
}
|
||||
|
||||
void item_value::cast_to_int()
|
||||
void item_handle::swap(item_handle &b)
|
||||
{
|
||||
switch (type())
|
||||
{
|
||||
using enum item_value_type;
|
||||
|
||||
case INT:
|
||||
break;
|
||||
|
||||
case FLOAT:
|
||||
*this = std::rint(m_data.m_value.m_float);
|
||||
break;
|
||||
|
||||
case TEXT:
|
||||
{
|
||||
auto s = sv();
|
||||
int64_t v;
|
||||
|
||||
auto sp = s.data();
|
||||
if (*sp == '+')
|
||||
++sp;
|
||||
|
||||
auto [ptr, ec] = cif::from_chars(sp, s.data() + s.size(), v);
|
||||
if (ec != std::errc{})
|
||||
throw std::system_error(std::make_error_code(ec), "attempt to cast value to integer failed");
|
||||
if (ptr != s.data() + s.size())
|
||||
throw std::runtime_error("attempt to cast value to integer failed, trailing data");
|
||||
|
||||
*this = v;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
assert(m_item_ix == b.m_item_ix);
|
||||
// assert(&m_row_handle.m_category == &b.m_row_handle.m_category);
|
||||
m_row_handle.swap(m_item_ix, b.m_row_handle);
|
||||
}
|
||||
|
||||
void item_value::cast_to_float()
|
||||
{
|
||||
switch (type())
|
||||
{
|
||||
using enum item_value_type;
|
||||
|
||||
case INT:
|
||||
*this = static_cast<double>(m_data.m_value.m_integer);
|
||||
break;
|
||||
|
||||
case FLOAT:
|
||||
break;
|
||||
|
||||
case TEXT:
|
||||
{
|
||||
auto s = sv();
|
||||
double v;
|
||||
auto [ptr, ec] = cif::from_chars(s.data(), s.data() + s.size(), v);
|
||||
if (ec != std::errc{})
|
||||
throw std::system_error(std::make_error_code(ec), "attempt to cast value to integer failed");
|
||||
if (ptr != s.data() + s.size())
|
||||
throw std::runtime_error("attempt to cast value to integer failed, trailing data");
|
||||
*this = v;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void item_value::cast_to_string()
|
||||
{
|
||||
*this = str();
|
||||
}
|
||||
|
||||
} // namespace cif
|
||||
|
||||
984
src/model.cpp
984
src/model.cpp
File diff suppressed because it is too large
Load Diff
407
src/parser.cpp
407
src/parser.cpp
@@ -24,20 +24,15 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "cif++/cif++.hpp"
|
||||
#include "cif++/utilities.hpp"
|
||||
#include "cif++/forward_decl.hpp"
|
||||
#include "cif++/parser.hpp"
|
||||
#include "cif++/file.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <cctype>
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <system_error>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <stack>
|
||||
|
||||
namespace cif
|
||||
{
|
||||
@@ -47,7 +42,7 @@ namespace cif
|
||||
class reserved_words_automaton
|
||||
{
|
||||
public:
|
||||
reserved_words_automaton() = default;
|
||||
reserved_words_automaton() {}
|
||||
|
||||
enum move_result
|
||||
{
|
||||
@@ -61,14 +56,14 @@ class reserved_words_automaton
|
||||
stop
|
||||
};
|
||||
|
||||
[[nodiscard]] constexpr bool finished() const
|
||||
constexpr bool finished() const
|
||||
{
|
||||
return m_state <= 0;
|
||||
return m_state <= 0;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool matched() const
|
||||
constexpr bool matched() const
|
||||
{
|
||||
return m_state < 0;
|
||||
return m_state < 0;
|
||||
}
|
||||
|
||||
constexpr move_result move(int ch)
|
||||
@@ -80,7 +75,7 @@ class reserved_words_automaton
|
||||
case 0:
|
||||
break;
|
||||
|
||||
case -1: // data_
|
||||
case -1: // data_
|
||||
if (sac_parser::is_non_blank(ch))
|
||||
m_seen_trailing_chars = true;
|
||||
else if (m_seen_trailing_chars)
|
||||
@@ -89,15 +84,15 @@ class reserved_words_automaton
|
||||
result = no_keyword;
|
||||
break;
|
||||
|
||||
case -2: // global_
|
||||
case -2: // global_
|
||||
result = sac_parser::is_non_blank(ch) ? no_keyword : global;
|
||||
break;
|
||||
|
||||
case -3: // loop_
|
||||
case -3: // loop_
|
||||
result = sac_parser::is_non_blank(ch) ? no_keyword : loop;
|
||||
break;
|
||||
|
||||
case -4: // save_
|
||||
case -4: // save_
|
||||
if (sac_parser::is_non_blank(ch))
|
||||
m_seen_trailing_chars = true;
|
||||
else if (m_seen_trailing_chars)
|
||||
@@ -106,10 +101,10 @@ class reserved_words_automaton
|
||||
result = save;
|
||||
break;
|
||||
|
||||
case -5: // stop_
|
||||
case -5: // stop_
|
||||
result = sac_parser::is_non_blank(ch) ? no_keyword : stop;
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
assert(m_state > 0 and m_state < NODE_COUNT);
|
||||
|
||||
@@ -142,17 +137,17 @@ class reserved_words_automaton
|
||||
static constexpr struct node
|
||||
{
|
||||
int16_t ch;
|
||||
int next_match;
|
||||
int next_nomatch;
|
||||
int8_t next_match;
|
||||
int8_t next_nomatch;
|
||||
} s_dag[] = {
|
||||
{ 0 },
|
||||
{ 'D', 5, 2 },
|
||||
{ 'G', 9, 3 },
|
||||
{ 'D', 5, 2 },
|
||||
{ 'G', 9, 3 },
|
||||
{ 'L', 15, 4 },
|
||||
{ 'S', 19, 0 },
|
||||
{ 'A', 6, 0 },
|
||||
{ 'T', 7, 0 },
|
||||
{ 'A', 8, 0 },
|
||||
{ 'A', 6, 0 },
|
||||
{ 'T', 7, 0 },
|
||||
{ 'A', 8, 0 },
|
||||
{ '_', -1, 0 },
|
||||
{ 'L', 10, 0 },
|
||||
{ 'O', 11, 0 },
|
||||
@@ -160,7 +155,7 @@ class reserved_words_automaton
|
||||
{ 'A', 13, 0 },
|
||||
{ 'L', 14, 0 },
|
||||
{ '_', -2, 0 },
|
||||
{ 'O', 16, 0 },
|
||||
{ 'O', 16, 0},
|
||||
{ 'O', 17, 0 },
|
||||
{ 'P', 18, 0 },
|
||||
{ '_', -3, 0 },
|
||||
@@ -243,7 +238,7 @@ int sac_parser::get_next_char()
|
||||
}
|
||||
else if (result == '\n')
|
||||
++m_line_nr;
|
||||
|
||||
|
||||
m_token_buffer.push_back(std::char_traits<char>::to_char_type(result));
|
||||
}
|
||||
|
||||
@@ -282,9 +277,6 @@ sac_parser::CIFToken sac_parser::get_next_token()
|
||||
m_token_buffer.clear();
|
||||
m_token_value = {};
|
||||
|
||||
bool negative = false;
|
||||
m_float_precision = 0;
|
||||
|
||||
reserved_words_automaton dag;
|
||||
|
||||
while (result == CIFToken::UNKNOWN)
|
||||
@@ -293,73 +285,53 @@ sac_parser::CIFToken sac_parser::get_next_token()
|
||||
|
||||
switch (state)
|
||||
{
|
||||
using enum State;
|
||||
|
||||
case Start:
|
||||
case State::Start:
|
||||
if (ch == kEOF)
|
||||
result = CIFToken::END_OF_FILE;
|
||||
else if (ch == '\n')
|
||||
{
|
||||
m_bol = true;
|
||||
state = White;
|
||||
state = State::White;
|
||||
}
|
||||
else if (ch == ' ' or ch == '\t')
|
||||
state = White;
|
||||
state = State::White;
|
||||
else if (ch == '#')
|
||||
state = Comment;
|
||||
state = State::Comment;
|
||||
else if (ch == '_')
|
||||
state = ItemName;
|
||||
state = State::ItemName;
|
||||
else if (ch == ';' and m_bol)
|
||||
{
|
||||
if (m_backslash_strings)
|
||||
state = TextItemBS;
|
||||
else
|
||||
state = TextItem;
|
||||
}
|
||||
state = State::TextItem;
|
||||
else if (ch == '?')
|
||||
state = QuestionMark;
|
||||
state = State::QuestionMark;
|
||||
else if (ch == '\'' or ch == '"')
|
||||
{
|
||||
quoteChar = ch;
|
||||
state = QuotedString;
|
||||
state = State::QuotedString;
|
||||
}
|
||||
else if (dag.move(ch) == reserved_words_automaton::undefined)
|
||||
state = Reserved;
|
||||
else if (ch == '+' or ch == '-')
|
||||
{
|
||||
negative = true;
|
||||
state = Numeric_Integer;
|
||||
}
|
||||
else if (ch == '0')
|
||||
state = Numeric_Zero;
|
||||
else if (ch >= '1' and ch <= '9')
|
||||
state = Numeric_Integer;
|
||||
else if (ch == '.')
|
||||
state = Numeric_Float;
|
||||
state = State::Reserved;
|
||||
else
|
||||
state = Value;
|
||||
state = State::Value;
|
||||
break;
|
||||
|
||||
case White:
|
||||
case State::White:
|
||||
if (ch == kEOF)
|
||||
result = CIFToken::END_OF_FILE;
|
||||
else if (not is_space(ch))
|
||||
{
|
||||
state = Start;
|
||||
state = State::Start;
|
||||
retract();
|
||||
m_token_buffer.clear();
|
||||
}
|
||||
else
|
||||
m_bol = (ch == '\n');
|
||||
break;
|
||||
|
||||
case Comment:
|
||||
|
||||
case State::Comment:
|
||||
if (ch == '\n')
|
||||
{
|
||||
state = Start;
|
||||
state = State::Start;
|
||||
m_bol = true;
|
||||
if (m_token_buffer.size() == 3 and m_token_buffer == std::vector{ '#', '\\', '\n' })
|
||||
m_backslash_strings = true;
|
||||
m_token_buffer.clear();
|
||||
}
|
||||
else if (ch == kEOF)
|
||||
@@ -367,58 +339,34 @@ sac_parser::CIFToken sac_parser::get_next_token()
|
||||
else if (not is_any_print(ch))
|
||||
error("invalid character in comment");
|
||||
break;
|
||||
|
||||
case QuestionMark:
|
||||
|
||||
case State::QuestionMark:
|
||||
if (not is_non_blank(ch))
|
||||
{
|
||||
retract();
|
||||
result = CIFToken::VALUE_UNKNOWN;
|
||||
result = CIFToken::VALUE;
|
||||
}
|
||||
else
|
||||
state = Value;
|
||||
state = State::Value;
|
||||
break;
|
||||
|
||||
case TextItemBS:
|
||||
if (ch == '\\')
|
||||
{
|
||||
state = TextItemBS2;
|
||||
break;
|
||||
}
|
||||
[[fallthrough]];
|
||||
|
||||
case TextItem:
|
||||
case State::TextItem:
|
||||
if (ch == '\n')
|
||||
state = TextItemNL;
|
||||
state = State::TextItemNL;
|
||||
else if (ch == kEOF)
|
||||
error("unterminated textfield");
|
||||
else if (not is_any_print(ch) and VERBOSE > 2)
|
||||
warning("invalid character in text field '" + std::string({ static_cast<char>(ch) }) + "' (" + std::to_string(ch) + ")");
|
||||
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 TextItemBS2:
|
||||
if (ch == '\n')
|
||||
{
|
||||
if (m_token_buffer[m_token_buffer.size() - 2] == '\\')
|
||||
{
|
||||
m_token_buffer.pop_back();
|
||||
m_token_buffer.pop_back();
|
||||
}
|
||||
state = TextItemBSNL;
|
||||
}
|
||||
else if (ch == kEOF)
|
||||
error("unterminated textfield");
|
||||
else if (not is_any_print(ch) and VERBOSE > 2)
|
||||
warning("invalid character in text field '" + std::string({ static_cast<char>(ch) }) + "' (" + std::to_string(ch) + ")");
|
||||
break;
|
||||
|
||||
case TextItemBSNL:
|
||||
case State::TextItemNL:
|
||||
if (is_text_lead(ch) or ch == ' ' or ch == '\t')
|
||||
state = TextItemBS;
|
||||
state = State::TextItem;
|
||||
else if (ch == ';')
|
||||
{
|
||||
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_CHARSTRING;
|
||||
result = CIFToken::VALUE;
|
||||
}
|
||||
else if (ch == kEOF)
|
||||
error("unterminated textfield");
|
||||
@@ -426,35 +374,20 @@ sac_parser::CIFToken sac_parser::get_next_token()
|
||||
error("invalid character in text field");
|
||||
break;
|
||||
|
||||
case TextItemNL:
|
||||
if (is_text_lead(ch) or ch == ' ' or ch == '\t')
|
||||
state = TextItem;
|
||||
else if (ch == ';')
|
||||
{
|
||||
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_TEXTFIELD;
|
||||
}
|
||||
else if (ch == kEOF)
|
||||
error("unterminated textfield");
|
||||
else if (ch != '\n')
|
||||
error("invalid character in text field");
|
||||
break;
|
||||
|
||||
case QuotedString:
|
||||
case State::QuotedString:
|
||||
if (ch == kEOF)
|
||||
error("unterminated quoted string");
|
||||
else if (ch == quoteChar)
|
||||
state = QuotedStringQuote;
|
||||
else if (not is_any_print(ch) and VERBOSE > 2)
|
||||
warning("invalid character in quoted string: '" + std::string({ static_cast<char>(ch) }) + "' (" + std::to_string(ch) + ")");
|
||||
state = State::QuotedStringQuote;
|
||||
else if (not is_any_print(ch) and cif::VERBOSE > 2)
|
||||
warning("invalid character in quoted string: '" + std::string({static_cast<char>(ch)}) + "' (" + std::to_string((int)ch) + ")");
|
||||
break;
|
||||
|
||||
case QuotedStringQuote:
|
||||
case State::QuotedStringQuote:
|
||||
if (is_white(ch))
|
||||
{
|
||||
retract();
|
||||
result = CIFToken::VALUE_CHARSTRING;
|
||||
result = CIFToken::VALUE;
|
||||
if (m_token_buffer.size() < 2)
|
||||
error("Invalid quoted string token");
|
||||
|
||||
@@ -463,14 +396,14 @@ sac_parser::CIFToken sac_parser::get_next_token()
|
||||
else if (ch == quoteChar)
|
||||
;
|
||||
else if (is_any_print(ch))
|
||||
state = QuotedString;
|
||||
state = State::QuotedString;
|
||||
else if (ch == kEOF)
|
||||
error("unterminated quoted string");
|
||||
else
|
||||
error("invalid character in quoted string");
|
||||
break;
|
||||
|
||||
case ItemName:
|
||||
case State::ItemName:
|
||||
if (not is_non_blank(ch))
|
||||
{
|
||||
retract();
|
||||
@@ -479,7 +412,7 @@ sac_parser::CIFToken sac_parser::get_next_token()
|
||||
}
|
||||
break;
|
||||
|
||||
case Reserved:
|
||||
case State::Reserved:
|
||||
switch (dag.move(ch))
|
||||
{
|
||||
case reserved_words_automaton::undefined:
|
||||
@@ -489,11 +422,11 @@ sac_parser::CIFToken sac_parser::get_next_token()
|
||||
if (not is_non_blank(ch))
|
||||
{
|
||||
retract();
|
||||
result = CIFToken::VALUE_CHARSTRING;
|
||||
result = CIFToken::VALUE;
|
||||
m_token_value = std::string_view(m_token_buffer.data(), m_token_buffer.size());
|
||||
}
|
||||
else
|
||||
state = Value;
|
||||
state = State::Value;
|
||||
break;
|
||||
|
||||
case reserved_words_automaton::data:
|
||||
@@ -530,90 +463,11 @@ sac_parser::CIFToken sac_parser::get_next_token()
|
||||
}
|
||||
break;
|
||||
|
||||
case Numeric_Zero:
|
||||
case State::Value:
|
||||
if (not is_non_blank(ch))
|
||||
{
|
||||
retract();
|
||||
result = CIFToken::VALUE_NUMERIC_INTEGER;
|
||||
}
|
||||
else if (ch == '.')
|
||||
state = Numeric_Float;
|
||||
else
|
||||
state = Value;
|
||||
break;
|
||||
|
||||
case Numeric_Integer:
|
||||
if (ch == '.')
|
||||
state = Numeric_Float;
|
||||
else if (ch == 'e' or ch == 'E')
|
||||
state = Numeric_Exponent1;
|
||||
else if (not is_non_blank(ch))
|
||||
{
|
||||
retract();
|
||||
if (m_token_buffer.size() == 1 and negative)
|
||||
{
|
||||
result = CIFToken::VALUE_CHARSTRING; // A single hyphen...
|
||||
m_token_value = std::string_view{ m_token_buffer.data(), m_token_buffer.data() + 1 };
|
||||
}
|
||||
else
|
||||
result = CIFToken::VALUE_NUMERIC_INTEGER;
|
||||
}
|
||||
else if (ch < '0' or ch > '9')
|
||||
state = Value;
|
||||
break;
|
||||
|
||||
case Numeric_Float:
|
||||
if (not is_non_blank(ch))
|
||||
{
|
||||
retract();
|
||||
if (m_token_buffer.size() == 1)
|
||||
result = CIFToken::VALUE_INAPPLICABLE;
|
||||
else
|
||||
result = CIFToken::VALUE_NUMERIC_FLOAT;
|
||||
}
|
||||
else if (ch == 'e' or ch == 'E')
|
||||
state = Numeric_Exponent1;
|
||||
else if (ch < '0' or ch > '9')
|
||||
state = Value;
|
||||
else
|
||||
++m_float_precision;
|
||||
break;
|
||||
|
||||
case Numeric_Exponent1:
|
||||
if (not is_non_blank(ch))
|
||||
{
|
||||
retract();
|
||||
result = CIFToken::VALUE_CHARSTRING;
|
||||
m_token_value = std::string_view(m_token_buffer.data(), m_token_buffer.size());
|
||||
}
|
||||
else if (ch == '+' or ch == '-' or (ch >= '0' and ch <= '9'))
|
||||
state = Numeric_Exponent2;
|
||||
else
|
||||
{
|
||||
// warning(std::format("parsing {}: Invalid floating point value, expected digit or sign character", std::string_view{ m_token_buffer.data(), m_token_buffer.size() }));
|
||||
state = Value;
|
||||
}
|
||||
break;
|
||||
|
||||
case Numeric_Exponent2:
|
||||
if (not is_non_blank(ch))
|
||||
{
|
||||
retract();
|
||||
result = CIFToken::VALUE_NUMERIC_FLOAT;
|
||||
}
|
||||
else if (ch < '0' or ch > '9')
|
||||
{
|
||||
if (VERBOSE > 0)
|
||||
// warning(std::format("parsing {}: Invalid floating point value, expected digit or sign character", std::string_view{ m_token_buffer.data(), m_token_buffer.size() }));
|
||||
state = Value;
|
||||
}
|
||||
break;
|
||||
|
||||
case Value:
|
||||
if (not is_non_blank(ch))
|
||||
{
|
||||
retract();
|
||||
result = CIFToken::VALUE_CHARSTRING;
|
||||
result = CIFToken::VALUE;
|
||||
m_token_value = std::string_view(m_token_buffer.data(), m_token_buffer.size());
|
||||
break;
|
||||
}
|
||||
@@ -626,38 +480,12 @@ sac_parser::CIFToken sac_parser::get_next_token()
|
||||
}
|
||||
}
|
||||
|
||||
// if (VERBOSE >= 5)
|
||||
// {
|
||||
// std::cerr << get_token_name(result);
|
||||
// if (result != CIFToken::END_OF_FILE)
|
||||
// std::cerr << " " << std::quoted(m_token_value);
|
||||
// std::cerr << '\n';
|
||||
// }
|
||||
|
||||
if (result == CIFToken::VALUE_NUMERIC_INTEGER)
|
||||
if (VERBOSE >= 5)
|
||||
{
|
||||
// Avoid interpreting phone numbers as integers, TODO: check if this is an issue
|
||||
auto [ptr, ec] = from_chars(m_token_buffer.data(), m_token_buffer.data() + m_token_buffer.size(), m_token_value_int);
|
||||
if (ec != std::errc{})
|
||||
{
|
||||
if (cif::VERBOSE > 0)
|
||||
std::clog << "Invalid integer value: " << std::make_error_code(ec).message() << '\n';
|
||||
|
||||
result = CIFToken::VALUE_CHARSTRING;
|
||||
m_token_value = std::string_view(m_token_buffer.data(), m_token_buffer.size());
|
||||
}
|
||||
}
|
||||
else if (result == CIFToken::VALUE_NUMERIC_FLOAT)
|
||||
{
|
||||
auto [ptr, ec] = from_chars(m_token_buffer.data(), m_token_buffer.data() + m_token_buffer.size(), m_token_value_float);
|
||||
if (ec != std::errc{})
|
||||
{
|
||||
if (cif::VERBOSE > 0)
|
||||
std::clog << "Invalid floating point value: " << std::make_error_code(ec).message() << '\n';
|
||||
|
||||
result = CIFToken::VALUE_CHARSTRING;
|
||||
m_token_value = std::string_view(m_token_buffer.data(), m_token_buffer.size());
|
||||
}
|
||||
std::cerr << get_token_name(result);
|
||||
if (result != CIFToken::END_OF_FILE)
|
||||
std::cerr << " " << std::quoted(m_token_value);
|
||||
std::cerr << '\n';
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -712,7 +540,6 @@ bool sac_parser::parse_single_datablock(const std::string &datablock)
|
||||
if (bol)
|
||||
state = qstring;
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -806,7 +633,6 @@ sac_parser::datablock_index sac_parser::index_datablocks()
|
||||
if (bol)
|
||||
state = qstring;
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -835,7 +661,7 @@ sac_parser::datablock_index sac_parser::index_datablocks()
|
||||
case data:
|
||||
if (dblk[si] == 0 and is_non_blank(ch))
|
||||
{
|
||||
datablock = { static_cast<char>(ch) };
|
||||
datablock = {static_cast<char>(ch)};
|
||||
state = data_name;
|
||||
}
|
||||
else if (dblk[si++] != ch)
|
||||
@@ -844,7 +670,7 @@ sac_parser::datablock_index sac_parser::index_datablocks()
|
||||
|
||||
case data_name:
|
||||
if (is_non_blank(ch))
|
||||
datablock.insert(datablock.end(), static_cast<char>(std::toupper(ch)));
|
||||
datablock.insert(datablock.end(), (char)std::toupper(ch));
|
||||
else if (is_space(ch))
|
||||
{
|
||||
if (not datablock.empty())
|
||||
@@ -912,17 +738,14 @@ void sac_parser::parse_global()
|
||||
while (m_lookahead == CIFToken::ITEM_NAME)
|
||||
{
|
||||
match(CIFToken::ITEM_NAME);
|
||||
if (m_lookahead >= CIFToken::VALUE_INAPPLICABLE)
|
||||
match(m_lookahead);
|
||||
else
|
||||
match(CIFToken::VALUE_CHARSTRING);
|
||||
match(CIFToken::VALUE);
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
std::string cat = kUnitializedCategory; // intial value acts as a guard for empty category names
|
||||
|
||||
while (m_lookahead == CIFToken::LOOP or m_lookahead == CIFToken::ITEM_NAME or m_lookahead == CIFToken::SAVE_NAME)
|
||||
{
|
||||
@@ -954,38 +777,14 @@ void sac_parser::parse_datablock()
|
||||
match(CIFToken::ITEM_NAME);
|
||||
}
|
||||
|
||||
while (m_lookahead >= CIFToken::VALUE_INAPPLICABLE)
|
||||
while (m_lookahead == CIFToken::VALUE)
|
||||
{
|
||||
produce_row();
|
||||
|
||||
for (auto item_name : item_names)
|
||||
{
|
||||
switch (m_lookahead)
|
||||
{
|
||||
case CIFToken::VALUE_INAPPLICABLE:
|
||||
produce_item(cat, item_name, item_value_type::INAPPLICABLE);
|
||||
match(m_lookahead);
|
||||
break;
|
||||
case CIFToken::VALUE_UNKNOWN:
|
||||
produce_item(cat, item_name, item_value_type::MISSING);
|
||||
match(m_lookahead);
|
||||
break;
|
||||
case CIFToken::VALUE_NUMERIC_INTEGER:
|
||||
produce_item(cat, item_name, m_token_value_int);
|
||||
match(m_lookahead);
|
||||
break;
|
||||
case CIFToken::VALUE_NUMERIC_FLOAT:
|
||||
produce_item(cat, item_name, { m_token_value_float, m_float_precision });
|
||||
match(m_lookahead);
|
||||
break;
|
||||
case CIFToken::VALUE_CHARSTRING:
|
||||
case CIFToken::VALUE_TEXTFIELD:
|
||||
produce_item(cat, item_name, m_token_value);
|
||||
match(m_lookahead);
|
||||
break;
|
||||
default:;
|
||||
match(CIFToken::VALUE_CHARSTRING);
|
||||
}
|
||||
produce_item(cat, item_name, m_token_value);
|
||||
match(CIFToken::VALUE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1007,33 +806,9 @@ void sac_parser::parse_datablock()
|
||||
|
||||
match(CIFToken::ITEM_NAME);
|
||||
|
||||
switch (m_lookahead)
|
||||
{
|
||||
case CIFToken::VALUE_INAPPLICABLE:
|
||||
produce_item(cat, itemName, item_value_type::INAPPLICABLE);
|
||||
match(CIFToken::VALUE_INAPPLICABLE);
|
||||
break;
|
||||
case CIFToken::VALUE_UNKNOWN:
|
||||
produce_item(cat, itemName, item_value_type::MISSING);
|
||||
match(CIFToken::VALUE_UNKNOWN);
|
||||
break;
|
||||
case CIFToken::VALUE_NUMERIC_INTEGER:
|
||||
produce_item(cat, itemName, m_token_value_int);
|
||||
match(CIFToken::VALUE_NUMERIC_INTEGER);
|
||||
break;
|
||||
case CIFToken::VALUE_NUMERIC_FLOAT:
|
||||
produce_item(cat, itemName, { m_token_value_float, m_float_precision });
|
||||
match(CIFToken::VALUE_NUMERIC_FLOAT);
|
||||
break;
|
||||
case CIFToken::VALUE_CHARSTRING:
|
||||
case CIFToken::VALUE_TEXTFIELD:
|
||||
produce_item(cat, itemName, m_token_value);
|
||||
match(m_lookahead);
|
||||
break;
|
||||
default:
|
||||
match(CIFToken::VALUE_CHARSTRING);
|
||||
}
|
||||
produce_item(cat, itemName, m_token_value);
|
||||
|
||||
match(CIFToken::VALUE);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1072,9 +847,7 @@ void parser::produce_category(std::string_view name)
|
||||
if (VERBOSE >= 4)
|
||||
std::cerr << "producing category " << name << '\n';
|
||||
|
||||
const auto &[cat, is_new] = m_datablock->emplace(name);
|
||||
if (is_new and m_validator)
|
||||
cat->set_validator(m_validator, *m_datablock);
|
||||
const auto &[cat, ignore] = m_datablock->emplace(name);
|
||||
m_category = &*cat;
|
||||
}
|
||||
|
||||
@@ -1086,11 +859,12 @@ void parser::produce_row()
|
||||
if (m_category == nullptr)
|
||||
error("inconsistent categories in loop_");
|
||||
|
||||
auto i = m_category->emplace({});
|
||||
m_row = *i;
|
||||
m_category->emplace({});
|
||||
m_row = m_category->back();
|
||||
// m_row.lineNr(m_line_nr);
|
||||
}
|
||||
|
||||
void parser::produce_item(std::string_view category, std::string_view item, item_value 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 << '\n';
|
||||
@@ -1098,20 +872,7 @@ void parser::produce_item(std::string_view category, std::string_view item, item
|
||||
if (m_category == nullptr or not iequals(category, m_category->name()))
|
||||
error("inconsistent categories in loop_");
|
||||
|
||||
if (value.is_number())
|
||||
{
|
||||
auto cv = m_category->get_cat_validator();
|
||||
if (cv != nullptr)
|
||||
{
|
||||
if (auto iv = cv->get_validator_for_item(item))
|
||||
{
|
||||
if (auto tv = iv->m_type; tv and tv->m_primitive_type != DDL_PrimitiveType::Numb)
|
||||
value = std::string_view{ m_token_buffer.data(), m_token_buffer.data() + m_token_buffer.size() };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_row[item].set(value, false);
|
||||
m_row[item] = m_token_value;
|
||||
}
|
||||
|
||||
} // namespace cif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -26,19 +26,10 @@
|
||||
|
||||
#include "pdb2cif_remark_3.hpp"
|
||||
|
||||
#include "cif++/cif++.hpp"
|
||||
#include <cif++.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <cctype>
|
||||
#include <exception>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
// NOLINTBEGIN(bugprone-empty-catch)
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
namespace cif::pdb
|
||||
{
|
||||
@@ -162,7 +153,7 @@ const TemplateLine kBusterTNT_Template[] = {
|
||||
class BUSTER_TNT_Remark3Parser : public Remark3Parser
|
||||
{
|
||||
public:
|
||||
BUSTER_TNT_Remark3Parser(std::string name, std::string expMethod, PDBRecord *r, cif::datablock &db)
|
||||
BUSTER_TNT_Remark3Parser(const std::string &name, const std::string &expMethod, PDBRecord *r, cif::datablock &db)
|
||||
: Remark3Parser(name, expMethod, r, db,
|
||||
kBusterTNT_Template, sizeof(kBusterTNT_Template) / sizeof(TemplateLine),
|
||||
std::regex(R"((BUSTER(?:-TNT)?)(?: (\d+(?:\..+)?))?)"))
|
||||
@@ -246,28 +237,18 @@ const TemplateLine kCNS_Template[] = {
|
||||
/* 72 */ { R"(METHOD USED\s*:\s*(.+))", 1, "refine", { "solvent_model_details" } },
|
||||
/* 73 */ { R"(KSOL\s*:\s*(.+))", 1, "refine", { "solvent_model_param_ksol" } },
|
||||
/* 74 */ { R"(BSOL\s*:\s*(.+))", 1, "refine", { "solvent_model_param_bsol" } },
|
||||
/* 75 */ { R"(NCS MODEL\s*:\s*(.+))",
|
||||
1,
|
||||
/* "refine_ls_restr_ncs", { "ncs_model_details" } */ },
|
||||
/* 75 */ { R"(NCS MODEL\s*:\s*(.+))", 1, /* "refine_ls_restr_ncs", { "ncs_model_details" } */ },
|
||||
/* 76 */ { R"(NCS RESTRAINTS\. RMS SIGMA/WEIGHT)", 1 },
|
||||
/* 77 */ { R"(GROUP (\d+) POSITIONAL \(A\)\s*:\s*(.+))",
|
||||
1,
|
||||
/* "refine_ls_restr_ncs", { "dom_id", "rms_dev_position", "weight_position" } */ },
|
||||
/* 78 */ { R"(GROUP (\d+) B-FACTOR \(A\*\*2\)\s*:\s*(.+))",
|
||||
1,
|
||||
/* "refine_ls_restr_ncs", { "dom_id", "rms_dev_B_iso", "weight_B_iso" } */ },
|
||||
/* 79 */ { R"(PARAMETER FILE (\d+) :\s+(.+))",
|
||||
1,
|
||||
/* "pdbx_xplor_file", { "serial_no", "param_file" } */ },
|
||||
/* 80 */ { R"(TOPOLOGY FILE (\d+) :\s+(.+))",
|
||||
1,
|
||||
/* "pdbx_xplor_file", { "serial_no", "topol_file" } */ },
|
||||
/* 77 */ { R"(GROUP (\d+) POSITIONAL \(A\)\s*:\s*(.+))", 1, /* "refine_ls_restr_ncs", { "dom_id", "rms_dev_position", "weight_position" } */ },
|
||||
/* 78 */ { R"(GROUP (\d+) B-FACTOR \(A\*\*2\)\s*:\s*(.+))", 1, /* "refine_ls_restr_ncs", { "dom_id", "rms_dev_B_iso", "weight_B_iso" } */ },
|
||||
/* 79 */ { R"(PARAMETER FILE (\d+) :\s+(.+))", 1, /* "pdbx_xplor_file", { "serial_no", "param_file" } */ },
|
||||
/* 80 */ { R"(TOPOLOGY FILE (\d+) :\s+(.+))", 1, /* "pdbx_xplor_file", { "serial_no", "topol_file" } */ },
|
||||
};
|
||||
|
||||
class CNS_Remark3Parser : public Remark3Parser
|
||||
{
|
||||
public:
|
||||
CNS_Remark3Parser(std::string name, std::string expMethod, PDBRecord *r, cif::datablock &db)
|
||||
CNS_Remark3Parser(const std::string &name, const std::string &expMethod, PDBRecord *r, cif::datablock &db)
|
||||
: Remark3Parser(name, expMethod, r, db, kCNS_Template,
|
||||
sizeof(kCNS_Template) / sizeof(TemplateLine), std::regex(R"((CN[SX])(?: (\d+(?:\.\d+)?))?)"))
|
||||
{
|
||||
@@ -351,13 +332,13 @@ const TemplateLine kPHENIX_Template[] = {
|
||||
class PHENIX_Remark3Parser : public Remark3Parser
|
||||
{
|
||||
public:
|
||||
PHENIX_Remark3Parser(std::string name, std::string expMethod, PDBRecord *r, cif::datablock &db)
|
||||
PHENIX_Remark3Parser(const std::string &name, const std::string &expMethod, PDBRecord *r, cif::datablock &db)
|
||||
: Remark3Parser(name, expMethod, r, db, kPHENIX_Template, sizeof(kPHENIX_Template) / sizeof(TemplateLine),
|
||||
std::regex(R"((PHENIX)(?: \(PHENIX\.REFINE:) (\d+(?:\.[^)]+)?)\)?)"))
|
||||
{
|
||||
}
|
||||
|
||||
void fixup() override;
|
||||
virtual void fixup();
|
||||
};
|
||||
|
||||
void PHENIX_Remark3Parser::fixup()
|
||||
@@ -366,7 +347,7 @@ void PHENIX_Remark3Parser::fixup()
|
||||
{
|
||||
try
|
||||
{
|
||||
auto val = r["percent_reflns_obs"].get<float>();
|
||||
float val = r["percent_reflns_obs"].as<float>();
|
||||
int perc = static_cast<int>(val * 100);
|
||||
r["percent_reflns_obs"] = perc;
|
||||
}
|
||||
@@ -439,13 +420,13 @@ const TemplateLine kNUCLSQ_Template[] = {
|
||||
class NUCLSQ_Remark3Parser : public Remark3Parser
|
||||
{
|
||||
public:
|
||||
NUCLSQ_Remark3Parser(std::string name, std::string expMethod, PDBRecord *r, cif::datablock &db)
|
||||
NUCLSQ_Remark3Parser(const std::string &name, const std::string &expMethod, PDBRecord *r, cif::datablock &db)
|
||||
: Remark3Parser(name, expMethod, r, db, kNUCLSQ_Template, sizeof(kNUCLSQ_Template) / sizeof(TemplateLine),
|
||||
std::regex(R"((NUCLSQ)(?: (\d+(?:\.\d+)?))?)"))
|
||||
{
|
||||
}
|
||||
|
||||
void fixup() override
|
||||
virtual void fixup()
|
||||
{
|
||||
for (auto r : mDb["refine_hist"])
|
||||
{
|
||||
@@ -532,13 +513,13 @@ const TemplateLine kPROLSQ_Template[] = {
|
||||
class PROLSQ_Remark3Parser : public Remark3Parser
|
||||
{
|
||||
public:
|
||||
PROLSQ_Remark3Parser(std::string name, std::string expMethod, PDBRecord *r, cif::datablock &db)
|
||||
PROLSQ_Remark3Parser(const std::string &name, const std::string &expMethod, PDBRecord *r, cif::datablock &db)
|
||||
: Remark3Parser(name, expMethod, r, db, kPROLSQ_Template, sizeof(kPROLSQ_Template) / sizeof(TemplateLine),
|
||||
std::regex(R"((PROLSQ)(?: (\d+(?:\.\d+)?))?)"))
|
||||
{
|
||||
}
|
||||
|
||||
void fixup() override
|
||||
virtual void fixup()
|
||||
{
|
||||
for (auto r : mDb["refine_hist"])
|
||||
{
|
||||
@@ -575,9 +556,7 @@ const TemplateLine kREFMAC_Template[] = {
|
||||
/* 17 */ { R"(NUCLEIC ACID ATOMS\s*:\s*(.+))", 1, "refine_hist", { "pdbx_number_atoms_nucleic_acid" } },
|
||||
/* 18 */ { R"(HETEROGEN ATOMS\s*:\s*(.+))", 1, "refine_hist", { "pdbx_number_atoms_ligand" } },
|
||||
/* 19 */ { R"(SOLVENT ATOMS\s*:\s*(.+))", 1, "refine_hist", { "number_atoms_solvent" } },
|
||||
/* 20 */ { R"(ALL ATOMS\s*:\s*(.+))",
|
||||
1,
|
||||
/* "refine_hist", "pdbx_number_atoms_protein" */ },
|
||||
/* 20 */ { R"(ALL ATOMS\s*:\s*(.+))", 1, /* "refine_hist", "pdbx_number_atoms_protein" */ },
|
||||
/* 21 */ { R"(B VALUES\..*)", 1 },
|
||||
/* 22 */ { R"(B VALUE TYPE\s*:\s*(.+))", 1, "refine", { "pdbx_TLS_residual_ADP_flag" } },
|
||||
/* 23 */ { R"(FROM WILSON PLOT \(A\*\*2\)\s*:\s*(.+))", 1, "reflns", { "B_iso_Wilson_estimate" } },
|
||||
@@ -622,14 +601,14 @@ const TemplateLine kREFMAC_Template[] = {
|
||||
class REFMAC_Remark3Parser : public Remark3Parser
|
||||
{
|
||||
public:
|
||||
REFMAC_Remark3Parser(std::string name, std::string expMethod, PDBRecord *r, cif::datablock &db)
|
||||
REFMAC_Remark3Parser(const std::string &name, const std::string &expMethod, PDBRecord *r, cif::datablock &db)
|
||||
: Remark3Parser(name, expMethod, r, db, kREFMAC_Template, sizeof(kREFMAC_Template) / sizeof(TemplateLine),
|
||||
std::regex(".+"))
|
||||
{
|
||||
}
|
||||
|
||||
std::string program() override { return "REFMAC"; }
|
||||
std::string version() override { return ""; }
|
||||
virtual std::string program() { return "REFMAC"; }
|
||||
virtual std::string version() { return ""; }
|
||||
};
|
||||
|
||||
const TemplateLine kREFMAC5_Template[] = {
|
||||
@@ -662,9 +641,7 @@ const TemplateLine kREFMAC5_Template[] = {
|
||||
/* 26 */ { R"(NUCLEIC ACID ATOMS\s*:\s*(.+))", 1, "refine_hist", { "pdbx_number_atoms_nucleic_acid" } },
|
||||
/* 27 */ { R"(HETEROGEN ATOMS\s*:\s*(.+))", 1, "refine_hist", { "pdbx_number_atoms_ligand" } },
|
||||
/* 28 */ { R"(SOLVENT ATOMS\s*:\s*(.+))", 1, "refine_hist", { "number_atoms_solvent" } },
|
||||
/* 29 */ { R"(ALL ATOMS\s*:\s*(.+))",
|
||||
1,
|
||||
/* "refine_hist", { "pdbx_number_atoms_protein" } */ },
|
||||
/* 29 */ { R"(ALL ATOMS\s*:\s*(.+))", 1, /* "refine_hist", { "pdbx_number_atoms_protein" } */ },
|
||||
/* 30 */ { R"(B VALUES\..*)", 1 },
|
||||
/* 31 */ { R"(B VALUE TYPE\s*:\s*(.+))", 1, "refine", { "pdbx_TLS_residual_ADP_flag" } },
|
||||
/* 32 */ { R"(FROM WILSON PLOT \(A\*\*2\)\s*:\s*(.+))", 1, "reflns", { "B_iso_Wilson_estimate" } },
|
||||
@@ -728,12 +705,8 @@ const TemplateLine kREFMAC5_Template[] = {
|
||||
// Simply ignore NCS, you can ask Robbie why
|
||||
/* 90 */ { R"(NCS RESTRAINTS STATISTICS)", 1 },
|
||||
/* 91 */ { R"(NUMBER OF DIFFERENT NCS GROUPS\s*:\s*(.+))", 1 },
|
||||
/* 92 */ { R"(NCS GROUP NUMBER\s*:\s*(\d+))",
|
||||
1,
|
||||
/*"struct_ncs_dom", { "pdbx_ens_id" }*/ },
|
||||
/* 93 */ { R"(CHAIN NAMES\s*:\s*(.+))",
|
||||
1,
|
||||
/*"struct_ncs_dom", { "details" }*/ },
|
||||
/* 92 */ { R"(NCS GROUP NUMBER\s*:\s*(\d+))", 1, /*"struct_ncs_dom", { "pdbx_ens_id" }*/ },
|
||||
/* 93 */ { R"(CHAIN NAMES\s*:\s*(.+))", 1, /*"struct_ncs_dom", { "details" }*/ },
|
||||
/* 94 */ { R"(NUMBER OF COMPONENTS NCS GROUP\s*:\s*(\d+))", 1 },
|
||||
/* 95 */ { R"(COMPONENT C SSSEQI TO C SSSEQI CODE)", 1 },
|
||||
//// This sucks.... The following line is fixed format
|
||||
@@ -746,9 +719,7 @@ const TemplateLine kREFMAC5_Template[] = {
|
||||
/* 102 */ { R"(TIGHT THERMAL\s+\d+\s+(.)\s+\(A\*\*2\):\s+(\d+)\s*;\s*(\d+(?:\.\d*)?)\s*;\s*(\d+(?:\.\d*)?))", 0 }, // , "refine_ls_restr_ncs", {"pdbx_auth_asym_id", "pdbx_number", "rms_dev_position", "weight_position"}, { "pdbx_type", "tight thermal", }, 1 },
|
||||
/* 103 */ { R"(MEDIUM THERMAL\s+\d+\s+(.)\s+\(A\*\*2\):\s+(\d+)\s*;\s*(\d+(?:\.\d*)?)\s*;\s*(\d+(?:\.\d*)?))", 0 }, // , "refine_ls_restr_ncs", {"pdbx_auth_asym_id", "pdbx_number", "rms_dev_position", "weight_position"}, { "pdbx_type", "medium thermal", }, 1 },
|
||||
/* 104 */ { R"(LOOSE THERMAL\s+\d+\s+(.)\s+\(A\*\*2\):\s+(\d+)\s*;\s*(\d+(?:\.\d*)?)\s*;\s*(\d+(?:\.\d*)?))", 0 }, // , "refine_ls_restr_ncs", {"pdbx_auth_asym_id", "pdbx_number", "rms_dev_position", "weight_position"}, { "pdbx_type", "loose thermal", }, 10 },
|
||||
/* 105 */ { R"(NCS GROUP NUMBER\s*:\s*(\d+))",
|
||||
93 - 105,
|
||||
/*"struct_ncs_dom", { "pdbx_ens_id" }*/ },
|
||||
/* 105 */ { R"(NCS GROUP NUMBER\s*:\s*(\d+))", 93 - 105, /*"struct_ncs_dom", { "pdbx_ens_id" }*/ },
|
||||
/* 106 */ { R"(TWIN DETAILS)", 1 },
|
||||
/* 107 */ { R"(NUMBER OF TWIN DOMAINS\s*:\s*(\d*))", 1 },
|
||||
/* 108 */ { R"(TWIN DOMAIN\s*:\s*(.+))", 1, "pdbx_reflns_twin", { "domain_id" }, nullptr, true },
|
||||
@@ -784,7 +755,7 @@ const TemplateLine kREFMAC5_Template[] = {
|
||||
class REFMAC5_Remark3Parser : public Remark3Parser
|
||||
{
|
||||
public:
|
||||
REFMAC5_Remark3Parser(std::string name, std::string expMethod, PDBRecord *r, cif::datablock &db)
|
||||
REFMAC5_Remark3Parser(const std::string &name, const std::string &expMethod, PDBRecord *r, cif::datablock &db)
|
||||
: Remark3Parser(name, expMethod, r, db, kREFMAC5_Template, sizeof(kREFMAC5_Template) / sizeof(TemplateLine),
|
||||
std::regex(R"((REFMAC)(?: (\d+(?:\..+)?))?)"))
|
||||
{
|
||||
@@ -844,7 +815,7 @@ const TemplateLine kSHELXL_Template[] = {
|
||||
class SHELXL_Remark3Parser : public Remark3Parser
|
||||
{
|
||||
public:
|
||||
SHELXL_Remark3Parser(std::string name, std::string expMethod, PDBRecord *r, cif::datablock &db)
|
||||
SHELXL_Remark3Parser(const std::string &name, const std::string &expMethod, PDBRecord *r, cif::datablock &db)
|
||||
: Remark3Parser(name, expMethod, r, db, kSHELXL_Template, sizeof(kSHELXL_Template) / sizeof(TemplateLine),
|
||||
std::regex(R"((SHELXL)(?:-(\d+(?:\..+)?)))"))
|
||||
{
|
||||
@@ -901,7 +872,7 @@ const TemplateLine kTNT_Template[] = {
|
||||
class TNT_Remark3Parser : public Remark3Parser
|
||||
{
|
||||
public:
|
||||
TNT_Remark3Parser(std::string name, std::string expMethod, PDBRecord *r, cif::datablock &db)
|
||||
TNT_Remark3Parser(const std::string &name, const std::string &expMethod, PDBRecord *r, cif::datablock &db)
|
||||
: Remark3Parser(name, expMethod, r, db, kTNT_Template, sizeof(kTNT_Template) / sizeof(TemplateLine),
|
||||
std::regex(R"((TNT)(?: V. (\d+.+)?)?)"))
|
||||
{
|
||||
@@ -970,28 +941,18 @@ const TemplateLine kXPLOR_Template[] = {
|
||||
/* 58 */ { R"(MAIN-CHAIN ANGLE \(A\*\*2\) :\s+(.+?);\s+(.+))", 1, "refine_ls_restr", { "dev_ideal", "dev_ideal_target" }, "x_mcangle_it", false },
|
||||
/* 59 */ { R"(SIDE-CHAIN BOND \(A\*\*2\) :\s+(.+?);\s+(.+))", 1, "refine_ls_restr", { "dev_ideal", "dev_ideal_target" }, "x_scbond_it", false },
|
||||
/* 60 */ { R"(SIDE-CHAIN ANGLE \(A\*\*2\) :\s+(.+?);\s+(.+))", 1, "refine_ls_restr", { "dev_ideal", "dev_ideal_target" }, "x_scangle_it", false },
|
||||
/* 61 */ { R"(NCS MODEL :\s+(.+))",
|
||||
1,
|
||||
/* "refine_ls_restr_ncs", { "ncs_model_details" } */ },
|
||||
/* 61 */ { R"(NCS MODEL :\s+(.+))", 1, /* "refine_ls_restr_ncs", { "ncs_model_details" } */ },
|
||||
/* 62 */ { R"(NCS RESTRAINTS\. RMS SIGMA/WEIGHT)", 1 },
|
||||
/* 63 */ { R"(GROUP (\d+) POSITIONAL \(A\) :\s+(.+?);\s+(.+))",
|
||||
1,
|
||||
/* "refine_ls_restr_ncs", { ":dom_id", "rms_dev_position", "weight_position" } */ },
|
||||
/* 64 */ { R"(GROUP (\d+) B-FACTOR \(A\*\*2\) :\s+(.+?);\s+(.+))",
|
||||
63 - 64,
|
||||
/* "refine_ls_restr_ncs", { ":dom_id", "rms_dev_B_iso", "weight_B_iso" } */ },
|
||||
/* 65 */ { R"(PARAMETER FILE (\d+) :\s+(.+))",
|
||||
0,
|
||||
/* "pdbx_xplor_file", { "serial_no", "param_file" } */ },
|
||||
/* 66 */ { R"(TOPOLOGY FILE (\d+) :\s+(.+))",
|
||||
0,
|
||||
/* "pdbx_xplor_file", { "serial_no", "topol_file" } */ },
|
||||
/* 63 */ { R"(GROUP (\d+) POSITIONAL \(A\) :\s+(.+?);\s+(.+))", 1, /* "refine_ls_restr_ncs", { ":dom_id", "rms_dev_position", "weight_position" } */ },
|
||||
/* 64 */ { R"(GROUP (\d+) B-FACTOR \(A\*\*2\) :\s+(.+?);\s+(.+))", 63 - 64, /* "refine_ls_restr_ncs", { ":dom_id", "rms_dev_B_iso", "weight_B_iso" } */ },
|
||||
/* 65 */ { R"(PARAMETER FILE (\d+) :\s+(.+))", 0, /* "pdbx_xplor_file", { "serial_no", "param_file" } */ },
|
||||
/* 66 */ { R"(TOPOLOGY FILE (\d+) :\s+(.+))", 0, /* "pdbx_xplor_file", { "serial_no", "topol_file" } */ },
|
||||
};
|
||||
|
||||
class XPLOR_Remark3Parser : public Remark3Parser
|
||||
{
|
||||
public:
|
||||
XPLOR_Remark3Parser(std::string name, std::string expMethod, PDBRecord *r, cif::datablock &db)
|
||||
XPLOR_Remark3Parser(const std::string &name, const std::string &expMethod, PDBRecord *r, cif::datablock &db)
|
||||
: Remark3Parser(name, expMethod, r, db, kXPLOR_Template, sizeof(kXPLOR_Template) / sizeof(TemplateLine),
|
||||
std::regex(R"((X-PLOR)(?: (\d+(?:\.\d+)?))?)"))
|
||||
{
|
||||
@@ -1000,15 +961,15 @@ class XPLOR_Remark3Parser : public Remark3Parser
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
Remark3Parser::Remark3Parser(std::string name, std::string expMethod, PDBRecord *r, cif::datablock &db,
|
||||
Remark3Parser::Remark3Parser(const std::string &name, const std::string &expMethod, PDBRecord *r, cif::datablock &db,
|
||||
const TemplateLine templatelines[], uint32_t templateLineCount, std::regex programversion)
|
||||
: mName(std::move(name))
|
||||
, mExpMethod(std::move(expMethod))
|
||||
: mName(name)
|
||||
, mExpMethod(expMethod)
|
||||
, mRec(r)
|
||||
, mDb(db.name())
|
||||
, mTemplate(templatelines)
|
||||
, mTemplateCount(templateLineCount)
|
||||
, mProgramVersion(std::move(programversion))
|
||||
, mProgramVersion(programversion)
|
||||
{
|
||||
mDb.set_validator(db.get_validator());
|
||||
}
|
||||
@@ -1081,13 +1042,13 @@ std::string Remark3Parser::nextLine()
|
||||
break;
|
||||
}
|
||||
|
||||
if (VERBOSE >= 2)
|
||||
if (cif::VERBOSE >= 2)
|
||||
std::cerr << "RM3: " << mLine << '\n';
|
||||
|
||||
return mLine;
|
||||
}
|
||||
|
||||
bool Remark3Parser::match(const char *expr, uint32_t nextState)
|
||||
bool Remark3Parser::match(const char *expr, int nextState)
|
||||
{
|
||||
std::regex rx(expr);
|
||||
|
||||
@@ -1095,7 +1056,7 @@ bool Remark3Parser::match(const char *expr, uint32_t nextState)
|
||||
|
||||
if (result)
|
||||
mState = nextState;
|
||||
else if (VERBOSE >= 3)
|
||||
else if (cif::VERBOSE >= 3)
|
||||
{
|
||||
using namespace colour;
|
||||
|
||||
@@ -1124,7 +1085,7 @@ float Remark3Parser::parse()
|
||||
if (mState == 0 and match(R"(AUTHORS\s*:.+)", 0))
|
||||
continue;
|
||||
|
||||
uint32_t state;
|
||||
auto state = mState;
|
||||
for (state = mState; state < mTemplateCount; ++state)
|
||||
{
|
||||
const TemplateLine &tmpl = mTemplate[state];
|
||||
@@ -1159,7 +1120,7 @@ float Remark3Parser::parse()
|
||||
continue;
|
||||
}
|
||||
|
||||
if (VERBOSE >= 2)
|
||||
if (cif::VERBOSE >= 2)
|
||||
{
|
||||
using namespace colour;
|
||||
|
||||
@@ -1175,7 +1136,7 @@ float Remark3Parser::parse()
|
||||
mDb["refine"].front()["details"] = remarks;
|
||||
}
|
||||
|
||||
float score = static_cast<float>(lineCount - dropped) / static_cast<float>(lineCount);
|
||||
float score = float(lineCount - dropped) / lineCount;
|
||||
|
||||
return score;
|
||||
}
|
||||
@@ -1215,7 +1176,7 @@ void Remark3Parser::storeCapture(const char *category, std::initializer_list<con
|
||||
if (iequals(value, "NULL") or iequals(value, "NONE") or iequals(value, "Inf") or iequals(value, "+Inf") or iequals(value, std::string(value.length(), '*')))
|
||||
continue;
|
||||
|
||||
if (VERBOSE >= 3)
|
||||
if (cif::VERBOSE >= 3)
|
||||
std::cerr << "storing: '" << value << "' in _" << category << '.' << item << '\n';
|
||||
|
||||
auto &cat = mDb[category];
|
||||
@@ -1224,7 +1185,7 @@ void Remark3Parser::storeCapture(const char *category, std::initializer_list<con
|
||||
if (iequals(category, "refine"))
|
||||
cat.emplace({ { "pdbx_refine_id", mExpMethod },
|
||||
{ "entry_id", mDb.name() },
|
||||
// #warning("this diffrn-id is probably not correct?")
|
||||
//#warning("this diffrn-id is probably not correct?")
|
||||
{ "pdbx_diffrn_id", 1 } });
|
||||
else if (iequals(category, "refine_analyze") or iequals(category, "pdbx_refine"))
|
||||
cat.emplace({
|
||||
@@ -1234,17 +1195,17 @@ void Remark3Parser::storeCapture(const char *category, std::initializer_list<con
|
||||
});
|
||||
else if (iequals(category, "refine_hist"))
|
||||
{
|
||||
std::optional<float> dResHigh, dResLow;
|
||||
std::string dResHigh, dResLow;
|
||||
for (auto r : mDb["refine"])
|
||||
{
|
||||
cif::tie(dResHigh, dResLow) = r.get<float, float>("ls_d_res_high", "ls_d_res_low");
|
||||
cif::tie(dResHigh, dResLow) = r.get("ls_d_res_high", "ls_d_res_low");
|
||||
break;
|
||||
}
|
||||
|
||||
cat.emplace({ { "pdbx_refine_id", mExpMethod },
|
||||
{ "cycle_id", "LAST" },
|
||||
{ "d_res_high", dResHigh },
|
||||
{ "d_res_low", dResLow } });
|
||||
{ "d_res_high", dResHigh.empty() ? "." : dResHigh },
|
||||
{ "d_res_low", dResLow.empty() ? "." : dResLow } });
|
||||
}
|
||||
else if (iequals(category, "refine_ls_shell"))
|
||||
{
|
||||
@@ -1256,10 +1217,11 @@ void Remark3Parser::storeCapture(const char *category, std::initializer_list<con
|
||||
{
|
||||
std::string tlsID;
|
||||
if (not mDb["pdbx_refine_tls"].empty())
|
||||
tlsID = mDb["pdbx_refine_tls"].back()["id"].get<std::string>();
|
||||
tlsID = mDb["pdbx_refine_tls"].back()["id"].as<std::string>();
|
||||
std::string tlsGroupID = cat.get_unique_id("");
|
||||
|
||||
cat.emplace({ { "pdbx_refine_id", mExpMethod },
|
||||
cat.emplace({
|
||||
{ "pdbx_refine_id", mExpMethod },
|
||||
{ "id", tlsGroupID },
|
||||
{ "refine_tls_id", tlsID } });
|
||||
}
|
||||
@@ -1314,8 +1276,10 @@ void Remark3Parser::storeRefineLsRestr(const char *type, std::initializer_list<c
|
||||
|
||||
if (r.empty())
|
||||
{
|
||||
r = mDb["refine_ls_restr"].emplace({ { "pdbx_refine_id", mExpMethod },
|
||||
{ "type", type } });
|
||||
r = mDb["refine_ls_restr"].emplace({
|
||||
{"pdbx_refine_id", mExpMethod},
|
||||
{"type", type}
|
||||
});
|
||||
}
|
||||
|
||||
r[item] = value;
|
||||
@@ -1373,7 +1337,7 @@ bool Remark3Parser::parse(const std::string &expMethod, PDBRecord *r, cif::datab
|
||||
|
||||
if (line != "REFINEMENT.")
|
||||
{
|
||||
if (VERBOSE > 0)
|
||||
if (cif::VERBOSE > 0)
|
||||
std::cerr << "Unexpected data in REMARK 3\n";
|
||||
return false;
|
||||
}
|
||||
@@ -1385,7 +1349,7 @@ bool Remark3Parser::parse(const std::string &expMethod, PDBRecord *r, cif::datab
|
||||
|
||||
if (not std::regex_match(line, m, rxp))
|
||||
{
|
||||
if (VERBOSE > 0)
|
||||
if (cif::VERBOSE > 0)
|
||||
std::cerr << "Expected valid PROGRAM line in REMARK 3\n";
|
||||
return false;
|
||||
}
|
||||
@@ -1394,8 +1358,8 @@ bool Remark3Parser::parse(const std::string &expMethod, PDBRecord *r, cif::datab
|
||||
|
||||
struct programScore
|
||||
{
|
||||
programScore(std::string program, Remark3Parser *parser, float score)
|
||||
: program(std::move(program))
|
||||
programScore(const std::string &program, Remark3Parser *parser, float score)
|
||||
: program(program)
|
||||
, parser(parser)
|
||||
, score(score)
|
||||
{
|
||||
@@ -1424,18 +1388,20 @@ bool Remark3Parser::parse(const std::string &expMethod, PDBRecord *r, cif::datab
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
if (VERBOSE >= 0)
|
||||
if (cif::VERBOSE >= 0)
|
||||
std::cerr << "Error parsing REMARK 3 with " << parser->program() << '\n'
|
||||
<< e.what() << '\n';
|
||||
score = 0;
|
||||
}
|
||||
|
||||
if (VERBOSE >= 2)
|
||||
if (cif::VERBOSE >= 2)
|
||||
std::cerr << "Score for " << parser->program() << ": " << score << '\n';
|
||||
|
||||
if (score > 0)
|
||||
{
|
||||
std::string program = parser->program();
|
||||
std::string version = parser->version();
|
||||
|
||||
scores.emplace_back(program, parser.release(), score);
|
||||
}
|
||||
};
|
||||
@@ -1464,16 +1430,16 @@ bool Remark3Parser::parse(const std::string &expMethod, PDBRecord *r, cif::datab
|
||||
tryParser(new TNT_Remark3Parser(program, expMethod, r, db));
|
||||
else if (cif::starts_with(program, "X-PLOR"))
|
||||
tryParser(new XPLOR_Remark3Parser(program, expMethod, r, db));
|
||||
else if (VERBOSE > 0)
|
||||
else if (cif::VERBOSE > 0)
|
||||
std::cerr << "Skipping unknown program (" << program << ") in REMARK 3\n";
|
||||
}
|
||||
|
||||
std::sort(scores.begin(), scores.end()); // NOLINT(modernize-use-ranges)
|
||||
sort(scores.begin(), scores.end());
|
||||
|
||||
bool guessProgram = scores.empty() or scores.front().score < 0.9f;
|
||||
if (guessProgram)
|
||||
{
|
||||
if (VERBOSE > 0)
|
||||
if (cif::VERBOSE > 0)
|
||||
std::cerr << "Unknown or untrusted program in REMARK 3, trying all parsers to see if there is a match\n";
|
||||
|
||||
tryParser(new BUSTER_TNT_Remark3Parser("BUSTER-TNT", expMethod, r, db));
|
||||
@@ -1494,11 +1460,11 @@ bool Remark3Parser::parse(const std::string &expMethod, PDBRecord *r, cif::datab
|
||||
{
|
||||
result = true;
|
||||
|
||||
sort(scores.begin(), scores.end()); // NOLINT(modernize-use-ranges)
|
||||
sort(scores.begin(), scores.end());
|
||||
|
||||
auto &best = scores.front();
|
||||
|
||||
if (VERBOSE > 0)
|
||||
if (cif::VERBOSE > 0)
|
||||
std::cerr << "Choosing " << best.parser->program() << " version '" << best.parser->version() << "' as refinement program. Score = " << best.score << '\n';
|
||||
|
||||
auto &software = db["software"];
|
||||
@@ -1512,8 +1478,6 @@ bool Remark3Parser::parse(const std::string &expMethod, PDBRecord *r, cif::datab
|
||||
|
||||
best.parser->fixup();
|
||||
|
||||
auto &validator = cif::validator_factory::instance()["mmcif_pdbx.dic"];
|
||||
|
||||
for (auto &cat1 : best.parser->mDb)
|
||||
{
|
||||
if (cat1.empty())
|
||||
@@ -1521,104 +1485,30 @@ bool Remark3Parser::parse(const std::string &expMethod, PDBRecord *r, cif::datab
|
||||
|
||||
auto &cat2 = db[cat1.name()];
|
||||
|
||||
row_handle r1 = cat1.front();
|
||||
row_handle r2;
|
||||
|
||||
if (cat2.empty() or (cat1.name() == "reflns" or cat1.name() == "refine"))
|
||||
r2 = cat2.emplace({});
|
||||
else
|
||||
r2 = cat2.front();
|
||||
|
||||
auto cv = cat1.get_cat_validator();
|
||||
if (cv == nullptr)
|
||||
cv = validator.get_validator_for_category(cat1.name());
|
||||
|
||||
if (cv == nullptr)
|
||||
continue;
|
||||
|
||||
for (auto &iv : cv->m_item_validators)
|
||||
// copy only the values in the first row for the following categories
|
||||
if (cat1.name() == "reflns" or cat1.name() == "refine")
|
||||
{
|
||||
if (r1[iv.m_item_name].empty())
|
||||
continue;
|
||||
if (cat2.empty())
|
||||
cat2.emplace(cat1.front());
|
||||
else
|
||||
{
|
||||
|
||||
auto r1 = cat1.front();
|
||||
auto r2 = cat2.front();
|
||||
|
||||
// if (iv.m_type and iv.m_type->m_primitive_type == DDL_PrimitiveType::Numb)
|
||||
// {
|
||||
// try
|
||||
// {
|
||||
// r2[iv.m_item_name] = r1[iv.m_item_name].get<int64_t>();
|
||||
// continue;
|
||||
// }
|
||||
// catch (...)
|
||||
// {
|
||||
// }
|
||||
|
||||
// try
|
||||
// {
|
||||
// r2[iv.m_item_name] = r1[iv.m_item_name].get<double>();
|
||||
// continue;
|
||||
// }
|
||||
// catch (...)
|
||||
// {
|
||||
// }
|
||||
// }
|
||||
|
||||
r2[iv.m_item_name] = r1[iv.m_item_name].value();
|
||||
for (auto item : cat1.key_items())
|
||||
r2[item] = r1[item].text();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto rs : cat1)
|
||||
cat2.emplace(rs);
|
||||
}
|
||||
|
||||
// // copy only the values in the first row for the following categories
|
||||
// if (cat1.name() == "reflns" or cat1.name() == "refine")
|
||||
// {
|
||||
// if (cat2.empty())
|
||||
// cat2.emplace(cat1.front());
|
||||
// else
|
||||
// {
|
||||
// auto r1 = cat1.front();
|
||||
// auto r2 = cat2.front();
|
||||
|
||||
// auto cv = cat1.get_cat_validator();
|
||||
// if (cv == nullptr)
|
||||
// cv = validator.get_validator_for_category(cat1.name());
|
||||
|
||||
// if (cv == nullptr)
|
||||
// continue;
|
||||
|
||||
// for (auto &iv : cv->m_item_validators)
|
||||
// {
|
||||
// if (r1[iv.m_item_name].empty())
|
||||
// continue;
|
||||
|
||||
// if (iv.m_type and iv.m_type->m_primitive_type == DDL_PrimitiveType::Numb)
|
||||
// {
|
||||
// try
|
||||
// {
|
||||
// r2[iv.m_item_name] = r1[iv.m_item_name].get<int64_t>();
|
||||
// continue;
|
||||
// }
|
||||
// catch (...) {}
|
||||
|
||||
// try
|
||||
// {
|
||||
// r2[iv.m_item_name] = r1[iv.m_item_name].get<double>();
|
||||
// continue;
|
||||
// }
|
||||
// catch (...) {}
|
||||
// }
|
||||
|
||||
// r2[iv.m_item_name] = r1[iv.m_item_name].value();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// for (auto rs : cat1)
|
||||
// cat2.emplace(rs);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace cif::pdb
|
||||
|
||||
// NOLINTEND(bugprone-empty-catch)
|
||||
} // namespace pdbx
|
||||
@@ -26,14 +26,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cif++/datablock.hpp"
|
||||
#include "pdb_record.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <initializer_list>
|
||||
#include <regex>
|
||||
#include <string>
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
namespace cif::pdb
|
||||
@@ -44,7 +38,7 @@ struct TemplateLine;
|
||||
class Remark3Parser
|
||||
{
|
||||
public:
|
||||
virtual ~Remark3Parser() = default;
|
||||
virtual ~Remark3Parser() {}
|
||||
|
||||
static bool parse(const std::string &expMethod, PDBRecord *r, cif::datablock &db);
|
||||
|
||||
@@ -52,13 +46,13 @@ class Remark3Parser
|
||||
virtual std::string version();
|
||||
|
||||
protected:
|
||||
Remark3Parser(std::string name, std::string expMethod, PDBRecord *r, cif::datablock &db,
|
||||
Remark3Parser(const std::string &name, const std::string &expMethod, PDBRecord *r, cif::datablock &db,
|
||||
const TemplateLine templatelines[], uint32_t templateLineCount, std::regex programVersion);
|
||||
|
||||
virtual float parse();
|
||||
std::string nextLine();
|
||||
|
||||
bool match(const char *expr, uint32_t nextState);
|
||||
bool match(const char *expr, int nextState);
|
||||
void storeCapture(const char *category, std::initializer_list<const char *> items, bool createNew = false);
|
||||
void storeRefineLsRestr(const char *type, std::initializer_list<const char *> values);
|
||||
void updateRefineLsRestr(const char *type, std::initializer_list<const char *> values);
|
||||
@@ -78,4 +72,4 @@ class Remark3Parser
|
||||
std::regex mProgramVersion;
|
||||
};
|
||||
|
||||
} // namespace cif::pdb
|
||||
} // namespace pdbx
|
||||
|
||||
@@ -26,10 +26,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include "cif++/file.hpp"
|
||||
|
||||
/// \file pdb_record.hpp
|
||||
|
||||
@@ -40,14 +37,14 @@ namespace cif::pdb
|
||||
|
||||
struct PDBRecord
|
||||
{
|
||||
PDBRecord *mNext = nullptr;
|
||||
PDBRecord *mNext;
|
||||
uint32_t mLineNr;
|
||||
char mName[11];
|
||||
std::size_t mVlen;
|
||||
char mValue[1];
|
||||
|
||||
PDBRecord(uint32_t lineNr, const std::string &name, const std::string &value);
|
||||
~PDBRecord() = default;
|
||||
~PDBRecord();
|
||||
|
||||
void *operator new(std::size_t);
|
||||
void *operator new(std::size_t size, std::size_t vLen);
|
||||
@@ -60,7 +57,7 @@ struct PDBRecord
|
||||
char vC(std::size_t column);
|
||||
std::string vS(std::size_t columnFirst, std::size_t columnLast = std::numeric_limits<std::size_t>::max());
|
||||
int vI(int columnFirst, int columnLast);
|
||||
std::optional<float> vF(std::size_t columnFirst, std::size_t columnLast);
|
||||
std::string vF(std::size_t columnFirst, std::size_t columnLast);
|
||||
};
|
||||
|
||||
} // namespace cif::pdb
|
||||
} // namespace pdbx
|
||||
File diff suppressed because it is too large
Load Diff
@@ -24,27 +24,12 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "cif++/cif++.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <cstddef>
|
||||
#include <exception>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <system_error>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "cif++.hpp"
|
||||
|
||||
namespace cif::pdb
|
||||
{
|
||||
|
||||
condition get_parents_condition(const validator &validator, const_row_handle rh, const category &parentCat)
|
||||
condition get_parents_condition(const validator_base &validator, row_handle rh, const category &parentCat)
|
||||
{
|
||||
condition result;
|
||||
|
||||
@@ -53,8 +38,9 @@ condition get_parents_condition(const validator &validator, const_row_handle rh,
|
||||
auto parentName = parentCat.name();
|
||||
|
||||
auto links = validator.get_links_for_child(childName);
|
||||
std::erase_if(links, [n = parentName](auto &l)
|
||||
{ return l->m_parent_category != n; });
|
||||
links.erase(remove_if(links.begin(), links.end(), [n = parentName](auto &l)
|
||||
{ return l->m_parent_category != n; }),
|
||||
links.end());
|
||||
|
||||
if (not links.empty())
|
||||
{
|
||||
@@ -64,31 +50,28 @@ condition get_parents_condition(const validator &validator, const_row_handle rh,
|
||||
|
||||
for (std::size_t ix = 0; ix < link->m_child_keys.size(); ++ix)
|
||||
{
|
||||
if (rh[link->m_child_keys[ix]].empty())
|
||||
auto childValue = rh[link->m_child_keys[ix]];
|
||||
|
||||
if (childValue.empty())
|
||||
continue;
|
||||
|
||||
cond = std::move(cond) and key(link->m_parent_keys[ix]) == rh[link->m_child_keys[ix]].value();
|
||||
cond = std::move(cond) and key(link->m_parent_keys[ix]) == childValue.text();
|
||||
}
|
||||
|
||||
result = std::move(result) or std::move(cond);
|
||||
}
|
||||
}
|
||||
else if (cif::VERBOSE > 0)
|
||||
std::cerr << "warning: no child to parent links were found for child " << childName << " and parent " << parentName << '\n';
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool is_valid_pdbx_file(const file &file)
|
||||
bool is_valid_pdbx_file(const file &file, std::string_view dictionary)
|
||||
{
|
||||
std::error_code ec;
|
||||
bool result = is_valid_pdbx_file(file, validator_factory::instance()["mmcif_pdbx.dic"], ec);
|
||||
return result and ec == std::errc{};
|
||||
}
|
||||
|
||||
bool is_valid_pdbx_file(const file &file, const validator &v)
|
||||
{
|
||||
std::error_code ec;
|
||||
bool result = is_valid_pdbx_file(file, v, ec);
|
||||
return result and ec == std::errc{};
|
||||
bool result = is_valid_pdbx_file(file, dictionary, ec);
|
||||
return result and not (bool)ec;
|
||||
}
|
||||
|
||||
bool is_valid_pdbx_file(const file &file, std::error_code &ec)
|
||||
@@ -97,23 +80,42 @@ bool is_valid_pdbx_file(const file &file, std::error_code &ec)
|
||||
|
||||
if (file.empty())
|
||||
ec = make_error_code(validation_error::empty_file);
|
||||
else if (auto ac = file.front().get("audit_conform"); ac != nullptr)
|
||||
result = is_valid_pdbx_file(file, validator_factory::instance()[*ac], ec);
|
||||
else
|
||||
result = is_valid_pdbx_file(file, validator_factory::instance()["mmcif_pdbx.dic"], ec);
|
||||
{
|
||||
std::string dictionary = "mmcif_pdbx";
|
||||
|
||||
for (auto &db : file)
|
||||
{
|
||||
auto audit_conform = db.get("audit_conform");
|
||||
if (audit_conform == nullptr)
|
||||
continue;
|
||||
|
||||
if (not audit_conform->empty())
|
||||
{
|
||||
auto specified_dict = audit_conform->front()["dict_name"];
|
||||
if (not specified_dict.empty())
|
||||
dictionary = specified_dict.as<std::string>();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
result = is_valid_pdbx_file(file, dictionary, ec);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool is_valid_pdbx_file(const file &file, const validator &validator, std::error_code &ec)
|
||||
bool is_valid_pdbx_file(const file &file, std::string_view dictionary, std::error_code &ec)
|
||||
{
|
||||
using namespace cif::literals;
|
||||
|
||||
bool result = true, warned_missing_parents = false;
|
||||
bool result = true;
|
||||
|
||||
try
|
||||
{
|
||||
auto &cf = cif::compound_factory::instance();
|
||||
auto &validator = cif::validator_factory::instance().operator[](dictionary);
|
||||
|
||||
if (file.empty())
|
||||
throw std::runtime_error("Empty file");
|
||||
@@ -129,6 +131,7 @@ bool is_valid_pdbx_file(const file &file, const validator &validator, std::error
|
||||
|
||||
auto &pdbx_poly_seq_scheme = db["pdbx_poly_seq_scheme"];
|
||||
|
||||
std::string last_asym_id;
|
||||
int last_seq_id = -1;
|
||||
for (auto r : atom_site)
|
||||
{
|
||||
@@ -145,19 +148,11 @@ bool is_valid_pdbx_file(const file &file, const validator &validator, std::error
|
||||
if (not cf.is_monomer(comp_id))
|
||||
continue;
|
||||
|
||||
auto cond = get_parents_condition(validator, r, pdbx_poly_seq_scheme);
|
||||
if (not cond)
|
||||
{
|
||||
if (VERBOSE > 0 and std::exchange(warned_missing_parents, true) == false)
|
||||
std::cerr << "warning: missing links for atom_site/pdbx_poly_seq_scheme\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
auto p = pdbx_poly_seq_scheme.find(std::move(cond));
|
||||
auto p = pdbx_poly_seq_scheme.find(get_parents_condition(validator, r, pdbx_poly_seq_scheme));
|
||||
if (p.size() != 1)
|
||||
{
|
||||
if (VERBOSE > 0)
|
||||
std::clog << "In atom_site record: " << r["id"].str() << '\n';
|
||||
if (cif::VERBOSE > 0)
|
||||
std::clog << "In atom_site record: " << r["id"].text() << '\n';
|
||||
throw std::runtime_error("For each monomer in atom_site there should be exactly one pdbx_poly_seq_scheme record");
|
||||
}
|
||||
}
|
||||
@@ -183,11 +178,11 @@ bool is_valid_pdbx_file(const file &file, const validator &validator, std::error
|
||||
if (entity_poly.count("entity_id"_key == entity_id) != 1)
|
||||
throw std::runtime_error("There should be exactly one entity_poly record per polymer entity");
|
||||
|
||||
// const auto entity_poly_type = entity_poly.find1<std::string>("entity_id"_key == entity_id, "type");
|
||||
const auto entity_poly_type = entity_poly.find1<std::string>("entity_id"_key == entity_id, "type");
|
||||
|
||||
std::map<int, std::set<std::string>> mon_per_seq_id;
|
||||
std::map<int,std::set<std::string>> mon_per_seq_id;
|
||||
|
||||
for (const auto &[num, mon_id, hetero] : entity_poly_seq.find<int, std::string, std::string>("entity_id"_key == entity_id, "num", "mon_id", "hetero"))
|
||||
for (const auto &[num, mon_id, hetero] : entity_poly_seq.find<int, std::string, bool>("entity_id"_key == entity_id, "num", "mon_id", "hetero"))
|
||||
{
|
||||
mon_per_seq_id[num].emplace(mon_id);
|
||||
|
||||
@@ -205,7 +200,7 @@ bool is_valid_pdbx_file(const file &file, const validator &validator, std::error
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &[seq_id, mon_id, hetero] : pdbx_poly_seq_scheme.find<int, std::string, std::string>("entity_id"_key == entity_id, "seq_id", "mon_id", "hetero"))
|
||||
for (const auto &[seq_id, mon_id, hetero] : pdbx_poly_seq_scheme.find<int, std::string, bool>("entity_id"_key == entity_id, "seq_id", "mon_id", "hetero"))
|
||||
{
|
||||
if (entity_poly_seq.count(
|
||||
"entity_id"_key == entity_id and
|
||||
@@ -216,41 +211,32 @@ bool is_valid_pdbx_file(const file &file, const validator &validator, std::error
|
||||
throw std::runtime_error("For each pdbx_poly_seq/struct_asym record there should be exactly one entity_poly_seq record");
|
||||
}
|
||||
|
||||
if ((mon_per_seq_id[seq_id].size() > 1) != iequals(hetero, "Y"))
|
||||
if ((mon_per_seq_id[seq_id].size() > 1) != hetero)
|
||||
throw std::runtime_error("Mismatch between the hetero flag in the poly seq schemes and the number residues per seq_id");
|
||||
}
|
||||
|
||||
// This code proved to take too much time ...
|
||||
|
||||
// for (const auto &[seq_id, mon_ids] : mon_per_seq_id)
|
||||
// {
|
||||
// for (auto asym_id : struct_asym.find<std::string>("entity_id"_key == entity_id, "id"))
|
||||
// {
|
||||
// condition cond;
|
||||
|
||||
// for (auto mon_id : mon_ids)
|
||||
// cond = std::move(cond) or "label_comp_id"_key == mon_id;
|
||||
|
||||
// cond = "label_entity_id"_key == entity_id and
|
||||
// "label_asym_id"_key == asym_id and
|
||||
// "label_seq_id"_key == seq_id and not std::move(cond);
|
||||
|
||||
// if (atom_site.contains(std::move(cond)))
|
||||
// throw std::runtime_error("An atom_site record exists that has no parent in the poly seq scheme categories");
|
||||
// }
|
||||
// }
|
||||
|
||||
// ... so we're using this instead, should be almost the same...
|
||||
|
||||
for (const auto &[comp_id, seq_id] :
|
||||
atom_site.find<std::string, int>("label_entity_id"_key == entity_id, "label_comp_id", "label_seq_id"))
|
||||
for (const auto &[seq_id, mon_ids] : mon_per_seq_id)
|
||||
{
|
||||
if (not mon_per_seq_id[seq_id].contains(comp_id))
|
||||
throw std::runtime_error("An atom_site record exists that has no parent in the poly seq scheme categories");
|
||||
for (auto asym_id : struct_asym.find<std::string>("entity_id"_key == entity_id, "id"))
|
||||
{
|
||||
condition cond;
|
||||
|
||||
for (auto mon_id : mon_ids)
|
||||
cond = std::move(cond) or "label_comp_id"_key == mon_id;
|
||||
|
||||
cond = "label_entity_id"_key == entity_id and
|
||||
"label_asym_id"_key == asym_id and
|
||||
"label_seq_id"_key == seq_id and not std::move(cond);
|
||||
|
||||
if (atom_site.contains(std::move(cond)))
|
||||
throw std::runtime_error("An atom_site record exists that has no parent in the poly seq scheme categories");
|
||||
}
|
||||
}
|
||||
|
||||
auto &&[seq, seq_can] = entity_poly.find1<std::optional<std::string>, std::optional<std::string>>("entity_id"_key == entity_id,
|
||||
"pdbx_seq_one_letter_code", "pdbx_seq_one_letter_code_can");
|
||||
|
||||
std::string::const_iterator si, sci, se, sce;
|
||||
|
||||
auto seq_match = [&](bool can, std::string::const_iterator si, std::string::const_iterator se)
|
||||
{
|
||||
@@ -287,11 +273,11 @@ bool is_valid_pdbx_file(const file &file, const validator &validator, std::error
|
||||
else
|
||||
letter = '(' + comp_id + ')';
|
||||
}
|
||||
|
||||
if (iequals(std::string{ si, si + static_cast<int>(letter.length()) }, letter))
|
||||
|
||||
if (iequals(std::string{si, si + letter.length()}, letter))
|
||||
{
|
||||
match = true;
|
||||
si += static_cast<int>(letter.length());
|
||||
si += letter.length();
|
||||
break;
|
||||
}
|
||||
else
|
||||
@@ -307,14 +293,12 @@ bool is_valid_pdbx_file(const file &file, const validator &validator, std::error
|
||||
|
||||
if (not seq.has_value())
|
||||
{
|
||||
if (VERBOSE > 0)
|
||||
if (cif::VERBOSE > 0)
|
||||
std::clog << "Warning: entity_poly has no sequence for entity_id " << entity_id << '\n';
|
||||
}
|
||||
else
|
||||
{
|
||||
seq->erase(std::remove_if(seq->begin(), seq->end(), [](char ch)
|
||||
{ return std::isspace(ch); }),
|
||||
seq->end());
|
||||
seq->erase(std::remove_if(seq->begin(), seq->end(), [](char ch) { return std::isspace(ch); }), seq->end());
|
||||
|
||||
if (not seq_match(false, seq->begin(), seq->end()))
|
||||
throw std::runtime_error("Sequences do not match for entity " + entity_id);
|
||||
@@ -322,14 +306,12 @@ bool is_valid_pdbx_file(const file &file, const validator &validator, std::error
|
||||
|
||||
if (not seq_can.has_value())
|
||||
{
|
||||
if (VERBOSE > 1)
|
||||
if (cif::VERBOSE > 1)
|
||||
std::clog << "Warning: entity_poly has no canonical sequence for entity_id " << entity_id << '\n';
|
||||
}
|
||||
else
|
||||
{
|
||||
seq_can->erase(std::remove_if(seq_can->begin(), seq_can->end(), [](char ch)
|
||||
{ return std::isspace(ch); }),
|
||||
seq_can->end());
|
||||
seq_can->erase(std::remove_if(seq_can->begin(), seq_can->end(), [](char ch) { return std::isspace(ch); }), seq_can->end());
|
||||
|
||||
if (not seq_match(true, seq_can->begin(), seq_can->end()))
|
||||
throw std::runtime_error("Canonical sequences do not match for entity " + entity_id);
|
||||
@@ -341,15 +323,16 @@ bool is_valid_pdbx_file(const file &file, const validator &validator, std::error
|
||||
catch (const std::exception &ex)
|
||||
{
|
||||
result = false;
|
||||
if (VERBOSE > 0)
|
||||
if (cif::VERBOSE > 0)
|
||||
std::clog << ex.what() << '\n';
|
||||
ec = make_error_code(validation_error::not_valid_pdbx);
|
||||
}
|
||||
|
||||
if (not result and ec == std::errc{})
|
||||
if (not result and (bool)ec)
|
||||
ec = make_error_code(validation_error::not_valid_pdbx);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace cif::pdb
|
||||
|
||||
298
src/point.cpp
298
src/point.cpp
@@ -24,30 +24,18 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "cif++/cif++.hpp"
|
||||
#include "cif++/point.hpp"
|
||||
#include "cif++/matrix.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <complex>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <initializer_list>
|
||||
#include <numbers>
|
||||
#include <optional>
|
||||
#include <random>
|
||||
#include <stdexcept>
|
||||
#include <tuple>
|
||||
#include <valarray>
|
||||
#include <vector>
|
||||
|
||||
namespace cif
|
||||
{
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
template <typename T>
|
||||
template<typename T>
|
||||
quaternion_type<T> normalize(quaternion_type<T> q)
|
||||
{
|
||||
std::valarray<double> t(4);
|
||||
@@ -73,7 +61,7 @@ quaternion_type<T> normalize(quaternion_type<T> q)
|
||||
|
||||
quaternion construct_from_angle_axis(float angle, point axis)
|
||||
{
|
||||
angle = (angle * std::numbers::pi_v<float> / 180) / 2;
|
||||
angle = static_cast<float>((angle * kPI / 180) / 2);
|
||||
auto s = std::sin(angle);
|
||||
auto c = std::cos(angle);
|
||||
|
||||
@@ -86,14 +74,14 @@ quaternion construct_from_angle_axis(float angle, point axis)
|
||||
static_cast<float>(s * axis.m_z) });
|
||||
}
|
||||
|
||||
std::tuple<float, point> quaternion_to_angle_axis(quaternion q)
|
||||
std::tuple<double, point> quaternion_to_angle_axis(quaternion q)
|
||||
{
|
||||
if (q.get_a() > 1)
|
||||
q = normalize(q);
|
||||
|
||||
// angle:
|
||||
float angle = 2 * std::acos(q.get_a());
|
||||
angle = angle * 180 / std::numbers::pi_v<float>;
|
||||
double angle = 2 * std::acos(q.get_a());
|
||||
angle = angle * 180 / kPI;
|
||||
|
||||
// axis:
|
||||
float s = std::sqrt(1 - q.get_a() * q.get_a());
|
||||
@@ -116,9 +104,9 @@ point center_points(std::vector<point> &Points)
|
||||
t.m_z += pt.m_z;
|
||||
}
|
||||
|
||||
t.m_x /= static_cast<float>(Points.size());
|
||||
t.m_y /= static_cast<float>(Points.size());
|
||||
t.m_z /= static_cast<float>(Points.size());
|
||||
t.m_x /= Points.size();
|
||||
t.m_y /= Points.size();
|
||||
t.m_z /= Points.size();
|
||||
|
||||
for (point &pt : Points)
|
||||
{
|
||||
@@ -138,9 +126,10 @@ quaternion construct_for_dihedral_angle(point p1, point p2, point p3, point p4,
|
||||
p4 -= p3;
|
||||
p3 -= p3;
|
||||
|
||||
quaternion q;
|
||||
auto axis = -p2;
|
||||
float dh = dihedral_angle(p1, p2, p3, p4);
|
||||
|
||||
float dh = dihedral_angle(p1, p2, p3, p4);
|
||||
return construct_from_angle_axis(angle - dh, axis);
|
||||
}
|
||||
|
||||
@@ -172,7 +161,7 @@ double RMSd(const std::vector<point> &a, const std::vector<point> &b)
|
||||
sum += d.sum();
|
||||
}
|
||||
|
||||
return std::sqrt(sum / static_cast<double>(a.size()));
|
||||
return std::sqrt(sum / a.size());
|
||||
}
|
||||
|
||||
// The next function returns the largest solution for a quartic equation
|
||||
@@ -304,9 +293,9 @@ quaternion align_points(const std::vector<point> &pa, const std::vector<point> &
|
||||
}
|
||||
|
||||
quaternion q(
|
||||
static_cast<float>(cf(maxR, 0)),
|
||||
static_cast<float>(cf(maxR, 1)),
|
||||
static_cast<float>(cf(maxR, 2)),
|
||||
static_cast<float>(cf(maxR, 0)),
|
||||
static_cast<float>(cf(maxR, 1)),
|
||||
static_cast<float>(cf(maxR, 2)),
|
||||
static_cast<float>(cf(maxR, 3)));
|
||||
q = normalize(q);
|
||||
|
||||
@@ -317,15 +306,17 @@ quaternion align_points(const std::vector<point> &pa, const std::vector<point> &
|
||||
|
||||
point nudge(point p, float offset)
|
||||
{
|
||||
static const float kPI_f = static_cast<float>(kPI);
|
||||
|
||||
static std::random_device rd;
|
||||
static std::mt19937_64 rng(rd());
|
||||
|
||||
std::uniform_real_distribution<float> randomAngle(0, 2 * std::numbers::pi);
|
||||
std::uniform_real_distribution<float> randomAngle(0, 2 * kPI_f);
|
||||
std::normal_distribution<float> randomOffset(0, offset);
|
||||
|
||||
float theta = randomAngle(rng);
|
||||
float phi1 = randomAngle(rng) - static_cast<float>(std::numbers::pi);
|
||||
float phi2 = randomAngle(rng) - static_cast<float>(std::numbers::pi);
|
||||
float phi1 = randomAngle(rng) - kPI_f;
|
||||
float phi2 = randomAngle(rng) - kPI_f;
|
||||
|
||||
quaternion q = spherical(1.0f, theta, phi1, phi2);
|
||||
|
||||
@@ -336,251 +327,4 @@ point nudge(point p, float offset)
|
||||
return p + r;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
std::tuple<point, float> smallest_sphere_around_2_points(std::array<cif::point, 2> pts)
|
||||
{
|
||||
return { (pts[0] + pts[1]) / 2, distance(pts[0], pts[1]) / 2 };
|
||||
}
|
||||
|
||||
std::tuple<point, float> smallest_sphere_around_3_points(std::array<cif::point, 3> pts)
|
||||
{
|
||||
// Find two bisectors
|
||||
auto vz = cross_product(pts[1] - pts[0], pts[2] - pts[0]);
|
||||
|
||||
auto bs1 = cross_product(vz, pts[1] - pts[0]);
|
||||
bs1.normalize();
|
||||
|
||||
auto v1 = (pts[1] - pts[0]);
|
||||
v1.normalize();
|
||||
|
||||
auto s1 = pts[0] + (distance(pts[1], pts[0]) / 2) * v1;
|
||||
|
||||
auto bs2 = cross_product(vz, pts[2] - pts[0]);
|
||||
bs2.normalize();
|
||||
|
||||
auto v2 = (pts[2] - pts[0]);
|
||||
v2.normalize();
|
||||
|
||||
auto s2 = pts[0] + (distance(pts[2], pts[0]) / 2) * v2;
|
||||
|
||||
auto c = line_line_intersection(s1, s1 + bs1, s2, s2 + bs2);
|
||||
if (c)
|
||||
return { *c, distance(*c, pts[0]) };
|
||||
|
||||
// Colinear points I guess, try something else
|
||||
auto l1 = distance_squared(pts[0], pts[1]);
|
||||
auto l2 = distance_squared(pts[0], pts[2]);
|
||||
auto l3 = distance_squared(pts[1], pts[2]);
|
||||
|
||||
if (l1 > l2 and l1 > l3)
|
||||
return smallest_sphere_around_2_points({ pts[0], pts[1] });
|
||||
else if (l2 > l1 and l2 > l3)
|
||||
return smallest_sphere_around_2_points({ pts[0], pts[2] });
|
||||
else
|
||||
return smallest_sphere_around_2_points({ pts[1], pts[2] });
|
||||
}
|
||||
|
||||
std::tuple<point, float> smallest_sphere_around_4_points(std::array<cif::point, 4> pts)
|
||||
{
|
||||
auto t0 = -norm_squared(pts[0]);
|
||||
auto t1 = -norm_squared(pts[1]);
|
||||
auto t2 = -norm_squared(pts[2]);
|
||||
auto t3 = -norm_squared(pts[3]);
|
||||
|
||||
// clang-format off
|
||||
matrix4x4<float> Tm({
|
||||
pts[0].m_x, pts[0].m_y, pts[0].m_z, 1,
|
||||
pts[1].m_x, pts[1].m_y, pts[1].m_z, 1,
|
||||
pts[2].m_x, pts[2].m_y, pts[2].m_z, 1,
|
||||
pts[3].m_x, pts[3].m_y, pts[3].m_z, 1
|
||||
});
|
||||
auto T = determinant(Tm);
|
||||
|
||||
if (T != 0)
|
||||
{
|
||||
matrix4x4<float> Dm({
|
||||
t0, pts[0].m_y, pts[0].m_z, 1,
|
||||
t1, pts[1].m_y, pts[1].m_z, 1,
|
||||
t2, pts[2].m_y, pts[2].m_z, 1,
|
||||
t3, pts[3].m_y, pts[3].m_z, 1
|
||||
});
|
||||
auto D = determinant(Dm) / T;
|
||||
|
||||
matrix4x4<float> Em({
|
||||
pts[0].m_x, t0, pts[0].m_z, 1,
|
||||
pts[1].m_x, t1, pts[1].m_z, 1,
|
||||
pts[2].m_x, t2, pts[2].m_z, 1,
|
||||
pts[3].m_x, t3, pts[3].m_z, 1
|
||||
});
|
||||
auto E = determinant(Em) / T;
|
||||
|
||||
matrix4x4<float> Fm({
|
||||
pts[0].m_x, pts[0].m_y, t0, 1,
|
||||
pts[1].m_x, pts[1].m_y, t1, 1,
|
||||
pts[2].m_x, pts[2].m_y, t2, 1,
|
||||
pts[3].m_x, pts[3].m_y, t3, 1
|
||||
});
|
||||
|
||||
auto F = determinant(Fm) / T;
|
||||
|
||||
matrix4x4<float> Gm({
|
||||
pts[0].m_x, pts[0].m_y, pts[0].m_z, t0,
|
||||
pts[1].m_x, pts[1].m_y, pts[1].m_z, t1,
|
||||
pts[2].m_x, pts[2].m_y, pts[2].m_z, t2,
|
||||
pts[3].m_x, pts[3].m_y, pts[3].m_z, t3
|
||||
});
|
||||
auto G = determinant(Gm) / T;
|
||||
|
||||
point center{ -D / 2, -E / 2, -F / 2 };
|
||||
float radius = std::sqrt(D * D + E * E + F * F - 4 * G) / 2;
|
||||
|
||||
// clang-format on
|
||||
|
||||
return { center, radius };
|
||||
}
|
||||
|
||||
// Perhaps some colinear points, try something else:
|
||||
|
||||
for (auto ix : std::initializer_list<std::array<size_t, 4>>{
|
||||
{ 1, 2, 3, 0 },
|
||||
{ 0, 2, 3, 1 },
|
||||
{ 0, 1, 3, 2 },
|
||||
{ 0, 1, 2, 3 },
|
||||
})
|
||||
{
|
||||
auto [center, radius] =
|
||||
smallest_sphere_around_3_points({ pts[ix[0]], pts[ix[1]], pts[ix[2]] });
|
||||
|
||||
if (distance(pts[ix[3]], center) <= radius)
|
||||
return { center, radius };
|
||||
}
|
||||
|
||||
assert(false);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
std::tuple<point, float> smallest_sphere_around_all_points(std::vector<point> P, std::vector<point> R)
|
||||
{
|
||||
if (P.empty() or R.size() == 4)
|
||||
{
|
||||
switch (R.size())
|
||||
{
|
||||
case 1:
|
||||
return { R[0], 0 };
|
||||
|
||||
case 2:
|
||||
return smallest_sphere_around_2_points({ R[0], R[1] });
|
||||
|
||||
case 3:
|
||||
return smallest_sphere_around_3_points({ R[0], R[1], R[2] });
|
||||
|
||||
case 4:
|
||||
return smallest_sphere_around_4_points({ R[0], R[1], R[2], R[3] });
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
auto p = P.back();
|
||||
P.pop_back();
|
||||
|
||||
auto [c, r] = smallest_sphere_around_all_points(P, R);
|
||||
assert(not std::isnan(r));
|
||||
if (distance(c, p) <= r)
|
||||
return { c, r };
|
||||
|
||||
R.emplace_back(p);
|
||||
return smallest_sphere_around_all_points(P, R);
|
||||
}
|
||||
|
||||
bool point_in_circle(point p, std::vector<point> c)
|
||||
{
|
||||
switch (c.size())
|
||||
{
|
||||
case 0:
|
||||
return false;
|
||||
|
||||
case 1:
|
||||
return p == c.front();
|
||||
|
||||
case 2:
|
||||
{
|
||||
auto [center, radius] = smallest_sphere_around_2_points({ c[0], c[1] });
|
||||
return cif::distance_squared(p, center) <= radius * radius;
|
||||
}
|
||||
|
||||
case 3:
|
||||
{
|
||||
auto [center, radius] = smallest_sphere_around_3_points({ c[0], c[1], c[2] });
|
||||
return cif::distance_squared(p, center) <= radius * radius;
|
||||
}
|
||||
|
||||
case 4:
|
||||
{
|
||||
auto [center, radius] = smallest_sphere_around_4_points({ c[0], c[1], c[2], c[3] });
|
||||
return cif::distance_squared(p, center) <= radius * radius;
|
||||
}
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
throw std::runtime_error("Error finding smallest sphere");
|
||||
}
|
||||
}
|
||||
|
||||
std::tuple<point, float> smallest_sphere_around_points(std::vector<point> pts)
|
||||
{
|
||||
std::random_device rd;
|
||||
std::mt19937 g(rd());
|
||||
|
||||
std::shuffle(pts.begin(), pts.end(), g);
|
||||
|
||||
std::vector<size_t> cix;
|
||||
|
||||
auto cirle_points = [&]()
|
||||
{
|
||||
std::vector<point> result;
|
||||
for (auto ix : cix)
|
||||
result.emplace_back(pts[ix]);
|
||||
return result;
|
||||
};
|
||||
|
||||
size_t i = 0;
|
||||
while (i < pts.size())
|
||||
{
|
||||
if (std::ranges::find(cix, i) != cix.end() or
|
||||
point_in_circle(pts[i], cirle_points()))
|
||||
{
|
||||
++i;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::erase_if(cix, [i](size_t j)
|
||||
{ return j < i; });
|
||||
cix.push_back(i);
|
||||
if (cix.size() < 4)
|
||||
i = 0;
|
||||
else
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
switch (cix.size())
|
||||
{
|
||||
case 1:
|
||||
return { pts[cix[0]], 0 };
|
||||
case 2:
|
||||
return smallest_sphere_around_2_points({ pts[cix[0]], pts[cix[1]] });
|
||||
case 3:
|
||||
return smallest_sphere_around_3_points({ pts[cix[0]], pts[cix[1]], pts[cix[2]] });
|
||||
case 4:
|
||||
return smallest_sphere_around_4_points({ pts[cix[0]], pts[cix[1]], pts[cix[2]], pts[cix[3]] });
|
||||
default:
|
||||
assert(false);
|
||||
throw std::runtime_error(std::format("Error finding smallest sphere (cix size: {}, pts size: {})",
|
||||
cix.size(), pts.size()));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace cif
|
||||
|
||||
93
src/row.cpp
93
src/row.cpp
@@ -24,38 +24,18 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "cif++/cif++.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
#include "cif++/category.hpp"
|
||||
|
||||
namespace cif
|
||||
{
|
||||
|
||||
// item_value &row_handle::operator[](uint16_t item_ix)
|
||||
// {
|
||||
// return empty() or item_ix >= m_row->size() ? s_null_item : m_row->operator[](item_ix);
|
||||
// }
|
||||
void row_handle::assign(uint16_t item, std::string_view value, bool updateLinked, bool validate)
|
||||
{
|
||||
if (not m_category)
|
||||
throw std::runtime_error("uninitialized row");
|
||||
|
||||
// const item_value &row_handle::operator[](uint16_t item_ix) const
|
||||
// {
|
||||
// return empty() or item_ix >= m_row->size() ? s_null_item : m_row->operator[](item_ix);
|
||||
// }
|
||||
|
||||
// item_value &row_handle::operator[](std::string_view item_name)
|
||||
// {
|
||||
// return operator[](get_item_ix(item_name));
|
||||
// }
|
||||
|
||||
// const item_value &row_handle::operator[](std::string_view item_name) const
|
||||
// {
|
||||
// return operator[](get_item_ix(item_name));
|
||||
// }
|
||||
m_category->update_value(m_row, item, value, updateLinked, validate);
|
||||
}
|
||||
|
||||
uint16_t row_handle::get_item_ix(std::string_view name) const
|
||||
{
|
||||
@@ -73,32 +53,6 @@ std::string_view row_handle::get_item_name(uint16_t ix) const
|
||||
return m_category->get_item_name(ix);
|
||||
}
|
||||
|
||||
uint16_t const_row_handle::get_item_ix(std::string_view name) const
|
||||
{
|
||||
if (not m_category)
|
||||
throw std::runtime_error("uninitialized row");
|
||||
|
||||
return m_category->get_item_ix(name);
|
||||
}
|
||||
|
||||
std::string_view const_row_handle::get_item_name(uint16_t ix) const
|
||||
{
|
||||
if (not m_category)
|
||||
throw std::runtime_error("uninitialized row");
|
||||
|
||||
return m_category->get_item_name(ix);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
void row_handle::assign(uint16_t item, item_value value, bool updateLinked, bool validate)
|
||||
{
|
||||
if (not m_category)
|
||||
throw std::runtime_error("uninitialized row");
|
||||
|
||||
m_category->update_value(m_row, item, std::move(value), updateLinked, validate);
|
||||
}
|
||||
|
||||
uint16_t row_handle::add_item(std::string_view name)
|
||||
{
|
||||
if (not m_category)
|
||||
@@ -107,44 +61,53 @@ uint16_t row_handle::add_item(std::string_view name)
|
||||
return m_category->add_item(name);
|
||||
}
|
||||
|
||||
void row_handle::swap(uint16_t item, row_handle &b)
|
||||
{
|
||||
if (not m_category)
|
||||
throw std::runtime_error("uninitialized row");
|
||||
|
||||
m_category->swap_item(item, *this, b);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
row_initializer::row_initializer(const_row_handle rh)
|
||||
row_initializer::row_initializer(row_handle rh)
|
||||
{
|
||||
if (not rh.m_category)
|
||||
throw std::runtime_error("uninitialized row");
|
||||
|
||||
assert(rh.m_row);
|
||||
|
||||
auto r = rh.get_row();
|
||||
row *r = rh.get_row();
|
||||
auto &cat = *rh.m_category;
|
||||
|
||||
for (uint16_t ix = 0; std::cmp_less(ix, r->size()); ++ix)
|
||||
for (uint16_t ix = 0; ix < r->size(); ++ix)
|
||||
{
|
||||
auto &i = r->operator[](ix);
|
||||
emplace_back(cat.get_item_name(ix), i);
|
||||
if (not i)
|
||||
continue;
|
||||
emplace_back(cat.get_item_name(ix), i.text());
|
||||
}
|
||||
}
|
||||
|
||||
void row_initializer::set_value(std::string name, item_value value)
|
||||
void row_initializer::set_value(std::string_view name, std::string_view value)
|
||||
{
|
||||
for (auto &i : *this)
|
||||
{
|
||||
if (i.name() == name)
|
||||
{
|
||||
i.value(std::move(value));
|
||||
i.value(value);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
emplace_back(std::move(name), std::move(value));
|
||||
emplace_back(name, value);
|
||||
}
|
||||
|
||||
void row_initializer::set_value_if_empty(std::string name, item_value value)
|
||||
void row_initializer::set_value_if_empty(std::string_view name, std::string_view value)
|
||||
{
|
||||
if (std::ranges::find_if(*this, [name](auto &i)
|
||||
{ return i.name() == name; }) == end())
|
||||
emplace_back(std::move(name), std::move(value));
|
||||
if (find_if(begin(), end(), [name](auto &i) { return i.name() == name; }) == end())
|
||||
emplace_back(name, value);
|
||||
}
|
||||
|
||||
} // namespace cif
|
||||
} // namespace cif
|
||||
@@ -25,26 +25,12 @@
|
||||
*/
|
||||
|
||||
#include "cif++/symmetry.hpp"
|
||||
#include "cif++/cif++.hpp"
|
||||
#include "symop_table_data.hpp"
|
||||
#include "cif++/datablock.hpp"
|
||||
#include "cif++/point.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <charconv>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <system_error>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# pragma warning(disable : 5054) // warning C5054: operator '&': deprecated between enumerations of different types
|
||||
# pragma warning(disable : 4127) // conditional expression is constant
|
||||
#endif
|
||||
#include "symop_table_data.hpp"
|
||||
|
||||
#include <Eigen/Eigen>
|
||||
|
||||
@@ -76,38 +62,38 @@ cell::cell(const datablock &db)
|
||||
|
||||
void cell::init()
|
||||
{
|
||||
auto alpha = (m_alpha * std::numbers::pi_v<float>) / 180;
|
||||
auto beta = (m_beta * std::numbers::pi_v<float>) / 180;
|
||||
auto gamma = (m_gamma * std::numbers::pi_v<float>) / 180;
|
||||
auto alpha = (m_alpha * kPI) / 180;
|
||||
auto beta = (m_beta * kPI) / 180;
|
||||
auto gamma = (m_gamma * kPI) / 180;
|
||||
|
||||
auto alpha_star = std::acos((std::cos(gamma) * std::cos(beta) - std::cos(alpha)) / (std::sin(beta) * std::sin(gamma)));
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
float cell::get_volume() const
|
||||
{
|
||||
auto alpha = (m_alpha * std::numbers::pi_v<float>) / 180;
|
||||
auto beta = (m_beta * std::numbers::pi_v<float>) / 180;
|
||||
auto gamma = (m_gamma * std::numbers::pi_v<float>) / 180;
|
||||
auto alpha = (m_alpha * kPI) / 180;
|
||||
auto beta = (m_beta * kPI) / 180;
|
||||
auto gamma = (m_gamma * kPI) / 180;
|
||||
|
||||
auto cos_alpha = std::cos(alpha);
|
||||
auto cos_beta = std::cos(beta);
|
||||
auto cos_gamma = std::cos(gamma);
|
||||
|
||||
double vol = m_a * m_b * m_c;
|
||||
auto vol = m_a * m_b * m_c;
|
||||
vol *= std::sqrt(1.0f - cos_alpha * cos_alpha - cos_beta * cos_beta - cos_gamma * cos_gamma + 2.0f * cos_alpha * cos_beta * cos_gamma);
|
||||
|
||||
return static_cast<float>(vol);
|
||||
return vol;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
@@ -125,7 +111,7 @@ sym_op::sym_op(std::string_view s)
|
||||
m_tb = r.ptr[2] - '0';
|
||||
m_tc = r.ptr[3] - '0';
|
||||
|
||||
if (r.ec != std::errc{} or rnri > 192 or r.ptr[0] != '_' or m_ta > 9 or m_tb > 9 or m_tc > 9)
|
||||
if ((bool)r.ec or rnri > 192 or r.ptr[0] != '_' or m_ta > 9 or m_tb > 9 or m_tc > 9)
|
||||
throw std::invalid_argument("Could not convert string into sym_op");
|
||||
}
|
||||
|
||||
@@ -133,13 +119,13 @@ std::string sym_op::string() const
|
||||
{
|
||||
char b[9];
|
||||
auto r = std::to_chars(b, b + sizeof(b), m_nr);
|
||||
if (r.ec != std::errc{} or r.ptr > b + 4)
|
||||
if ((bool)r.ec or r.ptr > b + 4)
|
||||
throw std::runtime_error("Could not write out symmetry operation to string");
|
||||
|
||||
*r.ptr++ = '_';
|
||||
*r.ptr++ = static_cast<char>('0' + m_ta);
|
||||
*r.ptr++ = static_cast<char>('0' + m_tb);
|
||||
*r.ptr++ = static_cast<char>('0' + m_tc);
|
||||
*r.ptr++ = '0' + m_ta;
|
||||
*r.ptr++ = '0' + m_tb;
|
||||
*r.ptr++ = '0' + m_tc;
|
||||
*r.ptr = 0;
|
||||
|
||||
return { b, static_cast<std::size_t>(r.ptr - b) };
|
||||
@@ -196,7 +182,7 @@ transformation operator*(const transformation &lhs, const transformation &rhs)
|
||||
auto t = lhs.m_rotation * rhs.m_translation;
|
||||
t = t + lhs.m_translation;
|
||||
|
||||
return { r, t };
|
||||
return transformation(r, t);
|
||||
}
|
||||
|
||||
transformation inverse(const transformation &t)
|
||||
@@ -293,7 +279,12 @@ point spacegroup::operator()(const point &pt, const cell &c, sym_op symop) const
|
||||
t.m_translation.m_y += symop.m_tb - 5;
|
||||
t.m_translation.m_z += symop.m_tc - 5;
|
||||
|
||||
return orthogonal(t(fractional(pt, c)), c);
|
||||
auto fpt = fractional(pt, c);
|
||||
auto o = offsetToOriginFractional(fpt);
|
||||
|
||||
auto spt = t(fpt + o) - o;
|
||||
|
||||
return orthogonal(spt, c);
|
||||
}
|
||||
|
||||
point spacegroup::inverse(const point &pt, const cell &c, sym_op symop) const
|
||||
@@ -307,8 +298,13 @@ point spacegroup::inverse(const point &pt, const cell &c, sym_op symop) const
|
||||
t.m_translation.m_y += symop.m_tb - 5;
|
||||
t.m_translation.m_z += symop.m_tc - 5;
|
||||
|
||||
auto fpt = fractional(pt, c);
|
||||
auto o = offsetToOriginFractional(fpt);
|
||||
|
||||
auto it = cif::inverse(t);
|
||||
return orthogonal(it(fractional(pt, c)), c);
|
||||
auto spt = it(fpt + o) - o;
|
||||
|
||||
return orthogonal(spt, c);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
@@ -344,8 +340,9 @@ int get_space_group_number(std::string_view spacegroup)
|
||||
// not found, see if we can find a match based on xHM name
|
||||
if (result == 0)
|
||||
{
|
||||
for (const auto &sp : kSpaceGroups)
|
||||
for (std::size_t i = 0; i < kNrOfSpaceGroups; ++i)
|
||||
{
|
||||
auto &sp = kSpaceGroups[i];
|
||||
if (sp.xHM == spacegroup)
|
||||
{
|
||||
result = sp.nr;
|
||||
@@ -453,9 +450,9 @@ std::tuple<float, point, sym_op> crystal::closest_symmetry_copy(point a, point b
|
||||
|
||||
a = orthogonal(fa, m_cell);
|
||||
|
||||
for (uint8_t i = 0; std::cmp_less(i, m_spacegroup.size()); ++i)
|
||||
for (std::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);
|
||||
|
||||
@@ -280,7 +280,7 @@ int main(int argc, char* const argv[])
|
||||
if (std::isdigit(line[0])) // start of new spacegroup
|
||||
{
|
||||
auto r = std::from_chars(line.data(), line.data() + line.length(), sgnr);
|
||||
if (r.ec != std::errc{})
|
||||
if ((bool)r.ec)
|
||||
throw std::runtime_error("Error parsing symop.lib file");
|
||||
rnr = 1;
|
||||
continue;
|
||||
|
||||
66
src/text.cpp
66
src/text.cpp
@@ -28,12 +28,6 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cctype>
|
||||
#include <stdexcept>
|
||||
|
||||
#if defined(USE_FAST_FLOAT)
|
||||
# include "fast_float/fast_float.h"
|
||||
#endif
|
||||
|
||||
namespace cif
|
||||
{
|
||||
@@ -62,29 +56,31 @@ const uint8_t kCharToLowerMap[256] = {
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
bool iequals(std::string_view a, std::string_view b) noexcept
|
||||
bool iequals(std::string_view a, std::string_view b)
|
||||
{
|
||||
bool result = a.length() == b.length();
|
||||
for (auto ai = a.begin(), bi = b.begin(); result and ai != a.end(); ++ai, ++bi)
|
||||
result = kCharToLowerMap[static_cast<uint8_t>(*ai)] == kCharToLowerMap[static_cast<uint8_t>(*bi)];
|
||||
result = kCharToLowerMap[uint8_t(*ai)] == kCharToLowerMap[uint8_t(*bi)];
|
||||
// result = tolower(*ai) == tolower(*bi);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool iequals(const char *a, const char *b) noexcept
|
||||
bool iequals(const char *a, const char *b)
|
||||
{
|
||||
bool result = true;
|
||||
for (; result and *a and *b; ++a, ++b)
|
||||
result = kCharToLowerMap[static_cast<uint8_t>(*a)] == kCharToLowerMap[static_cast<uint8_t>(*b)];
|
||||
result = kCharToLowerMap[uint8_t(*a)] == kCharToLowerMap[uint8_t(*b)];
|
||||
|
||||
return result and *a == *b;
|
||||
}
|
||||
|
||||
int icompare(std::string_view a, std::string_view b) noexcept
|
||||
int icompare(std::string_view a, std::string_view b)
|
||||
{
|
||||
int d = 0;
|
||||
auto ai = a.begin(), bi = b.begin();
|
||||
|
||||
for (; d == 0 and ai != a.end() and bi != b.end(); ++ai, ++bi)
|
||||
d = static_cast<int>(kCharToLowerMap[static_cast<uint8_t>(*ai)]) - static_cast<int>(kCharToLowerMap[static_cast<uint8_t>(*bi)]);
|
||||
d = (int)kCharToLowerMap[uint8_t(*ai)] - (int)kCharToLowerMap[uint8_t(*bi)];
|
||||
|
||||
if (d == 0)
|
||||
{
|
||||
@@ -97,12 +93,12 @@ int icompare(std::string_view a, std::string_view b) noexcept
|
||||
return d;
|
||||
}
|
||||
|
||||
int icompare(const char *a, const char *b) noexcept
|
||||
int icompare(const char *a, const char *b)
|
||||
{
|
||||
int d = 0;
|
||||
|
||||
for (; d == 0 and *a != 0 and *b != 0; ++a, ++b)
|
||||
d = static_cast<int>(kCharToLowerMap[static_cast<uint8_t>(*a)]) - static_cast<int>(kCharToLowerMap[static_cast<uint8_t>(*b)]);
|
||||
d = (int)kCharToLowerMap[uint8_t(*a)] - (int)kCharToLowerMap[uint8_t(*b)];
|
||||
|
||||
if (d == 0)
|
||||
{
|
||||
@@ -198,7 +194,7 @@ void trim_left(std::string &s)
|
||||
|
||||
while (in != s.end() and std::isspace(*in))
|
||||
++in;
|
||||
|
||||
|
||||
if (in == s.end())
|
||||
s.clear();
|
||||
else if (in != out)
|
||||
@@ -218,7 +214,7 @@ void trim(std::string &s)
|
||||
|
||||
while (in != end and std::isspace(*in))
|
||||
++in;
|
||||
|
||||
|
||||
if (in == end)
|
||||
s.clear();
|
||||
else if (in != out)
|
||||
@@ -267,7 +263,7 @@ std::string cif_id_for_number(int number)
|
||||
number = (number - r) / 26 - 1;
|
||||
} while (number >= 0);
|
||||
|
||||
std::ranges::reverse(result);
|
||||
std::reverse(result.begin(), result.end());
|
||||
|
||||
assert(not result.empty());
|
||||
|
||||
@@ -389,7 +385,7 @@ std::string::const_iterator nextLineBreak(std::string::const_iterator text, std:
|
||||
/* 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 },
|
||||
};
|
||||
|
||||
auto ch = static_cast<uint8_t>(*text);
|
||||
uint8_t ch = static_cast<uint8_t>(*text);
|
||||
|
||||
LineBreakClass cls;
|
||||
|
||||
@@ -493,7 +489,7 @@ std::vector<std::string> wrapLine(const std::string &text, std::size_t width)
|
||||
j = i;
|
||||
}
|
||||
|
||||
std::ranges::reverse(result);
|
||||
reverse(result.begin(), result.end());
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -505,7 +501,7 @@ std::vector<std::string> word_wrap(const std::string &text, std::size_t width)
|
||||
{
|
||||
if (p.empty())
|
||||
{
|
||||
result.emplace_back("");
|
||||
result.push_back("");
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -516,32 +512,4 @@ std::vector<std::string> word_wrap(const std::string &text, std::size_t width)
|
||||
return result;
|
||||
}
|
||||
|
||||
#if defined(USE_FAST_FLOAT)
|
||||
|
||||
template <typename T>
|
||||
std::from_chars_result ff_charconv<T, typename std::enable_if_t<std::is_floating_point_v<T>>>::from_chars(const char *a, const char *b, T &v)
|
||||
{
|
||||
auto r = fast_float::from_chars(a, b, v);
|
||||
return { r.ptr, r.ec };
|
||||
}
|
||||
|
||||
template struct ff_charconv<float>;
|
||||
template struct ff_charconv<double>;
|
||||
// template struct ff_charconv<long double>;
|
||||
|
||||
# ifdef __STDCPP_FLOAT64_T__
|
||||
template struct ff_charconv<std::float64_t>;
|
||||
# endif
|
||||
# ifdef __STDCPP_FLOAT32_T__
|
||||
template struct ff_charconv<std::float32_t>;
|
||||
# endif
|
||||
# ifdef __STDCPP_FLOAT16_T__
|
||||
template struct ff_charconv<std::float16_t>;
|
||||
# endif
|
||||
# ifdef __STDCPP_BFLOAT16_T__
|
||||
template struct ff_charconv<std::bfloat16_t>;
|
||||
# endif
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace cif
|
||||
} // namespace cif
|
||||
File diff suppressed because it is too large
Load Diff
616
src/validate.cpp
616
src/validate.cpp
@@ -25,38 +25,27 @@
|
||||
*/
|
||||
|
||||
#include "cif++/validate.hpp"
|
||||
|
||||
#include "cif++/cif++.hpp"
|
||||
#include "cif++/text.hpp"
|
||||
#include "cif++/category.hpp"
|
||||
#include "cif++/dictionary_parser.hpp"
|
||||
#include "cif++/gzio.hpp"
|
||||
#include "cif++/utilities.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <charconv>
|
||||
#include <cstddef>
|
||||
#include <filesystem>
|
||||
#include <format>
|
||||
#include <iomanip>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <ranges>
|
||||
#include <set>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <system_error>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
// The validator depends on regular expressions. Unfortunately,
|
||||
// the implementation of std::regex in g++ is buggy and crashes
|
||||
// on reading the pdbx dictionary. We used to use boost regex
|
||||
// instead but using pcre2 is even easier and faster.
|
||||
// on reading the pdbx dictionary. Therefore, in case g++ is used
|
||||
// the code will use boost::regex instead.
|
||||
|
||||
#define PCRE2_CODE_UNIT_WIDTH 8
|
||||
#include <pcre2.h>
|
||||
#if USE_BOOST_REGEX
|
||||
# include <boost/regex.hpp>
|
||||
using boost::regex;
|
||||
#else
|
||||
# include <regex>
|
||||
using std::regex;
|
||||
#endif
|
||||
|
||||
namespace cif
|
||||
{
|
||||
@@ -78,62 +67,13 @@ validation_exception::validation_exception(std::error_code ec, std::string_view
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
struct regex_impl
|
||||
struct regex_impl : public regex
|
||||
{
|
||||
regex_impl(std::string_view rx);
|
||||
~regex_impl();
|
||||
|
||||
regex_impl(const regex_impl &) = delete;
|
||||
regex_impl &operator=(const regex_impl &) = delete;
|
||||
|
||||
bool match(std::string_view v) const;
|
||||
|
||||
private:
|
||||
pcre2_code_8 *m_rx = nullptr;
|
||||
pcre2_match_data *m_data = nullptr;
|
||||
mutable std::mutex m_mutex;
|
||||
};
|
||||
|
||||
regex_impl::regex_impl(std::string_view rx)
|
||||
{
|
||||
int err_code;
|
||||
size_t err_offset;
|
||||
m_rx = pcre2_compile(reinterpret_cast<PCRE2_SPTR>(rx.data()), rx.length(), 0, &err_code, &err_offset, nullptr);
|
||||
if (m_rx == nullptr)
|
||||
regex_impl(std::string_view rx)
|
||||
: regex(rx.begin(), rx.end(), regex::extended | regex::optimize)
|
||||
{
|
||||
char buffer[256];
|
||||
int n = pcre2_get_error_message(err_code, reinterpret_cast<unsigned char *>(&buffer[0]), sizeof(buffer));
|
||||
|
||||
throw std::runtime_error(std::string("PCRE2 compilation failed: ") + std::string{ buffer, buffer + n });
|
||||
}
|
||||
|
||||
m_data = pcre2_match_data_create_from_pattern(m_rx, nullptr);
|
||||
}
|
||||
|
||||
regex_impl::~regex_impl()
|
||||
{
|
||||
std::unique_lock lock(m_mutex);
|
||||
|
||||
if (m_data)
|
||||
pcre2_match_data_free(m_data);
|
||||
|
||||
if (m_rx)
|
||||
pcre2_code_free(m_rx);
|
||||
}
|
||||
|
||||
bool regex_impl::match(std::string_view v) const
|
||||
{
|
||||
std::unique_lock lock(m_mutex);
|
||||
|
||||
bool result = false;
|
||||
|
||||
if (int rc = pcre2_match(m_rx, reinterpret_cast<PCRE2_SPTR>(v.data()), v.length(), 0, 0, m_data, nullptr); rc >= 0)
|
||||
result = true;
|
||||
else if (rc != PCRE2_ERROR_NOMATCH)
|
||||
std::cerr << "Error matching with pcre\n";
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
@@ -170,99 +110,130 @@ type_validator::type_validator(std::string_view name, DDL_PrimitiveType type, st
|
||||
{
|
||||
}
|
||||
|
||||
int type_validator::compare(const item_value &a, const item_value &b) const
|
||||
type_validator::~type_validator()
|
||||
{
|
||||
switch (m_primitive_type)
|
||||
delete m_rx;
|
||||
}
|
||||
|
||||
int type_validator::compare(std::string_view a, std::string_view b) const
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
if (a.empty())
|
||||
result = b.empty() ? 0 : -1;
|
||||
else if (b.empty())
|
||||
result = a.empty() ? 0 : +1;
|
||||
else
|
||||
{
|
||||
using enum DDL_PrimitiveType;
|
||||
|
||||
case Numb:
|
||||
switch (m_primitive_type)
|
||||
{
|
||||
if (a.is_number() and b.is_number())
|
||||
return a.compare(b);
|
||||
case DDL_PrimitiveType::Numb:
|
||||
{
|
||||
double da, db;
|
||||
|
||||
auto da = a.get<double>();
|
||||
auto db = b.get<double>();
|
||||
using namespace cif;
|
||||
using namespace std;
|
||||
|
||||
return da < db
|
||||
? -1
|
||||
: da > db
|
||||
? 1
|
||||
: 0;
|
||||
std::from_chars_result ra, rb;
|
||||
|
||||
ra = selected_charconv<double>::from_chars(a.data(), a.data() + a.length(), da);
|
||||
rb = selected_charconv<double>::from_chars(b.data(), b.data() + b.length(), db);
|
||||
|
||||
if (not(bool) ra.ec and not(bool) rb.ec)
|
||||
{
|
||||
auto d = da - db;
|
||||
if (std::abs(d) > std::numeric_limits<double>::epsilon())
|
||||
{
|
||||
if (d > 0)
|
||||
result = 1;
|
||||
else if (d < 0)
|
||||
result = -1;
|
||||
}
|
||||
}
|
||||
else if ((bool)ra.ec)
|
||||
result = 1;
|
||||
else
|
||||
result = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
case DDL_PrimitiveType::UChar:
|
||||
case DDL_PrimitiveType::Char:
|
||||
{
|
||||
// CIF is guaranteed to have ascii only, therefore this primitive code will do
|
||||
// also, we're collapsing spaces
|
||||
|
||||
auto ai = a.begin(), bi = b.begin();
|
||||
for (;;)
|
||||
{
|
||||
if (ai == a.end())
|
||||
{
|
||||
if (bi != b.end())
|
||||
result = -1;
|
||||
break;
|
||||
}
|
||||
else if (bi == b.end())
|
||||
{
|
||||
result = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
char ca = *ai;
|
||||
char cb = *bi;
|
||||
|
||||
if (m_primitive_type == DDL_PrimitiveType::UChar)
|
||||
{
|
||||
ca = tolower(ca);
|
||||
cb = tolower(cb);
|
||||
}
|
||||
|
||||
result = ca - cb;
|
||||
|
||||
if (result != 0)
|
||||
break;
|
||||
|
||||
if (ca == ' ')
|
||||
{
|
||||
while (ai[1] == ' ')
|
||||
++ai;
|
||||
while (bi[1] == ' ')
|
||||
++bi;
|
||||
}
|
||||
|
||||
++ai;
|
||||
++bi;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
case UChar:
|
||||
if (a.is_string() and b.is_string())
|
||||
return a.compare(b, true);
|
||||
|
||||
return icompare(a.str(), b.str());
|
||||
|
||||
case Char:
|
||||
if (a.is_string() and b.is_string())
|
||||
return a.compare(b, false);
|
||||
|
||||
return a.str().compare(b.str());
|
||||
|
||||
default:
|
||||
throw std::runtime_error("invalid primitive type");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
void item_validator::validate_value(const item_value &value) const
|
||||
void item_validator::operator()(std::string_view value) const
|
||||
{
|
||||
std::error_code ec;
|
||||
if (not validate_value(value, ec))
|
||||
throw std::system_error(ec, std::format("'{}' is not a valid value for {}", value.str(), m_item_name));
|
||||
throw std::system_error(ec, std::string{ value } + " does not match rx for " + m_item_name);
|
||||
}
|
||||
|
||||
bool item_validator::validate_value(const item_value &value, std::error_code &ec) const noexcept
|
||||
bool item_validator::validate_value(std::string_view value, std::error_code &ec) const noexcept
|
||||
{
|
||||
ec.clear();
|
||||
|
||||
if (not value.empty())
|
||||
if (not value.empty() and value != "?" and value != ".")
|
||||
{
|
||||
if (m_type != nullptr)
|
||||
{
|
||||
if (m_type->m_primitive_type == DDL_PrimitiveType::Numb)
|
||||
{
|
||||
if (not value.is_number())
|
||||
ec = make_error_code(validation_error::value_is_not_a_number);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (value.is_number())
|
||||
ec = make_error_code(validation_error::value_is_not_a_char_string);
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
if (not m_type->m_rx->match(value.sv()))
|
||||
ec = make_error_code(validation_error::value_does_not_match_rx);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
ec = make_error_code(validation_error::value_does_not_match_rx);
|
||||
}
|
||||
|
||||
if (ec == std::errc{} and not m_enums.empty())
|
||||
{
|
||||
bool valid =
|
||||
m_type->m_primitive_type == DDL_PrimitiveType::UChar ? //
|
||||
m_enums.contains(cif::to_lower_copy(value.sv()))
|
||||
: //
|
||||
m_enums.contains(std::string{ value.sv() });
|
||||
|
||||
if (not valid)
|
||||
ec = make_error_code(validation_error::value_is_not_in_enumeration_list);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (m_type != nullptr and not regex_match(value.begin(), value.end(), *m_type->m_rx))
|
||||
ec = make_error_code(validation_error::value_does_not_match_rx);
|
||||
else if (not m_enums.empty() and m_enums.count(std::string{ value }) == 0)
|
||||
ec = make_error_code(validation_error::value_is_not_in_enumeration_list);
|
||||
}
|
||||
|
||||
return ec == std::errc{};
|
||||
return not(bool) ec;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
@@ -272,22 +243,17 @@ void category_validator::add_item_validator(item_validator &&v)
|
||||
if (v.m_mandatory)
|
||||
m_mandatory_items.insert(v.m_item_name);
|
||||
|
||||
v.m_category = m_name;
|
||||
v.m_category = this;
|
||||
|
||||
auto i = std::ranges::find(m_item_validators, v);
|
||||
if (i != m_item_validators.end())
|
||||
{
|
||||
if (VERBOSE >= 4)
|
||||
std::cout << "Could not add validator for item " << v.m_item_name << " to category " << m_name << '\n';
|
||||
}
|
||||
else
|
||||
m_item_validators.emplace_back(std::move(v));
|
||||
auto r = m_item_validators.insert(std::move(v));
|
||||
if (not r.second and VERBOSE >= 4)
|
||||
std::cout << "Could not add validator for item " << v.m_item_name << " to category " << m_name << '\n';
|
||||
}
|
||||
|
||||
const item_validator *category_validator::get_validator_for_item(std::string_view item_name) const
|
||||
{
|
||||
const item_validator *result = nullptr;
|
||||
auto i = std::ranges::find(m_item_validators, item_validator{ std::string(item_name) });
|
||||
auto i = m_item_validators.find(item_validator{ std::string(item_name) });
|
||||
if (i != m_item_validators.end())
|
||||
result = &*i;
|
||||
else if (VERBOSE > 4)
|
||||
@@ -319,23 +285,32 @@ const item_validator *category_validator::get_validator_for_aliased_item(std::st
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
void swap(validator &a, validator &b) noexcept
|
||||
void validator_base::report_error(std::error_code ec, bool fatal) const
|
||||
{
|
||||
std::swap(a.m_audit_conform, b.m_audit_conform);
|
||||
std::swap(a.m_strict, b.m_strict);
|
||||
std::swap(a.m_type_validators, b.m_type_validators);
|
||||
std::swap(a.m_category_validators, b.m_category_validators);
|
||||
std::swap(a.m_link_validators, b.m_link_validators);
|
||||
if (m_strict or fatal)
|
||||
throw validation_exception(ec);
|
||||
else if (VERBOSE > 0)
|
||||
std::cerr << ec.message() << '\n';
|
||||
}
|
||||
|
||||
void validator::parse(std::istream &is)
|
||||
void validator_base::report_error(std::error_code ec, std::string_view category,
|
||||
std::string_view item, bool fatal) const
|
||||
{
|
||||
parse_dictionary(*this, is);
|
||||
auto ex = item.empty() ? validation_exception(ec, category) : validation_exception(ec, category, item);
|
||||
|
||||
if (m_strict or fatal)
|
||||
throw ex;
|
||||
else if (VERBOSE > 0)
|
||||
std::cerr << ex.what() << '\n';
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
void validator::add_type_validator(type_validator &&v)
|
||||
{
|
||||
m_type_validators.emplace(v);
|
||||
auto r = m_type_validators.insert(std::move(v));
|
||||
if (not r.second and VERBOSE > 4)
|
||||
std::cout << "Could not add validator for type " << v.m_name << '\n';
|
||||
}
|
||||
|
||||
const type_validator *validator::get_validator_for_type(std::string_view typeCode) const
|
||||
@@ -345,12 +320,16 @@ const type_validator *validator::get_validator_for_type(std::string_view typeCod
|
||||
auto i = m_type_validators.find(type_validator{ std::string(typeCode), DDL_PrimitiveType::Char, {} });
|
||||
if (i != m_type_validators.end())
|
||||
result = &*i;
|
||||
else if (VERBOSE > 4)
|
||||
std::cout << "No validator for type " << typeCode << '\n';
|
||||
return result;
|
||||
}
|
||||
|
||||
void validator::add_category_validator(category_validator &&v)
|
||||
{
|
||||
m_category_validators.emplace(v);
|
||||
auto r = m_category_validators.insert(std::move(v));
|
||||
if (not r.second and VERBOSE > 4)
|
||||
std::cout << "Could not add validator for category " << v.m_name << '\n';
|
||||
}
|
||||
|
||||
const category_validator *validator::get_validator_for_category(std::string_view category) const
|
||||
@@ -359,6 +338,8 @@ const category_validator *validator::get_validator_for_category(std::string_view
|
||||
auto i = m_category_validators.find(category_validator{ std::string(category) });
|
||||
if (i != m_category_validators.end())
|
||||
result = &*i;
|
||||
else if (VERBOSE > 4)
|
||||
std::cout << "No validator for category " << category << '\n';
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -438,81 +419,76 @@ std::vector<const link_validator *> validator::get_links_for_child(std::string_v
|
||||
return result;
|
||||
}
|
||||
|
||||
void validator::report_error(std::error_code ec, bool fatal) const
|
||||
{
|
||||
if (m_strict or fatal)
|
||||
throw validation_exception(ec);
|
||||
else if (VERBOSE > 0)
|
||||
std::cerr << ec.message() << '\n';
|
||||
}
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
void validator::report_error(std::error_code ec, std::string value,
|
||||
std::string_view category, std::string_view item, bool fatal) const
|
||||
extended_validator::extended_validator(std::vector<const validator *> validators)
|
||||
: m_validators(validators)
|
||||
{
|
||||
if (m_strict or fatal)
|
||||
std::vector<std::string> names, versions;
|
||||
|
||||
for (auto v : m_validators)
|
||||
{
|
||||
if (item.empty())
|
||||
throw validation_exception(ec, category);
|
||||
else
|
||||
throw validation_exception(ec, category, item);
|
||||
names.emplace_back(v->name());
|
||||
versions.emplace_back(v->version());
|
||||
m_strict = m_strict or v->is_strict();
|
||||
}
|
||||
|
||||
if (VERBOSE > 0)
|
||||
{
|
||||
if (value.empty())
|
||||
std::cerr << ec.message()
|
||||
<< "; category: " << std::quoted(category)
|
||||
<< " item: " << std::quoted(item)
|
||||
<< '\n';
|
||||
else
|
||||
std::cerr << ec.message()
|
||||
<< "; value: " << std::quoted(value)
|
||||
<< "; category: " << std::quoted(category)
|
||||
<< " item: " << std::quoted(item)
|
||||
<< '\n';
|
||||
}
|
||||
m_name = cif::join(names, "; ");
|
||||
m_version = cif::join(versions, "; ");
|
||||
}
|
||||
|
||||
void validator::fill_audit_conform(category &audit_conform) const
|
||||
const type_validator *extended_validator::get_validator_for_type(std::string_view type_code) const
|
||||
{
|
||||
audit_conform.clear();
|
||||
audit_conform.emplace(m_audit_conform.begin(), m_audit_conform.end());
|
||||
}
|
||||
const type_validator *result = nullptr;
|
||||
|
||||
bool validator::matches_audit_conform(const category &audit_conform) const
|
||||
{
|
||||
if (audit_conform.empty())
|
||||
return false;
|
||||
|
||||
auto ai = m_audit_conform.begin();
|
||||
auto bi = audit_conform.begin();
|
||||
|
||||
while (ai != m_audit_conform.end() and bi != audit_conform.end())
|
||||
for (auto v : m_validators)
|
||||
{
|
||||
const auto &[name_a, version_a] = ai->get<std::string, std::optional<std::string>>("dict_name", "dict_version");
|
||||
const auto &[name_b, version_b] = bi->get<std::string, std::optional<std::string>>("dict_name", "dict_version");
|
||||
|
||||
++ai;
|
||||
++bi;
|
||||
|
||||
if (name_a != name_b)
|
||||
return false;
|
||||
|
||||
if (not version_b.has_value() or not version_a.has_value())
|
||||
continue;
|
||||
|
||||
if (validator_factory::check_version(name_a, *version_b, *version_a) == false)
|
||||
return false;
|
||||
result = v->get_validator_for_type(type_code);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
|
||||
return ai == m_audit_conform.end() and bi == audit_conform.end();
|
||||
return result;
|
||||
}
|
||||
|
||||
void validator::append_audit_conform(const std::string &name, const std::optional<std::string> &version)
|
||||
const category_validator *extended_validator::get_validator_for_category(std::string_view category) const
|
||||
{
|
||||
m_audit_conform.emplace({ //
|
||||
{ "dict_name", name },
|
||||
{ "dict_version", version } });
|
||||
const category_validator *result = nullptr;
|
||||
|
||||
for (auto v : m_validators)
|
||||
{
|
||||
result = v->get_validator_for_category(category);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<const link_validator *> extended_validator::get_links_for_parent(std::string_view category) const
|
||||
{
|
||||
std::vector<const link_validator *> result;
|
||||
|
||||
for (auto v : m_validators)
|
||||
{
|
||||
auto links = v->get_links_for_parent(category);
|
||||
result.insert(result.end(), links.begin(), links.end());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<const link_validator *> extended_validator::get_links_for_child(std::string_view category) const
|
||||
{
|
||||
std::vector<const link_validator *> result;
|
||||
|
||||
for (auto v : m_validators)
|
||||
{
|
||||
auto links = v->get_links_for_child(category);
|
||||
result.insert(result.end(), links.begin(), links.end());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
@@ -523,101 +499,129 @@ validator_factory &validator_factory::instance()
|
||||
return s_instance;
|
||||
}
|
||||
|
||||
const validator *validator_factory::get(std::string_view dictionary_name)
|
||||
const validator_base &validator_factory::operator[](std::string_view dictionary_name)
|
||||
{
|
||||
category audit_conform("audit_conform");
|
||||
for (auto part : cif::split(dictionary_name, ";,", true))
|
||||
for (auto part : cif::split(dictionary_name, ";", true))
|
||||
audit_conform.emplace({ { "dict_name", part } });
|
||||
|
||||
return get(audit_conform);
|
||||
return construct_validator(audit_conform);
|
||||
}
|
||||
|
||||
const validator *validator_factory::get(const category &audit_conform)
|
||||
const validator_base &validator_factory::construct_validator(const category &audit_conform)
|
||||
{
|
||||
const validator *result = nullptr;
|
||||
if (audit_conform.empty())
|
||||
throw std::runtime_error("Empty audit_conform category, cannot create a validator");
|
||||
|
||||
std::scoped_lock lock(m_mutex);
|
||||
std::lock_guard lock(m_mutex);
|
||||
|
||||
// Check existing first
|
||||
std::vector<const validator *> validators;
|
||||
|
||||
for (const auto &[name, version] : audit_conform.rows<std::string, std::optional<std::string>>("dict_name", "dict_version"))
|
||||
{
|
||||
auto &v = construct_validator(name, version);
|
||||
validators.emplace_back(&v);
|
||||
}
|
||||
|
||||
if (validators.size() == 1)
|
||||
return *validators.front();
|
||||
|
||||
// override mode, last dictionary is most important
|
||||
std::reverse(validators.begin(), validators.end());
|
||||
|
||||
for (auto &ev : m_extended_validators)
|
||||
{
|
||||
if (ev.m_validators == validators)
|
||||
return ev;
|
||||
}
|
||||
|
||||
return m_extended_validators.emplace_back(validators);
|
||||
}
|
||||
|
||||
const validator &validator_factory::construct_validator(std::string_view name,
|
||||
std::optional<std::string> version)
|
||||
{
|
||||
for (auto &v : m_validators)
|
||||
{
|
||||
if (v.matches_audit_conform(audit_conform))
|
||||
result = &v;
|
||||
if (version.has_value())
|
||||
check_version(name, *version, v.version());
|
||||
|
||||
if (v.name() == name)
|
||||
return v;
|
||||
}
|
||||
|
||||
// If the audit conform contains only one record, this is easy
|
||||
if (result == nullptr and audit_conform.size() == 1)
|
||||
{
|
||||
const auto &[name, version] =
|
||||
audit_conform.front().get<std::string, std::optional<std::string>>("dict_name", "dict_version");
|
||||
if (not name.empty())
|
||||
result = &m_validators.emplace_back(construct_validator(name, version));
|
||||
}
|
||||
std::filesystem::path dictionary(name);
|
||||
|
||||
if (result == nullptr)
|
||||
{
|
||||
// A new, merged dictionary
|
||||
std::optional<validator> v;
|
||||
for (const auto &[name, version] : audit_conform.rows<std::string, std::optional<std::string>>("dict_name", "dict_version"))
|
||||
{
|
||||
if (name.empty())
|
||||
continue;
|
||||
|
||||
if (not v) // first dict
|
||||
v = construct_validator(name, version);
|
||||
else // additional/extending dict
|
||||
{
|
||||
auto data = load_resource(name);
|
||||
if (not data)
|
||||
throw std::runtime_error("Could not load dictionary " + std::string{ name });
|
||||
|
||||
v->parse(*data);
|
||||
}
|
||||
}
|
||||
|
||||
if (v)
|
||||
result = &m_validators.emplace_back(std::move(*v));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const validator &validator_factory::operator[](const category &audit_conform)
|
||||
{
|
||||
auto v = get(audit_conform);
|
||||
if (v == nullptr)
|
||||
throw std::runtime_error("Could not load dictionary for audit_conform");
|
||||
return *v;
|
||||
}
|
||||
|
||||
const validator &validator_factory::operator[](std::string_view dictionary_name)
|
||||
{
|
||||
auto v = get(dictionary_name);
|
||||
if (v == nullptr)
|
||||
throw std::runtime_error("Could not load dictionary for " + std::string{ dictionary_name });
|
||||
return *v;
|
||||
}
|
||||
|
||||
validator validator_factory::construct_validator(std::string_view name, std::optional<std::string> version)
|
||||
{
|
||||
auto data = load_resource(name);
|
||||
if (not data and name == "mmcif_pdbx_v50")
|
||||
data = load_resource("mmcif_pdbx.dic");
|
||||
|
||||
if (not data and dictionary.extension().string() != ".dic")
|
||||
data = load_resource(dictionary.parent_path() / (dictionary.filename().string() + ".dic"));
|
||||
|
||||
if (not data)
|
||||
throw std::runtime_error("Could not load dictionary " + std::string{ name });
|
||||
|
||||
validator v;
|
||||
v.parse(*data);
|
||||
|
||||
if (version.has_value() and VERBOSE >= 0 and
|
||||
not v.matches_audit_conform(category{ "audit_conform", //
|
||||
{ { "dict_name", name }, { "dict_version", version } } }))
|
||||
{
|
||||
std::clog << "Loaded dictionary does not match name=" << name << " and version=" << version.value_or("''") << "\n";
|
||||
std::error_code ec;
|
||||
|
||||
// might be a compressed dictionary on disk
|
||||
std::filesystem::path p = dictionary;
|
||||
if (p.extension() == ".dic")
|
||||
p = p.parent_path() / (p.filename().string() + ".gz");
|
||||
else
|
||||
p = p.parent_path() / (p.filename().string() + ".dic.gz");
|
||||
|
||||
#if defined(CACHE_DIR) or defined(DATA_DIR)
|
||||
if (not std::filesystem::exists(p, ec) or ec)
|
||||
{
|
||||
for (const char *dir : {
|
||||
# if defined(CACHE_DIR)
|
||||
CACHE_DIR,
|
||||
# endif
|
||||
# if defined(DATA_DIR)
|
||||
DATA_DIR
|
||||
# endif
|
||||
})
|
||||
{
|
||||
auto p2 = std::filesystem::path(dir) / p;
|
||||
if (std::filesystem::exists(p2, ec) and not ec)
|
||||
{
|
||||
swap(p, p2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (std::filesystem::exists(p, ec) and not ec)
|
||||
{
|
||||
auto in = std::make_unique<gzio::ifstream>(p);
|
||||
|
||||
if (not in->is_open())
|
||||
throw std::runtime_error("Could not open dictionary (" + p.string() + ")");
|
||||
|
||||
data.reset(in.release());
|
||||
}
|
||||
else
|
||||
throw std::runtime_error("Dictionary not found or defined (" + dictionary.string() + ")");
|
||||
}
|
||||
|
||||
return v;
|
||||
return construct_validator(name, version, *data);
|
||||
}
|
||||
|
||||
const validator &validator_factory::construct_validator(std::string_view name,
|
||||
std::optional<std::string> version, std::istream &is)
|
||||
{
|
||||
auto v = parse_dictionary(name, is);
|
||||
|
||||
if (version.has_value() and VERBOSE >= 0)
|
||||
{
|
||||
auto vv = v.version();
|
||||
|
||||
if (vv.empty())
|
||||
std::clog << "Could not check version of dictionary " << name << " since this info is missing\n";
|
||||
else
|
||||
check_version(name, *version, vv);
|
||||
}
|
||||
|
||||
return m_validators.emplace_back(std::move(v));
|
||||
}
|
||||
|
||||
bool validator_factory::check_version(std::string_view name, std::string_view expected, std::string_view found)
|
||||
@@ -632,14 +636,14 @@ bool validator_factory::check_version(std::string_view name, std::string_view ex
|
||||
while (eli != el.end() and fli != fl.end())
|
||||
{
|
||||
int e_int, f_int;
|
||||
if (auto [ptr, ec] = std::from_chars(eli->data(), eli->data() + eli->length(), e_int); ec != std::errc{})
|
||||
if (auto [ptr, ec] = std::from_chars(eli->begin(), eli->end(), e_int); ec != std::errc{})
|
||||
{
|
||||
std::clog << "Could not parse requested version string for dictionary " << std::quoted(expected) << "\n";
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (auto [ptr, ec] = std::from_chars(fli->data(), fli->data() + fli->length(), f_int); ec != std::errc{})
|
||||
if (auto [ptr, ec] = std::from_chars(fli->begin(), fli->end(), f_int); ec != std::errc{})
|
||||
{
|
||||
std::clog << "Could not parse version string in dictionary " << name << " " << std::quoted(found) << "\n";
|
||||
result = false;
|
||||
|
||||
2770
test/1cbs-dssp.cif
2770
test/1cbs-dssp.cif
File diff suppressed because it is too large
Load Diff
BIN
test/476d.cif.gz
BIN
test/476d.cif.gz
Binary file not shown.
@@ -1,39 +1,19 @@
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
#
|
||||
# Copyright (c) 2025 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.
|
||||
# We're using the older version 2 of Catch2
|
||||
|
||||
if(NOT (Catch2_FOUND OR TARGET Catch2))
|
||||
find_package(Catch2 3 QUIET)
|
||||
if(NOT(Catch2_FOUND OR TARGET Catch2))
|
||||
find_package(Catch2 QUIET)
|
||||
|
||||
if(NOT Catch2_FOUND)
|
||||
include(FetchContent)
|
||||
|
||||
FetchContent_Declare(
|
||||
Catch2
|
||||
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
|
||||
GIT_TAG v3.4.0)
|
||||
GIT_TAG v2.13.9)
|
||||
|
||||
FetchContent_MakeAvailable(Catch2)
|
||||
|
||||
target_compile_features(Catch2 PRIVATE cxx_std_20)
|
||||
set(Catch2_VERSION "2.13.9")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -42,21 +22,24 @@ list(
|
||||
CIFPP_tests
|
||||
unit-v2
|
||||
unit-3d
|
||||
format
|
||||
model
|
||||
# query
|
||||
rename-compound
|
||||
sugar
|
||||
spinner
|
||||
reconstruction
|
||||
validate-pdbx
|
||||
cql
|
||||
matrix
|
||||
)
|
||||
# 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_LESS 3.0.0)
|
||||
target_compile_definitions(test-main PUBLIC CATCH22=1)
|
||||
else()
|
||||
target_compile_definitions(test-main PUBLIC CATCH22=0)
|
||||
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")
|
||||
@@ -64,17 +47,29 @@ foreach(CIFPP_TEST IN LISTS CIFPP_tests)
|
||||
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 cifpp::cifpp Catch2::Catch2)
|
||||
target_include_directories(${CIFPP_TEST} PRIVATE "${EIGEN_INCLUDE_DIR}")
|
||||
target_compile_features(${CIFPP_TEST} PUBLIC cxx_std_23)
|
||||
|
||||
if(MSVC)
|
||||
# Specify unwind semantics so that MSVC knowns how to handle exceptions
|
||||
target_compile_options(${CIFPP_TEST} PRIVATE /EHsc)
|
||||
endif()
|
||||
|
||||
if(NOT (CIFPP_TEST STREQUAL "spinner-test"))
|
||||
add_test(NAME ${CIFPP_TEST}
|
||||
COMMAND $<TARGET_FILE:${CIFPP_TEST}> --data-dir ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
endif()
|
||||
endforeach()
|
||||
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()
|
||||
822
test/brak.pdb
822
test/brak.pdb
@@ -1,822 +0,0 @@
|
||||
REMARK 001 design 0 N 3 RMSD 1.605
|
||||
MODEL 1
|
||||
ATOM 1 N MET A 1 -24.216 -7.571 -1.155 1.00 31.87 N
|
||||
ATOM 2 CA MET A 1 -22.971 -7.756 -0.416 1.00 31.87 C
|
||||
ATOM 3 C MET A 1 -21.814 -7.051 -1.114 1.00 31.87 C
|
||||
ATOM 4 CB MET A 1 -22.656 -9.245 -0.256 1.00 31.87 C
|
||||
ATOM 5 O MET A 1 -21.516 -7.338 -2.275 1.00 31.87 O
|
||||
ATOM 6 CG MET A 1 -22.779 -9.747 1.174 1.00 31.87 C
|
||||
ATOM 7 SD MET A 1 -22.473 -11.551 1.314 1.00 31.87 S
|
||||
ATOM 8 CE MET A 1 -22.597 -11.758 3.112 1.00 31.87 C
|
||||
ATOM 9 N LYS A 2 -21.652 -5.596 -0.909 1.00 33.06 N
|
||||
ATOM 10 CA LYS A 2 -21.035 -4.320 -0.554 1.00 33.06 C
|
||||
ATOM 11 C LYS A 2 -19.531 -4.475 -0.351 1.00 33.06 C
|
||||
ATOM 12 CB LYS A 2 -21.678 -3.747 0.710 1.00 33.06 C
|
||||
ATOM 13 O LYS A 2 -19.087 -5.326 0.423 1.00 33.06 O
|
||||
ATOM 14 CG LYS A 2 -22.957 -2.963 0.453 1.00 33.06 C
|
||||
ATOM 15 CD LYS A 2 -23.454 -2.275 1.717 1.00 33.06 C
|
||||
ATOM 16 CE LYS A 2 -24.810 -1.615 1.500 1.00 33.06 C
|
||||
ATOM 17 NZ LYS A 2 -25.284 -0.906 2.725 1.00 33.06 N
|
||||
ATOM 18 N ILE A 3 -18.889 -4.065 -1.586 1.00 34.22 N
|
||||
ATOM 19 CA ILE A 3 -17.539 -3.550 -1.381 1.00 34.22 C
|
||||
ATOM 20 C ILE A 3 -17.331 -2.297 -2.229 1.00 34.22 C
|
||||
ATOM 21 CB ILE A 3 -16.471 -4.612 -1.721 1.00 34.22 C
|
||||
ATOM 22 O ILE A 3 -17.508 -2.330 -3.449 1.00 34.22 O
|
||||
ATOM 23 CG1 ILE A 3 -16.524 -5.766 -0.713 1.00 34.22 C
|
||||
ATOM 24 CG2 ILE A 3 -15.075 -3.982 -1.759 1.00 34.22 C
|
||||
ATOM 25 CD1 ILE A 3 -15.743 -7.000 -1.142 1.00 34.22 C
|
||||
ATOM 26 N ILE A 4 -17.776 -0.985 -1.831 1.00 40.18 N
|
||||
ATOM 27 CA ILE A 4 -17.255 0.212 -1.181 1.00 40.18 C
|
||||
ATOM 28 C ILE A 4 -16.631 1.136 -2.224 1.00 40.18 C
|
||||
ATOM 29 CB ILE A 4 -16.218 -0.142 -0.091 1.00 40.18 C
|
||||
ATOM 30 O ILE A 4 -15.717 0.736 -2.949 1.00 40.18 O
|
||||
ATOM 31 CG1 ILE A 4 -16.844 -1.063 0.963 1.00 40.18 C
|
||||
ATOM 32 CG2 ILE A 4 -15.658 1.128 0.555 1.00 40.18 C
|
||||
ATOM 33 CD1 ILE A 4 -15.839 -1.662 1.937 1.00 40.18 C
|
||||
ATOM 34 N GLU A 5 -17.325 2.198 -2.769 1.00 38.95 N
|
||||
ATOM 35 CA GLU A 5 -17.243 3.640 -2.553 1.00 38.95 C
|
||||
ATOM 36 C GLU A 5 -15.944 4.019 -1.848 1.00 38.95 C
|
||||
ATOM 37 CB GLU A 5 -18.445 4.131 -1.741 1.00 38.95 C
|
||||
ATOM 38 O GLU A 5 -15.602 3.445 -0.812 1.00 38.95 O
|
||||
ATOM 39 CG GLU A 5 -19.296 5.162 -2.466 1.00 38.95 C
|
||||
ATOM 40 CD GLU A 5 -20.407 5.738 -1.602 1.00 38.95 C
|
||||
ATOM 41 OE1 GLU A 5 -20.194 6.791 -0.960 1.00 38.95 O
|
||||
ATOM 42 OE2 GLU A 5 -21.500 5.129 -1.566 1.00 38.95 O
|
||||
ATOM 43 N LYS A 6 -14.697 4.048 -2.514 1.00 40.24 N
|
||||
ATOM 44 CA LYS A 6 -13.793 5.173 -2.294 1.00 40.24 C
|
||||
ATOM 45 C LYS A 6 -12.348 4.784 -2.593 1.00 40.24 C
|
||||
ATOM 46 CB LYS A 6 -13.911 5.684 -0.857 1.00 40.24 C
|
||||
ATOM 47 O LYS A 6 -11.769 3.946 -1.899 1.00 40.24 O
|
||||
ATOM 48 CG LYS A 6 -14.799 6.911 -0.707 1.00 40.24 C
|
||||
ATOM 49 CD LYS A 6 -14.696 7.508 0.690 1.00 40.24 C
|
||||
ATOM 50 CE LYS A 6 -15.689 8.645 0.887 1.00 40.24 C
|
||||
ATOM 51 NZ LYS A 6 -15.523 9.301 2.219 1.00 40.24 N
|
||||
ATOM 52 N TYR A 7 -12.096 4.360 -3.877 1.00 55.19 N
|
||||
ATOM 53 CA TYR A 7 -10.695 4.330 -4.282 1.00 55.19 C
|
||||
ATOM 54 C TYR A 7 -9.919 5.478 -3.647 1.00 55.19 C
|
||||
ATOM 55 CB TYR A 7 -10.574 4.398 -5.807 1.00 55.19 C
|
||||
ATOM 56 O TYR A 7 -10.324 6.639 -3.746 1.00 55.19 O
|
||||
ATOM 57 CG TYR A 7 -11.069 3.159 -6.511 1.00 55.19 C
|
||||
ATOM 58 CD1 TYR A 7 -10.245 2.047 -6.669 1.00 55.19 C
|
||||
ATOM 59 CD2 TYR A 7 -12.361 3.097 -7.021 1.00 55.19 C
|
||||
ATOM 60 CE1 TYR A 7 -10.696 0.903 -7.319 1.00 55.19 C
|
||||
ATOM 61 CE2 TYR A 7 -12.823 1.958 -7.673 1.00 55.19 C
|
||||
ATOM 62 OH TYR A 7 -12.437 -0.262 -8.461 1.00 55.19 O
|
||||
ATOM 63 CZ TYR A 7 -11.985 0.868 -7.817 1.00 55.19 C
|
||||
ATOM 64 N VAL A 8 -9.308 5.253 -2.484 1.00 55.50 N
|
||||
ATOM 65 CA VAL A 8 -8.469 6.226 -1.792 1.00 55.50 C
|
||||
ATOM 66 C VAL A 8 -7.196 6.476 -2.597 1.00 55.50 C
|
||||
ATOM 67 CB VAL A 8 -8.112 5.754 -0.364 1.00 55.50 C
|
||||
ATOM 68 O VAL A 8 -6.488 5.534 -2.960 1.00 55.50 O
|
||||
ATOM 69 CG1 VAL A 8 -7.215 6.774 0.333 1.00 55.50 C
|
||||
ATOM 70 CG2 VAL A 8 -9.381 5.509 0.450 1.00 55.50 C
|
||||
ATOM 71 N PHE A 9 -7.225 7.625 -3.250 1.00 66.91 N
|
||||
ATOM 72 CA PHE A 9 -6.004 8.094 -3.895 1.00 66.91 C
|
||||
ATOM 73 C PHE A 9 -4.934 8.414 -2.858 1.00 66.91 C
|
||||
ATOM 74 CB PHE A 9 -6.289 9.330 -4.754 1.00 66.91 C
|
||||
ATOM 75 O PHE A 9 -5.089 9.345 -2.065 1.00 66.91 O
|
||||
ATOM 76 CG PHE A 9 -6.868 9.009 -6.105 1.00 66.91 C
|
||||
ATOM 77 CD1 PHE A 9 -6.039 8.797 -7.200 1.00 66.91 C
|
||||
ATOM 78 CD2 PHE A 9 -8.243 8.920 -6.281 1.00 66.91 C
|
||||
ATOM 79 CE1 PHE A 9 -6.572 8.499 -8.452 1.00 66.91 C
|
||||
ATOM 80 CE2 PHE A 9 -8.783 8.623 -7.530 1.00 66.91 C
|
||||
ATOM 81 CZ PHE A 9 -7.946 8.414 -8.614 1.00 66.91 C
|
||||
ATOM 82 N LEU A 10 -4.065 7.388 -2.607 1.00 72.14 N
|
||||
ATOM 83 CA LEU A 10 -2.967 7.542 -1.658 1.00 72.14 C
|
||||
ATOM 84 C LEU A 10 -2.342 8.929 -1.771 1.00 72.14 C
|
||||
ATOM 85 CB LEU A 10 -1.902 6.469 -1.893 1.00 72.14 C
|
||||
ATOM 86 O LEU A 10 -1.903 9.499 -0.770 1.00 72.14 O
|
||||
ATOM 87 CG LEU A 10 -2.222 5.069 -1.365 1.00 72.14 C
|
||||
ATOM 88 CD1 LEU A 10 -1.258 4.046 -1.957 1.00 72.14 C
|
||||
ATOM 89 CD2 LEU A 10 -2.165 5.045 0.158 1.00 72.14 C
|
||||
ATOM 90 N ALA A 11 -2.498 9.659 -2.947 1.00 69.94 N
|
||||
ATOM 91 CA ALA A 11 -1.847 10.939 -3.211 1.00 69.94 C
|
||||
ATOM 92 C ALA A 11 -2.571 12.080 -2.501 1.00 69.94 C
|
||||
ATOM 93 CB ALA A 11 -1.786 11.206 -4.713 1.00 69.94 C
|
||||
ATOM 94 O ALA A 11 -1.971 13.117 -2.207 1.00 69.94 O
|
||||
ATOM 95 N GLU A 12 -3.713 11.866 -1.974 1.00 76.23 N
|
||||
ATOM 96 CA GLU A 12 -4.520 12.921 -1.368 1.00 76.23 C
|
||||
ATOM 97 C GLU A 12 -4.620 12.741 0.144 1.00 76.23 C
|
||||
ATOM 98 CB GLU A 12 -5.920 12.951 -1.987 1.00 76.23 C
|
||||
ATOM 99 O GLU A 12 -5.178 13.590 0.841 1.00 76.23 O
|
||||
ATOM 100 CG GLU A 12 -5.939 13.391 -3.444 1.00 76.23 C
|
||||
ATOM 101 CD GLU A 12 -7.343 13.548 -4.005 1.00 76.23 C
|
||||
ATOM 102 OE1 GLU A 12 -7.904 14.665 -3.935 1.00 76.23 O
|
||||
ATOM 103 OE2 GLU A 12 -7.888 12.544 -4.518 1.00 76.23 O
|
||||
ATOM 104 N LEU A 13 -3.986 11.682 0.620 1.00 82.70 N
|
||||
ATOM 105 CA LEU A 13 -4.106 11.386 2.043 1.00 82.70 C
|
||||
ATOM 106 C LEU A 13 -2.951 12.001 2.826 1.00 82.70 C
|
||||
ATOM 107 CB LEU A 13 -4.146 9.873 2.274 1.00 82.70 C
|
||||
ATOM 108 O LEU A 13 -1.826 12.073 2.327 1.00 82.70 O
|
||||
ATOM 109 CG LEU A 13 -5.347 9.129 1.688 1.00 82.70 C
|
||||
ATOM 110 CD1 LEU A 13 -5.171 7.623 1.857 1.00 82.70 C
|
||||
ATOM 111 CD2 LEU A 13 -6.640 9.598 2.346 1.00 82.70 C
|
||||
ATOM 112 N SER A 14 -3.339 12.631 3.947 1.00 86.03 N
|
||||
ATOM 113 CA SER A 14 -2.328 13.121 4.878 1.00 86.03 C
|
||||
ATOM 114 C SER A 14 -1.680 11.974 5.645 1.00 86.03 C
|
||||
ATOM 115 CB SER A 14 -2.942 14.120 5.859 1.00 86.03 C
|
||||
ATOM 116 O SER A 14 -2.161 10.839 5.599 1.00 86.03 O
|
||||
ATOM 117 OG SER A 14 -3.526 15.211 5.168 1.00 86.03 O
|
||||
ATOM 118 N ASP A 15 -0.488 12.215 6.359 1.00 86.85 N
|
||||
ATOM 119 CA ASP A 15 0.221 11.246 7.189 1.00 86.85 C
|
||||
ATOM 120 C ASP A 15 -0.734 10.542 8.149 1.00 86.85 C
|
||||
ATOM 121 CB ASP A 15 1.345 11.930 7.971 1.00 86.85 C
|
||||
ATOM 122 O ASP A 15 -0.647 9.327 8.340 1.00 86.85 O
|
||||
ATOM 123 CG ASP A 15 2.418 12.521 7.074 1.00 86.85 C
|
||||
ATOM 124 OD1 ASP A 15 3.279 11.766 6.575 1.00 86.85 O
|
||||
ATOM 125 OD2 ASP A 15 2.403 13.754 6.867 1.00 86.85 O
|
||||
ATOM 126 N GLU A 16 -1.606 11.353 8.835 1.00 86.30 N
|
||||
ATOM 127 CA GLU A 16 -2.590 10.797 9.760 1.00 86.30 C
|
||||
ATOM 128 C GLU A 16 -3.555 9.859 9.041 1.00 86.30 C
|
||||
ATOM 129 CB GLU A 16 -3.366 11.918 10.456 1.00 86.30 C
|
||||
ATOM 130 O GLU A 16 -3.871 8.780 9.545 1.00 86.30 O
|
||||
ATOM 131 CG GLU A 16 -2.547 12.688 11.481 1.00 86.30 C
|
||||
ATOM 132 CD GLU A 16 -3.342 13.770 12.194 1.00 86.30 C
|
||||
ATOM 133 OE1 GLU A 16 -3.925 13.489 13.266 1.00 86.30 O
|
||||
ATOM 134 OE2 GLU A 16 -3.384 14.908 11.676 1.00 86.30 O
|
||||
ATOM 135 N GLU A 17 -4.022 10.266 7.880 1.00 87.05 N
|
||||
ATOM 136 CA GLU A 17 -4.956 9.466 7.093 1.00 87.05 C
|
||||
ATOM 137 C GLU A 17 -4.305 8.172 6.613 1.00 87.05 C
|
||||
ATOM 138 CB GLU A 17 -5.477 10.268 5.898 1.00 87.05 C
|
||||
ATOM 139 O GLU A 17 -4.937 7.114 6.618 1.00 87.05 O
|
||||
ATOM 140 CG GLU A 17 -6.410 11.407 6.281 1.00 87.05 C
|
||||
ATOM 141 CD GLU A 17 -7.322 11.844 5.146 1.00 87.05 C
|
||||
ATOM 142 OE1 GLU A 17 -8.505 11.433 5.125 1.00 87.05 O
|
||||
ATOM 143 OE2 GLU A 17 -6.850 12.602 4.270 1.00 87.05 O
|
||||
ATOM 144 N LEU A 18 -3.057 8.282 6.290 1.00 88.16 N
|
||||
ATOM 145 CA LEU A 18 -2.291 7.120 5.855 1.00 88.16 C
|
||||
ATOM 146 C LEU A 18 -2.194 6.084 6.970 1.00 88.16 C
|
||||
ATOM 147 CB LEU A 18 -0.889 7.539 5.407 1.00 88.16 C
|
||||
ATOM 148 O LEU A 18 -2.374 4.888 6.730 1.00 88.16 O
|
||||
ATOM 149 CG LEU A 18 -0.785 8.201 4.032 1.00 88.16 C
|
||||
ATOM 150 CD1 LEU A 18 0.627 8.730 3.803 1.00 88.16 C
|
||||
ATOM 151 CD2 LEU A 18 -1.179 7.219 2.934 1.00 88.16 C
|
||||
ATOM 152 N LYS A 19 -1.979 6.558 8.141 1.00 87.30 N
|
||||
ATOM 153 CA LYS A 19 -1.908 5.682 9.308 1.00 87.30 C
|
||||
ATOM 154 C LYS A 19 -3.243 4.984 9.553 1.00 87.30 C
|
||||
ATOM 155 CB LYS A 19 -1.495 6.474 10.549 1.00 87.30 C
|
||||
ATOM 156 O LYS A 19 -3.280 3.787 9.843 1.00 87.30 O
|
||||
ATOM 157 CG LYS A 19 -0.007 6.781 10.620 1.00 87.30 C
|
||||
ATOM 158 CD LYS A 19 0.352 7.515 11.906 1.00 87.30 C
|
||||
ATOM 159 CE LYS A 19 1.818 7.927 11.926 1.00 87.30 C
|
||||
ATOM 160 NZ LYS A 19 2.176 8.639 13.189 1.00 87.30 N
|
||||
ATOM 161 N LYS A 20 -4.246 5.781 9.525 1.00 88.15 N
|
||||
ATOM 162 CA LYS A 20 -5.586 5.234 9.715 1.00 88.15 C
|
||||
ATOM 163 C LYS A 20 -5.907 4.185 8.654 1.00 88.15 C
|
||||
ATOM 164 CB LYS A 20 -6.631 6.350 9.682 1.00 88.15 C
|
||||
ATOM 165 O LYS A 20 -6.511 3.153 8.956 1.00 88.15 O
|
||||
ATOM 166 CG LYS A 20 -6.661 7.208 10.937 1.00 88.15 C
|
||||
ATOM 167 CD LYS A 20 -7.772 8.249 10.877 1.00 88.15 C
|
||||
ATOM 168 CE LYS A 20 -7.774 9.138 12.113 1.00 88.15 C
|
||||
ATOM 169 NZ LYS A 20 -8.875 10.146 12.069 1.00 88.15 N
|
||||
ATOM 170 N LEU A 21 -5.444 4.518 7.462 1.00 86.41 N
|
||||
ATOM 171 CA LEU A 21 -5.662 3.611 6.341 1.00 86.41 C
|
||||
ATOM 172 C LEU A 21 -4.974 2.271 6.583 1.00 86.41 C
|
||||
ATOM 173 CB LEU A 21 -5.148 4.234 5.040 1.00 86.41 C
|
||||
ATOM 174 O LEU A 21 -5.577 1.214 6.385 1.00 86.41 O
|
||||
ATOM 175 CG LEU A 21 -5.364 3.417 3.765 1.00 86.41 C
|
||||
ATOM 176 CD1 LEU A 21 -6.842 3.400 3.391 1.00 86.41 C
|
||||
ATOM 177 CD2 LEU A 21 -4.524 3.976 2.622 1.00 86.41 C
|
||||
ATOM 178 N VAL A 22 -3.737 2.304 6.914 1.00 87.19 N
|
||||
ATOM 179 CA VAL A 22 -2.953 1.109 7.205 1.00 87.19 C
|
||||
ATOM 180 C VAL A 22 -3.627 0.307 8.316 1.00 87.19 C
|
||||
ATOM 181 CB VAL A 22 -1.504 1.464 7.609 1.00 87.19 C
|
||||
ATOM 182 O VAL A 22 -3.719 -0.921 8.236 1.00 87.19 O
|
||||
ATOM 183 CG1 VAL A 22 -0.752 0.218 8.073 1.00 87.19 C
|
||||
ATOM 184 CG2 VAL A 22 -0.774 2.130 6.444 1.00 87.19 C
|
||||
ATOM 185 N GLU A 23 -4.070 0.928 9.305 1.00 88.34 N
|
||||
ATOM 186 CA GLU A 23 -4.790 0.285 10.400 1.00 88.34 C
|
||||
ATOM 187 C GLU A 23 -6.050 -0.414 9.897 1.00 88.34 C
|
||||
ATOM 188 CB GLU A 23 -5.151 1.308 11.480 1.00 88.34 C
|
||||
ATOM 189 O GLU A 23 -6.364 -1.525 10.328 1.00 88.34 O
|
||||
ATOM 190 CG GLU A 23 -3.959 1.792 12.292 1.00 88.34 C
|
||||
ATOM 191 CD GLU A 23 -4.356 2.595 13.521 1.00 88.34 C
|
||||
ATOM 192 OE1 GLU A 23 -4.486 2.004 14.616 1.00 88.34 O
|
||||
ATOM 193 OE2 GLU A 23 -4.539 3.826 13.386 1.00 88.34 O
|
||||
ATOM 194 N GLU A 24 -6.671 0.256 9.129 1.00 87.82 N
|
||||
ATOM 195 CA GLU A 24 -7.883 -0.315 8.549 1.00 87.82 C
|
||||
ATOM 196 C GLU A 24 -7.569 -1.568 7.737 1.00 87.82 C
|
||||
ATOM 197 CB GLU A 24 -8.595 0.717 7.670 1.00 87.82 C
|
||||
ATOM 198 O GLU A 24 -8.334 -2.535 7.758 1.00 87.82 O
|
||||
ATOM 199 CG GLU A 24 -9.372 1.763 8.456 1.00 87.82 C
|
||||
ATOM 200 CD GLU A 24 -10.598 1.200 9.157 1.00 87.82 C
|
||||
ATOM 201 OE1 GLU A 24 -10.544 0.974 10.387 1.00 87.82 O
|
||||
ATOM 202 OE2 GLU A 24 -11.621 0.982 8.469 1.00 87.82 O
|
||||
ATOM 203 N TRP A 25 -6.452 -1.421 6.925 1.00 87.98 N
|
||||
ATOM 204 CA TRP A 25 -6.008 -2.576 6.152 1.00 87.98 C
|
||||
ATOM 205 C TRP A 25 -5.804 -3.789 7.054 1.00 87.98 C
|
||||
ATOM 206 CB TRP A 25 -4.712 -2.256 5.403 1.00 87.98 C
|
||||
ATOM 207 O TRP A 25 -6.237 -4.895 6.724 1.00 87.98 O
|
||||
ATOM 208 CG TRP A 25 -4.867 -1.219 4.332 1.00 87.98 C
|
||||
ATOM 209 CD1 TRP A 25 -6.030 -0.819 3.734 1.00 87.98 C
|
||||
ATOM 210 CD2 TRP A 25 -3.820 -0.453 3.727 1.00 87.98 C
|
||||
ATOM 211 CE2 TRP A 25 -4.422 0.394 2.770 1.00 87.98 C
|
||||
ATOM 212 CE3 TRP A 25 -2.431 -0.399 3.902 1.00 87.98 C
|
||||
ATOM 213 NE1 TRP A 25 -5.769 0.151 2.794 1.00 87.98 N
|
||||
ATOM 214 CH2 TRP A 25 -2.324 1.317 2.182 1.00 87.98 C
|
||||
ATOM 215 CZ2 TRP A 25 -3.681 1.285 1.990 1.00 87.98 C
|
||||
ATOM 216 CZ3 TRP A 25 -1.695 0.488 3.125 1.00 87.98 C
|
||||
ATOM 217 N ILE A 26 -5.164 -3.521 8.121 1.00 86.80 N
|
||||
ATOM 218 CA ILE A 26 -4.842 -4.578 9.074 1.00 86.80 C
|
||||
ATOM 219 C ILE A 26 -6.123 -5.095 9.724 1.00 86.80 C
|
||||
ATOM 220 CB ILE A 26 -3.855 -4.082 10.155 1.00 86.80 C
|
||||
ATOM 221 O ILE A 26 -6.287 -6.302 9.913 1.00 86.80 O
|
||||
ATOM 222 CG1 ILE A 26 -2.511 -3.706 9.519 1.00 86.80 C
|
||||
ATOM 223 CG2 ILE A 26 -3.667 -5.144 11.243 1.00 86.80 C
|
||||
ATOM 224 CD1 ILE A 26 -1.549 -3.010 10.471 1.00 86.80 C
|
||||
ATOM 225 N LYS A 27 -7.085 -4.130 10.074 1.00 88.23 N
|
||||
ATOM 226 CA LYS A 27 -8.358 -4.482 10.697 1.00 88.23 C
|
||||
ATOM 227 C LYS A 27 -9.231 -5.292 9.743 1.00 88.23 C
|
||||
ATOM 228 CB LYS A 27 -9.101 -3.224 11.147 1.00 88.23 C
|
||||
ATOM 229 O LYS A 27 -9.857 -6.273 10.148 1.00 88.23 O
|
||||
ATOM 230 CG LYS A 27 -10.280 -3.498 12.070 1.00 88.23 C
|
||||
ATOM 231 CD LYS A 27 -10.890 -2.206 12.597 1.00 88.23 C
|
||||
ATOM 232 CE LYS A 27 -12.096 -2.477 13.486 1.00 88.23 C
|
||||
ATOM 233 NZ LYS A 27 -12.726 -1.212 13.967 1.00 88.23 N
|
||||
ATOM 234 N SER A 28 -9.257 -4.866 8.486 1.00 88.60 N
|
||||
ATOM 235 CA SER A 28 -10.097 -5.462 7.453 1.00 88.60 C
|
||||
ATOM 236 C SER A 28 -9.499 -6.767 6.939 1.00 88.60 C
|
||||
ATOM 237 CB SER A 28 -10.292 -4.488 6.290 1.00 88.60 C
|
||||
ATOM 238 O SER A 28 -10.208 -7.598 6.366 1.00 88.60 O
|
||||
ATOM 239 OG SER A 28 -11.021 -3.347 6.707 1.00 88.60 O
|
||||
ATOM 240 N LYS A 29 -8.274 -7.060 7.266 1.00 87.22 N
|
||||
ATOM 241 CA LYS A 29 -7.552 -8.279 6.911 1.00 87.22 C
|
||||
ATOM 242 C LYS A 29 -7.546 -8.493 5.400 1.00 87.22 C
|
||||
ATOM 243 CB LYS A 29 -8.169 -9.491 7.609 1.00 87.22 C
|
||||
ATOM 244 O LYS A 29 -7.336 -9.612 4.927 1.00 87.22 O
|
||||
ATOM 245 CG LYS A 29 -7.958 -9.511 9.116 1.00 87.22 C
|
||||
ATOM 246 CD LYS A 29 -8.508 -10.787 9.741 1.00 87.22 C
|
||||
ATOM 247 CE LYS A 29 -8.322 -10.795 11.252 1.00 87.22 C
|
||||
ATOM 248 NZ LYS A 29 -8.836 -12.056 11.866 1.00 87.22 N
|
||||
ATOM 249 N GLU A 30 -7.995 -7.561 4.711 1.00 90.12 N
|
||||
ATOM 250 CA GLU A 30 -7.955 -7.620 3.253 1.00 90.12 C
|
||||
ATOM 251 C GLU A 30 -7.715 -6.239 2.650 1.00 90.12 C
|
||||
ATOM 252 CB GLU A 30 -9.254 -8.215 2.703 1.00 90.12 C
|
||||
ATOM 253 O GLU A 30 -8.286 -5.248 3.110 1.00 90.12 O
|
||||
ATOM 254 CG GLU A 30 -9.273 -8.357 1.188 1.00 90.12 C
|
||||
ATOM 255 CD GLU A 30 -10.542 -9.008 0.662 1.00 90.12 C
|
||||
ATOM 256 OE1 GLU A 30 -11.585 -8.321 0.575 1.00 90.12 O
|
||||
ATOM 257 OE2 GLU A 30 -10.494 -10.215 0.335 1.00 90.12 O
|
||||
ATOM 258 N VAL A 31 -6.835 -6.090 1.610 1.00 86.60 N
|
||||
ATOM 259 CA VAL A 31 -6.583 -4.828 0.922 1.00 86.60 C
|
||||
ATOM 260 C VAL A 31 -6.313 -5.090 -0.558 1.00 86.60 C
|
||||
ATOM 261 CB VAL A 31 -5.397 -4.064 1.553 1.00 86.60 C
|
||||
ATOM 262 O VAL A 31 -5.684 -6.090 -0.912 1.00 86.60 O
|
||||
ATOM 263 CG1 VAL A 31 -4.102 -4.859 1.404 1.00 86.60 C
|
||||
ATOM 264 CG2 VAL A 31 -5.255 -2.682 0.919 1.00 86.60 C
|
||||
ATOM 265 N THR A 32 -6.886 -4.281 -1.455 1.00 86.60 N
|
||||
ATOM 266 CA THR A 32 -6.648 -4.386 -2.890 1.00 86.60 C
|
||||
ATOM 267 C THR A 32 -5.875 -3.173 -3.400 1.00 86.60 C
|
||||
ATOM 268 CB THR A 32 -7.971 -4.518 -3.667 1.00 86.60 C
|
||||
ATOM 269 O THR A 32 -6.311 -2.033 -3.224 1.00 86.60 O
|
||||
ATOM 270 CG2 THR A 32 -7.715 -4.710 -5.159 1.00 86.60 C
|
||||
ATOM 271 OG1 THR A 32 -8.700 -5.647 -3.170 1.00 86.60 O
|
||||
ATOM 272 N PHE A 33 -4.627 -3.379 -3.960 1.00 85.17 N
|
||||
ATOM 273 CA PHE A 33 -3.825 -2.315 -4.552 1.00 85.17 C
|
||||
ATOM 274 C PHE A 33 -4.096 -2.201 -6.048 1.00 85.17 C
|
||||
ATOM 275 CB PHE A 33 -2.333 -2.565 -4.307 1.00 85.17 C
|
||||
ATOM 276 O PHE A 33 -4.048 -3.198 -6.771 1.00 85.17 O
|
||||
ATOM 277 CG PHE A 33 -1.918 -2.397 -2.870 1.00 85.17 C
|
||||
ATOM 278 CD1 PHE A 33 -1.696 -1.132 -2.340 1.00 85.17 C
|
||||
ATOM 279 CD2 PHE A 33 -1.750 -3.504 -2.050 1.00 85.17 C
|
||||
ATOM 280 CE1 PHE A 33 -1.312 -0.973 -1.011 1.00 85.17 C
|
||||
ATOM 281 CE2 PHE A 33 -1.366 -3.354 -0.720 1.00 85.17 C
|
||||
ATOM 282 CZ PHE A 33 -1.146 -2.087 -0.203 1.00 85.17 C
|
||||
ATOM 283 N VAL A 34 -4.488 -1.033 -6.377 1.00 79.71 N
|
||||
ATOM 284 CA VAL A 34 -4.738 -0.771 -7.791 1.00 79.71 C
|
||||
ATOM 285 C VAL A 34 -3.582 0.033 -8.380 1.00 79.71 C
|
||||
ATOM 286 CB VAL A 34 -6.072 -0.020 -8.002 1.00 79.71 C
|
||||
ATOM 287 O VAL A 34 -3.285 1.137 -7.917 1.00 79.71 O
|
||||
ATOM 288 CG1 VAL A 34 -6.363 0.156 -9.491 1.00 79.71 C
|
||||
ATOM 289 CG2 VAL A 34 -7.216 -0.762 -7.314 1.00 79.71 C
|
||||
ATOM 290 N ILE A 35 -2.823 -0.596 -9.337 1.00 77.12 N
|
||||
ATOM 291 CA ILE A 35 -1.721 0.099 -9.993 1.00 77.12 C
|
||||
ATOM 292 C ILE A 35 -2.004 0.218 -11.489 1.00 77.12 C
|
||||
ATOM 293 CB ILE A 35 -0.376 -0.624 -9.757 1.00 77.12 C
|
||||
ATOM 294 O ILE A 35 -2.768 -0.572 -12.047 1.00 77.12 O
|
||||
ATOM 295 CG1 ILE A 35 -0.441 -2.059 -10.291 1.00 77.12 C
|
||||
ATOM 296 CG2 ILE A 35 -0.007 -0.608 -8.271 1.00 77.12 C
|
||||
ATOM 297 CD1 ILE A 35 0.916 -2.740 -10.402 1.00 77.12 C
|
||||
ATOM 298 N SER A 36 -1.599 1.325 -11.947 1.00 72.93 N
|
||||
ATOM 299 CA SER A 36 -1.731 1.517 -13.387 1.00 72.93 C
|
||||
ATOM 300 C SER A 36 -0.484 1.040 -14.125 1.00 72.93 C
|
||||
ATOM 301 CB SER A 36 -1.994 2.988 -13.711 1.00 72.93 C
|
||||
ATOM 302 O SER A 36 0.613 1.040 -13.564 1.00 72.93 O
|
||||
ATOM 303 OG SER A 36 -1.967 3.208 -15.110 1.00 72.93 O
|
||||
ATOM 304 N SER A 37 -0.670 0.403 -15.236 1.00 69.39 N
|
||||
ATOM 305 CA SER A 37 0.426 -0.073 -16.073 1.00 69.39 C
|
||||
ATOM 306 C SER A 37 1.372 1.064 -16.443 1.00 69.39 C
|
||||
ATOM 307 CB SER A 37 -0.115 -0.731 -17.343 1.00 69.39 C
|
||||
ATOM 308 O SER A 37 2.505 0.823 -16.867 1.00 69.39 O
|
||||
ATOM 309 OG SER A 37 -1.045 0.119 -17.992 1.00 69.39 O
|
||||
ATOM 310 N ALA A 38 0.862 2.297 -16.248 1.00 67.39 N
|
||||
ATOM 311 CA ALA A 38 1.656 3.492 -16.525 1.00 67.39 C
|
||||
ATOM 312 C ALA A 38 2.561 3.834 -15.344 1.00 67.39 C
|
||||
ATOM 313 CB ALA A 38 0.745 4.672 -16.853 1.00 67.39 C
|
||||
ATOM 314 O ALA A 38 3.386 4.746 -15.431 1.00 67.39 O
|
||||
ATOM 315 N ASP A 39 2.279 3.071 -14.251 1.00 72.75 N
|
||||
ATOM 316 CA ASP A 39 3.057 3.298 -13.037 1.00 72.75 C
|
||||
ATOM 317 C ASP A 39 4.501 2.833 -13.215 1.00 72.75 C
|
||||
ATOM 318 CB ASP A 39 2.417 2.580 -11.847 1.00 72.75 C
|
||||
ATOM 319 O ASP A 39 4.780 1.959 -14.039 1.00 72.75 O
|
||||
ATOM 320 CG ASP A 39 1.183 3.292 -11.320 1.00 72.75 C
|
||||
ATOM 321 OD1 ASP A 39 1.293 4.454 -10.874 1.00 72.75 O
|
||||
ATOM 322 OD2 ASP A 39 0.091 2.684 -11.348 1.00 72.75 O
|
||||
ATOM 323 N SER A 40 5.475 3.562 -12.768 1.00 72.73 N
|
||||
ATOM 324 CA SER A 40 6.908 3.286 -12.803 1.00 72.73 C
|
||||
ATOM 325 C SER A 40 7.256 2.065 -11.958 1.00 72.73 C
|
||||
ATOM 326 CB SER A 40 7.700 4.499 -12.314 1.00 72.73 C
|
||||
ATOM 327 O SER A 40 6.491 1.677 -11.073 1.00 72.73 O
|
||||
ATOM 328 OG SER A 40 7.410 5.640 -13.101 1.00 72.73 O
|
||||
ATOM 329 N GLU A 41 8.265 1.200 -12.472 1.00 83.34 N
|
||||
ATOM 330 CA GLU A 41 8.802 0.051 -11.749 1.00 83.34 C
|
||||
ATOM 331 C GLU A 41 8.950 0.356 -10.261 1.00 83.34 C
|
||||
ATOM 332 CB GLU A 41 10.152 -0.371 -12.336 1.00 83.34 C
|
||||
ATOM 333 O GLU A 41 8.722 -0.515 -9.418 1.00 83.34 O
|
||||
ATOM 334 CG GLU A 41 10.046 -1.058 -13.689 1.00 83.34 C
|
||||
ATOM 335 CD GLU A 41 11.377 -1.586 -14.200 1.00 83.34 C
|
||||
ATOM 336 OE1 GLU A 41 11.690 -2.775 -13.962 1.00 83.34 O
|
||||
ATOM 337 OE2 GLU A 41 12.113 -0.805 -14.842 1.00 83.34 O
|
||||
ATOM 338 N GLU A 42 9.164 1.541 -9.996 1.00 85.29 N
|
||||
ATOM 339 CA GLU A 42 9.324 1.965 -8.608 1.00 85.29 C
|
||||
ATOM 340 C GLU A 42 8.026 1.793 -7.825 1.00 85.29 C
|
||||
ATOM 341 CB GLU A 42 9.789 3.422 -8.541 1.00 85.29 C
|
||||
ATOM 342 O GLU A 42 8.031 1.257 -6.715 1.00 85.29 O
|
||||
ATOM 343 CG GLU A 42 10.241 3.861 -7.156 1.00 85.29 C
|
||||
ATOM 344 CD GLU A 42 11.177 5.059 -7.182 1.00 85.29 C
|
||||
ATOM 345 OE1 GLU A 42 10.689 6.208 -7.276 1.00 85.29 O
|
||||
ATOM 346 OE2 GLU A 42 12.408 4.847 -7.108 1.00 85.29 O
|
||||
ATOM 347 N ILE A 43 6.916 2.343 -8.302 1.00 82.81 N
|
||||
ATOM 348 CA ILE A 43 5.610 2.254 -7.658 1.00 82.81 C
|
||||
ATOM 349 C ILE A 43 5.202 0.789 -7.519 1.00 82.81 C
|
||||
ATOM 350 CB ILE A 43 4.537 3.036 -8.447 1.00 82.81 C
|
||||
ATOM 351 O ILE A 43 4.717 0.370 -6.465 1.00 82.81 O
|
||||
ATOM 352 CG1 ILE A 43 4.822 4.541 -8.387 1.00 82.81 C
|
||||
ATOM 353 CG2 ILE A 43 3.137 2.722 -7.911 1.00 82.81 C
|
||||
ATOM 354 CD1 ILE A 43 3.876 5.384 -9.232 1.00 82.81 C
|
||||
ATOM 355 N LYS A 44 5.549 -0.013 -8.535 1.00 83.23 N
|
||||
ATOM 356 CA LYS A 44 5.294 -1.450 -8.502 1.00 83.23 C
|
||||
ATOM 357 C LYS A 44 6.064 -2.118 -7.366 1.00 83.23 C
|
||||
ATOM 358 CB LYS A 44 5.667 -2.093 -9.838 1.00 83.23 C
|
||||
ATOM 359 O LYS A 44 5.511 -2.944 -6.636 1.00 83.23 O
|
||||
ATOM 360 CG LYS A 44 4.624 -1.902 -10.929 1.00 83.23 C
|
||||
ATOM 361 CD LYS A 44 4.985 -2.679 -12.189 1.00 83.23 C
|
||||
ATOM 362 CE LYS A 44 4.004 -2.398 -13.320 1.00 83.23 C
|
||||
ATOM 363 NZ LYS A 44 4.334 -3.183 -14.547 1.00 83.23 N
|
||||
ATOM 364 N LYS A 45 7.296 -1.791 -7.304 1.00 88.48 N
|
||||
ATOM 365 CA LYS A 45 8.146 -2.345 -6.255 1.00 88.48 C
|
||||
ATOM 366 C LYS A 45 7.628 -1.967 -4.870 1.00 88.48 C
|
||||
ATOM 367 CB LYS A 45 9.589 -1.867 -6.424 1.00 88.48 C
|
||||
ATOM 368 O LYS A 45 7.601 -2.800 -3.962 1.00 88.48 O
|
||||
ATOM 369 CG LYS A 45 10.363 -2.605 -7.506 1.00 88.48 C
|
||||
ATOM 370 CD LYS A 45 11.819 -2.159 -7.554 1.00 88.48 C
|
||||
ATOM 371 CE LYS A 45 12.582 -2.860 -8.670 1.00 88.48 C
|
||||
ATOM 372 NZ LYS A 45 14.014 -2.437 -8.712 1.00 88.48 N
|
||||
ATOM 373 N LEU A 46 7.267 -0.760 -4.707 1.00 90.20 N
|
||||
ATOM 374 CA LEU A 46 6.764 -0.277 -3.426 1.00 90.20 C
|
||||
ATOM 375 C LEU A 46 5.478 -1.001 -3.040 1.00 90.20 C
|
||||
ATOM 376 CB LEU A 46 6.516 1.233 -3.481 1.00 90.20 C
|
||||
ATOM 377 O LEU A 46 5.308 -1.401 -1.886 1.00 90.20 O
|
||||
ATOM 378 CG LEU A 46 7.756 2.126 -3.413 1.00 90.20 C
|
||||
ATOM 379 CD1 LEU A 46 7.391 3.567 -3.755 1.00 90.20 C
|
||||
ATOM 380 CD2 LEU A 46 8.398 2.045 -2.033 1.00 90.20 C
|
||||
ATOM 381 N VAL A 47 4.634 -1.055 -3.956 1.00 87.72 N
|
||||
ATOM 382 CA VAL A 47 3.355 -1.724 -3.743 1.00 87.72 C
|
||||
ATOM 383 C VAL A 47 3.592 -3.184 -3.363 1.00 87.72 C
|
||||
ATOM 384 CB VAL A 47 2.454 -1.638 -4.995 1.00 87.72 C
|
||||
ATOM 385 O VAL A 47 2.953 -3.705 -2.446 1.00 87.72 O
|
||||
ATOM 386 CG1 VAL A 47 1.201 -2.494 -4.819 1.00 87.72 C
|
||||
ATOM 387 CG2 VAL A 47 2.077 -0.186 -5.282 1.00 87.72 C
|
||||
ATOM 388 N GLU A 48 4.453 -3.832 -4.059 1.00 89.12 N
|
||||
ATOM 389 CA GLU A 48 4.817 -5.214 -3.761 1.00 89.12 C
|
||||
ATOM 390 C GLU A 48 5.366 -5.347 -2.344 1.00 89.12 C
|
||||
ATOM 391 CB GLU A 48 5.843 -5.729 -4.774 1.00 89.12 C
|
||||
ATOM 392 O GLU A 48 5.015 -6.283 -1.622 1.00 89.12 O
|
||||
ATOM 393 CG GLU A 48 5.260 -6.014 -6.150 1.00 89.12 C
|
||||
ATOM 394 CD GLU A 48 6.211 -6.777 -7.058 1.00 89.12 C
|
||||
ATOM 395 OE1 GLU A 48 6.128 -8.025 -7.112 1.00 89.12 O
|
||||
ATOM 396 OE2 GLU A 48 7.046 -6.122 -7.721 1.00 89.12 O
|
||||
ATOM 397 N GLU A 49 6.263 -4.525 -2.078 1.00 92.03 N
|
||||
ATOM 398 CA GLU A 49 6.825 -4.532 -0.731 1.00 92.03 C
|
||||
ATOM 399 C GLU A 49 5.738 -4.339 0.322 1.00 92.03 C
|
||||
ATOM 400 CB GLU A 49 7.894 -3.445 -0.589 1.00 92.03 C
|
||||
ATOM 401 O GLU A 49 5.730 -5.026 1.346 1.00 92.03 O
|
||||
ATOM 402 CG GLU A 49 9.203 -3.773 -1.292 1.00 92.03 C
|
||||
ATOM 403 CD GLU A 49 10.340 -2.840 -0.909 1.00 92.03 C
|
||||
ATOM 404 OE1 GLU A 49 10.970 -3.054 0.152 1.00 92.03 O
|
||||
ATOM 405 OE2 GLU A 49 10.603 -1.886 -1.675 1.00 92.03 O
|
||||
ATOM 406 N ASN A 50 4.950 -3.304 0.106 1.00 90.05 N
|
||||
ATOM 407 CA ASN A 50 3.830 -3.068 1.010 1.00 90.05 C
|
||||
ATOM 408 C ASN A 50 2.960 -4.313 1.161 1.00 90.05 C
|
||||
ATOM 409 CB ASN A 50 2.987 -1.887 0.524 1.00 90.05 C
|
||||
ATOM 410 O ASN A 50 2.539 -4.651 2.269 1.00 90.05 O
|
||||
ATOM 411 CG ASN A 50 3.539 -0.550 0.978 1.00 90.05 C
|
||||
ATOM 412 ND2 ASN A 50 4.277 0.116 0.098 1.00 90.05 N
|
||||
ATOM 413 OD1 ASN A 50 3.305 -0.120 2.110 1.00 90.05 O
|
||||
ATOM 414 N ALA A 51 2.704 -4.904 0.020 1.00 89.43 N
|
||||
ATOM 415 CA ALA A 51 1.897 -6.121 -0.004 1.00 89.43 C
|
||||
ATOM 416 C ALA A 51 2.538 -7.220 0.839 1.00 89.43 C
|
||||
ATOM 417 CB ALA A 51 1.701 -6.602 -1.439 1.00 89.43 C
|
||||
ATOM 418 O ALA A 51 1.849 -7.920 1.585 1.00 89.43 O
|
||||
ATOM 419 N GLU A 52 3.815 -7.414 0.696 1.00 91.12 N
|
||||
ATOM 420 CA GLU A 52 4.547 -8.437 1.437 1.00 91.12 C
|
||||
ATOM 421 C GLU A 52 4.436 -8.213 2.942 1.00 91.12 C
|
||||
ATOM 422 CB GLU A 52 6.018 -8.457 1.015 1.00 91.12 C
|
||||
ATOM 423 O GLU A 52 4.209 -9.158 3.700 1.00 91.12 O
|
||||
ATOM 424 CG GLU A 52 6.248 -9.005 -0.387 1.00 91.12 C
|
||||
ATOM 425 CD GLU A 52 7.720 -9.166 -0.733 1.00 91.12 C
|
||||
ATOM 426 OE1 GLU A 52 8.313 -10.215 -0.392 1.00 91.12 O
|
||||
ATOM 427 OE2 GLU A 52 8.285 -8.235 -1.350 1.00 91.12 O
|
||||
ATOM 428 N ILE A 53 4.609 -7.008 3.402 1.00 91.89 N
|
||||
ATOM 429 CA ILE A 53 4.531 -6.669 4.819 1.00 91.89 C
|
||||
ATOM 430 C ILE A 53 3.112 -6.910 5.330 1.00 91.89 C
|
||||
ATOM 431 CB ILE A 53 4.950 -5.204 5.074 1.00 91.89 C
|
||||
ATOM 432 O ILE A 53 2.921 -7.486 6.403 1.00 91.89 O
|
||||
ATOM 433 CG1 ILE A 53 6.419 -4.994 4.686 1.00 91.89 C
|
||||
ATOM 434 CG2 ILE A 53 4.710 -4.819 6.536 1.00 91.89 C
|
||||
ATOM 435 CD1 ILE A 53 6.878 -3.544 4.762 1.00 91.89 C
|
||||
ATOM 436 N LEU A 54 2.220 -6.422 4.598 1.00 90.60 N
|
||||
ATOM 437 CA LEU A 54 0.817 -6.592 4.960 1.00 90.60 C
|
||||
ATOM 438 C LEU A 54 0.454 -8.071 5.048 1.00 90.60 C
|
||||
ATOM 439 CB LEU A 54 -0.087 -5.892 3.942 1.00 90.60 C
|
||||
ATOM 440 O LEU A 54 -0.274 -8.482 5.955 1.00 90.60 O
|
||||
ATOM 441 CG LEU A 54 -0.161 -4.367 4.036 1.00 90.60 C
|
||||
ATOM 442 CD1 LEU A 54 -0.837 -3.792 2.797 1.00 90.60 C
|
||||
ATOM 443 CD2 LEU A 54 -0.900 -3.944 5.301 1.00 90.60 C
|
||||
ATOM 444 N GLU A 55 0.909 -8.858 4.086 1.00 90.94 N
|
||||
ATOM 445 CA GLU A 55 0.715 -10.305 4.103 1.00 90.94 C
|
||||
ATOM 446 C GLU A 55 1.303 -10.926 5.367 1.00 90.94 C
|
||||
ATOM 447 CB GLU A 55 1.342 -10.946 2.862 1.00 90.94 C
|
||||
ATOM 448 O GLU A 55 0.712 -11.837 5.950 1.00 90.94 O
|
||||
ATOM 449 CG GLU A 55 0.549 -10.716 1.584 1.00 90.94 C
|
||||
ATOM 450 CD GLU A 55 0.996 -11.603 0.432 1.00 90.94 C
|
||||
ATOM 451 OE1 GLU A 55 0.436 -12.710 0.266 1.00 90.94 O
|
||||
ATOM 452 OE2 GLU A 55 1.915 -11.187 -0.308 1.00 90.94 O
|
||||
ATOM 453 N LYS A 56 2.477 -10.439 5.689 1.00 90.58 N
|
||||
ATOM 454 CA LYS A 56 3.128 -10.914 6.907 1.00 90.58 C
|
||||
ATOM 455 C LYS A 56 2.303 -10.564 8.143 1.00 90.58 C
|
||||
ATOM 456 CB LYS A 56 4.533 -10.324 7.031 1.00 90.58 C
|
||||
ATOM 457 O LYS A 56 2.287 -11.317 9.119 1.00 90.58 O
|
||||
ATOM 458 CG LYS A 56 5.551 -10.945 6.085 1.00 90.58 C
|
||||
ATOM 459 CD LYS A 56 6.949 -10.393 6.327 1.00 90.58 C
|
||||
ATOM 460 CE LYS A 56 7.967 -11.008 5.376 1.00 90.58 C
|
||||
ATOM 461 NZ LYS A 56 9.350 -10.516 5.651 1.00 90.58 N
|
||||
ATOM 462 N LEU A 57 1.666 -9.472 8.081 1.00 89.28 N
|
||||
ATOM 463 CA LEU A 57 0.843 -8.979 9.180 1.00 89.28 C
|
||||
ATOM 464 C LEU A 57 -0.522 -9.661 9.185 1.00 89.28 C
|
||||
ATOM 465 CB LEU A 57 0.668 -7.462 9.080 1.00 89.28 C
|
||||
ATOM 466 O LEU A 57 -1.332 -9.430 10.085 1.00 89.28 O
|
||||
ATOM 467 CG LEU A 57 1.906 -6.615 9.381 1.00 89.28 C
|
||||
ATOM 468 CD1 LEU A 57 1.651 -5.157 9.016 1.00 89.28 C
|
||||
ATOM 469 CD2 LEU A 57 2.298 -6.744 10.849 1.00 89.28 C
|
||||
ATOM 470 N GLY A 58 -0.801 -10.562 8.254 1.00 89.24 N
|
||||
ATOM 471 CA GLY A 58 -2.043 -11.316 8.202 1.00 89.24 C
|
||||
ATOM 472 C GLY A 58 -3.109 -10.651 7.352 1.00 89.24 C
|
||||
ATOM 473 O GLY A 58 -4.304 -10.868 7.563 1.00 89.24 O
|
||||
ATOM 474 N VAL A 59 -2.742 -9.745 6.559 1.00 90.59 N
|
||||
ATOM 475 CA VAL A 59 -3.658 -9.015 5.689 1.00 90.59 C
|
||||
ATOM 476 C VAL A 59 -3.626 -9.615 4.285 1.00 90.59 C
|
||||
ATOM 477 CB VAL A 59 -3.312 -7.511 5.634 1.00 90.59 C
|
||||
ATOM 478 O VAL A 59 -2.551 -9.854 3.730 1.00 90.59 O
|
||||
ATOM 479 CG1 VAL A 59 -4.305 -6.760 4.750 1.00 90.59 C
|
||||
ATOM 480 CG2 VAL A 59 -3.290 -6.917 7.042 1.00 90.59 C
|
||||
ATOM 481 N LYS A 60 -4.796 -10.038 3.669 1.00 91.31 N
|
||||
ATOM 482 CA LYS A 60 -4.890 -10.525 2.295 1.00 91.31 C
|
||||
ATOM 483 C LYS A 60 -4.751 -9.380 1.296 1.00 91.31 C
|
||||
ATOM 484 CB LYS A 60 -6.215 -11.256 2.074 1.00 91.31 C
|
||||
ATOM 485 O LYS A 60 -5.554 -8.444 1.300 1.00 91.31 O
|
||||
ATOM 486 CG LYS A 60 -6.280 -12.039 0.771 1.00 91.31 C
|
||||
ATOM 487 CD LYS A 60 -7.562 -12.856 0.673 1.00 91.31 C
|
||||
ATOM 488 CE LYS A 60 -7.618 -13.657 -0.621 1.00 91.31 C
|
||||
ATOM 489 NZ LYS A 60 -8.859 -14.483 -0.707 1.00 91.31 N
|
||||
ATOM 490 N VAL A 61 -3.640 -9.388 0.542 1.00 90.50 N
|
||||
ATOM 491 CA VAL A 61 -3.325 -8.295 -0.373 1.00 90.50 C
|
||||
ATOM 492 C VAL A 61 -3.627 -8.719 -1.808 1.00 90.50 C
|
||||
ATOM 493 CB VAL A 61 -1.849 -7.856 -0.246 1.00 90.50 C
|
||||
ATOM 494 O VAL A 61 -3.177 -9.776 -2.258 1.00 90.50 O
|
||||
ATOM 495 CG1 VAL A 61 -1.548 -6.696 -1.192 1.00 90.50 C
|
||||
ATOM 496 CG2 VAL A 61 -1.531 -7.470 1.197 1.00 90.50 C
|
||||
ATOM 497 N LYS A 62 -4.464 -7.942 -2.568 1.00 89.89 N
|
||||
ATOM 498 CA LYS A 62 -4.755 -8.135 -3.986 1.00 89.89 C
|
||||
ATOM 499 C LYS A 62 -4.271 -6.948 -4.813 1.00 89.89 C
|
||||
ATOM 500 CB LYS A 62 -6.254 -8.348 -4.202 1.00 89.89 C
|
||||
ATOM 501 O LYS A 62 -4.598 -5.799 -4.510 1.00 89.89 O
|
||||
ATOM 502 CG LYS A 62 -6.615 -8.835 -5.598 1.00 89.89 C
|
||||
ATOM 503 CD LYS A 62 -8.100 -9.156 -5.711 1.00 89.89 C
|
||||
ATOM 504 CE LYS A 62 -8.454 -9.686 -7.094 1.00 89.89 C
|
||||
ATOM 505 NZ LYS A 62 -9.906 -10.018 -7.205 1.00 89.89 N
|
||||
ATOM 506 N VAL A 63 -3.369 -7.174 -5.795 1.00 85.66 N
|
||||
ATOM 507 CA VAL A 63 -2.847 -6.112 -6.649 1.00 85.66 C
|
||||
ATOM 508 C VAL A 63 -3.490 -6.198 -8.032 1.00 85.66 C
|
||||
ATOM 509 CB VAL A 63 -1.309 -6.185 -6.772 1.00 85.66 C
|
||||
ATOM 510 O VAL A 63 -3.359 -7.211 -8.723 1.00 85.66 O
|
||||
ATOM 511 CG1 VAL A 63 -0.779 -5.034 -7.625 1.00 85.66 C
|
||||
ATOM 512 CG2 VAL A 63 -0.663 -6.171 -5.388 1.00 85.66 C
|
||||
ATOM 513 N VAL A 64 -4.304 -5.230 -8.309 1.00 83.17 N
|
||||
ATOM 514 CA VAL A 64 -5.001 -5.174 -9.589 1.00 83.17 C
|
||||
ATOM 515 C VAL A 64 -4.339 -4.137 -10.494 1.00 83.17 C
|
||||
ATOM 516 CB VAL A 64 -6.499 -4.843 -9.406 1.00 83.17 C
|
||||
ATOM 517 O VAL A 64 -4.094 -3.004 -10.073 1.00 83.17 O
|
||||
ATOM 518 CG1 VAL A 64 -7.221 -4.843 -10.753 1.00 83.17 C
|
||||
ATOM 519 CG2 VAL A 64 -7.152 -5.836 -8.447 1.00 83.17 C
|
||||
ATOM 520 N GLU A 65 -3.914 -4.576 -11.655 1.00 82.38 N
|
||||
ATOM 521 CA GLU A 65 -3.300 -3.697 -12.646 1.00 82.38 C
|
||||
ATOM 522 C GLU A 65 -4.341 -3.154 -13.621 1.00 82.38 C
|
||||
ATOM 523 CB GLU A 65 -2.198 -4.434 -13.410 1.00 82.38 C
|
||||
ATOM 524 O GLU A 65 -5.007 -3.922 -14.318 1.00 82.38 O
|
||||
ATOM 525 CG GLU A 65 -1.357 -3.531 -14.300 1.00 82.38 C
|
||||
ATOM 526 CD GLU A 65 -0.228 -4.266 -15.005 1.00 82.38 C
|
||||
ATOM 527 OE1 GLU A 65 -0.445 -4.784 -16.124 1.00 82.38 O
|
||||
ATOM 528 OE2 GLU A 65 0.884 -4.325 -14.433 1.00 82.38 O
|
||||
ATOM 529 N LEU A 66 -4.731 -1.848 -13.511 1.00 73.61 N
|
||||
ATOM 530 CA LEU A 66 -5.704 -1.232 -14.407 1.00 73.61 C
|
||||
ATOM 531 C LEU A 66 -5.031 -0.737 -15.682 1.00 73.61 C
|
||||
ATOM 532 CB LEU A 66 -6.417 -0.072 -13.708 1.00 73.61 C
|
||||
ATOM 533 O LEU A 66 -3.927 -0.189 -15.634 1.00 73.61 O
|
||||
ATOM 534 CG LEU A 66 -7.425 -0.450 -12.622 1.00 73.61 C
|
||||
ATOM 535 CD1 LEU A 66 -7.847 0.787 -11.836 1.00 73.61 C
|
||||
ATOM 536 CD2 LEU A 66 -8.638 -1.141 -13.234 1.00 73.61 C
|
||||
ATOM 537 N GLY A 67 -5.215 -1.540 -16.831 1.00 61.81 N
|
||||
ATOM 538 CA GLY A 67 -4.761 -1.145 -18.155 1.00 61.81 C
|
||||
ATOM 539 C GLY A 67 -5.505 0.056 -18.708 1.00 61.81 C
|
||||
ATOM 540 O GLY A 67 -6.738 0.065 -18.746 1.00 61.81 O
|
||||
ATOM 541 N GLY A 68 -5.090 1.390 -18.491 1.00 60.96 N
|
||||
ATOM 542 CA GLY A 68 -5.697 2.625 -18.962 1.00 60.96 C
|
||||
ATOM 543 C GLY A 68 -4.768 3.820 -18.865 1.00 60.96 C
|
||||
ATOM 544 O GLY A 68 -3.738 3.760 -18.191 1.00 60.96 O
|
||||
ATOM 545 N GLU A 69 -4.531 4.607 -19.986 1.00 63.19 N
|
||||
ATOM 546 CA GLU A 69 -3.769 5.840 -20.158 1.00 63.19 C
|
||||
ATOM 547 C GLU A 69 -3.863 6.725 -18.918 1.00 63.19 C
|
||||
ATOM 548 CB GLU A 69 -4.257 6.607 -21.389 1.00 63.19 C
|
||||
ATOM 549 O GLU A 69 -4.938 6.870 -18.332 1.00 63.19 O
|
||||
ATOM 550 CG GLU A 69 -3.142 7.015 -22.341 1.00 63.19 C
|
||||
ATOM 551 CD GLU A 69 -3.653 7.632 -23.634 1.00 63.19 C
|
||||
ATOM 552 OE1 GLU A 69 -3.936 8.852 -23.654 1.00 63.19 O
|
||||
ATOM 553 OE2 GLU A 69 -3.771 6.890 -24.634 1.00 63.19 O
|
||||
ATOM 554 N LEU A 70 -2.763 6.805 -18.127 1.00 62.85 N
|
||||
ATOM 555 CA LEU A 70 -2.656 7.713 -16.990 1.00 62.85 C
|
||||
ATOM 556 C LEU A 70 -3.013 9.139 -17.398 1.00 62.85 C
|
||||
ATOM 557 CB LEU A 70 -1.242 7.676 -16.406 1.00 62.85 C
|
||||
ATOM 558 O LEU A 70 -2.495 9.653 -18.391 1.00 62.85 O
|
||||
ATOM 559 CG LEU A 70 -0.896 6.460 -15.544 1.00 62.85 C
|
||||
ATOM 560 CD1 LEU A 70 0.611 6.230 -15.534 1.00 62.85 C
|
||||
ATOM 561 CD2 LEU A 70 -1.425 6.642 -14.126 1.00 62.85 C
|
||||
ATOM 562 N ASP A 71 -4.382 9.504 -17.115 1.00 67.78 N
|
||||
ATOM 563 CA ASP A 71 -4.779 10.889 -17.347 1.00 67.78 C
|
||||
ATOM 564 C ASP A 71 -3.796 11.859 -16.695 1.00 67.78 C
|
||||
ATOM 565 CB ASP A 71 -6.193 11.139 -16.819 1.00 67.78 C
|
||||
ATOM 566 O ASP A 71 -3.070 11.487 -15.770 1.00 67.78 O
|
||||
ATOM 567 CG ASP A 71 -6.996 12.083 -17.696 1.00 67.78 C
|
||||
ATOM 568 OD1 ASP A 71 -7.054 13.295 -17.394 1.00 67.78 O
|
||||
ATOM 569 OD2 ASP A 71 -7.578 11.611 -18.697 1.00 67.78 O
|
||||
ATOM 570 N GLU A 72 -3.069 12.841 -17.280 1.00 66.31 N
|
||||
ATOM 571 CA GLU A 72 -2.192 13.936 -16.876 1.00 66.31 C
|
||||
ATOM 572 C GLU A 72 -2.299 14.205 -15.378 1.00 66.31 C
|
||||
ATOM 573 CB GLU A 72 -2.521 15.207 -17.663 1.00 66.31 C
|
||||
ATOM 574 O GLU A 72 -1.296 14.487 -14.719 1.00 66.31 O
|
||||
ATOM 575 CG GLU A 72 -1.767 15.327 -18.980 1.00 66.31 C
|
||||
ATOM 576 CD GLU A 72 -2.109 16.590 -19.754 1.00 66.31 C
|
||||
ATOM 577 OE1 GLU A 72 -1.474 17.642 -19.511 1.00 66.31 O
|
||||
ATOM 578 OE2 GLU A 72 -3.020 16.529 -20.609 1.00 66.31 O
|
||||
ATOM 579 N LEU A 73 -3.365 13.942 -14.773 1.00 66.33 N
|
||||
ATOM 580 CA LEU A 73 -3.564 14.142 -13.342 1.00 66.33 C
|
||||
ATOM 581 C LEU A 73 -2.893 13.032 -12.539 1.00 66.33 C
|
||||
ATOM 582 CB LEU A 73 -5.058 14.196 -13.010 1.00 66.33 C
|
||||
ATOM 583 O LEU A 73 -2.291 13.292 -11.495 1.00 66.33 O
|
||||
ATOM 584 CG LEU A 73 -5.727 15.567 -13.115 1.00 66.33 C
|
||||
ATOM 585 CD1 LEU A 73 -7.205 15.411 -13.456 1.00 66.33 C
|
||||
ATOM 586 CD2 LEU A 73 -5.551 16.349 -11.818 1.00 66.33 C
|
||||
ATOM 587 N THR A 74 -2.894 11.771 -13.049 1.00 65.78 N
|
||||
ATOM 588 CA THR A 74 -2.225 10.632 -12.430 1.00 65.78 C
|
||||
ATOM 589 C THR A 74 -0.710 10.750 -12.575 1.00 65.78 C
|
||||
ATOM 590 CB THR A 74 -2.699 9.303 -13.046 1.00 65.78 C
|
||||
ATOM 591 O THR A 74 0.035 10.429 -11.646 1.00 65.78 O
|
||||
ATOM 592 CG2 THR A 74 -2.057 8.111 -12.344 1.00 65.78 C
|
||||
ATOM 593 OG1 THR A 74 -4.124 9.206 -12.920 1.00 65.78 O
|
||||
ATOM 594 N LEU A 75 -0.311 11.344 -13.746 1.00 68.90 N
|
||||
ATOM 595 CA LEU A 75 1.107 11.593 -13.982 1.00 68.90 C
|
||||
ATOM 596 C LEU A 75 1.625 12.698 -13.068 1.00 68.90 C
|
||||
ATOM 597 CB LEU A 75 1.348 11.970 -15.446 1.00 68.90 C
|
||||
ATOM 598 O LEU A 75 2.740 12.610 -12.550 1.00 68.90 O
|
||||
ATOM 599 CG LEU A 75 1.401 10.812 -16.445 1.00 68.90 C
|
||||
ATOM 600 CD1 LEU A 75 1.017 11.297 -17.839 1.00 68.90 C
|
||||
ATOM 601 CD2 LEU A 75 2.788 10.179 -16.456 1.00 68.90 C
|
||||
ATOM 602 N LYS A 76 0.708 13.698 -12.805 1.00 71.32 N
|
||||
ATOM 603 CA LYS A 76 1.071 14.813 -11.936 1.00 71.32 C
|
||||
ATOM 604 C LYS A 76 1.146 14.372 -10.477 1.00 71.32 C
|
||||
ATOM 605 CB LYS A 76 0.068 15.959 -12.086 1.00 71.32 C
|
||||
ATOM 606 O LYS A 76 1.991 14.854 -9.720 1.00 71.32 O
|
||||
ATOM 607 CG LYS A 76 0.514 17.260 -11.436 1.00 71.32 C
|
||||
ATOM 608 CD LYS A 76 -0.488 18.381 -11.684 1.00 71.32 C
|
||||
ATOM 609 CE LYS A 76 -0.066 19.672 -10.996 1.00 71.32 C
|
||||
ATOM 610 NZ LYS A 76 -1.069 20.760 -11.197 1.00 71.32 N
|
||||
ATOM 611 N HIS A 77 0.420 13.365 -10.189 1.00 75.38 N
|
||||
ATOM 612 CA HIS A 77 0.315 12.913 -8.807 1.00 75.38 C
|
||||
ATOM 613 C HIS A 77 1.167 11.672 -8.567 1.00 75.38 C
|
||||
ATOM 614 CB HIS A 77 -1.144 12.626 -8.446 1.00 75.38 C
|
||||
ATOM 615 O HIS A 77 1.146 11.101 -7.474 1.00 75.38 O
|
||||
ATOM 616 CG HIS A 77 -1.983 13.857 -8.316 1.00 75.38 C
|
||||
ATOM 617 CD2 HIS A 77 -1.961 14.855 -7.401 1.00 75.38 C
|
||||
ATOM 618 ND1 HIS A 77 -2.994 14.166 -9.199 1.00 75.38 N
|
||||
ATOM 619 CE1 HIS A 77 -3.559 15.304 -8.833 1.00 75.38 C
|
||||
ATOM 620 NE2 HIS A 77 -2.951 15.743 -7.744 1.00 75.38 N
|
||||
ATOM 621 N LYS A 78 1.936 11.316 -9.653 1.00 73.17 N
|
||||
ATOM 622 CA LYS A 78 2.824 10.158 -9.610 1.00 73.17 C
|
||||
ATOM 623 C LYS A 78 3.862 10.302 -8.500 1.00 73.17 C
|
||||
ATOM 624 CB LYS A 78 3.521 9.965 -10.957 1.00 73.17 C
|
||||
ATOM 625 O LYS A 78 4.117 9.353 -7.755 1.00 73.17 O
|
||||
ATOM 626 CG LYS A 78 4.245 8.633 -11.095 1.00 73.17 C
|
||||
ATOM 627 CD LYS A 78 4.838 8.461 -12.487 1.00 73.17 C
|
||||
ATOM 628 CE LYS A 78 5.641 7.172 -12.598 1.00 73.17 C
|
||||
ATOM 629 NZ LYS A 78 6.222 6.996 -13.963 1.00 73.17 N
|
||||
ATOM 630 N GLU A 79 4.467 11.425 -8.459 1.00 82.01 N
|
||||
ATOM 631 CA GLU A 79 5.451 11.676 -7.410 1.00 82.01 C
|
||||
ATOM 632 C GLU A 79 4.810 11.619 -6.027 1.00 82.01 C
|
||||
ATOM 633 CB GLU A 79 6.127 13.034 -7.621 1.00 82.01 C
|
||||
ATOM 634 O GLU A 79 5.388 11.062 -5.091 1.00 82.01 O
|
||||
ATOM 635 CG GLU A 79 7.125 13.052 -8.769 1.00 82.01 C
|
||||
ATOM 636 CD GLU A 79 7.967 14.317 -8.812 1.00 82.01 C
|
||||
ATOM 637 OE1 GLU A 79 9.088 14.320 -8.254 1.00 82.01 O
|
||||
ATOM 638 OE2 GLU A 79 7.502 15.314 -9.408 1.00 82.01 O
|
||||
ATOM 639 N LYS A 80 3.748 12.178 -5.930 1.00 81.73 N
|
||||
ATOM 640 CA LYS A 80 3.031 12.190 -4.659 1.00 81.73 C
|
||||
ATOM 641 C LYS A 80 2.604 10.781 -4.255 1.00 81.73 C
|
||||
ATOM 642 CB LYS A 80 1.808 13.105 -4.740 1.00 81.73 C
|
||||
ATOM 643 O LYS A 80 2.693 10.412 -3.082 1.00 81.73 O
|
||||
ATOM 644 CG LYS A 80 2.129 14.583 -4.570 1.00 81.73 C
|
||||
ATOM 645 CD LYS A 80 0.863 15.427 -4.516 1.00 81.73 C
|
||||
ATOM 646 CE LYS A 80 1.184 16.914 -4.444 1.00 81.73 C
|
||||
ATOM 647 NZ LYS A 80 -0.055 17.744 -4.351 1.00 81.73 N
|
||||
ATOM 648 N ILE A 81 2.180 10.044 -5.166 1.00 80.10 N
|
||||
ATOM 649 CA ILE A 81 1.790 8.655 -4.957 1.00 80.10 C
|
||||
ATOM 650 C ILE A 81 2.993 7.848 -4.473 1.00 80.10 C
|
||||
ATOM 651 CB ILE A 81 1.208 8.030 -6.245 1.00 80.10 C
|
||||
ATOM 652 O ILE A 81 2.875 7.039 -3.550 1.00 80.10 O
|
||||
ATOM 653 CG1 ILE A 81 -0.130 8.688 -6.600 1.00 80.10 C
|
||||
ATOM 654 CG2 ILE A 81 1.050 6.515 -6.087 1.00 80.10 C
|
||||
ATOM 655 CD1 ILE A 81 -0.679 8.279 -7.960 1.00 80.10 C
|
||||
ATOM 656 N LEU A 82 4.081 8.122 -5.134 1.00 83.52 N
|
||||
ATOM 657 CA LEU A 82 5.328 7.478 -4.739 1.00 83.52 C
|
||||
ATOM 658 C LEU A 82 5.679 7.813 -3.294 1.00 83.52 C
|
||||
ATOM 659 CB LEU A 82 6.470 7.905 -5.666 1.00 83.52 C
|
||||
ATOM 660 O LEU A 82 5.984 6.919 -2.501 1.00 83.52 O
|
||||
ATOM 661 CG LEU A 82 7.813 7.204 -5.456 1.00 83.52 C
|
||||
ATOM 662 CD1 LEU A 82 7.738 5.760 -5.939 1.00 83.52 C
|
||||
ATOM 663 CD2 LEU A 82 8.927 7.957 -6.174 1.00 83.52 C
|
||||
ATOM 664 N GLU A 83 5.694 9.021 -2.968 1.00 87.96 N
|
||||
ATOM 665 CA GLU A 83 6.011 9.477 -1.618 1.00 87.96 C
|
||||
ATOM 666 C GLU A 83 5.056 8.873 -0.593 1.00 87.96 C
|
||||
ATOM 667 CB GLU A 83 5.967 11.005 -1.542 1.00 87.96 C
|
||||
ATOM 668 O GLU A 83 5.488 8.386 0.454 1.00 87.96 O
|
||||
ATOM 669 CG GLU A 83 6.496 11.571 -0.233 1.00 87.96 C
|
||||
ATOM 670 CD GLU A 83 6.453 13.090 -0.175 1.00 87.96 C
|
||||
ATOM 671 OE1 GLU A 83 5.424 13.652 0.264 1.00 87.96 O
|
||||
ATOM 672 OE2 GLU A 83 7.456 13.723 -0.573 1.00 87.96 O
|
||||
ATOM 673 N LYS A 84 3.752 8.925 -0.931 1.00 87.17 N
|
||||
ATOM 674 CA LYS A 84 2.749 8.416 0.000 1.00 87.17 C
|
||||
ATOM 675 C LYS A 84 2.865 6.903 0.160 1.00 87.17 C
|
||||
ATOM 676 CB LYS A 84 1.342 8.787 -0.470 1.00 87.17 C
|
||||
ATOM 677 O LYS A 84 2.708 6.376 1.264 1.00 87.17 O
|
||||
ATOM 678 CG LYS A 84 1.031 10.274 -0.383 1.00 87.17 C
|
||||
ATOM 679 CD LYS A 84 0.932 10.739 1.064 1.00 87.17 C
|
||||
ATOM 680 CE LYS A 84 0.563 12.214 1.154 1.00 87.17 C
|
||||
ATOM 681 NZ LYS A 84 0.580 12.705 2.564 1.00 87.17 N
|
||||
ATOM 682 N THR A 85 3.075 6.194 -0.878 1.00 86.48 N
|
||||
ATOM 683 CA THR A 85 3.277 4.749 -0.859 1.00 86.48 C
|
||||
ATOM 684 C THR A 85 4.478 4.381 0.007 1.00 86.48 C
|
||||
ATOM 685 CB THR A 85 3.478 4.195 -2.282 1.00 86.48 C
|
||||
ATOM 686 O THR A 85 4.438 3.396 0.747 1.00 86.48 O
|
||||
ATOM 687 CG2 THR A 85 3.571 2.673 -2.271 1.00 86.48 C
|
||||
ATOM 688 OG1 THR A 85 2.371 4.589 -3.103 1.00 86.48 O
|
||||
ATOM 689 N LYS A 86 5.560 5.179 -0.120 1.00 89.61 N
|
||||
ATOM 690 CA LYS A 86 6.738 4.988 0.722 1.00 89.61 C
|
||||
ATOM 691 C LYS A 86 6.390 5.146 2.199 1.00 89.61 C
|
||||
ATOM 692 CB LYS A 86 7.840 5.975 0.335 1.00 89.61 C
|
||||
ATOM 693 O LYS A 86 6.864 4.379 3.040 1.00 89.61 O
|
||||
ATOM 694 CG LYS A 86 8.596 5.594 -0.930 1.00 89.61 C
|
||||
ATOM 695 CD LYS A 86 9.745 6.555 -1.205 1.00 89.61 C
|
||||
ATOM 696 CE LYS A 86 10.475 6.201 -2.494 1.00 89.61 C
|
||||
ATOM 697 NZ LYS A 86 11.592 7.151 -2.777 1.00 89.61 N
|
||||
ATOM 698 N LEU A 87 5.725 6.133 2.442 1.00 90.63 N
|
||||
ATOM 699 CA LEU A 87 5.303 6.398 3.814 1.00 90.63 C
|
||||
ATOM 700 C LEU A 87 4.520 5.217 4.379 1.00 90.63 C
|
||||
ATOM 701 CB LEU A 87 4.449 7.667 3.877 1.00 90.63 C
|
||||
ATOM 702 O LEU A 87 4.736 4.815 5.524 1.00 90.63 O
|
||||
ATOM 703 CG LEU A 87 4.127 8.198 5.274 1.00 90.63 C
|
||||
ATOM 704 CD1 LEU A 87 5.400 8.666 5.971 1.00 90.63 C
|
||||
ATOM 705 CD2 LEU A 87 3.108 9.330 5.195 1.00 90.63 C
|
||||
ATOM 706 N VAL A 88 3.611 4.770 3.617 1.00 89.50 N
|
||||
ATOM 707 CA VAL A 88 2.818 3.610 4.012 1.00 89.50 C
|
||||
ATOM 708 C VAL A 88 3.741 2.436 4.330 1.00 89.50 C
|
||||
ATOM 709 CB VAL A 88 1.808 3.212 2.913 1.00 89.50 C
|
||||
ATOM 710 O VAL A 88 3.547 1.739 5.328 1.00 89.50 O
|
||||
ATOM 711 CG1 VAL A 88 1.118 1.895 3.265 1.00 89.50 C
|
||||
ATOM 712 CG2 VAL A 88 0.777 4.321 2.708 1.00 89.50 C
|
||||
ATOM 713 N LEU A 89 4.633 2.181 3.505 1.00 90.95 N
|
||||
ATOM 714 CA LEU A 89 5.629 1.136 3.718 1.00 90.95 C
|
||||
ATOM 715 C LEU A 89 6.348 1.334 5.048 1.00 90.95 C
|
||||
ATOM 716 CB LEU A 89 6.644 1.123 2.572 1.00 90.95 C
|
||||
ATOM 717 O LEU A 89 6.528 0.380 5.809 1.00 90.95 O
|
||||
ATOM 718 CG LEU A 89 7.716 0.033 2.629 1.00 90.95 C
|
||||
ATOM 719 CD1 LEU A 89 7.069 -1.348 2.620 1.00 90.95 C
|
||||
ATOM 720 CD2 LEU A 89 8.691 0.180 1.466 1.00 90.95 C
|
||||
ATOM 721 N GLU A 90 6.858 2.505 5.268 1.00 91.77 N
|
||||
ATOM 722 CA GLU A 90 7.540 2.813 6.521 1.00 91.77 C
|
||||
ATOM 723 C GLU A 90 6.648 2.516 7.723 1.00 91.77 C
|
||||
ATOM 724 CB GLU A 90 7.985 4.278 6.545 1.00 91.77 C
|
||||
ATOM 725 O GLU A 90 7.113 1.982 8.731 1.00 91.77 O
|
||||
ATOM 726 CG GLU A 90 9.127 4.590 5.589 1.00 91.77 C
|
||||
ATOM 727 CD GLU A 90 10.319 5.241 6.271 1.00 91.77 C
|
||||
ATOM 728 OE1 GLU A 90 11.320 4.540 6.544 1.00 91.77 O
|
||||
ATOM 729 OE2 GLU A 90 10.252 6.462 6.535 1.00 91.77 O
|
||||
ATOM 730 N ILE A 91 5.411 2.885 7.569 1.00 90.84 N
|
||||
ATOM 731 CA ILE A 91 4.447 2.638 8.635 1.00 90.84 C
|
||||
ATOM 732 C ILE A 91 4.287 1.135 8.849 1.00 90.84 C
|
||||
ATOM 733 CB ILE A 91 3.078 3.283 8.321 1.00 90.84 C
|
||||
ATOM 734 O ILE A 91 4.286 0.660 9.987 1.00 90.84 O
|
||||
ATOM 735 CG1 ILE A 91 3.208 4.810 8.263 1.00 90.84 C
|
||||
ATOM 736 CG2 ILE A 91 2.031 2.861 9.356 1.00 90.84 C
|
||||
ATOM 737 CD1 ILE A 91 1.989 5.514 7.684 1.00 90.84 C
|
||||
ATOM 738 N LEU A 92 4.083 0.438 7.825 1.00 90.22 N
|
||||
ATOM 739 CA LEU A 92 3.929 -1.012 7.890 1.00 90.22 C
|
||||
ATOM 740 C LEU A 92 5.163 -1.662 8.506 1.00 90.22 C
|
||||
ATOM 741 CB LEU A 92 3.677 -1.587 6.494 1.00 90.22 C
|
||||
ATOM 742 O LEU A 92 5.045 -2.579 9.322 1.00 90.22 O
|
||||
ATOM 743 CG LEU A 92 2.300 -1.314 5.887 1.00 90.22 C
|
||||
ATOM 744 CD1 LEU A 92 2.262 -1.772 4.432 1.00 90.22 C
|
||||
ATOM 745 CD2 LEU A 92 1.211 -2.006 6.699 1.00 90.22 C
|
||||
ATOM 746 N LYS A 93 6.355 -1.270 8.049 1.00 89.96 N
|
||||
ATOM 747 CA LYS A 93 7.611 -1.791 8.582 1.00 89.96 C
|
||||
ATOM 748 C LYS A 93 7.703 -1.568 10.089 1.00 89.96 C
|
||||
ATOM 749 CB LYS A 93 8.803 -1.137 7.881 1.00 89.96 C
|
||||
ATOM 750 O LYS A 93 8.149 -2.450 10.826 1.00 89.96 O
|
||||
ATOM 751 CG LYS A 93 9.068 -1.672 6.481 1.00 89.96 C
|
||||
ATOM 752 CD LYS A 93 10.333 -1.070 5.884 1.00 89.96 C
|
||||
ATOM 753 CE LYS A 93 10.606 -1.615 4.488 1.00 89.96 C
|
||||
ATOM 754 NZ LYS A 93 11.842 -1.022 3.894 1.00 89.96 N
|
||||
ATOM 755 N GLU A 94 7.401 -0.356 10.430 1.00 91.25 N
|
||||
ATOM 756 CA GLU A 94 7.387 -0.032 11.853 1.00 91.25 C
|
||||
ATOM 757 C GLU A 94 6.457 -0.965 12.623 1.00 91.25 C
|
||||
ATOM 758 CB GLU A 94 6.968 1.425 12.069 1.00 91.25 C
|
||||
ATOM 759 O GLU A 94 6.797 -1.429 13.713 1.00 91.25 O
|
||||
ATOM 760 CG GLU A 94 8.067 2.432 11.765 1.00 91.25 C
|
||||
ATOM 761 CD GLU A 94 7.783 3.817 12.324 1.00 91.25 C
|
||||
ATOM 762 OE1 GLU A 94 8.221 4.116 13.459 1.00 91.25 O
|
||||
ATOM 763 OE2 GLU A 94 7.116 4.610 11.623 1.00 91.25 O
|
||||
ATOM 764 N ARG A 95 5.355 -1.225 12.075 1.00 85.31 N
|
||||
ATOM 765 CA ARG A 95 4.398 -2.127 12.709 1.00 85.31 C
|
||||
ATOM 766 C ARG A 95 4.938 -3.553 12.756 1.00 85.31 C
|
||||
ATOM 767 CB ARG A 95 3.059 -2.098 11.969 1.00 85.31 C
|
||||
ATOM 768 O ARG A 95 4.712 -4.276 13.728 1.00 85.31 O
|
||||
ATOM 769 CG ARG A 95 2.304 -0.786 12.115 1.00 85.31 C
|
||||
ATOM 770 CD ARG A 95 1.648 -0.662 13.483 1.00 85.31 C
|
||||
ATOM 771 NE ARG A 95 0.780 0.509 13.560 1.00 85.31 N
|
||||
ATOM 772 NH1 ARG A 95 -1.032 -0.634 14.424 1.00 85.31 N
|
||||
ATOM 773 NH2 ARG A 95 -1.174 1.620 14.033 1.00 85.31 N
|
||||
ATOM 774 CZ ARG A 95 -0.474 0.496 14.006 1.00 85.31 C
|
||||
ATOM 775 N LEU A 96 5.431 -3.928 11.737 1.00 87.53 N
|
||||
ATOM 776 CA LEU A 96 6.039 -5.251 11.646 1.00 87.53 C
|
||||
ATOM 777 C LEU A 96 7.142 -5.415 12.687 1.00 87.53 C
|
||||
ATOM 778 CB LEU A 96 6.605 -5.486 10.244 1.00 87.53 C
|
||||
ATOM 779 O LEU A 96 7.260 -6.471 13.311 1.00 87.53 O
|
||||
ATOM 780 CG LEU A 96 7.106 -6.899 9.943 1.00 87.53 C
|
||||
ATOM 781 CD1 LEU A 96 5.938 -7.879 9.903 1.00 87.53 C
|
||||
ATOM 782 CD2 LEU A 96 7.877 -6.925 8.627 1.00 87.53 C
|
||||
ATOM 783 N LYS A 97 8.035 -4.458 12.855 1.00 87.68 N
|
||||
ATOM 784 CA LYS A 97 9.111 -4.470 13.842 1.00 87.68 C
|
||||
ATOM 785 C LYS A 97 8.555 -4.573 15.260 1.00 87.68 C
|
||||
ATOM 786 CB LYS A 97 9.976 -3.216 13.709 1.00 87.68 C
|
||||
ATOM 787 O LYS A 97 9.131 -5.256 16.109 1.00 87.68 O
|
||||
ATOM 788 CG LYS A 97 10.961 -3.264 12.550 1.00 87.68 C
|
||||
ATOM 789 CD LYS A 97 11.875 -2.045 12.542 1.00 87.68 C
|
||||
ATOM 790 CE LYS A 97 12.840 -2.076 11.365 1.00 87.68 C
|
||||
ATOM 791 NZ LYS A 97 13.742 -0.886 11.356 1.00 87.68 N
|
||||
ATOM 792 N GLU A 98 7.395 -3.949 15.535 1.00 85.16 N
|
||||
ATOM 793 CA GLU A 98 6.766 -3.985 16.852 1.00 85.16 C
|
||||
ATOM 794 C GLU A 98 6.185 -5.364 17.149 1.00 85.16 C
|
||||
ATOM 795 CB GLU A 98 5.671 -2.920 16.954 1.00 85.16 C
|
||||
ATOM 796 O GLU A 98 6.174 -5.804 18.300 1.00 85.16 O
|
||||
ATOM 797 CG GLU A 98 6.201 -1.494 16.993 1.00 85.16 C
|
||||
ATOM 798 CD GLU A 98 5.199 -0.496 17.550 1.00 85.16 C
|
||||
ATOM 799 OE1 GLU A 98 5.207 -0.247 18.777 1.00 85.16 O
|
||||
ATOM 800 OE2 GLU A 98 4.397 0.041 16.753 1.00 85.16 O
|
||||
ATOM 801 N LYS A 99 5.862 -6.201 16.145 1.00 71.59 N
|
||||
ATOM 802 CA LYS A 99 5.236 -7.516 16.249 1.00 71.59 C
|
||||
ATOM 803 C LYS A 99 6.285 -8.620 16.338 1.00 71.59 C
|
||||
ATOM 804 CB LYS A 99 4.311 -7.766 15.057 1.00 71.59 C
|
||||
ATOM 805 O LYS A 99 6.031 -9.682 16.910 1.00 71.59 O
|
||||
ATOM 806 CG LYS A 99 2.886 -7.276 15.266 1.00 71.59 C
|
||||
ATOM 807 CD LYS A 99 1.932 -7.876 14.240 1.00 71.59 C
|
||||
ATOM 808 CE LYS A 99 0.499 -7.420 14.474 1.00 71.59 C
|
||||
ATOM 809 NZ LYS A 99 -0.480 -8.264 13.726 1.00 71.59 N
|
||||
ATOM 810 N GLU A 100 7.534 -8.377 16.016 1.00 69.93 N
|
||||
ATOM 811 CA GLU A 100 8.637 -9.325 16.142 1.00 69.93 C
|
||||
ATOM 812 C GLU A 100 9.233 -9.296 17.546 1.00 69.93 C
|
||||
ATOM 813 CB GLU A 100 9.723 -9.028 15.104 1.00 69.93 C
|
||||
ATOM 814 O GLU A 100 9.551 -10.343 18.113 1.00 69.93 O
|
||||
ATOM 815 CG GLU A 100 9.683 -9.948 13.892 1.00 69.93 C
|
||||
ATOM 816 CD GLU A 100 10.905 -9.814 12.998 1.00 69.93 C
|
||||
ATOM 817 OE1 GLU A 100 11.866 -10.601 13.160 1.00 69.93 O
|
||||
ATOM 818 OE2 GLU A 100 10.903 -8.915 12.128 1.00 69.93 O
|
||||
ENDMDL
|
||||
END
|
||||
@@ -1,570 +0,0 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2025 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 "test-main.hpp"
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <cif++/cif++.hpp>
|
||||
#include <cif++/cql.hpp>
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
cif::file operator""_cf(const char *text, std::size_t length)
|
||||
{
|
||||
struct membuf : public std::streambuf
|
||||
{
|
||||
membuf(char *text, std::size_t length)
|
||||
{
|
||||
this->setg(text, text, text + length);
|
||||
}
|
||||
} buffer(const_cast<char *>(text), length);
|
||||
|
||||
std::istream is(&buffer);
|
||||
return cif::file(is);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
const char *kAuthors[] = {
|
||||
"Kleywegt, G.J.",
|
||||
"Bergfors, T.",
|
||||
"Senn, H.",
|
||||
"Le Motte, P.",
|
||||
"Gsell, B.",
|
||||
"Shudo, K.",
|
||||
"Jones, T.A.",
|
||||
|
||||
"Banaszak, L.",
|
||||
"Winter, N.",
|
||||
"Xu, Z.",
|
||||
"Bernlohr, D.A.",
|
||||
"Cowan, S.W.",
|
||||
"Jones, T.A.",
|
||||
"Bergfors, T.",
|
||||
"Kleywegt, G.J.",
|
||||
"Jones, T.A.",
|
||||
"Cowan, S.W.",
|
||||
"Newcomer, M.E.",
|
||||
"Jones, T.A.",
|
||||
"Jones, T.A.",
|
||||
"Bergfors, T.",
|
||||
"Sedzik, J.",
|
||||
"Unge, T."
|
||||
};
|
||||
|
||||
// Test simple SELECT
|
||||
TEST_CASE("cql-1")
|
||||
{
|
||||
cif::file f(gTestDir / ".." / "examples" / "1cbs.cif.gz");
|
||||
auto &db = f.front();
|
||||
db.load_dictionary("mmcif_pdbx.dic");
|
||||
|
||||
cif::cql::connection connection(db);
|
||||
cif::cql::transaction tx(connection);
|
||||
|
||||
auto r = tx.exec("SELECT name, ordinal FROM citation_author WHERE citation_id = 'primary';");
|
||||
CHECK(r.size() == 7);
|
||||
|
||||
for (size_t ix = 0; auto row : r)
|
||||
{
|
||||
REQUIRE(ix < (sizeof(kAuthors) / sizeof(char *)));
|
||||
|
||||
CHECK(row[0].get<std::string>() == kAuthors[ix]);
|
||||
CHECK(row[1].get<size_t>() == ix + 1);
|
||||
|
||||
CHECK(row["name"].get<std::string>() == kAuthors[ix]);
|
||||
CHECK(row["ordinal"].get<size_t>() == ix + 1);
|
||||
|
||||
++ix;
|
||||
}
|
||||
|
||||
r = tx.exec("SELECT ordinal, name FROM citation_author WHERE citation_id = 'primary';");
|
||||
CHECK(r.size() == 7);
|
||||
|
||||
for (size_t ix = 0; auto row : r)
|
||||
{
|
||||
REQUIRE(ix < (sizeof(kAuthors) / sizeof(char *)));
|
||||
|
||||
CHECK(row[1].get<std::string>() == kAuthors[ix]);
|
||||
CHECK(row[0].get<size_t>() == ix + 1);
|
||||
|
||||
CHECK(row["name"].get<std::string>() == kAuthors[ix]);
|
||||
CHECK(row["ordinal"].get<size_t>() == ix + 1);
|
||||
|
||||
++ix;
|
||||
}
|
||||
|
||||
r = tx.exec("SELECT * FROM citation_author WHERE citation_id = 'primary';");
|
||||
CHECK(r.size() == 7);
|
||||
|
||||
for (int ix = 0; auto row : r)
|
||||
{
|
||||
REQUIRE(static_cast<size_t>(ix) < (sizeof(kAuthors) / sizeof(char *)));
|
||||
|
||||
for (auto fld : row)
|
||||
{
|
||||
switch (fld.num())
|
||||
{
|
||||
case 0:
|
||||
CHECK(fld.name() == "citation_id");
|
||||
CHECK(fld.get<std::string>() == "primary");
|
||||
break;
|
||||
case 1:
|
||||
CHECK(fld.name() == "name");
|
||||
CHECK(fld.get<std::string>() == kAuthors[ix]);
|
||||
break;
|
||||
case 2:
|
||||
CHECK(fld.name() == "ordinal");
|
||||
CHECK(fld.get<int>() == ix + 1);
|
||||
break;
|
||||
default:
|
||||
CHECK(fld.name() == "identifier_ORCID");
|
||||
CHECK(fld.is_null());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
CHECK(row["name"].get<std::string>() == kAuthors[ix]);
|
||||
CHECK(row["ordinal"].get<int>() == ix + 1);
|
||||
CHECK(row["citation_id"].get<std::string>() == "primary");
|
||||
|
||||
++ix;
|
||||
}
|
||||
}
|
||||
|
||||
// Test SELECT AS
|
||||
TEST_CASE("cql-2")
|
||||
{
|
||||
cif::file f(gTestDir / ".." / "examples" / "1cbs.cif.gz");
|
||||
auto &db = f.front();
|
||||
db.load_dictionary("mmcif_pdbx.dic");
|
||||
|
||||
cif::cql::connection connection(db);
|
||||
cif::cql::transaction tx(connection);
|
||||
|
||||
auto r = tx.exec("SELECT name AS v1, ordinal AS v2 FROM citation_author WHERE citation_id = 'primary';");
|
||||
CHECK(r.size() == 7);
|
||||
|
||||
for (size_t ix = 0; auto row : r)
|
||||
{
|
||||
REQUIRE(ix < (sizeof(kAuthors) / sizeof(char *)));
|
||||
|
||||
CHECK(row[0].get<std::string>() == kAuthors[ix]);
|
||||
CHECK(row[1].get<size_t>() == ix + 1);
|
||||
|
||||
CHECK(row["v1"].get<std::string>() == kAuthors[ix]);
|
||||
CHECK(row["v2"].get<size_t>() == ix + 1);
|
||||
|
||||
++ix;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("cql-3")
|
||||
{
|
||||
cif::file f(gTestDir / ".." / "examples" / "1cbs.cif.gz");
|
||||
auto &db = f.front();
|
||||
db.load_dictionary("mmcif_pdbx.dic");
|
||||
|
||||
cif::cql::connection connection(db);
|
||||
cif::cql::transaction tx(connection);
|
||||
|
||||
auto r = tx.exec("SELECT name FROM citation_author WHERE ordinal = 10").one_field();
|
||||
CHECK(r.get<std::string>() == kAuthors[9]);
|
||||
}
|
||||
|
||||
TEST_CASE("cql-4")
|
||||
{
|
||||
cif::file f(gTestDir / ".." / "examples" / "1cbs.cif.gz");
|
||||
auto &db = f.front();
|
||||
db.load_dictionary("mmcif_pdbx.dic");
|
||||
|
||||
cif::cql::connection connection(db);
|
||||
cif::cql::transaction tx(connection);
|
||||
|
||||
auto r = tx.exec("SELECT name FROM citation_author WHERE ordinal BETWEEN 10 AND 15");
|
||||
REQUIRE(r.size() == 6);
|
||||
}
|
||||
|
||||
TEST_CASE("cql-5")
|
||||
{
|
||||
cif::file f(gTestDir / ".." / "examples" / "1cbs.cif.gz");
|
||||
auto &db = f.front();
|
||||
db.load_dictionary("mmcif_pdbx.dic");
|
||||
|
||||
cif::cql::connection connection(db);
|
||||
cif::cql::transaction tx(connection);
|
||||
|
||||
auto r = tx.exec("SELECT (SELECT year FROM citation WHERE id = citation_id) AS jaar FROM citation_author WHERE ordinal IS 23").one_field();
|
||||
CHECK(r.name() == "jaar");
|
||||
CHECK(r.get<int>() == 1988);
|
||||
}
|
||||
|
||||
TEST_CASE("cql-6")
|
||||
{
|
||||
cif::file f(gTestDir / ".." / "examples" / "1cbs.cif.gz");
|
||||
auto &db = f.front();
|
||||
db.load_dictionary("mmcif_pdbx.dic");
|
||||
|
||||
cif::cql::connection connection(db);
|
||||
cif::cql::transaction tx(connection);
|
||||
|
||||
auto r = tx.exec("SELECT COUNT(*) FROM citation WHERE page_last IS NULL").one_field();
|
||||
CHECK(r.get<int>() == 4);
|
||||
|
||||
r = tx.exec("SELECT COUNT(*) FROM citation WHERE page_last IS NOT NULL").one_field();
|
||||
CHECK(r.get<int>() == 1);
|
||||
}
|
||||
|
||||
TEST_CASE("cql-stream-1")
|
||||
{
|
||||
cif::file f(gTestDir / ".." / "examples" / "1cbs.cif.gz");
|
||||
auto &db = f.front();
|
||||
db.load_dictionary("mmcif_pdbx.dic");
|
||||
|
||||
cif::cql::connection connection(db);
|
||||
cif::cql::transaction tx(connection);
|
||||
|
||||
for (size_t ix = 0;
|
||||
const auto &[name, ordinal] : tx.stream<std::string, size_t>(
|
||||
"SELECT name, ordinal FROM citation_author WHERE citation_id = 'primary';"))
|
||||
{
|
||||
REQUIRE(ix < (sizeof(kAuthors) / sizeof(char *)));
|
||||
|
||||
CHECK(name == kAuthors[ix]);
|
||||
CHECK(ordinal == (ix + 1));
|
||||
|
||||
++ix;
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
TEST_CASE("cql-insert-1")
|
||||
{
|
||||
auto f1 = R"(
|
||||
data_T1
|
||||
loop_
|
||||
_table1.id
|
||||
_table1.name
|
||||
1 aap
|
||||
2 noot)"_cf;
|
||||
auto f0 = f1;
|
||||
|
||||
auto &db = f1.front();
|
||||
|
||||
cif::cql::connection connection(db);
|
||||
cif::cql::transaction tx(connection);
|
||||
|
||||
auto count = tx.exec("SELECT COUNT(*) FROM table1;").one_field().get<int>();
|
||||
CHECK(count == 2);
|
||||
|
||||
auto r = tx.exec("INSERT INTO table1 (id, name) VALUES (3, 'mies')");
|
||||
|
||||
count = tx.exec("SELECT COUNT(*) FROM table1").one_field().get<int>();
|
||||
CHECK(count == 3);
|
||||
|
||||
(void)tx.exec("DELETE FROM table1 WHERE CAST(id AS INTEGER) = 1;");
|
||||
|
||||
count = tx.exec("SELECT COUNT(*) FROM table1;").one_field().get<int>();
|
||||
CHECK(count == 2);
|
||||
|
||||
(void)tx.exec("UPDATE table1 SET name = 'amandel' WHERE CAST(id AS INTEGER) = 2");
|
||||
|
||||
auto f2 = R"(
|
||||
data_T1
|
||||
loop_
|
||||
_table1.id
|
||||
_table1.name
|
||||
2 amandel
|
||||
3 mies)"_cf;
|
||||
|
||||
CHECK(f1 == f2);
|
||||
|
||||
tx.rollback();
|
||||
|
||||
CHECK(f1 == f0);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
TEST_CASE("cql-rename")
|
||||
{
|
||||
auto f1 = R"(
|
||||
data_T1
|
||||
loop_
|
||||
_table1.id
|
||||
_table1.name
|
||||
1 aap
|
||||
2 noot)"_cf;
|
||||
|
||||
auto &db = f1.front();
|
||||
|
||||
cif::cql::connection connection(db);
|
||||
cif::cql::transaction tx(connection);
|
||||
|
||||
(void)tx.exec("ALTER TABLE table1 RENAME TO 'table2'");
|
||||
|
||||
auto f2 = R"(
|
||||
data_T1
|
||||
loop_
|
||||
_table2.id
|
||||
_table2.name
|
||||
1 aap
|
||||
2 noot)"_cf;
|
||||
|
||||
CHECK(f1 == f2);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
TEST_CASE("cql-foreign-keys-1")
|
||||
{
|
||||
const char dict[] = R"(
|
||||
data_test_dict.dic
|
||||
_datablock.id test_dict.dic
|
||||
_datablock.description
|
||||
;
|
||||
A test dictionary
|
||||
;
|
||||
_dictionary.title test_dict.dic
|
||||
_dictionary.datablock_id test_dict.dic
|
||||
_dictionary.version 1.0
|
||||
|
||||
loop_
|
||||
_item_type_list.code
|
||||
_item_type_list.primitive_code
|
||||
_item_type_list.construct
|
||||
_item_type_list.detail
|
||||
code char
|
||||
'[][_,.;:"&<>()/\{}'`~!@#$%A-Za-z0-9*|+-]*'
|
||||
; code item types/single words ...
|
||||
;
|
||||
text char
|
||||
'[][ \n\t()_,.;:"&<>/\{}'`~!@#$%?+=*A-Za-z0-9|^-]*'
|
||||
; text item types / multi-line text ...
|
||||
;
|
||||
int numb
|
||||
'[+-]?[0-9]+'
|
||||
; int item types are the subset of numbers that are the negative
|
||||
or positive integers.
|
||||
;
|
||||
|
||||
save_cat_1
|
||||
_category.description 'A simple test category'
|
||||
_category.id cat_1
|
||||
_category.mandatory_code no
|
||||
_category_key.name '_cat_1.id'
|
||||
|
||||
save_
|
||||
|
||||
save__cat_1.id
|
||||
_item.name '_cat_1.id'
|
||||
_item.category_id cat_1
|
||||
_item.mandatory_code yes
|
||||
_item_aliases.dictionary cif_core.dic
|
||||
_item_aliases.version 2.0.1
|
||||
_item_linked.child_name '_cat_2.parent_id'
|
||||
_item_linked.parent_name '_cat_1.id'
|
||||
_item_type.code code
|
||||
save_
|
||||
|
||||
save__cat_1.name
|
||||
_item.name '_cat_1.name'
|
||||
_item.category_id cat_1
|
||||
_item.mandatory_code yes
|
||||
_item_aliases.dictionary cif_core.dic
|
||||
_item_aliases.version 2.0.1
|
||||
_item_type.code text
|
||||
save_
|
||||
|
||||
save_cat_2
|
||||
_category.description 'A second simple test category'
|
||||
_category.id cat_2
|
||||
_category.mandatory_code no
|
||||
_category_key.name '_cat_2.id'
|
||||
save_
|
||||
|
||||
save__cat_2.id
|
||||
_item.name '_cat_2.id'
|
||||
_item.category_id cat_2
|
||||
_item.mandatory_code yes
|
||||
_item_aliases.dictionary cif_core.dic
|
||||
_item_aliases.version 2.0.1
|
||||
_item_type.code int
|
||||
save_
|
||||
|
||||
save__cat_2.parent_id
|
||||
_item.name '_cat_2.parent_id'
|
||||
_item.category_id cat_2
|
||||
_item.mandatory_code yes
|
||||
_item_aliases.dictionary cif_core.dic
|
||||
_item_aliases.version 2.0.1
|
||||
_item_type.code code
|
||||
save_
|
||||
|
||||
save__cat_2.desc
|
||||
_item.name '_cat_2.desc'
|
||||
_item.category_id cat_2
|
||||
_item.mandatory_code yes
|
||||
_item_aliases.dictionary cif_core.dic
|
||||
_item_aliases.version 2.0.1
|
||||
_item_type.code text
|
||||
save_
|
||||
)";
|
||||
|
||||
struct membuf : public std::streambuf
|
||||
{
|
||||
membuf(char *text, std::size_t length)
|
||||
{
|
||||
this->setg(text, text, text + length);
|
||||
}
|
||||
} buffer(const_cast<char *>(dict), sizeof(dict) - 1);
|
||||
|
||||
std::istream is_dict(&buffer);
|
||||
|
||||
cif::validator validator(is_dict);
|
||||
|
||||
cif::file f;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
const char data[] = R"(
|
||||
data_test
|
||||
loop_
|
||||
_cat_1.id
|
||||
_cat_1.name
|
||||
1 Aap
|
||||
2 Noot
|
||||
3 Mies
|
||||
|
||||
loop_
|
||||
_cat_2.id
|
||||
_cat_2.parent_id
|
||||
_cat_2.desc
|
||||
1 1 'Een dier'
|
||||
2 1 'Een andere aap'
|
||||
3 2 'walnoot bijvoorbeeld'
|
||||
)";
|
||||
|
||||
struct data_membuf : public std::streambuf
|
||||
{
|
||||
data_membuf(char *text, std::size_t length)
|
||||
{
|
||||
this->setg(text, text, text + length);
|
||||
}
|
||||
} data_buffer(const_cast<char *>(data), sizeof(data) - 1);
|
||||
|
||||
std::istream is_data(&data_buffer);
|
||||
f.load(is_data);
|
||||
f.front().set_validator(&validator);
|
||||
|
||||
auto &db = f.front();
|
||||
|
||||
SECTION("stream")
|
||||
{
|
||||
cif::cql::connection connection(db);
|
||||
cif::cql::transaction tx(connection);
|
||||
|
||||
for (const auto &desc : tx.stream<std::string>(R"(SELECT b.desc FROM cat_1 a, cat_2 b WHERE a.id = b.parent_id AND a.name = 'Noot')"))
|
||||
{
|
||||
CHECK(desc == "walnoot bijvoorbeeld");
|
||||
}
|
||||
}
|
||||
|
||||
// Check cascading delete
|
||||
SECTION("delete")
|
||||
{
|
||||
cif::cql::connection connection(db);
|
||||
cif::cql::transaction tx(connection);
|
||||
|
||||
tx.exec("DELETE FROM cat_1 WHERE id = 1");
|
||||
CHECK(db["cat_1"].size() == 2);
|
||||
CHECK(db["cat_2"].size() == 1);
|
||||
|
||||
tx.rollback();
|
||||
CHECK(db["cat_1"].size() == 3);
|
||||
CHECK(db["cat_2"].size() == 3);
|
||||
}
|
||||
|
||||
// Check cascading update
|
||||
SECTION("update")
|
||||
{
|
||||
cif::cql::connection connection(db);
|
||||
cif::cql::transaction tx(connection);
|
||||
|
||||
tx.exec("UPDATE cat_1 SET id = '4' WHERE id = '1'");
|
||||
CHECK(db["cat_1"].size() == 3);
|
||||
CHECK(db["cat_2"].size() == 3);
|
||||
CHECK(db["cat_1"].count(cif::key("id") == 4) == 1);
|
||||
CHECK(db["cat_2"].count(cif::key("parent_id") == 4) == 2);
|
||||
|
||||
std::cout << db;
|
||||
|
||||
tx.rollback();
|
||||
CHECK(db["cat_1"].size() == 3);
|
||||
CHECK(db["cat_2"].size() == 3);
|
||||
CHECK_FALSE(db["cat_1"].contains(cif::key("id") == 4));
|
||||
CHECK_FALSE(db["cat_2"].contains(cif::key("parent_id") == 4));
|
||||
|
||||
std::cout << db;
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
TEST_CASE("drop-table")
|
||||
{
|
||||
auto f1 = R"(
|
||||
data_T1
|
||||
loop_
|
||||
_table1.id
|
||||
_table1.name
|
||||
1 aap
|
||||
2 noot)"_cf;
|
||||
|
||||
auto &db = f1.front();
|
||||
|
||||
cif::cql::connection connection(db);
|
||||
cif::cql::transaction tx(connection);
|
||||
|
||||
SECTION("commit")
|
||||
{
|
||||
(void)tx.exec("DROP TABLE table1;");
|
||||
tx.commit();
|
||||
|
||||
CHECK(db.empty());
|
||||
}
|
||||
|
||||
// Ah, too bad: this doesn't work
|
||||
// SECTION("rollback")
|
||||
// {
|
||||
// (void)tx.exec("DROP TABLE table1;");
|
||||
// tx.rollback();
|
||||
|
||||
// CHECK(not db.empty());
|
||||
// CHECK(db["table1"].size() == 2);
|
||||
// }
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
61
test/format-test.cpp
Normal file
61
test/format-test.cpp
Normal file
@@ -0,0 +1,61 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2020 NKI/AVL, Netherlands Cancer Institute
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
#include "test-main.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include <cif++.hpp>
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
TEST_CASE("fmt_1")
|
||||
{
|
||||
std::ostringstream os;
|
||||
|
||||
std::string world("world");
|
||||
os << cif::format("Hello, %-10.10s, the magic number is %d and pi is %g", world, 42, cif::kPI);
|
||||
REQUIRE(os.str() == "Hello, world , the magic number is 42 and pi is 3.14159");
|
||||
|
||||
REQUIRE(cif::format("Hello, %-10.10s, the magic number is %d and pi is %g", world, 42, cif::kPI).str() ==
|
||||
"Hello, world , the magic number is 42 and pi is 3.14159");
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
TEST_CASE("clr_1")
|
||||
{
|
||||
using namespace cif::colour;
|
||||
|
||||
std::cout << "Hello, " << cif::coloured("world!", white, red, cif::colour::regular) << '\n'
|
||||
<< "Hello, " << cif::coloured("world!", white, red, bold) << '\n'
|
||||
<< "Hello, " << cif::coloured("world!", black, red) << '\n'
|
||||
<< "Hello, " << cif::coloured("world!", white, green) << '\n'
|
||||
<< "Hello, " << cif::coloured("world!", white, blue) << '\n'
|
||||
<< "Hello, " << cif::coloured("world!", blue, white) << '\n'
|
||||
<< "Hello, " << cif::coloured("world!", red, white, bold) << '\n';
|
||||
}
|
||||
@@ -1,30 +1,4 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2026 NKI/AVL, Netherlands Cancer Institute
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <cif++/cif++.hpp>
|
||||
#include <cif++.hpp>
|
||||
|
||||
class dummy_parser : public cif::sac_parser
|
||||
{
|
||||
|
||||
@@ -1,115 +0,0 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2025 NKI/AVL, Netherlands Cancer Institute
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "cif++/matrix.hpp"
|
||||
#include "test-main.hpp"
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <cif++/cif++.hpp>
|
||||
|
||||
TEST_CASE("m1")
|
||||
{
|
||||
cif::matrix3x3<int> m = cif::identity_matrix<int>(3);
|
||||
|
||||
CHECK(cif::determinant(m) == 1);
|
||||
}
|
||||
|
||||
TEST_CASE("m2")
|
||||
{
|
||||
cif::matrix4x4<int> m = cif::identity_matrix<int>(4);
|
||||
|
||||
cif::sub_matrix<cif::matrix4x4<int>> ms(m, 1, 1);
|
||||
CHECK(ms == cif::identity_matrix<int>(3));
|
||||
}
|
||||
|
||||
TEST_CASE("m3")
|
||||
{
|
||||
cif::matrix4x4<int> m{
|
||||
{ 1, 2, 3, 4, //
|
||||
5, 6, 7, 8, //
|
||||
9, 10, 11, 12, //
|
||||
13, 14, 15, 16 }
|
||||
};
|
||||
cif::sub_matrix<cif::matrix4x4<int>> ms(m, 1, 1);
|
||||
|
||||
cif::matrix3x3<int> t{
|
||||
{ 1, 3, 4, 9, 11, 12, 13, 15, 16 }
|
||||
};
|
||||
|
||||
CHECK(ms == t);
|
||||
}
|
||||
|
||||
TEST_CASE("m4")
|
||||
{
|
||||
cif::matrix4x4<int> m{
|
||||
{
|
||||
-2,
|
||||
3,
|
||||
1,
|
||||
0,
|
||||
4,
|
||||
1,
|
||||
-3,
|
||||
2,
|
||||
0,
|
||||
-1,
|
||||
2,
|
||||
5,
|
||||
3,
|
||||
2,
|
||||
0,
|
||||
-4,
|
||||
}
|
||||
};
|
||||
|
||||
std::cout << m << "\n\n";
|
||||
|
||||
// std::cout << cif::matrix3x3<int>(cif::sub_matrix<decltype(m)>(m, 0, 0)) << "\n\n";
|
||||
// std::cout << cif::matrix3x3<int>(cif::sub_matrix<decltype(m)>(m, 0, 1)) << "\n\n";
|
||||
// std::cout << cif::matrix3x3<int>(cif::sub_matrix<decltype(m)>(m, 0, 2)) << "\n\n";
|
||||
// std::cout << cif::matrix3x3<int>(cif::sub_matrix<decltype(m)>(m, 0, 3)) << "\n\n";
|
||||
|
||||
// std::cout << cif::determinant(cif::matrix3x3<int>(cif::sub_matrix<decltype(m)>(m, 0, 0))) << "\n\n";
|
||||
// std::cout << cif::determinant(cif::matrix3x3<int>(cif::sub_matrix<decltype(m)>(m, 0, 1))) << "\n\n";
|
||||
// std::cout << cif::determinant(cif::matrix3x3<int>(cif::sub_matrix<decltype(m)>(m, 0, 2))) << "\n\n";
|
||||
// std::cout << cif::determinant(cif::matrix3x3<int>(cif::sub_matrix<decltype(m)>(m, 0, 3))) << "\n\n";
|
||||
|
||||
CHECK(cif::determinant(m) == 332);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
TEST_CASE("m5")
|
||||
{
|
||||
cif::matrix4x4<float> m = cif::identity_matrix<float>(4);
|
||||
cif::matrix_fixed<float, 1, 4> v({ 0, 0.5f, 0, 1.0f });
|
||||
|
||||
auto mv = v * m;
|
||||
|
||||
CHECK(mv == v);
|
||||
|
||||
}
|
||||
|
||||
@@ -26,8 +26,9 @@
|
||||
|
||||
#include "test-main.hpp"
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <cif++/cif++.hpp>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <cif++.hpp>
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
@@ -93,7 +94,8 @@ _atom_site.pdbx_formal_charge
|
||||
|
||||
structure.create_non_poly(entity_id, atom_data);
|
||||
|
||||
auto expected = R"(data_TEST
|
||||
auto expected = R"(
|
||||
data_TEST
|
||||
#
|
||||
_pdbx_nonpoly_scheme.asym_id A
|
||||
_pdbx_nonpoly_scheme.ndb_seq_num 1
|
||||
@@ -137,7 +139,7 @@ _chem_comp.id HEM
|
||||
_chem_comp.type NON-POLYMER
|
||||
_chem_comp.name 'PROTOPORPHYRIN IX CONTAINING FE'
|
||||
_chem_comp.formula 'C34 H32 Fe N4 O4'
|
||||
_chem_comp.formula_weight 616.487
|
||||
_chem_comp.formula_weight 616.487000
|
||||
#
|
||||
_pdbx_entity_nonpoly.entity_id 1
|
||||
_pdbx_entity_nonpoly.name 'PROTOPORPHYRIN IX CONTAINING FE'
|
||||
@@ -146,7 +148,7 @@ _pdbx_entity_nonpoly.comp_id HEM
|
||||
_entity.id 1
|
||||
_entity.type non-polymer
|
||||
_entity.pdbx_description 'PROTOPORPHYRIN IX CONTAINING FE'
|
||||
_entity.formula_weight 616.487
|
||||
_entity.formula_weight 616.487000
|
||||
#
|
||||
_struct_asym.id A
|
||||
_struct_asym.entity_id 1
|
||||
@@ -161,16 +163,10 @@ _atom_type.symbol C
|
||||
|
||||
if (not(expected.front() == structure.get_datablock()))
|
||||
{
|
||||
CHECK(false);
|
||||
std::cout << expected << '\n'
|
||||
std::cerr << expected.front() << '\n'
|
||||
<< '\n'
|
||||
<< structure.get_datablock() << '\n';
|
||||
|
||||
|
||||
std::ofstream of("/tmp/a");
|
||||
of << expected;
|
||||
|
||||
file.save("/tmp/b");
|
||||
REQUIRE(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,9 +195,9 @@ TEST_CASE("create_nonpoly_2")
|
||||
{ "type_symbol", type_symbol },
|
||||
{ "label_atom_id", label_atom_id },
|
||||
{ "auth_atom_id", label_atom_id },
|
||||
{ "Cartn_x", { Cartn_x, 3 } },
|
||||
{ "Cartn_y", { Cartn_y, 3 } },
|
||||
{ "Cartn_z", { Cartn_z, 3 } } });
|
||||
{ "Cartn_x", Cartn_x },
|
||||
{ "Cartn_y", Cartn_y },
|
||||
{ "Cartn_z", Cartn_z } });
|
||||
|
||||
if (atoms.size() == 4)
|
||||
break;
|
||||
@@ -247,14 +243,14 @@ _atom_site.auth_atom_id
|
||||
_atom_site.pdbx_PDB_model_num
|
||||
1 A ? A CHA HEM 1 . C HETATM ? 2.748 -19.531 39.896 1.00 ? 1 HEM CHA 1
|
||||
2 A ? A CHB HEM 1 . C HETATM ? 3.258 -17.744 35.477 1.00 ? 1 HEM CHB 1
|
||||
3 A ? A CHC HEM 1 . C HETATM ? 1.703 -21.900 33.637 1.00 ? 1 HEM CHC 1
|
||||
3 A ? A CHC HEM 1 . C HETATM ? 1.703 -21.9 33.637 1.00 ? 1 HEM CHC 1
|
||||
4 A ? A CHD HEM 1 . C HETATM ? 1.149 -23.677 38.059 1.00 ? 1 HEM CHD 1
|
||||
#
|
||||
_chem_comp.id HEM
|
||||
_chem_comp.type NON-POLYMER
|
||||
_chem_comp.name 'PROTOPORPHYRIN IX CONTAINING FE'
|
||||
_chem_comp.formula 'C34 H32 Fe N4 O4'
|
||||
_chem_comp.formula_weight 616.487
|
||||
_chem_comp.formula_weight 616.487000
|
||||
#
|
||||
_pdbx_entity_nonpoly.entity_id 1
|
||||
_pdbx_entity_nonpoly.name 'PROTOPORPHYRIN IX CONTAINING FE'
|
||||
@@ -263,7 +259,7 @@ _pdbx_entity_nonpoly.comp_id HEM
|
||||
_entity.id 1
|
||||
_entity.type non-polymer
|
||||
_entity.pdbx_description 'PROTOPORPHYRIN IX CONTAINING FE'
|
||||
_entity.formula_weight 616.487
|
||||
_entity.formula_weight 616.487000
|
||||
#
|
||||
_struct_asym.id A
|
||||
_struct_asym.entity_id 1
|
||||
@@ -280,7 +276,7 @@ _atom_type.symbol C
|
||||
|
||||
if (not(expected.front() == structure.get_datablock()))
|
||||
{
|
||||
CHECK(false);
|
||||
// REQUIRE(false);
|
||||
std::cout << expected.front() << '\n'
|
||||
<< '\n'
|
||||
<< structure.get_datablock() << '\n';
|
||||
@@ -362,10 +358,10 @@ _struct_asym.details ?
|
||||
|
||||
cif::mm::structure s(data);
|
||||
|
||||
CHECK(s.get_atom_by_id("1").get_label_atom_id() == "CHA");
|
||||
CHECK(s.get_atom_by_id("2").get_label_atom_id() == "CHC");
|
||||
CHECK(s.get_atom_by_id("3").get_label_atom_id() == "CHB");
|
||||
CHECK(s.get_atom_by_id("4").get_label_atom_id() == "CHD");
|
||||
REQUIRE(s.get_atom_by_id("1").get_label_atom_id() == "CHA");
|
||||
REQUIRE(s.get_atom_by_id("2").get_label_atom_id() == "CHC");
|
||||
REQUIRE(s.get_atom_by_id("3").get_label_atom_id() == "CHB");
|
||||
REQUIRE(s.get_atom_by_id("4").get_label_atom_id() == "CHD");
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
@@ -386,19 +382,19 @@ TEST_CASE("atom_numbers_1")
|
||||
{
|
||||
auto atom = structure.get_atom_by_id(id);
|
||||
|
||||
CHECK(atom.get_label_asym_id() == label_asym_id);
|
||||
CHECK(atom.get_label_seq_id() == label_seq_id);
|
||||
CHECK(atom.get_label_atom_id() == label_atom_id);
|
||||
CHECK(atom.get_auth_seq_id() == auth_seq_id);
|
||||
CHECK(atom.get_label_comp_id() == label_comp_id);
|
||||
REQUIRE(atom.get_label_asym_id() == label_asym_id);
|
||||
REQUIRE(atom.get_label_seq_id() == label_seq_id);
|
||||
REQUIRE(atom.get_label_atom_id() == label_atom_id);
|
||||
REQUIRE(atom.get_auth_seq_id() == auth_seq_id);
|
||||
REQUIRE(atom.get_label_comp_id() == label_comp_id);
|
||||
|
||||
CHECK(ai != atoms.end());
|
||||
REQUIRE(ai != atoms.end());
|
||||
|
||||
CHECK(ai->id() == id);
|
||||
REQUIRE(ai->id() == id);
|
||||
++ai;
|
||||
}
|
||||
|
||||
CHECK(ai == atoms.end());
|
||||
REQUIRE(ai == atoms.end());
|
||||
}
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
@@ -418,7 +414,9 @@ TEST_CASE("test_load_2")
|
||||
auto &pdbx_poly_seq_scheme = db["pdbx_poly_seq_scheme"];
|
||||
|
||||
for (auto &poly : s.polymers())
|
||||
CHECK(poly.size() == pdbx_poly_seq_scheme.find("asym_id"_key == poly.get_asym_id()).size());
|
||||
{
|
||||
REQUIRE(poly.size() == pdbx_poly_seq_scheme.find("asym_id"_key == poly.get_asym_id()).size());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("remove_residue_1")
|
||||
@@ -431,186 +429,5 @@ TEST_CASE("remove_residue_1")
|
||||
cif::mm::structure s(file);
|
||||
s.remove_residue(s.get_residue("B"));
|
||||
|
||||
CHECK_NOTHROW(s.validate_atoms());
|
||||
REQUIRE_NOTHROW(s.validate_atoms());
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
TEST_CASE("test_alternates_1")
|
||||
{
|
||||
using namespace cif::literals;
|
||||
|
||||
const std::filesystem::path example(gTestDir / ".." / "examples" / "1cbs.cif.gz");
|
||||
cif::file file(example.string());
|
||||
|
||||
cif::mm::structure s(file);
|
||||
|
||||
for (auto atom : s.atoms())
|
||||
CHECK_FALSE(atom.is_alternate());
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// Tests for structure_open_options
|
||||
|
||||
TEST_CASE("options_1")
|
||||
{
|
||||
using namespace cif::literals;
|
||||
|
||||
const std::filesystem::path example(gTestDir / ".." / "examples" / "1cbs.cif.gz");
|
||||
cif::file file(example.string());
|
||||
|
||||
auto &cf = cif::compound_factory::instance();
|
||||
|
||||
SECTION("skip_water")
|
||||
{
|
||||
cif::mm::structure s(file, 1, { .skip_water = true });
|
||||
|
||||
REQUIRE_NOTHROW(s.validate_atoms());
|
||||
|
||||
for (auto a : s.atoms())
|
||||
CHECK_FALSE(a.is_water());
|
||||
}
|
||||
|
||||
SECTION("skip_hetatom")
|
||||
{
|
||||
cif::mm::structure s(file, 1, { .skip_hetatom = true });
|
||||
|
||||
REQUIRE_NOTHROW(s.validate_atoms());
|
||||
|
||||
for (auto a : s.atoms())
|
||||
CHECK((a.is_water() or cf.is_peptide(a.get_label_comp_id()) or cf.is_base(a.get_label_comp_id())));
|
||||
}
|
||||
|
||||
SECTION("selected_asyms")
|
||||
{
|
||||
cif::mm::structure s(file, 1, { .asyms = { "A" } });
|
||||
|
||||
REQUIRE_NOTHROW(s.validate_atoms());
|
||||
|
||||
for (auto a : s.atoms())
|
||||
CHECK(a.get_label_asym_id() == "A");
|
||||
}
|
||||
|
||||
SECTION("min-b-factor")
|
||||
{
|
||||
cif::mm::structure s(file, 1, { .min_b_factor = 20.f });
|
||||
|
||||
REQUIRE_NOTHROW(s.validate_atoms());
|
||||
|
||||
for (auto a : s.atoms())
|
||||
CHECK(a.get_property_float("B_iso_or_equiv") >= 20.f);
|
||||
}
|
||||
|
||||
SECTION("max-b-factor")
|
||||
{
|
||||
cif::mm::structure s(file, 1, { .max_b_factor = 20.f });
|
||||
|
||||
REQUIRE_NOTHROW(s.validate_atoms());
|
||||
|
||||
for (auto a : s.atoms())
|
||||
CHECK(a.get_property_float("B_iso_or_equiv") <= 20.f);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("options_2")
|
||||
{
|
||||
|
||||
auto data = R"(
|
||||
data_TEST
|
||||
#
|
||||
_pdbx_nonpoly_scheme.asym_id A
|
||||
_pdbx_nonpoly_scheme.ndb_seq_num 1
|
||||
_pdbx_nonpoly_scheme.entity_id 1
|
||||
_pdbx_nonpoly_scheme.mon_id HEM
|
||||
_pdbx_nonpoly_scheme.pdb_seq_num 1
|
||||
_pdbx_nonpoly_scheme.auth_seq_num 1
|
||||
_pdbx_nonpoly_scheme.pdb_mon_id HEM
|
||||
_pdbx_nonpoly_scheme.auth_mon_id HEM
|
||||
_pdbx_nonpoly_scheme.pdb_strand_id A
|
||||
_pdbx_nonpoly_scheme.pdb_ins_code .
|
||||
#
|
||||
loop_
|
||||
_atom_site.id
|
||||
_atom_site.auth_asym_id
|
||||
_atom_site.label_alt_id
|
||||
_atom_site.label_asym_id
|
||||
_atom_site.label_atom_id
|
||||
_atom_site.label_comp_id
|
||||
_atom_site.label_entity_id
|
||||
_atom_site.label_seq_id
|
||||
_atom_site.type_symbol
|
||||
_atom_site.group_PDB
|
||||
_atom_site.pdbx_PDB_ins_code
|
||||
_atom_site.Cartn_x
|
||||
_atom_site.Cartn_y
|
||||
_atom_site.Cartn_z
|
||||
_atom_site.occupancy
|
||||
_atom_site.B_iso_or_equiv
|
||||
_atom_site.pdbx_formal_charge
|
||||
_atom_site.auth_seq_id
|
||||
_atom_site.auth_comp_id
|
||||
_atom_site.auth_atom_id
|
||||
_atom_site.pdbx_PDB_model_num
|
||||
1 A A A CHA HEM 1 . C HETATM ? -5.248 39.769 -0.250 0.75 7.67 ? 1 HEM CHA 1
|
||||
3 A A A CHB HEM 1 . C HETATM ? -3.774 36.790 3.280 0.75 7.05 ? 1 HEM CHB 1
|
||||
2 A A A CHC HEM 1 . C HETATM ? -2.879 33.328 0.013 0.75 7.69 ? 1 HEM CHC 1
|
||||
4 A A A CHD HEM 1 . C HETATM ? -4.342 36.262 -3.536 0.75 8.00 ? 1 HEM CHD 1
|
||||
5 A B A CHA HEM 1 . C HETATM ? -5.248 39.769 -0.250 0.25 7.67 ? 1 HEM CHA 1
|
||||
6 A B A CHB HEM 1 . C HETATM ? -3.774 36.790 3.280 0.25 7.05 ? 1 HEM CHB 1
|
||||
7 A B A CHC HEM 1 . C HETATM ? -2.879 33.328 0.013 0.25 7.69 ? 1 HEM CHC 1
|
||||
8 A B A CHD HEM 1 . C HETATM ? -4.342 36.262 -3.536 0.25 8.00 ? 1 HEM CHD 1
|
||||
#
|
||||
_chem_comp.id HEM
|
||||
_chem_comp.type NON-POLYMER
|
||||
_chem_comp.name 'PROTOPORPHYRIN IX CONTAINING FE'
|
||||
_chem_comp.formula 'C34 H32 Fe N4 O4'
|
||||
_chem_comp.formula_weight 616.487000
|
||||
#
|
||||
_pdbx_entity_nonpoly.entity_id 1
|
||||
_pdbx_entity_nonpoly.name 'PROTOPORPHYRIN IX CONTAINING FE'
|
||||
_pdbx_entity_nonpoly.comp_id HEM
|
||||
#
|
||||
_entity.id 1
|
||||
_entity.type non-polymer
|
||||
_entity.pdbx_description 'PROTOPORPHYRIN IX CONTAINING FE'
|
||||
_entity.formula_weight 616.487000
|
||||
#
|
||||
_struct_asym.id A
|
||||
_struct_asym.entity_id 1
|
||||
_struct_asym.pdbx_blank_PDB_chainid_flag N
|
||||
_struct_asym.pdbx_modified N
|
||||
_struct_asym.details ?
|
||||
#
|
||||
)"_cf;
|
||||
|
||||
data.front().load_dictionary("mmcif_pdbx.dic");
|
||||
|
||||
SECTION("max")
|
||||
{
|
||||
cif::mm::structure s(data, 1, {
|
||||
.occupancy_mode = cif::mm::occupancy_policy::MAX
|
||||
});
|
||||
|
||||
REQUIRE(s.atoms().size() == 4);
|
||||
CHECK(s.atoms().front().get_label_alt_id() == "A");
|
||||
}
|
||||
|
||||
SECTION("min")
|
||||
{
|
||||
cif::mm::structure s(data, 1, {
|
||||
.occupancy_mode = cif::mm::occupancy_policy::MIN
|
||||
});
|
||||
|
||||
REQUIRE(s.atoms().size() == 4);
|
||||
CHECK(s.atoms().front().get_label_alt_id() == "B");
|
||||
}
|
||||
|
||||
SECTION("unoccupied")
|
||||
{
|
||||
cif::mm::structure s(data, 1, {
|
||||
.occupancy_mode = cif::mm::occupancy_policy::UNOCCUPIED
|
||||
});
|
||||
|
||||
CHECK(s.atoms().empty());
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -24,19 +24,15 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "cif++/utilities.hpp"
|
||||
#include "test-main.hpp"
|
||||
|
||||
#include <cif++/cif++.hpp>
|
||||
#include <cif++.hpp>
|
||||
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
TEST_CASE("reconstruct")
|
||||
{
|
||||
cif::VERBOSE = 1;
|
||||
|
||||
cif::compound_factory::instance().push_dictionary(gTestDir / "REA.cif");
|
||||
|
||||
for (std::filesystem::directory_iterator i(gTestDir / "reconstruct"); i != std::filesystem::directory_iterator{}; ++i)
|
||||
@@ -58,18 +54,9 @@ TEST_CASE("reconstruct")
|
||||
|
||||
std::error_code ec;
|
||||
CHECK_FALSE(cif::pdb::is_valid_pdbx_file(f, ec));
|
||||
CHECK(ec != std::errc{});
|
||||
CHECK((bool)ec);
|
||||
|
||||
auto valid = cif::pdb::reconstruct_pdbx(f);
|
||||
|
||||
CHECK(valid);
|
||||
|
||||
if (not valid)
|
||||
{
|
||||
std::ofstream of(std::filesystem::temp_directory_path() / i->path().filename());
|
||||
of << f;
|
||||
of.close();
|
||||
}
|
||||
CHECK(cif::pdb::reconstruct_pdbx(f));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
#include "test-main.hpp"
|
||||
|
||||
#include <cif++/cif++.hpp>
|
||||
#include <cif++.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include <cif++/cif++.hpp>
|
||||
#include <cif++.hpp>
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
@@ -183,6 +183,4 @@ TEST_CASE("delete_sugar_1")
|
||||
// file.save(gTestDir / "test-create_sugar_3.cif");
|
||||
|
||||
cif::mm::structure s2(file);
|
||||
|
||||
file.save("/tmp/min-s.cif");
|
||||
}
|
||||
|
||||
@@ -1,46 +1,22 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2026 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.
|
||||
*/
|
||||
|
||||
#define CATCH_CONFIG_RUNNER 1 // NOLINT
|
||||
#define CATCH_CONFIG_RUNNER 1
|
||||
|
||||
#include "test-main.hpp"
|
||||
|
||||
#include <cif++/utilities.hpp>
|
||||
#include <cif++/compound.hpp>
|
||||
#include <cif++.hpp>
|
||||
|
||||
std::filesystem::path gTestDir;
|
||||
std::filesystem::path gTestDir = std::filesystem::current_path();
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
gTestDir = std::filesystem::current_path();
|
||||
|
||||
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
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user